Home | History | Annotate | Line # | Download | only in libbluetooth
      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 (at) 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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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