1/*
2 * hci.c
3 */
4
5/*-
6 * SPDX-License-Identifier: BSD-2-Clause
7 *
8 * Copyright (c) 2009 Maksim Yevmenkin <m_evmenkin@yahoo.com>
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <sys/types.h>
34#include <sys/sysctl.h>
35
36#include <assert.h>
37#define L2CAP_SOCKET_CHECKED
38#include <bluetooth.h>
39#include <inttypes.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43#include <time.h>
44#include <unistd.h>
45
46#undef	MIN
47#define	MIN(a, b)	(((a) < (b))? (a) : (b))
48
49static int    bt_devany_cb(int s, struct bt_devinfo const *di, void *xdevname);
50static char * bt_dev2node (char const *devname, char *nodename, int nnlen);
51static time_t bt_get_default_hci_command_timeout(void);
52
53int
54bt_devopen(char const *devname)
55{
56	struct sockaddr_hci	ha;
57	bdaddr_t		ba;
58	int			s;
59
60	if (devname == NULL) {
61		errno = EINVAL;
62		return (-1);
63	}
64
65	memset(&ha, 0, sizeof(ha));
66	ha.hci_len = sizeof(ha);
67	ha.hci_family = AF_BLUETOOTH;
68
69	if (bt_aton(devname, &ba)) {
70		if (!bt_devname(ha.hci_node, &ba))
71			return (-1);
72	} else if (bt_dev2node(devname, ha.hci_node,
73					sizeof(ha.hci_node)) == NULL) {
74		errno = ENXIO;
75		return (-1);
76	}
77
78	s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI);
79	if (s < 0)
80		return (-1);
81
82	if (bind(s, (struct sockaddr *) &ha, sizeof(ha)) < 0 ||
83	    connect(s, (struct sockaddr *) &ha, sizeof(ha)) < 0) {
84		close(s);
85		return (-1);
86	}
87
88	return (s);
89}
90
91int
92bt_devclose(int s)
93{
94	return (close(s));
95}
96
97int
98bt_devsend(int s, uint16_t opcode, void *param, size_t plen)
99{
100	ng_hci_cmd_pkt_t	h;
101	struct iovec		iv[2];
102	int			ivn;
103
104	if ((plen == 0 && param != NULL) ||
105	    (plen > 0 && param == NULL) ||
106	    plen > UINT8_MAX) {
107		errno = EINVAL;
108		return (-1);
109	}
110
111	iv[0].iov_base = &h;
112	iv[0].iov_len = sizeof(h);
113	ivn = 1;
114
115	h.type = NG_HCI_CMD_PKT;
116	h.opcode = htole16(opcode);
117	if (plen > 0) {
118		h.length = plen;
119
120		iv[1].iov_base = param;
121		iv[1].iov_len = plen;
122		ivn = 2;
123	} else
124		h.length = 0;
125
126	while (writev(s, iv, ivn) < 0) {
127		if (errno == EAGAIN || errno == EINTR)
128			continue;
129
130		return (-1);
131	}
132
133	return (0);
134}
135
136ssize_t
137bt_devrecv(int s, void *buf, size_t size, time_t to)
138{
139	ssize_t	n;
140
141	if (buf == NULL || size == 0) {
142		errno = EINVAL;
143		return (-1);
144	}
145
146	if (to >= 0) {
147		fd_set		rfd;
148		struct timeval	tv;
149
150		FD_ZERO(&rfd);
151		FD_SET(s, &rfd);
152
153		tv.tv_sec = to;
154		tv.tv_usec = 0;
155
156		while ((n = select(s + 1, &rfd, NULL, NULL, &tv)) < 0) {
157			if (errno == EAGAIN || errno == EINTR)
158				continue;
159
160			return (-1);
161		}
162
163		if (n == 0) {
164			errno = ETIMEDOUT;
165			return (-1);
166		}
167
168		assert(FD_ISSET(s, &rfd));
169	}
170
171	while ((n = read(s, buf, size)) < 0) {
172		if (errno == EAGAIN || errno == EINTR)
173			continue;
174
175		return (-1);
176	}
177
178	switch (*((uint8_t *) buf)) {
179	case NG_HCI_CMD_PKT: {
180		ng_hci_cmd_pkt_t	*h = (ng_hci_cmd_pkt_t *) buf;
181
182		if (n >= sizeof(*h) && n == (sizeof(*h) + h->length))
183			return (n);
184		} break;
185
186	case NG_HCI_ACL_DATA_PKT: {
187		ng_hci_acldata_pkt_t	*h = (ng_hci_acldata_pkt_t *) buf;
188
189		if (n >= sizeof(*h) && n == (sizeof(*h) + le16toh(h->length)))
190			return (n);
191		} break;
192
193	case NG_HCI_SCO_DATA_PKT: {
194		ng_hci_scodata_pkt_t	*h = (ng_hci_scodata_pkt_t *) buf;
195
196		if (n >= sizeof(*h) && n == (sizeof(*h) + h->length))
197			return (n);
198		} break;
199
200	case NG_HCI_EVENT_PKT: {
201		ng_hci_event_pkt_t	*h = (ng_hci_event_pkt_t *) buf;
202
203		if (n >= sizeof(*h) && n == (sizeof(*h) + h->length))
204			return (n);
205		} break;
206	}
207
208	errno = EIO;
209	return (-1);
210}
211
212int
213bt_devreq(int s, struct bt_devreq *r, time_t to)
214{
215	uint8_t				buf[320]; /* more than enough */
216	ng_hci_event_pkt_t		*e = (ng_hci_event_pkt_t *) buf;
217	ng_hci_command_compl_ep		*cc = (ng_hci_command_compl_ep *)(e+1);
218	ng_hci_command_status_ep	*cs = (ng_hci_command_status_ep*)(e+1);
219	struct bt_devfilter		old, new;
220	time_t				t_end;
221	uint16_t			opcode;
222	ssize_t				n;
223	int				error;
224
225	if (s < 0 || r == NULL || to < 0) {
226		errno = EINVAL;
227		return (-1);
228	}
229
230	if ((r->rlen == 0 && r->rparam != NULL) ||
231	    (r->rlen > 0 && r->rparam == NULL)) {
232		errno = EINVAL;
233		return (-1);
234	}
235
236	memset(&new, 0, sizeof(new));
237	bt_devfilter_pkt_set(&new, NG_HCI_EVENT_PKT);
238	bt_devfilter_evt_set(&new, NG_HCI_EVENT_COMMAND_COMPL);
239	bt_devfilter_evt_set(&new, NG_HCI_EVENT_COMMAND_STATUS);
240	if (r->event != 0)
241		bt_devfilter_evt_set(&new, r->event);
242
243	if (bt_devfilter(s, &new, &old) < 0)
244		return (-1);
245
246	error = 0;
247
248	n = bt_devsend(s, r->opcode, r->cparam, r->clen);
249	if (n < 0) {
250		error = errno;
251		goto out;
252	}
253
254	opcode = htole16(r->opcode);
255	t_end = time(NULL) + to;
256
257	do {
258		to = t_end - time(NULL);
259		if (to < 0)
260			to = 0;
261
262		n = bt_devrecv(s, buf, sizeof(buf), to);
263		if (n < 0) {
264			error = errno;
265			goto out;
266		}
267
268		if (e->type != NG_HCI_EVENT_PKT) {
269			error = EIO;
270			goto out;
271		}
272
273		n -= sizeof(*e);
274
275		switch (e->event) {
276		case NG_HCI_EVENT_COMMAND_COMPL:
277			if (cc->opcode == opcode) {
278				n -= sizeof(*cc);
279
280				if (r->rlen >= n) {
281					r->rlen = n;
282					memcpy(r->rparam, cc + 1, r->rlen);
283				}
284
285				goto out;
286			}
287			break;
288
289		case NG_HCI_EVENT_COMMAND_STATUS:
290			if (cs->opcode == opcode) {
291				if (r->event != NG_HCI_EVENT_COMMAND_STATUS) {
292					if (cs->status != 0) {
293						error = EIO;
294						goto out;
295					}
296				} else {
297					if (r->rlen >= n) {
298						r->rlen = n;
299						memcpy(r->rparam, cs, r->rlen);
300					}
301
302					goto out;
303				}
304			}
305			break;
306
307		default:
308			if (e->event == r->event) {
309				if (r->rlen >= n) {
310					r->rlen = n;
311					memcpy(r->rparam, e + 1, r->rlen);
312				}
313
314				goto out;
315			}
316			break;
317		}
318	} while (to > 0);
319
320	error = ETIMEDOUT;
321out:
322	bt_devfilter(s, &old, NULL);
323
324	if (error != 0) {
325		errno = error;
326		return (-1);
327	}
328
329	return (0);
330}
331
332int
333bt_devfilter(int s, struct bt_devfilter const *new, struct bt_devfilter *old)
334{
335	struct ng_btsocket_hci_raw_filter	f;
336	socklen_t				len;
337
338	if (new == NULL && old == NULL) {
339		errno = EINVAL;
340		return (-1);
341	}
342
343	if (old != NULL) {
344		len = sizeof(f);
345		if (getsockopt(s, SOL_HCI_RAW, SO_HCI_RAW_FILTER, &f, &len) < 0)
346			return (-1);
347
348		memset(old, 0, sizeof(*old));
349		memcpy(old->packet_mask, &f.packet_mask,
350			MIN(sizeof(old->packet_mask), sizeof(f.packet_mask)));
351		memcpy(old->event_mask, &f.event_mask,
352			MIN(sizeof(old->event_mask), sizeof(f.packet_mask)));
353	}
354
355	if (new != NULL) {
356		memset(&f, 0, sizeof(f));
357		memcpy(&f.packet_mask, new->packet_mask,
358			MIN(sizeof(f.packet_mask), sizeof(new->event_mask)));
359		memcpy(&f.event_mask, new->event_mask,
360			MIN(sizeof(f.event_mask), sizeof(new->event_mask)));
361
362		len = sizeof(f);
363		if (setsockopt(s, SOL_HCI_RAW, SO_HCI_RAW_FILTER, &f, len) < 0)
364			return (-1);
365	}
366
367	return (0);
368}
369
370void
371bt_devfilter_pkt_set(struct bt_devfilter *filter, uint8_t type)
372{
373	bit_set(filter->packet_mask, type - 1);
374}
375
376void
377bt_devfilter_pkt_clr(struct bt_devfilter *filter, uint8_t type)
378{
379	bit_clear(filter->packet_mask, type - 1);
380}
381
382int
383bt_devfilter_pkt_tst(struct bt_devfilter const *filter, uint8_t type)
384{
385	return (bit_test(filter->packet_mask, type - 1));
386}
387
388void
389bt_devfilter_evt_set(struct bt_devfilter *filter, uint8_t event)
390{
391	bit_set(filter->event_mask, event - 1);
392}
393
394void
395bt_devfilter_evt_clr(struct bt_devfilter *filter, uint8_t event)
396{
397	bit_clear(filter->event_mask, event - 1);
398}
399
400int
401bt_devfilter_evt_tst(struct bt_devfilter const *filter, uint8_t event)
402{
403	return (bit_test(filter->event_mask, event - 1));
404}
405
406int
407bt_devinquiry(char const *devname, time_t length, int num_rsp,
408		struct bt_devinquiry **ii)
409{
410	uint8_t				buf[320];
411	char				_devname[HCI_DEVNAME_SIZE];
412	struct bt_devfilter		f;
413	ng_hci_inquiry_cp		*cp = (ng_hci_inquiry_cp *) buf;
414	ng_hci_event_pkt_t		*e = (ng_hci_event_pkt_t *) buf;
415	ng_hci_inquiry_result_ep	*ep = (ng_hci_inquiry_result_ep *)(e+1);
416	ng_hci_inquiry_response		*ir;
417	struct bt_devinquiry		*i;
418	int				s, n;
419
420	if (ii == NULL) {
421		errno = EINVAL;
422		return (-1);
423	}
424
425	if (devname == NULL) {
426		memset(_devname, 0, sizeof(_devname));
427		devname = _devname;
428
429		n = bt_devenum(bt_devany_cb, _devname);
430		if (n <= 0) {
431			if (n == 0)
432				*ii = NULL;
433
434			return (n);
435		}
436	}
437
438	s = bt_devopen(devname);
439	if (s < 0)
440		return (-1);
441
442	if (bt_devfilter(s, NULL, &f) < 0) {
443		bt_devclose(s);
444		return (-1);
445	}
446
447	bt_devfilter_evt_set(&f, NG_HCI_EVENT_INQUIRY_COMPL);
448	bt_devfilter_evt_set(&f, NG_HCI_EVENT_INQUIRY_RESULT);
449
450	if (bt_devfilter(s, &f, NULL) < 0) {
451		bt_devclose(s);
452		return (-1);
453	}
454
455	/* Always use GIAC LAP */
456	cp->lap[0] = 0x33;
457	cp->lap[1] = 0x8b;
458	cp->lap[2] = 0x9e;
459
460	/*
461	 * Calculate inquire length in 1.28 second units
462	 * v2.x specification says that 1.28 -> 61.44 seconds
463	 * range is acceptable
464	 */
465
466	if (length <= 0)
467		length = 5;
468	else if (length == 1)
469		length = 2;
470	else if (length > 62)
471		length = 62;
472
473	cp->inquiry_length = (uint8_t)((length * 100) / 128);
474
475	if (num_rsp <= 0 || num_rsp > 255)
476		num_rsp = 8;
477	cp->num_responses = (uint8_t) num_rsp;
478
479	i = *ii = calloc(num_rsp, sizeof(struct bt_devinquiry));
480	if (i == NULL) {
481		bt_devclose(s);
482		errno = ENOMEM;
483		return (-1);
484	}
485
486	if (bt_devsend(s,
487		NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, NG_HCI_OCF_INQUIRY),
488			cp, sizeof(*cp)) < 0) {
489		free(i);
490		bt_devclose(s);
491		return (-1);
492	}
493
494wait_for_more:
495
496	n = bt_devrecv(s, buf, sizeof(buf), length);
497	if (n < 0) {
498		free(i);
499		bt_devclose(s);
500		return (-1);
501	}
502
503	if (n < sizeof(ng_hci_event_pkt_t)) {
504		free(i);
505		bt_devclose(s);
506		errno = EIO;
507		return (-1);
508	}
509
510	switch (e->event) {
511	case NG_HCI_EVENT_INQUIRY_COMPL:
512		break;
513
514	case NG_HCI_EVENT_INQUIRY_RESULT:
515		ir = (ng_hci_inquiry_response *)(ep + 1);
516
517		for (n = 0; n < MIN(ep->num_responses, num_rsp); n ++) {
518			bdaddr_copy(&i->bdaddr, &ir->bdaddr);
519			i->pscan_rep_mode = ir->page_scan_rep_mode;
520			i->pscan_period_mode = ir->page_scan_period_mode;
521			memcpy(i->dev_class, ir->uclass, sizeof(i->dev_class));
522			i->clock_offset = le16toh(ir->clock_offset);
523
524			ir ++;
525			i ++;
526			num_rsp --;
527		}
528		/* FALLTHROUGH */
529
530	default:
531		goto wait_for_more;
532		/* NOT REACHED */
533	}
534
535	bt_devclose(s);
536
537	return (i - *ii);
538}
539
540char *
541bt_devremote_name(char const *devname, const bdaddr_t *remote, time_t to,
542    uint16_t clk_off, uint8_t ps_rep_mode, uint8_t ps_mode)
543{
544	char				 _devname[HCI_DEVNAME_SIZE];
545	struct bt_devreq		 r;
546	ng_hci_remote_name_req_cp	 cp;
547	ng_hci_remote_name_req_compl_ep	 ep;
548	int				 s;
549	char				*remote_name = NULL;
550
551	if (remote == NULL || to < 0) {
552		errno = EINVAL;
553		goto out;
554	}
555
556	if (to == 0) {
557		to = bt_get_default_hci_command_timeout();
558		if (to < 0)
559			goto out;
560	}
561	to++;
562
563	if (devname == NULL) {
564		memset(_devname, 0, sizeof(_devname));
565		devname = _devname;
566		if (bt_devenum(bt_devany_cb, _devname) <= 0)
567			goto out;
568        }
569
570	memset(&r, 0, sizeof(r));
571	memset(&cp, 0, sizeof(cp));
572	memset(&ep, 0, sizeof(ep));
573	cp.clock_offset = htole16(clk_off);
574	cp.page_scan_rep_mode = ps_rep_mode;
575	cp.page_scan_mode = ps_mode;
576	bdaddr_copy(&cp.bdaddr, remote);
577	r.opcode = NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
578				 NG_HCI_OCF_REMOTE_NAME_REQ);
579	r.event = NG_HCI_EVENT_REMOTE_NAME_REQ_COMPL;
580	r.cparam = &cp;
581	r.clen = sizeof(cp);
582	r.rparam = &ep;
583	r.rlen = sizeof(ep);
584
585	s = bt_devopen(devname);
586	if (s < 0)
587		goto out;
588
589	if (bt_devreq(s, &r, to) == 0 || ep.status == 0x00)
590		remote_name = strndup((const char *)&ep.name, sizeof(ep.name));
591
592	bt_devclose(s);
593out:
594	return (remote_name);
595}
596
597int
598bt_devinfo(struct bt_devinfo *di)
599{
600	union {
601		struct ng_btsocket_hci_raw_node_state		r0;
602		struct ng_btsocket_hci_raw_node_bdaddr		r1;
603		struct ng_btsocket_hci_raw_node_features	r2;
604		struct ng_btsocket_hci_raw_node_buffer		r3;
605		struct ng_btsocket_hci_raw_node_stat		r4;
606		struct ng_btsocket_hci_raw_node_link_policy_mask r5;
607		struct ng_btsocket_hci_raw_node_packet_mask	r6;
608		struct ng_btsocket_hci_raw_node_role_switch	r7;
609		struct ng_btsocket_hci_raw_node_debug		r8;
610	}						rp;
611	struct sockaddr_hci				ha;
612	socklen_t					halen;
613	int						s, rval;
614
615	if (di == NULL) {
616		errno = EINVAL;
617		return (-1);
618	}
619
620	s = bt_devopen(di->devname);
621	if (s < 0)
622		return (-1);
623
624	rval = -1;
625
626	halen = sizeof(ha);
627	if (getsockname(s, (struct sockaddr *) &ha, &halen) < 0)
628		goto bad;
629	strlcpy(di->devname, ha.hci_node, sizeof(di->devname));
630
631	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_STATE, &rp.r0, sizeof(rp.r0)) < 0)
632		goto bad;
633	di->state = rp.r0.state;
634
635	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_BDADDR, &rp.r1, sizeof(rp.r1)) < 0)
636		goto bad;
637	bdaddr_copy(&di->bdaddr, &rp.r1.bdaddr);
638
639	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_FEATURES, &rp.r2, sizeof(rp.r2)) < 0)
640		goto bad;
641	memcpy(di->features, rp.r2.features, sizeof(di->features));
642
643	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_BUFFER, &rp.r3, sizeof(rp.r3)) < 0)
644		goto bad;
645	di->cmd_free = rp.r3.buffer.cmd_free;
646	di->sco_size = rp.r3.buffer.sco_size;
647	di->sco_pkts = rp.r3.buffer.sco_pkts;
648	di->sco_free = rp.r3.buffer.sco_free;
649	di->acl_size = rp.r3.buffer.acl_size;
650	di->acl_pkts = rp.r3.buffer.acl_pkts;
651	di->acl_free = rp.r3.buffer.acl_free;
652
653	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_STAT, &rp.r4, sizeof(rp.r4)) < 0)
654		goto bad;
655	di->cmd_sent = rp.r4.stat.cmd_sent;
656	di->evnt_recv = rp.r4.stat.evnt_recv;
657	di->acl_recv = rp.r4.stat.acl_recv;
658	di->acl_sent = rp.r4.stat.acl_sent;
659	di->sco_recv = rp.r4.stat.sco_recv;
660	di->sco_sent = rp.r4.stat.sco_sent;
661	di->bytes_recv = rp.r4.stat.bytes_recv;
662	di->bytes_sent = rp.r4.stat.bytes_sent;
663
664	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_LINK_POLICY_MASK,
665			&rp.r5, sizeof(rp.r5)) < 0)
666		goto bad;
667	di->link_policy_info = rp.r5.policy_mask;
668
669	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_PACKET_MASK,
670			&rp.r6, sizeof(rp.r6)) < 0)
671		goto bad;
672	di->packet_type_info = rp.r6.packet_mask;
673
674	 if (ioctl(s, SIOC_HCI_RAW_NODE_GET_ROLE_SWITCH,
675			&rp.r7, sizeof(rp.r7)) < 0)
676		goto bad;
677	di->role_switch_info = rp.r7.role_switch;
678
679	if (ioctl(s, SIOC_HCI_RAW_NODE_GET_DEBUG, &rp.r8, sizeof(rp.r8)) < 0)
680		goto bad;
681	di->debug = rp.r8.debug;
682
683	rval = 0;
684bad:
685	bt_devclose(s);
686
687	return (rval);
688}
689
690int
691bt_devenum(bt_devenum_cb_t cb, void *arg)
692{
693	struct ng_btsocket_hci_raw_node_list_names	rp;
694	struct bt_devinfo				di;
695	struct sockaddr_hci				ha;
696	int						s, i, count;
697
698	rp.num_names = HCI_DEVMAX;
699	rp.names = (struct nodeinfo *) calloc(rp.num_names,
700						sizeof(struct nodeinfo));
701	if (rp.names == NULL) {
702		errno = ENOMEM;
703		return (-1);
704	}
705
706	memset(&ha, 0, sizeof(ha));
707	ha.hci_len = sizeof(ha);
708	ha.hci_family = AF_BLUETOOTH;
709	ha.hci_node[0] = 'x';
710
711	s = socket(PF_BLUETOOTH, SOCK_RAW, BLUETOOTH_PROTO_HCI);
712	if (s < 0) {
713		free(rp.names);
714
715		return (-1);
716	}
717
718	if (bind(s, (struct sockaddr *) &ha, sizeof(ha)) < 0 ||
719	    connect(s, (struct sockaddr *) &ha, sizeof(ha)) < 0 ||
720	    ioctl(s, SIOC_HCI_RAW_NODE_LIST_NAMES, &rp, sizeof(rp)) < 0) {
721		close(s);
722		free(rp.names);
723
724		return (-1);
725	}
726
727	for (count = 0, i = 0; i < rp.num_names; i ++) {
728		strlcpy(di.devname, rp.names[i].name, sizeof(di.devname));
729		if (bt_devinfo(&di) < 0)
730			continue;
731
732		count ++;
733
734		if (cb == NULL)
735			continue;
736
737		strlcpy(ha.hci_node, rp.names[i].name, sizeof(ha.hci_node));
738		if (bind(s, (struct sockaddr *) &ha, sizeof(ha)) < 0 ||
739		    connect(s, (struct sockaddr *) &ha, sizeof(ha)) < 0)
740			continue;
741
742		if ((*cb)(s, &di, arg) > 0)
743			break;
744	}
745
746	close (s);
747	free(rp.names);
748
749	return (count);
750}
751
752static int
753bt_devany_cb(int s, struct bt_devinfo const *di, void *xdevname)
754{
755	strlcpy((char *) xdevname, di->devname, HCI_DEVNAME_SIZE);
756	return (1);
757}
758
759static char *
760bt_dev2node(char const *devname, char *nodename, int nnlen)
761{
762	static char const *	 bt_dev_prefix[] = {
763		"ubt",		/* Bluetooth USB devices */
764		NULL		/* should be last */
765	};
766
767	static char		_nodename[HCI_DEVNAME_SIZE];
768	char const		**p;
769	char			*ep;
770	int			plen, unit;
771
772	if (nodename == NULL) {
773		nodename = _nodename;
774		nnlen = HCI_DEVNAME_SIZE;
775	}
776
777	for (p = bt_dev_prefix; *p != NULL; p ++) {
778		plen = strlen(*p);
779		if (strncmp(devname, *p, plen) != 0)
780			continue;
781
782		unit = strtoul(devname + plen, &ep, 10);
783		if (*ep != '\0' &&
784		    strcmp(ep, "hci") != 0 &&
785		    strcmp(ep, "l2cap") != 0)
786			return (NULL);	/* can't make sense of device name */
787
788		snprintf(nodename, nnlen, "%s%uhci", *p, unit);
789
790		return (nodename);
791	}
792
793	return (NULL);
794}
795
796static time_t
797bt_get_default_hci_command_timeout(void)
798{
799	int	to;
800	size_t	to_size = sizeof(to);
801
802	if (sysctlbyname("net.bluetooth.hci.command_timeout",
803			 &to, &to_size, NULL, 0) < 0)
804		return (-1);
805
806	/* Should not happen */
807	if (to <= 0) {
808		errno = ERANGE;
809		return (-1);
810	}
811
812	return ((time_t)to);
813}
814