xref: /netbsd-src/usr.bin/rfcomm_sppd/rfcomm_sppd.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
1 /*	$NetBSD: rfcomm_sppd.c,v 1.16 2013/12/09 09:35:17 wiz Exp $	*/
2 
3 /*-
4  * Copyright (c) 2006 Itronix Inc.
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  * 3. The name of Itronix Inc. may not be used to endorse
16  *    or promote products derived from this software without specific
17  *    prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
23  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26  * ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 /*
32  * Copyright (c) 2009 The NetBSD Foundation, Inc.
33  * Copyright (c) 2007 Iain Hibbert
34  * Copyright (c) 2003 Maksim Yevmenkin <m_evmenkin@yahoo.com>
35  * All rights reserved.
36  *
37  * Redistribution and use in source and binary forms, with or without
38  * modification, are permitted provided that the following conditions
39  * are met:
40  * 1. Redistributions of source code must retain the above copyright
41  *    notice, this list of conditions and the following disclaimer.
42  * 2. Redistributions in binary form must reproduce the above copyright
43  *    notice, this list of conditions and the following disclaimer in the
44  *    documentation and/or other materials provided with the distribution.
45  *
46  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
47  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
50  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56  * SUCH DAMAGE.
57  */
58 
59 #include <sys/cdefs.h>
60 __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc.\
61   Copyright (c) 2007 Iain Hibbert.\
62   Copyright (c) 2006 Itronix, Inc.\
63   Copyright (c) 2003 Maksim Yevmenkin m_evmenkin@yahoo.com.\
64   All rights reserved.");
65 __RCSID("$NetBSD: rfcomm_sppd.c,v 1.16 2013/12/09 09:35:17 wiz Exp $");
66 
67 #include <sys/param.h>
68 
69 #include <bluetooth.h>
70 #include <ctype.h>
71 #include <err.h>
72 #include <errno.h>
73 #include <fcntl.h>
74 #include <grp.h>
75 #include <limits.h>
76 #include <paths.h>
77 #include <sdp.h>
78 #include <signal.h>
79 #include <stdarg.h>
80 #include <poll.h>
81 #include <stdio.h>
82 #include <stdlib.h>
83 #include <string.h>
84 #include <syslog.h>
85 #include <termios.h>
86 #include <unistd.h>
87 
88 #include <netbt/rfcomm.h>
89 
90 static int open_tty(const char *);
91 static int open_client(bdaddr_t *, bdaddr_t *, int, uintmax_t, const char *);
92 static int open_server(bdaddr_t *, uint16_t, uint8_t, int, const char *);
93 static void copy_data(int, int);
94 static int service_search(const bdaddr_t *, const bdaddr_t *, uint16_t,
95     uintmax_t *, uintmax_t *);
96 static void sighandler(int);
97 static void usage(void) __attribute__((__noreturn__));
98 static void reset_tio(void);
99 
100 static sig_atomic_t done;	/* got a signal */
101 static struct termios tio;	/* stored termios for reset on exit */
102 
103 static const struct service {
104 	const char *	name;
105 	const char *	description;
106 	uint16_t	class;
107 } services[] = {
108 	{ "DUN",	"Dialup Networking",
109 	    SDP_SERVICE_CLASS_DIALUP_NETWORKING		},
110 	{ "LAN",	"LAN access using PPP",
111 	    SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP	},
112 	{ "SP",		"Serial Port",
113 	    SDP_SERVICE_CLASS_SERIAL_PORT		},
114 	{ NULL,		NULL,		0		}
115 };
116 
117 int
118 main(int argc, char *argv[])
119 {
120 	struct termios		t;
121 	bdaddr_t		laddr, raddr;
122 	struct pollfd		pfd[2];
123 	const char		*service;
124 	char			*ep, *tty;
125 	int			n, lm, rfcomm, tty_in, tty_out;
126 	uint16_t		psm;
127 	uint8_t			channel;
128 
129 	setprogname(argv[0]);
130 	bdaddr_copy(&laddr, BDADDR_ANY);
131 	bdaddr_copy(&raddr, BDADDR_ANY);
132 	service = "SP";
133 	tty = NULL;
134 	channel = RFCOMM_CHANNEL_ANY;
135 	psm = L2CAP_PSM_RFCOMM;
136 	lm = 0;
137 
138 	/* Parse command line options */
139 	while ((n = getopt(argc, argv, "a:c:d:hm:p:s:t:")) != -1) {
140 		switch (n) {
141 		case 'a': /* remote device address */
142 			if (!bt_aton(optarg, &raddr)) {
143 				struct hostent	*he = NULL;
144 
145 				if ((he = bt_gethostbyname(optarg)) == NULL)
146 					errx(EXIT_FAILURE, "%s: %s", optarg,
147 					    hstrerror(h_errno));
148 
149 				bdaddr_copy(&raddr, (bdaddr_t *)he->h_addr);
150 			}
151 			break;
152 
153 		case 'c': /* RFCOMM channel */
154 			channel = strtoul(optarg, &ep, 10);
155 			if (*ep != '\0'
156 			    || channel < RFCOMM_CHANNEL_MIN
157 			    || channel > RFCOMM_CHANNEL_MAX)
158 				errx(EXIT_FAILURE, "Invalid channel: %s",
159 				    optarg);
160 
161 			break;
162 
163 		case 'd': /* local device address */
164 			if (!bt_devaddr(optarg, &laddr))
165 				err(EXIT_FAILURE, "%s", optarg);
166 
167 			break;
168 
169 		case 'm': /* Link Mode */
170 			if (strcasecmp(optarg, "auth") == 0)
171 				lm = RFCOMM_LM_AUTH;
172 			else if (strcasecmp(optarg, "encrypt") == 0)
173 				lm = RFCOMM_LM_ENCRYPT;
174 			else if (strcasecmp(optarg, "secure") == 0)
175 				lm = RFCOMM_LM_SECURE;
176 			else
177 				errx(EXIT_FAILURE, "Unknown mode: %s", optarg);
178 
179 			break;
180 
181 		case 'p': /* PSM */
182 			psm = strtoul(optarg, &ep, 0);
183 			if (*ep != '\0' || L2CAP_PSM_INVALID(psm))
184 				errx(EXIT_FAILURE, "Invalid PSM: %s", optarg);
185 
186 			break;
187 
188 		case 's': /* service class */
189 			service = optarg;
190 			break;
191 
192 		case 't': /* Slave TTY name */
193 			if (optarg[0] != '/')
194 				asprintf(&tty, "%s%s", _PATH_DEV, optarg);
195 			else
196 				tty = optarg;
197 
198 			break;
199 
200 		case 'h':
201 		default:
202 			usage();
203 			/* NOT REACHED */
204 		}
205 	}
206 
207 	/*
208 	 * validate options:
209 	 *	cannot have remote address if channel was given
210 	 */
211 	if (channel != RFCOMM_CHANNEL_ANY && !bdaddr_any(&raddr))
212 		usage();
213 
214 	/*
215 	 * grab ttys before we start the bluetooth
216 	 */
217 	if (tty == NULL) {
218 		tty_in = STDIN_FILENO;
219 		tty_out = STDOUT_FILENO;
220 	} else {
221 		tty_in = open_tty(tty);
222 		tty_out = tty_in;
223 	}
224 
225 	/* open RFCOMM */
226 	if (!bdaddr_any(&raddr))
227 		rfcomm = open_client(&laddr, &raddr, lm, psm, service);
228 	else
229 		rfcomm = open_server(&laddr, psm, channel, lm, service);
230 
231 	/*
232 	 * now we are ready to go, so either detach or maybe turn
233 	 * off some input processing, so that rfcomm_sppd can
234 	 * be used directly with stdio
235 	 */
236 	if (tty == NULL) {
237 		if (tcgetattr(tty_in, &t) != -1) {
238 			tio = t;
239 			t.c_lflag &= ~(ECHO | ICANON);
240 			t.c_iflag &= ~(ICRNL);
241 
242 			if (tio.c_lflag != t.c_lflag ||
243 			    tio.c_iflag != t.c_iflag) {
244 				if (tcsetattr(tty_in, TCSANOW, &t) == -1)
245 					err(EXIT_FAILURE, "tcsetattr");
246 
247 				atexit(reset_tio);
248 			}
249 		}
250 	} else {
251 		if (daemon(0, 0) == -1)
252 			err(EXIT_FAILURE, "daemon() failed");
253 	}
254 
255 	/* catch signals */
256 	done = 0;
257 	(void)signal(SIGHUP, sighandler);
258 	(void)signal(SIGINT, sighandler);
259 	(void)signal(SIGPIPE, sighandler);
260 	(void)signal(SIGTERM, sighandler);
261 
262 	openlog(getprogname(), LOG_PERROR | LOG_PID, LOG_DAEMON);
263 	syslog(LOG_INFO, "Starting on %s...", (tty ? tty : "stdio"));
264 
265 	pfd[0].fd = tty_in;
266 	pfd[1].fd = rfcomm;
267 	pfd[0].events = POLLIN|POLLRDNORM;
268 	pfd[1].events = POLLIN|POLLRDNORM;
269 
270 	while (!done) {
271 		if (poll(pfd, 2, INFTIM) == -1) {
272 			if (errno == EINTR)
273 				continue;
274 
275 			syslog(LOG_ERR, "poll error: %m");
276 		}
277 		if (pfd[0].revents & (POLLIN|POLLRDNORM))
278 			copy_data(tty_in, rfcomm);
279 
280 		if (pfd[1].revents & (POLLIN|POLLRDNORM))
281 			copy_data(rfcomm, tty_out);
282 	}
283 
284 	syslog(LOG_INFO, "Completed on %s", (tty ? tty : "stdio"));
285 	return EXIT_SUCCESS;
286 }
287 
288 static int
289 open_tty(const char *tty)
290 {
291 	char		 pty[PATH_MAX], *slash;
292 	struct group	*gr = NULL;
293 	gid_t		 ttygid;
294 	int		 master;
295 
296 	/*
297 	 * Construct master PTY name. The slave tty name must be less than
298 	 * PATH_MAX characters in length, must contain '/' character and
299 	 * must not end with '/'.
300 	 */
301 	if (strlcpy(pty, tty, sizeof(pty)) >= sizeof(pty))
302 		errx(EXIT_FAILURE, "Tty name too long `%s'", tty);
303 
304 	slash = strrchr(pty, '/');
305 	if (slash == NULL || slash[1] == '\0')
306 		errx(EXIT_FAILURE, "Invalid tty `%s'", tty);
307 
308 	slash[1] = 'p';
309 	if (strcmp(pty, tty) == 0)
310 		errx(EXIT_FAILURE, "Master and slave tty are the same (%s)",
311 		    tty);
312 
313 	if ((master = open(pty, O_RDWR)) == -1)
314 		err(EXIT_FAILURE, "Cannot open `%s'", pty);
315 
316 	/*
317 	 * Slave TTY
318 	 */
319 	if ((gr = getgrnam("tty")) != NULL)
320 		ttygid = gr->gr_gid;
321 	else
322 		ttygid = (gid_t)-1;
323 
324 	if (chown(tty, getuid(), ttygid) == -1)
325 		err(EXIT_FAILURE, "Cannot chown `%s'", pty);
326 	if (chmod(tty, S_IRUSR | S_IWUSR | S_IWGRP) == -1)
327 		err(EXIT_FAILURE, "Cannot chmod `%s'", pty);
328 	if (revoke(tty) == -1)
329 		err(EXIT_FAILURE, "Cannot revoke `%s'", pty);
330 
331 	return master;
332 }
333 
334 static int
335 open_client(bdaddr_t *laddr, bdaddr_t *raddr, int lm, uintmax_t psm,
336     const char *service)
337 {
338 	struct sockaddr_bt sa;
339 	const struct service *s;
340 	struct linger l;
341 	char *ep;
342 	int fd;
343 	uintmax_t channel;
344 
345 	for (s = services ; ; s++) {
346 		if (s->name == NULL) {
347 			errno = 0;
348 			channel = strtoul(service, &ep, 10);
349 			if (service == ep || *ep != '\0')
350 				errx(EXIT_FAILURE, "Unknown service `%s'",
351 				    service);
352 			if (channel == ULONG_MAX && errno == ERANGE)
353 				err(EXIT_FAILURE, "Service `%s'",
354 				    service);
355 
356 			break;
357 		}
358 
359 		if (strcasecmp(s->name, service) == 0) {
360 			if (service_search(laddr, raddr, s->class, &psm,
361 			    &channel) == -1)
362 				err(EXIT_FAILURE, "%s", s->name);
363 
364 			break;
365 		}
366 	}
367 
368 	if (channel < RFCOMM_CHANNEL_MIN || channel > RFCOMM_CHANNEL_MAX)
369 		errx(EXIT_FAILURE, "Invalid channel %"PRIuMAX, channel);
370 
371 	if (L2CAP_PSM_INVALID(psm))
372 		errx(EXIT_FAILURE, "Invalid PSM 0x%04"PRIxMAX, psm);
373 
374 	memset(&sa, 0, sizeof(sa));
375 	sa.bt_len = sizeof(sa);
376 	sa.bt_family = AF_BLUETOOTH;
377 	bdaddr_copy(&sa.bt_bdaddr, laddr);
378 
379 	fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
380 	if (fd == -1)
381 		err(EXIT_FAILURE, "socket()");
382 
383 	if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1)
384 		err(EXIT_FAILURE, "bind(%s)", bt_ntoa(laddr, NULL));
385 
386 	memset(&l, 0, sizeof(l));
387 	l.l_onoff = 1;
388 	l.l_linger = 5;
389 	if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) == -1)
390 		err(EXIT_FAILURE, "linger()");
391 
392 	if (setsockopt(fd, BTPROTO_RFCOMM, SO_RFCOMM_LM, &lm, sizeof(lm)) == -1)
393 		err(EXIT_FAILURE, "link mode");
394 
395 	sa.bt_psm = psm;
396 	sa.bt_channel = channel;
397 	bdaddr_copy(&sa.bt_bdaddr, raddr);
398 
399 	if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1)
400 		err(EXIT_FAILURE, "connect(%s, 0x%04"PRIxMAX", %"PRIuMAX")",
401 		    bt_ntoa(raddr, NULL), psm, channel);
402 
403 	return fd;
404 }
405 
406 static int
407 open_server(bdaddr_t *laddr, uint16_t psm, uint8_t channel, int lm,
408     const char *service)
409 {
410 	uint8_t	buffer[256];
411 	struct sockaddr_bt sa;
412 	const struct service *s;
413 	struct linger l;
414 	socklen_t len;
415 	sdp_session_t ss;
416 	sdp_data_t rec;
417 	int sv, fd;
418 
419 	for (s = services; ; s++) {
420 		if (s->name == NULL)
421 			usage();
422 
423 		if (strcasecmp(s->name, service) == 0)
424 			break;
425 	}
426 
427 	/* Open server socket */
428 	sv = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
429 	if (sv == -1)
430 		err(EXIT_FAILURE, "socket()");
431 
432 	memset(&sa, 0, sizeof(sa));
433 	sa.bt_len = sizeof(sa);
434 	sa.bt_family = AF_BLUETOOTH;
435 	sa.bt_psm = psm;
436 	sa.bt_channel = channel;
437 	bdaddr_copy(&sa.bt_bdaddr, laddr);
438 	if (bind(sv, (struct sockaddr *)&sa, sizeof(sa)) == -1)
439 		err(EXIT_FAILURE, "bind(%s, 0x%04x, %d)",
440 		    bt_ntoa(laddr, NULL), psm, channel);
441 
442 	if (setsockopt(sv, BTPROTO_RFCOMM, SO_RFCOMM_LM, &lm, sizeof(lm)) == -1)
443 		err(EXIT_FAILURE, "link mode");
444 
445 	if (listen(sv, 1) == -1)
446 		err(EXIT_FAILURE, "listen()");
447 
448 	len = sizeof(sa);
449 	if (getsockname(sv, (struct sockaddr *)&sa, &len) == -1)
450 		err(EXIT_FAILURE, "getsockname()");
451 	if (len != sizeof(sa))
452 		errx(EXIT_FAILURE, "getsockname()");
453 
454 	/* Build SDP record */
455 	rec.next = buffer;
456 	rec.end = buffer + sizeof(buffer);
457 
458 	sdp_put_uint16(&rec, SDP_ATTR_SERVICE_RECORD_HANDLE);
459 	sdp_put_uint32(&rec, 0x00000000);
460 
461 	sdp_put_uint16(&rec, SDP_ATTR_SERVICE_CLASS_ID_LIST);
462 	sdp_put_seq(&rec, 3);
463 	sdp_put_uuid16(&rec, s->class);
464 
465 	len = (psm == L2CAP_PSM_RFCOMM ? 0 : 3);
466 
467 	sdp_put_uint16(&rec, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
468 	sdp_put_seq(&rec, 12 + len);
469 	sdp_put_seq(&rec, 3 + len);
470 	sdp_put_uuid16(&rec, SDP_UUID_PROTOCOL_L2CAP);
471 	if (len > 0)
472 		sdp_put_uint16(&rec, psm);
473 	sdp_put_seq(&rec, 5);
474 	sdp_put_uuid16(&rec, SDP_UUID_PROTOCOL_RFCOMM);
475 	sdp_put_uint8(&rec, sa.bt_channel);
476 
477 	sdp_put_uint16(&rec, SDP_ATTR_BROWSE_GROUP_LIST);
478 	sdp_put_seq(&rec, 3);
479 	sdp_put_uuid16(&rec, SDP_SERVICE_CLASS_PUBLIC_BROWSE_GROUP);
480 
481 	sdp_put_uint16(&rec, SDP_ATTR_LANGUAGE_BASE_ATTRIBUTE_ID_LIST);
482 	sdp_put_seq(&rec, 9);
483 	sdp_put_uint16(&rec, 0x656e);	/* "en" */
484 	sdp_put_uint16(&rec, 106);	/* UTF-8 */
485 	sdp_put_uint16(&rec, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID);
486 
487 	if (s->class == SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP) {
488 		sdp_put_uint16(&rec, SDP_ATTR_SERVICE_AVAILABILITY);
489 		sdp_put_uint8(&rec, 0x00);
490 	}
491 
492 	sdp_put_uint16(&rec, SDP_ATTR_BLUETOOTH_PROFILE_DESCRIPTOR_LIST);
493 	sdp_put_seq(&rec, 8);
494 	sdp_put_seq(&rec, 6);
495 	sdp_put_uuid16(&rec, s->class);
496 	sdp_put_uint16(&rec, 0x0100);	/* v1.0 */
497 
498 	sdp_put_uint16(&rec, SDP_ATTR_PRIMARY_LANGUAGE_BASE_ID
499 	    + SDP_ATTR_SERVICE_NAME_OFFSET);
500 	sdp_put_str(&rec, s->description, -1);
501 
502 	if (s->class == SDP_SERVICE_CLASS_DIALUP_NETWORKING) {
503 		sdp_put_uint16(&rec, SDP_ATTR_AUDIO_FEEDBACK_SUPPORT);
504 		sdp_put_bool(&rec, false);
505 	}
506 
507 #if 0
508 	if (s->class == SDP_SERVICE_CLASS_LAN_ACCESS_USING_PPP) {
509 		sdp_put_uint16(&rec, SDP_ATTR_IP_SUBNET);	/* TODO */
510 		sdp_put_str(&rec, "0.0.0.0/0", -1);
511 	}
512 #endif
513 
514 	rec.end = rec.next;
515 	rec.next = buffer;
516 
517 	/* Register service with SDP server */
518 	ss = sdp_open_local(NULL);
519 	if (ss == NULL)
520 		err(EXIT_FAILURE, "sdp_open_local");
521 
522 	if (!sdp_record_insert(ss, laddr, NULL, &rec))
523 		err(EXIT_FAILURE, "sdp_record_insert");
524 
525 	/* Accept client connection */
526 	len = sizeof(sa);
527 	fd = accept(sv, (struct sockaddr *)&sa, &len);
528 	if (fd == -1)
529 		err(EXIT_FAILURE, "accept");
530 
531 	memset(&l, 0, sizeof(l));
532 	l.l_onoff = 1;
533 	l.l_linger = 5;
534 	if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) == -1)
535 		err(EXIT_FAILURE, "linger()");
536 
537 	close(sv);
538 	return fd;
539 }
540 
541 static void
542 copy_data(int src, int dst)
543 {
544 	static char	buf[BUFSIZ];
545 	ssize_t		nr, nw, off;
546 
547 	while ((nr = read(src, buf, sizeof(buf))) == -1) {
548 		if (errno != EINTR) {
549 			syslog(LOG_ERR, "read failed: %m");
550 			exit(EXIT_FAILURE);
551 		}
552 	}
553 
554 	if (nr == 0)	/* reached EOF */
555 		done++;
556 
557 	for (off = 0 ; nr ; nr -= nw, off += nw) {
558 		if ((nw = write(dst, buf + off, (size_t)nr)) == -1) {
559 			syslog(LOG_ERR, "write failed: %m");
560 			exit(EXIT_FAILURE);
561 		}
562 	}
563 }
564 
565 static int
566 service_search(bdaddr_t const *laddr, bdaddr_t const *raddr,
567     uint16_t class, uintmax_t *psm, uintmax_t *channel)
568 {
569 	uint8_t		buffer[6];	/* SSP (3 bytes) + AIL (3 bytes) */
570 	sdp_session_t	ss;
571 	sdp_data_t	ail, ssp, rsp, rec, value, pdl, seq;
572 	uint16_t	attr;
573 	bool		rv;
574 
575 	seq.next = buffer;
576 	seq.end = buffer + sizeof(buffer);
577 
578 	/*
579 	 * build ServiceSearchPattern (3 bytes)
580 	 */
581 	ssp.next = seq.next;
582 	sdp_put_uuid16(&seq, class);
583 	ssp.end = seq.next;
584 
585 	/*
586 	 * build AttributeIDList (3 bytes)
587 	 */
588 	ail.next = seq.next;
589 	sdp_put_uint16(&seq, SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
590 	ail.end = seq.next;
591 
592 	ss = sdp_open(laddr, raddr);
593 	if (ss == NULL)
594 		return -1;
595 
596 	rv = sdp_service_search_attribute(ss, &ssp, &ail, &rsp);
597 	if (!rv) {
598 		sdp_close(ss);
599 		return -1;
600 	}
601 
602 	/*
603 	 * The response will be a list of records that matched our
604 	 * ServiceSearchPattern, where each record is a sequence
605 	 * containing a single ProtocolDescriptorList attribute and
606 	 * value
607 	 *
608 	 *	seq
609 	 *	  uint16	ProtocolDescriptorList
610 	 *	  value
611 	 *	seq
612 	 *	  uint16	ProtocolDescriptorList
613 	 *	  value
614 	 *
615 	 * If the ProtocolDescriptorList describes a single stack,
616 	 * the attribute value takes the form of a single Data Element
617 	 * Sequence where each member is a protocol descriptor.
618 	 *
619 	 *	seq
620 	 *	  list
621 	 *
622 	 * If it is possible for more than one kind of protocol
623 	 * stack to be used to gain access to the service, the
624 	 * ProtocolDescriptorList takes the form of a Data Element
625 	 * Alternative where each member is a Data Element Sequence
626 	 * describing an alternative protocol stack.
627 	 *
628 	 *	alt
629 	 *	  seq
630 	 *	    list
631 	 *	  seq
632 	 *	    list
633 	 *
634 	 * Each protocol stack description contains a sequence for each
635 	 * protocol, where each sequence contains the protocol UUID as
636 	 * the first element, and any ProtocolSpecificParameters. We are
637 	 * interested in the L2CAP psm if provided, and the RFCOMM channel
638 	 * number, stored as parameter#1 in each case.
639 	 *
640 	 *	seq
641 	 *	  uuid		L2CAP
642 	 *	  uint16	psm
643 	 *	seq
644 	 *	  uuid		RFCOMM
645 	 *	  uint8		channel
646 	 */
647 
648 	rv = false;
649 	while (!rv && sdp_get_seq(&rsp, &rec)) {
650 		if (!sdp_get_attr(&rec, &attr, &value)
651 		    || attr != SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST)
652 			continue;
653 
654 		sdp_get_alt(&value, &value);	/* strip any alt container */
655 		while (!rv && sdp_get_seq(&value, &pdl)) {
656 			*psm = L2CAP_PSM_RFCOMM;
657 			if (sdp_get_seq(&pdl, &seq)
658 			    && sdp_match_uuid16(&seq, SDP_UUID_PROTOCOL_L2CAP)
659 			    && (sdp_get_uint(&seq, psm) || true)
660 			    && sdp_get_seq(&pdl, &seq)
661 			    && sdp_match_uuid16(&seq, SDP_UUID_PROTOCOL_RFCOMM)
662 			    && sdp_get_uint(&seq, channel))
663 				rv = true;
664 		}
665 	}
666 
667 	sdp_close(ss);
668 	if (rv)
669 		return 0;
670 	errno = ENOATTR;
671 	return -1;
672 }
673 
674 static void
675 sighandler(int s)
676 {
677 
678 	done++;
679 }
680 
681 static void
682 reset_tio(void)
683 {
684 
685 	tcsetattr(STDIN_FILENO, TCSAFLUSH, &tio);
686 }
687 
688 static void
689 usage(void)
690 {
691 	const char *cmd = getprogname();
692 	const struct service *s;
693 
694 	fprintf(stderr, "Usage: %s [-d device] [-m mode] [-p psm] [-s service]"
695 	    " [-t tty]\n"
696 	    "       %*s {-a bdaddr | [-c channel]}\n"
697 	    "\n"
698 	    "Where:\n"
699 	    "\t-a bdaddr    remote device address\n"
700 	    "\t-c channel   local RFCOMM channel\n"
701 	    "\t-d device    local device address\n"
702 	    "\t-m mode      link mode\n"
703 	    "\t-p psm       protocol/service multiplexer\n"
704 	    "\t-s service   service class\n"
705 	    "\t-t tty       run in background using pty\n"
706 	    "\n", cmd, (int)strlen(cmd), "");
707 
708 	fprintf(stderr, "Known service classes:\n");
709 	for (s = services ; s->name != NULL ; s++)
710 		fprintf(stderr, "\t%-13s%s\n", s->name, s->description);
711 
712 	exit(EXIT_FAILURE);
713 }
714