Home | History | Annotate | Line # | Download | only in rfcomm_sppd
rfcomm_sppd.c revision 1.8.12.1
      1  1.8.12.1  wrstuden /*	$NetBSD: rfcomm_sppd.c,v 1.8.12.1 2008/09/18 04:29:19 wrstuden Exp $	*/
      2       1.1   gdamore 
      3       1.1   gdamore /*-
      4       1.1   gdamore  * Copyright (c) 2006 Itronix Inc.
      5       1.1   gdamore  * All rights reserved.
      6       1.1   gdamore  *
      7       1.1   gdamore  * Redistribution and use in source and binary forms, with or without
      8       1.1   gdamore  * modification, are permitted provided that the following conditions
      9       1.1   gdamore  * are met:
     10       1.1   gdamore  * 1. Redistributions of source code must retain the above copyright
     11       1.1   gdamore  *    notice, this list of conditions and the following disclaimer.
     12       1.1   gdamore  * 2. Redistributions in binary form must reproduce the above copyright
     13       1.1   gdamore  *    notice, this list of conditions and the following disclaimer in the
     14       1.1   gdamore  *    documentation and/or other materials provided with the distribution.
     15       1.1   gdamore  * 3. The name of Itronix Inc. may not be used to endorse
     16       1.1   gdamore  *    or promote products derived from this software without specific
     17       1.1   gdamore  *    prior written permission.
     18       1.1   gdamore  *
     19       1.1   gdamore  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
     20       1.1   gdamore  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21       1.1   gdamore  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22       1.1   gdamore  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
     23       1.1   gdamore  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     24       1.1   gdamore  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     25       1.1   gdamore  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     26       1.1   gdamore  * ON ANY THEORY OF LIABILITY, WHETHER IN
     27       1.1   gdamore  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28       1.1   gdamore  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29       1.1   gdamore  * POSSIBILITY OF SUCH DAMAGE.
     30       1.1   gdamore  */
     31       1.1   gdamore /*
     32       1.1   gdamore  * rfcomm_sppd.c
     33       1.1   gdamore  *
     34       1.2    plunky  * Copyright (c) 2007 Iain Hibbert
     35       1.1   gdamore  * Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin (at) yahoo.com>
     36       1.1   gdamore  * All rights reserved.
     37       1.1   gdamore  *
     38       1.1   gdamore  * Redistribution and use in source and binary forms, with or without
     39       1.1   gdamore  * modification, are permitted provided that the following conditions
     40       1.1   gdamore  * are met:
     41       1.1   gdamore  * 1. Redistributions of source code must retain the above copyright
     42       1.1   gdamore  *    notice, this list of conditions and the following disclaimer.
     43       1.1   gdamore  * 2. Redistributions in binary form must reproduce the above copyright
     44       1.1   gdamore  *    notice, this list of conditions and the following disclaimer in the
     45       1.1   gdamore  *    documentation and/or other materials provided with the distribution.
     46       1.1   gdamore  *
     47       1.1   gdamore  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     48       1.1   gdamore  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     49       1.1   gdamore  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     50       1.1   gdamore  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     51       1.1   gdamore  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     52       1.1   gdamore  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     53       1.1   gdamore  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     54       1.1   gdamore  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     55       1.1   gdamore  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     56       1.1   gdamore  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     57       1.1   gdamore  * SUCH DAMAGE.
     58       1.1   gdamore  */
     59       1.1   gdamore 
     60       1.1   gdamore #include <sys/cdefs.h>
     61  1.8.12.1  wrstuden __COPYRIGHT("@(#) Copyright (c) 2007 Iain Hibbert.\
     62  1.8.12.1  wrstuden   Copyright (c) 2006 Itronix, Inc.\
     63  1.8.12.1  wrstuden   Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin (at) yahoo.com>.\
     64  1.8.12.1  wrstuden   All rights reserved.\n");
     65  1.8.12.1  wrstuden __RCSID("$NetBSD: rfcomm_sppd.c,v 1.8.12.1 2008/09/18 04:29:19 wrstuden Exp $");
     66       1.1   gdamore 
     67       1.1   gdamore #include <bluetooth.h>
     68       1.1   gdamore #include <ctype.h>
     69       1.1   gdamore #include <err.h>
     70       1.1   gdamore #include <errno.h>
     71       1.1   gdamore #include <fcntl.h>
     72       1.1   gdamore #include <grp.h>
     73       1.1   gdamore #include <limits.h>
     74       1.1   gdamore #include <paths.h>
     75       1.1   gdamore #include <sdp.h>
     76       1.1   gdamore #include <signal.h>
     77       1.1   gdamore #include <stdarg.h>
     78       1.1   gdamore #include <stdio.h>
     79       1.1   gdamore #include <stdlib.h>
     80       1.1   gdamore #include <string.h>
     81       1.1   gdamore #include <syslog.h>
     82       1.1   gdamore #include <termios.h>
     83       1.1   gdamore #include <unistd.h>
     84       1.1   gdamore 
     85       1.7    plunky #include <netbt/rfcomm.h>
     86       1.7    plunky 
     87       1.1   gdamore #include "rfcomm_sdp.h"
     88       1.1   gdamore 
     89       1.2    plunky #define max(a, b)	((a) > (b) ? (a) : (b))
     90       1.1   gdamore 
     91       1.2    plunky int open_tty(const char *);
     92       1.7    plunky int open_client(bdaddr_t *, bdaddr_t *, int, const char *);
     93       1.7    plunky int open_server(bdaddr_t *, uint8_t, int, const char *);
     94       1.2    plunky void copy_data(int, int);
     95       1.2    plunky void sighandler(int);
     96       1.2    plunky void usage(void);
     97       1.2    plunky void reset_tio(void);
     98       1.2    plunky 
     99       1.2    plunky int done;		/* got a signal */
    100       1.2    plunky struct termios tio;	/* stored termios for reset on exit */
    101       1.2    plunky 
    102       1.2    plunky struct service {
    103       1.2    plunky 	const char	*name;
    104       1.2    plunky 	const char	*description;
    105       1.2    plunky 	uint16_t	class;
    106       1.2    plunky 	int		pdulen;
    107       1.2    plunky } services[] = {
    108       1.2    plunky 	{ "DUN",	"Dialup Networking",
    109       1.2    plunky 	  SDP_SERVICE_CLASS_DIALUP_NETWORKING,
    110       1.2    plunky 	  sizeof(struct sdp_dun_profile)
    111       1.2    plunky 	},
    112       1.2    plunky 	{ "LAN",	"Lan access using PPP",
    113       1.2    plunky 	  SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP,
    114       1.2    plunky 	  sizeof(struct sdp_lan_profile)
    115       1.2    plunky 	},
    116       1.2    plunky 	{ "SP",		"Serial Port",
    117       1.2    plunky 	  SDP_SERVICE_CLASS_SERIAL_PORT,
    118       1.2    plunky 	  sizeof(struct sdp_sp_profile)
    119       1.2    plunky 	},
    120       1.6    plunky 	{ NULL,		NULL,
    121       1.6    plunky 	  0,
    122       1.6    plunky 	  0
    123       1.6    plunky 	}
    124       1.2    plunky };
    125       1.1   gdamore 
    126       1.1   gdamore int
    127       1.1   gdamore main(int argc, char *argv[])
    128       1.1   gdamore {
    129       1.2    plunky 	struct termios		t;
    130       1.2    plunky 	bdaddr_t		laddr, raddr;
    131       1.2    plunky 	fd_set			rdset;
    132       1.6    plunky 	const char		*service;
    133       1.6    plunky 	char			*ep, *tty;
    134       1.7    plunky 	int			lm, n, rfcomm, tty_in, tty_out;
    135       1.2    plunky 	uint8_t			channel;
    136       1.1   gdamore 
    137       1.1   gdamore 	bdaddr_copy(&laddr, BDADDR_ANY);
    138       1.1   gdamore 	bdaddr_copy(&raddr, BDADDR_ANY);
    139       1.3    plunky 	service = "SP";
    140       1.3    plunky 	tty = NULL;
    141       1.2    plunky 	channel = 0;
    142       1.7    plunky 	lm = 0;
    143       1.1   gdamore 
    144       1.1   gdamore 	/* Parse command line options */
    145       1.7    plunky 	while ((n = getopt(argc, argv, "a:c:d:hm:s:t:")) != -1) {
    146       1.1   gdamore 		switch (n) {
    147       1.2    plunky 		case 'a': /* remote device address */
    148       1.1   gdamore 			if (!bt_aton(optarg, &raddr)) {
    149       1.1   gdamore 				struct hostent	*he = NULL;
    150       1.1   gdamore 
    151       1.1   gdamore 				if ((he = bt_gethostbyname(optarg)) == NULL)
    152       1.2    plunky 					errx(EXIT_FAILURE, "%s: %s", optarg,
    153       1.2    plunky 					    hstrerror(h_errno));
    154       1.1   gdamore 
    155       1.1   gdamore 				bdaddr_copy(&raddr, (bdaddr_t *)he->h_addr);
    156       1.1   gdamore 			}
    157       1.1   gdamore 			break;
    158       1.1   gdamore 
    159       1.1   gdamore 		case 'c': /* RFCOMM channel */
    160       1.1   gdamore 			channel = strtoul(optarg, &ep, 10);
    161       1.3    plunky 			if (*ep != '\0' || channel < 1 || channel > 30)
    162       1.3    plunky 				errx(EXIT_FAILURE, "Invalid channel: %s", optarg);
    163       1.3    plunky 
    164       1.1   gdamore 			break;
    165       1.1   gdamore 
    166       1.2    plunky 		case 'd': /* local device address */
    167       1.2    plunky 			if (!bt_devaddr(optarg, &laddr))
    168       1.2    plunky 				err(EXIT_FAILURE, "%s", optarg);
    169       1.2    plunky 
    170       1.1   gdamore 			break;
    171       1.1   gdamore 
    172       1.7    plunky 		case 'm': /* Link Mode */
    173       1.7    plunky 			if (strcasecmp(optarg, "auth") == 0)
    174       1.7    plunky 				lm = RFCOMM_LM_AUTH;
    175       1.7    plunky 			else if (strcasecmp(optarg, "encrypt") == 0)
    176       1.7    plunky 				lm = RFCOMM_LM_ENCRYPT;
    177       1.7    plunky 			else if (strcasecmp(optarg, "secure") == 0)
    178       1.7    plunky 				lm = RFCOMM_LM_SECURE;
    179       1.7    plunky 			else
    180       1.7    plunky 				errx(EXIT_FAILURE, "%s: unknown mode", optarg);
    181       1.7    plunky 
    182       1.7    plunky 			break;
    183       1.7    plunky 
    184       1.3    plunky 		case 's': /* service class */
    185       1.2    plunky 			service = optarg;
    186       1.1   gdamore 			break;
    187       1.1   gdamore 
    188       1.1   gdamore 		case 't': /* Slave TTY name */
    189       1.1   gdamore 			if (optarg[0] != '/')
    190       1.1   gdamore 				asprintf(&tty, "%s%s", _PATH_DEV, optarg);
    191       1.1   gdamore 			else
    192       1.1   gdamore 				tty = optarg;
    193       1.2    plunky 
    194       1.1   gdamore 			break;
    195       1.1   gdamore 
    196       1.1   gdamore 		case 'h':
    197       1.1   gdamore 		default:
    198       1.1   gdamore 			usage();
    199       1.1   gdamore 			/* NOT REACHED */
    200       1.1   gdamore 		}
    201       1.1   gdamore 	}
    202       1.1   gdamore 
    203       1.2    plunky 	/*
    204       1.2    plunky 	 * validate options:
    205       1.3    plunky 	 *	must have channel or remote address but not both
    206       1.2    plunky 	 */
    207       1.3    plunky 	if ((channel == 0 && bdaddr_any(&raddr))
    208       1.3    plunky 	    || (channel != 0 && !bdaddr_any(&raddr)))
    209       1.1   gdamore 		usage();
    210       1.1   gdamore 
    211       1.2    plunky 	/*
    212       1.2    plunky 	 * grab ttys before we start the bluetooth
    213       1.2    plunky 	 */
    214       1.1   gdamore 	if (tty == NULL) {
    215       1.2    plunky 		tty_in = STDIN_FILENO;
    216       1.2    plunky 		tty_out = STDOUT_FILENO;
    217       1.2    plunky 	} else {
    218       1.2    plunky 		tty_in = open_tty(tty);
    219       1.2    plunky 		tty_out = tty_in;
    220       1.2    plunky 	}
    221       1.1   gdamore 
    222       1.2    plunky 	/* open RFCOMM */
    223       1.3    plunky 	if (channel == 0)
    224       1.7    plunky 		rfcomm = open_client(&laddr, &raddr, lm, service);
    225       1.2    plunky 	else
    226       1.7    plunky 		rfcomm = open_server(&laddr, channel, lm, service);
    227       1.1   gdamore 
    228       1.2    plunky 	/*
    229       1.4    plunky 	 * now we are ready to go, so either detach or maybe turn
    230       1.2    plunky 	 * off some input processing, so that rfcomm_sppd can
    231       1.2    plunky 	 * be used directly with stdio
    232       1.2    plunky 	 */
    233       1.2    plunky 	if (tty == NULL) {
    234       1.2    plunky 		if (tcgetattr(tty_in, &t) < 0)
    235       1.2    plunky 			err(EXIT_FAILURE, "tcgetattr");
    236       1.1   gdamore 
    237       1.2    plunky 		memcpy(&tio, &t, sizeof(tio));
    238       1.2    plunky 		t.c_lflag &= ~(ECHO | ICANON);
    239       1.2    plunky 		t.c_iflag &= ~(ICRNL);
    240       1.1   gdamore 
    241       1.4    plunky 		if (memcmp(&tio, &t, sizeof(tio))) {
    242       1.4    plunky 			if (tcsetattr(tty_in, TCSANOW, &t) < 0)
    243       1.4    plunky 				err(EXIT_FAILURE, "tcsetattr");
    244       1.1   gdamore 
    245       1.4    plunky 			atexit(reset_tio);
    246       1.4    plunky 		}
    247       1.2    plunky 	} else {
    248       1.2    plunky 		if (daemon(0, 0) < 0)
    249       1.2    plunky 			err(EXIT_FAILURE, "daemon() failed");
    250       1.1   gdamore 	}
    251       1.1   gdamore 
    252       1.2    plunky 	/* catch signals */
    253       1.2    plunky 	done = 0;
    254       1.2    plunky 	(void)signal(SIGHUP, sighandler);
    255       1.2    plunky 	(void)signal(SIGINT, sighandler);
    256       1.2    plunky 	(void)signal(SIGPIPE, sighandler);
    257       1.2    plunky 	(void)signal(SIGTERM, sighandler);
    258       1.2    plunky 
    259       1.2    plunky 	openlog(getprogname(), LOG_PERROR | LOG_PID, LOG_DAEMON);
    260       1.2    plunky 	syslog(LOG_INFO, "Starting on %s...", (tty ? tty : "stdio"));
    261       1.2    plunky 
    262       1.2    plunky 	n = max(tty_in, rfcomm) + 1;
    263       1.2    plunky 	while (!done) {
    264       1.2    plunky 		FD_ZERO(&rdset);
    265       1.2    plunky 		FD_SET(tty_in, &rdset);
    266       1.2    plunky 		FD_SET(rfcomm, &rdset);
    267       1.1   gdamore 
    268       1.2    plunky 		if (select(n, &rdset, NULL, NULL, NULL) < 0) {
    269       1.1   gdamore 			if (errno == EINTR)
    270       1.1   gdamore 				continue;
    271       1.1   gdamore 
    272       1.2    plunky 			syslog(LOG_ERR, "select error: %m");
    273       1.1   gdamore 			exit(EXIT_FAILURE);
    274       1.1   gdamore 		}
    275       1.1   gdamore 
    276       1.2    plunky 		if (FD_ISSET(tty_in, &rdset))
    277       1.2    plunky 			copy_data(tty_in, rfcomm);
    278       1.1   gdamore 
    279       1.2    plunky 		if (FD_ISSET(rfcomm, &rdset))
    280       1.2    plunky 			copy_data(rfcomm, tty_out);
    281       1.2    plunky 	}
    282       1.1   gdamore 
    283       1.2    plunky 	syslog(LOG_INFO, "Completed on %s", (tty ? tty : "stdio"));
    284       1.2    plunky 	exit(EXIT_SUCCESS);
    285       1.2    plunky }
    286       1.1   gdamore 
    287       1.2    plunky int
    288       1.2    plunky open_tty(const char *tty)
    289       1.1   gdamore {
    290       1.1   gdamore 	char		 pty[PATH_MAX], *slash;
    291       1.1   gdamore 	struct group	*gr = NULL;
    292       1.1   gdamore 	gid_t		 ttygid;
    293       1.2    plunky 	int		 master;
    294       1.1   gdamore 
    295       1.1   gdamore 	/*
    296       1.1   gdamore 	 * Construct master PTY name. The slave tty name must be less then
    297       1.1   gdamore 	 * PATH_MAX characters in length, must contain '/' character and
    298       1.1   gdamore 	 * must not end with '/'.
    299       1.1   gdamore 	 */
    300       1.2    plunky 	if (strlen(tty) >= sizeof(pty))
    301       1.2    plunky 		errx(EXIT_FAILURE, ": tty name too long");
    302       1.1   gdamore 
    303       1.1   gdamore 	strlcpy(pty, tty, sizeof(pty));
    304       1.1   gdamore 	slash = strrchr(pty, '/');
    305       1.2    plunky 	if (slash == NULL || slash[1] == '\0')
    306       1.2    plunky 		errx(EXIT_FAILURE, "%s: invalid tty", tty);
    307       1.1   gdamore 
    308       1.1   gdamore 	slash[1] = 'p';
    309       1.2    plunky 	if (strcmp(pty, tty) == 0)
    310       1.2    plunky 		errx(EXIT_FAILURE, "Master and slave tty are the same (%s)", tty);
    311       1.1   gdamore 
    312       1.2    plunky 	if ((master = open(pty, O_RDWR, 0)) < 0)
    313       1.2    plunky 		err(EXIT_FAILURE, "%s", pty);
    314       1.1   gdamore 
    315       1.1   gdamore 	/*
    316       1.1   gdamore 	 * Slave TTY
    317       1.1   gdamore 	 */
    318       1.1   gdamore 
    319       1.1   gdamore 	if ((gr = getgrnam("tty")) != NULL)
    320       1.1   gdamore 		ttygid = gr->gr_gid;
    321       1.1   gdamore 	else
    322       1.1   gdamore 		ttygid = (gid_t)-1;
    323       1.1   gdamore 
    324       1.2    plunky 	(void)chown(tty, getuid(), ttygid);
    325       1.2    plunky 	(void)chmod(tty, S_IRUSR | S_IWUSR | S_IWGRP);
    326       1.2    plunky 	(void)revoke(tty);
    327       1.2    plunky 
    328       1.2    plunky 	return master;
    329       1.2    plunky }
    330       1.1   gdamore 
    331       1.2    plunky int
    332       1.7    plunky open_client(bdaddr_t *laddr, bdaddr_t *raddr, int lm, const char *service)
    333       1.2    plunky {
    334       1.2    plunky 	struct sockaddr_bt sa;
    335       1.3    plunky 	struct service *s;
    336       1.2    plunky 	struct linger l;
    337       1.3    plunky 	char *ep;
    338       1.2    plunky 	int fd;
    339       1.3    plunky 	uint8_t channel;
    340       1.3    plunky 
    341       1.3    plunky 	for (s = services ; ; s++) {
    342       1.3    plunky 		if (s->name == NULL) {
    343       1.5    plunky 			channel = strtoul(service, &ep, 10);
    344       1.3    plunky 			if (*ep != '\0' || channel < 1 || channel > 30)
    345       1.3    plunky 				errx(EXIT_FAILURE, "Invalid service: %s", service);
    346       1.3    plunky 
    347       1.3    plunky 			break;
    348       1.3    plunky 		}
    349       1.3    plunky 
    350       1.3    plunky 		if (strcasecmp(s->name, service) == 0) {
    351       1.3    plunky 			if (rfcomm_channel_lookup(laddr, raddr, s->class, &channel, &errno) < 0)
    352       1.3    plunky 				err(EXIT_FAILURE, "%s", s->name);
    353       1.3    plunky 
    354       1.3    plunky 			break;
    355       1.3    plunky 		}
    356       1.3    plunky 	}
    357       1.1   gdamore 
    358       1.2    plunky 	memset(&sa, 0, sizeof(sa));
    359       1.2    plunky 	sa.bt_len = sizeof(sa);
    360       1.2    plunky 	sa.bt_family = AF_BLUETOOTH;
    361       1.2    plunky 	bdaddr_copy(&sa.bt_bdaddr, laddr);
    362       1.2    plunky 
    363       1.2    plunky 	fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
    364       1.2    plunky 	if (fd < 0)
    365       1.2    plunky 		err(EXIT_FAILURE, "socket()");
    366       1.2    plunky 
    367       1.2    plunky 	if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0)
    368       1.2    plunky 		err(EXIT_FAILURE, "bind(%s)", bt_ntoa(laddr, NULL));
    369       1.2    plunky 
    370       1.2    plunky 	memset(&l, 0, sizeof(l));
    371       1.2    plunky 	l.l_onoff = 1;
    372       1.2    plunky 	l.l_linger = 5;
    373       1.2    plunky 	if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0)
    374       1.2    plunky 		err(EXIT_FAILURE, "linger()");
    375       1.2    plunky 
    376       1.7    plunky 	if (setsockopt(fd, BTPROTO_RFCOMM, SO_RFCOMM_LM, &lm, sizeof(lm)) < 0)
    377       1.7    plunky 		err(EXIT_FAILURE, "link mode");
    378       1.7    plunky 
    379       1.2    plunky 	sa.bt_channel = channel;
    380       1.2    plunky 	bdaddr_copy(&sa.bt_bdaddr, raddr);
    381       1.2    plunky 
    382       1.2    plunky 	if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0)
    383       1.2    plunky 		err(EXIT_FAILURE, "connect(%s, %d)", bt_ntoa(raddr, NULL),
    384       1.2    plunky 						     channel);
    385       1.1   gdamore 
    386       1.2    plunky 	return fd;
    387       1.2    plunky }
    388       1.1   gdamore 
    389       1.2    plunky /*
    390       1.2    plunky  * In all the profiles we currently support registering, the channel
    391       1.2    plunky  * is the first octet in the PDU, and it seems all the rest can be
    392       1.2    plunky  * zero, so we just use an array of uint8_t big enough to store the
    393       1.2    plunky  * largest, currently LAN. See <sdp.h> for definitions..
    394       1.2    plunky  */
    395       1.2    plunky #define pdu_len		sizeof(struct sdp_lan_profile)
    396       1.1   gdamore 
    397       1.2    plunky int
    398       1.7    plunky open_server(bdaddr_t *laddr, uint8_t channel, int lm, const char *service)
    399       1.1   gdamore {
    400       1.2    plunky 	struct sockaddr_bt sa;
    401       1.2    plunky 	struct linger l;
    402       1.2    plunky 	socklen_t len;
    403       1.2    plunky 	void *ss;
    404       1.2    plunky 	int sv, fd, n;
    405       1.2    plunky 	uint8_t pdu[pdu_len];
    406       1.1   gdamore 
    407       1.2    plunky 	memset(&sa, 0, sizeof(sa));
    408       1.2    plunky 	sa.bt_len = sizeof(sa);
    409       1.2    plunky 	sa.bt_family = AF_BLUETOOTH;
    410       1.2    plunky 	bdaddr_copy(&sa.bt_bdaddr, laddr);
    411       1.2    plunky 	sa.bt_channel = channel;
    412       1.2    plunky 
    413       1.2    plunky 	sv = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
    414       1.2    plunky 	if (sv < 0)
    415       1.2    plunky 		err(EXIT_FAILURE, "socket()");
    416       1.2    plunky 
    417       1.2    plunky 	if (bind(sv, (struct sockaddr *)&sa, sizeof(sa)) < 0)
    418       1.2    plunky 		err(EXIT_FAILURE, "bind(%s, %d)", bt_ntoa(laddr, NULL),
    419       1.2    plunky 						  channel);
    420       1.2    plunky 
    421       1.7    plunky 	if (setsockopt(sv, BTPROTO_RFCOMM, SO_RFCOMM_LM, &lm, sizeof(lm)) < 0)
    422       1.7    plunky 		err(EXIT_FAILURE, "link mode");
    423       1.7    plunky 
    424       1.2    plunky 	if (listen(sv, 1) < 0)
    425       1.2    plunky 		err(EXIT_FAILURE, "listen()");
    426       1.2    plunky 
    427       1.2    plunky 	/* Register service with SDP server */
    428       1.2    plunky 	for (n = 0 ; ; n++) {
    429       1.2    plunky 		if (services[n].name == NULL)
    430       1.2    plunky 			usage();
    431       1.1   gdamore 
    432       1.2    plunky 		if (strcasecmp(services[n].name, service) == 0)
    433       1.2    plunky 			break;
    434       1.1   gdamore 	}
    435       1.1   gdamore 
    436       1.2    plunky 	memset(pdu, 0, pdu_len);
    437       1.2    plunky 	pdu[0] = channel;
    438       1.2    plunky 
    439       1.2    plunky 	ss = sdp_open_local(NULL);
    440       1.2    plunky 	if (ss == NULL || (errno = sdp_error(ss)) != 0)
    441       1.2    plunky 		err(EXIT_FAILURE, "sdp_open_local");
    442       1.2    plunky 
    443       1.2    plunky 	if (sdp_register_service(ss, services[n].class, laddr,
    444       1.2    plunky 		    pdu, services[n].pdulen, NULL) != 0) {
    445       1.2    plunky 		errno = sdp_error(ss);
    446       1.2    plunky 		err(EXIT_FAILURE, "sdp_register_service");
    447       1.2    plunky 	}
    448       1.2    plunky 
    449       1.2    plunky 	len = sizeof(sa);
    450       1.2    plunky 	fd = accept(sv, (struct sockaddr *)&sa, &len);
    451       1.2    plunky 	if (fd < 0)
    452       1.2    plunky 		err(EXIT_FAILURE, "accept");
    453       1.2    plunky 
    454       1.2    plunky 	memset(&l, 0, sizeof(l));
    455       1.2    plunky 	l.l_onoff = 1;
    456       1.2    plunky 	l.l_linger = 5;
    457       1.2    plunky 	if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0)
    458       1.2    plunky 		err(EXIT_FAILURE, "linger()");
    459       1.2    plunky 
    460       1.2    plunky 	close(sv);
    461       1.2    plunky 	return fd;
    462       1.2    plunky }
    463       1.1   gdamore 
    464       1.2    plunky void
    465       1.2    plunky copy_data(int src, int dst)
    466       1.1   gdamore {
    467       1.2    plunky 	static char	buf[BUFSIZ];
    468       1.2    plunky 	ssize_t		nr, nw, off;
    469       1.1   gdamore 
    470       1.2    plunky 	while ((nr = read(src, buf, sizeof(buf))) == -1) {
    471       1.2    plunky 		if (errno != EINTR) {
    472       1.2    plunky 			syslog(LOG_ERR, "read failed: %m");
    473       1.2    plunky 			exit(EXIT_FAILURE);
    474       1.2    plunky 		}
    475       1.2    plunky 	}
    476       1.1   gdamore 
    477       1.3    plunky 	if (nr == 0)	/* reached EOF */
    478       1.3    plunky 		done++;
    479       1.3    plunky 
    480       1.2    plunky 	for (off = 0 ; nr ; nr -= nw, off += nw) {
    481       1.2    plunky 		if ((nw = write(dst, buf + off, (size_t)nr)) == -1) {
    482       1.2    plunky 			syslog(LOG_ERR, "write failed: %m");
    483       1.2    plunky 			exit(EXIT_FAILURE);
    484       1.1   gdamore 		}
    485       1.1   gdamore 	}
    486       1.2    plunky }
    487       1.1   gdamore 
    488       1.2    plunky void
    489       1.2    plunky sighandler(int s)
    490       1.2    plunky {
    491       1.1   gdamore 
    492       1.2    plunky 	done++;
    493       1.2    plunky }
    494       1.2    plunky 
    495       1.2    plunky void
    496       1.2    plunky reset_tio(void)
    497       1.1   gdamore {
    498       1.1   gdamore 
    499       1.2    plunky 	tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio);
    500       1.2    plunky }
    501       1.2    plunky 
    502       1.2    plunky void
    503       1.1   gdamore usage(void)
    504       1.1   gdamore {
    505       1.7    plunky 	const char *cmd = getprogname();
    506       1.2    plunky 	struct service *s;
    507       1.2    plunky 
    508       1.7    plunky 	fprintf(stderr, "Usage: %s [-d device] [-m mode] [-s service] [-t tty]\n"
    509       1.7    plunky 			"       %*s {-a bdaddr | -c channel}\n"
    510       1.2    plunky 			"\n"
    511       1.2    plunky 			"Where:\n"
    512       1.2    plunky 			"\t-a bdaddr    remote device address\n"
    513       1.3    plunky 			"\t-c channel   local RFCOMM channel\n"
    514       1.2    plunky 			"\t-d device    local device address\n"
    515       1.7    plunky 			"\t-m mode      link mode\n"
    516       1.3    plunky 			"\t-s service   service class\n"
    517       1.2    plunky 			"\t-t tty       run in background using pty\n"
    518       1.8       dsl 			"\n", cmd, (int)strlen(cmd), "");
    519       1.2    plunky 
    520       1.3    plunky 	fprintf(stderr, "Known service classes:\n");
    521       1.2    plunky 	for (s = services ; s->name != NULL ; s++)
    522       1.3    plunky 		fprintf(stderr, "\t%-13s%s\n", s->name, s->description);
    523       1.1   gdamore 
    524       1.1   gdamore 	exit(EXIT_FAILURE);
    525       1.2    plunky }
    526