11a63eb31SJulian Elischer /* 21a63eb31SJulian Elischer * rfcomm_pppd.c 31a63eb31SJulian Elischer * 41a63eb31SJulian Elischer * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com> 51a63eb31SJulian Elischer * All rights reserved. 61a63eb31SJulian Elischer * 71a63eb31SJulian Elischer * Redistribution and use in source and binary forms, with or without 81a63eb31SJulian Elischer * modification, are permitted provided that the following conditions 91a63eb31SJulian Elischer * are met: 101a63eb31SJulian Elischer * 1. Redistributions of source code must retain the above copyright 111a63eb31SJulian Elischer * notice, this list of conditions and the following disclaimer. 121a63eb31SJulian Elischer * 2. Redistributions in binary form must reproduce the above copyright 131a63eb31SJulian Elischer * notice, this list of conditions and the following disclaimer in the 141a63eb31SJulian Elischer * documentation and/or other materials provided with the distribution. 151a63eb31SJulian Elischer * 161a63eb31SJulian Elischer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 171a63eb31SJulian Elischer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 181a63eb31SJulian Elischer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 191a63eb31SJulian Elischer * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 201a63eb31SJulian Elischer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 211a63eb31SJulian Elischer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 221a63eb31SJulian Elischer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 231a63eb31SJulian Elischer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 241a63eb31SJulian Elischer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 251a63eb31SJulian Elischer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 261a63eb31SJulian Elischer * SUCH DAMAGE. 271a63eb31SJulian Elischer * 280986ab12SMaksim Yevmenkin * $Id: rfcomm_pppd.c,v 1.5 2003/09/07 18:32:11 max Exp $ 291a63eb31SJulian Elischer * $FreeBSD$ 301a63eb31SJulian Elischer */ 311a63eb31SJulian Elischer 320986ab12SMaksim Yevmenkin #include <bluetooth.h> 330986ab12SMaksim Yevmenkin #include <ctype.h> 340986ab12SMaksim Yevmenkin #include <err.h> 351a63eb31SJulian Elischer #include <errno.h> 361a63eb31SJulian Elischer #include <fcntl.h> 370986ab12SMaksim Yevmenkin #include <sdp.h> 381a63eb31SJulian Elischer #include <signal.h> 391a63eb31SJulian Elischer #include <stdarg.h> 401a63eb31SJulian Elischer #include <stdio.h> 411a63eb31SJulian Elischer #include <stdlib.h> 421a63eb31SJulian Elischer #include <string.h> 431a63eb31SJulian Elischer #include <syslog.h> 441a63eb31SJulian Elischer #include <unistd.h> 451a63eb31SJulian Elischer 461a63eb31SJulian Elischer #define RFCOMM_PPPD "rfcomm_pppd" 471a63eb31SJulian Elischer 480986ab12SMaksim Yevmenkin int rfcomm_channel_lookup (bdaddr_t const *local, 490986ab12SMaksim Yevmenkin bdaddr_t const *remote, 500986ab12SMaksim Yevmenkin int service, int *channel, int *error); 510986ab12SMaksim Yevmenkin 5213706e45SMaksim Yevmenkin static void exec_ppp (int s, char *unit, char *label); 531a63eb31SJulian Elischer static void sighandler (int s); 541a63eb31SJulian Elischer static void usage (void); 551a63eb31SJulian Elischer 561a63eb31SJulian Elischer static int done; 571a63eb31SJulian Elischer 581a63eb31SJulian Elischer /* Main */ 591a63eb31SJulian Elischer int 601a63eb31SJulian Elischer main(int argc, char *argv[]) 611a63eb31SJulian Elischer { 621a63eb31SJulian Elischer struct sockaddr_rfcomm sock_addr; 6313706e45SMaksim Yevmenkin char *label = NULL, *unit = NULL, *ep = NULL; 641a63eb31SJulian Elischer bdaddr_t addr; 65b1fae135SMaksim Yevmenkin int s, channel, detach, server, service, 66b1fae135SMaksim Yevmenkin regdun, regsp; 671a63eb31SJulian Elischer pid_t pid; 681a63eb31SJulian Elischer 691a63eb31SJulian Elischer memcpy(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)); 701a63eb31SJulian Elischer channel = 0; 711a63eb31SJulian Elischer detach = 1; 721a63eb31SJulian Elischer server = 0; 730986ab12SMaksim Yevmenkin service = 0; 74b1fae135SMaksim Yevmenkin regdun = 0; 751985a3a3SMaksim Yevmenkin regsp = 0; 761a63eb31SJulian Elischer 771a63eb31SJulian Elischer /* Parse command line arguments */ 78b1fae135SMaksim Yevmenkin while ((s = getopt(argc, argv, "a:cC:dDhl:sSu:")) != -1) { 791a63eb31SJulian Elischer switch (s) { 800986ab12SMaksim Yevmenkin case 'a': /* BDADDR */ 810986ab12SMaksim Yevmenkin if (!bt_aton(optarg, &addr)) { 820986ab12SMaksim Yevmenkin struct hostent *he = NULL; 831a63eb31SJulian Elischer 840986ab12SMaksim Yevmenkin if ((he = bt_gethostbyname(optarg)) == NULL) 850986ab12SMaksim Yevmenkin errx(1, "%s: %s", optarg, hstrerror(h_errno)); 861a63eb31SJulian Elischer 870986ab12SMaksim Yevmenkin memcpy(&addr, he->h_addr, sizeof(addr)); 880986ab12SMaksim Yevmenkin } 890986ab12SMaksim Yevmenkin break; 901a63eb31SJulian Elischer 911a63eb31SJulian Elischer case 'c': /* client */ 921a63eb31SJulian Elischer server = 0; 931a63eb31SJulian Elischer break; 941a63eb31SJulian Elischer 951a63eb31SJulian Elischer case 'C': /* RFCOMM channel */ 960986ab12SMaksim Yevmenkin channel = strtoul(optarg, &ep, 10); 9713706e45SMaksim Yevmenkin if (*ep != '\0') { 980986ab12SMaksim Yevmenkin channel = 0; 990986ab12SMaksim Yevmenkin switch (tolower(optarg[0])) { 1000986ab12SMaksim Yevmenkin case 'd': /* DialUp Networking */ 1010986ab12SMaksim Yevmenkin service = SDP_SERVICE_CLASS_DIALUP_NETWORKING; 1020986ab12SMaksim Yevmenkin break; 1030986ab12SMaksim Yevmenkin 1040986ab12SMaksim Yevmenkin case 'l': /* LAN Access Using PPP */ 1050986ab12SMaksim Yevmenkin service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP; 1060986ab12SMaksim Yevmenkin break; 1070986ab12SMaksim Yevmenkin } 1080986ab12SMaksim Yevmenkin } 1091a63eb31SJulian Elischer break; 1101a63eb31SJulian Elischer 1111a63eb31SJulian Elischer case 'd': /* do not detach */ 1121a63eb31SJulian Elischer detach = 0; 1131a63eb31SJulian Elischer break; 1141a63eb31SJulian Elischer 115b1fae135SMaksim Yevmenkin case 'D': /* Register DUN service as well as LAN service */ 116b1fae135SMaksim Yevmenkin regdun = 1; 117b1fae135SMaksim Yevmenkin break; 118b1fae135SMaksim Yevmenkin 1191a63eb31SJulian Elischer case 'l': /* PPP label */ 1201a63eb31SJulian Elischer label = optarg; 1211a63eb31SJulian Elischer break; 1221a63eb31SJulian Elischer 12313706e45SMaksim Yevmenkin case 's': /* server */ 1241a63eb31SJulian Elischer server = 1; 1251a63eb31SJulian Elischer break; 1261a63eb31SJulian Elischer 1271985a3a3SMaksim Yevmenkin case 'S': /* Register SP service as well as LAN service */ 1281985a3a3SMaksim Yevmenkin regsp = 1; 1291985a3a3SMaksim Yevmenkin break; 1301985a3a3SMaksim Yevmenkin 13113706e45SMaksim Yevmenkin case 'u': /* PPP -unit option */ 13213706e45SMaksim Yevmenkin strtoul(optarg, &ep, 10); 13313706e45SMaksim Yevmenkin if (*ep != '\0') 13413706e45SMaksim Yevmenkin usage(); 13513706e45SMaksim Yevmenkin /* NOT REACHED */ 13613706e45SMaksim Yevmenkin 13713706e45SMaksim Yevmenkin unit = optarg; 13813706e45SMaksim Yevmenkin break; 13913706e45SMaksim Yevmenkin 1401a63eb31SJulian Elischer case 'h': 1411a63eb31SJulian Elischer default: 1421a63eb31SJulian Elischer usage(); 1431a63eb31SJulian Elischer /* NOT REACHED */ 1441a63eb31SJulian Elischer } 1451a63eb31SJulian Elischer } 1461a63eb31SJulian Elischer 1471a63eb31SJulian Elischer /* Check if we got everything we wanted */ 1480986ab12SMaksim Yevmenkin if (label == NULL) 1490986ab12SMaksim Yevmenkin errx(1, "Must specify PPP label"); 1500986ab12SMaksim Yevmenkin 1510986ab12SMaksim Yevmenkin if (!server) { 1520986ab12SMaksim Yevmenkin if (memcmp(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)) == 0) 1530986ab12SMaksim Yevmenkin errx(1, "Must specify server BD_ADDR"); 1540986ab12SMaksim Yevmenkin 1550986ab12SMaksim Yevmenkin /* Check channel, if was not set then obtain it via SDP */ 1560986ab12SMaksim Yevmenkin if (channel == 0 && service != 0) 1570986ab12SMaksim Yevmenkin if (rfcomm_channel_lookup(NULL, &addr, service, 1580986ab12SMaksim Yevmenkin &channel, &s) != 0) 1590986ab12SMaksim Yevmenkin errc(1, s, "Could not obtain RFCOMM channel"); 1600986ab12SMaksim Yevmenkin } 1610986ab12SMaksim Yevmenkin 1620986ab12SMaksim Yevmenkin if (channel <= 0 || channel > 30) 1630986ab12SMaksim Yevmenkin errx(1, "Invalid RFCOMM channel number %d", channel); 1641a63eb31SJulian Elischer 1651a63eb31SJulian Elischer openlog(RFCOMM_PPPD, LOG_PID | LOG_PERROR | LOG_NDELAY, LOG_USER); 1661a63eb31SJulian Elischer 1671a63eb31SJulian Elischer if (detach) { 1681a63eb31SJulian Elischer pid = fork(); 1691a63eb31SJulian Elischer if (pid == (pid_t) -1) { 1701a63eb31SJulian Elischer syslog(LOG_ERR, "Could not fork(). %s (%d)", 1711a63eb31SJulian Elischer strerror(errno), errno); 1721a63eb31SJulian Elischer exit(1); 1731a63eb31SJulian Elischer } 1741a63eb31SJulian Elischer 1751a63eb31SJulian Elischer if (pid != 0) 1761a63eb31SJulian Elischer exit(0); 1771a63eb31SJulian Elischer 1781a63eb31SJulian Elischer if (daemon(0, 0) < 0) { 1791a63eb31SJulian Elischer syslog(LOG_ERR, "Could not daemon(0, 0). %s (%d)", 1801a63eb31SJulian Elischer strerror(errno), errno); 1811a63eb31SJulian Elischer exit(1); 1821a63eb31SJulian Elischer } 1831a63eb31SJulian Elischer } 1841a63eb31SJulian Elischer 1851a63eb31SJulian Elischer s = socket(PF_BLUETOOTH, SOCK_STREAM, BLUETOOTH_PROTO_RFCOMM); 1861a63eb31SJulian Elischer if (s < 0) { 1871a63eb31SJulian Elischer syslog(LOG_ERR, "Could not create socket. %s (%d)", 1881a63eb31SJulian Elischer strerror(errno), errno); 1891a63eb31SJulian Elischer exit(1); 1901a63eb31SJulian Elischer } 1911a63eb31SJulian Elischer 1921a63eb31SJulian Elischer if (server) { 1931a63eb31SJulian Elischer struct sigaction sa; 19413706e45SMaksim Yevmenkin void *ss = NULL; 19513706e45SMaksim Yevmenkin sdp_lan_profile_t lan; 1961a63eb31SJulian Elischer 1971a63eb31SJulian Elischer /* Install signal handler */ 1981a63eb31SJulian Elischer memset(&sa, 0, sizeof(sa)); 1991a63eb31SJulian Elischer sa.sa_handler = sighandler; 2001a63eb31SJulian Elischer 2011a63eb31SJulian Elischer if (sigaction(SIGTERM, &sa, NULL) < 0) { 2021a63eb31SJulian Elischer syslog(LOG_ERR, "Could not sigaction(SIGTERM). %s (%d)", 2031a63eb31SJulian Elischer strerror(errno), errno); 2041a63eb31SJulian Elischer exit(1); 2051a63eb31SJulian Elischer } 2061a63eb31SJulian Elischer 2071a63eb31SJulian Elischer if (sigaction(SIGHUP, &sa, NULL) < 0) { 2081a63eb31SJulian Elischer syslog(LOG_ERR, "Could not sigaction(SIGHUP). %s (%d)", 2091a63eb31SJulian Elischer strerror(errno), errno); 2101a63eb31SJulian Elischer exit(1); 2111a63eb31SJulian Elischer } 2121a63eb31SJulian Elischer 2131a63eb31SJulian Elischer if (sigaction(SIGINT, &sa, NULL) < 0) { 2141a63eb31SJulian Elischer syslog(LOG_ERR, "Could not sigaction(SIGINT). %s (%d)", 2151a63eb31SJulian Elischer strerror(errno), errno); 2161a63eb31SJulian Elischer exit(1); 2171a63eb31SJulian Elischer } 2181a63eb31SJulian Elischer 2191a63eb31SJulian Elischer sa.sa_handler = SIG_IGN; 2201a63eb31SJulian Elischer sa.sa_flags = SA_NOCLDWAIT; 2211a63eb31SJulian Elischer 2221a63eb31SJulian Elischer if (sigaction(SIGCHLD, &sa, NULL) < 0) { 2231a63eb31SJulian Elischer syslog(LOG_ERR, "Could not sigaction(SIGCHLD). %s (%d)", 2241a63eb31SJulian Elischer strerror(errno), errno); 2251a63eb31SJulian Elischer exit(1); 2261a63eb31SJulian Elischer } 2271a63eb31SJulian Elischer 2281a63eb31SJulian Elischer /* bind socket and listen for incoming connections */ 2291a63eb31SJulian Elischer sock_addr.rfcomm_len = sizeof(sock_addr); 2301a63eb31SJulian Elischer sock_addr.rfcomm_family = AF_BLUETOOTH; 2311a63eb31SJulian Elischer memcpy(&sock_addr.rfcomm_bdaddr, &addr, 2321a63eb31SJulian Elischer sizeof(sock_addr.rfcomm_bdaddr)); 2331a63eb31SJulian Elischer sock_addr.rfcomm_channel = channel; 2341a63eb31SJulian Elischer 2351a63eb31SJulian Elischer if (bind(s, (struct sockaddr *) &sock_addr, 2361a63eb31SJulian Elischer sizeof(sock_addr)) < 0) { 2371a63eb31SJulian Elischer syslog(LOG_ERR, "Could not bind socket. %s (%d)", 2381a63eb31SJulian Elischer strerror(errno), errno); 2391a63eb31SJulian Elischer exit(1); 2401a63eb31SJulian Elischer } 2411a63eb31SJulian Elischer 2421a63eb31SJulian Elischer if (listen(s, 10) < 0) { 2431a63eb31SJulian Elischer syslog(LOG_ERR, "Could not listen on socket. %s (%d)", 2441a63eb31SJulian Elischer strerror(errno), errno); 2451a63eb31SJulian Elischer exit(1); 2461a63eb31SJulian Elischer } 2471a63eb31SJulian Elischer 24813706e45SMaksim Yevmenkin ss = sdp_open_local(NULL); 24913706e45SMaksim Yevmenkin if (ss == NULL) { 25013706e45SMaksim Yevmenkin syslog(LOG_ERR, "Unable to create local SDP session"); 25113706e45SMaksim Yevmenkin exit(1); 25213706e45SMaksim Yevmenkin } 25313706e45SMaksim Yevmenkin 25413706e45SMaksim Yevmenkin if (sdp_error(ss) != 0) { 25513706e45SMaksim Yevmenkin syslog(LOG_ERR, "Unable to open local SDP session. " \ 25613706e45SMaksim Yevmenkin "%s (%d)", strerror(sdp_error(ss)), 25713706e45SMaksim Yevmenkin sdp_error(ss)); 25813706e45SMaksim Yevmenkin exit(1); 25913706e45SMaksim Yevmenkin } 26013706e45SMaksim Yevmenkin 26113706e45SMaksim Yevmenkin memset(&lan, 0, sizeof(lan)); 26213706e45SMaksim Yevmenkin lan.server_channel = channel; 26313706e45SMaksim Yevmenkin 26413706e45SMaksim Yevmenkin if (sdp_register_service(ss, 26513706e45SMaksim Yevmenkin SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP, 26613706e45SMaksim Yevmenkin &addr, (void *) &lan, sizeof(lan), NULL) != 0) { 26713706e45SMaksim Yevmenkin syslog(LOG_ERR, "Unable to register LAN service with " \ 26813706e45SMaksim Yevmenkin "local SDP daemon. %s (%d)", 26913706e45SMaksim Yevmenkin strerror(sdp_error(ss)), sdp_error(ss)); 27013706e45SMaksim Yevmenkin exit(1); 27113706e45SMaksim Yevmenkin } 27213706e45SMaksim Yevmenkin 2731985a3a3SMaksim Yevmenkin /* 274b1fae135SMaksim Yevmenkin * Register DUN (Dial-Up Networking) service on the same 275b1fae135SMaksim Yevmenkin * RFCOMM channel if requested. There is really no good reason 276b1fae135SMaksim Yevmenkin * to not to support this. AT-command exchange can be faked 277b1fae135SMaksim Yevmenkin * with chat script in ppp.conf 278b1fae135SMaksim Yevmenkin */ 279b1fae135SMaksim Yevmenkin 280b1fae135SMaksim Yevmenkin if (regdun) { 281b1fae135SMaksim Yevmenkin sdp_dun_profile_t dun; 282b1fae135SMaksim Yevmenkin 283b1fae135SMaksim Yevmenkin memset(&dun, 0, sizeof(dun)); 284b1fae135SMaksim Yevmenkin dun.server_channel = channel; 285b1fae135SMaksim Yevmenkin 286b1fae135SMaksim Yevmenkin if (sdp_register_service(ss, 287b1fae135SMaksim Yevmenkin SDP_SERVICE_CLASS_DIALUP_NETWORKING, 288b1fae135SMaksim Yevmenkin &addr, (void *) &dun, sizeof(dun), 289b1fae135SMaksim Yevmenkin NULL) != 0) { 290b1fae135SMaksim Yevmenkin syslog(LOG_ERR, "Unable to register DUN " \ 291b1fae135SMaksim Yevmenkin "service with local SDP daemon. " \ 292b1fae135SMaksim Yevmenkin "%s (%d)", strerror(sdp_error(ss)), 293b1fae135SMaksim Yevmenkin sdp_error(ss)); 294b1fae135SMaksim Yevmenkin exit(1); 295b1fae135SMaksim Yevmenkin } 296b1fae135SMaksim Yevmenkin } 297b1fae135SMaksim Yevmenkin 298b1fae135SMaksim Yevmenkin /* 2991985a3a3SMaksim Yevmenkin * Register SP (Serial Port) service on the same RFCOMM channel 3001985a3a3SMaksim Yevmenkin * if requested. It appears that some cell phones are using so 3011985a3a3SMaksim Yevmenkin * called "callback mechanism". In this scenario user is trying 3021985a3a3SMaksim Yevmenkin * to connect his cell phone to the Internet, and, user's host 3031985a3a3SMaksim Yevmenkin * computer is acting as the gateway server. It seems that it 3041985a3a3SMaksim Yevmenkin * is not possible to tell the phone to just connect and start 3051985a3a3SMaksim Yevmenkin * using the LAN service. Instead the user's host computer must 3061985a3a3SMaksim Yevmenkin * "jump start" the phone by connecting to the phone's SP 3071985a3a3SMaksim Yevmenkin * service. What happens next is the phone kills the existing 3081985a3a3SMaksim Yevmenkin * connection and opens another connection back to the user's 3091985a3a3SMaksim Yevmenkin * host computer. The phone really wants to use LAN service, 3101985a3a3SMaksim Yevmenkin * but for whatever reason it looks for SP service on the 3111985a3a3SMaksim Yevmenkin * user's host computer. This brain damaged behavior was 3121985a3a3SMaksim Yevmenkin * reported for Nokia 6600 and Sony/Ericsson P900. Both phones 3131985a3a3SMaksim Yevmenkin * are Symbian-based phones. Perhaps this is a Symbian problem? 3141985a3a3SMaksim Yevmenkin */ 3151985a3a3SMaksim Yevmenkin 3161985a3a3SMaksim Yevmenkin if (regsp) { 3171985a3a3SMaksim Yevmenkin sdp_sp_profile_t sp; 3181985a3a3SMaksim Yevmenkin 3191985a3a3SMaksim Yevmenkin memset(&sp, 0, sizeof(sp)); 3201985a3a3SMaksim Yevmenkin sp.server_channel = channel; 3211985a3a3SMaksim Yevmenkin 3221985a3a3SMaksim Yevmenkin if (sdp_register_service(ss, 3231985a3a3SMaksim Yevmenkin SDP_SERVICE_CLASS_SERIAL_PORT, 3241985a3a3SMaksim Yevmenkin &addr, (void *) &sp, sizeof(sp), 3251985a3a3SMaksim Yevmenkin NULL) != 0) { 3261985a3a3SMaksim Yevmenkin syslog(LOG_ERR, "Unable to register SP " \ 3271985a3a3SMaksim Yevmenkin "service with local SDP daemon. " \ 3281985a3a3SMaksim Yevmenkin "%s (%d)", strerror(sdp_error(ss)), 3291985a3a3SMaksim Yevmenkin sdp_error(ss)); 3301985a3a3SMaksim Yevmenkin exit(1); 3311985a3a3SMaksim Yevmenkin } 3321985a3a3SMaksim Yevmenkin } 3331985a3a3SMaksim Yevmenkin 3341a63eb31SJulian Elischer for (done = 0; !done; ) { 335831a4264SMaksim Yevmenkin socklen_t len = sizeof(sock_addr); 3361a63eb31SJulian Elischer int s1 = accept(s, (struct sockaddr *) &sock_addr, &len); 3371a63eb31SJulian Elischer 3381a63eb31SJulian Elischer if (s1 < 0) { 3391a63eb31SJulian Elischer syslog(LOG_ERR, "Could not accept connection " \ 3401a63eb31SJulian Elischer "on socket. %s (%d)", strerror(errno), 3411a63eb31SJulian Elischer errno); 3421a63eb31SJulian Elischer exit(1); 3431a63eb31SJulian Elischer } 3441a63eb31SJulian Elischer 3451a63eb31SJulian Elischer pid = fork(); 3461a63eb31SJulian Elischer if (pid == (pid_t) -1) { 3471a63eb31SJulian Elischer syslog(LOG_ERR, "Could not fork(). %s (%d)", 3481a63eb31SJulian Elischer strerror(errno), errno); 3491a63eb31SJulian Elischer exit(1); 3501a63eb31SJulian Elischer } 3511a63eb31SJulian Elischer 3521a63eb31SJulian Elischer if (pid == 0) { 35313706e45SMaksim Yevmenkin sdp_close(ss); 3541a63eb31SJulian Elischer close(s); 3551a63eb31SJulian Elischer 3561a63eb31SJulian Elischer /* Reset signal handler */ 3571a63eb31SJulian Elischer memset(&sa, 0, sizeof(sa)); 3581a63eb31SJulian Elischer sa.sa_handler = SIG_DFL; 3591a63eb31SJulian Elischer 3601a63eb31SJulian Elischer sigaction(SIGTERM, &sa, NULL); 3611a63eb31SJulian Elischer sigaction(SIGHUP, &sa, NULL); 3621a63eb31SJulian Elischer sigaction(SIGINT, &sa, NULL); 3631a63eb31SJulian Elischer sigaction(SIGCHLD, &sa, NULL); 3641a63eb31SJulian Elischer 3651a63eb31SJulian Elischer /* Become daemon */ 3661a63eb31SJulian Elischer daemon(0, 0); 3671a63eb31SJulian Elischer 36813706e45SMaksim Yevmenkin /* 36913706e45SMaksim Yevmenkin * XXX Make sure user does not shoot himself 37013706e45SMaksim Yevmenkin * in the foot. Do not pass unit option to the 37113706e45SMaksim Yevmenkin * PPP when operating in the server mode. 37213706e45SMaksim Yevmenkin */ 37313706e45SMaksim Yevmenkin 37413706e45SMaksim Yevmenkin exec_ppp(s1, NULL, label); 3751a63eb31SJulian Elischer } else 3761a63eb31SJulian Elischer close(s1); 3771a63eb31SJulian Elischer } 3781a63eb31SJulian Elischer } else { 3791a63eb31SJulian Elischer sock_addr.rfcomm_len = sizeof(sock_addr); 3801a63eb31SJulian Elischer sock_addr.rfcomm_family = AF_BLUETOOTH; 3811a63eb31SJulian Elischer memcpy(&sock_addr.rfcomm_bdaddr, NG_HCI_BDADDR_ANY, 3821a63eb31SJulian Elischer sizeof(sock_addr.rfcomm_bdaddr)); 3831a63eb31SJulian Elischer sock_addr.rfcomm_channel = 0; 3841a63eb31SJulian Elischer 3851a63eb31SJulian Elischer if (bind(s, (struct sockaddr *) &sock_addr, 3861a63eb31SJulian Elischer sizeof(sock_addr)) < 0) { 3871a63eb31SJulian Elischer syslog(LOG_ERR, "Could not bind socket. %s (%d)", 3881a63eb31SJulian Elischer strerror(errno), errno); 3891a63eb31SJulian Elischer exit(1); 3901a63eb31SJulian Elischer } 3911a63eb31SJulian Elischer 3921a63eb31SJulian Elischer memcpy(&sock_addr.rfcomm_bdaddr, &addr, 3931a63eb31SJulian Elischer sizeof(sock_addr.rfcomm_bdaddr)); 3941a63eb31SJulian Elischer sock_addr.rfcomm_channel = channel; 3951a63eb31SJulian Elischer 3961a63eb31SJulian Elischer if (connect(s, (struct sockaddr *) &sock_addr, 3971a63eb31SJulian Elischer sizeof(sock_addr)) < 0) { 3981a63eb31SJulian Elischer syslog(LOG_ERR, "Could not connect socket. %s (%d)", 3991a63eb31SJulian Elischer strerror(errno), errno); 4001a63eb31SJulian Elischer exit(1); 4011a63eb31SJulian Elischer } 4021a63eb31SJulian Elischer 40313706e45SMaksim Yevmenkin exec_ppp(s, unit, label); 4041a63eb31SJulian Elischer } 4051a63eb31SJulian Elischer 4061a63eb31SJulian Elischer exit(0); 4071a63eb31SJulian Elischer } /* main */ 4081a63eb31SJulian Elischer 4091a63eb31SJulian Elischer /* 41013706e45SMaksim Yevmenkin * Redirects stdin/stdout to s, stderr to /dev/null and exec 41113706e45SMaksim Yevmenkin * 'ppp -direct -quiet [-unit N] label'. Never returns. 4121a63eb31SJulian Elischer */ 4131a63eb31SJulian Elischer 4141a63eb31SJulian Elischer static void 41513706e45SMaksim Yevmenkin exec_ppp(int s, char *unit, char *label) 4161a63eb31SJulian Elischer { 4171a63eb31SJulian Elischer char ppp[] = "/usr/sbin/ppp"; 41813706e45SMaksim Yevmenkin char *ppp_args[] = { ppp, "-direct", "-quiet", 41913706e45SMaksim Yevmenkin NULL, NULL, NULL, NULL }; 4201a63eb31SJulian Elischer 4211a63eb31SJulian Elischer close(0); 4221a63eb31SJulian Elischer if (dup(s) < 0) { 4231a63eb31SJulian Elischer syslog(LOG_ERR, "Could not dup(0). %s (%d)", 4241a63eb31SJulian Elischer strerror(errno), errno); 4251a63eb31SJulian Elischer exit(1); 4261a63eb31SJulian Elischer } 4271a63eb31SJulian Elischer 4281a63eb31SJulian Elischer close(1); 4291a63eb31SJulian Elischer if (dup(s) < 0) { 4301a63eb31SJulian Elischer syslog(LOG_ERR, "Could not dup(1). %s (%d)", 4311a63eb31SJulian Elischer strerror(errno), errno); 4321a63eb31SJulian Elischer exit(1); 4331a63eb31SJulian Elischer } 4341a63eb31SJulian Elischer 4351a63eb31SJulian Elischer close(2); 4361a63eb31SJulian Elischer open("/dev/null", O_RDWR); 4371a63eb31SJulian Elischer 43813706e45SMaksim Yevmenkin if (unit != NULL) { 43913706e45SMaksim Yevmenkin ppp_args[3] = "-unit"; 44013706e45SMaksim Yevmenkin ppp_args[4] = unit; 44113706e45SMaksim Yevmenkin ppp_args[5] = label; 44213706e45SMaksim Yevmenkin } else 44313706e45SMaksim Yevmenkin ppp_args[3] = label; 44413706e45SMaksim Yevmenkin 4451a63eb31SJulian Elischer if (execv(ppp, ppp_args) < 0) { 44613706e45SMaksim Yevmenkin syslog(LOG_ERR, "Could not exec(%s -direct -quiet%s%s %s). " \ 44713706e45SMaksim Yevmenkin "%s (%d)", ppp, (unit != NULL)? " -unit " : "", 44813706e45SMaksim Yevmenkin (unit != NULL)? unit : "", label, 44913706e45SMaksim Yevmenkin strerror(errno), errno); 4501a63eb31SJulian Elischer exit(1); 4511a63eb31SJulian Elischer } 4521a63eb31SJulian Elischer } /* run_ppp */ 4531a63eb31SJulian Elischer 4541a63eb31SJulian Elischer /* Signal handler */ 4551a63eb31SJulian Elischer static void 4561a63eb31SJulian Elischer sighandler(int s) 4571a63eb31SJulian Elischer { 4581a63eb31SJulian Elischer done = 1; 4591a63eb31SJulian Elischer } /* sighandler */ 4601a63eb31SJulian Elischer 4611a63eb31SJulian Elischer /* Display usage and exit */ 4621a63eb31SJulian Elischer static void 4631a63eb31SJulian Elischer usage(void) 4641a63eb31SJulian Elischer { 4651a63eb31SJulian Elischer fprintf(stdout, 4661a63eb31SJulian Elischer "Usage: %s options\n" \ 4671a63eb31SJulian Elischer "Where options are:\n" \ 4682aa65cf7SMaksim Yevmenkin "\t-a address Address to listen on or connect to (required for client)\n" \ 4691a63eb31SJulian Elischer "\t-c Act as a clinet (default)\n" \ 4701a63eb31SJulian Elischer "\t-C channel RFCOMM channel to listen on or connect to (required)\n" \ 4711a63eb31SJulian Elischer "\t-d Run in foreground\n" \ 4721a63eb31SJulian Elischer "\t-l label Use PPP label (required)\n" \ 4731a63eb31SJulian Elischer "\t-s Act as a server\n" \ 4741985a3a3SMaksim Yevmenkin "\t-S Register Serial Port service (server mode only)\n" \ 47513706e45SMaksim Yevmenkin "\t-u N Tell PPP to operate on /dev/tunN (client mode only)\n" \ 4761a63eb31SJulian Elischer "\t-h Display this message\n", RFCOMM_PPPD); 4771a63eb31SJulian Elischer 4781a63eb31SJulian Elischer exit(255); 4791a63eb31SJulian Elischer } /* usage */ 4801a63eb31SJulian Elischer 481