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