xref: /netbsd-src/lib/libbluetooth/bt_dev.c (revision 37a23ecf39b616ebc8f7f8be96b814ad1bd168f5)
1 /*	$NetBSD: bt_dev.c,v 1.5 2023/06/24 05:18:12 msaitoh Exp $	*/
2 
3 /*-
4  * Copyright (c) 2009 Iain Hibbert
5  * Copyright (c) 2009 Maksim Yevmenkin <m_evmenkin@yahoo.com>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 /*-
31  * Copyright (c) 2006 Itronix Inc.
32  * All rights reserved.
33  *
34  * Written by Iain Hibbert for Itronix Inc.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  * 3. The name of Itronix Inc. may not be used to endorse
45  *    or promote products derived from this software without specific
46  *    prior written permission.
47  *
48  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
49  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
50  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
51  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
52  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
53  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
54  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
55  * ON ANY THEORY OF LIABILITY, WHETHER IN
56  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
57  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
58  * POSSIBILITY OF SUCH DAMAGE.
59  */
60 
61 #include <sys/cdefs.h>
62 __RCSID("$NetBSD: bt_dev.c,v 1.5 2023/06/24 05:18:12 msaitoh Exp $");
63 
64 #include <sys/event.h>
65 #include <sys/ioctl.h>
66 #include <sys/param.h>
67 #include <sys/time.h>
68 #include <sys/uio.h>
69 
70 #include <bluetooth.h>
71 #include <errno.h>
72 #include <stdlib.h>
73 #include <string.h>
74 #include <unistd.h>
75 
76 int
bt_devaddr(const char * name,bdaddr_t * addr)77 bt_devaddr(const char *name, bdaddr_t *addr)
78 {
79 	struct btreq btr;
80 	bdaddr_t bdaddr;
81 	int s, rv;
82 
83 	if (name == NULL) {
84 		errno = EINVAL;
85 		return 0;
86 	}
87 
88 	if (addr == NULL)
89 		addr = &bdaddr;
90 
91 	if (bt_aton(name, addr))
92 		return bt_devname(NULL, addr);
93 
94 	memset(&btr, 0, sizeof(btr));
95 	strlcpy(btr.btr_name, name, HCI_DEVNAME_SIZE);
96 
97 	s = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
98 	if (s == -1)
99 		return 0;
100 
101 	rv = ioctl(s, SIOCGBTINFO, &btr);
102 	close(s);
103 
104 	if (rv == -1)
105 		return 0;
106 
107 	if ((btr.btr_flags & BTF_UP) == 0) {
108 		errno = ENXIO;
109 		return 0;
110 	}
111 
112 	bdaddr_copy(addr, &btr.btr_bdaddr);
113 	return 1;
114 }
115 
116 int
bt_devname(char * name,const bdaddr_t * bdaddr)117 bt_devname(char *name, const bdaddr_t *bdaddr)
118 {
119 	struct btreq btr;
120 	int s, rv;
121 
122 	if (bdaddr == NULL) {
123 		errno = EINVAL;
124 		return 0;
125 	}
126 
127 	memset(&btr, 0, sizeof(btr));
128 	bdaddr_copy(&btr.btr_bdaddr, bdaddr);
129 
130 	s = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
131 	if (s == -1)
132 		return 0;
133 
134 	rv = ioctl(s, SIOCGBTINFOA, &btr);
135 	close(s);
136 
137 	if (rv == -1)
138 		return 0;
139 
140 	if ((btr.btr_flags & BTF_UP) == 0) {
141 		errno = ENXIO;
142 		return 0;
143 	}
144 
145 	if (name != NULL)
146 		strlcpy(name, btr.btr_name, HCI_DEVNAME_SIZE);
147 
148 	return 1;
149 }
150 
151 int
bt_devopen(const char * name,int options)152 bt_devopen(const char *name, int options)
153 {
154 	struct sockaddr_bt	sa;
155 	int			opt, s;
156 
157 	memset(&sa, 0, sizeof(sa));
158 	sa.bt_len = sizeof(sa);
159 	sa.bt_family = AF_BLUETOOTH;
160 
161 	if (name != NULL && !bt_devaddr(name, &sa.bt_bdaddr))
162 		return -1;
163 
164 	s = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
165 	if (s == -1)
166 		return -1;
167 
168 	opt = 1;
169 
170 	if ((options & BTOPT_DIRECTION) && setsockopt(s, BTPROTO_HCI,
171 	    SO_HCI_DIRECTION, &opt, sizeof(opt)) == -1) {
172 		close(s);
173 		return -1;
174 	}
175 
176 	if ((options & BTOPT_TIMESTAMP) && setsockopt(s, SOL_SOCKET,
177 	    SO_TIMESTAMP, &opt, sizeof(opt)) == -1) {
178 		close(s);
179 		return -1;
180 	}
181 
182 	if (bind(s, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
183 		close(s);
184 		return -1;
185 	}
186 
187 	if (name != NULL
188 	    && connect(s, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
189 		close(s);
190 		return -1;
191 	}
192 
193 	return s;
194 }
195 
196 ssize_t
bt_devsend(int s,uint16_t opcode,void * param,size_t plen)197 bt_devsend(int s, uint16_t opcode, void *param, size_t plen)
198 {
199 	hci_cmd_hdr_t	hdr;
200 	struct iovec	iov[2];
201 	ssize_t		n;
202 
203 	if (plen > UINT8_MAX
204 	    || (plen == 0 && param != NULL)
205 	    || (plen != 0 && param == NULL)) {
206 		errno = EINVAL;
207 		return -1;
208 	}
209 
210 	hdr.type = HCI_CMD_PKT;
211 	hdr.opcode = htole16(opcode);
212 	hdr.length = (uint8_t)plen;
213 
214 	iov[0].iov_base = &hdr;
215 	iov[0].iov_len = sizeof(hdr);
216 
217 	iov[1].iov_base = param;
218 	iov[1].iov_len = plen;
219 
220 	while ((n = writev(s, iov, __arraycount(iov))) == -1) {
221 		if (errno == EINTR)
222 			continue;
223 
224 		return -1;
225 	}
226 
227 	return n;
228 }
229 
230 ssize_t
bt_devrecv(int s,void * buf,size_t size,time_t to)231 bt_devrecv(int s, void *buf, size_t size, time_t to)
232 {
233 	struct kevent	ev;
234 	struct timespec ts;
235 	uint8_t		*p;
236 	ssize_t		n;
237 	int		kq;
238 
239 	if (buf == NULL || size == 0) {
240 		errno = EINVAL;
241 		return -1;
242 	}
243 
244 	if (to >= 0) {	/* timeout is optional */
245 		kq = kqueue();
246 		if (kq == -1)
247 			return -1;
248 
249 		EV_SET(&ev, s, EVFILT_READ, EV_ADD, 0, 0, 0);
250 
251 		ts.tv_sec = to;
252 		ts.tv_nsec = 0;
253 
254 		while (kevent(kq, &ev, 1, &ev, 1, &ts) == -1) {
255 			if (errno == EINTR)
256 				continue;
257 
258 			close(kq);
259 			return -1;
260 		}
261 
262 		close(kq);
263 
264 		if (ev.data == 0) {
265 			errno = ETIMEDOUT;
266 			return -1;
267 		}
268 	}
269 
270 	while ((n = recv(s, buf, size, 0)) == -1) {
271 		if (errno == EINTR)
272 			continue;
273 
274 		return -1;
275 	}
276 
277 	if (n == 0)
278 		return 0;
279 
280 	p = buf;
281 	switch (p[0]) {	/* validate that they get complete packets */
282 	case HCI_CMD_PKT:
283 		if (sizeof(hci_cmd_hdr_t) > (size_t)n
284 		    || sizeof(hci_cmd_hdr_t) + p[3] != (size_t)n)
285 			break;
286 
287 		return n;
288 
289 	case HCI_ACL_DATA_PKT:
290 		if (sizeof(hci_acldata_hdr_t) > (size_t)n
291 		    || sizeof(hci_acldata_hdr_t) + le16dec(p + 3) != (size_t)n)
292 			break;
293 
294 		return n;
295 
296 	case HCI_SCO_DATA_PKT:
297 		if (sizeof(hci_scodata_hdr_t) > (size_t)n
298 		    || sizeof(hci_scodata_hdr_t) + p[3] != (size_t)n)
299 			break;
300 
301 		return n;
302 
303 	case HCI_EVENT_PKT:
304 		if (sizeof(hci_event_hdr_t) > (size_t)n
305 		    || sizeof(hci_event_hdr_t) + p[2] != (size_t)n)
306 			break;
307 
308 		return n;
309 
310 	default:
311 		break;
312 	}
313 
314 	errno = EIO;
315 	return -1;
316 }
317 
318 /*
319  * Internal handler for bt_devreq(), do the actual request.
320  */
321 static int
bt__devreq(int s,struct bt_devreq * req,time_t t_end)322 bt__devreq(int s, struct bt_devreq *req, time_t t_end)
323 {
324 	uint8_t			buf[HCI_EVENT_PKT_SIZE], *p;
325 	hci_event_hdr_t		ev;
326 	hci_command_status_ep	cs;
327 	hci_command_compl_ep	cc;
328 	time_t			to;
329 	ssize_t			n;
330 
331 	n = bt_devsend(s, req->opcode, req->cparam, req->clen);
332 	if (n == -1)
333 		return errno;
334 
335 	for (;;) {
336 		to = t_end - time(NULL);
337 		if (to < 0)
338 			return ETIMEDOUT;
339 
340 		p = buf;
341 		n = bt_devrecv(s, buf, sizeof(buf), to);
342 		if (n == -1)
343 			return errno;
344 
345 		if (sizeof(ev) > (size_t)n || p[0] != HCI_EVENT_PKT)
346 			return EIO;
347 
348 		memcpy(&ev, p, sizeof(ev));
349 		p += sizeof(ev);
350 		n -= sizeof(ev);
351 
352 		if (ev.event == req->event)
353 			break;
354 
355 		if (ev.event == HCI_EVENT_COMMAND_STATUS) {
356 			if (sizeof(cs) > (size_t)n)
357 				return EIO;
358 
359 			memcpy(&cs, p, sizeof(cs));
360 			p += sizeof(cs);
361 			n -= sizeof(cs);
362 
363 			if (le16toh(cs.opcode) == req->opcode) {
364 				if (cs.status != 0)
365 					return EIO;
366 
367 				if (req->event == 0)
368 					break;
369 			}
370 
371 			continue;
372 		}
373 
374 		if (ev.event == HCI_EVENT_COMMAND_COMPL) {
375 			if (sizeof(cc) > (size_t)n)
376 				return EIO;
377 
378 			memcpy(&cc, p, sizeof(cc));
379 			p += sizeof(cc);
380 			n -= sizeof(cc);
381 
382 			if (le16toh(cc.opcode) == req->opcode)
383 				break;
384 
385 			continue;
386 		}
387 	}
388 
389 	/* copy out response data */
390 	if (req->rlen >= (size_t)n) {
391 		req->rlen = n;
392 		memcpy(req->rparam, p, req->rlen);
393 	} else if (req->rlen > 0)
394 		return EIO;
395 
396 	return 0;
397 }
398 
399 int
bt_devreq(int s,struct bt_devreq * req,time_t to)400 bt_devreq(int s, struct bt_devreq *req, time_t to)
401 {
402 	struct bt_devfilter	new, old;
403 	int			error;
404 
405 	if (req == NULL || to < 0
406 	    || (req->rlen == 0 && req->rparam != NULL)
407 	    || (req->rlen != 0 && req->rparam == NULL)) {
408 		errno = EINVAL;
409 		return -1;
410 	}
411 
412 	memset(&new, 0, sizeof(new));
413 	bt_devfilter_pkt_set(&new, HCI_EVENT_PKT);
414 	bt_devfilter_evt_set(&new, HCI_EVENT_COMMAND_COMPL);
415 	bt_devfilter_evt_set(&new, HCI_EVENT_COMMAND_STATUS);
416 
417 	if (req->event != 0)
418 		bt_devfilter_evt_set(&new, req->event);
419 
420 	if (bt_devfilter(s, &new, &old) == -1)
421 		return -1;
422 
423 	error = bt__devreq(s, req, to + time(NULL));
424 
425 	(void)bt_devfilter(s, &old, NULL);
426 
427 	if (error != 0) {
428 		errno = error;
429 		return -1;
430 	}
431 
432 	return 0;
433 }
434 
435 int
bt_devfilter(int s,const struct bt_devfilter * new,struct bt_devfilter * old)436 bt_devfilter(int s, const struct bt_devfilter *new, struct bt_devfilter *old)
437 {
438 	socklen_t	len;
439 
440 	if (new == NULL && old == NULL) {
441 		errno = EINVAL;
442 		return -1;
443 	}
444 
445 	len = sizeof(struct hci_filter);
446 
447 	if (old != NULL) {
448 		if (getsockopt(s, BTPROTO_HCI,
449 		    SO_HCI_PKT_FILTER, &old->packet_mask, &len) == -1
450 		    || len != sizeof(struct hci_filter))
451 			return -1;
452 
453 		if (getsockopt(s, BTPROTO_HCI,
454 		    SO_HCI_EVT_FILTER, &old->event_mask, &len) == -1
455 		    || len != sizeof(struct hci_filter))
456 			return -1;
457 	}
458 
459 	if (new != NULL) {
460 		if (setsockopt(s, BTPROTO_HCI,
461 		    SO_HCI_PKT_FILTER, &new->packet_mask, len) == -1)
462 			return -1;
463 
464 		if (setsockopt(s, BTPROTO_HCI,
465 		    SO_HCI_EVT_FILTER, &new->event_mask, len) == -1)
466 			return -1;
467 	}
468 
469 	return 0;
470 }
471 
472 void
bt_devfilter_pkt_set(struct bt_devfilter * filter,uint8_t type)473 bt_devfilter_pkt_set(struct bt_devfilter *filter, uint8_t type)
474 {
475 
476 	hci_filter_set(type, &filter->packet_mask);
477 }
478 
479 void
bt_devfilter_pkt_clr(struct bt_devfilter * filter,uint8_t type)480 bt_devfilter_pkt_clr(struct bt_devfilter *filter, uint8_t type)
481 {
482 
483 	hci_filter_clr(type, &filter->packet_mask);
484 }
485 
486 int
bt_devfilter_pkt_tst(const struct bt_devfilter * filter,uint8_t type)487 bt_devfilter_pkt_tst(const struct bt_devfilter *filter, uint8_t type)
488 {
489 
490 	return hci_filter_test(type, &filter->packet_mask);
491 }
492 
493 void
bt_devfilter_evt_set(struct bt_devfilter * filter,uint8_t event)494 bt_devfilter_evt_set(struct bt_devfilter *filter, uint8_t event)
495 {
496 
497 	hci_filter_set(event, &filter->event_mask);
498 }
499 
500 void
bt_devfilter_evt_clr(struct bt_devfilter * filter,uint8_t event)501 bt_devfilter_evt_clr(struct bt_devfilter *filter, uint8_t event)
502 {
503 
504 	hci_filter_clr(event, &filter->event_mask);
505 }
506 
507 int
bt_devfilter_evt_tst(const struct bt_devfilter * filter,uint8_t event)508 bt_devfilter_evt_tst(const struct bt_devfilter *filter, uint8_t event)
509 {
510 
511 	return hci_filter_test(event, &filter->event_mask);
512 }
513 
514 /*
515  * Internal function used by bt_devinquiry to find the first
516  * active device.
517  */
518 /* ARGSUSED */
519 static int
bt__devany_cb(int s,const struct bt_devinfo * info,void * arg)520 bt__devany_cb(int s, const struct bt_devinfo *info, void *arg)
521 {
522 
523 	if ((info->enabled)) {
524 		strlcpy(arg, info->devname, HCI_DEVNAME_SIZE + 1);
525 		return 1;
526 	}
527 
528 	return 0;
529 }
530 
531 /*
532  * Internal function used by bt_devinquiry to insert inquiry
533  * results to an array. Make sure that a bdaddr only appears
534  * once in the list and always use the latest result.
535  */
536 static void
bt__devresult(struct bt_devinquiry * ii,int * count,int max_count,bdaddr_t * ba,uint8_t psrm,uint8_t pspm,uint8_t * cl,uint16_t co,int8_t rssi,uint8_t * data)537 bt__devresult(struct bt_devinquiry *ii, int *count, int max_count,
538     bdaddr_t *ba, uint8_t psrm, uint8_t pspm, uint8_t *cl, uint16_t co,
539     int8_t rssi, uint8_t *data)
540 {
541 	int	n;
542 
543 	for (n = 0; ; n++, ii++) {
544 		if (n == *count) {
545 			if (*count == max_count)
546 				return;
547 
548 			(*count)++;
549 			break;
550 		}
551 
552 		if (bdaddr_same(&ii->bdaddr, ba))
553 			break;
554 	}
555 
556 	bdaddr_copy(&ii->bdaddr, ba);
557 	ii->pscan_rep_mode = psrm;
558 	ii->pscan_period_mode = pspm;
559 	ii->clock_offset = le16toh(co);
560 	ii->rssi = rssi;
561 
562 	if (cl != NULL)
563 		memcpy(ii->dev_class, cl, HCI_CLASS_SIZE);
564 
565 	if (data != NULL)
566 		memcpy(ii->data, data, 240);
567 }
568 
569 int
bt_devinquiry(const char * name,time_t to,int max_rsp,struct bt_devinquiry ** iip)570 bt_devinquiry(const char *name, time_t to, int max_rsp,
571     struct bt_devinquiry **iip)
572 {
573 	uint8_t			buf[HCI_EVENT_PKT_SIZE], *p;
574 	struct bt_devfilter	f;
575 	hci_event_hdr_t		ev;
576 	hci_command_status_ep	sp;
577 	hci_inquiry_cp		cp;
578 	hci_inquiry_result_ep	ip;
579 	hci_inquiry_response	ir;
580 	hci_rssi_result_ep	rp;
581 	hci_rssi_response	rr;
582 	hci_extended_result_ep	ep;
583 	struct bt_devinquiry	*ii;
584 	int			count, i, s;
585 	time_t			t_end;
586 	ssize_t			n;
587 
588 	if (iip == NULL) {
589 		errno = EINVAL;
590 		return -1;
591 	}
592 
593 	if (name == NULL) {
594 		if (bt_devenum(bt__devany_cb, buf) == -1)
595 			return -1;
596 
597 		name = (const char *)buf;
598 	}
599 
600 	s = bt_devopen(name, 0);
601 	if (s == -1)
602 		return -1;
603 
604 	memset(&f, 0, sizeof(f));
605 	bt_devfilter_pkt_set(&f, HCI_EVENT_PKT);
606 	bt_devfilter_evt_set(&f, HCI_EVENT_COMMAND_STATUS);
607 	bt_devfilter_evt_set(&f, HCI_EVENT_INQUIRY_COMPL);
608 	bt_devfilter_evt_set(&f, HCI_EVENT_INQUIRY_RESULT);
609 	bt_devfilter_evt_set(&f, HCI_EVENT_RSSI_RESULT);
610 	bt_devfilter_evt_set(&f, HCI_EVENT_EXTENDED_RESULT);
611 	if (bt_devfilter(s, &f, NULL) == -1) {
612 		close(s);
613 		return -1;
614 	}
615 
616 	/*
617 	 * silently adjust number of responses to fit in uint8_t
618 	 */
619 	if (max_rsp < 1)
620 		max_rsp = 8;
621 	else if (max_rsp > UINT8_MAX)
622 		max_rsp = UINT8_MAX;
623 
624 	ii = calloc((size_t)max_rsp, sizeof(struct bt_devinquiry));
625 	if (ii == NULL) {
626 		close(s);
627 		return -1;
628 	}
629 
630 	/*
631 	 * silently adjust timeout value so that inquiry_length
632 	 * falls into the range 0x01->0x30 (unit is 1.28 seconds)
633 	 */
634 	if (to < 1)
635 		to = 5;
636 	else if (to == 1)
637 		to = 2;
638 	else if (to > 62)
639 		to = 62;
640 
641 	/* General Inquiry LAP is 0x9e8b33 */
642 	cp.lap[0] = 0x33;
643 	cp.lap[1] = 0x8b;
644 	cp.lap[2] = 0x9e;
645 	cp.inquiry_length = (uint8_t)(to * 100 / 128);
646 	cp.num_responses = (uint8_t)max_rsp;
647 
648 	if (bt_devsend(s, HCI_CMD_INQUIRY, &cp, sizeof(cp)) == -1)
649 		goto fail;
650 
651 	count = 0;
652 
653 	for (t_end = time(NULL) + to + 1; to > 0; to = t_end - time(NULL)) {
654 		p = buf;
655 		n = bt_devrecv(s, buf, sizeof(buf), to);
656 		if (n == -1)
657 			goto fail;
658 
659 		if (sizeof(ev) > (size_t)n) {
660 			errno = EIO;
661 			goto fail;
662 		}
663 
664 		memcpy(&ev, p, sizeof(ev));
665 		p += sizeof(ev);
666 		n -= sizeof(ev);
667 
668 		switch (ev.event) {
669 		case HCI_EVENT_COMMAND_STATUS:
670 			if (sizeof(sp) > (size_t)n)
671 				break;
672 
673 			memcpy(&sp, p, sizeof(sp));
674 
675 			if (le16toh(sp.opcode) != HCI_CMD_INQUIRY
676 			    || sp.status == 0)
677 				break;
678 
679 			errno = EIO;
680 			goto fail;
681 
682 		case HCI_EVENT_INQUIRY_COMPL:
683 			close(s);
684 			*iip = ii;
685 			return count;
686 
687 		case HCI_EVENT_INQUIRY_RESULT:
688 			if (sizeof(ip) > (size_t)n)
689 				break;
690 
691 			memcpy(&ip, p, sizeof(ip));
692 			p += sizeof(ip);
693 			n -= sizeof(ip);
694 
695 			if (sizeof(ir) * ip.num_responses != (size_t)n)
696 				break;
697 
698 			for (i = 0; i < ip.num_responses; i++) {
699 				memcpy(&ir, p, sizeof(ir));
700 				p += sizeof(ir);
701 
702 				bt__devresult(ii, &count, max_rsp,
703 					&ir.bdaddr,
704 					ir.page_scan_rep_mode,
705 					ir.page_scan_period_mode,
706 					ir.uclass,
707 					ir.clock_offset,
708 					0,		/* rssi */
709 					NULL);		/* extended data */
710 			}
711 
712 			break;
713 
714 		case HCI_EVENT_RSSI_RESULT:
715 			if (sizeof(rp) > (size_t)n)
716 				break;
717 
718 			memcpy(&rp, p, sizeof(rp));
719 			p += sizeof(rp);
720 			n -= sizeof(rp);
721 
722 			if (sizeof(rr) * rp.num_responses != (size_t)n)
723 				break;
724 
725 			for (i = 0; i < rp.num_responses; i++) {
726 				memcpy(&rr, p, sizeof(rr));
727 				p += sizeof(rr);
728 
729 				bt__devresult(ii, &count, max_rsp,
730 					&rr.bdaddr,
731 					rr.page_scan_rep_mode,
732 					0,	/* page scan period mode */
733 					rr.uclass,
734 					rr.clock_offset,
735 					rr.rssi,
736 					NULL);		/* extended data */
737 			}
738 
739 			break;
740 
741 		case HCI_EVENT_EXTENDED_RESULT:
742 			if (sizeof(ep) != (size_t)n)
743 				break;
744 
745 			memcpy(&ep, p, sizeof(ep));
746 
747 			if (ep.num_responses != 1)
748 				break;
749 
750 			bt__devresult(ii, &count, max_rsp,
751 				&ep.bdaddr,
752 				ep.page_scan_rep_mode,
753 				0,	/* page scan period mode */
754 				ep.uclass,
755 				ep.clock_offset,
756 				ep.rssi,
757 				ep.response);
758 
759 			break;
760 
761 		default:
762 			break;
763 		}
764 	}
765 
766 	errno = ETIMEDOUT;
767 
768 fail:
769 	free(ii);
770 	close(s);
771 	return -1;
772 }
773 
774 /*
775  * Internal version of bt_devinfo. Fill in the devinfo structure
776  * with the socket handle provided.
777  */
778 static int
bt__devinfo(int s,const char * name,struct bt_devinfo * info)779 bt__devinfo(int s, const char *name, struct bt_devinfo *info)
780 {
781 	struct btreq			btr;
782 
783 	memset(&btr, 0, sizeof(btr));
784 	strlcpy(btr.btr_name, name, HCI_DEVNAME_SIZE);
785 
786 	if (ioctl(s, SIOCGBTINFO, &btr) == -1)
787 		return -1;
788 
789 	memset(info, 0, sizeof(struct bt_devinfo));
790 	memcpy(info->devname, btr.btr_name, HCI_DEVNAME_SIZE);
791 	bdaddr_copy(&info->bdaddr, &btr.btr_bdaddr);
792 	info->enabled = ((btr.btr_flags & BTF_UP) ? 1 : 0);
793 
794 	info->sco_size = btr.btr_sco_mtu;
795 	info->acl_size = btr.btr_acl_mtu;
796 	info->cmd_free = btr.btr_num_cmd;
797 	info->sco_free = btr.btr_num_sco;
798 	info->acl_free = btr.btr_num_acl;
799 	info->sco_pkts = btr.btr_max_sco;
800 	info->acl_pkts = btr.btr_max_acl;
801 
802 	info->link_policy_info = btr.btr_link_policy;
803 	info->packet_type_info = btr.btr_packet_type;
804 
805 	if (ioctl(s, SIOCGBTFEAT, &btr) == -1)
806 		return -1;
807 
808 	memcpy(info->features, btr.btr_features0, HCI_FEATURES_SIZE);
809 
810 	if (ioctl(s, SIOCGBTSTATS, &btr) == -1)
811 		return -1;
812 
813 	info->cmd_sent = btr.btr_stats.cmd_tx;
814 	info->evnt_recv = btr.btr_stats.evt_rx;
815 	info->acl_recv = btr.btr_stats.acl_rx;
816 	info->acl_sent = btr.btr_stats.acl_tx;
817 	info->sco_recv = btr.btr_stats.sco_rx;
818 	info->sco_sent = btr.btr_stats.sco_tx;
819 	info->bytes_recv = btr.btr_stats.byte_rx;
820 	info->bytes_sent = btr.btr_stats.byte_tx;
821 
822 	return 0;
823 }
824 
825 int
bt_devinfo(const char * name,struct bt_devinfo * info)826 bt_devinfo(const char *name, struct bt_devinfo *info)
827 {
828 	int	rv, s;
829 
830 	if (name == NULL || info == NULL) {
831 		errno = EINVAL;
832 		return -1;
833 	}
834 
835 	s = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
836 	if (s == -1)
837 		return -1;
838 
839 	rv = bt__devinfo(s, name, info);
840 	close(s);
841 	return rv;
842 }
843 
844 int
bt_devenum(bt_devenum_cb_t cb,void * arg)845 bt_devenum(bt_devenum_cb_t cb, void *arg)
846 {
847 	struct btreq		btr;
848 	struct bt_devinfo	info;
849 	struct sockaddr_bt	sa;
850 	int			count, fd, rv, s;
851 
852 	s = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
853 	if (s == -1)
854 		return -1;
855 
856 	memset(&btr, 0, sizeof(btr));
857 	count = 0;
858 
859 	while (ioctl(s, SIOCNBTINFO, &btr) != -1) {
860 		count++;
861 
862 		if (cb == NULL)
863 			continue;
864 
865 		fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
866 		if (fd == -1) {
867 			close(s);
868 			return -1;
869 		}
870 
871 		if (bt__devinfo(fd, btr.btr_name, &info) == -1) {
872 			close(fd);
873 			close(s);
874 			return -1;
875 		}
876 
877 		if (info.enabled) {
878 			memset(&sa, 0, sizeof(sa));
879 			sa.bt_len = sizeof(sa);
880 			sa.bt_family = AF_BLUETOOTH;
881 			bdaddr_copy(&sa.bt_bdaddr, &info.bdaddr);
882 
883 			if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1
884 			    || connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
885 				close(fd);
886 				close(s);
887 				return -1;
888 			}
889 		}
890 
891 		rv = (*cb)(fd, &info, arg);
892 		close(fd);
893 		if (rv != 0)
894 			break;
895 	}
896 
897 	close(s);
898 	return count;
899 }
900