1 | /* $NetBSD: hci_event.c,v 1.24 2015/11/28 09:04:34 plunky Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2005 Iain Hibbert. |
5 | * Copyright (c) 2006 Itronix Inc. |
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 | * 3. The name of Itronix Inc. may not be used to endorse |
17 | * or promote products derived from this software without specific |
18 | * prior written permission. |
19 | * |
20 | * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND |
21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY |
24 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
25 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
26 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
27 | * ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30 | * POSSIBILITY OF SUCH DAMAGE. |
31 | */ |
32 | |
33 | #include <sys/cdefs.h> |
34 | __KERNEL_RCSID(0, "$NetBSD: hci_event.c,v 1.24 2015/11/28 09:04:34 plunky Exp $" ); |
35 | |
36 | #include <sys/param.h> |
37 | #include <sys/kernel.h> |
38 | #include <sys/malloc.h> |
39 | #include <sys/mbuf.h> |
40 | #include <sys/proc.h> |
41 | #include <sys/systm.h> |
42 | |
43 | #include <netbt/bluetooth.h> |
44 | #include <netbt/hci.h> |
45 | #include <netbt/sco.h> |
46 | |
47 | static void hci_event_inquiry_result(struct hci_unit *, struct mbuf *); |
48 | static void hci_event_rssi_result(struct hci_unit *, struct mbuf *); |
49 | static void hci_event_extended_result(struct hci_unit *, struct mbuf *); |
50 | static void hci_event_command_status(struct hci_unit *, struct mbuf *); |
51 | static void hci_event_command_compl(struct hci_unit *, struct mbuf *); |
52 | static void hci_event_con_compl(struct hci_unit *, struct mbuf *); |
53 | static void hci_event_discon_compl(struct hci_unit *, struct mbuf *); |
54 | static void hci_event_con_req(struct hci_unit *, struct mbuf *); |
55 | static void hci_event_num_compl_pkts(struct hci_unit *, struct mbuf *); |
56 | static void hci_event_auth_compl(struct hci_unit *, struct mbuf *); |
57 | static void hci_event_encryption_change(struct hci_unit *, struct mbuf *); |
58 | static void hci_event_change_con_link_key_compl(struct hci_unit *, struct mbuf *); |
59 | static void hci_event_read_clock_offset_compl(struct hci_unit *, struct mbuf *); |
60 | static void hci_cmd_read_bdaddr(struct hci_unit *, struct mbuf *); |
61 | static void hci_cmd_read_buffer_size(struct hci_unit *, struct mbuf *); |
62 | static void hci_cmd_read_local_features(struct hci_unit *, struct mbuf *); |
63 | static void hci_cmd_read_local_extended_features(struct hci_unit *, struct mbuf *); |
64 | static void hci_cmd_read_local_ver(struct hci_unit *, struct mbuf *); |
65 | static void hci_cmd_read_local_commands(struct hci_unit *, struct mbuf *); |
66 | static void hci_cmd_reset(struct hci_unit *, struct mbuf *); |
67 | static void hci_cmd_create_con(struct hci_unit *unit, uint8_t status); |
68 | |
69 | #ifdef BLUETOOTH_DEBUG |
70 | int bluetooth_debug; |
71 | |
72 | static const char *hci_eventnames[] = { |
73 | /* 0x00 */ "NULL" , |
74 | /* 0x01 */ "INQUIRY COMPLETE" , |
75 | /* 0x02 */ "INQUIRY RESULT" , |
76 | /* 0x03 */ "CONN COMPLETE" , |
77 | /* 0x04 */ "CONN REQ" , |
78 | /* 0x05 */ "DISCONN COMPLETE" , |
79 | /* 0x06 */ "AUTH COMPLETE" , |
80 | /* 0x07 */ "REMOTE NAME REQ COMPLETE" , |
81 | /* 0x08 */ "ENCRYPTION CHANGE" , |
82 | /* 0x09 */ "CHANGE CONN LINK KEY COMPLETE" , |
83 | /* 0x0a */ "MASTER LINK KEY COMPLETE" , |
84 | /* 0x0b */ "READ REMOTE FEATURES COMPLETE" , |
85 | /* 0x0c */ "READ REMOTE VERSION INFO COMPLETE" , |
86 | /* 0x0d */ "QoS SETUP COMPLETE" , |
87 | /* 0x0e */ "COMMAND COMPLETE" , |
88 | /* 0x0f */ "COMMAND STATUS" , |
89 | /* 0x10 */ "HARDWARE ERROR" , |
90 | /* 0x11 */ "FLUSH OCCUR" , |
91 | /* 0x12 */ "ROLE CHANGE" , |
92 | /* 0x13 */ "NUM COMPLETED PACKETS" , |
93 | /* 0x14 */ "MODE CHANGE" , |
94 | /* 0x15 */ "RETURN LINK KEYS" , |
95 | /* 0x16 */ "PIN CODE REQ" , |
96 | /* 0x17 */ "LINK KEY REQ" , |
97 | /* 0x18 */ "LINK KEY NOTIFICATION" , |
98 | /* 0x19 */ "LOOPBACK COMMAND" , |
99 | /* 0x1a */ "DATA BUFFER OVERFLOW" , |
100 | /* 0x1b */ "MAX SLOT CHANGE" , |
101 | /* 0x1c */ "READ CLOCK OFFSET COMPLETE" , |
102 | /* 0x1d */ "CONN PKT TYPE CHANGED" , |
103 | /* 0x1e */ "QOS VIOLATION" , |
104 | /* 0x1f */ "PAGE SCAN MODE CHANGE" , |
105 | /* 0x20 */ "PAGE SCAN REP MODE CHANGE" , |
106 | /* 0x21 */ "FLOW SPECIFICATION COMPLETE" , |
107 | /* 0x22 */ "RSSI RESULT" , |
108 | /* 0x23 */ "READ REMOTE EXT FEATURES" , |
109 | /* 0x24 */ "UNKNOWN" , |
110 | /* 0x25 */ "UNKNOWN" , |
111 | /* 0x26 */ "UNKNOWN" , |
112 | /* 0x27 */ "UNKNOWN" , |
113 | /* 0x28 */ "UNKNOWN" , |
114 | /* 0x29 */ "UNKNOWN" , |
115 | /* 0x2a */ "UNKNOWN" , |
116 | /* 0x2b */ "UNKNOWN" , |
117 | /* 0x2c */ "SCO CON COMPLETE" , |
118 | /* 0x2d */ "SCO CON CHANGED" , |
119 | /* 0x2e */ "SNIFF SUBRATING" , |
120 | /* 0x2f */ "EXTENDED INQUIRY RESULT" , |
121 | /* 0x30 */ "ENCRYPTION KEY REFRESH" , |
122 | /* 0x31 */ "IO CAPABILITY REQUEST" , |
123 | /* 0x32 */ "IO CAPABILITY RESPONSE" , |
124 | /* 0x33 */ "USER CONFIRM REQUEST" , |
125 | /* 0x34 */ "USER PASSKEY REQUEST" , |
126 | /* 0x35 */ "REMOTE OOB DATA REQUEST" , |
127 | /* 0x36 */ "SIMPLE PAIRING COMPLETE" , |
128 | /* 0x37 */ "UNKNOWN" , |
129 | /* 0x38 */ "LINK SUPERVISION TIMEOUT CHANGED" , |
130 | /* 0x39 */ "ENHANCED FLUSH COMPLETE" , |
131 | /* 0x3a */ "UNKNOWN" , |
132 | /* 0x3b */ "USER PASSKEY NOTIFICATION" , |
133 | /* 0x3c */ "KEYPRESS NOTIFICATION" , |
134 | /* 0x3d */ "REMOTE HOST FEATURES NOTIFICATION" , |
135 | }; |
136 | |
137 | static const char * |
138 | hci_eventstr(unsigned int event) |
139 | { |
140 | |
141 | if (event < __arraycount(hci_eventnames)) |
142 | return hci_eventnames[event]; |
143 | |
144 | switch (event) { |
145 | case HCI_EVENT_BT_LOGO: /* 0xfe */ |
146 | return "BT_LOGO" ; |
147 | |
148 | case HCI_EVENT_VENDOR: /* 0xff */ |
149 | return "VENDOR" ; |
150 | } |
151 | |
152 | return "UNKNOWN" ; |
153 | } |
154 | #endif /* BLUETOOTH_DEBUG */ |
155 | |
156 | /* |
157 | * process HCI Events |
158 | * |
159 | * We will free the mbuf at the end, no need for any sub |
160 | * functions to handle that. |
161 | */ |
162 | void |
163 | hci_event(struct mbuf *m, struct hci_unit *unit) |
164 | { |
165 | hci_event_hdr_t hdr; |
166 | |
167 | KASSERT(m->m_flags & M_PKTHDR); |
168 | |
169 | if (m->m_pkthdr.len < sizeof(hdr)) |
170 | goto done; |
171 | |
172 | m_copydata(m, 0, sizeof(hdr), &hdr); |
173 | m_adj(m, sizeof(hdr)); |
174 | |
175 | KASSERT(hdr.type == HCI_EVENT_PKT); |
176 | if (m->m_pkthdr.len != hdr.length) |
177 | goto done; |
178 | |
179 | DPRINTFN(1, "(%s) event %s\n" , |
180 | device_xname(unit->hci_dev), hci_eventstr(hdr.event)); |
181 | |
182 | switch(hdr.event) { |
183 | case HCI_EVENT_COMMAND_STATUS: |
184 | hci_event_command_status(unit, m); |
185 | break; |
186 | |
187 | case HCI_EVENT_COMMAND_COMPL: |
188 | hci_event_command_compl(unit, m); |
189 | break; |
190 | |
191 | case HCI_EVENT_NUM_COMPL_PKTS: |
192 | hci_event_num_compl_pkts(unit, m); |
193 | break; |
194 | |
195 | case HCI_EVENT_INQUIRY_RESULT: |
196 | hci_event_inquiry_result(unit, m); |
197 | break; |
198 | |
199 | case HCI_EVENT_RSSI_RESULT: |
200 | hci_event_rssi_result(unit, m); |
201 | break; |
202 | |
203 | case HCI_EVENT_EXTENDED_RESULT: |
204 | hci_event_extended_result(unit, m); |
205 | break; |
206 | |
207 | case HCI_EVENT_CON_COMPL: |
208 | hci_event_con_compl(unit, m); |
209 | break; |
210 | |
211 | case HCI_EVENT_DISCON_COMPL: |
212 | hci_event_discon_compl(unit, m); |
213 | break; |
214 | |
215 | case HCI_EVENT_CON_REQ: |
216 | hci_event_con_req(unit, m); |
217 | break; |
218 | |
219 | case HCI_EVENT_AUTH_COMPL: |
220 | hci_event_auth_compl(unit, m); |
221 | break; |
222 | |
223 | case HCI_EVENT_ENCRYPTION_CHANGE: |
224 | hci_event_encryption_change(unit, m); |
225 | break; |
226 | |
227 | case HCI_EVENT_CHANGE_CON_LINK_KEY_COMPL: |
228 | hci_event_change_con_link_key_compl(unit, m); |
229 | break; |
230 | |
231 | case HCI_EVENT_READ_CLOCK_OFFSET_COMPL: |
232 | hci_event_read_clock_offset_compl(unit, m); |
233 | break; |
234 | |
235 | default: |
236 | break; |
237 | } |
238 | |
239 | done: |
240 | m_freem(m); |
241 | } |
242 | |
243 | /* |
244 | * Command Status |
245 | * |
246 | * Restart command queue and post-process any pending commands |
247 | */ |
248 | static void |
249 | hci_event_command_status(struct hci_unit *unit, struct mbuf *m) |
250 | { |
251 | hci_command_status_ep ep; |
252 | |
253 | if (m->m_pkthdr.len < sizeof(ep)) |
254 | return; |
255 | |
256 | m_copydata(m, 0, sizeof(ep), &ep); |
257 | m_adj(m, sizeof(ep)); |
258 | |
259 | ep.opcode = le16toh(ep.opcode); |
260 | |
261 | DPRINTFN(1, "(%s) opcode (%03x|%04x) status = 0x%x num_cmd_pkts = %d\n" , |
262 | device_xname(unit->hci_dev), |
263 | HCI_OGF(ep.opcode), HCI_OCF(ep.opcode), |
264 | ep.status, |
265 | ep.num_cmd_pkts); |
266 | |
267 | hci_num_cmds(unit, ep.num_cmd_pkts); |
268 | |
269 | /* |
270 | * post processing of pending commands |
271 | */ |
272 | switch(ep.opcode) { |
273 | case HCI_CMD_CREATE_CON: |
274 | hci_cmd_create_con(unit, ep.status); |
275 | break; |
276 | |
277 | default: |
278 | if (ep.status == 0) |
279 | break; |
280 | |
281 | aprint_error_dev(unit->hci_dev, |
282 | "CommandStatus opcode (%03x|%04x) failed (status=0x%02x)\n" , |
283 | HCI_OGF(ep.opcode), HCI_OCF(ep.opcode), |
284 | ep.status); |
285 | |
286 | break; |
287 | } |
288 | } |
289 | |
290 | /* |
291 | * Command Complete |
292 | * |
293 | * Restart command queue and handle the completed command |
294 | */ |
295 | static void |
296 | hci_event_command_compl(struct hci_unit *unit, struct mbuf *m) |
297 | { |
298 | hci_command_compl_ep ep; |
299 | hci_status_rp rp; |
300 | |
301 | if (m->m_pkthdr.len < sizeof(ep)) |
302 | return; |
303 | |
304 | m_copydata(m, 0, sizeof(ep), &ep); |
305 | m_adj(m, sizeof(ep)); |
306 | |
307 | DPRINTFN(1, "(%s) opcode (%03x|%04x) num_cmd_pkts = %d\n" , |
308 | device_xname(unit->hci_dev), |
309 | HCI_OGF(le16toh(ep.opcode)), HCI_OCF(le16toh(ep.opcode)), |
310 | ep.num_cmd_pkts); |
311 | |
312 | hci_num_cmds(unit, ep.num_cmd_pkts); |
313 | |
314 | /* |
315 | * I am not sure if this is completely correct, it is not guaranteed |
316 | * that a command_complete packet will contain the status though most |
317 | * do seem to. |
318 | */ |
319 | m_copydata(m, 0, sizeof(rp), &rp); |
320 | if (rp.status > 0) |
321 | aprint_error_dev(unit->hci_dev, |
322 | "CommandComplete opcode (%03x|%04x) failed (status=0x%02x)\n" , |
323 | HCI_OGF(le16toh(ep.opcode)), HCI_OCF(le16toh(ep.opcode)), |
324 | rp.status); |
325 | |
326 | /* |
327 | * post processing of completed commands |
328 | */ |
329 | switch(le16toh(ep.opcode)) { |
330 | case HCI_CMD_READ_BDADDR: |
331 | hci_cmd_read_bdaddr(unit, m); |
332 | break; |
333 | |
334 | case HCI_CMD_READ_BUFFER_SIZE: |
335 | hci_cmd_read_buffer_size(unit, m); |
336 | break; |
337 | |
338 | case HCI_CMD_READ_LOCAL_FEATURES: |
339 | hci_cmd_read_local_features(unit, m); |
340 | break; |
341 | |
342 | case HCI_CMD_READ_LOCAL_EXTENDED_FEATURES: |
343 | hci_cmd_read_local_extended_features(unit, m); |
344 | break; |
345 | |
346 | case HCI_CMD_READ_LOCAL_VER: |
347 | hci_cmd_read_local_ver(unit, m); |
348 | break; |
349 | |
350 | case HCI_CMD_READ_LOCAL_COMMANDS: |
351 | hci_cmd_read_local_commands(unit, m); |
352 | break; |
353 | |
354 | case HCI_CMD_RESET: |
355 | hci_cmd_reset(unit, m); |
356 | break; |
357 | |
358 | default: |
359 | break; |
360 | } |
361 | } |
362 | |
363 | /* |
364 | * Number of Completed Packets |
365 | * |
366 | * This is sent periodically by the Controller telling us how many |
367 | * buffers are now freed up and which handle was using them. From |
368 | * this we determine which type of buffer it was and add the qty |
369 | * back into the relevant packet counter, then restart output on |
370 | * links that have halted. |
371 | */ |
372 | static void |
373 | hci_event_num_compl_pkts(struct hci_unit *unit, struct mbuf *m) |
374 | { |
375 | hci_num_compl_pkts_ep ep; |
376 | struct hci_link *link, *next; |
377 | uint16_t handle, num; |
378 | int num_acl = 0, num_sco = 0; |
379 | |
380 | if (m->m_pkthdr.len < sizeof(ep)) |
381 | return; |
382 | |
383 | m_copydata(m, 0, sizeof(ep), &ep); |
384 | m_adj(m, sizeof(ep)); |
385 | |
386 | while (ep.num_con_handles--) { |
387 | m_copydata(m, 0, sizeof(handle), &handle); |
388 | m_adj(m, sizeof(handle)); |
389 | handle = le16toh(handle); |
390 | |
391 | m_copydata(m, 0, sizeof(num), &num); |
392 | m_adj(m, sizeof(num)); |
393 | num = le16toh(num); |
394 | |
395 | link = hci_link_lookup_handle(unit, handle); |
396 | if (link) { |
397 | if (link->hl_type == HCI_LINK_ACL) { |
398 | num_acl += num; |
399 | hci_acl_complete(link, num); |
400 | } else { |
401 | num_sco += num; |
402 | hci_sco_complete(link, num); |
403 | } |
404 | } else { |
405 | /* XXX need to issue Read_Buffer_Size or Reset? */ |
406 | aprint_error_dev(unit->hci_dev, |
407 | "unknown handle %d! (losing track of %d packet buffer%s)\n" , |
408 | handle, num, (num == 1 ? "" : "s" )); |
409 | } |
410 | } |
411 | |
412 | /* |
413 | * Move up any queued packets. When a link has sent data, it will move |
414 | * to the back of the queue - technically then if a link had something |
415 | * to send and there were still buffers available it could get started |
416 | * twice but it seemed more important to to handle higher loads fairly |
417 | * than worry about wasting cycles when we are not busy. |
418 | */ |
419 | |
420 | unit->hci_num_acl_pkts += num_acl; |
421 | unit->hci_num_sco_pkts += num_sco; |
422 | |
423 | link = TAILQ_FIRST(&unit->hci_links); |
424 | while (link && (unit->hci_num_acl_pkts > 0 || unit->hci_num_sco_pkts > 0)) { |
425 | next = TAILQ_NEXT(link, hl_next); |
426 | |
427 | if (link->hl_type == HCI_LINK_ACL) { |
428 | if (unit->hci_num_acl_pkts > 0 && link->hl_txqlen > 0) |
429 | hci_acl_start(link); |
430 | } else { |
431 | if (unit->hci_num_sco_pkts > 0 && link->hl_txqlen > 0) |
432 | hci_sco_start(link); |
433 | } |
434 | |
435 | link = next; |
436 | } |
437 | } |
438 | |
439 | /* |
440 | * Inquiry Result |
441 | * |
442 | * keep a note of devices seen, so we know which unit to use |
443 | * on outgoing connections |
444 | */ |
445 | static void |
446 | hci_event_inquiry_result(struct hci_unit *unit, struct mbuf *m) |
447 | { |
448 | hci_inquiry_result_ep ep; |
449 | hci_inquiry_response ir; |
450 | struct hci_memo *memo; |
451 | |
452 | if (m->m_pkthdr.len < sizeof(ep)) |
453 | return; |
454 | |
455 | m_copydata(m, 0, sizeof(ep), &ep); |
456 | m_adj(m, sizeof(ep)); |
457 | |
458 | DPRINTFN(1, "%d response%s\n" , ep.num_responses, |
459 | (ep.num_responses == 1 ? "" : "s" )); |
460 | |
461 | while(ep.num_responses--) { |
462 | if (m->m_pkthdr.len < sizeof(ir)) |
463 | return; |
464 | |
465 | m_copydata(m, 0, sizeof(ir), &ir); |
466 | m_adj(m, sizeof(ir)); |
467 | |
468 | DPRINTFN(1, "bdaddr %02x:%02x:%02x:%02x:%02x:%02x\n" , |
469 | ir.bdaddr.b[5], ir.bdaddr.b[4], ir.bdaddr.b[3], |
470 | ir.bdaddr.b[2], ir.bdaddr.b[1], ir.bdaddr.b[0]); |
471 | |
472 | memo = hci_memo_new(unit, &ir.bdaddr); |
473 | if (memo != NULL) { |
474 | memo->page_scan_rep_mode = ir.page_scan_rep_mode; |
475 | memo->page_scan_mode = ir.page_scan_mode; |
476 | memo->clock_offset = ir.clock_offset; |
477 | } |
478 | } |
479 | } |
480 | |
481 | /* |
482 | * Inquiry Result with RSSI |
483 | * |
484 | * as above but different packet when RSSI result is enabled |
485 | */ |
486 | static void |
487 | (struct hci_unit *unit, struct mbuf *m) |
488 | { |
489 | hci_rssi_result_ep ep; |
490 | hci_rssi_response rr; |
491 | struct hci_memo *memo; |
492 | |
493 | if (m->m_pkthdr.len < sizeof(ep)) |
494 | return; |
495 | |
496 | m_copydata(m, 0, sizeof(ep), &ep); |
497 | m_adj(m, sizeof(ep)); |
498 | |
499 | DPRINTFN(1, "%d response%s\n" , ep.num_responses, |
500 | (ep.num_responses == 1 ? "" : "s" )); |
501 | |
502 | while(ep.num_responses--) { |
503 | if (m->m_pkthdr.len < sizeof(rr)) |
504 | return; |
505 | |
506 | m_copydata(m, 0, sizeof(rr), &rr); |
507 | m_adj(m, sizeof(rr)); |
508 | |
509 | DPRINTFN(1, "bdaddr %02x:%02x:%02x:%02x:%02x:%02x\n" , |
510 | rr.bdaddr.b[5], rr.bdaddr.b[4], rr.bdaddr.b[3], |
511 | rr.bdaddr.b[2], rr.bdaddr.b[1], rr.bdaddr.b[0]); |
512 | |
513 | memo = hci_memo_new(unit, &rr.bdaddr); |
514 | if (memo != NULL) { |
515 | memo->page_scan_rep_mode = rr.page_scan_rep_mode; |
516 | memo->page_scan_mode = 0; |
517 | memo->clock_offset = rr.clock_offset; |
518 | } |
519 | } |
520 | } |
521 | |
522 | /* |
523 | * Extended Inquiry Result |
524 | * |
525 | * as above but provides only one response and extended service info |
526 | */ |
527 | static void |
528 | hci_event_extended_result(struct hci_unit *unit, struct mbuf *m) |
529 | { |
530 | hci_extended_result_ep ep; |
531 | struct hci_memo *memo; |
532 | |
533 | if (m->m_pkthdr.len < sizeof(ep)) |
534 | return; |
535 | |
536 | m_copydata(m, 0, sizeof(ep), &ep); |
537 | m_adj(m, sizeof(ep)); |
538 | |
539 | if (ep.num_responses != 1) |
540 | return; |
541 | |
542 | DPRINTFN(1, "bdaddr %02x:%02x:%02x:%02x:%02x:%02x\n" , |
543 | ep.bdaddr.b[5], ep.bdaddr.b[4], ep.bdaddr.b[3], |
544 | ep.bdaddr.b[2], ep.bdaddr.b[1], ep.bdaddr.b[0]); |
545 | |
546 | memo = hci_memo_new(unit, &ep.bdaddr); |
547 | if (memo != NULL) { |
548 | memo->page_scan_rep_mode = ep.page_scan_rep_mode; |
549 | memo->page_scan_mode = 0; |
550 | memo->clock_offset = ep.clock_offset; |
551 | } |
552 | } |
553 | |
554 | /* |
555 | * Connection Complete |
556 | * |
557 | * Sent to us when a connection is made. If there is no link |
558 | * structure already allocated for this, we must have changed |
559 | * our mind, so just disconnect. |
560 | */ |
561 | static void |
562 | hci_event_con_compl(struct hci_unit *unit, struct mbuf *m) |
563 | { |
564 | hci_con_compl_ep ep; |
565 | hci_write_link_policy_settings_cp cp; |
566 | struct hci_link *link; |
567 | int err; |
568 | |
569 | if (m->m_pkthdr.len < sizeof(ep)) |
570 | return; |
571 | |
572 | m_copydata(m, 0, sizeof(ep), &ep); |
573 | m_adj(m, sizeof(ep)); |
574 | |
575 | DPRINTFN(1, "(%s) %s connection complete for " |
576 | "%02x:%02x:%02x:%02x:%02x:%02x status %#x\n" , |
577 | device_xname(unit->hci_dev), |
578 | (ep.link_type == HCI_LINK_ACL ? "ACL" : "SCO" ), |
579 | ep.bdaddr.b[5], ep.bdaddr.b[4], ep.bdaddr.b[3], |
580 | ep.bdaddr.b[2], ep.bdaddr.b[1], ep.bdaddr.b[0], |
581 | ep.status); |
582 | |
583 | link = hci_link_lookup_bdaddr(unit, &ep.bdaddr, ep.link_type); |
584 | |
585 | if (ep.status) { |
586 | if (link != NULL) { |
587 | switch (ep.status) { |
588 | case 0x04: /* "Page Timeout" */ |
589 | err = EHOSTDOWN; |
590 | break; |
591 | |
592 | case 0x08: /* "Connection Timed Out" */ |
593 | err = ETIMEDOUT; |
594 | break; |
595 | |
596 | case 0x16: /* "Connection Terminated by Local Host" */ |
597 | err = 0; |
598 | break; |
599 | |
600 | default: |
601 | err = ECONNREFUSED; |
602 | break; |
603 | } |
604 | |
605 | hci_link_free(link, err); |
606 | } |
607 | |
608 | return; |
609 | } |
610 | |
611 | if (link == NULL) { |
612 | hci_discon_cp dp; |
613 | |
614 | dp.con_handle = ep.con_handle; |
615 | dp.reason = 0x13; /* "Remote User Terminated Connection" */ |
616 | |
617 | hci_send_cmd(unit, HCI_CMD_DISCONNECT, &dp, sizeof(dp)); |
618 | return; |
619 | } |
620 | |
621 | /* XXX could check auth_enable here */ |
622 | |
623 | if (ep.encryption_mode) |
624 | link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_ENCRYPT); |
625 | |
626 | link->hl_state = HCI_LINK_OPEN; |
627 | link->hl_handle = HCI_CON_HANDLE(le16toh(ep.con_handle)); |
628 | |
629 | if (ep.link_type == HCI_LINK_ACL) { |
630 | cp.con_handle = ep.con_handle; |
631 | cp.settings = htole16(unit->hci_link_policy); |
632 | err = hci_send_cmd(unit, HCI_CMD_WRITE_LINK_POLICY_SETTINGS, |
633 | &cp, sizeof(cp)); |
634 | if (err) |
635 | aprint_error_dev(unit->hci_dev, |
636 | "Warning, could not write link policy\n" ); |
637 | |
638 | err = hci_send_cmd(unit, HCI_CMD_READ_CLOCK_OFFSET, |
639 | &cp.con_handle, sizeof(cp.con_handle)); |
640 | if (err) |
641 | aprint_error_dev(unit->hci_dev, |
642 | "Warning, could not read clock offset\n" ); |
643 | |
644 | err = hci_acl_setmode(link); |
645 | if (err == EINPROGRESS) |
646 | return; |
647 | |
648 | hci_acl_linkmode(link); |
649 | } else { |
650 | (*link->hl_sco->sp_proto->connected)(link->hl_sco->sp_upper); |
651 | } |
652 | } |
653 | |
654 | /* |
655 | * Disconnection Complete |
656 | * |
657 | * This is sent in response to a disconnection request, but also if |
658 | * the remote device goes out of range. |
659 | */ |
660 | static void |
661 | hci_event_discon_compl(struct hci_unit *unit, struct mbuf *m) |
662 | { |
663 | hci_discon_compl_ep ep; |
664 | struct hci_link *link; |
665 | |
666 | if (m->m_pkthdr.len < sizeof(ep)) |
667 | return; |
668 | |
669 | m_copydata(m, 0, sizeof(ep), &ep); |
670 | m_adj(m, sizeof(ep)); |
671 | |
672 | ep.con_handle = le16toh(ep.con_handle); |
673 | |
674 | DPRINTFN(1, "handle #%d, status=0x%x\n" , ep.con_handle, ep.status); |
675 | |
676 | link = hci_link_lookup_handle(unit, HCI_CON_HANDLE(ep.con_handle)); |
677 | if (link) |
678 | hci_link_free(link, ENOLINK); |
679 | } |
680 | |
681 | /* |
682 | * Connect Request |
683 | * |
684 | * We check upstream for appropriate listeners and accept connections |
685 | * that are wanted. |
686 | */ |
687 | static void |
688 | hci_event_con_req(struct hci_unit *unit, struct mbuf *m) |
689 | { |
690 | hci_con_req_ep ep; |
691 | hci_accept_con_cp ap; |
692 | hci_reject_con_cp rp; |
693 | struct hci_link *link; |
694 | |
695 | if (m->m_pkthdr.len < sizeof(ep)) |
696 | return; |
697 | |
698 | m_copydata(m, 0, sizeof(ep), &ep); |
699 | m_adj(m, sizeof(ep)); |
700 | |
701 | DPRINTFN(1, "bdaddr %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " |
702 | "class %2.2x%2.2x%2.2x type %s\n" , |
703 | ep.bdaddr.b[5], ep.bdaddr.b[4], ep.bdaddr.b[3], |
704 | ep.bdaddr.b[2], ep.bdaddr.b[1], ep.bdaddr.b[0], |
705 | ep.uclass[0], ep.uclass[1], ep.uclass[2], |
706 | ep.link_type == HCI_LINK_ACL ? "ACL" : "SCO" ); |
707 | |
708 | if (ep.link_type == HCI_LINK_ACL) |
709 | link = hci_acl_newconn(unit, &ep.bdaddr); |
710 | else |
711 | link = hci_sco_newconn(unit, &ep.bdaddr); |
712 | |
713 | if (link == NULL) { |
714 | memset(&rp, 0, sizeof(rp)); |
715 | bdaddr_copy(&rp.bdaddr, &ep.bdaddr); |
716 | rp.reason = 0x0f; /* Unacceptable BD_ADDR */ |
717 | |
718 | hci_send_cmd(unit, HCI_CMD_REJECT_CON, &rp, sizeof(rp)); |
719 | } else { |
720 | memset(&ap, 0, sizeof(ap)); |
721 | bdaddr_copy(&ap.bdaddr, &ep.bdaddr); |
722 | if (unit->hci_flags & BTF_MASTER) |
723 | ap.role = HCI_ROLE_MASTER; |
724 | else |
725 | ap.role = HCI_ROLE_SLAVE; |
726 | |
727 | hci_send_cmd(unit, HCI_CMD_ACCEPT_CON, &ap, sizeof(ap)); |
728 | } |
729 | } |
730 | |
731 | /* |
732 | * Auth Complete |
733 | * |
734 | * Authentication has been completed on an ACL link. We can notify the |
735 | * upper layer protocols unless further mode changes are pending. |
736 | */ |
737 | static void |
738 | hci_event_auth_compl(struct hci_unit *unit, struct mbuf *m) |
739 | { |
740 | hci_auth_compl_ep ep; |
741 | struct hci_link *link; |
742 | int err; |
743 | |
744 | if (m->m_pkthdr.len < sizeof(ep)) |
745 | return; |
746 | |
747 | m_copydata(m, 0, sizeof(ep), &ep); |
748 | m_adj(m, sizeof(ep)); |
749 | |
750 | ep.con_handle = HCI_CON_HANDLE(le16toh(ep.con_handle)); |
751 | |
752 | DPRINTFN(1, "handle #%d, status=0x%x\n" , ep.con_handle, ep.status); |
753 | |
754 | link = hci_link_lookup_handle(unit, ep.con_handle); |
755 | if (link == NULL || link->hl_type != HCI_LINK_ACL) |
756 | return; |
757 | |
758 | if (ep.status == 0) { |
759 | link->hl_flags |= HCI_LINK_AUTH; |
760 | |
761 | if (link->hl_state == HCI_LINK_WAIT_AUTH) |
762 | link->hl_state = HCI_LINK_OPEN; |
763 | |
764 | err = hci_acl_setmode(link); |
765 | if (err == EINPROGRESS) |
766 | return; |
767 | } |
768 | |
769 | hci_acl_linkmode(link); |
770 | } |
771 | |
772 | /* |
773 | * Encryption Change |
774 | * |
775 | * The encryption status has changed. Basically, we note the change |
776 | * then notify the upper layer protocol unless further mode changes |
777 | * are pending. |
778 | * Note that if encryption gets disabled when it has been requested, |
779 | * we will attempt to enable it again.. (its a feature not a bug :) |
780 | */ |
781 | static void |
782 | hci_event_encryption_change(struct hci_unit *unit, struct mbuf *m) |
783 | { |
784 | hci_encryption_change_ep ep; |
785 | struct hci_link *link; |
786 | int err; |
787 | |
788 | if (m->m_pkthdr.len < sizeof(ep)) |
789 | return; |
790 | |
791 | m_copydata(m, 0, sizeof(ep), &ep); |
792 | m_adj(m, sizeof(ep)); |
793 | |
794 | ep.con_handle = HCI_CON_HANDLE(le16toh(ep.con_handle)); |
795 | |
796 | DPRINTFN(1, "handle #%d, status=0x%x, encryption_enable=0x%x\n" , |
797 | ep.con_handle, ep.status, ep.encryption_enable); |
798 | |
799 | link = hci_link_lookup_handle(unit, ep.con_handle); |
800 | if (link == NULL || link->hl_type != HCI_LINK_ACL) |
801 | return; |
802 | |
803 | if (ep.status == 0) { |
804 | if (ep.encryption_enable == 0) |
805 | link->hl_flags &= ~HCI_LINK_ENCRYPT; |
806 | else |
807 | link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_ENCRYPT); |
808 | |
809 | if (link->hl_state == HCI_LINK_WAIT_ENCRYPT) |
810 | link->hl_state = HCI_LINK_OPEN; |
811 | |
812 | err = hci_acl_setmode(link); |
813 | if (err == EINPROGRESS) |
814 | return; |
815 | } |
816 | |
817 | hci_acl_linkmode(link); |
818 | } |
819 | |
820 | /* |
821 | * Change Connection Link Key Complete |
822 | * |
823 | * Link keys are handled in userland but if we are waiting to secure |
824 | * this link, we should notify the upper protocols. A SECURE request |
825 | * only needs a single key change, so we can cancel the request. |
826 | */ |
827 | static void |
828 | hci_event_change_con_link_key_compl(struct hci_unit *unit, struct mbuf *m) |
829 | { |
830 | hci_change_con_link_key_compl_ep ep; |
831 | struct hci_link *link; |
832 | int err; |
833 | |
834 | if (m->m_pkthdr.len < sizeof(ep)) |
835 | return; |
836 | |
837 | m_copydata(m, 0, sizeof(ep), &ep); |
838 | m_adj(m, sizeof(ep)); |
839 | |
840 | ep.con_handle = HCI_CON_HANDLE(le16toh(ep.con_handle)); |
841 | |
842 | DPRINTFN(1, "handle #%d, status=0x%x\n" , ep.con_handle, ep.status); |
843 | |
844 | link = hci_link_lookup_handle(unit, ep.con_handle); |
845 | if (link == NULL || link->hl_type != HCI_LINK_ACL) |
846 | return; |
847 | |
848 | link->hl_flags &= ~HCI_LINK_SECURE_REQ; |
849 | |
850 | if (ep.status == 0) { |
851 | link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_SECURE); |
852 | |
853 | if (link->hl_state == HCI_LINK_WAIT_SECURE) |
854 | link->hl_state = HCI_LINK_OPEN; |
855 | |
856 | err = hci_acl_setmode(link); |
857 | if (err == EINPROGRESS) |
858 | return; |
859 | } |
860 | |
861 | hci_acl_linkmode(link); |
862 | } |
863 | |
864 | /* |
865 | * Read Clock Offset Complete |
866 | * |
867 | * We keep a note of the clock offset of remote devices when a |
868 | * link is made, in order to facilitate reconnections to the device |
869 | */ |
870 | static void |
871 | hci_event_read_clock_offset_compl(struct hci_unit *unit, struct mbuf *m) |
872 | { |
873 | hci_read_clock_offset_compl_ep ep; |
874 | struct hci_link *link; |
875 | |
876 | if (m->m_pkthdr.len < sizeof(ep)) |
877 | return; |
878 | |
879 | m_copydata(m, 0, sizeof(ep), &ep); |
880 | m_adj(m, sizeof(ep)); |
881 | |
882 | DPRINTFN(1, "handle #%d, offset=%u, status=0x%x\n" , |
883 | le16toh(ep.con_handle), le16toh(ep.clock_offset), ep.status); |
884 | |
885 | ep.con_handle = HCI_CON_HANDLE(le16toh(ep.con_handle)); |
886 | link = hci_link_lookup_handle(unit, ep.con_handle); |
887 | if (link == NULL || link->hl_type != HCI_LINK_ACL) |
888 | return; |
889 | |
890 | if (ep.status == 0) |
891 | link->hl_clock = ep.clock_offset; |
892 | } |
893 | |
894 | /* |
895 | * process results of read_bdaddr command_complete event |
896 | */ |
897 | static void |
898 | hci_cmd_read_bdaddr(struct hci_unit *unit, struct mbuf *m) |
899 | { |
900 | hci_read_bdaddr_rp rp; |
901 | |
902 | if (m->m_pkthdr.len < sizeof(rp)) |
903 | return; |
904 | |
905 | m_copydata(m, 0, sizeof(rp), &rp); |
906 | m_adj(m, sizeof(rp)); |
907 | |
908 | if (rp.status > 0) |
909 | return; |
910 | |
911 | if ((unit->hci_flags & BTF_INIT_BDADDR) == 0) |
912 | return; |
913 | |
914 | bdaddr_copy(&unit->hci_bdaddr, &rp.bdaddr); |
915 | |
916 | unit->hci_flags &= ~BTF_INIT_BDADDR; |
917 | |
918 | cv_broadcast(&unit->hci_init); |
919 | } |
920 | |
921 | /* |
922 | * process results of read_buffer_size command_complete event |
923 | */ |
924 | static void |
925 | hci_cmd_read_buffer_size(struct hci_unit *unit, struct mbuf *m) |
926 | { |
927 | hci_read_buffer_size_rp rp; |
928 | |
929 | if (m->m_pkthdr.len < sizeof(rp)) |
930 | return; |
931 | |
932 | m_copydata(m, 0, sizeof(rp), &rp); |
933 | m_adj(m, sizeof(rp)); |
934 | |
935 | if (rp.status > 0) |
936 | return; |
937 | |
938 | if ((unit->hci_flags & BTF_INIT_BUFFER_SIZE) == 0) |
939 | return; |
940 | |
941 | unit->hci_max_acl_size = le16toh(rp.max_acl_size); |
942 | unit->hci_num_acl_pkts = le16toh(rp.num_acl_pkts); |
943 | unit->hci_max_acl_pkts = le16toh(rp.num_acl_pkts); |
944 | unit->hci_max_sco_size = rp.max_sco_size; |
945 | unit->hci_num_sco_pkts = le16toh(rp.num_sco_pkts); |
946 | unit->hci_max_sco_pkts = le16toh(rp.num_sco_pkts); |
947 | |
948 | unit->hci_flags &= ~BTF_INIT_BUFFER_SIZE; |
949 | |
950 | cv_broadcast(&unit->hci_init); |
951 | } |
952 | |
953 | /* |
954 | * process results of read_local_features command_complete event |
955 | */ |
956 | static void |
957 | hci_cmd_read_local_features(struct hci_unit *unit, struct mbuf *m) |
958 | { |
959 | hci_read_local_features_rp rp; |
960 | |
961 | if (m->m_pkthdr.len < sizeof(rp)) |
962 | return; |
963 | |
964 | m_copydata(m, 0, sizeof(rp), &rp); |
965 | m_adj(m, sizeof(rp)); |
966 | |
967 | if (rp.status > 0) |
968 | return; |
969 | |
970 | if ((unit->hci_flags & BTF_INIT_FEATURES) == 0) |
971 | return; |
972 | |
973 | memcpy(unit->hci_feat0, rp.features, HCI_FEATURES_SIZE); |
974 | |
975 | unit->hci_lmp_mask = 0; |
976 | |
977 | if (rp.features[0] & HCI_LMP_ROLE_SWITCH) |
978 | unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_ROLE_SWITCH; |
979 | |
980 | if (rp.features[0] & HCI_LMP_HOLD_MODE) |
981 | unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_HOLD_MODE; |
982 | |
983 | if (rp.features[0] & HCI_LMP_SNIFF_MODE) |
984 | unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_SNIFF_MODE; |
985 | |
986 | if (rp.features[1] & HCI_LMP_PARK_MODE) |
987 | unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_PARK_MODE; |
988 | |
989 | DPRINTFN(1, "%s: lmp_mask %4.4x\n" , |
990 | device_xname(unit->hci_dev), unit->hci_lmp_mask); |
991 | |
992 | /* ACL packet mask */ |
993 | unit->hci_acl_mask = HCI_PKT_DM1 | HCI_PKT_DH1; |
994 | |
995 | if (rp.features[0] & HCI_LMP_3SLOT) |
996 | unit->hci_acl_mask |= HCI_PKT_DM3 | HCI_PKT_DH3; |
997 | |
998 | if (rp.features[0] & HCI_LMP_5SLOT) |
999 | unit->hci_acl_mask |= HCI_PKT_DM5 | HCI_PKT_DH5; |
1000 | |
1001 | if ((rp.features[3] & HCI_LMP_EDR_ACL_2MBPS) == 0) |
1002 | unit->hci_acl_mask |= HCI_PKT_2MBPS_DH1 |
1003 | | HCI_PKT_2MBPS_DH3 |
1004 | | HCI_PKT_2MBPS_DH5; |
1005 | |
1006 | if ((rp.features[3] & HCI_LMP_EDR_ACL_3MBPS) == 0) |
1007 | unit->hci_acl_mask |= HCI_PKT_3MBPS_DH1 |
1008 | | HCI_PKT_3MBPS_DH3 |
1009 | | HCI_PKT_3MBPS_DH5; |
1010 | |
1011 | if ((rp.features[4] & HCI_LMP_3SLOT_EDR_ACL) == 0) |
1012 | unit->hci_acl_mask |= HCI_PKT_2MBPS_DH3 |
1013 | | HCI_PKT_3MBPS_DH3; |
1014 | |
1015 | if ((rp.features[5] & HCI_LMP_5SLOT_EDR_ACL) == 0) |
1016 | unit->hci_acl_mask |= HCI_PKT_2MBPS_DH5 |
1017 | | HCI_PKT_3MBPS_DH5; |
1018 | |
1019 | DPRINTFN(1, "%s: acl_mask %4.4x\n" , |
1020 | device_xname(unit->hci_dev), unit->hci_acl_mask); |
1021 | |
1022 | unit->hci_packet_type = unit->hci_acl_mask; |
1023 | |
1024 | /* SCO packet mask */ |
1025 | unit->hci_sco_mask = 0; |
1026 | if (rp.features[1] & HCI_LMP_SCO_LINK) |
1027 | unit->hci_sco_mask |= HCI_PKT_HV1; |
1028 | |
1029 | if (rp.features[1] & HCI_LMP_HV2_PKT) |
1030 | unit->hci_sco_mask |= HCI_PKT_HV2; |
1031 | |
1032 | if (rp.features[1] & HCI_LMP_HV3_PKT) |
1033 | unit->hci_sco_mask |= HCI_PKT_HV3; |
1034 | |
1035 | if (rp.features[3] & HCI_LMP_EV3_PKT) |
1036 | unit->hci_sco_mask |= HCI_PKT_EV3; |
1037 | |
1038 | if (rp.features[4] & HCI_LMP_EV4_PKT) |
1039 | unit->hci_sco_mask |= HCI_PKT_EV4; |
1040 | |
1041 | if (rp.features[4] & HCI_LMP_EV5_PKT) |
1042 | unit->hci_sco_mask |= HCI_PKT_EV5; |
1043 | |
1044 | /* XXX what do 2MBPS/3MBPS/3SLOT eSCO mean? */ |
1045 | |
1046 | DPRINTFN(1, "%s: sco_mask %4.4x\n" , |
1047 | device_xname(unit->hci_dev), unit->hci_sco_mask); |
1048 | |
1049 | /* extended feature masks */ |
1050 | if (rp.features[7] & HCI_LMP_EXTENDED_FEATURES) { |
1051 | hci_read_local_extended_features_cp cp; |
1052 | |
1053 | cp.page = 0; |
1054 | hci_send_cmd(unit, HCI_CMD_READ_LOCAL_EXTENDED_FEATURES, |
1055 | &cp, sizeof(cp)); |
1056 | |
1057 | return; |
1058 | } |
1059 | |
1060 | unit->hci_flags &= ~BTF_INIT_FEATURES; |
1061 | cv_broadcast(&unit->hci_init); |
1062 | } |
1063 | |
1064 | /* |
1065 | * process results of read_local_extended_features command_complete event |
1066 | */ |
1067 | static void |
1068 | hci_cmd_read_local_extended_features(struct hci_unit *unit, struct mbuf *m) |
1069 | { |
1070 | hci_read_local_extended_features_rp rp; |
1071 | |
1072 | if (m->m_pkthdr.len < sizeof(rp)) |
1073 | return; |
1074 | |
1075 | m_copydata(m, 0, sizeof(rp), &rp); |
1076 | m_adj(m, sizeof(rp)); |
1077 | |
1078 | if (rp.status > 0) |
1079 | return; |
1080 | |
1081 | if ((unit->hci_flags & BTF_INIT_FEATURES) == 0) |
1082 | return; |
1083 | |
1084 | DPRINTFN(1, "%s: page %d of %d\n" , device_xname(unit->hci_dev), |
1085 | rp.page, rp.max_page); |
1086 | |
1087 | switch (rp.page) { |
1088 | case 2: |
1089 | memcpy(unit->hci_feat2, rp.features, HCI_FEATURES_SIZE); |
1090 | break; |
1091 | |
1092 | case 1: |
1093 | memcpy(unit->hci_feat1, rp.features, HCI_FEATURES_SIZE); |
1094 | break; |
1095 | |
1096 | case 0: /* (already handled) */ |
1097 | default: |
1098 | break; |
1099 | } |
1100 | |
1101 | if (rp.page < rp.max_page) { |
1102 | hci_read_local_extended_features_cp cp; |
1103 | |
1104 | cp.page = rp.page + 1; |
1105 | hci_send_cmd(unit, HCI_CMD_READ_LOCAL_EXTENDED_FEATURES, |
1106 | &cp, sizeof(cp)); |
1107 | |
1108 | return; |
1109 | } |
1110 | |
1111 | unit->hci_flags &= ~BTF_INIT_FEATURES; |
1112 | cv_broadcast(&unit->hci_init); |
1113 | } |
1114 | |
1115 | /* |
1116 | * process results of read_local_ver command_complete event |
1117 | * |
1118 | * reading local supported commands is only supported from 1.2 spec |
1119 | */ |
1120 | static void |
1121 | hci_cmd_read_local_ver(struct hci_unit *unit, struct mbuf *m) |
1122 | { |
1123 | hci_read_local_ver_rp rp; |
1124 | |
1125 | if (m->m_pkthdr.len < sizeof(rp)) |
1126 | return; |
1127 | |
1128 | m_copydata(m, 0, sizeof(rp), &rp); |
1129 | m_adj(m, sizeof(rp)); |
1130 | |
1131 | if (rp.status != 0) |
1132 | return; |
1133 | |
1134 | if ((unit->hci_flags & BTF_INIT_COMMANDS) == 0) |
1135 | return; |
1136 | |
1137 | if (rp.hci_version < HCI_SPEC_V12) { |
1138 | unit->hci_flags &= ~BTF_INIT_COMMANDS; |
1139 | cv_broadcast(&unit->hci_init); |
1140 | return; |
1141 | } |
1142 | |
1143 | hci_send_cmd(unit, HCI_CMD_READ_LOCAL_COMMANDS, NULL, 0); |
1144 | } |
1145 | |
1146 | /* |
1147 | * process results of read_local_commands command_complete event |
1148 | */ |
1149 | static void |
1150 | hci_cmd_read_local_commands(struct hci_unit *unit, struct mbuf *m) |
1151 | { |
1152 | hci_read_local_commands_rp rp; |
1153 | |
1154 | if (m->m_pkthdr.len < sizeof(rp)) |
1155 | return; |
1156 | |
1157 | m_copydata(m, 0, sizeof(rp), &rp); |
1158 | m_adj(m, sizeof(rp)); |
1159 | |
1160 | if (rp.status != 0) |
1161 | return; |
1162 | |
1163 | if ((unit->hci_flags & BTF_INIT_COMMANDS) == 0) |
1164 | return; |
1165 | |
1166 | unit->hci_flags &= ~BTF_INIT_COMMANDS; |
1167 | memcpy(unit->hci_cmds, rp.commands, HCI_COMMANDS_SIZE); |
1168 | |
1169 | cv_broadcast(&unit->hci_init); |
1170 | } |
1171 | |
1172 | /* |
1173 | * process results of reset command_complete event |
1174 | * |
1175 | * This has killed all the connections, so close down anything we have left, |
1176 | * and reinitialise the unit. |
1177 | */ |
1178 | static void |
1179 | hci_cmd_reset(struct hci_unit *unit, struct mbuf *m) |
1180 | { |
1181 | hci_reset_rp rp; |
1182 | struct hci_link *link, *next; |
1183 | int acl; |
1184 | |
1185 | if (m->m_pkthdr.len < sizeof(rp)) |
1186 | return; |
1187 | |
1188 | m_copydata(m, 0, sizeof(rp), &rp); |
1189 | m_adj(m, sizeof(rp)); |
1190 | |
1191 | if (rp.status != 0) |
1192 | return; |
1193 | |
1194 | /* |
1195 | * release SCO links first, since they may be holding |
1196 | * an ACL link reference. |
1197 | */ |
1198 | for (acl = 0 ; acl < 2 ; acl++) { |
1199 | next = TAILQ_FIRST(&unit->hci_links); |
1200 | while ((link = next) != NULL) { |
1201 | next = TAILQ_NEXT(link, hl_next); |
1202 | if (acl || link->hl_type != HCI_LINK_ACL) |
1203 | hci_link_free(link, ECONNABORTED); |
1204 | } |
1205 | } |
1206 | |
1207 | unit->hci_num_acl_pkts = 0; |
1208 | unit->hci_num_sco_pkts = 0; |
1209 | |
1210 | if (hci_send_cmd(unit, HCI_CMD_READ_BDADDR, NULL, 0)) |
1211 | return; |
1212 | |
1213 | if (hci_send_cmd(unit, HCI_CMD_READ_BUFFER_SIZE, NULL, 0)) |
1214 | return; |
1215 | |
1216 | if (hci_send_cmd(unit, HCI_CMD_READ_LOCAL_FEATURES, NULL, 0)) |
1217 | return; |
1218 | |
1219 | if (hci_send_cmd(unit, HCI_CMD_READ_LOCAL_VER, NULL, 0)) |
1220 | return; |
1221 | } |
1222 | |
1223 | /* |
1224 | * process command_status event for create_con command |
1225 | * |
1226 | * a "Create Connection" command can sometimes fail to start for whatever |
1227 | * reason and the command_status event returns failure but we get no |
1228 | * indication of which connection failed (for instance in the case where |
1229 | * we tried to open too many connections all at once) So, we keep a flag |
1230 | * on the link to indicate pending status until the command_status event |
1231 | * is returned to help us decide which needs to be failed. |
1232 | * |
1233 | * since created links are inserted at the tail of hci_links, we know that |
1234 | * the first pending link we find will be the one that this command status |
1235 | * refers to. |
1236 | */ |
1237 | static void |
1238 | hci_cmd_create_con(struct hci_unit *unit, uint8_t status) |
1239 | { |
1240 | struct hci_link *link; |
1241 | |
1242 | TAILQ_FOREACH(link, &unit->hci_links, hl_next) { |
1243 | if ((link->hl_flags & HCI_LINK_CREATE_CON) == 0) |
1244 | continue; |
1245 | |
1246 | link->hl_flags &= ~HCI_LINK_CREATE_CON; |
1247 | |
1248 | switch(status) { |
1249 | case 0x00: /* success */ |
1250 | break; |
1251 | |
1252 | case 0x0c: /* "Command Disallowed" */ |
1253 | hci_link_free(link, EBUSY); |
1254 | break; |
1255 | |
1256 | default: /* some other trouble */ |
1257 | hci_link_free(link, EPROTO); |
1258 | break; |
1259 | } |
1260 | |
1261 | return; |
1262 | } |
1263 | } |
1264 | |