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
76int
77bt_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
116int
117bt_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
151int
152bt_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
196ssize_t
197bt_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
230ssize_t
231bt_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 */
321static int
322bt__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
399int
400bt_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
435int
436bt_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
472void
473bt_devfilter_pkt_set(struct bt_devfilter *filter, uint8_t type)
474{
475
476	hci_filter_set(type, &filter->packet_mask);
477}
478
479void
480bt_devfilter_pkt_clr(struct bt_devfilter *filter, uint8_t type)
481{
482
483	hci_filter_clr(type, &filter->packet_mask);
484}
485
486int
487bt_devfilter_pkt_tst(const struct bt_devfilter *filter, uint8_t type)
488{
489
490	return hci_filter_test(type, &filter->packet_mask);
491}
492
493void
494bt_devfilter_evt_set(struct bt_devfilter *filter, uint8_t event)
495{
496
497	hci_filter_set(event, &filter->event_mask);
498}
499
500void
501bt_devfilter_evt_clr(struct bt_devfilter *filter, uint8_t event)
502{
503
504	hci_filter_clr(event, &filter->event_mask);
505}
506
507int
508bt_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 */
519static int
520bt__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 */
536static void
537bt__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
569int
570bt_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
768fail:
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 */
778static int
779bt__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
825int
826bt_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
844int
845bt_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