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 * 281a63eb31SJulian Elischer * $Id: rfcomm_pppd.c,v 1.3 2003/04/26 23:59:49 max Exp $ 291a63eb31SJulian Elischer * $FreeBSD$ 301a63eb31SJulian Elischer */ 311a63eb31SJulian Elischer 321a63eb31SJulian Elischer #include <sys/types.h> 331a63eb31SJulian Elischer #include <sys/socket.h> 341a63eb31SJulian Elischer #include <bitstring.h> 351a63eb31SJulian Elischer #include <errno.h> 361a63eb31SJulian Elischer #include <fcntl.h> 371a63eb31SJulian Elischer #include <ng_hci.h> 381a63eb31SJulian Elischer #include <ng_l2cap.h> 391a63eb31SJulian Elischer #include <ng_btsocket.h> 401a63eb31SJulian Elischer #include <signal.h> 411a63eb31SJulian Elischer #include <stdarg.h> 421a63eb31SJulian Elischer #include <stdio.h> 431a63eb31SJulian Elischer #include <stdlib.h> 441a63eb31SJulian Elischer #include <string.h> 451a63eb31SJulian Elischer #include <syslog.h> 461a63eb31SJulian Elischer #include <unistd.h> 471a63eb31SJulian Elischer 481a63eb31SJulian Elischer #define RFCOMM_PPPD "rfcomm_pppd" 491a63eb31SJulian Elischer 501a63eb31SJulian Elischer static void exec_ppp (int s, char *label); 511a63eb31SJulian Elischer static void sighandler (int s); 521a63eb31SJulian Elischer static void usage (void); 531a63eb31SJulian Elischer 541a63eb31SJulian Elischer static int done; 551a63eb31SJulian Elischer 561a63eb31SJulian Elischer /* Main */ 571a63eb31SJulian Elischer int 581a63eb31SJulian Elischer main(int argc, char *argv[]) 591a63eb31SJulian Elischer { 601a63eb31SJulian Elischer struct sockaddr_rfcomm sock_addr; 611a63eb31SJulian Elischer char *label = NULL; 621a63eb31SJulian Elischer bdaddr_t addr; 631a63eb31SJulian Elischer int s, channel, detach, server; 641a63eb31SJulian Elischer pid_t pid; 651a63eb31SJulian Elischer 661a63eb31SJulian Elischer memcpy(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)); 671a63eb31SJulian Elischer channel = 0; 681a63eb31SJulian Elischer detach = 1; 691a63eb31SJulian Elischer server = 0; 701a63eb31SJulian Elischer 711a63eb31SJulian Elischer /* Parse command line arguments */ 721a63eb31SJulian Elischer while ((s = getopt(argc, argv, "a:cC:dhl:s")) != -1) { 731a63eb31SJulian Elischer switch (s) { 741a63eb31SJulian Elischer case 'a': { /* BDADDR */ 751a63eb31SJulian Elischer int a0, a1, a2, a3, a4, a5; 761a63eb31SJulian Elischer 771a63eb31SJulian Elischer if (sscanf(optarg, "%x:%x:%x:%x:%x:%x", 781a63eb31SJulian Elischer &a5, &a4, &a3, &a2, &a1, &a0) != 6) 791a63eb31SJulian Elischer usage(); 801a63eb31SJulian Elischer /* NOT REACHED */ 811a63eb31SJulian Elischer 821a63eb31SJulian Elischer addr.b[0] = a0 & 0xff; 831a63eb31SJulian Elischer addr.b[1] = a1 & 0xff; 841a63eb31SJulian Elischer addr.b[2] = a2 & 0xff; 851a63eb31SJulian Elischer addr.b[3] = a3 & 0xff; 861a63eb31SJulian Elischer addr.b[4] = a4 & 0xff; 871a63eb31SJulian Elischer addr.b[5] = a5 & 0xff; 881a63eb31SJulian Elischer } break; 891a63eb31SJulian Elischer 901a63eb31SJulian Elischer case 'c': /* client */ 911a63eb31SJulian Elischer server = 0; 921a63eb31SJulian Elischer break; 931a63eb31SJulian Elischer 941a63eb31SJulian Elischer case 'C': /* RFCOMM channel */ 951a63eb31SJulian Elischer channel = atoi(optarg); 961a63eb31SJulian Elischer break; 971a63eb31SJulian Elischer 981a63eb31SJulian Elischer case 'd': /* do not detach */ 991a63eb31SJulian Elischer detach = 0; 1001a63eb31SJulian Elischer break; 1011a63eb31SJulian Elischer 1021a63eb31SJulian Elischer case 'l': /* PPP label */ 1031a63eb31SJulian Elischer label = optarg; 1041a63eb31SJulian Elischer break; 1051a63eb31SJulian Elischer 1061a63eb31SJulian Elischer case 's': 1071a63eb31SJulian Elischer server = 1; 1081a63eb31SJulian Elischer break; 1091a63eb31SJulian Elischer 1101a63eb31SJulian Elischer case 'h': 1111a63eb31SJulian Elischer default: 1121a63eb31SJulian Elischer usage(); 1131a63eb31SJulian Elischer /* NOT REACHED */ 1141a63eb31SJulian Elischer } 1151a63eb31SJulian Elischer } 1161a63eb31SJulian Elischer 1171a63eb31SJulian Elischer /* Check if we got everything we wanted */ 1181a63eb31SJulian Elischer if ((channel <= 0 || channel > 30) || label == NULL || 1191a63eb31SJulian Elischer (!server && memcmp(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)) == 0)) 1201a63eb31SJulian Elischer usage(); 1211a63eb31SJulian Elischer /* NOT REACHED */ 1221a63eb31SJulian Elischer 1231a63eb31SJulian Elischer openlog(RFCOMM_PPPD, LOG_PID | LOG_PERROR | LOG_NDELAY, LOG_USER); 1241a63eb31SJulian Elischer 1251a63eb31SJulian Elischer if (detach) { 1261a63eb31SJulian Elischer pid = fork(); 1271a63eb31SJulian Elischer if (pid == (pid_t) -1) { 1281a63eb31SJulian Elischer syslog(LOG_ERR, "Could not fork(). %s (%d)", 1291a63eb31SJulian Elischer strerror(errno), errno); 1301a63eb31SJulian Elischer exit(1); 1311a63eb31SJulian Elischer } 1321a63eb31SJulian Elischer 1331a63eb31SJulian Elischer if (pid != 0) 1341a63eb31SJulian Elischer exit(0); 1351a63eb31SJulian Elischer 1361a63eb31SJulian Elischer if (daemon(0, 0) < 0) { 1371a63eb31SJulian Elischer syslog(LOG_ERR, "Could not daemon(0, 0). %s (%d)", 1381a63eb31SJulian Elischer strerror(errno), errno); 1391a63eb31SJulian Elischer exit(1); 1401a63eb31SJulian Elischer } 1411a63eb31SJulian Elischer } 1421a63eb31SJulian Elischer 1431a63eb31SJulian Elischer s = socket(PF_BLUETOOTH, SOCK_STREAM, BLUETOOTH_PROTO_RFCOMM); 1441a63eb31SJulian Elischer if (s < 0) { 1451a63eb31SJulian Elischer syslog(LOG_ERR, "Could not create socket. %s (%d)", 1461a63eb31SJulian Elischer strerror(errno), errno); 1471a63eb31SJulian Elischer exit(1); 1481a63eb31SJulian Elischer } 1491a63eb31SJulian Elischer 1501a63eb31SJulian Elischer if (server) { 1511a63eb31SJulian Elischer struct sigaction sa; 1521a63eb31SJulian Elischer 1531a63eb31SJulian Elischer /* Install signal handler */ 1541a63eb31SJulian Elischer memset(&sa, 0, sizeof(sa)); 1551a63eb31SJulian Elischer sa.sa_handler = sighandler; 1561a63eb31SJulian Elischer 1571a63eb31SJulian Elischer if (sigaction(SIGTERM, &sa, NULL) < 0) { 1581a63eb31SJulian Elischer syslog(LOG_ERR, "Could not sigaction(SIGTERM). %s (%d)", 1591a63eb31SJulian Elischer strerror(errno), errno); 1601a63eb31SJulian Elischer exit(1); 1611a63eb31SJulian Elischer } 1621a63eb31SJulian Elischer 1631a63eb31SJulian Elischer if (sigaction(SIGHUP, &sa, NULL) < 0) { 1641a63eb31SJulian Elischer syslog(LOG_ERR, "Could not sigaction(SIGHUP). %s (%d)", 1651a63eb31SJulian Elischer strerror(errno), errno); 1661a63eb31SJulian Elischer exit(1); 1671a63eb31SJulian Elischer } 1681a63eb31SJulian Elischer 1691a63eb31SJulian Elischer if (sigaction(SIGINT, &sa, NULL) < 0) { 1701a63eb31SJulian Elischer syslog(LOG_ERR, "Could not sigaction(SIGINT). %s (%d)", 1711a63eb31SJulian Elischer strerror(errno), errno); 1721a63eb31SJulian Elischer exit(1); 1731a63eb31SJulian Elischer } 1741a63eb31SJulian Elischer 1751a63eb31SJulian Elischer sa.sa_handler = SIG_IGN; 1761a63eb31SJulian Elischer sa.sa_flags = SA_NOCLDWAIT; 1771a63eb31SJulian Elischer 1781a63eb31SJulian Elischer if (sigaction(SIGCHLD, &sa, NULL) < 0) { 1791a63eb31SJulian Elischer syslog(LOG_ERR, "Could not sigaction(SIGCHLD). %s (%d)", 1801a63eb31SJulian Elischer strerror(errno), errno); 1811a63eb31SJulian Elischer exit(1); 1821a63eb31SJulian Elischer } 1831a63eb31SJulian Elischer 1841a63eb31SJulian Elischer /* bind socket and listen for incoming connections */ 1851a63eb31SJulian Elischer sock_addr.rfcomm_len = sizeof(sock_addr); 1861a63eb31SJulian Elischer sock_addr.rfcomm_family = AF_BLUETOOTH; 1871a63eb31SJulian Elischer memcpy(&sock_addr.rfcomm_bdaddr, &addr, 1881a63eb31SJulian Elischer sizeof(sock_addr.rfcomm_bdaddr)); 1891a63eb31SJulian Elischer sock_addr.rfcomm_channel = channel; 1901a63eb31SJulian Elischer 1911a63eb31SJulian Elischer if (bind(s, (struct sockaddr *) &sock_addr, 1921a63eb31SJulian Elischer sizeof(sock_addr)) < 0) { 1931a63eb31SJulian Elischer syslog(LOG_ERR, "Could not bind socket. %s (%d)", 1941a63eb31SJulian Elischer strerror(errno), errno); 1951a63eb31SJulian Elischer exit(1); 1961a63eb31SJulian Elischer } 1971a63eb31SJulian Elischer 1981a63eb31SJulian Elischer if (listen(s, 10) < 0) { 1991a63eb31SJulian Elischer syslog(LOG_ERR, "Could not listen on socket. %s (%d)", 2001a63eb31SJulian Elischer strerror(errno), errno); 2011a63eb31SJulian Elischer exit(1); 2021a63eb31SJulian Elischer } 2031a63eb31SJulian Elischer 2041a63eb31SJulian Elischer for (done = 0; !done; ) { 2051a63eb31SJulian Elischer int len = sizeof(sock_addr); 2061a63eb31SJulian Elischer int s1 = accept(s, (struct sockaddr *) &sock_addr, &len); 2071a63eb31SJulian Elischer 2081a63eb31SJulian Elischer if (s1 < 0) { 2091a63eb31SJulian Elischer syslog(LOG_ERR, "Could not accept connection " \ 2101a63eb31SJulian Elischer "on socket. %s (%d)", strerror(errno), 2111a63eb31SJulian Elischer errno); 2121a63eb31SJulian Elischer exit(1); 2131a63eb31SJulian Elischer } 2141a63eb31SJulian Elischer 2151a63eb31SJulian Elischer pid = fork(); 2161a63eb31SJulian Elischer if (pid == (pid_t) -1) { 2171a63eb31SJulian Elischer syslog(LOG_ERR, "Could not fork(). %s (%d)", 2181a63eb31SJulian Elischer strerror(errno), errno); 2191a63eb31SJulian Elischer exit(1); 2201a63eb31SJulian Elischer } 2211a63eb31SJulian Elischer 2221a63eb31SJulian Elischer if (pid == 0) { 2231a63eb31SJulian Elischer close(s); 2241a63eb31SJulian Elischer 2251a63eb31SJulian Elischer /* Reset signal handler */ 2261a63eb31SJulian Elischer memset(&sa, 0, sizeof(sa)); 2271a63eb31SJulian Elischer sa.sa_handler = SIG_DFL; 2281a63eb31SJulian Elischer 2291a63eb31SJulian Elischer sigaction(SIGTERM, &sa, NULL); 2301a63eb31SJulian Elischer sigaction(SIGHUP, &sa, NULL); 2311a63eb31SJulian Elischer sigaction(SIGINT, &sa, NULL); 2321a63eb31SJulian Elischer sigaction(SIGCHLD, &sa, NULL); 2331a63eb31SJulian Elischer 2341a63eb31SJulian Elischer /* Become daemon */ 2351a63eb31SJulian Elischer daemon(0, 0); 2361a63eb31SJulian Elischer 2371a63eb31SJulian Elischer exec_ppp(s1, label); 2381a63eb31SJulian Elischer } else 2391a63eb31SJulian Elischer close(s1); 2401a63eb31SJulian Elischer } 2411a63eb31SJulian Elischer } else { 2421a63eb31SJulian Elischer sock_addr.rfcomm_len = sizeof(sock_addr); 2431a63eb31SJulian Elischer sock_addr.rfcomm_family = AF_BLUETOOTH; 2441a63eb31SJulian Elischer memcpy(&sock_addr.rfcomm_bdaddr, NG_HCI_BDADDR_ANY, 2451a63eb31SJulian Elischer sizeof(sock_addr.rfcomm_bdaddr)); 2461a63eb31SJulian Elischer sock_addr.rfcomm_channel = 0; 2471a63eb31SJulian Elischer 2481a63eb31SJulian Elischer if (bind(s, (struct sockaddr *) &sock_addr, 2491a63eb31SJulian Elischer sizeof(sock_addr)) < 0) { 2501a63eb31SJulian Elischer syslog(LOG_ERR, "Could not bind socket. %s (%d)", 2511a63eb31SJulian Elischer strerror(errno), errno); 2521a63eb31SJulian Elischer exit(1); 2531a63eb31SJulian Elischer } 2541a63eb31SJulian Elischer 2551a63eb31SJulian Elischer memcpy(&sock_addr.rfcomm_bdaddr, &addr, 2561a63eb31SJulian Elischer sizeof(sock_addr.rfcomm_bdaddr)); 2571a63eb31SJulian Elischer sock_addr.rfcomm_channel = channel; 2581a63eb31SJulian Elischer 2591a63eb31SJulian Elischer if (connect(s, (struct sockaddr *) &sock_addr, 2601a63eb31SJulian Elischer sizeof(sock_addr)) < 0) { 2611a63eb31SJulian Elischer syslog(LOG_ERR, "Could not connect socket. %s (%d)", 2621a63eb31SJulian Elischer strerror(errno), errno); 2631a63eb31SJulian Elischer exit(1); 2641a63eb31SJulian Elischer } 2651a63eb31SJulian Elischer 2661a63eb31SJulian Elischer exec_ppp(s, label); 2671a63eb31SJulian Elischer } 2681a63eb31SJulian Elischer 2691a63eb31SJulian Elischer exit(0); 2701a63eb31SJulian Elischer } /* main */ 2711a63eb31SJulian Elischer 2721a63eb31SJulian Elischer /* 2731a63eb31SJulian Elischer * Redirects stdin/stdout to s, stderr to /dev/null and exec ppp -direct label. 2741a63eb31SJulian Elischer * Never retruns. 2751a63eb31SJulian Elischer */ 2761a63eb31SJulian Elischer 2771a63eb31SJulian Elischer static void 2781a63eb31SJulian Elischer exec_ppp(int s, char *label) 2791a63eb31SJulian Elischer { 2801a63eb31SJulian Elischer char ppp[] = "/usr/sbin/ppp"; 2811a63eb31SJulian Elischer char *ppp_args[] = { ppp, "-direct", NULL, NULL }; 2821a63eb31SJulian Elischer 2831a63eb31SJulian Elischer close(0); 2841a63eb31SJulian Elischer if (dup(s) < 0) { 2851a63eb31SJulian Elischer syslog(LOG_ERR, "Could not dup(0). %s (%d)", 2861a63eb31SJulian Elischer strerror(errno), errno); 2871a63eb31SJulian Elischer exit(1); 2881a63eb31SJulian Elischer } 2891a63eb31SJulian Elischer 2901a63eb31SJulian Elischer close(1); 2911a63eb31SJulian Elischer if (dup(s) < 0) { 2921a63eb31SJulian Elischer syslog(LOG_ERR, "Could not dup(1). %s (%d)", 2931a63eb31SJulian Elischer strerror(errno), errno); 2941a63eb31SJulian Elischer exit(1); 2951a63eb31SJulian Elischer } 2961a63eb31SJulian Elischer 2971a63eb31SJulian Elischer close(2); 2981a63eb31SJulian Elischer open("/dev/null", O_RDWR); 2991a63eb31SJulian Elischer 3001a63eb31SJulian Elischer ppp_args[2] = label; 3011a63eb31SJulian Elischer if (execv(ppp, ppp_args) < 0) { 3021a63eb31SJulian Elischer syslog(LOG_ERR, "Could not exec(%s -direct %s). %s (%d)", 3031a63eb31SJulian Elischer ppp, label, strerror(errno), errno); 3041a63eb31SJulian Elischer exit(1); 3051a63eb31SJulian Elischer } 3061a63eb31SJulian Elischer } /* run_ppp */ 3071a63eb31SJulian Elischer 3081a63eb31SJulian Elischer /* Signal handler */ 3091a63eb31SJulian Elischer static void 3101a63eb31SJulian Elischer sighandler(int s) 3111a63eb31SJulian Elischer { 3121a63eb31SJulian Elischer done = 1; 3131a63eb31SJulian Elischer } /* sighandler */ 3141a63eb31SJulian Elischer 3151a63eb31SJulian Elischer /* Display usage and exit */ 3161a63eb31SJulian Elischer static void 3171a63eb31SJulian Elischer usage(void) 3181a63eb31SJulian Elischer { 3191a63eb31SJulian Elischer fprintf(stdout, 3201a63eb31SJulian Elischer "Usage: %s options\n" \ 3211a63eb31SJulian Elischer "Where options are:\n" \ 3221a63eb31SJulian Elischer "\t-a bdaddr BDADDR to listen on or connect to (required for client)\n" \ 3231a63eb31SJulian Elischer "\t-c Act as a clinet (default)\n" \ 3241a63eb31SJulian Elischer "\t-C channel RFCOMM channel to listen on or connect to (required)\n" \ 3251a63eb31SJulian Elischer "\t-d Run in foreground\n" \ 3261a63eb31SJulian Elischer "\t-l label Use PPP label (required)\n" \ 3271a63eb31SJulian Elischer "\t-s Act as a server\n" \ 3281a63eb31SJulian Elischer "\t-h Display this message\n", RFCOMM_PPPD); 3291a63eb31SJulian Elischer 3301a63eb31SJulian Elischer exit(255); 3311a63eb31SJulian Elischer } /* usage */ 3321a63eb31SJulian Elischer 333