rfcomm_pppd.c revision 121054
1/* 2 * rfcomm_pppd.c 3 * 4 * Copyright (c) 2001-2003 Maksim Yevmenkin <m_evmenkin@yahoo.com> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $Id: rfcomm_pppd.c,v 1.5 2003/09/07 18:32:11 max Exp $ 29 * $FreeBSD: head/usr.sbin/bluetooth/rfcomm_pppd/rfcomm_pppd.c 121054 2003-10-12 22:04:24Z emax $ 30 */ 31 32#include <bluetooth.h> 33#include <ctype.h> 34#include <err.h> 35#include <errno.h> 36#include <fcntl.h> 37#include <sdp.h> 38#include <signal.h> 39#include <stdarg.h> 40#include <stdio.h> 41#include <stdlib.h> 42#include <string.h> 43#include <syslog.h> 44#include <unistd.h> 45 46#define RFCOMM_PPPD "rfcomm_pppd" 47 48int rfcomm_channel_lookup (bdaddr_t const *local, 49 bdaddr_t const *remote, 50 int service, int *channel, int *error); 51 52static void exec_ppp (int s, char *label); 53static void sighandler (int s); 54static void usage (void); 55 56static int done; 57 58/* Main */ 59int 60main(int argc, char *argv[]) 61{ 62 struct sockaddr_rfcomm sock_addr; 63 char *label = NULL, *ep = NULL; 64 bdaddr_t addr; 65 int s, channel, detach, server, service; 66 pid_t pid; 67 68 memcpy(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)); 69 channel = 0; 70 detach = 1; 71 server = 0; 72 service = 0; 73 74 /* Parse command line arguments */ 75 while ((s = getopt(argc, argv, "a:cC:dhl:s")) != -1) { 76 switch (s) { 77 case 'a': /* BDADDR */ 78 if (!bt_aton(optarg, &addr)) { 79 struct hostent *he = NULL; 80 81 if ((he = bt_gethostbyname(optarg)) == NULL) 82 errx(1, "%s: %s", optarg, hstrerror(h_errno)); 83 84 memcpy(&addr, he->h_addr, sizeof(addr)); 85 } 86 break; 87 88 case 'c': /* client */ 89 server = 0; 90 break; 91 92 case 'C': /* RFCOMM channel */ 93 channel = strtoul(optarg, &ep, 10); 94 if (*ep != 0) { 95 channel = 0; 96 switch (tolower(optarg[0])) { 97 case 'd': /* DialUp Networking */ 98 service = SDP_SERVICE_CLASS_DIALUP_NETWORKING; 99 break; 100 101 case 'l': /* LAN Access Using PPP */ 102 service = SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP; 103 break; 104 } 105 } 106 break; 107 108 case 'd': /* do not detach */ 109 detach = 0; 110 break; 111 112 case 'l': /* PPP label */ 113 label = optarg; 114 break; 115 116 case 's': 117 server = 1; 118 break; 119 120 case 'h': 121 default: 122 usage(); 123 /* NOT REACHED */ 124 } 125 } 126 127 /* Check if we got everything we wanted */ 128 if (label == NULL) 129 errx(1, "Must specify PPP label"); 130 131 if (!server) { 132 if (memcmp(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)) == 0) 133 errx(1, "Must specify server BD_ADDR"); 134 135 /* Check channel, if was not set then obtain it via SDP */ 136 if (channel == 0 && service != 0) 137 if (rfcomm_channel_lookup(NULL, &addr, service, 138 &channel, &s) != 0) 139 errc(1, s, "Could not obtain RFCOMM channel"); 140 } 141 142 if (channel <= 0 || channel > 30) 143 errx(1, "Invalid RFCOMM channel number %d", channel); 144 145 openlog(RFCOMM_PPPD, LOG_PID | LOG_PERROR | LOG_NDELAY, LOG_USER); 146 147 if (detach) { 148 pid = fork(); 149 if (pid == (pid_t) -1) { 150 syslog(LOG_ERR, "Could not fork(). %s (%d)", 151 strerror(errno), errno); 152 exit(1); 153 } 154 155 if (pid != 0) 156 exit(0); 157 158 if (daemon(0, 0) < 0) { 159 syslog(LOG_ERR, "Could not daemon(0, 0). %s (%d)", 160 strerror(errno), errno); 161 exit(1); 162 } 163 } 164 165 s = socket(PF_BLUETOOTH, SOCK_STREAM, BLUETOOTH_PROTO_RFCOMM); 166 if (s < 0) { 167 syslog(LOG_ERR, "Could not create socket. %s (%d)", 168 strerror(errno), errno); 169 exit(1); 170 } 171 172 if (server) { 173 struct sigaction sa; 174 175 /* Install signal handler */ 176 memset(&sa, 0, sizeof(sa)); 177 sa.sa_handler = sighandler; 178 179 if (sigaction(SIGTERM, &sa, NULL) < 0) { 180 syslog(LOG_ERR, "Could not sigaction(SIGTERM). %s (%d)", 181 strerror(errno), errno); 182 exit(1); 183 } 184 185 if (sigaction(SIGHUP, &sa, NULL) < 0) { 186 syslog(LOG_ERR, "Could not sigaction(SIGHUP). %s (%d)", 187 strerror(errno), errno); 188 exit(1); 189 } 190 191 if (sigaction(SIGINT, &sa, NULL) < 0) { 192 syslog(LOG_ERR, "Could not sigaction(SIGINT). %s (%d)", 193 strerror(errno), errno); 194 exit(1); 195 } 196 197 sa.sa_handler = SIG_IGN; 198 sa.sa_flags = SA_NOCLDWAIT; 199 200 if (sigaction(SIGCHLD, &sa, NULL) < 0) { 201 syslog(LOG_ERR, "Could not sigaction(SIGCHLD). %s (%d)", 202 strerror(errno), errno); 203 exit(1); 204 } 205 206 /* bind socket and listen for incoming connections */ 207 sock_addr.rfcomm_len = sizeof(sock_addr); 208 sock_addr.rfcomm_family = AF_BLUETOOTH; 209 memcpy(&sock_addr.rfcomm_bdaddr, &addr, 210 sizeof(sock_addr.rfcomm_bdaddr)); 211 sock_addr.rfcomm_channel = channel; 212 213 if (bind(s, (struct sockaddr *) &sock_addr, 214 sizeof(sock_addr)) < 0) { 215 syslog(LOG_ERR, "Could not bind socket. %s (%d)", 216 strerror(errno), errno); 217 exit(1); 218 } 219 220 if (listen(s, 10) < 0) { 221 syslog(LOG_ERR, "Could not listen on socket. %s (%d)", 222 strerror(errno), errno); 223 exit(1); 224 } 225 226 for (done = 0; !done; ) { 227 int len = sizeof(sock_addr); 228 int s1 = accept(s, (struct sockaddr *) &sock_addr, &len); 229 230 if (s1 < 0) { 231 syslog(LOG_ERR, "Could not accept connection " \ 232 "on socket. %s (%d)", strerror(errno), 233 errno); 234 exit(1); 235 } 236 237 pid = fork(); 238 if (pid == (pid_t) -1) { 239 syslog(LOG_ERR, "Could not fork(). %s (%d)", 240 strerror(errno), errno); 241 exit(1); 242 } 243 244 if (pid == 0) { 245 close(s); 246 247 /* Reset signal handler */ 248 memset(&sa, 0, sizeof(sa)); 249 sa.sa_handler = SIG_DFL; 250 251 sigaction(SIGTERM, &sa, NULL); 252 sigaction(SIGHUP, &sa, NULL); 253 sigaction(SIGINT, &sa, NULL); 254 sigaction(SIGCHLD, &sa, NULL); 255 256 /* Become daemon */ 257 daemon(0, 0); 258 259 exec_ppp(s1, label); 260 } else 261 close(s1); 262 } 263 } else { 264 sock_addr.rfcomm_len = sizeof(sock_addr); 265 sock_addr.rfcomm_family = AF_BLUETOOTH; 266 memcpy(&sock_addr.rfcomm_bdaddr, NG_HCI_BDADDR_ANY, 267 sizeof(sock_addr.rfcomm_bdaddr)); 268 sock_addr.rfcomm_channel = 0; 269 270 if (bind(s, (struct sockaddr *) &sock_addr, 271 sizeof(sock_addr)) < 0) { 272 syslog(LOG_ERR, "Could not bind socket. %s (%d)", 273 strerror(errno), errno); 274 exit(1); 275 } 276 277 memcpy(&sock_addr.rfcomm_bdaddr, &addr, 278 sizeof(sock_addr.rfcomm_bdaddr)); 279 sock_addr.rfcomm_channel = channel; 280 281 if (connect(s, (struct sockaddr *) &sock_addr, 282 sizeof(sock_addr)) < 0) { 283 syslog(LOG_ERR, "Could not connect socket. %s (%d)", 284 strerror(errno), errno); 285 exit(1); 286 } 287 288 exec_ppp(s, label); 289 } 290 291 exit(0); 292} /* main */ 293 294/* 295 * Redirects stdin/stdout to s, stderr to /dev/null and exec ppp -direct label. 296 * Never retruns. 297 */ 298 299static void 300exec_ppp(int s, char *label) 301{ 302 char ppp[] = "/usr/sbin/ppp"; 303 char *ppp_args[] = { ppp, "-direct", NULL, NULL }; 304 305 close(0); 306 if (dup(s) < 0) { 307 syslog(LOG_ERR, "Could not dup(0). %s (%d)", 308 strerror(errno), errno); 309 exit(1); 310 } 311 312 close(1); 313 if (dup(s) < 0) { 314 syslog(LOG_ERR, "Could not dup(1). %s (%d)", 315 strerror(errno), errno); 316 exit(1); 317 } 318 319 close(2); 320 open("/dev/null", O_RDWR); 321 322 ppp_args[2] = label; 323 if (execv(ppp, ppp_args) < 0) { 324 syslog(LOG_ERR, "Could not exec(%s -direct %s). %s (%d)", 325 ppp, label, strerror(errno), errno); 326 exit(1); 327 } 328} /* run_ppp */ 329 330/* Signal handler */ 331static void 332sighandler(int s) 333{ 334 done = 1; 335} /* sighandler */ 336 337/* Display usage and exit */ 338static void 339usage(void) 340{ 341 fprintf(stdout, 342"Usage: %s options\n" \ 343"Where options are:\n" \ 344"\t-a bdaddr BDADDR to listen on or connect to (required for client)\n" \ 345"\t-c Act as a clinet (default)\n" \ 346"\t-C channel RFCOMM channel to listen on or connect to (required)\n" \ 347"\t-d Run in foreground\n" \ 348"\t-l label Use PPP label (required)\n" \ 349"\t-s Act as a server\n" \ 350"\t-h Display this message\n", RFCOMM_PPPD); 351 352 exit(255); 353} /* usage */ 354 355