Home | History | Annotate | Download | only in compat
      1 /*
      2  *
      3  *  BlueZ - Bluetooth protocol stack for Linux
      4  *
      5  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk (at) qualcomm.com>
      6  *  Copyright (C) 2002-2009  Marcel Holtmann <marcel (at) holtmann.org>
      7  *
      8  *
      9  *  This program is free software; you can redistribute it and/or modify
     10  *  it under the terms of the GNU General Public License as published by
     11  *  the Free Software Foundation; either version 2 of the License, or
     12  *  (at your option) any later version.
     13  *
     14  *  This program is distributed in the hope that it will be useful,
     15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17  *  GNU General Public License for more details.
     18  *
     19  *  You should have received a copy of the GNU General Public License
     20  *  along with this program; if not, write to the Free Software
     21  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     22  *
     23  */
     24 
     25 #ifdef HAVE_CONFIG_H
     26 #include <config.h>
     27 #endif
     28 
     29 #include <stdio.h>
     30 #include <errno.h>
     31 #include <fcntl.h>
     32 #include <unistd.h>
     33 #include <stdlib.h>
     34 #include <string.h>
     35 #include <syslog.h>
     36 #include <signal.h>
     37 #include <getopt.h>
     38 
     39 #include <sys/socket.h>
     40 
     41 #include <bluetooth/bluetooth.h>
     42 #include <bluetooth/hci.h>
     43 #include <bluetooth/hci_lib.h>
     44 #include <bluetooth/rfcomm.h>
     45 #include <bluetooth/hidp.h>
     46 
     47 #include "sdp.h"
     48 #include "dund.h"
     49 #include "lib.h"
     50 
     51 volatile sig_atomic_t __io_canceled;
     52 
     53 /* MS dialup networking support (i.e. CLIENT / CLIENTSERVER thing) */
     54 static int msdun = 0;
     55 
     56 static char *pppd = "/usr/sbin/pppd";
     57 static char *pppd_opts[DUN_MAX_PPP_OPTS] =
     58 	{
     59 		/* First 3 are reserved */
     60 		"", "", "",
     61 		"noauth",
     62 		"noipdefault",
     63 		NULL
     64 	};
     65 
     66 static int  detach = 1;
     67 static int  persist;
     68 static int  use_sdp = 1;
     69 static int  auth;
     70 static int  encrypt;
     71 static int  secure;
     72 static int  master;
     73 static int  type = LANACCESS;
     74 static int  search_duration = 10;
     75 static uint use_cache;
     76 
     77 static int  channel;
     78 
     79 static struct {
     80 	uint     valid;
     81 	char     dst[40];
     82 	bdaddr_t bdaddr;
     83 	int      channel;
     84 } cache;
     85 
     86 static bdaddr_t src_addr = *BDADDR_ANY;
     87 static int src_dev = -1;
     88 
     89 volatile int terminate;
     90 
     91 enum {
     92 	NONE,
     93 	SHOW,
     94 	LISTEN,
     95 	CONNECT,
     96 	KILL
     97 } modes;
     98 
     99 static int create_connection(char *dst, bdaddr_t *bdaddr, int mrouter);
    100 
    101 static int do_listen(void)
    102 {
    103 	struct sockaddr_rc sa;
    104 	int sk, lm;
    105 
    106 	if (type == MROUTER) {
    107 		if (!cache.valid)
    108 			return -1;
    109 
    110 		if (create_connection(cache.dst, &cache.bdaddr, type) < 0) {
    111 			syslog(LOG_ERR, "Cannot connect to mRouter device. %s(%d)",
    112 								strerror(errno), errno);
    113 			return -1;
    114 		}
    115 	}
    116 
    117 	if (!channel)
    118 		channel = DUN_DEFAULT_CHANNEL;
    119 
    120 	if (use_sdp)
    121 		dun_sdp_register(&src_addr, channel, type);
    122 
    123 	if (type == MROUTER)
    124 		syslog(LOG_INFO, "Waiting for mRouter callback on channel %d", channel);
    125 
    126 	/* Create RFCOMM socket */
    127 	sk = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
    128 	if (sk < 0) {
    129 		syslog(LOG_ERR, "Cannot create RFCOMM socket. %s(%d)",
    130 				strerror(errno), errno);
    131 		return -1;
    132 	}
    133 
    134 	sa.rc_family  = AF_BLUETOOTH;
    135 	sa.rc_channel = channel;
    136 	sa.rc_bdaddr  = src_addr;
    137 
    138 	if (bind(sk, (struct sockaddr *) &sa, sizeof(sa))) {
    139 		syslog(LOG_ERR, "Bind failed. %s(%d)", strerror(errno), errno);
    140 		return -1;
    141 	}
    142 
    143 	/* Set link mode */
    144 	lm = 0;
    145 	if (master)
    146 		lm |= RFCOMM_LM_MASTER;
    147 	if (auth)
    148 		lm |= RFCOMM_LM_AUTH;
    149 	if (encrypt)
    150 		lm |= RFCOMM_LM_ENCRYPT;
    151 	if (secure)
    152 		lm |= RFCOMM_LM_SECURE;
    153 
    154 	if (lm && setsockopt(sk, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm)) < 0) {
    155 		syslog(LOG_ERR, "Failed to set link mode. %s(%d)", strerror(errno), errno);
    156 		return -1;
    157 	}
    158 
    159 	listen(sk, 10);
    160 
    161 	while (!terminate) {
    162 		socklen_t alen = sizeof(sa);
    163 		int nsk;
    164 		char ba[40];
    165 		char ch[10];
    166 
    167 		nsk = accept(sk, (struct sockaddr *) &sa, &alen);
    168 		if (nsk < 0) {
    169 			syslog(LOG_ERR, "Accept failed. %s(%d)", strerror(errno), errno);
    170 			continue;
    171 		}
    172 
    173 		switch (fork()) {
    174 		case 0:
    175 			break;
    176 		case -1:
    177 			syslog(LOG_ERR, "Fork failed. %s(%d)", strerror(errno), errno);
    178 		default:
    179 			close(nsk);
    180 			if (type == MROUTER) {
    181 				close(sk);
    182 				terminate = 1;
    183 			}
    184 			continue;
    185 		}
    186 
    187 		close(sk);
    188 
    189 		if (msdun && ms_dun(nsk, 1, msdun) < 0) {
    190 			syslog(LOG_ERR, "MSDUN failed. %s(%d)", strerror(errno), errno);
    191 			exit(0);
    192 		}
    193 
    194 		ba2str(&sa.rc_bdaddr, ba);
    195 		sprintf(ch, "%d", channel);
    196 
    197 		/* Setup environment */
    198 		setenv("DUN_BDADDR",  ba, 1);
    199 		setenv("DUN_CHANNEL", ch, 1);
    200 
    201 		if (!dun_open_connection(nsk, pppd, pppd_opts, 0))
    202 			syslog(LOG_INFO, "New connection from %s", ba);
    203 
    204 		close(nsk);
    205 		exit(0);
    206 	}
    207 
    208 	if (use_sdp)
    209 		dun_sdp_unregister();
    210 	return 0;
    211 }
    212 
    213 /* Connect and initiate RFCOMM session
    214  * Returns:
    215  *   -1 - critical error (exit persist mode)
    216  *   1  - non critical error
    217  *   0  - success
    218  */
    219 static int create_connection(char *dst, bdaddr_t *bdaddr, int mrouter)
    220 {
    221 	struct sockaddr_rc sa;
    222 	int sk, err = 0, ch;
    223 
    224 	if (use_cache && cache.valid && cache.channel) {
    225 		/* Use cached channel */
    226 		ch = cache.channel;
    227 
    228 	} else if (!channel) {
    229 		syslog(LOG_INFO, "Searching for %s on %s", mrouter ? "SP" : "LAP", dst);
    230 
    231 		if (dun_sdp_search(&src_addr, bdaddr, &ch, mrouter) <= 0)
    232 			return 0;
    233 	} else
    234 		ch = channel;
    235 
    236 	syslog(LOG_INFO, "Connecting to %s channel %d", dst, ch);
    237 
    238 	sk = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
    239 	if (sk < 0) {
    240 		syslog(LOG_ERR, "Cannot create RFCOMM socket. %s(%d)",
    241 		     strerror(errno), errno);
    242 		return -1;
    243 	}
    244 
    245 	sa.rc_family  = AF_BLUETOOTH;
    246 	sa.rc_channel = 0;
    247 	sa.rc_bdaddr  = src_addr;
    248 
    249 	if (bind(sk, (struct sockaddr *) &sa, sizeof(sa)))
    250 		syslog(LOG_ERR, "Bind failed. %s(%d)",
    251 			strerror(errno), errno);
    252 
    253 	sa.rc_channel = ch;
    254 	sa.rc_bdaddr  = *bdaddr;
    255 
    256 	if (!connect(sk, (struct sockaddr *) &sa, sizeof(sa)) ) {
    257 		if (mrouter) {
    258 			sleep(1);
    259 			close(sk);
    260 			return 0;
    261 		}
    262 
    263 		syslog(LOG_INFO, "Connection established");
    264 
    265 		if (msdun && ms_dun(sk, 0, msdun) < 0) {
    266 			syslog(LOG_ERR, "MSDUN failed. %s(%d)", strerror(errno), errno);
    267 			err = 1;
    268 			goto out;
    269 		}
    270 
    271 		if (!dun_open_connection(sk, pppd, pppd_opts, (persist > 0)))
    272 			err = 0;
    273 		else
    274 			err = 1;
    275 	} else {
    276 		syslog(LOG_ERR, "Connect to %s failed. %s(%d)",
    277 				dst, strerror(errno), errno);
    278 		err = 1;
    279 	}
    280 
    281 out:
    282 	if (use_cache) {
    283 		if (!err) {
    284 			/* Succesesful connection, validate cache */
    285 			strcpy(cache.dst, dst);
    286 			bacpy(&cache.bdaddr, bdaddr);
    287 			cache.channel = ch;
    288 			cache.valid   = use_cache;
    289 		} else {
    290 			cache.channel = 0;
    291 			cache.valid--;
    292 		}
    293 	}
    294 
    295 	close(sk);
    296 	return err;
    297 }
    298 
    299 /* Search and connect
    300  * Returns:
    301  *   -1 - critical error (exit persist mode)
    302  *   1  - non critical error
    303  *   0  - success
    304  */
    305 static int do_connect(void)
    306 {
    307 	inquiry_info *ii;
    308 	int reconnect = 0;
    309 	int i, n, r = 0;
    310 
    311 	do {
    312 		if (reconnect)
    313 			sleep(persist);
    314 		reconnect = 1;
    315 
    316 		if (cache.valid) {
    317 			/* Use cached bdaddr */
    318 			r = create_connection(cache.dst, &cache.bdaddr, 0);
    319 			if (r < 0) {
    320 				terminate = 1;
    321 				break;
    322 			}
    323 			continue;
    324 		}
    325 
    326 		syslog(LOG_INFO, "Inquiring");
    327 
    328 		/* FIXME: Should we use non general LAP here ? */
    329 
    330 		ii = NULL;
    331 		n  = hci_inquiry(src_dev, search_duration, 0, NULL, &ii, 0);
    332 		if (n < 0) {
    333 			syslog(LOG_ERR, "Inquiry failed. %s(%d)", strerror(errno), errno);
    334 			continue;
    335 		}
    336 
    337 		for (i = 0; i < n; i++) {
    338 			char dst[40];
    339 			ba2str(&ii[i].bdaddr, dst);
    340 
    341 			r = create_connection(dst, &ii[i].bdaddr, 0);
    342 			if (r < 0) {
    343 				terminate = 1;
    344 				break;
    345 			}
    346 		}
    347 		bt_free(ii);
    348 	} while (!terminate && persist);
    349 
    350 	return r;
    351 }
    352 
    353 static void do_show(void)
    354 {
    355 	dun_show_connections();
    356 }
    357 
    358 static void do_kill(char *dst)
    359 {
    360 	if (dst) {
    361 		bdaddr_t ba;
    362 		str2ba(dst, &ba);
    363 		dun_kill_connection((void *) &ba);
    364 	} else
    365 		dun_kill_all_connections();
    366 }
    367 
    368 static void sig_hup(int sig)
    369 {
    370 	return;
    371 }
    372 
    373 static void sig_term(int sig)
    374 {
    375 	io_cancel();
    376 	terminate = 1;
    377 }
    378 
    379 static struct option main_lopts[] = {
    380 	{ "help",	0, 0, 'h' },
    381 	{ "listen",	0, 0, 's' },
    382 	{ "connect",	1, 0, 'c' },
    383 	{ "search",	2, 0, 'Q' },
    384 	{ "kill",	1, 0, 'k' },
    385 	{ "killall",	0, 0, 'K' },
    386 	{ "channel",	1, 0, 'P' },
    387 	{ "device",	1, 0, 'i' },
    388 	{ "nosdp",	0, 0, 'D' },
    389 	{ "list",	0, 0, 'l' },
    390 	{ "show",	0, 0, 'l' },
    391 	{ "nodetach",	0, 0, 'n' },
    392 	{ "persist",	2, 0, 'p' },
    393 	{ "auth",	0, 0, 'A' },
    394 	{ "encrypt",	0, 0, 'E' },
    395 	{ "secure",	0, 0, 'S' },
    396 	{ "master",	0, 0, 'M' },
    397 	{ "cache",	0, 0, 'C' },
    398 	{ "pppd",	1, 0, 'd' },
    399 	{ "msdun",	2, 0, 'X' },
    400 	{ "activesync",	0, 0, 'a' },
    401 	{ "mrouter",	1, 0, 'm' },
    402 	{ "dialup",	0, 0, 'u' },
    403 	{ 0, 0, 0, 0 }
    404 };
    405 
    406 static const char *main_sopts = "hsc:k:Kr:i:lnp::DQ::AESMP:C::P:Xam:u";
    407 
    408 static const char *main_help =
    409 	"Bluetooth LAP (LAN Access over PPP) daemon version %s\n"
    410 	"Usage:\n"
    411 	"\tdund <options> [pppd options]\n"
    412 	"Options:\n"
    413 	"\t--show --list -l          Show active LAP connections\n"
    414 	"\t--listen -s               Listen for LAP connections\n"
    415 	"\t--dialup -u               Pretend to be a dialup/telephone\n"
    416 	"\t--connect -c <bdaddr>     Create LAP connection\n"
    417 	"\t--mrouter -m <bdaddr>     Create mRouter connection\n"
    418 	"\t--search -Q[duration]     Search and connect\n"
    419 	"\t--kill -k <bdaddr>        Kill LAP connection\n"
    420 	"\t--killall -K              Kill all LAP connections\n"
    421 	"\t--channel -P <channel>    RFCOMM channel\n"
    422 	"\t--device -i <bdaddr>      Source bdaddr\n"
    423 	"\t--nosdp -D                Disable SDP\n"
    424 	"\t--auth -A                 Enable authentication\n"
    425 	"\t--encrypt -E              Enable encryption\n"
    426 	"\t--secure -S               Secure connection\n"
    427 	"\t--master -M               Become the master of a piconet\n"
    428 	"\t--nodetach -n             Do not become a daemon\n"
    429 	"\t--persist -p[interval]    Persist mode\n"
    430 	"\t--pppd -d <pppd>          Location of the PPP daemon (pppd)\n"
    431 	"\t--msdun -X[timeo]         Enable Microsoft dialup networking support\n"
    432 	"\t--activesync -a           Enable Microsoft ActiveSync networking\n"
    433 	"\t--cache -C[valid]         Enable address cache\n";
    434 
    435 int main(int argc, char *argv[])
    436 {
    437 	char *dst = NULL, *src = NULL;
    438 	struct sigaction sa;
    439 	int mode = NONE;
    440 	int opt;
    441 
    442 	while ((opt=getopt_long(argc, argv, main_sopts, main_lopts, NULL)) != -1) {
    443 		switch(opt) {
    444 		case 'l':
    445 			mode = SHOW;
    446 			detach = 0;
    447 			break;
    448 
    449 		case 's':
    450 			mode = LISTEN;
    451 			type = LANACCESS;
    452 			break;
    453 
    454 		case 'c':
    455 			mode = CONNECT;
    456 			dst  = strdup(optarg);
    457 			break;
    458 
    459 		case 'Q':
    460 			mode = CONNECT;
    461 			dst  = NULL;
    462 			if (optarg)
    463 				search_duration = atoi(optarg);
    464 			break;
    465 
    466 		case 'k':
    467 			mode = KILL;
    468 			detach = 0;
    469 			dst  = strdup(optarg);
    470 			break;
    471 
    472 		case 'K':
    473 			mode = KILL;
    474 			detach = 0;
    475 			dst  = NULL;
    476 			break;
    477 
    478 		case 'P':
    479 			channel = atoi(optarg);
    480 			break;
    481 
    482 		case 'i':
    483 			src = strdup(optarg);
    484 			break;
    485 
    486 		case 'D':
    487 			use_sdp = 0;
    488 			break;
    489 
    490 		case 'A':
    491 			auth = 1;
    492 			break;
    493 
    494 		case 'E':
    495 			encrypt = 1;
    496 			break;
    497 
    498 		case 'S':
    499 			secure = 1;
    500 			break;
    501 
    502 		case 'M':
    503 			master = 1;
    504 			break;
    505 
    506 		case 'n':
    507 			detach = 0;
    508 			break;
    509 
    510 		case 'p':
    511 			if (optarg)
    512 				persist = atoi(optarg);
    513 			else
    514 				persist = 5;
    515 			break;
    516 
    517 		case 'C':
    518 			if (optarg)
    519 				use_cache = atoi(optarg);
    520 			else
    521 				use_cache = 2;
    522 			break;
    523 
    524 		case 'd':
    525 			pppd  = strdup(optarg);
    526 			break;
    527 
    528 		case 'X':
    529 			if (optarg)
    530 				msdun = atoi(optarg);
    531 			else
    532 				msdun = 10;
    533 			break;
    534 
    535 		case 'a':
    536 			msdun = 10;
    537 			type = ACTIVESYNC;
    538 			break;
    539 
    540 		case 'm':
    541 			mode = LISTEN;
    542 			dst  = strdup(optarg);
    543 			type = MROUTER;
    544 			break;
    545 
    546 		case 'u':
    547 			mode = LISTEN;
    548 			type = DIALUP;
    549 			break;
    550 
    551 		case 'h':
    552 		default:
    553 			printf(main_help, VERSION);
    554 			exit(0);
    555 		}
    556 	}
    557 
    558 	argc -= optind;
    559 	argv += optind;
    560 
    561 	/* The rest is pppd options */
    562 	if (argc > 0) {
    563 		for (opt = 3; argc && opt < DUN_MAX_PPP_OPTS - 1;
    564 							argc--, opt++)
    565 			pppd_opts[opt] = *argv++;
    566 		pppd_opts[opt] = NULL;
    567 	}
    568 
    569 	io_init();
    570 
    571 	if (dun_init())
    572 		return -1;
    573 
    574 	/* Check non daemon modes first */
    575 	switch (mode) {
    576 	case SHOW:
    577 		do_show();
    578 		return 0;
    579 
    580 	case KILL:
    581 		do_kill(dst);
    582 		return 0;
    583 
    584 	case NONE:
    585 		printf(main_help, VERSION);
    586 		return 0;
    587 	}
    588 
    589 	/* Initialize signals */
    590 	memset(&sa, 0, sizeof(sa));
    591 	sa.sa_flags   = SA_NOCLDSTOP;
    592 	sa.sa_handler = SIG_IGN;
    593 	sigaction(SIGCHLD, &sa, NULL);
    594 	sigaction(SIGPIPE, &sa, NULL);
    595 
    596 	sa.sa_handler = sig_term;
    597 	sigaction(SIGTERM, &sa, NULL);
    598 	sigaction(SIGINT,  &sa, NULL);
    599 
    600 	sa.sa_handler = sig_hup;
    601 	sigaction(SIGHUP, &sa, NULL);
    602 
    603 	if (detach && daemon(0, 0)) {
    604 		perror("Can't start daemon");
    605 		exit(1);
    606 	}
    607 
    608 	openlog("dund", LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_DAEMON);
    609 	syslog(LOG_INFO, "Bluetooth DUN daemon version %s", VERSION);
    610 
    611 	if (src) {
    612 		src_dev = hci_devid(src);
    613 		if (src_dev < 0 || hci_devba(src_dev, &src_addr) < 0) {
    614 			syslog(LOG_ERR, "Invalid source. %s(%d)", strerror(errno), errno);
    615 			return -1;
    616 		}
    617 	}
    618 
    619 	if (dst) {
    620 		strncpy(cache.dst, dst, sizeof(cache.dst) - 1);
    621 		str2ba(dst, &cache.bdaddr);
    622 
    623 		/* Disable cache invalidation */
    624 		use_cache = cache.valid = ~0;
    625 	}
    626 
    627 	switch (mode) {
    628 	case CONNECT:
    629 		do_connect();
    630 		break;
    631 
    632 	case LISTEN:
    633 		do_listen();
    634 		break;
    635 	}
    636 
    637 	return 0;
    638 }
    639