1114879Sjulian/* 2114879Sjulian * rfcomm_pppd.c 3177174Semax */ 4177174Semax 5177174Semax/*- 6330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 7330449Seadler * 8177174Semax * Copyright (c) 2001-2008 Maksim Yevmenkin <m_evmenkin@yahoo.com> 9114879Sjulian * All rights reserved. 10114879Sjulian * 11114879Sjulian * Redistribution and use in source and binary forms, with or without 12114879Sjulian * modification, are permitted provided that the following conditions 13114879Sjulian * are met: 14114879Sjulian * 1. Redistributions of source code must retain the above copyright 15114879Sjulian * notice, this list of conditions and the following disclaimer. 16114879Sjulian * 2. Redistributions in binary form must reproduce the above copyright 17114879Sjulian * notice, this list of conditions and the following disclaimer in the 18114879Sjulian * documentation and/or other materials provided with the distribution. 19114879Sjulian * 20114879Sjulian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21114879Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22114879Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23114879Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24114879Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25114879Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26114879Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27114879Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28114879Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29114879Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30114879Sjulian * SUCH DAMAGE. 31114879Sjulian * 32121054Semax * $Id: rfcomm_pppd.c,v 1.5 2003/09/07 18:32:11 max Exp $ 33114879Sjulian * $FreeBSD: stable/11/usr.sbin/bluetooth/rfcomm_pppd/rfcomm_pppd.c 330449 2018-03-05 07:26:05Z eadler $ 34114879Sjulian */ 35281210Stakawata#define L2CAP_SOCKET_CHECKED 36121054Semax#include <bluetooth.h> 37121054Semax#include <ctype.h> 38121054Semax#include <err.h> 39114879Sjulian#include <errno.h> 40114879Sjulian#include <fcntl.h> 41121054Semax#include <sdp.h> 42114879Sjulian#include <signal.h> 43114879Sjulian#include <stdarg.h> 44114879Sjulian#include <stdio.h> 45114879Sjulian#include <stdlib.h> 46114879Sjulian#include <string.h> 47114879Sjulian#include <syslog.h> 48114879Sjulian#include <unistd.h> 49114879Sjulian 50114879Sjulian#define RFCOMM_PPPD "rfcomm_pppd" 51114879Sjulian 52121054Semaxint rfcomm_channel_lookup (bdaddr_t const *local, 53121054Semax bdaddr_t const *remote, 54121054Semax int service, int *channel, int *error); 55121054Semax 56126169Semaxstatic void exec_ppp (int s, char *unit, char *label); 57114879Sjulianstatic void sighandler (int s); 58114879Sjulianstatic void usage (void); 59114879Sjulian 60114879Sjulianstatic int done; 61114879Sjulian 62114879Sjulian/* Main */ 63114879Sjulianint 64114879Sjulianmain(int argc, char *argv[]) 65114879Sjulian{ 66114879Sjulian struct sockaddr_rfcomm sock_addr; 67126169Semax char *label = NULL, *unit = NULL, *ep = NULL; 68114879Sjulian bdaddr_t addr; 69176857Semax int s, channel, detach, server, service, 70176857Semax regdun, regsp; 71114879Sjulian pid_t pid; 72114879Sjulian 73114879Sjulian memcpy(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)); 74114879Sjulian channel = 0; 75114879Sjulian detach = 1; 76114879Sjulian server = 0; 77121054Semax service = 0; 78176857Semax regdun = 0; 79132711Semax regsp = 0; 80114879Sjulian 81114879Sjulian /* Parse command line arguments */ 82176857Semax while ((s = getopt(argc, argv, "a:cC:dDhl:sSu:")) != -1) { 83114879Sjulian switch (s) { 84121054Semax case 'a': /* BDADDR */ 85121054Semax if (!bt_aton(optarg, &addr)) { 86121054Semax struct hostent *he = NULL; 87114879Sjulian 88121054Semax if ((he = bt_gethostbyname(optarg)) == NULL) 89121054Semax errx(1, "%s: %s", optarg, hstrerror(h_errno)); 90114879Sjulian 91121054Semax memcpy(&addr, he->h_addr, sizeof(addr)); 92121054Semax } 93121054Semax break; 94114879Sjulian 95114879Sjulian case 'c': /* client */ 96114879Sjulian server = 0; 97114879Sjulian break; 98114879Sjulian 99114879Sjulian case 'C': /* RFCOMM channel */ 100121054Semax channel = strtoul(optarg, &ep, 10); 101126169Semax if (*ep != '\0') { 102121054Semax channel = 0; 103121054Semax switch (tolower(optarg[0])) { 104121054Semax case 'd': /* DialUp Networking */ 105121054Semax service = SDP_SERVICE_CLASS_DIALUP_NETWORKING; 106121054Semax break; 107121054Semax 108121054Semax case 'l': /* LAN Access Using PPP */ 109121054Semax service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP; 110121054Semax break; 111121054Semax } 112121054Semax } 113114879Sjulian break; 114114879Sjulian 115114879Sjulian case 'd': /* do not detach */ 116114879Sjulian detach = 0; 117114879Sjulian break; 118114879Sjulian 119176857Semax case 'D': /* Register DUN service as well as LAN service */ 120176857Semax regdun = 1; 121176857Semax break; 122176857Semax 123114879Sjulian case 'l': /* PPP label */ 124114879Sjulian label = optarg; 125114879Sjulian break; 126114879Sjulian 127126169Semax case 's': /* server */ 128114879Sjulian server = 1; 129114879Sjulian break; 130114879Sjulian 131132711Semax case 'S': /* Register SP service as well as LAN service */ 132132711Semax regsp = 1; 133132711Semax break; 134132711Semax 135126169Semax case 'u': /* PPP -unit option */ 136126169Semax strtoul(optarg, &ep, 10); 137126169Semax if (*ep != '\0') 138126169Semax usage(); 139126169Semax /* NOT REACHED */ 140126169Semax 141126169Semax unit = optarg; 142126169Semax break; 143126169Semax 144114879Sjulian case 'h': 145114879Sjulian default: 146114879Sjulian usage(); 147114879Sjulian /* NOT REACHED */ 148114879Sjulian } 149114879Sjulian } 150114879Sjulian 151114879Sjulian /* Check if we got everything we wanted */ 152121054Semax if (label == NULL) 153121054Semax errx(1, "Must specify PPP label"); 154114879Sjulian 155121054Semax if (!server) { 156121054Semax if (memcmp(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)) == 0) 157121054Semax errx(1, "Must specify server BD_ADDR"); 158121054Semax 159121054Semax /* Check channel, if was not set then obtain it via SDP */ 160121054Semax if (channel == 0 && service != 0) 161121054Semax if (rfcomm_channel_lookup(NULL, &addr, service, 162121054Semax &channel, &s) != 0) 163121054Semax errc(1, s, "Could not obtain RFCOMM channel"); 164121054Semax } 165121054Semax 166121054Semax if (channel <= 0 || channel > 30) 167121054Semax errx(1, "Invalid RFCOMM channel number %d", channel); 168121054Semax 169114879Sjulian openlog(RFCOMM_PPPD, LOG_PID | LOG_PERROR | LOG_NDELAY, LOG_USER); 170114879Sjulian 171188130Semax if (detach && daemon(0, 0) < 0) { 172188130Semax syslog(LOG_ERR, "Could not daemon(0, 0). %s (%d)", 173188130Semax strerror(errno), errno); 174188130Semax exit(1); 175114879Sjulian } 176114879Sjulian 177114879Sjulian s = socket(PF_BLUETOOTH, SOCK_STREAM, BLUETOOTH_PROTO_RFCOMM); 178114879Sjulian if (s < 0) { 179114879Sjulian syslog(LOG_ERR, "Could not create socket. %s (%d)", 180114879Sjulian strerror(errno), errno); 181114879Sjulian exit(1); 182114879Sjulian } 183114879Sjulian 184114879Sjulian if (server) { 185126169Semax struct sigaction sa; 186126169Semax void *ss = NULL; 187126169Semax sdp_lan_profile_t lan; 188114879Sjulian 189114879Sjulian /* Install signal handler */ 190114879Sjulian memset(&sa, 0, sizeof(sa)); 191114879Sjulian sa.sa_handler = sighandler; 192114879Sjulian 193114879Sjulian if (sigaction(SIGTERM, &sa, NULL) < 0) { 194114879Sjulian syslog(LOG_ERR, "Could not sigaction(SIGTERM). %s (%d)", 195114879Sjulian strerror(errno), errno); 196114879Sjulian exit(1); 197114879Sjulian } 198114879Sjulian 199114879Sjulian if (sigaction(SIGHUP, &sa, NULL) < 0) { 200114879Sjulian syslog(LOG_ERR, "Could not sigaction(SIGHUP). %s (%d)", 201114879Sjulian strerror(errno), errno); 202114879Sjulian exit(1); 203114879Sjulian } 204114879Sjulian 205114879Sjulian if (sigaction(SIGINT, &sa, NULL) < 0) { 206114879Sjulian syslog(LOG_ERR, "Could not sigaction(SIGINT). %s (%d)", 207114879Sjulian strerror(errno), errno); 208114879Sjulian exit(1); 209114879Sjulian } 210114879Sjulian 211114879Sjulian sa.sa_handler = SIG_IGN; 212114879Sjulian sa.sa_flags = SA_NOCLDWAIT; 213114879Sjulian 214114879Sjulian if (sigaction(SIGCHLD, &sa, NULL) < 0) { 215114879Sjulian syslog(LOG_ERR, "Could not sigaction(SIGCHLD). %s (%d)", 216114879Sjulian strerror(errno), errno); 217114879Sjulian exit(1); 218114879Sjulian } 219114879Sjulian 220114879Sjulian /* bind socket and listen for incoming connections */ 221114879Sjulian sock_addr.rfcomm_len = sizeof(sock_addr); 222114879Sjulian sock_addr.rfcomm_family = AF_BLUETOOTH; 223114879Sjulian memcpy(&sock_addr.rfcomm_bdaddr, &addr, 224114879Sjulian sizeof(sock_addr.rfcomm_bdaddr)); 225114879Sjulian sock_addr.rfcomm_channel = channel; 226114879Sjulian 227114879Sjulian if (bind(s, (struct sockaddr *) &sock_addr, 228114879Sjulian sizeof(sock_addr)) < 0) { 229114879Sjulian syslog(LOG_ERR, "Could not bind socket. %s (%d)", 230114879Sjulian strerror(errno), errno); 231114879Sjulian exit(1); 232114879Sjulian } 233114879Sjulian 234114879Sjulian if (listen(s, 10) < 0) { 235114879Sjulian syslog(LOG_ERR, "Could not listen on socket. %s (%d)", 236114879Sjulian strerror(errno), errno); 237114879Sjulian exit(1); 238114879Sjulian } 239114879Sjulian 240126169Semax ss = sdp_open_local(NULL); 241126169Semax if (ss == NULL) { 242126169Semax syslog(LOG_ERR, "Unable to create local SDP session"); 243126169Semax exit(1); 244126169Semax } 245126169Semax 246126169Semax if (sdp_error(ss) != 0) { 247126169Semax syslog(LOG_ERR, "Unable to open local SDP session. " \ 248126169Semax "%s (%d)", strerror(sdp_error(ss)), 249126169Semax sdp_error(ss)); 250126169Semax exit(1); 251126169Semax } 252126169Semax 253126169Semax memset(&lan, 0, sizeof(lan)); 254126169Semax lan.server_channel = channel; 255126169Semax 256126169Semax if (sdp_register_service(ss, 257126169Semax SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP, 258126169Semax &addr, (void *) &lan, sizeof(lan), NULL) != 0) { 259126169Semax syslog(LOG_ERR, "Unable to register LAN service with " \ 260126169Semax "local SDP daemon. %s (%d)", 261126169Semax strerror(sdp_error(ss)), sdp_error(ss)); 262126169Semax exit(1); 263126169Semax } 264132711Semax 265132711Semax /* 266176857Semax * Register DUN (Dial-Up Networking) service on the same 267176857Semax * RFCOMM channel if requested. There is really no good reason 268176857Semax * to not to support this. AT-command exchange can be faked 269176857Semax * with chat script in ppp.conf 270176857Semax */ 271176857Semax 272176857Semax if (regdun) { 273176857Semax sdp_dun_profile_t dun; 274176857Semax 275176857Semax memset(&dun, 0, sizeof(dun)); 276176857Semax dun.server_channel = channel; 277176857Semax 278176857Semax if (sdp_register_service(ss, 279176857Semax SDP_SERVICE_CLASS_DIALUP_NETWORKING, 280176857Semax &addr, (void *) &dun, sizeof(dun), 281176857Semax NULL) != 0) { 282176857Semax syslog(LOG_ERR, "Unable to register DUN " \ 283176857Semax "service with local SDP daemon. " \ 284176857Semax "%s (%d)", strerror(sdp_error(ss)), 285176857Semax sdp_error(ss)); 286176857Semax exit(1); 287176857Semax } 288176857Semax } 289176857Semax 290176857Semax /* 291132711Semax * Register SP (Serial Port) service on the same RFCOMM channel 292132711Semax * if requested. It appears that some cell phones are using so 293132711Semax * called "callback mechanism". In this scenario user is trying 294132711Semax * to connect his cell phone to the Internet, and, user's host 295132711Semax * computer is acting as the gateway server. It seems that it 296132711Semax * is not possible to tell the phone to just connect and start 297132711Semax * using the LAN service. Instead the user's host computer must 298132711Semax * "jump start" the phone by connecting to the phone's SP 299132711Semax * service. What happens next is the phone kills the existing 300132711Semax * connection and opens another connection back to the user's 301132711Semax * host computer. The phone really wants to use LAN service, 302132711Semax * but for whatever reason it looks for SP service on the 303132711Semax * user's host computer. This brain damaged behavior was 304132711Semax * reported for Nokia 6600 and Sony/Ericsson P900. Both phones 305132711Semax * are Symbian-based phones. Perhaps this is a Symbian problem? 306132711Semax */ 307132711Semax 308132711Semax if (regsp) { 309132711Semax sdp_sp_profile_t sp; 310132711Semax 311132711Semax memset(&sp, 0, sizeof(sp)); 312132711Semax sp.server_channel = channel; 313132711Semax 314132711Semax if (sdp_register_service(ss, 315132711Semax SDP_SERVICE_CLASS_SERIAL_PORT, 316132711Semax &addr, (void *) &sp, sizeof(sp), 317132711Semax NULL) != 0) { 318132711Semax syslog(LOG_ERR, "Unable to register SP " \ 319132711Semax "service with local SDP daemon. " \ 320132711Semax "%s (%d)", strerror(sdp_error(ss)), 321132711Semax sdp_error(ss)); 322132711Semax exit(1); 323132711Semax } 324132711Semax } 325126169Semax 326114879Sjulian for (done = 0; !done; ) { 327162494Semax socklen_t len = sizeof(sock_addr); 328162494Semax int s1 = accept(s, (struct sockaddr *) &sock_addr, &len); 329114879Sjulian 330114879Sjulian if (s1 < 0) { 331114879Sjulian syslog(LOG_ERR, "Could not accept connection " \ 332114879Sjulian "on socket. %s (%d)", strerror(errno), 333114879Sjulian errno); 334114879Sjulian exit(1); 335114879Sjulian } 336114879Sjulian 337114879Sjulian pid = fork(); 338114879Sjulian if (pid == (pid_t) -1) { 339114879Sjulian syslog(LOG_ERR, "Could not fork(). %s (%d)", 340114879Sjulian strerror(errno), errno); 341114879Sjulian exit(1); 342114879Sjulian } 343114879Sjulian 344114879Sjulian if (pid == 0) { 345126169Semax sdp_close(ss); 346114879Sjulian close(s); 347114879Sjulian 348114879Sjulian /* Reset signal handler */ 349114879Sjulian memset(&sa, 0, sizeof(sa)); 350114879Sjulian sa.sa_handler = SIG_DFL; 351114879Sjulian 352114879Sjulian sigaction(SIGTERM, &sa, NULL); 353114879Sjulian sigaction(SIGHUP, &sa, NULL); 354114879Sjulian sigaction(SIGINT, &sa, NULL); 355114879Sjulian sigaction(SIGCHLD, &sa, NULL); 356114879Sjulian 357114879Sjulian /* Become daemon */ 358114879Sjulian daemon(0, 0); 359114879Sjulian 360126169Semax /* 361126169Semax * XXX Make sure user does not shoot himself 362126169Semax * in the foot. Do not pass unit option to the 363126169Semax * PPP when operating in the server mode. 364126169Semax */ 365126169Semax 366126169Semax exec_ppp(s1, NULL, label); 367114879Sjulian } else 368114879Sjulian close(s1); 369114879Sjulian } 370114879Sjulian } else { 371114879Sjulian sock_addr.rfcomm_len = sizeof(sock_addr); 372114879Sjulian sock_addr.rfcomm_family = AF_BLUETOOTH; 373114879Sjulian memcpy(&sock_addr.rfcomm_bdaddr, NG_HCI_BDADDR_ANY, 374114879Sjulian sizeof(sock_addr.rfcomm_bdaddr)); 375114879Sjulian sock_addr.rfcomm_channel = 0; 376114879Sjulian 377114879Sjulian if (bind(s, (struct sockaddr *) &sock_addr, 378114879Sjulian sizeof(sock_addr)) < 0) { 379114879Sjulian syslog(LOG_ERR, "Could not bind socket. %s (%d)", 380114879Sjulian strerror(errno), errno); 381114879Sjulian exit(1); 382114879Sjulian } 383114879Sjulian 384114879Sjulian memcpy(&sock_addr.rfcomm_bdaddr, &addr, 385114879Sjulian sizeof(sock_addr.rfcomm_bdaddr)); 386114879Sjulian sock_addr.rfcomm_channel = channel; 387114879Sjulian 388114879Sjulian if (connect(s, (struct sockaddr *) &sock_addr, 389114879Sjulian sizeof(sock_addr)) < 0) { 390114879Sjulian syslog(LOG_ERR, "Could not connect socket. %s (%d)", 391114879Sjulian strerror(errno), errno); 392114879Sjulian exit(1); 393114879Sjulian } 394114879Sjulian 395126169Semax exec_ppp(s, unit, label); 396114879Sjulian } 397114879Sjulian 398114879Sjulian exit(0); 399114879Sjulian} /* main */ 400114879Sjulian 401114879Sjulian/* 402126169Semax * Redirects stdin/stdout to s, stderr to /dev/null and exec 403126169Semax * 'ppp -direct -quiet [-unit N] label'. Never returns. 404114879Sjulian */ 405114879Sjulian 406114879Sjulianstatic void 407126169Semaxexec_ppp(int s, char *unit, char *label) 408114879Sjulian{ 409114879Sjulian char ppp[] = "/usr/sbin/ppp"; 410126169Semax char *ppp_args[] = { ppp, "-direct", "-quiet", 411126169Semax NULL, NULL, NULL, NULL }; 412114879Sjulian 413114879Sjulian close(0); 414114879Sjulian if (dup(s) < 0) { 415114879Sjulian syslog(LOG_ERR, "Could not dup(0). %s (%d)", 416114879Sjulian strerror(errno), errno); 417114879Sjulian exit(1); 418114879Sjulian } 419114879Sjulian 420114879Sjulian close(1); 421114879Sjulian if (dup(s) < 0) { 422114879Sjulian syslog(LOG_ERR, "Could not dup(1). %s (%d)", 423114879Sjulian strerror(errno), errno); 424114879Sjulian exit(1); 425114879Sjulian } 426114879Sjulian 427114879Sjulian close(2); 428114879Sjulian open("/dev/null", O_RDWR); 429114879Sjulian 430126169Semax if (unit != NULL) { 431126169Semax ppp_args[3] = "-unit"; 432126169Semax ppp_args[4] = unit; 433126169Semax ppp_args[5] = label; 434126169Semax } else 435126169Semax ppp_args[3] = label; 436126169Semax 437114879Sjulian if (execv(ppp, ppp_args) < 0) { 438126169Semax syslog(LOG_ERR, "Could not exec(%s -direct -quiet%s%s %s). " \ 439126169Semax "%s (%d)", ppp, (unit != NULL)? " -unit " : "", 440126169Semax (unit != NULL)? unit : "", label, 441126169Semax strerror(errno), errno); 442114879Sjulian exit(1); 443114879Sjulian } 444114879Sjulian} /* run_ppp */ 445114879Sjulian 446114879Sjulian/* Signal handler */ 447114879Sjulianstatic void 448114879Sjuliansighandler(int s) 449114879Sjulian{ 450114879Sjulian done = 1; 451114879Sjulian} /* sighandler */ 452114879Sjulian 453114879Sjulian/* Display usage and exit */ 454114879Sjulianstatic void 455114879Sjulianusage(void) 456114879Sjulian{ 457114879Sjulian fprintf(stdout, 458114879Sjulian"Usage: %s options\n" \ 459114879Sjulian"Where options are:\n" \ 460133178Semax"\t-a address Address to listen on or connect to (required for client)\n" \ 461114879Sjulian"\t-c Act as a clinet (default)\n" \ 462114879Sjulian"\t-C channel RFCOMM channel to listen on or connect to (required)\n" \ 463114879Sjulian"\t-d Run in foreground\n" \ 464177174Semax"\t-D Register Dial-Up Networking service (server mode only)\n" \ 465114879Sjulian"\t-l label Use PPP label (required)\n" \ 466114879Sjulian"\t-s Act as a server\n" \ 467132711Semax"\t-S Register Serial Port service (server mode only)\n" \ 468126169Semax"\t-u N Tell PPP to operate on /dev/tunN (client mode only)\n" \ 469114879Sjulian"\t-h Display this message\n", RFCOMM_PPPD); 470114879Sjulian 471114879Sjulian exit(255); 472114879Sjulian} /* usage */ 473114879Sjulian 474