| 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 | |