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.3 2003/04/26 23:59:49 max Exp $ 29 * $FreeBSD$ 30 */ 31 32 #include <sys/types.h> 33 #include <sys/socket.h> 34 #include <bitstring.h> 35 #include <errno.h> 36 #include <fcntl.h> 37 #include <ng_hci.h> 38 #include <ng_l2cap.h> 39 #include <ng_btsocket.h> 40 #include <signal.h> 41 #include <stdarg.h> 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <syslog.h> 46 #include <unistd.h> 47 48 #define RFCOMM_PPPD "rfcomm_pppd" 49 50 static void exec_ppp (int s, char *label); 51 static void sighandler (int s); 52 static void usage (void); 53 54 static int done; 55 56 /* Main */ 57 int 58 main(int argc, char *argv[]) 59 { 60 struct sockaddr_rfcomm sock_addr; 61 char *label = NULL; 62 bdaddr_t addr; 63 int s, channel, detach, server; 64 pid_t pid; 65 66 memcpy(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)); 67 channel = 0; 68 detach = 1; 69 server = 0; 70 71 /* Parse command line arguments */ 72 while ((s = getopt(argc, argv, "a:cC:dhl:s")) != -1) { 73 switch (s) { 74 case 'a': { /* BDADDR */ 75 int a0, a1, a2, a3, a4, a5; 76 77 if (sscanf(optarg, "%x:%x:%x:%x:%x:%x", 78 &a5, &a4, &a3, &a2, &a1, &a0) != 6) 79 usage(); 80 /* NOT REACHED */ 81 82 addr.b[0] = a0 & 0xff; 83 addr.b[1] = a1 & 0xff; 84 addr.b[2] = a2 & 0xff; 85 addr.b[3] = a3 & 0xff; 86 addr.b[4] = a4 & 0xff; 87 addr.b[5] = a5 & 0xff; 88 } break; 89 90 case 'c': /* client */ 91 server = 0; 92 break; 93 94 case 'C': /* RFCOMM channel */ 95 channel = atoi(optarg); 96 break; 97 98 case 'd': /* do not detach */ 99 detach = 0; 100 break; 101 102 case 'l': /* PPP label */ 103 label = optarg; 104 break; 105 106 case 's': 107 server = 1; 108 break; 109 110 case 'h': 111 default: 112 usage(); 113 /* NOT REACHED */ 114 } 115 } 116 117 /* Check if we got everything we wanted */ 118 if ((channel <= 0 || channel > 30) || label == NULL || 119 (!server && memcmp(&addr, NG_HCI_BDADDR_ANY, sizeof(addr)) == 0)) 120 usage(); 121 /* NOT REACHED */ 122 123 openlog(RFCOMM_PPPD, LOG_PID | LOG_PERROR | LOG_NDELAY, LOG_USER); 124 125 if (detach) { 126 pid = fork(); 127 if (pid == (pid_t) -1) { 128 syslog(LOG_ERR, "Could not fork(). %s (%d)", 129 strerror(errno), errno); 130 exit(1); 131 } 132 133 if (pid != 0) 134 exit(0); 135 136 if (daemon(0, 0) < 0) { 137 syslog(LOG_ERR, "Could not daemon(0, 0). %s (%d)", 138 strerror(errno), errno); 139 exit(1); 140 } 141 } 142 143 s = socket(PF_BLUETOOTH, SOCK_STREAM, BLUETOOTH_PROTO_RFCOMM); 144 if (s < 0) { 145 syslog(LOG_ERR, "Could not create socket. %s (%d)", 146 strerror(errno), errno); 147 exit(1); 148 } 149 150 if (server) { 151 struct sigaction sa; 152 153 /* Install signal handler */ 154 memset(&sa, 0, sizeof(sa)); 155 sa.sa_handler = sighandler; 156 157 if (sigaction(SIGTERM, &sa, NULL) < 0) { 158 syslog(LOG_ERR, "Could not sigaction(SIGTERM). %s (%d)", 159 strerror(errno), errno); 160 exit(1); 161 } 162 163 if (sigaction(SIGHUP, &sa, NULL) < 0) { 164 syslog(LOG_ERR, "Could not sigaction(SIGHUP). %s (%d)", 165 strerror(errno), errno); 166 exit(1); 167 } 168 169 if (sigaction(SIGINT, &sa, NULL) < 0) { 170 syslog(LOG_ERR, "Could not sigaction(SIGINT). %s (%d)", 171 strerror(errno), errno); 172 exit(1); 173 } 174 175 sa.sa_handler = SIG_IGN; 176 sa.sa_flags = SA_NOCLDWAIT; 177 178 if (sigaction(SIGCHLD, &sa, NULL) < 0) { 179 syslog(LOG_ERR, "Could not sigaction(SIGCHLD). %s (%d)", 180 strerror(errno), errno); 181 exit(1); 182 } 183 184 /* bind socket and listen for incoming connections */ 185 sock_addr.rfcomm_len = sizeof(sock_addr); 186 sock_addr.rfcomm_family = AF_BLUETOOTH; 187 memcpy(&sock_addr.rfcomm_bdaddr, &addr, 188 sizeof(sock_addr.rfcomm_bdaddr)); 189 sock_addr.rfcomm_channel = channel; 190 191 if (bind(s, (struct sockaddr *) &sock_addr, 192 sizeof(sock_addr)) < 0) { 193 syslog(LOG_ERR, "Could not bind socket. %s (%d)", 194 strerror(errno), errno); 195 exit(1); 196 } 197 198 if (listen(s, 10) < 0) { 199 syslog(LOG_ERR, "Could not listen on socket. %s (%d)", 200 strerror(errno), errno); 201 exit(1); 202 } 203 204 for (done = 0; !done; ) { 205 int len = sizeof(sock_addr); 206 int s1 = accept(s, (struct sockaddr *) &sock_addr, &len); 207 208 if (s1 < 0) { 209 syslog(LOG_ERR, "Could not accept connection " \ 210 "on socket. %s (%d)", strerror(errno), 211 errno); 212 exit(1); 213 } 214 215 pid = fork(); 216 if (pid == (pid_t) -1) { 217 syslog(LOG_ERR, "Could not fork(). %s (%d)", 218 strerror(errno), errno); 219 exit(1); 220 } 221 222 if (pid == 0) { 223 close(s); 224 225 /* Reset signal handler */ 226 memset(&sa, 0, sizeof(sa)); 227 sa.sa_handler = SIG_DFL; 228 229 sigaction(SIGTERM, &sa, NULL); 230 sigaction(SIGHUP, &sa, NULL); 231 sigaction(SIGINT, &sa, NULL); 232 sigaction(SIGCHLD, &sa, NULL); 233 234 /* Become daemon */ 235 daemon(0, 0); 236 237 exec_ppp(s1, label); 238 } else 239 close(s1); 240 } 241 } else { 242 sock_addr.rfcomm_len = sizeof(sock_addr); 243 sock_addr.rfcomm_family = AF_BLUETOOTH; 244 memcpy(&sock_addr.rfcomm_bdaddr, NG_HCI_BDADDR_ANY, 245 sizeof(sock_addr.rfcomm_bdaddr)); 246 sock_addr.rfcomm_channel = 0; 247 248 if (bind(s, (struct sockaddr *) &sock_addr, 249 sizeof(sock_addr)) < 0) { 250 syslog(LOG_ERR, "Could not bind socket. %s (%d)", 251 strerror(errno), errno); 252 exit(1); 253 } 254 255 memcpy(&sock_addr.rfcomm_bdaddr, &addr, 256 sizeof(sock_addr.rfcomm_bdaddr)); 257 sock_addr.rfcomm_channel = channel; 258 259 if (connect(s, (struct sockaddr *) &sock_addr, 260 sizeof(sock_addr)) < 0) { 261 syslog(LOG_ERR, "Could not connect socket. %s (%d)", 262 strerror(errno), errno); 263 exit(1); 264 } 265 266 exec_ppp(s, label); 267 } 268 269 exit(0); 270 } /* main */ 271 272 /* 273 * Redirects stdin/stdout to s, stderr to /dev/null and exec ppp -direct label. 274 * Never retruns. 275 */ 276 277 static void 278 exec_ppp(int s, char *label) 279 { 280 char ppp[] = "/usr/sbin/ppp"; 281 char *ppp_args[] = { ppp, "-direct", NULL, NULL }; 282 283 close(0); 284 if (dup(s) < 0) { 285 syslog(LOG_ERR, "Could not dup(0). %s (%d)", 286 strerror(errno), errno); 287 exit(1); 288 } 289 290 close(1); 291 if (dup(s) < 0) { 292 syslog(LOG_ERR, "Could not dup(1). %s (%d)", 293 strerror(errno), errno); 294 exit(1); 295 } 296 297 close(2); 298 open("/dev/null", O_RDWR); 299 300 ppp_args[2] = label; 301 if (execv(ppp, ppp_args) < 0) { 302 syslog(LOG_ERR, "Could not exec(%s -direct %s). %s (%d)", 303 ppp, label, strerror(errno), errno); 304 exit(1); 305 } 306 } /* run_ppp */ 307 308 /* Signal handler */ 309 static void 310 sighandler(int s) 311 { 312 done = 1; 313 } /* sighandler */ 314 315 /* Display usage and exit */ 316 static void 317 usage(void) 318 { 319 fprintf(stdout, 320 "Usage: %s options\n" \ 321 "Where options are:\n" \ 322 "\t-a bdaddr BDADDR to listen on or connect to (required for client)\n" \ 323 "\t-c Act as a clinet (default)\n" \ 324 "\t-C channel RFCOMM channel to listen on or connect to (required)\n" \ 325 "\t-d Run in foreground\n" \ 326 "\t-l label Use PPP label (required)\n" \ 327 "\t-s Act as a server\n" \ 328 "\t-h Display this message\n", RFCOMM_PPPD); 329 330 exit(255); 331 } /* usage */ 332 333