1 /* $NetBSD: rfcomm_sppd.c,v 1.8 2007/04/21 10:39:30 dsl Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 Itronix Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of Itronix Inc. may not be used to endorse 16 * or promote products derived from this software without specific 17 * prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 /* 32 * rfcomm_sppd.c 33 * 34 * Copyright (c) 2007 Iain Hibbert 35 * Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com> 36 * All rights reserved. 37 * 38 * Redistribution and use in source and binary forms, with or without 39 * modification, are permitted provided that the following conditions 40 * are met: 41 * 1. Redistributions of source code must retain the above copyright 42 * notice, this list of conditions and the following disclaimer. 43 * 2. Redistributions in binary form must reproduce the above copyright 44 * notice, this list of conditions and the following disclaimer in the 45 * documentation and/or other materials provided with the distribution. 46 * 47 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 50 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 57 * SUCH DAMAGE. 58 */ 59 60 #include <bluetooth.h> 61 #include <ctype.h> 62 #include <err.h> 63 #include <errno.h> 64 #include <fcntl.h> 65 #include <grp.h> 66 #include <limits.h> 67 #include <paths.h> 68 #include <sdp.h> 69 #include <signal.h> 70 #include <stdarg.h> 71 #include <stdio.h> 72 #include <stdlib.h> 73 #include <string.h> 74 #include <syslog.h> 75 #include <termios.h> 76 #include <unistd.h> 77 #include <sys/stat.h> 78 79 #include <netbt/rfcomm.h> 80 81 #include "rfcomm_sdp.h" 82 83 #define max(a, b) ((a) > (b) ? (a) : (b)) 84 85 int open_tty(const char *); 86 int open_client(bdaddr_t *, bdaddr_t *, int, const char *); 87 int open_server(bdaddr_t *, uint8_t, int, const char *); 88 void copy_data(int, int); 89 void sighandler(int); 90 void usage(void) __dead2; 91 void reset_tio(void); 92 93 int done; /* got a signal */ 94 struct termios tio; /* stored termios for reset on exit */ 95 96 struct service { 97 const char *name; 98 const char *description; 99 uint16_t class; 100 int pdulen; 101 } services[] = { 102 { "DUN", "Dialup Networking", 103 SDP_SERVICE_CLASS_DIALUP_NETWORKING, 104 sizeof(struct sdp_dun_profile) 105 }, 106 { "LAN", "Lan access using PPP", 107 SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP, 108 sizeof(struct sdp_lan_profile) 109 }, 110 { "SP", "Serial Port", 111 SDP_SERVICE_CLASS_SERIAL_PORT, 112 sizeof(struct sdp_sp_profile) 113 }, 114 { NULL, NULL, 115 0, 116 0 117 } 118 }; 119 120 int 121 main(int argc, char *argv[]) 122 { 123 struct termios t; 124 bdaddr_t laddr, raddr; 125 fd_set rdset; 126 const char *service; 127 char *ep, *tty; 128 int lm, n, rfcomm, tty_in, tty_out; 129 uint8_t channel; 130 131 bdaddr_copy(&laddr, BDADDR_ANY); 132 bdaddr_copy(&raddr, BDADDR_ANY); 133 service = "SP"; 134 tty = NULL; 135 channel = 0; 136 lm = 0; 137 138 /* Parse command line options */ 139 while ((n = getopt(argc, argv, "a:c:d:hm:s:t:")) != -1) { 140 switch (n) { 141 case 'a': /* remote device address */ 142 if (!bt_aton(optarg, &raddr)) { 143 struct hostent *he = NULL; 144 145 if ((he = bt_gethostbyname(optarg)) == NULL) 146 errx(EXIT_FAILURE, "%s: %s", optarg, 147 hstrerror(h_errno)); 148 149 bdaddr_copy(&raddr, (bdaddr_t *)he->h_addr); 150 } 151 break; 152 153 case 'c': /* RFCOMM channel */ 154 channel = strtoul(optarg, &ep, 10); 155 if (*ep != '\0' || channel < 1 || channel > 30) 156 errx(EXIT_FAILURE, "Invalid channel: %s", optarg); 157 158 break; 159 160 case 'd': /* local device address */ 161 if (!bt_devaddr(optarg, &laddr)) 162 err(EXIT_FAILURE, "%s", optarg); 163 164 break; 165 166 case 'm': /* Link Mode */ 167 if (strcasecmp(optarg, "auth") == 0) 168 lm = RFCOMM_LM_AUTH; 169 else if (strcasecmp(optarg, "encrypt") == 0) 170 lm = RFCOMM_LM_ENCRYPT; 171 else if (strcasecmp(optarg, "secure") == 0) 172 lm = RFCOMM_LM_SECURE; 173 else 174 errx(EXIT_FAILURE, "%s: unknown mode", optarg); 175 176 break; 177 178 case 's': /* service class */ 179 service = optarg; 180 break; 181 182 case 't': /* Slave TTY name */ 183 if (optarg[0] != '/') 184 asprintf(&tty, "%s%s", _PATH_DEV, optarg); 185 else 186 tty = optarg; 187 188 break; 189 190 case 'h': 191 default: 192 usage(); 193 /* NOT REACHED */ 194 } 195 } 196 197 /* 198 * validate options: 199 * must have channel or remote address but not both 200 */ 201 if ((channel == 0 && bdaddr_any(&raddr)) 202 || (channel != 0 && !bdaddr_any(&raddr))) 203 usage(); 204 205 /* 206 * grab ttys before we start the bluetooth 207 */ 208 if (tty == NULL) { 209 tty_in = STDIN_FILENO; 210 tty_out = STDOUT_FILENO; 211 } else { 212 tty_in = open_tty(tty); 213 tty_out = tty_in; 214 } 215 216 /* open RFCOMM */ 217 if (channel == 0) 218 rfcomm = open_client(&laddr, &raddr, lm, service); 219 else 220 rfcomm = open_server(&laddr, channel, lm, service); 221 222 /* 223 * now we are ready to go, so either detach or maybe turn 224 * off some input processing, so that rfcomm_sppd can 225 * be used directly with stdio 226 */ 227 if (tty == NULL) { 228 if (tcgetattr(tty_in, &t) < 0) 229 err(EXIT_FAILURE, "tcgetattr"); 230 231 memcpy(&tio, &t, sizeof(tio)); 232 t.c_lflag &= ~(ECHO | ICANON); 233 t.c_iflag &= ~(ICRNL); 234 235 if (memcmp(&tio, &t, sizeof(tio))) { 236 if (tcsetattr(tty_in, TCSANOW, &t) < 0) 237 err(EXIT_FAILURE, "tcsetattr"); 238 239 atexit(reset_tio); 240 } 241 } else { 242 if (daemon(0, 0) < 0) 243 err(EXIT_FAILURE, "daemon() failed"); 244 } 245 246 /* catch signals */ 247 done = 0; 248 (void)signal(SIGHUP, sighandler); 249 (void)signal(SIGINT, sighandler); 250 (void)signal(SIGPIPE, sighandler); 251 (void)signal(SIGTERM, sighandler); 252 253 openlog(getprogname(), LOG_PERROR | LOG_PID, LOG_DAEMON); 254 syslog(LOG_INFO, "Starting on %s...", (tty ? tty : "stdio")); 255 256 n = max(tty_in, rfcomm) + 1; 257 while (!done) { 258 FD_ZERO(&rdset); 259 FD_SET(tty_in, &rdset); 260 FD_SET(rfcomm, &rdset); 261 262 if (select(n, &rdset, NULL, NULL, NULL) < 0) { 263 if (errno == EINTR) 264 continue; 265 266 syslog(LOG_ERR, "select error: %m"); 267 exit(EXIT_FAILURE); 268 } 269 270 if (FD_ISSET(tty_in, &rdset)) 271 copy_data(tty_in, rfcomm); 272 273 if (FD_ISSET(rfcomm, &rdset)) 274 copy_data(rfcomm, tty_out); 275 } 276 277 syslog(LOG_INFO, "Completed on %s", (tty ? tty : "stdio")); 278 exit(EXIT_SUCCESS); 279 } 280 281 int 282 open_tty(const char *tty) 283 { 284 char pty[PATH_MAX], *slash; 285 struct group *gr = NULL; 286 gid_t ttygid; 287 int master; 288 289 /* 290 * Construct master PTY name. The slave tty name must be less then 291 * PATH_MAX characters in length, must contain '/' character and 292 * must not end with '/'. 293 */ 294 if (strlen(tty) >= sizeof(pty)) 295 errx(EXIT_FAILURE, ": tty name too long"); 296 297 strlcpy(pty, tty, sizeof(pty)); 298 slash = strrchr(pty, '/'); 299 if (slash == NULL || slash[1] == '\0') 300 errx(EXIT_FAILURE, "%s: invalid tty", tty); 301 302 slash[1] = 'p'; 303 if (strcmp(pty, tty) == 0) 304 errx(EXIT_FAILURE, "Master and slave tty are the same (%s)", tty); 305 306 if ((master = open(pty, O_RDWR, 0)) < 0) 307 err(EXIT_FAILURE, "%s", pty); 308 309 /* 310 * Slave TTY 311 */ 312 313 if ((gr = getgrnam("tty")) != NULL) 314 ttygid = gr->gr_gid; 315 else 316 ttygid = (gid_t)-1; 317 318 (void)chown(tty, getuid(), ttygid); 319 (void)chmod(tty, S_IRUSR | S_IWUSR | S_IWGRP); 320 (void)revoke(tty); 321 322 return master; 323 } 324 325 int 326 open_client(bdaddr_t *laddr, bdaddr_t *raddr, int lm, const char *service) 327 { 328 struct sockaddr_bt sa; 329 struct service *s; 330 struct linger l; 331 char *ep; 332 int fd; 333 uint8_t channel = 0; /* avoid gcc warnings */ 334 335 for (s = services ; ; s++) { 336 if (s->name == NULL) { 337 channel = strtoul(service, &ep, 10); 338 if (*ep != '\0' || channel < 1 || channel > 30) 339 errx(EXIT_FAILURE, "Invalid service: %s", service); 340 341 break; 342 } 343 344 if (strcasecmp(s->name, service) == 0) { 345 if (rfcomm_channel_lookup(laddr, raddr, s->class, &channel, &errno) < 0) 346 err(EXIT_FAILURE, "%s", s->name); 347 348 break; 349 } 350 } 351 352 memset(&sa, 0, sizeof(sa)); 353 sa.bt_len = sizeof(sa); 354 sa.bt_family = AF_BLUETOOTH; 355 bdaddr_copy(&sa.bt_bdaddr, laddr); 356 357 fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); 358 if (fd < 0) 359 err(EXIT_FAILURE, "socket()"); 360 361 if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) 362 err(EXIT_FAILURE, "bind(%s)", bt_ntoa(laddr, NULL)); 363 364 memset(&l, 0, sizeof(l)); 365 l.l_onoff = 1; 366 l.l_linger = 5; 367 if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0) 368 err(EXIT_FAILURE, "linger()"); 369 370 if (setsockopt(fd, BTPROTO_RFCOMM, SO_RFCOMM_LM, &lm, sizeof(lm)) < 0) 371 err(EXIT_FAILURE, "link mode"); 372 373 sa.bt_channel = channel; 374 bdaddr_copy(&sa.bt_bdaddr, raddr); 375 376 if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) 377 err(EXIT_FAILURE, "connect(%s, %d)", bt_ntoa(raddr, NULL), 378 channel); 379 380 return fd; 381 } 382 383 /* 384 * In all the profiles we currently support registering, the channel 385 * is the first octet in the PDU, and it seems all the rest can be 386 * zero, so we just use an array of uint8_t big enough to store the 387 * largest, currently LAN. See <sdp.h> for definitions.. 388 */ 389 #define pdu_len sizeof(struct sdp_lan_profile) 390 391 int 392 open_server(bdaddr_t *laddr, uint8_t channel, int lm, const char *service) 393 { 394 struct sockaddr_bt sa; 395 struct linger l; 396 socklen_t len; 397 void *ss; 398 int sv, fd, n; 399 uint8_t pdu[pdu_len]; 400 401 memset(&sa, 0, sizeof(sa)); 402 sa.bt_len = sizeof(sa); 403 sa.bt_family = AF_BLUETOOTH; 404 bdaddr_copy(&sa.bt_bdaddr, laddr); 405 sa.bt_channel = channel; 406 407 sv = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); 408 if (sv < 0) 409 err(EXIT_FAILURE, "socket()"); 410 411 if (bind(sv, (struct sockaddr *)&sa, sizeof(sa)) < 0) 412 err(EXIT_FAILURE, "bind(%s, %d)", bt_ntoa(laddr, NULL), 413 channel); 414 415 if (setsockopt(sv, BTPROTO_RFCOMM, SO_RFCOMM_LM, &lm, sizeof(lm)) < 0) 416 err(EXIT_FAILURE, "link mode"); 417 418 if (listen(sv, 1) < 0) 419 err(EXIT_FAILURE, "listen()"); 420 421 /* Register service with SDP server */ 422 for (n = 0 ; ; n++) { 423 if (services[n].name == NULL) 424 usage(); 425 426 if (strcasecmp(services[n].name, service) == 0) 427 break; 428 } 429 430 memset(pdu, 0, pdu_len); 431 pdu[0] = channel; 432 433 ss = sdp_open_local(NULL); 434 if (ss == NULL || (errno = sdp_error(ss)) != 0) 435 err(EXIT_FAILURE, "sdp_open_local"); 436 437 if (sdp_register_service(ss, services[n].class, laddr, 438 pdu, services[n].pdulen, NULL) != 0) { 439 errno = sdp_error(ss); 440 err(EXIT_FAILURE, "sdp_register_service"); 441 } 442 443 len = sizeof(sa); 444 fd = accept(sv, (struct sockaddr *)&sa, &len); 445 if (fd < 0) 446 err(EXIT_FAILURE, "accept"); 447 448 memset(&l, 0, sizeof(l)); 449 l.l_onoff = 1; 450 l.l_linger = 5; 451 if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0) 452 err(EXIT_FAILURE, "linger()"); 453 454 close(sv); 455 return fd; 456 } 457 458 void 459 copy_data(int src, int dst) 460 { 461 static char buf[BUFSIZ]; 462 ssize_t nr, nw, off; 463 464 while ((nr = read(src, buf, sizeof(buf))) == -1) { 465 if (errno != EINTR) { 466 syslog(LOG_ERR, "read failed: %m"); 467 exit(EXIT_FAILURE); 468 } 469 } 470 471 if (nr == 0) /* reached EOF */ 472 done++; 473 474 for (off = 0 ; nr ; nr -= nw, off += nw) { 475 if ((nw = write(dst, buf + off, (size_t)nr)) == -1) { 476 syslog(LOG_ERR, "write failed: %m"); 477 exit(EXIT_FAILURE); 478 } 479 } 480 } 481 482 void 483 sighandler(int s __unused) 484 { 485 486 done++; 487 } 488 489 void 490 reset_tio(void) 491 { 492 493 tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio); 494 } 495 496 void 497 usage(void) 498 { 499 const char *cmd = getprogname(); 500 struct service *s; 501 502 fprintf(stderr, "Usage: %s [-d device] [-m mode] [-s service] [-t tty]\n" 503 " %*s {-a bdaddr | -c channel}\n" 504 "\n" 505 "Where:\n" 506 "\t-a bdaddr remote device address\n" 507 "\t-c channel local RFCOMM channel\n" 508 "\t-d device local device address\n" 509 "\t-m mode link mode\n" 510 "\t-s service service class\n" 511 "\t-t tty run in background using pty\n" 512 "\n", cmd, (int)strlen(cmd), ""); 513 514 fprintf(stderr, "Known service classes:\n"); 515 for (s = services ; s->name != NULL ; s++) 516 fprintf(stderr, "\t%-13s%s\n", s->name, s->description); 517 518 exit(EXIT_FAILURE); 519 } 520