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