1 /* 2 * rfcomm_pppd.c 3 */ 4 5 /*- 6 * SPDX-License-Identifier: BSD-2-Clause 7 * 8 * Copyright (c) 2001-2008 Maksim Yevmenkin <m_evmenkin@yahoo.com> 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $Id: rfcomm_pppd.c,v 1.5 2003/09/07 18:32:11 max Exp $ 33 * $FreeBSD$ 34 */ 35 #define L2CAP_SOCKET_CHECKED 36 #include <bluetooth.h> 37 #include <ctype.h> 38 #include <err.h> 39 #include <errno.h> 40 #include <fcntl.h> 41 #include <sdp.h> 42 #include <signal.h> 43 #include <stdarg.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <syslog.h> 48 #include <unistd.h> 49 50 #define RFCOMM_PPPD "rfcomm_pppd" 51 52 int rfcomm_channel_lookup (bdaddr_t const *local, 53 bdaddr_t const *remote, 54 int service, int *channel, int *error); 55 56 static void exec_ppp (int s, char *unit, char *label); 57 static void sighandler (int s); 58 static void usage (void); 59 60 static int done; 61 62 /* Main */ 63 int 64 main(int argc, char *argv[]) 65 { 66 struct sockaddr_rfcomm sock_addr; 67 char *label = NULL, *unit = NULL, *ep = NULL; 68 bdaddr_t addr; 69 int s, channel, detach, server, service, 70 regdun, regsp; 71 pid_t pid; 72 73 memcpy(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)); 74 channel = 0; 75 detach = 1; 76 server = 0; 77 service = 0; 78 regdun = 0; 79 regsp = 0; 80 81 /* Parse command line arguments */ 82 while ((s = getopt(argc, argv, "a:cC:dDhl:sSu:")) != -1) { 83 switch (s) { 84 case 'a': /* BDADDR */ 85 if (!bt_aton(optarg, &addr)) { 86 struct hostent *he = NULL; 87 88 if ((he = bt_gethostbyname(optarg)) == NULL) 89 errx(1, "%s: %s", optarg, hstrerror(h_errno)); 90 91 memcpy(&addr, he->h_addr, sizeof(addr)); 92 } 93 break; 94 95 case 'c': /* client */ 96 server = 0; 97 break; 98 99 case 'C': /* RFCOMM channel */ 100 channel = strtoul(optarg, &ep, 10); 101 if (*ep != '\0') { 102 channel = 0; 103 switch (tolower(optarg[0])) { 104 case 'd': /* DialUp Networking */ 105 service = SDP_SERVICE_CLASS_DIALUP_NETWORKING; 106 break; 107 108 case 'l': /* LAN Access Using PPP */ 109 service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP; 110 break; 111 } 112 } 113 break; 114 115 case 'd': /* do not detach */ 116 detach = 0; 117 break; 118 119 case 'D': /* Register DUN service as well as LAN service */ 120 regdun = 1; 121 break; 122 123 case 'l': /* PPP label */ 124 label = optarg; 125 break; 126 127 case 's': /* server */ 128 server = 1; 129 break; 130 131 case 'S': /* Register SP service as well as LAN service */ 132 regsp = 1; 133 break; 134 135 case 'u': /* PPP -unit option */ 136 strtoul(optarg, &ep, 10); 137 if (*ep != '\0') 138 usage(); 139 /* NOT REACHED */ 140 141 unit = optarg; 142 break; 143 144 case 'h': 145 default: 146 usage(); 147 /* NOT REACHED */ 148 } 149 } 150 151 /* Check if we got everything we wanted */ 152 if (label == NULL) 153 errx(1, "Must specify PPP label"); 154 155 if (!server) { 156 if (memcmp(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)) == 0) 157 errx(1, "Must specify server BD_ADDR"); 158 159 /* Check channel, if was not set then obtain it via SDP */ 160 if (channel == 0 && service != 0) 161 if (rfcomm_channel_lookup(NULL, &addr, service, 162 &channel, &s) != 0) 163 errc(1, s, "Could not obtain RFCOMM channel"); 164 } 165 166 if (channel <= 0 || channel > 30) 167 errx(1, "Invalid RFCOMM channel number %d", channel); 168 169 openlog(RFCOMM_PPPD, LOG_PID | LOG_PERROR | LOG_NDELAY, LOG_USER); 170 171 if (detach && daemon(0, 0) < 0) { 172 syslog(LOG_ERR, "Could not daemon(0, 0). %s (%d)", 173 strerror(errno), errno); 174 exit(1); 175 } 176 177 s = socket(PF_BLUETOOTH, SOCK_STREAM, BLUETOOTH_PROTO_RFCOMM); 178 if (s < 0) { 179 syslog(LOG_ERR, "Could not create socket. %s (%d)", 180 strerror(errno), errno); 181 exit(1); 182 } 183 184 if (server) { 185 struct sigaction sa; 186 void *ss = NULL; 187 sdp_lan_profile_t lan; 188 189 /* Install signal handler */ 190 memset(&sa, 0, sizeof(sa)); 191 sa.sa_handler = sighandler; 192 193 if (sigaction(SIGTERM, &sa, NULL) < 0) { 194 syslog(LOG_ERR, "Could not sigaction(SIGTERM). %s (%d)", 195 strerror(errno), errno); 196 exit(1); 197 } 198 199 if (sigaction(SIGHUP, &sa, NULL) < 0) { 200 syslog(LOG_ERR, "Could not sigaction(SIGHUP). %s (%d)", 201 strerror(errno), errno); 202 exit(1); 203 } 204 205 if (sigaction(SIGINT, &sa, NULL) < 0) { 206 syslog(LOG_ERR, "Could not sigaction(SIGINT). %s (%d)", 207 strerror(errno), errno); 208 exit(1); 209 } 210 211 sa.sa_handler = SIG_IGN; 212 sa.sa_flags = SA_NOCLDWAIT; 213 214 if (sigaction(SIGCHLD, &sa, NULL) < 0) { 215 syslog(LOG_ERR, "Could not sigaction(SIGCHLD). %s (%d)", 216 strerror(errno), errno); 217 exit(1); 218 } 219 220 /* bind socket and listen for incoming connections */ 221 sock_addr.rfcomm_len = sizeof(sock_addr); 222 sock_addr.rfcomm_family = AF_BLUETOOTH; 223 memcpy(&sock_addr.rfcomm_bdaddr, &addr, 224 sizeof(sock_addr.rfcomm_bdaddr)); 225 sock_addr.rfcomm_channel = channel; 226 227 if (bind(s, (struct sockaddr *) &sock_addr, 228 sizeof(sock_addr)) < 0) { 229 syslog(LOG_ERR, "Could not bind socket. %s (%d)", 230 strerror(errno), errno); 231 exit(1); 232 } 233 234 if (listen(s, 10) < 0) { 235 syslog(LOG_ERR, "Could not listen on socket. %s (%d)", 236 strerror(errno), errno); 237 exit(1); 238 } 239 240 ss = sdp_open_local(NULL); 241 if (ss == NULL) { 242 syslog(LOG_ERR, "Unable to create local SDP session"); 243 exit(1); 244 } 245 246 if (sdp_error(ss) != 0) { 247 syslog(LOG_ERR, "Unable to open local SDP session. " \ 248 "%s (%d)", strerror(sdp_error(ss)), 249 sdp_error(ss)); 250 exit(1); 251 } 252 253 memset(&lan, 0, sizeof(lan)); 254 lan.server_channel = channel; 255 256 if (sdp_register_service(ss, 257 SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP, 258 &addr, (void *) &lan, sizeof(lan), NULL) != 0) { 259 syslog(LOG_ERR, "Unable to register LAN service with " \ 260 "local SDP daemon. %s (%d)", 261 strerror(sdp_error(ss)), sdp_error(ss)); 262 exit(1); 263 } 264 265 /* 266 * Register DUN (Dial-Up Networking) service on the same 267 * RFCOMM channel if requested. There is really no good reason 268 * to not to support this. AT-command exchange can be faked 269 * with chat script in ppp.conf 270 */ 271 272 if (regdun) { 273 sdp_dun_profile_t dun; 274 275 memset(&dun, 0, sizeof(dun)); 276 dun.server_channel = channel; 277 278 if (sdp_register_service(ss, 279 SDP_SERVICE_CLASS_DIALUP_NETWORKING, 280 &addr, (void *) &dun, sizeof(dun), 281 NULL) != 0) { 282 syslog(LOG_ERR, "Unable to register DUN " \ 283 "service with local SDP daemon. " \ 284 "%s (%d)", strerror(sdp_error(ss)), 285 sdp_error(ss)); 286 exit(1); 287 } 288 } 289 290 /* 291 * Register SP (Serial Port) service on the same RFCOMM channel 292 * if requested. It appears that some cell phones are using so 293 * called "callback mechanism". In this scenario user is trying 294 * to connect his cell phone to the Internet, and, user's host 295 * computer is acting as the gateway server. It seems that it 296 * is not possible to tell the phone to just connect and start 297 * using the LAN service. Instead the user's host computer must 298 * "jump start" the phone by connecting to the phone's SP 299 * service. What happens next is the phone kills the existing 300 * connection and opens another connection back to the user's 301 * host computer. The phone really wants to use LAN service, 302 * but for whatever reason it looks for SP service on the 303 * user's host computer. This brain damaged behavior was 304 * reported for Nokia 6600 and Sony/Ericsson P900. Both phones 305 * are Symbian-based phones. Perhaps this is a Symbian problem? 306 */ 307 308 if (regsp) { 309 sdp_sp_profile_t sp; 310 311 memset(&sp, 0, sizeof(sp)); 312 sp.server_channel = channel; 313 314 if (sdp_register_service(ss, 315 SDP_SERVICE_CLASS_SERIAL_PORT, 316 &addr, (void *) &sp, sizeof(sp), 317 NULL) != 0) { 318 syslog(LOG_ERR, "Unable to register SP " \ 319 "service with local SDP daemon. " \ 320 "%s (%d)", strerror(sdp_error(ss)), 321 sdp_error(ss)); 322 exit(1); 323 } 324 } 325 326 for (done = 0; !done; ) { 327 socklen_t len = sizeof(sock_addr); 328 int s1 = accept(s, (struct sockaddr *) &sock_addr, &len); 329 330 if (s1 < 0) { 331 syslog(LOG_ERR, "Could not accept connection " \ 332 "on socket. %s (%d)", strerror(errno), 333 errno); 334 exit(1); 335 } 336 337 pid = fork(); 338 if (pid == (pid_t) -1) { 339 syslog(LOG_ERR, "Could not fork(). %s (%d)", 340 strerror(errno), errno); 341 exit(1); 342 } 343 344 if (pid == 0) { 345 sdp_close(ss); 346 close(s); 347 348 /* Reset signal handler */ 349 memset(&sa, 0, sizeof(sa)); 350 sa.sa_handler = SIG_DFL; 351 352 sigaction(SIGTERM, &sa, NULL); 353 sigaction(SIGHUP, &sa, NULL); 354 sigaction(SIGINT, &sa, NULL); 355 sigaction(SIGCHLD, &sa, NULL); 356 357 /* Become daemon */ 358 daemon(0, 0); 359 360 /* 361 * XXX Make sure user does not shoot himself 362 * in the foot. Do not pass unit option to the 363 * PPP when operating in the server mode. 364 */ 365 366 exec_ppp(s1, NULL, label); 367 } else 368 close(s1); 369 } 370 } else { 371 sock_addr.rfcomm_len = sizeof(sock_addr); 372 sock_addr.rfcomm_family = AF_BLUETOOTH; 373 memcpy(&sock_addr.rfcomm_bdaddr, NG_HCI_BDADDR_ANY, 374 sizeof(sock_addr.rfcomm_bdaddr)); 375 sock_addr.rfcomm_channel = 0; 376 377 if (bind(s, (struct sockaddr *) &sock_addr, 378 sizeof(sock_addr)) < 0) { 379 syslog(LOG_ERR, "Could not bind socket. %s (%d)", 380 strerror(errno), errno); 381 exit(1); 382 } 383 384 memcpy(&sock_addr.rfcomm_bdaddr, &addr, 385 sizeof(sock_addr.rfcomm_bdaddr)); 386 sock_addr.rfcomm_channel = channel; 387 388 if (connect(s, (struct sockaddr *) &sock_addr, 389 sizeof(sock_addr)) < 0) { 390 syslog(LOG_ERR, "Could not connect socket. %s (%d)", 391 strerror(errno), errno); 392 exit(1); 393 } 394 395 exec_ppp(s, unit, label); 396 } 397 398 exit(0); 399 } /* main */ 400 401 /* 402 * Redirects stdin/stdout to s, stderr to /dev/null and exec 403 * 'ppp -direct -quiet [-unit N] label'. Never returns. 404 */ 405 406 static void 407 exec_ppp(int s, char *unit, char *label) 408 { 409 char ppp[] = "/usr/sbin/ppp"; 410 char *ppp_args[] = { ppp, "-direct", "-quiet", 411 NULL, NULL, NULL, NULL }; 412 413 close(0); 414 if (dup(s) < 0) { 415 syslog(LOG_ERR, "Could not dup(0). %s (%d)", 416 strerror(errno), errno); 417 exit(1); 418 } 419 420 close(1); 421 if (dup(s) < 0) { 422 syslog(LOG_ERR, "Could not dup(1). %s (%d)", 423 strerror(errno), errno); 424 exit(1); 425 } 426 427 close(2); 428 open("/dev/null", O_RDWR); 429 430 if (unit != NULL) { 431 ppp_args[3] = "-unit"; 432 ppp_args[4] = unit; 433 ppp_args[5] = label; 434 } else 435 ppp_args[3] = label; 436 437 if (execv(ppp, ppp_args) < 0) { 438 syslog(LOG_ERR, "Could not exec(%s -direct -quiet%s%s %s). " \ 439 "%s (%d)", ppp, (unit != NULL)? " -unit " : "", 440 (unit != NULL)? unit : "", label, 441 strerror(errno), errno); 442 exit(1); 443 } 444 } /* run_ppp */ 445 446 /* Signal handler */ 447 static void 448 sighandler(int s) 449 { 450 done = 1; 451 } /* sighandler */ 452 453 /* Display usage and exit */ 454 static void 455 usage(void) 456 { 457 fprintf(stdout, 458 "Usage: %s options\n" \ 459 "Where options are:\n" \ 460 "\t-a address Address to listen on or connect to (required for client)\n" \ 461 "\t-c Act as a clinet (default)\n" \ 462 "\t-C channel RFCOMM channel to listen on or connect to (required)\n" \ 463 "\t-d Run in foreground\n" \ 464 "\t-D Register Dial-Up Networking service (server mode only)\n" \ 465 "\t-l label Use PPP label (required)\n" \ 466 "\t-s Act as a server\n" \ 467 "\t-S Register Serial Port service (server mode only)\n" \ 468 "\t-u N Tell PPP to operate on /dev/tunN (client mode only)\n" \ 469 "\t-h Display this message\n", RFCOMM_PPPD); 470 471 exit(255); 472 } /* usage */ 473 474