1 /* $NetBSD: bt_dev.c$ */
4 * Copyright (c) 2009 Iain Hibbert
5 * Copyright (c) 2009 Maksim Yevmenkin <m_evmenkin@yahoo.com>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
31 * Copyright (c) 2006 Itronix Inc.
32 * All rights reserved.
34 * Written by Iain Hibbert for Itronix Inc.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
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.
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.
61 #include <sys/cdefs.h>
62 __RCSID("$NetBSD: bt_dev.c$");
64 #include <sys/event.h>
65 #include <sys/ioctl.h>
66 #include <sys/param.h>
70 #include <bluetooth.h>
77 bt_devaddr(const char *name
, bdaddr_t
*addr
)
91 if (bt_aton(name
, addr
))
92 return bt_devname(NULL
, addr
);
94 memset(&btr
, 0, sizeof(btr
));
95 strncpy(btr
.btr_name
, name
, HCI_DEVNAME_SIZE
);
97 s
= socket(PF_BLUETOOTH
, SOCK_RAW
, BTPROTO_HCI
);
101 rv
= ioctl(s
, SIOCGBTINFO
, &btr
);
107 if ((btr
.btr_flags
& BTF_UP
) == 0) {
112 bdaddr_copy(addr
, &btr
.btr_bdaddr
);
117 bt_devname(char *name
, const bdaddr_t
*bdaddr
)
122 if (bdaddr
== NULL
) {
127 memset(&btr
, 0, sizeof(btr
));
128 bdaddr_copy(&btr
.btr_bdaddr
, bdaddr
);
130 s
= socket(PF_BLUETOOTH
, SOCK_RAW
, BTPROTO_HCI
);
134 rv
= ioctl(s
, SIOCGBTINFOA
, &btr
);
140 if ((btr
.btr_flags
& BTF_UP
) == 0) {
146 strlcpy(name
, btr
.btr_name
, HCI_DEVNAME_SIZE
);
152 bt_devopen(const char *name
, int options
)
154 struct sockaddr_bt sa
;
157 memset(&sa
, 0, sizeof(sa
));
158 sa
.bt_len
= sizeof(sa
);
159 sa
.bt_family
= AF_BLUETOOTH
;
161 if (name
!= NULL
&& !bt_devaddr(name
, &sa
.bt_bdaddr
))
164 s
= socket(PF_BLUETOOTH
, SOCK_RAW
, BTPROTO_HCI
);
170 if ((options
& BTOPT_DIRECTION
) && setsockopt(s
, BTPROTO_HCI
,
171 SO_HCI_DIRECTION
, &opt
, sizeof(opt
)) == -1) {
176 if ((options
& BTOPT_TIMESTAMP
) && setsockopt(s
, SOL_SOCKET
,
177 SO_TIMESTAMP
, &opt
, sizeof(opt
)) == -1) {
182 if (bind(s
, (struct sockaddr
*)&sa
, sizeof(sa
)) == -1) {
188 && connect(s
, (struct sockaddr
*)&sa
, sizeof(sa
)) == -1) {
197 bt_devsend(int s
, uint16_t opcode
, void *param
, size_t plen
)
204 || (plen
== 0 && param
!= NULL
)
205 || (plen
!= 0 && param
== NULL
)) {
210 hdr
.type
= HCI_CMD_PKT
;
211 hdr
.opcode
= htole16(opcode
);
212 hdr
.length
= (uint8_t)plen
;
214 iov
[0].iov_base
= &hdr
;
215 iov
[0].iov_len
= sizeof(hdr
);
217 iov
[1].iov_base
= param
;
218 iov
[1].iov_len
= plen
;
220 while ((n
= writev(s
, iov
, __arraycount(iov
))) == -1) {
231 bt_devrecv(int s
, void *buf
, size_t size
, time_t to
)
239 if (buf
== NULL
|| size
== 0) {
244 if (to
>= 0) { /* timeout is optional */
249 EV_SET(&ev
, s
, EVFILT_READ
, EV_ADD
, 0, 0, 0);
254 while (kevent(kq
, &ev
, 1, &ev
, 1, &ts
) == -1) {
270 while ((n
= recv(s
, buf
, size
, 0)) == -1) {
281 switch (p
[0]) { /* validate that they get complete packets */
283 if (sizeof(hci_cmd_hdr_t
) > (size_t)n
284 || sizeof(hci_cmd_hdr_t
) + p
[3] != (size_t)n
)
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
)
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
)
304 if (sizeof(hci_event_hdr_t
) > (size_t)n
305 || sizeof(hci_event_hdr_t
) + p
[2] != (size_t)n
)
319 * Internal handler for bt_devreq(), do the actual request.
322 bt__devreq(int s
, struct bt_devreq
*req
, time_t t_end
)
324 uint8_t buf
[HCI_EVENT_PKT_SIZE
], *p
;
326 hci_command_status_ep cs
;
327 hci_command_compl_ep cc
;
331 n
= bt_devsend(s
, req
->opcode
, req
->cparam
, req
->clen
);
336 to
= t_end
- time(NULL
);
341 n
= bt_devrecv(s
, buf
, sizeof(buf
), to
);
345 if (sizeof(ev
) > (size_t)n
|| p
[0] != HCI_EVENT_PKT
)
348 memcpy(&ev
, p
, sizeof(ev
));
352 if (ev
.event
== req
->event
)
355 if (ev
.event
== HCI_EVENT_COMMAND_STATUS
) {
356 if (sizeof(cs
) > (size_t)n
)
359 memcpy(&cs
, p
, sizeof(cs
));
363 if (le16toh(cs
.opcode
) == req
->opcode
) {
374 if (ev
.event
== HCI_EVENT_COMMAND_COMPL
) {
375 if (sizeof(cc
) > (size_t)n
)
378 memcpy(&cc
, p
, sizeof(cc
));
382 if (le16toh(cc
.opcode
) == req
->opcode
)
389 /* copy out response data */
390 if (req
->rlen
>= (size_t)n
) {
392 memcpy(req
->rparam
, p
, req
->rlen
);
393 } else if (req
->rlen
> 0)
400 bt_devreq(int s
, struct bt_devreq
*req
, time_t to
)
402 struct bt_devfilter
new, old
;
405 if (req
== NULL
|| to
< 0
406 || (req
->rlen
== 0 && req
->rparam
!= NULL
)
407 || (req
->rlen
!= 0 && req
->rparam
== NULL
)) {
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
);
418 bt_devfilter_evt_set(&new, req
->event
);
420 if (bt_devfilter(s
, &new, &old
) == -1)
423 error
= bt__devreq(s
, req
, to
+ time(NULL
));
425 (void)bt_devfilter(s
, &old
, NULL
);
436 bt_devfilter(int s
, const struct bt_devfilter
*new, struct bt_devfilter
*old
)
440 if (new == NULL
&& old
== NULL
) {
445 len
= sizeof(struct hci_filter
);
448 if (getsockopt(s
, BTPROTO_HCI
,
449 SO_HCI_PKT_FILTER
, &old
->packet_mask
, &len
) == -1
450 || len
!= sizeof(struct hci_filter
))
453 if (getsockopt(s
, BTPROTO_HCI
,
454 SO_HCI_EVT_FILTER
, &old
->event_mask
, &len
) == -1
455 || len
!= sizeof(struct hci_filter
))
460 if (setsockopt(s
, BTPROTO_HCI
,
461 SO_HCI_PKT_FILTER
, &new->packet_mask
, len
) == -1)
464 if (setsockopt(s
, BTPROTO_HCI
,
465 SO_HCI_EVT_FILTER
, &new->event_mask
, len
) == -1)
473 bt_devfilter_pkt_set(struct bt_devfilter
*filter
, uint8_t type
)
476 hci_filter_set(type
, &filter
->packet_mask
);
480 bt_devfilter_pkt_clr(struct bt_devfilter
*filter
, uint8_t type
)
483 hci_filter_clr(type
, &filter
->packet_mask
);
487 bt_devfilter_pkt_tst(const struct bt_devfilter
*filter
, uint8_t type
)
490 return hci_filter_test(type
, &filter
->packet_mask
);
494 bt_devfilter_evt_set(struct bt_devfilter
*filter
, uint8_t event
)
497 hci_filter_set(event
, &filter
->event_mask
);
501 bt_devfilter_evt_clr(struct bt_devfilter
*filter
, uint8_t event
)
504 hci_filter_clr(event
, &filter
->event_mask
);
508 bt_devfilter_evt_tst(const struct bt_devfilter
*filter
, uint8_t event
)
511 return hci_filter_test(event
, &filter
->event_mask
);
515 * Internal function used by bt_devinquiry to find the first
519 bt__devany_cb(int s
, const struct bt_devinfo
*info
, void *arg
)
522 if ((info
->enabled
)) {
523 strlcpy(arg
, info
->devname
, HCI_DEVNAME_SIZE
+ 1);
531 * Internal function used by bt_devinquiry to insert inquiry
532 * results to an array. Make sure that a bdaddr only appears
533 * once in the list and always use the latest result.
536 bt__devresult(struct bt_devinquiry
*ii
, int *count
, int max_count
,
537 bdaddr_t
*ba
, uint8_t psrm
, uint8_t pspm
, uint8_t *cl
, uint16_t co
,
538 int8_t rssi
, uint8_t *data
)
542 for (n
= 0; ; n
++, ii
++) {
544 if (*count
== max_count
)
551 if (bdaddr_same(&ii
->bdaddr
, ba
))
555 bdaddr_copy(&ii
->bdaddr
, ba
);
556 ii
->pscan_rep_mode
= psrm
;
557 ii
->pscan_period_mode
= pspm
;
558 ii
->clock_offset
= le16toh(co
);
562 memcpy(ii
->dev_class
, cl
, HCI_CLASS_SIZE
);
565 memcpy(ii
->data
, data
, 240);
569 bt_devinquiry(const char *name
, time_t to
, int max_rsp
,
570 struct bt_devinquiry
**iip
)
572 uint8_t buf
[HCI_EVENT_PKT_SIZE
], *p
;
573 struct bt_devfilter f
;
575 hci_command_status_ep sp
;
577 hci_inquiry_result_ep ip
;
578 hci_inquiry_response ir
;
579 hci_rssi_result_ep rp
;
580 hci_rssi_response rr
;
581 hci_extended_result_ep ep
;
582 struct bt_devinquiry
*ii
;
593 if (bt_devenum(bt__devany_cb
, buf
) == -1)
596 name
= (const char *)buf
;
599 s
= bt_devopen(name
, 0);
603 memset(&f
, 0, sizeof(f
));
604 bt_devfilter_pkt_set(&f
, HCI_EVENT_PKT
);
605 bt_devfilter_evt_set(&f
, HCI_EVENT_COMMAND_STATUS
);
606 bt_devfilter_evt_set(&f
, HCI_EVENT_INQUIRY_COMPL
);
607 bt_devfilter_evt_set(&f
, HCI_EVENT_INQUIRY_RESULT
);
608 bt_devfilter_evt_set(&f
, HCI_EVENT_RSSI_RESULT
);
609 bt_devfilter_evt_set(&f
, HCI_EVENT_EXTENDED_RESULT
);
610 if (bt_devfilter(s
, &f
, NULL
) == -1) {
616 * silently adjust number of reponses to fit in uint8_t
620 else if (max_rsp
> UINT8_MAX
)
623 ii
= calloc((size_t)max_rsp
, sizeof(struct bt_devinquiry
));
630 * silently adjust timeout value so that inquiry_length
631 * falls into the range 0x01->0x30 (unit is 1.28 seconds)
640 /* General Inquiry LAP is 0x9e8b33 */
644 cp
.inquiry_length
= (uint8_t)(to
* 100 / 128);
645 cp
.num_responses
= (uint8_t)max_rsp
;
647 if (bt_devsend(s
, HCI_CMD_INQUIRY
, &cp
, sizeof(cp
)) == -1)
652 for (t_end
= time(NULL
) + to
+ 1; to
> 0; to
= t_end
- time(NULL
)) {
654 n
= bt_devrecv(s
, buf
, sizeof(buf
), to
);
658 if (sizeof(ev
) > (size_t)n
) {
663 memcpy(&ev
, p
, sizeof(ev
));
668 case HCI_EVENT_COMMAND_STATUS
:
669 if (sizeof(sp
) > (size_t)n
)
672 memcpy(&sp
, p
, sizeof(sp
));
674 if (le16toh(sp
.opcode
) != HCI_CMD_INQUIRY
681 case HCI_EVENT_INQUIRY_COMPL
:
686 case HCI_EVENT_INQUIRY_RESULT
:
687 if (sizeof(ip
) > (size_t)n
)
690 memcpy(&ip
, p
, sizeof(ip
));
694 if (sizeof(ir
) * ip
.num_responses
!= (size_t)n
)
697 for (i
= 0; i
< ip
.num_responses
; i
++) {
698 memcpy(&ir
, p
, sizeof(ir
));
701 bt__devresult(ii
, &count
, max_rsp
,
703 ir
.page_scan_rep_mode
,
704 ir
.page_scan_period_mode
,
708 NULL
); /* extended data */
713 case HCI_EVENT_RSSI_RESULT
:
714 if (sizeof(rp
) > (size_t)n
)
717 memcpy(&rp
, p
, sizeof(rp
));
721 if (sizeof(rr
) * rp
.num_responses
!= (size_t)n
)
724 for (i
= 0; i
< rp
.num_responses
; i
++) {
725 memcpy(&rr
, p
, sizeof(rr
));
728 bt__devresult(ii
, &count
, max_rsp
,
730 rr
.page_scan_rep_mode
,
731 0, /* page scan period mode */
735 NULL
); /* extended data */
740 case HCI_EVENT_EXTENDED_RESULT
:
741 if (sizeof(ep
) != (size_t)n
)
744 memcpy(&ep
, p
, sizeof(ep
));
746 if (ep
.num_responses
!= 1)
749 bt__devresult(ii
, &count
, max_rsp
,
751 ep
.page_scan_rep_mode
,
752 0, /* page scan period mode */
774 * Internal version of bt_devinfo. Fill in the devinfo structure
775 * with the socket handle provided. If the device is present and
776 * active, the socket will be left connected to the device.
779 bt__devinfo(int s
, const char *name
, struct bt_devinfo
*info
)
781 struct sockaddr_bt sa
;
782 struct bt_devreq req
;
784 hci_read_buffer_size_rp bp
;
785 hci_read_local_features_rp fp
;
787 memset(&btr
, 0, sizeof(btr
));
788 strncpy(btr
.btr_name
, name
, HCI_DEVNAME_SIZE
);
790 if (ioctl(s
, SIOCGBTINFO
, &btr
) == -1)
793 memset(info
, 0, sizeof(struct bt_devinfo
));
794 memcpy(info
->devname
, btr
.btr_name
, HCI_DEVNAME_SIZE
);
795 bdaddr_copy(&info
->bdaddr
, &btr
.btr_bdaddr
);
796 info
->enabled
= ((btr
.btr_flags
& BTF_UP
) ? 1 : 0);
798 info
->sco_size
= btr
.btr_sco_mtu
;
799 info
->acl_size
= btr
.btr_acl_mtu
;
800 info
->cmd_free
= btr
.btr_num_cmd
;
801 info
->sco_free
= btr
.btr_num_sco
;
802 info
->acl_free
= btr
.btr_num_acl
;
804 info
->link_policy_info
= btr
.btr_link_policy
;
805 info
->packet_type_info
= btr
.btr_packet_type
;
807 if (ioctl(s
, SIOCGBTSTATS
, &btr
) == -1)
810 info
->cmd_sent
= btr
.btr_stats
.cmd_tx
;
811 info
->evnt_recv
= btr
.btr_stats
.evt_rx
;
812 info
->acl_recv
= btr
.btr_stats
.acl_rx
;
813 info
->acl_sent
= btr
.btr_stats
.acl_tx
;
814 info
->sco_recv
= btr
.btr_stats
.sco_rx
;
815 info
->sco_sent
= btr
.btr_stats
.sco_tx
;
816 info
->bytes_recv
= btr
.btr_stats
.byte_rx
;
817 info
->bytes_sent
= btr
.btr_stats
.byte_tx
;
819 /* can only get the rest from enabled devices */
820 if ((info
->enabled
) == 0)
823 memset(&sa
, 0, sizeof(sa
));
824 sa
.bt_len
= sizeof(sa
);
825 sa
.bt_family
= AF_BLUETOOTH
;
826 bdaddr_copy(&sa
.bt_bdaddr
, &info
->bdaddr
);
828 if (bind(s
, (struct sockaddr
*)&sa
, sizeof(sa
)) == -1
829 || connect(s
, (struct sockaddr
*)&sa
, sizeof(sa
)) == -1)
832 memset(&req
, 0, sizeof(req
));
833 req
.opcode
= HCI_CMD_READ_BUFFER_SIZE
;
835 req
.rlen
= sizeof(bp
);
837 if (bt_devreq(s
, &req
, 5) == -1)
840 info
->acl_pkts
= bp
.max_acl_size
;
841 info
->sco_pkts
= bp
.max_sco_size
;
843 memset(&req
, 0, sizeof(req
));
844 req
.opcode
= HCI_CMD_READ_LOCAL_FEATURES
;
846 req
.rlen
= sizeof(fp
);
848 if (bt_devreq(s
, &req
, 5) == -1)
851 memcpy(info
->features
, fp
.features
, HCI_FEATURES_SIZE
);
857 bt_devinfo(const char *name
, struct bt_devinfo
*info
)
861 if (name
== NULL
|| info
== NULL
) {
866 s
= socket(PF_BLUETOOTH
, SOCK_RAW
, BTPROTO_HCI
);
870 rv
= bt__devinfo(s
, name
, info
);
876 bt_devenum(bt_devenum_cb_t cb
, void *arg
)
879 struct bt_devinfo info
;
880 int count
, fd
, rv
, s
;
882 s
= socket(PF_BLUETOOTH
, SOCK_RAW
, BTPROTO_HCI
);
886 memset(&btr
, 0, sizeof(btr
));
889 while (ioctl(s
, SIOCNBTINFO
, &btr
) != -1) {
895 fd
= socket(PF_BLUETOOTH
, SOCK_RAW
, BTPROTO_HCI
);
901 if (bt__devinfo(fd
, btr
.btr_name
, &info
) == -1) {
907 rv
= (*cb
)(fd
, &info
, arg
);