rfcomm_pppd.c revision 121054
1114879Sjulian/* 2114879Sjulian * rfcomm_pppd.c 3114879Sjulian * 4114879Sjulian * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com> 5114879Sjulian * All rights reserved. 6114879Sjulian * 7114879Sjulian * Redistribution and use in source and binary forms, with or without 8114879Sjulian * modification, are permitted provided that the following conditions 9114879Sjulian * are met: 10114879Sjulian * 1. Redistributions of source code must retain the above copyright 11114879Sjulian * notice, this list of conditions and the following disclaimer. 12114879Sjulian * 2. Redistributions in binary form must reproduce the above copyright 13114879Sjulian * notice, this list of conditions and the following disclaimer in the 14114879Sjulian * documentation and/or other materials provided with the distribution. 15114879Sjulian * 16114879Sjulian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17114879Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18114879Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19114879Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20114879Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21114879Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22114879Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23114879Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24114879Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25114879Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26114879Sjulian * SUCH DAMAGE. 27114879Sjulian * 28121054Semax * $Id: rfcomm_pppd.c,v 1.5 2003/09/07 18:32:11 max Exp $ 29114879Sjulian * $FreeBSD: head/usr.sbin/bluetooth/rfcomm_pppd/rfcomm_pppd.c 121054 2003-10-12 22:04:24Z emax $ 30114879Sjulian */ 31114879Sjulian 32121054Semax#include <bluetooth.h> 33121054Semax#include <ctype.h> 34121054Semax#include <err.h> 35114879Sjulian#include <errno.h> 36114879Sjulian#include <fcntl.h> 37121054Semax#include <sdp.h> 38114879Sjulian#include <signal.h> 39114879Sjulian#include <stdarg.h> 40114879Sjulian#include <stdio.h> 41114879Sjulian#include <stdlib.h> 42114879Sjulian#include <string.h> 43114879Sjulian#include <syslog.h> 44114879Sjulian#include <unistd.h> 45114879Sjulian 46114879Sjulian#define RFCOMM_PPPD "rfcomm_pppd" 47114879Sjulian 48121054Semaxint rfcomm_channel_lookup (bdaddr_t const *local, 49121054Semax bdaddr_t const *remote, 50121054Semax int service, int *channel, int *error); 51121054Semax 52114879Sjulianstatic void exec_ppp (int s, char *label); 53114879Sjulianstatic void sighandler (int s); 54114879Sjulianstatic void usage (void); 55114879Sjulian 56114879Sjulianstatic int done; 57114879Sjulian 58114879Sjulian/* Main */ 59114879Sjulianint 60114879Sjulianmain(int argc, char *argv[]) 61114879Sjulian{ 62114879Sjulian struct sockaddr_rfcomm sock_addr; 63121054Semax char *label = NULL, *ep = NULL; 64114879Sjulian bdaddr_t addr; 65121054Semax int s, channel, detach, server, service; 66114879Sjulian pid_t pid; 67114879Sjulian 68114879Sjulian memcpy(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)); 69114879Sjulian channel = 0; 70114879Sjulian detach = 1; 71114879Sjulian server = 0; 72121054Semax service = 0; 73114879Sjulian 74114879Sjulian /* Parse command line arguments */ 75114879Sjulian while ((s = getopt(argc, argv, "a:cC:dhl:s")) != -1) { 76114879Sjulian switch (s) { 77121054Semax case 'a': /* BDADDR */ 78121054Semax if (!bt_aton(optarg, &addr)) { 79121054Semax struct hostent *he = NULL; 80114879Sjulian 81121054Semax if ((he = bt_gethostbyname(optarg)) == NULL) 82121054Semax errx(1, "%s: %s", optarg, hstrerror(h_errno)); 83114879Sjulian 84121054Semax memcpy(&addr, he->h_addr, sizeof(addr)); 85121054Semax } 86121054Semax break; 87114879Sjulian 88114879Sjulian case 'c': /* client */ 89114879Sjulian server = 0; 90114879Sjulian break; 91114879Sjulian 92114879Sjulian case 'C': /* RFCOMM channel */ 93121054Semax channel = strtoul(optarg, &ep, 10); 94121054Semax if (*ep != 0) { 95121054Semax channel = 0; 96121054Semax switch (tolower(optarg[0])) { 97121054Semax case 'd': /* DialUp Networking */ 98121054Semax service = SDP_SERVICE_CLASS_DIALUP_NETWORKING; 99121054Semax break; 100121054Semax 101121054Semax case 'l': /* LAN Access Using PPP */ 102121054Semax service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP; 103121054Semax break; 104121054Semax } 105121054Semax } 106114879Sjulian break; 107114879Sjulian 108114879Sjulian case 'd': /* do not detach */ 109114879Sjulian detach = 0; 110114879Sjulian break; 111114879Sjulian 112114879Sjulian case 'l': /* PPP label */ 113114879Sjulian label = optarg; 114114879Sjulian break; 115114879Sjulian 116114879Sjulian case 's': 117114879Sjulian server = 1; 118114879Sjulian break; 119114879Sjulian 120114879Sjulian case 'h': 121114879Sjulian default: 122114879Sjulian usage(); 123114879Sjulian /* NOT REACHED */ 124114879Sjulian } 125114879Sjulian } 126114879Sjulian 127114879Sjulian /* Check if we got everything we wanted */ 128121054Semax if (label == NULL) 129121054Semax errx(1, "Must specify PPP label"); 130114879Sjulian 131121054Semax if (!server) { 132121054Semax if (memcmp(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)) == 0) 133121054Semax errx(1, "Must specify server BD_ADDR"); 134121054Semax 135121054Semax /* Check channel, if was not set then obtain it via SDP */ 136121054Semax if (channel == 0 && service != 0) 137121054Semax if (rfcomm_channel_lookup(NULL, &addr, service, 138121054Semax &channel, &s) != 0) 139121054Semax errc(1, s, "Could not obtain RFCOMM channel"); 140121054Semax } 141121054Semax 142121054Semax if (channel <= 0 || channel > 30) 143121054Semax errx(1, "Invalid RFCOMM channel number %d", channel); 144121054Semax 145114879Sjulian openlog(RFCOMM_PPPD, LOG_PID | LOG_PERROR | LOG_NDELAY, LOG_USER); 146114879Sjulian 147114879Sjulian if (detach) { 148114879Sjulian pid = fork(); 149114879Sjulian if (pid == (pid_t) -1) { 150114879Sjulian syslog(LOG_ERR, "Could not fork(). %s (%d)", 151114879Sjulian strerror(errno), errno); 152114879Sjulian exit(1); 153114879Sjulian } 154114879Sjulian 155114879Sjulian if (pid != 0) 156114879Sjulian exit(0); 157114879Sjulian 158114879Sjulian if (daemon(0, 0) < 0) { 159114879Sjulian syslog(LOG_ERR, "Could not daemon(0, 0). %s (%d)", 160114879Sjulian strerror(errno), errno); 161114879Sjulian exit(1); 162114879Sjulian } 163114879Sjulian } 164114879Sjulian 165114879Sjulian s = socket(PF_BLUETOOTH, SOCK_STREAM, BLUETOOTH_PROTO_RFCOMM); 166114879Sjulian if (s < 0) { 167114879Sjulian syslog(LOG_ERR, "Could not create socket. %s (%d)", 168114879Sjulian strerror(errno), errno); 169114879Sjulian exit(1); 170114879Sjulian } 171114879Sjulian 172114879Sjulian if (server) { 173114879Sjulian struct sigaction sa; 174114879Sjulian 175114879Sjulian /* Install signal handler */ 176114879Sjulian memset(&sa, 0, sizeof(sa)); 177114879Sjulian sa.sa_handler = sighandler; 178114879Sjulian 179114879Sjulian if (sigaction(SIGTERM, &sa, NULL) < 0) { 180114879Sjulian syslog(LOG_ERR, "Could not sigaction(SIGTERM). %s (%d)", 181114879Sjulian strerror(errno), errno); 182114879Sjulian exit(1); 183114879Sjulian } 184114879Sjulian 185114879Sjulian if (sigaction(SIGHUP, &sa, NULL) < 0) { 186114879Sjulian syslog(LOG_ERR, "Could not sigaction(SIGHUP). %s (%d)", 187114879Sjulian strerror(errno), errno); 188114879Sjulian exit(1); 189114879Sjulian } 190114879Sjulian 191114879Sjulian if (sigaction(SIGINT, &sa, NULL) < 0) { 192114879Sjulian syslog(LOG_ERR, "Could not sigaction(SIGINT). %s (%d)", 193114879Sjulian strerror(errno), errno); 194114879Sjulian exit(1); 195114879Sjulian } 196114879Sjulian 197114879Sjulian sa.sa_handler = SIG_IGN; 198114879Sjulian sa.sa_flags = SA_NOCLDWAIT; 199114879Sjulian 200114879Sjulian if (sigaction(SIGCHLD, &sa, NULL) < 0) { 201114879Sjulian syslog(LOG_ERR, "Could not sigaction(SIGCHLD). %s (%d)", 202114879Sjulian strerror(errno), errno); 203114879Sjulian exit(1); 204114879Sjulian } 205114879Sjulian 206114879Sjulian /* bind socket and listen for incoming connections */ 207114879Sjulian sock_addr.rfcomm_len = sizeof(sock_addr); 208114879Sjulian sock_addr.rfcomm_family = AF_BLUETOOTH; 209114879Sjulian memcpy(&sock_addr.rfcomm_bdaddr, &addr, 210114879Sjulian sizeof(sock_addr.rfcomm_bdaddr)); 211114879Sjulian sock_addr.rfcomm_channel = channel; 212114879Sjulian 213114879Sjulian if (bind(s, (struct sockaddr *) &sock_addr, 214114879Sjulian sizeof(sock_addr)) < 0) { 215114879Sjulian syslog(LOG_ERR, "Could not bind socket. %s (%d)", 216114879Sjulian strerror(errno), errno); 217114879Sjulian exit(1); 218114879Sjulian } 219114879Sjulian 220114879Sjulian if (listen(s, 10) < 0) { 221114879Sjulian syslog(LOG_ERR, "Could not listen on socket. %s (%d)", 222114879Sjulian strerror(errno), errno); 223114879Sjulian exit(1); 224114879Sjulian } 225114879Sjulian 226114879Sjulian for (done = 0; !done; ) { 227114879Sjulian int len = sizeof(sock_addr); 228114879Sjulian int s1 = accept(s, (struct sockaddr *) &sock_addr, &len); 229114879Sjulian 230114879Sjulian if (s1 < 0) { 231114879Sjulian syslog(LOG_ERR, "Could not accept connection " \ 232114879Sjulian "on socket. %s (%d)", strerror(errno), 233114879Sjulian errno); 234114879Sjulian exit(1); 235114879Sjulian } 236114879Sjulian 237114879Sjulian pid = fork(); 238114879Sjulian if (pid == (pid_t) -1) { 239114879Sjulian syslog(LOG_ERR, "Could not fork(). %s (%d)", 240114879Sjulian strerror(errno), errno); 241114879Sjulian exit(1); 242114879Sjulian } 243114879Sjulian 244114879Sjulian if (pid == 0) { 245114879Sjulian close(s); 246114879Sjulian 247114879Sjulian /* Reset signal handler */ 248114879Sjulian memset(&sa, 0, sizeof(sa)); 249114879Sjulian sa.sa_handler = SIG_DFL; 250114879Sjulian 251114879Sjulian sigaction(SIGTERM, &sa, NULL); 252114879Sjulian sigaction(SIGHUP, &sa, NULL); 253114879Sjulian sigaction(SIGINT, &sa, NULL); 254114879Sjulian sigaction(SIGCHLD, &sa, NULL); 255114879Sjulian 256114879Sjulian /* Become daemon */ 257114879Sjulian daemon(0, 0); 258114879Sjulian 259114879Sjulian exec_ppp(s1, label); 260114879Sjulian } else 261114879Sjulian close(s1); 262114879Sjulian } 263114879Sjulian } else { 264114879Sjulian sock_addr.rfcomm_len = sizeof(sock_addr); 265114879Sjulian sock_addr.rfcomm_family = AF_BLUETOOTH; 266114879Sjulian memcpy(&sock_addr.rfcomm_bdaddr, NG_HCI_BDADDR_ANY, 267114879Sjulian sizeof(sock_addr.rfcomm_bdaddr)); 268114879Sjulian sock_addr.rfcomm_channel = 0; 269114879Sjulian 270114879Sjulian if (bind(s, (struct sockaddr *) &sock_addr, 271114879Sjulian sizeof(sock_addr)) < 0) { 272114879Sjulian syslog(LOG_ERR, "Could not bind socket. %s (%d)", 273114879Sjulian strerror(errno), errno); 274114879Sjulian exit(1); 275114879Sjulian } 276114879Sjulian 277114879Sjulian memcpy(&sock_addr.rfcomm_bdaddr, &addr, 278114879Sjulian sizeof(sock_addr.rfcomm_bdaddr)); 279114879Sjulian sock_addr.rfcomm_channel = channel; 280114879Sjulian 281114879Sjulian if (connect(s, (struct sockaddr *) &sock_addr, 282114879Sjulian sizeof(sock_addr)) < 0) { 283114879Sjulian syslog(LOG_ERR, "Could not connect socket. %s (%d)", 284114879Sjulian strerror(errno), errno); 285114879Sjulian exit(1); 286114879Sjulian } 287114879Sjulian 288114879Sjulian exec_ppp(s, label); 289114879Sjulian } 290114879Sjulian 291114879Sjulian exit(0); 292114879Sjulian} /* main */ 293114879Sjulian 294114879Sjulian/* 295114879Sjulian * Redirects stdin/stdout to s, stderr to /dev/null and exec ppp -direct label. 296114879Sjulian * Never retruns. 297114879Sjulian */ 298114879Sjulian 299114879Sjulianstatic void 300114879Sjulianexec_ppp(int s, char *label) 301114879Sjulian{ 302114879Sjulian char ppp[] = "/usr/sbin/ppp"; 303114879Sjulian char *ppp_args[] = { ppp, "-direct", NULL, NULL }; 304114879Sjulian 305114879Sjulian close(0); 306114879Sjulian if (dup(s) < 0) { 307114879Sjulian syslog(LOG_ERR, "Could not dup(0). %s (%d)", 308114879Sjulian strerror(errno), errno); 309114879Sjulian exit(1); 310114879Sjulian } 311114879Sjulian 312114879Sjulian close(1); 313114879Sjulian if (dup(s) < 0) { 314114879Sjulian syslog(LOG_ERR, "Could not dup(1). %s (%d)", 315114879Sjulian strerror(errno), errno); 316114879Sjulian exit(1); 317114879Sjulian } 318114879Sjulian 319114879Sjulian close(2); 320114879Sjulian open("/dev/null", O_RDWR); 321114879Sjulian 322114879Sjulian ppp_args[2] = label; 323114879Sjulian if (execv(ppp, ppp_args) < 0) { 324114879Sjulian syslog(LOG_ERR, "Could not exec(%s -direct %s). %s (%d)", 325114879Sjulian ppp, label, strerror(errno), errno); 326114879Sjulian exit(1); 327114879Sjulian } 328114879Sjulian} /* run_ppp */ 329114879Sjulian 330114879Sjulian/* Signal handler */ 331114879Sjulianstatic void 332114879Sjuliansighandler(int s) 333114879Sjulian{ 334114879Sjulian done = 1; 335114879Sjulian} /* sighandler */ 336114879Sjulian 337114879Sjulian/* Display usage and exit */ 338114879Sjulianstatic void 339114879Sjulianusage(void) 340114879Sjulian{ 341114879Sjulian fprintf(stdout, 342114879Sjulian"Usage: %s options\n" \ 343114879Sjulian"Where options are:\n" \ 344114879Sjulian"\t-a bdaddr BDADDR to listen on or connect to (required for client)\n" \ 345114879Sjulian"\t-c Act as a clinet (default)\n" \ 346114879Sjulian"\t-C channel RFCOMM channel to listen on or connect to (required)\n" \ 347114879Sjulian"\t-d Run in foreground\n" \ 348114879Sjulian"\t-l label Use PPP label (required)\n" \ 349114879Sjulian"\t-s Act as a server\n" \ 350114879Sjulian"\t-h Display this message\n", RFCOMM_PPPD); 351114879Sjulian 352114879Sjulian exit(255); 353114879Sjulian} /* usage */ 354114879Sjulian 355