bt_dev.c revision 1.5 1 1.5 msaitoh /* $NetBSD: bt_dev.c,v 1.5 2023/06/24 05:18:12 msaitoh Exp $ */
2 1.1 plunky
3 1.1 plunky /*-
4 1.1 plunky * Copyright (c) 2009 Iain Hibbert
5 1.1 plunky * Copyright (c) 2009 Maksim Yevmenkin <m_evmenkin (at) yahoo.com>
6 1.1 plunky * All rights reserved.
7 1.1 plunky *
8 1.1 plunky * Redistribution and use in source and binary forms, with or without
9 1.1 plunky * modification, are permitted provided that the following conditions
10 1.1 plunky * are met:
11 1.1 plunky * 1. Redistributions of source code must retain the above copyright
12 1.1 plunky * notice, this list of conditions and the following disclaimer.
13 1.1 plunky * 2. Redistributions in binary form must reproduce the above copyright
14 1.1 plunky * notice, this list of conditions and the following disclaimer in the
15 1.1 plunky * documentation and/or other materials provided with the distribution.
16 1.1 plunky *
17 1.1 plunky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 1.1 plunky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 1.1 plunky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 1.1 plunky * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 1.1 plunky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 1.1 plunky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 1.1 plunky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 1.1 plunky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 1.1 plunky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 1.1 plunky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 1.1 plunky * SUCH DAMAGE.
28 1.1 plunky */
29 1.1 plunky
30 1.1 plunky /*-
31 1.1 plunky * Copyright (c) 2006 Itronix Inc.
32 1.1 plunky * All rights reserved.
33 1.1 plunky *
34 1.1 plunky * Written by Iain Hibbert for Itronix Inc.
35 1.1 plunky *
36 1.1 plunky * Redistribution and use in source and binary forms, with or without
37 1.1 plunky * modification, are permitted provided that the following conditions
38 1.1 plunky * are met:
39 1.1 plunky * 1. Redistributions of source code must retain the above copyright
40 1.1 plunky * notice, this list of conditions and the following disclaimer.
41 1.1 plunky * 2. Redistributions in binary form must reproduce the above copyright
42 1.1 plunky * notice, this list of conditions and the following disclaimer in the
43 1.1 plunky * documentation and/or other materials provided with the distribution.
44 1.1 plunky * 3. The name of Itronix Inc. may not be used to endorse
45 1.1 plunky * or promote products derived from this software without specific
46 1.1 plunky * prior written permission.
47 1.1 plunky *
48 1.1 plunky * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
49 1.1 plunky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
50 1.1 plunky * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
51 1.1 plunky * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
52 1.1 plunky * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
53 1.1 plunky * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
54 1.1 plunky * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
55 1.1 plunky * ON ANY THEORY OF LIABILITY, WHETHER IN
56 1.1 plunky * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
57 1.1 plunky * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
58 1.1 plunky * POSSIBILITY OF SUCH DAMAGE.
59 1.1 plunky */
60 1.1 plunky
61 1.1 plunky #include <sys/cdefs.h>
62 1.5 msaitoh __RCSID("$NetBSD: bt_dev.c,v 1.5 2023/06/24 05:18:12 msaitoh Exp $");
63 1.1 plunky
64 1.1 plunky #include <sys/event.h>
65 1.1 plunky #include <sys/ioctl.h>
66 1.1 plunky #include <sys/param.h>
67 1.1 plunky #include <sys/time.h>
68 1.1 plunky #include <sys/uio.h>
69 1.1 plunky
70 1.1 plunky #include <bluetooth.h>
71 1.1 plunky #include <errno.h>
72 1.1 plunky #include <stdlib.h>
73 1.1 plunky #include <string.h>
74 1.1 plunky #include <unistd.h>
75 1.1 plunky
76 1.1 plunky int
77 1.1 plunky bt_devaddr(const char *name, bdaddr_t *addr)
78 1.1 plunky {
79 1.1 plunky struct btreq btr;
80 1.1 plunky bdaddr_t bdaddr;
81 1.1 plunky int s, rv;
82 1.1 plunky
83 1.1 plunky if (name == NULL) {
84 1.1 plunky errno = EINVAL;
85 1.1 plunky return 0;
86 1.1 plunky }
87 1.1 plunky
88 1.1 plunky if (addr == NULL)
89 1.1 plunky addr = &bdaddr;
90 1.1 plunky
91 1.1 plunky if (bt_aton(name, addr))
92 1.1 plunky return bt_devname(NULL, addr);
93 1.1 plunky
94 1.1 plunky memset(&btr, 0, sizeof(btr));
95 1.4 christos strlcpy(btr.btr_name, name, HCI_DEVNAME_SIZE);
96 1.1 plunky
97 1.1 plunky s = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
98 1.1 plunky if (s == -1)
99 1.1 plunky return 0;
100 1.1 plunky
101 1.1 plunky rv = ioctl(s, SIOCGBTINFO, &btr);
102 1.1 plunky close(s);
103 1.1 plunky
104 1.1 plunky if (rv == -1)
105 1.1 plunky return 0;
106 1.1 plunky
107 1.1 plunky if ((btr.btr_flags & BTF_UP) == 0) {
108 1.1 plunky errno = ENXIO;
109 1.1 plunky return 0;
110 1.1 plunky }
111 1.1 plunky
112 1.1 plunky bdaddr_copy(addr, &btr.btr_bdaddr);
113 1.1 plunky return 1;
114 1.1 plunky }
115 1.1 plunky
116 1.1 plunky int
117 1.1 plunky bt_devname(char *name, const bdaddr_t *bdaddr)
118 1.1 plunky {
119 1.1 plunky struct btreq btr;
120 1.1 plunky int s, rv;
121 1.1 plunky
122 1.1 plunky if (bdaddr == NULL) {
123 1.1 plunky errno = EINVAL;
124 1.1 plunky return 0;
125 1.1 plunky }
126 1.1 plunky
127 1.1 plunky memset(&btr, 0, sizeof(btr));
128 1.1 plunky bdaddr_copy(&btr.btr_bdaddr, bdaddr);
129 1.1 plunky
130 1.1 plunky s = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
131 1.1 plunky if (s == -1)
132 1.1 plunky return 0;
133 1.1 plunky
134 1.1 plunky rv = ioctl(s, SIOCGBTINFOA, &btr);
135 1.1 plunky close(s);
136 1.1 plunky
137 1.1 plunky if (rv == -1)
138 1.1 plunky return 0;
139 1.1 plunky
140 1.1 plunky if ((btr.btr_flags & BTF_UP) == 0) {
141 1.1 plunky errno = ENXIO;
142 1.1 plunky return 0;
143 1.1 plunky }
144 1.1 plunky
145 1.1 plunky if (name != NULL)
146 1.1 plunky strlcpy(name, btr.btr_name, HCI_DEVNAME_SIZE);
147 1.1 plunky
148 1.1 plunky return 1;
149 1.1 plunky }
150 1.1 plunky
151 1.1 plunky int
152 1.1 plunky bt_devopen(const char *name, int options)
153 1.1 plunky {
154 1.1 plunky struct sockaddr_bt sa;
155 1.1 plunky int opt, s;
156 1.1 plunky
157 1.1 plunky memset(&sa, 0, sizeof(sa));
158 1.1 plunky sa.bt_len = sizeof(sa);
159 1.1 plunky sa.bt_family = AF_BLUETOOTH;
160 1.1 plunky
161 1.1 plunky if (name != NULL && !bt_devaddr(name, &sa.bt_bdaddr))
162 1.1 plunky return -1;
163 1.1 plunky
164 1.1 plunky s = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
165 1.1 plunky if (s == -1)
166 1.1 plunky return -1;
167 1.1 plunky
168 1.1 plunky opt = 1;
169 1.1 plunky
170 1.1 plunky if ((options & BTOPT_DIRECTION) && setsockopt(s, BTPROTO_HCI,
171 1.1 plunky SO_HCI_DIRECTION, &opt, sizeof(opt)) == -1) {
172 1.1 plunky close(s);
173 1.1 plunky return -1;
174 1.1 plunky }
175 1.1 plunky
176 1.1 plunky if ((options & BTOPT_TIMESTAMP) && setsockopt(s, SOL_SOCKET,
177 1.1 plunky SO_TIMESTAMP, &opt, sizeof(opt)) == -1) {
178 1.1 plunky close(s);
179 1.1 plunky return -1;
180 1.1 plunky }
181 1.1 plunky
182 1.1 plunky if (bind(s, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
183 1.1 plunky close(s);
184 1.1 plunky return -1;
185 1.1 plunky }
186 1.1 plunky
187 1.1 plunky if (name != NULL
188 1.1 plunky && connect(s, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
189 1.1 plunky close(s);
190 1.1 plunky return -1;
191 1.1 plunky }
192 1.1 plunky
193 1.1 plunky return s;
194 1.1 plunky }
195 1.1 plunky
196 1.1 plunky ssize_t
197 1.1 plunky bt_devsend(int s, uint16_t opcode, void *param, size_t plen)
198 1.1 plunky {
199 1.1 plunky hci_cmd_hdr_t hdr;
200 1.1 plunky struct iovec iov[2];
201 1.1 plunky ssize_t n;
202 1.1 plunky
203 1.1 plunky if (plen > UINT8_MAX
204 1.1 plunky || (plen == 0 && param != NULL)
205 1.1 plunky || (plen != 0 && param == NULL)) {
206 1.1 plunky errno = EINVAL;
207 1.1 plunky return -1;
208 1.1 plunky }
209 1.1 plunky
210 1.1 plunky hdr.type = HCI_CMD_PKT;
211 1.1 plunky hdr.opcode = htole16(opcode);
212 1.1 plunky hdr.length = (uint8_t)plen;
213 1.1 plunky
214 1.1 plunky iov[0].iov_base = &hdr;
215 1.1 plunky iov[0].iov_len = sizeof(hdr);
216 1.1 plunky
217 1.1 plunky iov[1].iov_base = param;
218 1.1 plunky iov[1].iov_len = plen;
219 1.1 plunky
220 1.1 plunky while ((n = writev(s, iov, __arraycount(iov))) == -1) {
221 1.1 plunky if (errno == EINTR)
222 1.1 plunky continue;
223 1.1 plunky
224 1.1 plunky return -1;
225 1.1 plunky }
226 1.1 plunky
227 1.1 plunky return n;
228 1.1 plunky }
229 1.1 plunky
230 1.1 plunky ssize_t
231 1.1 plunky bt_devrecv(int s, void *buf, size_t size, time_t to)
232 1.1 plunky {
233 1.1 plunky struct kevent ev;
234 1.1 plunky struct timespec ts;
235 1.1 plunky uint8_t *p;
236 1.1 plunky ssize_t n;
237 1.1 plunky int kq;
238 1.1 plunky
239 1.1 plunky if (buf == NULL || size == 0) {
240 1.1 plunky errno = EINVAL;
241 1.1 plunky return -1;
242 1.1 plunky }
243 1.1 plunky
244 1.1 plunky if (to >= 0) { /* timeout is optional */
245 1.1 plunky kq = kqueue();
246 1.1 plunky if (kq == -1)
247 1.1 plunky return -1;
248 1.1 plunky
249 1.1 plunky EV_SET(&ev, s, EVFILT_READ, EV_ADD, 0, 0, 0);
250 1.1 plunky
251 1.1 plunky ts.tv_sec = to;
252 1.1 plunky ts.tv_nsec = 0;
253 1.1 plunky
254 1.1 plunky while (kevent(kq, &ev, 1, &ev, 1, &ts) == -1) {
255 1.1 plunky if (errno == EINTR)
256 1.1 plunky continue;
257 1.1 plunky
258 1.1 plunky close(kq);
259 1.1 plunky return -1;
260 1.1 plunky }
261 1.1 plunky
262 1.1 plunky close(kq);
263 1.1 plunky
264 1.1 plunky if (ev.data == 0) {
265 1.1 plunky errno = ETIMEDOUT;
266 1.1 plunky return -1;
267 1.1 plunky }
268 1.1 plunky }
269 1.1 plunky
270 1.1 plunky while ((n = recv(s, buf, size, 0)) == -1) {
271 1.1 plunky if (errno == EINTR)
272 1.1 plunky continue;
273 1.1 plunky
274 1.1 plunky return -1;
275 1.1 plunky }
276 1.1 plunky
277 1.1 plunky if (n == 0)
278 1.1 plunky return 0;
279 1.1 plunky
280 1.1 plunky p = buf;
281 1.1 plunky switch (p[0]) { /* validate that they get complete packets */
282 1.1 plunky case HCI_CMD_PKT:
283 1.1 plunky if (sizeof(hci_cmd_hdr_t) > (size_t)n
284 1.1 plunky || sizeof(hci_cmd_hdr_t) + p[3] != (size_t)n)
285 1.1 plunky break;
286 1.1 plunky
287 1.1 plunky return n;
288 1.1 plunky
289 1.1 plunky case HCI_ACL_DATA_PKT:
290 1.1 plunky if (sizeof(hci_acldata_hdr_t) > (size_t)n
291 1.1 plunky || sizeof(hci_acldata_hdr_t) + le16dec(p + 3) != (size_t)n)
292 1.1 plunky break;
293 1.1 plunky
294 1.1 plunky return n;
295 1.1 plunky
296 1.1 plunky case HCI_SCO_DATA_PKT:
297 1.1 plunky if (sizeof(hci_scodata_hdr_t) > (size_t)n
298 1.1 plunky || sizeof(hci_scodata_hdr_t) + p[3] != (size_t)n)
299 1.1 plunky break;
300 1.1 plunky
301 1.1 plunky return n;
302 1.1 plunky
303 1.1 plunky case HCI_EVENT_PKT:
304 1.1 plunky if (sizeof(hci_event_hdr_t) > (size_t)n
305 1.1 plunky || sizeof(hci_event_hdr_t) + p[2] != (size_t)n)
306 1.1 plunky break;
307 1.1 plunky
308 1.1 plunky return n;
309 1.1 plunky
310 1.1 plunky default:
311 1.1 plunky break;
312 1.1 plunky }
313 1.1 plunky
314 1.1 plunky errno = EIO;
315 1.1 plunky return -1;
316 1.1 plunky }
317 1.1 plunky
318 1.1 plunky /*
319 1.1 plunky * Internal handler for bt_devreq(), do the actual request.
320 1.1 plunky */
321 1.1 plunky static int
322 1.1 plunky bt__devreq(int s, struct bt_devreq *req, time_t t_end)
323 1.1 plunky {
324 1.1 plunky uint8_t buf[HCI_EVENT_PKT_SIZE], *p;
325 1.1 plunky hci_event_hdr_t ev;
326 1.1 plunky hci_command_status_ep cs;
327 1.1 plunky hci_command_compl_ep cc;
328 1.1 plunky time_t to;
329 1.1 plunky ssize_t n;
330 1.1 plunky
331 1.1 plunky n = bt_devsend(s, req->opcode, req->cparam, req->clen);
332 1.1 plunky if (n == -1)
333 1.1 plunky return errno;
334 1.1 plunky
335 1.1 plunky for (;;) {
336 1.1 plunky to = t_end - time(NULL);
337 1.1 plunky if (to < 0)
338 1.1 plunky return ETIMEDOUT;
339 1.1 plunky
340 1.1 plunky p = buf;
341 1.1 plunky n = bt_devrecv(s, buf, sizeof(buf), to);
342 1.1 plunky if (n == -1)
343 1.1 plunky return errno;
344 1.1 plunky
345 1.1 plunky if (sizeof(ev) > (size_t)n || p[0] != HCI_EVENT_PKT)
346 1.1 plunky return EIO;
347 1.1 plunky
348 1.1 plunky memcpy(&ev, p, sizeof(ev));
349 1.1 plunky p += sizeof(ev);
350 1.1 plunky n -= sizeof(ev);
351 1.1 plunky
352 1.1 plunky if (ev.event == req->event)
353 1.1 plunky break;
354 1.1 plunky
355 1.1 plunky if (ev.event == HCI_EVENT_COMMAND_STATUS) {
356 1.1 plunky if (sizeof(cs) > (size_t)n)
357 1.1 plunky return EIO;
358 1.1 plunky
359 1.1 plunky memcpy(&cs, p, sizeof(cs));
360 1.1 plunky p += sizeof(cs);
361 1.1 plunky n -= sizeof(cs);
362 1.1 plunky
363 1.1 plunky if (le16toh(cs.opcode) == req->opcode) {
364 1.1 plunky if (cs.status != 0)
365 1.1 plunky return EIO;
366 1.1 plunky
367 1.1 plunky if (req->event == 0)
368 1.1 plunky break;
369 1.1 plunky }
370 1.1 plunky
371 1.1 plunky continue;
372 1.1 plunky }
373 1.1 plunky
374 1.1 plunky if (ev.event == HCI_EVENT_COMMAND_COMPL) {
375 1.1 plunky if (sizeof(cc) > (size_t)n)
376 1.1 plunky return EIO;
377 1.1 plunky
378 1.1 plunky memcpy(&cc, p, sizeof(cc));
379 1.1 plunky p += sizeof(cc);
380 1.1 plunky n -= sizeof(cc);
381 1.1 plunky
382 1.1 plunky if (le16toh(cc.opcode) == req->opcode)
383 1.1 plunky break;
384 1.1 plunky
385 1.1 plunky continue;
386 1.1 plunky }
387 1.1 plunky }
388 1.1 plunky
389 1.1 plunky /* copy out response data */
390 1.1 plunky if (req->rlen >= (size_t)n) {
391 1.1 plunky req->rlen = n;
392 1.1 plunky memcpy(req->rparam, p, req->rlen);
393 1.1 plunky } else if (req->rlen > 0)
394 1.1 plunky return EIO;
395 1.1 plunky
396 1.1 plunky return 0;
397 1.1 plunky }
398 1.1 plunky
399 1.1 plunky int
400 1.1 plunky bt_devreq(int s, struct bt_devreq *req, time_t to)
401 1.1 plunky {
402 1.1 plunky struct bt_devfilter new, old;
403 1.1 plunky int error;
404 1.1 plunky
405 1.1 plunky if (req == NULL || to < 0
406 1.1 plunky || (req->rlen == 0 && req->rparam != NULL)
407 1.1 plunky || (req->rlen != 0 && req->rparam == NULL)) {
408 1.1 plunky errno = EINVAL;
409 1.1 plunky return -1;
410 1.1 plunky }
411 1.1 plunky
412 1.1 plunky memset(&new, 0, sizeof(new));
413 1.1 plunky bt_devfilter_pkt_set(&new, HCI_EVENT_PKT);
414 1.1 plunky bt_devfilter_evt_set(&new, HCI_EVENT_COMMAND_COMPL);
415 1.1 plunky bt_devfilter_evt_set(&new, HCI_EVENT_COMMAND_STATUS);
416 1.1 plunky
417 1.1 plunky if (req->event != 0)
418 1.1 plunky bt_devfilter_evt_set(&new, req->event);
419 1.1 plunky
420 1.1 plunky if (bt_devfilter(s, &new, &old) == -1)
421 1.1 plunky return -1;
422 1.1 plunky
423 1.1 plunky error = bt__devreq(s, req, to + time(NULL));
424 1.1 plunky
425 1.1 plunky (void)bt_devfilter(s, &old, NULL);
426 1.1 plunky
427 1.1 plunky if (error != 0) {
428 1.1 plunky errno = error;
429 1.1 plunky return -1;
430 1.1 plunky }
431 1.1 plunky
432 1.1 plunky return 0;
433 1.1 plunky }
434 1.1 plunky
435 1.1 plunky int
436 1.1 plunky bt_devfilter(int s, const struct bt_devfilter *new, struct bt_devfilter *old)
437 1.1 plunky {
438 1.1 plunky socklen_t len;
439 1.1 plunky
440 1.1 plunky if (new == NULL && old == NULL) {
441 1.1 plunky errno = EINVAL;
442 1.1 plunky return -1;
443 1.1 plunky }
444 1.1 plunky
445 1.1 plunky len = sizeof(struct hci_filter);
446 1.1 plunky
447 1.1 plunky if (old != NULL) {
448 1.1 plunky if (getsockopt(s, BTPROTO_HCI,
449 1.1 plunky SO_HCI_PKT_FILTER, &old->packet_mask, &len) == -1
450 1.1 plunky || len != sizeof(struct hci_filter))
451 1.1 plunky return -1;
452 1.1 plunky
453 1.1 plunky if (getsockopt(s, BTPROTO_HCI,
454 1.1 plunky SO_HCI_EVT_FILTER, &old->event_mask, &len) == -1
455 1.1 plunky || len != sizeof(struct hci_filter))
456 1.1 plunky return -1;
457 1.1 plunky }
458 1.1 plunky
459 1.1 plunky if (new != NULL) {
460 1.1 plunky if (setsockopt(s, BTPROTO_HCI,
461 1.1 plunky SO_HCI_PKT_FILTER, &new->packet_mask, len) == -1)
462 1.1 plunky return -1;
463 1.1 plunky
464 1.1 plunky if (setsockopt(s, BTPROTO_HCI,
465 1.1 plunky SO_HCI_EVT_FILTER, &new->event_mask, len) == -1)
466 1.1 plunky return -1;
467 1.1 plunky }
468 1.1 plunky
469 1.1 plunky return 0;
470 1.1 plunky }
471 1.1 plunky
472 1.1 plunky void
473 1.1 plunky bt_devfilter_pkt_set(struct bt_devfilter *filter, uint8_t type)
474 1.1 plunky {
475 1.1 plunky
476 1.1 plunky hci_filter_set(type, &filter->packet_mask);
477 1.1 plunky }
478 1.1 plunky
479 1.1 plunky void
480 1.1 plunky bt_devfilter_pkt_clr(struct bt_devfilter *filter, uint8_t type)
481 1.1 plunky {
482 1.1 plunky
483 1.1 plunky hci_filter_clr(type, &filter->packet_mask);
484 1.1 plunky }
485 1.1 plunky
486 1.1 plunky int
487 1.1 plunky bt_devfilter_pkt_tst(const struct bt_devfilter *filter, uint8_t type)
488 1.1 plunky {
489 1.1 plunky
490 1.1 plunky return hci_filter_test(type, &filter->packet_mask);
491 1.1 plunky }
492 1.1 plunky
493 1.1 plunky void
494 1.1 plunky bt_devfilter_evt_set(struct bt_devfilter *filter, uint8_t event)
495 1.1 plunky {
496 1.1 plunky
497 1.1 plunky hci_filter_set(event, &filter->event_mask);
498 1.1 plunky }
499 1.1 plunky
500 1.1 plunky void
501 1.1 plunky bt_devfilter_evt_clr(struct bt_devfilter *filter, uint8_t event)
502 1.1 plunky {
503 1.1 plunky
504 1.1 plunky hci_filter_clr(event, &filter->event_mask);
505 1.1 plunky }
506 1.1 plunky
507 1.1 plunky int
508 1.1 plunky bt_devfilter_evt_tst(const struct bt_devfilter *filter, uint8_t event)
509 1.1 plunky {
510 1.1 plunky
511 1.1 plunky return hci_filter_test(event, &filter->event_mask);
512 1.1 plunky }
513 1.1 plunky
514 1.1 plunky /*
515 1.1 plunky * Internal function used by bt_devinquiry to find the first
516 1.1 plunky * active device.
517 1.1 plunky */
518 1.2 plunky /* ARGSUSED */
519 1.1 plunky static int
520 1.1 plunky bt__devany_cb(int s, const struct bt_devinfo *info, void *arg)
521 1.1 plunky {
522 1.1 plunky
523 1.1 plunky if ((info->enabled)) {
524 1.1 plunky strlcpy(arg, info->devname, HCI_DEVNAME_SIZE + 1);
525 1.1 plunky return 1;
526 1.1 plunky }
527 1.1 plunky
528 1.1 plunky return 0;
529 1.1 plunky }
530 1.1 plunky
531 1.1 plunky /*
532 1.1 plunky * Internal function used by bt_devinquiry to insert inquiry
533 1.1 plunky * results to an array. Make sure that a bdaddr only appears
534 1.1 plunky * once in the list and always use the latest result.
535 1.1 plunky */
536 1.1 plunky static void
537 1.1 plunky bt__devresult(struct bt_devinquiry *ii, int *count, int max_count,
538 1.1 plunky bdaddr_t *ba, uint8_t psrm, uint8_t pspm, uint8_t *cl, uint16_t co,
539 1.1 plunky int8_t rssi, uint8_t *data)
540 1.1 plunky {
541 1.1 plunky int n;
542 1.1 plunky
543 1.1 plunky for (n = 0; ; n++, ii++) {
544 1.1 plunky if (n == *count) {
545 1.1 plunky if (*count == max_count)
546 1.1 plunky return;
547 1.1 plunky
548 1.1 plunky (*count)++;
549 1.1 plunky break;
550 1.1 plunky }
551 1.1 plunky
552 1.1 plunky if (bdaddr_same(&ii->bdaddr, ba))
553 1.1 plunky break;
554 1.1 plunky }
555 1.1 plunky
556 1.1 plunky bdaddr_copy(&ii->bdaddr, ba);
557 1.1 plunky ii->pscan_rep_mode = psrm;
558 1.1 plunky ii->pscan_period_mode = pspm;
559 1.1 plunky ii->clock_offset = le16toh(co);
560 1.1 plunky ii->rssi = rssi;
561 1.1 plunky
562 1.1 plunky if (cl != NULL)
563 1.1 plunky memcpy(ii->dev_class, cl, HCI_CLASS_SIZE);
564 1.1 plunky
565 1.1 plunky if (data != NULL)
566 1.1 plunky memcpy(ii->data, data, 240);
567 1.1 plunky }
568 1.1 plunky
569 1.1 plunky int
570 1.1 plunky bt_devinquiry(const char *name, time_t to, int max_rsp,
571 1.1 plunky struct bt_devinquiry **iip)
572 1.1 plunky {
573 1.1 plunky uint8_t buf[HCI_EVENT_PKT_SIZE], *p;
574 1.1 plunky struct bt_devfilter f;
575 1.1 plunky hci_event_hdr_t ev;
576 1.1 plunky hci_command_status_ep sp;
577 1.1 plunky hci_inquiry_cp cp;
578 1.1 plunky hci_inquiry_result_ep ip;
579 1.1 plunky hci_inquiry_response ir;
580 1.1 plunky hci_rssi_result_ep rp;
581 1.1 plunky hci_rssi_response rr;
582 1.1 plunky hci_extended_result_ep ep;
583 1.1 plunky struct bt_devinquiry *ii;
584 1.1 plunky int count, i, s;
585 1.1 plunky time_t t_end;
586 1.1 plunky ssize_t n;
587 1.1 plunky
588 1.1 plunky if (iip == NULL) {
589 1.1 plunky errno = EINVAL;
590 1.1 plunky return -1;
591 1.1 plunky }
592 1.1 plunky
593 1.1 plunky if (name == NULL) {
594 1.1 plunky if (bt_devenum(bt__devany_cb, buf) == -1)
595 1.1 plunky return -1;
596 1.1 plunky
597 1.1 plunky name = (const char *)buf;
598 1.1 plunky }
599 1.1 plunky
600 1.1 plunky s = bt_devopen(name, 0);
601 1.1 plunky if (s == -1)
602 1.1 plunky return -1;
603 1.1 plunky
604 1.1 plunky memset(&f, 0, sizeof(f));
605 1.1 plunky bt_devfilter_pkt_set(&f, HCI_EVENT_PKT);
606 1.1 plunky bt_devfilter_evt_set(&f, HCI_EVENT_COMMAND_STATUS);
607 1.1 plunky bt_devfilter_evt_set(&f, HCI_EVENT_INQUIRY_COMPL);
608 1.1 plunky bt_devfilter_evt_set(&f, HCI_EVENT_INQUIRY_RESULT);
609 1.1 plunky bt_devfilter_evt_set(&f, HCI_EVENT_RSSI_RESULT);
610 1.1 plunky bt_devfilter_evt_set(&f, HCI_EVENT_EXTENDED_RESULT);
611 1.1 plunky if (bt_devfilter(s, &f, NULL) == -1) {
612 1.1 plunky close(s);
613 1.1 plunky return -1;
614 1.1 plunky }
615 1.1 plunky
616 1.1 plunky /*
617 1.5 msaitoh * silently adjust number of responses to fit in uint8_t
618 1.1 plunky */
619 1.1 plunky if (max_rsp < 1)
620 1.1 plunky max_rsp = 8;
621 1.1 plunky else if (max_rsp > UINT8_MAX)
622 1.1 plunky max_rsp = UINT8_MAX;
623 1.1 plunky
624 1.1 plunky ii = calloc((size_t)max_rsp, sizeof(struct bt_devinquiry));
625 1.1 plunky if (ii == NULL) {
626 1.1 plunky close(s);
627 1.1 plunky return -1;
628 1.1 plunky }
629 1.1 plunky
630 1.1 plunky /*
631 1.1 plunky * silently adjust timeout value so that inquiry_length
632 1.1 plunky * falls into the range 0x01->0x30 (unit is 1.28 seconds)
633 1.1 plunky */
634 1.1 plunky if (to < 1)
635 1.1 plunky to = 5;
636 1.1 plunky else if (to == 1)
637 1.1 plunky to = 2;
638 1.1 plunky else if (to > 62)
639 1.1 plunky to = 62;
640 1.1 plunky
641 1.1 plunky /* General Inquiry LAP is 0x9e8b33 */
642 1.1 plunky cp.lap[0] = 0x33;
643 1.1 plunky cp.lap[1] = 0x8b;
644 1.1 plunky cp.lap[2] = 0x9e;
645 1.1 plunky cp.inquiry_length = (uint8_t)(to * 100 / 128);
646 1.1 plunky cp.num_responses = (uint8_t)max_rsp;
647 1.1 plunky
648 1.1 plunky if (bt_devsend(s, HCI_CMD_INQUIRY, &cp, sizeof(cp)) == -1)
649 1.1 plunky goto fail;
650 1.1 plunky
651 1.1 plunky count = 0;
652 1.1 plunky
653 1.1 plunky for (t_end = time(NULL) + to + 1; to > 0; to = t_end - time(NULL)) {
654 1.1 plunky p = buf;
655 1.1 plunky n = bt_devrecv(s, buf, sizeof(buf), to);
656 1.1 plunky if (n == -1)
657 1.1 plunky goto fail;
658 1.1 plunky
659 1.1 plunky if (sizeof(ev) > (size_t)n) {
660 1.1 plunky errno = EIO;
661 1.1 plunky goto fail;
662 1.1 plunky }
663 1.1 plunky
664 1.1 plunky memcpy(&ev, p, sizeof(ev));
665 1.1 plunky p += sizeof(ev);
666 1.1 plunky n -= sizeof(ev);
667 1.1 plunky
668 1.1 plunky switch (ev.event) {
669 1.1 plunky case HCI_EVENT_COMMAND_STATUS:
670 1.1 plunky if (sizeof(sp) > (size_t)n)
671 1.1 plunky break;
672 1.1 plunky
673 1.1 plunky memcpy(&sp, p, sizeof(sp));
674 1.1 plunky
675 1.1 plunky if (le16toh(sp.opcode) != HCI_CMD_INQUIRY
676 1.1 plunky || sp.status == 0)
677 1.1 plunky break;
678 1.1 plunky
679 1.1 plunky errno = EIO;
680 1.1 plunky goto fail;
681 1.1 plunky
682 1.1 plunky case HCI_EVENT_INQUIRY_COMPL:
683 1.1 plunky close(s);
684 1.1 plunky *iip = ii;
685 1.1 plunky return count;
686 1.1 plunky
687 1.1 plunky case HCI_EVENT_INQUIRY_RESULT:
688 1.1 plunky if (sizeof(ip) > (size_t)n)
689 1.1 plunky break;
690 1.1 plunky
691 1.1 plunky memcpy(&ip, p, sizeof(ip));
692 1.1 plunky p += sizeof(ip);
693 1.1 plunky n -= sizeof(ip);
694 1.1 plunky
695 1.1 plunky if (sizeof(ir) * ip.num_responses != (size_t)n)
696 1.1 plunky break;
697 1.1 plunky
698 1.1 plunky for (i = 0; i < ip.num_responses; i++) {
699 1.1 plunky memcpy(&ir, p, sizeof(ir));
700 1.1 plunky p += sizeof(ir);
701 1.1 plunky
702 1.1 plunky bt__devresult(ii, &count, max_rsp,
703 1.1 plunky &ir.bdaddr,
704 1.1 plunky ir.page_scan_rep_mode,
705 1.1 plunky ir.page_scan_period_mode,
706 1.1 plunky ir.uclass,
707 1.1 plunky ir.clock_offset,
708 1.1 plunky 0, /* rssi */
709 1.1 plunky NULL); /* extended data */
710 1.1 plunky }
711 1.1 plunky
712 1.1 plunky break;
713 1.1 plunky
714 1.1 plunky case HCI_EVENT_RSSI_RESULT:
715 1.1 plunky if (sizeof(rp) > (size_t)n)
716 1.1 plunky break;
717 1.1 plunky
718 1.1 plunky memcpy(&rp, p, sizeof(rp));
719 1.1 plunky p += sizeof(rp);
720 1.1 plunky n -= sizeof(rp);
721 1.1 plunky
722 1.1 plunky if (sizeof(rr) * rp.num_responses != (size_t)n)
723 1.1 plunky break;
724 1.1 plunky
725 1.1 plunky for (i = 0; i < rp.num_responses; i++) {
726 1.1 plunky memcpy(&rr, p, sizeof(rr));
727 1.1 plunky p += sizeof(rr);
728 1.1 plunky
729 1.1 plunky bt__devresult(ii, &count, max_rsp,
730 1.1 plunky &rr.bdaddr,
731 1.1 plunky rr.page_scan_rep_mode,
732 1.1 plunky 0, /* page scan period mode */
733 1.1 plunky rr.uclass,
734 1.1 plunky rr.clock_offset,
735 1.1 plunky rr.rssi,
736 1.1 plunky NULL); /* extended data */
737 1.1 plunky }
738 1.1 plunky
739 1.1 plunky break;
740 1.1 plunky
741 1.1 plunky case HCI_EVENT_EXTENDED_RESULT:
742 1.1 plunky if (sizeof(ep) != (size_t)n)
743 1.1 plunky break;
744 1.1 plunky
745 1.1 plunky memcpy(&ep, p, sizeof(ep));
746 1.1 plunky
747 1.1 plunky if (ep.num_responses != 1)
748 1.1 plunky break;
749 1.1 plunky
750 1.1 plunky bt__devresult(ii, &count, max_rsp,
751 1.1 plunky &ep.bdaddr,
752 1.1 plunky ep.page_scan_rep_mode,
753 1.1 plunky 0, /* page scan period mode */
754 1.1 plunky ep.uclass,
755 1.1 plunky ep.clock_offset,
756 1.1 plunky ep.rssi,
757 1.1 plunky ep.response);
758 1.1 plunky
759 1.1 plunky break;
760 1.1 plunky
761 1.1 plunky default:
762 1.1 plunky break;
763 1.1 plunky }
764 1.1 plunky }
765 1.1 plunky
766 1.1 plunky errno = ETIMEDOUT;
767 1.1 plunky
768 1.1 plunky fail:
769 1.1 plunky free(ii);
770 1.1 plunky close(s);
771 1.1 plunky return -1;
772 1.1 plunky }
773 1.1 plunky
774 1.1 plunky /*
775 1.1 plunky * Internal version of bt_devinfo. Fill in the devinfo structure
776 1.3 plunky * with the socket handle provided.
777 1.1 plunky */
778 1.1 plunky static int
779 1.1 plunky bt__devinfo(int s, const char *name, struct bt_devinfo *info)
780 1.1 plunky {
781 1.1 plunky struct btreq btr;
782 1.1 plunky
783 1.1 plunky memset(&btr, 0, sizeof(btr));
784 1.4 christos strlcpy(btr.btr_name, name, HCI_DEVNAME_SIZE);
785 1.1 plunky
786 1.1 plunky if (ioctl(s, SIOCGBTINFO, &btr) == -1)
787 1.1 plunky return -1;
788 1.1 plunky
789 1.1 plunky memset(info, 0, sizeof(struct bt_devinfo));
790 1.1 plunky memcpy(info->devname, btr.btr_name, HCI_DEVNAME_SIZE);
791 1.1 plunky bdaddr_copy(&info->bdaddr, &btr.btr_bdaddr);
792 1.1 plunky info->enabled = ((btr.btr_flags & BTF_UP) ? 1 : 0);
793 1.1 plunky
794 1.1 plunky info->sco_size = btr.btr_sco_mtu;
795 1.1 plunky info->acl_size = btr.btr_acl_mtu;
796 1.1 plunky info->cmd_free = btr.btr_num_cmd;
797 1.1 plunky info->sco_free = btr.btr_num_sco;
798 1.1 plunky info->acl_free = btr.btr_num_acl;
799 1.3 plunky info->sco_pkts = btr.btr_max_sco;
800 1.3 plunky info->acl_pkts = btr.btr_max_acl;
801 1.1 plunky
802 1.1 plunky info->link_policy_info = btr.btr_link_policy;
803 1.1 plunky info->packet_type_info = btr.btr_packet_type;
804 1.1 plunky
805 1.3 plunky if (ioctl(s, SIOCGBTFEAT, &btr) == -1)
806 1.3 plunky return -1;
807 1.3 plunky
808 1.3 plunky memcpy(info->features, btr.btr_features0, HCI_FEATURES_SIZE);
809 1.3 plunky
810 1.1 plunky if (ioctl(s, SIOCGBTSTATS, &btr) == -1)
811 1.1 plunky return -1;
812 1.1 plunky
813 1.1 plunky info->cmd_sent = btr.btr_stats.cmd_tx;
814 1.1 plunky info->evnt_recv = btr.btr_stats.evt_rx;
815 1.1 plunky info->acl_recv = btr.btr_stats.acl_rx;
816 1.1 plunky info->acl_sent = btr.btr_stats.acl_tx;
817 1.1 plunky info->sco_recv = btr.btr_stats.sco_rx;
818 1.1 plunky info->sco_sent = btr.btr_stats.sco_tx;
819 1.1 plunky info->bytes_recv = btr.btr_stats.byte_rx;
820 1.1 plunky info->bytes_sent = btr.btr_stats.byte_tx;
821 1.1 plunky
822 1.1 plunky return 0;
823 1.1 plunky }
824 1.1 plunky
825 1.1 plunky int
826 1.1 plunky bt_devinfo(const char *name, struct bt_devinfo *info)
827 1.1 plunky {
828 1.1 plunky int rv, s;
829 1.1 plunky
830 1.1 plunky if (name == NULL || info == NULL) {
831 1.1 plunky errno = EINVAL;
832 1.1 plunky return -1;
833 1.1 plunky }
834 1.1 plunky
835 1.1 plunky s = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
836 1.1 plunky if (s == -1)
837 1.1 plunky return -1;
838 1.1 plunky
839 1.1 plunky rv = bt__devinfo(s, name, info);
840 1.1 plunky close(s);
841 1.1 plunky return rv;
842 1.1 plunky }
843 1.1 plunky
844 1.1 plunky int
845 1.1 plunky bt_devenum(bt_devenum_cb_t cb, void *arg)
846 1.1 plunky {
847 1.1 plunky struct btreq btr;
848 1.1 plunky struct bt_devinfo info;
849 1.3 plunky struct sockaddr_bt sa;
850 1.1 plunky int count, fd, rv, s;
851 1.1 plunky
852 1.1 plunky s = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
853 1.1 plunky if (s == -1)
854 1.1 plunky return -1;
855 1.1 plunky
856 1.1 plunky memset(&btr, 0, sizeof(btr));
857 1.1 plunky count = 0;
858 1.1 plunky
859 1.1 plunky while (ioctl(s, SIOCNBTINFO, &btr) != -1) {
860 1.1 plunky count++;
861 1.1 plunky
862 1.1 plunky if (cb == NULL)
863 1.1 plunky continue;
864 1.1 plunky
865 1.1 plunky fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
866 1.1 plunky if (fd == -1) {
867 1.1 plunky close(s);
868 1.1 plunky return -1;
869 1.1 plunky }
870 1.1 plunky
871 1.1 plunky if (bt__devinfo(fd, btr.btr_name, &info) == -1) {
872 1.1 plunky close(fd);
873 1.1 plunky close(s);
874 1.1 plunky return -1;
875 1.1 plunky }
876 1.1 plunky
877 1.3 plunky if (info.enabled) {
878 1.3 plunky memset(&sa, 0, sizeof(sa));
879 1.3 plunky sa.bt_len = sizeof(sa);
880 1.3 plunky sa.bt_family = AF_BLUETOOTH;
881 1.3 plunky bdaddr_copy(&sa.bt_bdaddr, &info.bdaddr);
882 1.3 plunky
883 1.3 plunky if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1
884 1.3 plunky || connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
885 1.3 plunky close(fd);
886 1.3 plunky close(s);
887 1.3 plunky return -1;
888 1.3 plunky }
889 1.3 plunky }
890 1.3 plunky
891 1.1 plunky rv = (*cb)(fd, &info, arg);
892 1.1 plunky close(fd);
893 1.1 plunky if (rv != 0)
894 1.1 plunky break;
895 1.1 plunky }
896 1.1 plunky
897 1.1 plunky close(s);
898 1.1 plunky return count;
899 1.1 plunky }
900