1*83aacedeSHasso Tepper /* $DragonFly: src/sys/netbt/hci_event.c,v 1.2 2008/03/18 13:41:42 hasso Exp $ */ 2*83aacedeSHasso Tepper /* $OpenBSD: src/sys/netbt/hci_event.c,v 1.7 2008/02/24 21:34:48 uwe Exp $ */ 3*83aacedeSHasso Tepper /* $NetBSD: hci_event.c,v 1.14 2008/02/10 17:40:54 plunky Exp $ */ 40a9108ebSHasso Tepper 50a9108ebSHasso Tepper /*- 60a9108ebSHasso Tepper * Copyright (c) 2005 Iain Hibbert. 70a9108ebSHasso Tepper * Copyright (c) 2006 Itronix Inc. 80a9108ebSHasso Tepper * All rights reserved. 90a9108ebSHasso Tepper * 100a9108ebSHasso Tepper * Redistribution and use in source and binary forms, with or without 110a9108ebSHasso Tepper * modification, are permitted provided that the following conditions 120a9108ebSHasso Tepper * are met: 130a9108ebSHasso Tepper * 1. Redistributions of source code must retain the above copyright 140a9108ebSHasso Tepper * notice, this list of conditions and the following disclaimer. 150a9108ebSHasso Tepper * 2. Redistributions in binary form must reproduce the above copyright 160a9108ebSHasso Tepper * notice, this list of conditions and the following disclaimer in the 170a9108ebSHasso Tepper * documentation and/or other materials provided with the distribution. 180a9108ebSHasso Tepper * 3. The name of Itronix Inc. may not be used to endorse 190a9108ebSHasso Tepper * or promote products derived from this software without specific 200a9108ebSHasso Tepper * prior written permission. 210a9108ebSHasso Tepper * 220a9108ebSHasso Tepper * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND 230a9108ebSHasso Tepper * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 240a9108ebSHasso Tepper * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 250a9108ebSHasso Tepper * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY 260a9108ebSHasso Tepper * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 270a9108ebSHasso Tepper * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 280a9108ebSHasso Tepper * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 290a9108ebSHasso Tepper * ON ANY THEORY OF LIABILITY, WHETHER IN 300a9108ebSHasso Tepper * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 310a9108ebSHasso Tepper * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 320a9108ebSHasso Tepper * POSSIBILITY OF SUCH DAMAGE. 330a9108ebSHasso Tepper */ 340a9108ebSHasso Tepper 350a9108ebSHasso Tepper #include <sys/param.h> 360a9108ebSHasso Tepper #include <sys/kernel.h> 370a9108ebSHasso Tepper #include <sys/malloc.h> 380a9108ebSHasso Tepper #include <sys/mbuf.h> 390a9108ebSHasso Tepper #include <sys/proc.h> 400a9108ebSHasso Tepper #include <sys/systm.h> 410a9108ebSHasso Tepper #include <sys/endian.h> 420a9108ebSHasso Tepper #include <sys/bus.h> 430a9108ebSHasso Tepper 440a9108ebSHasso Tepper #include <netbt/bluetooth.h> 450a9108ebSHasso Tepper #include <netbt/hci.h> 460a9108ebSHasso Tepper #include <netbt/sco.h> 470a9108ebSHasso Tepper 480a9108ebSHasso Tepper static void hci_event_inquiry_result(struct hci_unit *, struct mbuf *); 49*83aacedeSHasso Tepper static void hci_event_rssi_result(struct hci_unit *, struct mbuf *); 500a9108ebSHasso Tepper static void hci_event_command_status(struct hci_unit *, struct mbuf *); 510a9108ebSHasso Tepper static void hci_event_command_compl(struct hci_unit *, struct mbuf *); 520a9108ebSHasso Tepper static void hci_event_con_compl(struct hci_unit *, struct mbuf *); 530a9108ebSHasso Tepper static void hci_event_discon_compl(struct hci_unit *, struct mbuf *); 540a9108ebSHasso Tepper static void hci_event_con_req(struct hci_unit *, struct mbuf *); 550a9108ebSHasso Tepper static void hci_event_num_compl_pkts(struct hci_unit *, struct mbuf *); 560a9108ebSHasso Tepper static void hci_event_auth_compl(struct hci_unit *, struct mbuf *); 570a9108ebSHasso Tepper static void hci_event_encryption_change(struct hci_unit *, struct mbuf *); 580a9108ebSHasso Tepper static void hci_event_change_con_link_key_compl(struct hci_unit *, struct mbuf *); 59*83aacedeSHasso Tepper static void hci_event_read_clock_offset_compl(struct hci_unit *, struct mbuf *); 600a9108ebSHasso Tepper static void hci_cmd_read_bdaddr(struct hci_unit *, struct mbuf *); 610a9108ebSHasso Tepper static void hci_cmd_read_buffer_size(struct hci_unit *, struct mbuf *); 620a9108ebSHasso Tepper static void hci_cmd_read_local_features(struct hci_unit *, struct mbuf *); 63*83aacedeSHasso Tepper static void hci_cmd_read_local_ver(struct hci_unit *, struct mbuf *); 64*83aacedeSHasso Tepper static void hci_cmd_read_local_commands(struct hci_unit *, struct mbuf *); 650a9108ebSHasso Tepper static void hci_cmd_reset(struct hci_unit *, struct mbuf *); 660a9108ebSHasso Tepper 670a9108ebSHasso Tepper #ifdef BLUETOOTH_DEBUG 680a9108ebSHasso Tepper int bluetooth_debug = BLUETOOTH_DEBUG; 690a9108ebSHasso Tepper 700a9108ebSHasso Tepper static const char *hci_eventnames[] = { 710a9108ebSHasso Tepper /* 0x00 */ "NULL", 720a9108ebSHasso Tepper /* 0x01 */ "INQUIRY COMPLETE", 730a9108ebSHasso Tepper /* 0x02 */ "INQUIRY RESULT", 740a9108ebSHasso Tepper /* 0x03 */ "CONN COMPLETE", 750a9108ebSHasso Tepper /* 0x04 */ "CONN REQ", 760a9108ebSHasso Tepper /* 0x05 */ "DISCONN COMPLETE", 770a9108ebSHasso Tepper /* 0x06 */ "AUTH COMPLETE", 780a9108ebSHasso Tepper /* 0x07 */ "REMOTE NAME REQ COMPLETE", 790a9108ebSHasso Tepper /* 0x08 */ "ENCRYPTION CHANGE", 800a9108ebSHasso Tepper /* 0x09 */ "CHANGE CONN LINK KEY COMPLETE", 810a9108ebSHasso Tepper /* 0x0a */ "MASTER LINK KEY COMPLETE", 820a9108ebSHasso Tepper /* 0x0b */ "READ REMOTE FEATURES COMPLETE", 830a9108ebSHasso Tepper /* 0x0c */ "READ REMOTE VERSION INFO COMPLETE", 840a9108ebSHasso Tepper /* 0x0d */ "QoS SETUP COMPLETE", 850a9108ebSHasso Tepper /* 0x0e */ "COMMAND COMPLETE", 860a9108ebSHasso Tepper /* 0x0f */ "COMMAND STATUS", 870a9108ebSHasso Tepper /* 0x10 */ "HARDWARE ERROR", 880a9108ebSHasso Tepper /* 0x11 */ "FLUSH OCCUR", 890a9108ebSHasso Tepper /* 0x12 */ "ROLE CHANGE", 900a9108ebSHasso Tepper /* 0x13 */ "NUM COMPLETED PACKETS", 910a9108ebSHasso Tepper /* 0x14 */ "MODE CHANGE", 920a9108ebSHasso Tepper /* 0x15 */ "RETURN LINK KEYS", 930a9108ebSHasso Tepper /* 0x16 */ "PIN CODE REQ", 940a9108ebSHasso Tepper /* 0x17 */ "LINK KEY REQ", 950a9108ebSHasso Tepper /* 0x18 */ "LINK KEY NOTIFICATION", 960a9108ebSHasso Tepper /* 0x19 */ "LOOPBACK COMMAND", 970a9108ebSHasso Tepper /* 0x1a */ "DATA BUFFER OVERFLOW", 980a9108ebSHasso Tepper /* 0x1b */ "MAX SLOT CHANGE", 990a9108ebSHasso Tepper /* 0x1c */ "READ CLOCK OFFSET COMPLETE", 1000a9108ebSHasso Tepper /* 0x1d */ "CONN PKT TYPE CHANGED", 1010a9108ebSHasso Tepper /* 0x1e */ "QOS VIOLATION", 1020a9108ebSHasso Tepper /* 0x1f */ "PAGE SCAN MODE CHANGE", 1030a9108ebSHasso Tepper /* 0x20 */ "PAGE SCAN REP MODE CHANGE", 1040a9108ebSHasso Tepper /* 0x21 */ "FLOW SPECIFICATION COMPLETE", 1050a9108ebSHasso Tepper /* 0x22 */ "RSSI RESULT", 106*83aacedeSHasso Tepper /* 0x23 */ "READ REMOTE EXT FEATURES", 107*83aacedeSHasso Tepper /* 0x24 */ "UNKNOWN", 108*83aacedeSHasso Tepper /* 0x25 */ "UNKNOWN", 109*83aacedeSHasso Tepper /* 0x26 */ "UNKNOWN", 110*83aacedeSHasso Tepper /* 0x27 */ "UNKNOWN", 111*83aacedeSHasso Tepper /* 0x28 */ "UNKNOWN", 112*83aacedeSHasso Tepper /* 0x29 */ "UNKNOWN", 113*83aacedeSHasso Tepper /* 0x2a */ "UNKNOWN", 114*83aacedeSHasso Tepper /* 0x2b */ "UNKNOWN", 115*83aacedeSHasso Tepper /* 0x2c */ "SCO CON COMPLETE", 116*83aacedeSHasso Tepper /* 0x2d */ "SCO CON CHANGED", 117*83aacedeSHasso Tepper /* 0x2e */ "SNIFF SUBRATING", 118*83aacedeSHasso Tepper /* 0x2f */ "EXTENDED INQUIRY RESULT", 119*83aacedeSHasso Tepper /* 0x30 */ "ENCRYPTION KEY REFRESH", 120*83aacedeSHasso Tepper /* 0x31 */ "IO CAPABILITY REQUEST", 121*83aacedeSHasso Tepper /* 0x32 */ "IO CAPABILITY RESPONSE", 122*83aacedeSHasso Tepper /* 0x33 */ "USER CONFIRM REQUEST", 123*83aacedeSHasso Tepper /* 0x34 */ "USER PASSKEY REQUEST", 124*83aacedeSHasso Tepper /* 0x35 */ "REMOTE OOB DATA REQUEST", 125*83aacedeSHasso Tepper /* 0x36 */ "SIMPLE PAIRING COMPLETE", 126*83aacedeSHasso Tepper /* 0x37 */ "UNKNOWN", 127*83aacedeSHasso Tepper /* 0x38 */ "LINK SUPERVISION TIMEOUT CHANGED", 128*83aacedeSHasso Tepper /* 0x39 */ "ENHANCED FLUSH COMPLETE", 129*83aacedeSHasso Tepper /* 0x3a */ "UNKNOWN", 130*83aacedeSHasso Tepper /* 0x3b */ "USER PASSKEY NOTIFICATION", 131*83aacedeSHasso Tepper /* 0x3c */ "KEYPRESS NOTIFICATION", 132*83aacedeSHasso Tepper /* 0x3d */ "REMOTE HOST FEATURES NOTIFICATION", 1330a9108ebSHasso Tepper }; 1340a9108ebSHasso Tepper 1350a9108ebSHasso Tepper static const char * 1360a9108ebSHasso Tepper hci_eventstr(unsigned int event) 1370a9108ebSHasso Tepper { 1380a9108ebSHasso Tepper 1390a9108ebSHasso Tepper if (event < (sizeof(hci_eventnames) / sizeof(*hci_eventnames))) 1400a9108ebSHasso Tepper return hci_eventnames[event]; 1410a9108ebSHasso Tepper 1420a9108ebSHasso Tepper switch (event) { 1430a9108ebSHasso Tepper case HCI_EVENT_BT_LOGO: /* 0xfe */ 1440a9108ebSHasso Tepper return "BT_LOGO"; 1450a9108ebSHasso Tepper 1460a9108ebSHasso Tepper case HCI_EVENT_VENDOR: /* 0xff */ 1470a9108ebSHasso Tepper return "VENDOR"; 1480a9108ebSHasso Tepper } 1490a9108ebSHasso Tepper 150*83aacedeSHasso Tepper return "UNKNOWN"; 1510a9108ebSHasso Tepper } 1520a9108ebSHasso Tepper #endif /* BLUETOOTH_DEBUG */ 1530a9108ebSHasso Tepper 1540a9108ebSHasso Tepper /* 1550a9108ebSHasso Tepper * process HCI Events 1560a9108ebSHasso Tepper * 1570a9108ebSHasso Tepper * We will free the mbuf at the end, no need for any sub 1580a9108ebSHasso Tepper * functions to handle that. We kind of assume that the 1590a9108ebSHasso Tepper * device sends us valid events. 1600a9108ebSHasso Tepper */ 1610a9108ebSHasso Tepper void 1620a9108ebSHasso Tepper hci_event(struct mbuf *m, struct hci_unit *unit) 1630a9108ebSHasso Tepper { 1640a9108ebSHasso Tepper hci_event_hdr_t hdr; 1650a9108ebSHasso Tepper 1660a9108ebSHasso Tepper KKASSERT(m->m_flags & M_PKTHDR); 1670a9108ebSHasso Tepper 1680a9108ebSHasso Tepper KKASSERT(m->m_pkthdr.len >= sizeof(hdr)); 1690a9108ebSHasso Tepper m_copydata(m, 0, sizeof(hdr), (caddr_t)&hdr); 1700a9108ebSHasso Tepper m_adj(m, sizeof(hdr)); 1710a9108ebSHasso Tepper 1720a9108ebSHasso Tepper KKASSERT(hdr.type == HCI_EVENT_PKT); 1730a9108ebSHasso Tepper 174*83aacedeSHasso Tepper DPRINTFN(1, "(%s) event %s\n", 175*83aacedeSHasso Tepper device_get_nameunit(unit->hci_dev), hci_eventstr(hdr.event)); 1760a9108ebSHasso Tepper 1770a9108ebSHasso Tepper switch(hdr.event) { 1780a9108ebSHasso Tepper case HCI_EVENT_COMMAND_STATUS: 1790a9108ebSHasso Tepper hci_event_command_status(unit, m); 1800a9108ebSHasso Tepper break; 1810a9108ebSHasso Tepper 1820a9108ebSHasso Tepper case HCI_EVENT_COMMAND_COMPL: 1830a9108ebSHasso Tepper hci_event_command_compl(unit, m); 1840a9108ebSHasso Tepper break; 1850a9108ebSHasso Tepper 1860a9108ebSHasso Tepper case HCI_EVENT_NUM_COMPL_PKTS: 1870a9108ebSHasso Tepper hci_event_num_compl_pkts(unit, m); 1880a9108ebSHasso Tepper break; 1890a9108ebSHasso Tepper 1900a9108ebSHasso Tepper case HCI_EVENT_INQUIRY_RESULT: 1910a9108ebSHasso Tepper hci_event_inquiry_result(unit, m); 1920a9108ebSHasso Tepper break; 1930a9108ebSHasso Tepper 194*83aacedeSHasso Tepper case HCI_EVENT_RSSI_RESULT: 195*83aacedeSHasso Tepper hci_event_rssi_result(unit, m); 196*83aacedeSHasso Tepper break; 197*83aacedeSHasso Tepper 1980a9108ebSHasso Tepper case HCI_EVENT_CON_COMPL: 1990a9108ebSHasso Tepper hci_event_con_compl(unit, m); 2000a9108ebSHasso Tepper break; 2010a9108ebSHasso Tepper 2020a9108ebSHasso Tepper case HCI_EVENT_DISCON_COMPL: 2030a9108ebSHasso Tepper hci_event_discon_compl(unit, m); 2040a9108ebSHasso Tepper break; 2050a9108ebSHasso Tepper 2060a9108ebSHasso Tepper case HCI_EVENT_CON_REQ: 2070a9108ebSHasso Tepper hci_event_con_req(unit, m); 2080a9108ebSHasso Tepper break; 2090a9108ebSHasso Tepper 2100a9108ebSHasso Tepper case HCI_EVENT_AUTH_COMPL: 2110a9108ebSHasso Tepper hci_event_auth_compl(unit, m); 2120a9108ebSHasso Tepper break; 2130a9108ebSHasso Tepper 2140a9108ebSHasso Tepper case HCI_EVENT_ENCRYPTION_CHANGE: 2150a9108ebSHasso Tepper hci_event_encryption_change(unit, m); 2160a9108ebSHasso Tepper break; 2170a9108ebSHasso Tepper 2180a9108ebSHasso Tepper case HCI_EVENT_CHANGE_CON_LINK_KEY_COMPL: 2190a9108ebSHasso Tepper hci_event_change_con_link_key_compl(unit, m); 2200a9108ebSHasso Tepper break; 2210a9108ebSHasso Tepper 2220a9108ebSHasso Tepper case HCI_EVENT_READ_CLOCK_OFFSET_COMPL: 223*83aacedeSHasso Tepper hci_event_read_clock_offset_compl(unit, m); 2240a9108ebSHasso Tepper break; 2250a9108ebSHasso Tepper 2260a9108ebSHasso Tepper default: 2270a9108ebSHasso Tepper break; 2280a9108ebSHasso Tepper } 2290a9108ebSHasso Tepper 2300a9108ebSHasso Tepper m_freem(m); 2310a9108ebSHasso Tepper } 2320a9108ebSHasso Tepper 2330a9108ebSHasso Tepper /* 2340a9108ebSHasso Tepper * Command Status 2350a9108ebSHasso Tepper * 2360a9108ebSHasso Tepper * Update our record of num_cmd_pkts then post-process any pending commands 2370a9108ebSHasso Tepper * and optionally restart cmd output on the unit. 2380a9108ebSHasso Tepper */ 2390a9108ebSHasso Tepper static void 2400a9108ebSHasso Tepper hci_event_command_status(struct hci_unit *unit, struct mbuf *m) 2410a9108ebSHasso Tepper { 2420a9108ebSHasso Tepper hci_command_status_ep ep; 2430a9108ebSHasso Tepper struct hci_link *link; 2440a9108ebSHasso Tepper 2450a9108ebSHasso Tepper KKASSERT(m->m_pkthdr.len >= sizeof(ep)); 2460a9108ebSHasso Tepper m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); 2470a9108ebSHasso Tepper m_adj(m, sizeof(ep)); 2480a9108ebSHasso Tepper 2490a9108ebSHasso Tepper DPRINTFN(1, "(%s) opcode (%03x|%04x) status = 0x%x num_cmd_pkts = %d\n", 250*83aacedeSHasso Tepper device_get_nameunit(unit->hci_dev), 2510a9108ebSHasso Tepper HCI_OGF(letoh16(ep.opcode)), HCI_OCF(letoh16(ep.opcode)), 2520a9108ebSHasso Tepper ep.status, 2530a9108ebSHasso Tepper ep.num_cmd_pkts); 2540a9108ebSHasso Tepper 255*83aacedeSHasso Tepper if (ep.status > 0) 256*83aacedeSHasso Tepper kprintf("%s: CommandStatus opcode (%03x|%04x) failed " 257*83aacedeSHasso Tepper "(status=0x%02x)\n", device_get_nameunit(unit->hci_dev), 258*83aacedeSHasso Tepper HCI_OGF(letoh16(ep.opcode)), 259*83aacedeSHasso Tepper HCI_OCF(letoh16(ep.opcode)), ep.status); 260*83aacedeSHasso Tepper 2610a9108ebSHasso Tepper unit->hci_num_cmd_pkts = ep.num_cmd_pkts; 2620a9108ebSHasso Tepper 2630a9108ebSHasso Tepper /* 2640a9108ebSHasso Tepper * post processing of pending commands 2650a9108ebSHasso Tepper */ 2660a9108ebSHasso Tepper switch(letoh16(ep.opcode)) { 2670a9108ebSHasso Tepper case HCI_CMD_CREATE_CON: 2680a9108ebSHasso Tepper switch (ep.status) { 2690a9108ebSHasso Tepper case 0x12: /* Invalid HCI command parameters */ 2700a9108ebSHasso Tepper DPRINTF("(%s) Invalid HCI command parameters\n", 271*83aacedeSHasso Tepper device_get_nameunit(unit->hci_dev)); 2720a9108ebSHasso Tepper while ((link = hci_link_lookup_state(unit, 2730a9108ebSHasso Tepper HCI_LINK_ACL, HCI_LINK_WAIT_CONNECT)) != NULL) 2740a9108ebSHasso Tepper hci_link_free(link, ECONNABORTED); 2750a9108ebSHasso Tepper break; 2760a9108ebSHasso Tepper } 2770a9108ebSHasso Tepper break; 2780a9108ebSHasso Tepper default: 2790a9108ebSHasso Tepper break; 2800a9108ebSHasso Tepper } 2810a9108ebSHasso Tepper 2820a9108ebSHasso Tepper while (unit->hci_num_cmd_pkts > 0 && !IF_QEMPTY(&unit->hci_cmdwait)) { 2830a9108ebSHasso Tepper IF_DEQUEUE(&unit->hci_cmdwait, m); 2840a9108ebSHasso Tepper hci_output_cmd(unit, m); 2850a9108ebSHasso Tepper } 2860a9108ebSHasso Tepper } 2870a9108ebSHasso Tepper 2880a9108ebSHasso Tepper /* 2890a9108ebSHasso Tepper * Command Complete 2900a9108ebSHasso Tepper * 2910a9108ebSHasso Tepper * Update our record of num_cmd_pkts then handle the completed command, 2920a9108ebSHasso Tepper * and optionally restart cmd output on the unit. 2930a9108ebSHasso Tepper */ 2940a9108ebSHasso Tepper static void 2950a9108ebSHasso Tepper hci_event_command_compl(struct hci_unit *unit, struct mbuf *m) 2960a9108ebSHasso Tepper { 2970a9108ebSHasso Tepper hci_command_compl_ep ep; 298*83aacedeSHasso Tepper hci_status_rp rp; 2990a9108ebSHasso Tepper 3000a9108ebSHasso Tepper KKASSERT(m->m_pkthdr.len >= sizeof(ep)); 3010a9108ebSHasso Tepper m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); 3020a9108ebSHasso Tepper m_adj(m, sizeof(ep)); 3030a9108ebSHasso Tepper 3040a9108ebSHasso Tepper DPRINTFN(1, "(%s) opcode (%03x|%04x) num_cmd_pkts = %d\n", 305*83aacedeSHasso Tepper device_get_nameunit(unit->hci_dev), 3060a9108ebSHasso Tepper HCI_OGF(letoh16(ep.opcode)), HCI_OCF(letoh16(ep.opcode)), 3070a9108ebSHasso Tepper ep.num_cmd_pkts); 3080a9108ebSHasso Tepper 309*83aacedeSHasso Tepper /* 310*83aacedeSHasso Tepper * I am not sure if this is completely correct, it is not guaranteed 311*83aacedeSHasso Tepper * that a command_complete packet will contain the status though most 312*83aacedeSHasso Tepper * do seem to. 313*83aacedeSHasso Tepper */ 314*83aacedeSHasso Tepper m_copydata(m, 0, sizeof(rp), (caddr_t)&rp); 315*83aacedeSHasso Tepper if (rp.status > 0) 316*83aacedeSHasso Tepper kprintf("%s: CommandComplete opcode (%03x|%04x) failed (status=0x%02x)\n", 317*83aacedeSHasso Tepper device_get_nameunit(unit->hci_dev), HCI_OGF(letoh16(ep.opcode)), 318*83aacedeSHasso Tepper HCI_OCF(letoh16(ep.opcode)), rp.status); 319*83aacedeSHasso Tepper 3200a9108ebSHasso Tepper unit->hci_num_cmd_pkts = ep.num_cmd_pkts; 3210a9108ebSHasso Tepper 3220a9108ebSHasso Tepper /* 3230a9108ebSHasso Tepper * post processing of completed commands 3240a9108ebSHasso Tepper */ 3250a9108ebSHasso Tepper switch(letoh16(ep.opcode)) { 3260a9108ebSHasso Tepper case HCI_CMD_READ_BDADDR: 3270a9108ebSHasso Tepper hci_cmd_read_bdaddr(unit, m); 3280a9108ebSHasso Tepper break; 3290a9108ebSHasso Tepper 3300a9108ebSHasso Tepper case HCI_CMD_READ_BUFFER_SIZE: 3310a9108ebSHasso Tepper hci_cmd_read_buffer_size(unit, m); 3320a9108ebSHasso Tepper break; 3330a9108ebSHasso Tepper 3340a9108ebSHasso Tepper case HCI_CMD_READ_LOCAL_FEATURES: 3350a9108ebSHasso Tepper hci_cmd_read_local_features(unit, m); 3360a9108ebSHasso Tepper break; 3370a9108ebSHasso Tepper 338*83aacedeSHasso Tepper case HCI_CMD_READ_LOCAL_VER: 339*83aacedeSHasso Tepper hci_cmd_read_local_ver(unit, m); 340*83aacedeSHasso Tepper break; 341*83aacedeSHasso Tepper 342*83aacedeSHasso Tepper case HCI_CMD_READ_LOCAL_COMMANDS: 343*83aacedeSHasso Tepper hci_cmd_read_local_commands(unit, m); 344*83aacedeSHasso Tepper break; 345*83aacedeSHasso Tepper 3460a9108ebSHasso Tepper case HCI_CMD_RESET: 3470a9108ebSHasso Tepper hci_cmd_reset(unit, m); 3480a9108ebSHasso Tepper break; 3490a9108ebSHasso Tepper 3500a9108ebSHasso Tepper default: 3510a9108ebSHasso Tepper break; 3520a9108ebSHasso Tepper } 3530a9108ebSHasso Tepper 3540a9108ebSHasso Tepper while (unit->hci_num_cmd_pkts > 0 && !IF_QEMPTY(&unit->hci_cmdwait)) { 3550a9108ebSHasso Tepper IF_DEQUEUE(&unit->hci_cmdwait, m); 3560a9108ebSHasso Tepper hci_output_cmd(unit, m); 3570a9108ebSHasso Tepper } 3580a9108ebSHasso Tepper } 3590a9108ebSHasso Tepper 3600a9108ebSHasso Tepper /* 3610a9108ebSHasso Tepper * Number of Completed Packets 3620a9108ebSHasso Tepper * 3630a9108ebSHasso Tepper * This is sent periodically by the Controller telling us how many 3640a9108ebSHasso Tepper * buffers are now freed up and which handle was using them. From 3650a9108ebSHasso Tepper * this we determine which type of buffer it was and add the qty 3660a9108ebSHasso Tepper * back into the relevant packet counter, then restart output on 3670a9108ebSHasso Tepper * links that have halted. 3680a9108ebSHasso Tepper */ 3690a9108ebSHasso Tepper static void 3700a9108ebSHasso Tepper hci_event_num_compl_pkts(struct hci_unit *unit, struct mbuf *m) 3710a9108ebSHasso Tepper { 3720a9108ebSHasso Tepper hci_num_compl_pkts_ep ep; 3730a9108ebSHasso Tepper struct hci_link *link, *next; 3740a9108ebSHasso Tepper uint16_t handle, num; 3750a9108ebSHasso Tepper int num_acl = 0, num_sco = 0; 3760a9108ebSHasso Tepper 3770a9108ebSHasso Tepper KKASSERT(m->m_pkthdr.len >= sizeof(ep)); 3780a9108ebSHasso Tepper m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); 3790a9108ebSHasso Tepper m_adj(m, sizeof(ep)); 3800a9108ebSHasso Tepper 3810a9108ebSHasso Tepper while (ep.num_con_handles--) { 3820a9108ebSHasso Tepper m_copydata(m, 0, sizeof(handle), (caddr_t)&handle); 3830a9108ebSHasso Tepper m_adj(m, sizeof(handle)); 3840a9108ebSHasso Tepper handle = letoh16(handle); 3850a9108ebSHasso Tepper 3860a9108ebSHasso Tepper m_copydata(m, 0, sizeof(num), (caddr_t)&num); 3870a9108ebSHasso Tepper m_adj(m, sizeof(num)); 3880a9108ebSHasso Tepper num = letoh16(num); 3890a9108ebSHasso Tepper 3900a9108ebSHasso Tepper link = hci_link_lookup_handle(unit, handle); 3910a9108ebSHasso Tepper if (link) { 3920a9108ebSHasso Tepper if (link->hl_type == HCI_LINK_ACL) { 3930a9108ebSHasso Tepper num_acl += num; 3940a9108ebSHasso Tepper hci_acl_complete(link, num); 3950a9108ebSHasso Tepper } else { 3960a9108ebSHasso Tepper num_sco += num; 3970a9108ebSHasso Tepper hci_sco_complete(link, num); 3980a9108ebSHasso Tepper } 3990a9108ebSHasso Tepper } else { 4000a9108ebSHasso Tepper /* XXX need to issue Read_Buffer_Size or Reset? */ 4010a9108ebSHasso Tepper kprintf("%s: unknown handle %d! " 4020a9108ebSHasso Tepper "(losing track of %d packet buffer%s)\n", 403*83aacedeSHasso Tepper device_get_nameunit(unit->hci_dev), handle, 4040a9108ebSHasso Tepper num, (num == 1 ? "" : "s")); 4050a9108ebSHasso Tepper } 4060a9108ebSHasso Tepper } 4070a9108ebSHasso Tepper 4080a9108ebSHasso Tepper /* 4090a9108ebSHasso Tepper * Move up any queued packets. When a link has sent data, it will move 4100a9108ebSHasso Tepper * to the back of the queue - technically then if a link had something 4110a9108ebSHasso Tepper * to send and there were still buffers available it could get started 4120a9108ebSHasso Tepper * twice but it seemed more important to to handle higher loads fairly 4130a9108ebSHasso Tepper * than worry about wasting cycles when we are not busy. 4140a9108ebSHasso Tepper */ 4150a9108ebSHasso Tepper 4160a9108ebSHasso Tepper unit->hci_num_acl_pkts += num_acl; 4170a9108ebSHasso Tepper unit->hci_num_sco_pkts += num_sco; 4180a9108ebSHasso Tepper 4190a9108ebSHasso Tepper link = TAILQ_FIRST(&unit->hci_links); 4200a9108ebSHasso Tepper while (link && (unit->hci_num_acl_pkts > 0 || unit->hci_num_sco_pkts > 0)) { 4210a9108ebSHasso Tepper next = TAILQ_NEXT(link, hl_next); 4220a9108ebSHasso Tepper 4230a9108ebSHasso Tepper if (link->hl_type == HCI_LINK_ACL) { 4240a9108ebSHasso Tepper if (unit->hci_num_acl_pkts > 0 && link->hl_txqlen > 0) 4250a9108ebSHasso Tepper hci_acl_start(link); 4260a9108ebSHasso Tepper } else { 4270a9108ebSHasso Tepper if (unit->hci_num_sco_pkts > 0 && link->hl_txqlen > 0) 4280a9108ebSHasso Tepper hci_sco_start(link); 4290a9108ebSHasso Tepper } 4300a9108ebSHasso Tepper 4310a9108ebSHasso Tepper link = next; 4320a9108ebSHasso Tepper } 4330a9108ebSHasso Tepper } 4340a9108ebSHasso Tepper 4350a9108ebSHasso Tepper /* 4360a9108ebSHasso Tepper * Inquiry Result 4370a9108ebSHasso Tepper * 4380a9108ebSHasso Tepper * keep a note of devices seen, so we know which unit to use 4390a9108ebSHasso Tepper * on outgoing connections 4400a9108ebSHasso Tepper */ 4410a9108ebSHasso Tepper static void 4420a9108ebSHasso Tepper hci_event_inquiry_result(struct hci_unit *unit, struct mbuf *m) 4430a9108ebSHasso Tepper { 4440a9108ebSHasso Tepper hci_inquiry_result_ep ep; 445*83aacedeSHasso Tepper hci_inquiry_response ir; 4460a9108ebSHasso Tepper struct hci_memo *memo; 447*83aacedeSHasso Tepper 448*83aacedeSHasso Tepper KKASSERT(m->m_pkthdr.len >= sizeof(ep)); 449*83aacedeSHasso Tepper m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); 450*83aacedeSHasso Tepper m_adj(m, sizeof(ep)); 451*83aacedeSHasso Tepper 452*83aacedeSHasso Tepper DPRINTFN(1, "(%s) %d response%s\n", device_get_nameunit(unit->hci_dev), 453*83aacedeSHasso Tepper ep.num_responses, (ep.num_responses == 1 ? "" : "s")); 454*83aacedeSHasso Tepper 455*83aacedeSHasso Tepper while(ep.num_responses--) { 456*83aacedeSHasso Tepper KKASSERT(m->m_pkthdr.len >= sizeof(ir)); 457*83aacedeSHasso Tepper m_copydata(m, 0, sizeof(ir), (caddr_t)&ir); 458*83aacedeSHasso Tepper m_adj(m, sizeof(ir)); 459*83aacedeSHasso Tepper 460*83aacedeSHasso Tepper DPRINTFN(1, "bdaddr %02x:%02x:%02x:%02x:%02x:%02x\n", 461*83aacedeSHasso Tepper ir.bdaddr.b[5], ir.bdaddr.b[4], ir.bdaddr.b[3], 462*83aacedeSHasso Tepper ir.bdaddr.b[2], ir.bdaddr.b[1], ir.bdaddr.b[0]); 463*83aacedeSHasso Tepper 464*83aacedeSHasso Tepper memo = hci_memo_new(unit, &ir.bdaddr); 465*83aacedeSHasso Tepper if (memo != NULL) { 466*83aacedeSHasso Tepper memo->page_scan_rep_mode = ir.page_scan_rep_mode; 467*83aacedeSHasso Tepper memo->page_scan_mode = ir.page_scan_mode; 468*83aacedeSHasso Tepper memo->clock_offset = ir.clock_offset; 469*83aacedeSHasso Tepper } 470*83aacedeSHasso Tepper } 471*83aacedeSHasso Tepper } 472*83aacedeSHasso Tepper 473*83aacedeSHasso Tepper /* 474*83aacedeSHasso Tepper * Inquiry Result with RSSI 475*83aacedeSHasso Tepper * 476*83aacedeSHasso Tepper * as above but different packet when RSSI result is enabled 477*83aacedeSHasso Tepper */ 478*83aacedeSHasso Tepper static void 479*83aacedeSHasso Tepper hci_event_rssi_result(struct hci_unit *unit, struct mbuf *m) 480*83aacedeSHasso Tepper { 481*83aacedeSHasso Tepper hci_rssi_result_ep ep; 482*83aacedeSHasso Tepper hci_rssi_response rr; 483*83aacedeSHasso Tepper struct hci_memo *memo; 4840a9108ebSHasso Tepper 4850a9108ebSHasso Tepper KKASSERT(m->m_pkthdr.len >= sizeof(ep)); 4860a9108ebSHasso Tepper m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); 4870a9108ebSHasso Tepper m_adj(m, sizeof(ep)); 4880a9108ebSHasso Tepper 4890a9108ebSHasso Tepper DPRINTFN(1, "%d response%s\n", ep.num_responses, 4900a9108ebSHasso Tepper (ep.num_responses == 1 ? "" : "s")); 4910a9108ebSHasso Tepper 4920a9108ebSHasso Tepper while(ep.num_responses--) { 493*83aacedeSHasso Tepper KKASSERT(m->m_pkthdr.len >= sizeof(rr)); 494*83aacedeSHasso Tepper m_copydata(m, 0, sizeof(rr), (caddr_t)&rr); 495*83aacedeSHasso Tepper m_adj(m, sizeof(rr)); 4960a9108ebSHasso Tepper 4970a9108ebSHasso Tepper DPRINTFN(1, "bdaddr %02x:%02x:%02x:%02x:%02x:%02x\n", 498*83aacedeSHasso Tepper rr.bdaddr.b[5], rr.bdaddr.b[4], rr.bdaddr.b[3], 499*83aacedeSHasso Tepper rr.bdaddr.b[2], rr.bdaddr.b[1], rr.bdaddr.b[0]); 5000a9108ebSHasso Tepper 501*83aacedeSHasso Tepper memo = hci_memo_new(unit, &rr.bdaddr); 502*83aacedeSHasso Tepper if (memo != NULL) { 503*83aacedeSHasso Tepper memo->page_scan_rep_mode = rr.page_scan_rep_mode; 504*83aacedeSHasso Tepper memo->page_scan_mode = 0; 505*83aacedeSHasso Tepper memo->clock_offset = rr.clock_offset; 5060a9108ebSHasso Tepper } 5070a9108ebSHasso Tepper } 5080a9108ebSHasso Tepper } 5090a9108ebSHasso Tepper 5100a9108ebSHasso Tepper /* 5110a9108ebSHasso Tepper * Connection Complete 5120a9108ebSHasso Tepper * 5130a9108ebSHasso Tepper * Sent to us when a connection is made. If there is no link 5140a9108ebSHasso Tepper * structure already allocated for this, we must have changed 5150a9108ebSHasso Tepper * our mind, so just disconnect. 5160a9108ebSHasso Tepper */ 5170a9108ebSHasso Tepper static void 5180a9108ebSHasso Tepper hci_event_con_compl(struct hci_unit *unit, struct mbuf *m) 5190a9108ebSHasso Tepper { 5200a9108ebSHasso Tepper hci_con_compl_ep ep; 5210a9108ebSHasso Tepper hci_write_link_policy_settings_cp cp; 5220a9108ebSHasso Tepper struct hci_link *link; 5230a9108ebSHasso Tepper int err; 5240a9108ebSHasso Tepper 5250a9108ebSHasso Tepper KKASSERT(m->m_pkthdr.len >= sizeof(ep)); 5260a9108ebSHasso Tepper m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); 5270a9108ebSHasso Tepper m_adj(m, sizeof(ep)); 5280a9108ebSHasso Tepper 5290a9108ebSHasso Tepper DPRINTFN(1, "(%s) %s connection complete for " 5300a9108ebSHasso Tepper "%02x:%02x:%02x:%02x:%02x:%02x status %#x\n", 531*83aacedeSHasso Tepper device_get_nameunit(unit->hci_dev), 5320a9108ebSHasso Tepper (ep.link_type == HCI_LINK_ACL ? "ACL" : "SCO"), 5330a9108ebSHasso Tepper ep.bdaddr.b[5], ep.bdaddr.b[4], ep.bdaddr.b[3], 5340a9108ebSHasso Tepper ep.bdaddr.b[2], ep.bdaddr.b[1], ep.bdaddr.b[0], 5350a9108ebSHasso Tepper ep.status); 5360a9108ebSHasso Tepper 5370a9108ebSHasso Tepper link = hci_link_lookup_bdaddr(unit, &ep.bdaddr, ep.link_type); 5380a9108ebSHasso Tepper 5390a9108ebSHasso Tepper if (ep.status) { 5400a9108ebSHasso Tepper if (link != NULL) { 5410a9108ebSHasso Tepper switch (ep.status) { 5420a9108ebSHasso Tepper case 0x04: /* "Page Timeout" */ 5430a9108ebSHasso Tepper err = EHOSTDOWN; 5440a9108ebSHasso Tepper break; 5450a9108ebSHasso Tepper 5460a9108ebSHasso Tepper case 0x08: /* "Connection Timed Out" */ 5470a9108ebSHasso Tepper case 0x10: /* "Connection Accept Timeout Exceeded" */ 5480a9108ebSHasso Tepper err = ETIMEDOUT; 5490a9108ebSHasso Tepper break; 5500a9108ebSHasso Tepper 5510a9108ebSHasso Tepper case 0x16: /* "Connection Terminated by Local Host" */ 5520a9108ebSHasso Tepper err = 0; 5530a9108ebSHasso Tepper break; 5540a9108ebSHasso Tepper 5550a9108ebSHasso Tepper default: 5560a9108ebSHasso Tepper err = ECONNREFUSED; 5570a9108ebSHasso Tepper break; 5580a9108ebSHasso Tepper } 5590a9108ebSHasso Tepper 5600a9108ebSHasso Tepper hci_link_free(link, err); 5610a9108ebSHasso Tepper } 5620a9108ebSHasso Tepper 5630a9108ebSHasso Tepper return; 5640a9108ebSHasso Tepper } 5650a9108ebSHasso Tepper 5660a9108ebSHasso Tepper if (link == NULL) { 5670a9108ebSHasso Tepper hci_discon_cp dp; 5680a9108ebSHasso Tepper 5690a9108ebSHasso Tepper dp.con_handle = ep.con_handle; 5700a9108ebSHasso Tepper dp.reason = 0x13; /* "Remote User Terminated Connection" */ 5710a9108ebSHasso Tepper 5720a9108ebSHasso Tepper hci_send_cmd(unit, HCI_CMD_DISCONNECT, &dp, sizeof(dp)); 5730a9108ebSHasso Tepper return; 5740a9108ebSHasso Tepper } 5750a9108ebSHasso Tepper 5760a9108ebSHasso Tepper /* XXX could check auth_enable here */ 5770a9108ebSHasso Tepper 5780a9108ebSHasso Tepper if (ep.encryption_mode) 5790a9108ebSHasso Tepper link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_ENCRYPT); 5800a9108ebSHasso Tepper 5810a9108ebSHasso Tepper link->hl_state = HCI_LINK_OPEN; 5820a9108ebSHasso Tepper link->hl_handle = HCI_CON_HANDLE(letoh16(ep.con_handle)); 5830a9108ebSHasso Tepper 5840a9108ebSHasso Tepper if (ep.link_type == HCI_LINK_ACL) { 5850a9108ebSHasso Tepper cp.con_handle = ep.con_handle; 5860a9108ebSHasso Tepper cp.settings = htole16(unit->hci_link_policy); 5870a9108ebSHasso Tepper err = hci_send_cmd(unit, HCI_CMD_WRITE_LINK_POLICY_SETTINGS, 5880a9108ebSHasso Tepper &cp, sizeof(cp)); 5890a9108ebSHasso Tepper if (err) 5900a9108ebSHasso Tepper kprintf("%s: Warning, could not write link policy\n", 591*83aacedeSHasso Tepper device_get_nameunit(unit->hci_dev)); 592*83aacedeSHasso Tepper 593*83aacedeSHasso Tepper err = hci_send_cmd(unit, HCI_CMD_READ_CLOCK_OFFSET, 594*83aacedeSHasso Tepper &cp.con_handle, sizeof(cp.con_handle)); 595*83aacedeSHasso Tepper if (err) 596*83aacedeSHasso Tepper kprintf("%s: Warning, could not read clock offset\n", 597*83aacedeSHasso Tepper device_get_nameunit(unit->hci_dev)); 5980a9108ebSHasso Tepper 5990a9108ebSHasso Tepper err = hci_acl_setmode(link); 6000a9108ebSHasso Tepper if (err == EINPROGRESS) 6010a9108ebSHasso Tepper return; 6020a9108ebSHasso Tepper 6030a9108ebSHasso Tepper hci_acl_linkmode(link); 6040a9108ebSHasso Tepper } else { 6050a9108ebSHasso Tepper (*link->hl_sco->sp_proto->connected)(link->hl_sco->sp_upper); 6060a9108ebSHasso Tepper } 6070a9108ebSHasso Tepper } 6080a9108ebSHasso Tepper 6090a9108ebSHasso Tepper /* 6100a9108ebSHasso Tepper * Disconnection Complete 6110a9108ebSHasso Tepper * 6120a9108ebSHasso Tepper * This is sent in response to a disconnection request, but also if 6130a9108ebSHasso Tepper * the remote device goes out of range. 6140a9108ebSHasso Tepper */ 6150a9108ebSHasso Tepper static void 6160a9108ebSHasso Tepper hci_event_discon_compl(struct hci_unit *unit, struct mbuf *m) 6170a9108ebSHasso Tepper { 6180a9108ebSHasso Tepper hci_discon_compl_ep ep; 6190a9108ebSHasso Tepper struct hci_link *link; 6200a9108ebSHasso Tepper 6210a9108ebSHasso Tepper KKASSERT(m->m_pkthdr.len >= sizeof(ep)); 6220a9108ebSHasso Tepper m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); 6230a9108ebSHasso Tepper m_adj(m, sizeof(ep)); 6240a9108ebSHasso Tepper 6250a9108ebSHasso Tepper ep.con_handle = letoh16(ep.con_handle); 6260a9108ebSHasso Tepper 627*83aacedeSHasso Tepper DPRINTFN(1, "(%s) handle #%d, status=0x%x\n", 628*83aacedeSHasso Tepper device_get_nameunit(unit->hci_dev), ep.con_handle, ep.status); 6290a9108ebSHasso Tepper 6300a9108ebSHasso Tepper link = hci_link_lookup_handle(unit, HCI_CON_HANDLE(ep.con_handle)); 6310a9108ebSHasso Tepper if (link) 6320a9108ebSHasso Tepper hci_link_free(link, ENOENT); /* XXX NetBSD used ENOLINK here */ 6330a9108ebSHasso Tepper } 6340a9108ebSHasso Tepper 6350a9108ebSHasso Tepper /* 6360a9108ebSHasso Tepper * Connect Request 6370a9108ebSHasso Tepper * 6380a9108ebSHasso Tepper * We check upstream for appropriate listeners and accept connections 6390a9108ebSHasso Tepper * that are wanted. 6400a9108ebSHasso Tepper */ 6410a9108ebSHasso Tepper static void 6420a9108ebSHasso Tepper hci_event_con_req(struct hci_unit *unit, struct mbuf *m) 6430a9108ebSHasso Tepper { 6440a9108ebSHasso Tepper hci_con_req_ep ep; 6450a9108ebSHasso Tepper hci_accept_con_cp ap; 6460a9108ebSHasso Tepper hci_reject_con_cp rp; 6470a9108ebSHasso Tepper struct hci_link *link; 6480a9108ebSHasso Tepper 6490a9108ebSHasso Tepper KKASSERT(m->m_pkthdr.len >= sizeof(ep)); 6500a9108ebSHasso Tepper m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); 6510a9108ebSHasso Tepper m_adj(m, sizeof(ep)); 6520a9108ebSHasso Tepper 653*83aacedeSHasso Tepper DPRINTFN(1, "(%s) bdaddr %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " 6540a9108ebSHasso Tepper "class %2.2x%2.2x%2.2x type %s\n", 655*83aacedeSHasso Tepper device_get_nameunit(unit->hci_dev), 6560a9108ebSHasso Tepper ep.bdaddr.b[5], ep.bdaddr.b[4], ep.bdaddr.b[3], 6570a9108ebSHasso Tepper ep.bdaddr.b[2], ep.bdaddr.b[1], ep.bdaddr.b[0], 6580a9108ebSHasso Tepper ep.uclass[0], ep.uclass[1], ep.uclass[2], 6590a9108ebSHasso Tepper ep.link_type == HCI_LINK_ACL ? "ACL" : "SCO"); 6600a9108ebSHasso Tepper 6610a9108ebSHasso Tepper if (ep.link_type == HCI_LINK_ACL) 6620a9108ebSHasso Tepper link = hci_acl_newconn(unit, &ep.bdaddr); 6630a9108ebSHasso Tepper else 6640a9108ebSHasso Tepper link = hci_sco_newconn(unit, &ep.bdaddr); 6650a9108ebSHasso Tepper 6660a9108ebSHasso Tepper if (link == NULL) { 6670a9108ebSHasso Tepper memset(&rp, 0, sizeof(rp)); 6680a9108ebSHasso Tepper bdaddr_copy(&rp.bdaddr, &ep.bdaddr); 6690a9108ebSHasso Tepper rp.reason = 0x0f; /* Unacceptable BD_ADDR */ 6700a9108ebSHasso Tepper 6710a9108ebSHasso Tepper hci_send_cmd(unit, HCI_CMD_REJECT_CON, &rp, sizeof(rp)); 6720a9108ebSHasso Tepper } else { 6730a9108ebSHasso Tepper memset(&ap, 0, sizeof(ap)); 6740a9108ebSHasso Tepper bdaddr_copy(&ap.bdaddr, &ep.bdaddr); 6750a9108ebSHasso Tepper if (unit->hci_link_policy & HCI_LINK_POLICY_ENABLE_ROLE_SWITCH) 6760a9108ebSHasso Tepper ap.role = HCI_ROLE_MASTER; 6770a9108ebSHasso Tepper else 6780a9108ebSHasso Tepper ap.role = HCI_ROLE_SLAVE; 6790a9108ebSHasso Tepper 6800a9108ebSHasso Tepper hci_send_cmd(unit, HCI_CMD_ACCEPT_CON, &ap, sizeof(ap)); 6810a9108ebSHasso Tepper } 6820a9108ebSHasso Tepper } 6830a9108ebSHasso Tepper 6840a9108ebSHasso Tepper /* 6850a9108ebSHasso Tepper * Auth Complete 6860a9108ebSHasso Tepper * 6870a9108ebSHasso Tepper * Authentication has been completed on an ACL link. We can notify the 6880a9108ebSHasso Tepper * upper layer protocols unless further mode changes are pending. 6890a9108ebSHasso Tepper */ 6900a9108ebSHasso Tepper static void 6910a9108ebSHasso Tepper hci_event_auth_compl(struct hci_unit *unit, struct mbuf *m) 6920a9108ebSHasso Tepper { 6930a9108ebSHasso Tepper hci_auth_compl_ep ep; 6940a9108ebSHasso Tepper struct hci_link *link; 6950a9108ebSHasso Tepper int err; 6960a9108ebSHasso Tepper 6970a9108ebSHasso Tepper KKASSERT(m->m_pkthdr.len >= sizeof(ep)); 6980a9108ebSHasso Tepper m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); 6990a9108ebSHasso Tepper m_adj(m, sizeof(ep)); 7000a9108ebSHasso Tepper 7010a9108ebSHasso Tepper ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle)); 7020a9108ebSHasso Tepper 703*83aacedeSHasso Tepper DPRINTFN(1, "(%s) handle #%d, status=0x%x\n", 704*83aacedeSHasso Tepper device_get_nameunit(unit->hci_dev), ep.con_handle, ep.status); 7050a9108ebSHasso Tepper 7060a9108ebSHasso Tepper link = hci_link_lookup_handle(unit, ep.con_handle); 7070a9108ebSHasso Tepper if (link == NULL || link->hl_type != HCI_LINK_ACL) 7080a9108ebSHasso Tepper return; 7090a9108ebSHasso Tepper 7100a9108ebSHasso Tepper if (ep.status == 0) { 7110a9108ebSHasso Tepper link->hl_flags |= HCI_LINK_AUTH; 7120a9108ebSHasso Tepper 7130a9108ebSHasso Tepper if (link->hl_state == HCI_LINK_WAIT_AUTH) 7140a9108ebSHasso Tepper link->hl_state = HCI_LINK_OPEN; 7150a9108ebSHasso Tepper 7160a9108ebSHasso Tepper err = hci_acl_setmode(link); 7170a9108ebSHasso Tepper if (err == EINPROGRESS) 7180a9108ebSHasso Tepper return; 7190a9108ebSHasso Tepper } 7200a9108ebSHasso Tepper 7210a9108ebSHasso Tepper hci_acl_linkmode(link); 7220a9108ebSHasso Tepper } 7230a9108ebSHasso Tepper 7240a9108ebSHasso Tepper /* 7250a9108ebSHasso Tepper * Encryption Change 7260a9108ebSHasso Tepper * 7270a9108ebSHasso Tepper * The encryption status has changed. Basically, we note the change 7280a9108ebSHasso Tepper * then notify the upper layer protocol unless further mode changes 7290a9108ebSHasso Tepper * are pending. 7300a9108ebSHasso Tepper * Note that if encryption gets disabled when it has been requested, 7310a9108ebSHasso Tepper * we will attempt to enable it again.. (its a feature not a bug :) 7320a9108ebSHasso Tepper */ 7330a9108ebSHasso Tepper static void 7340a9108ebSHasso Tepper hci_event_encryption_change(struct hci_unit *unit, struct mbuf *m) 7350a9108ebSHasso Tepper { 7360a9108ebSHasso Tepper hci_encryption_change_ep ep; 7370a9108ebSHasso Tepper struct hci_link *link; 7380a9108ebSHasso Tepper int err; 7390a9108ebSHasso Tepper 7400a9108ebSHasso Tepper KKASSERT(m->m_pkthdr.len >= sizeof(ep)); 7410a9108ebSHasso Tepper m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); 7420a9108ebSHasso Tepper m_adj(m, sizeof(ep)); 7430a9108ebSHasso Tepper 7440a9108ebSHasso Tepper ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle)); 7450a9108ebSHasso Tepper 746*83aacedeSHasso Tepper DPRINTFN(1, "(%s) handle #%d, status=0x%x, encryption_enable=0x%x\n", 747*83aacedeSHasso Tepper device_get_nameunit(unit->hci_dev), ep.con_handle, ep.status, 748*83aacedeSHasso Tepper ep.encryption_enable); 7490a9108ebSHasso Tepper 7500a9108ebSHasso Tepper link = hci_link_lookup_handle(unit, ep.con_handle); 7510a9108ebSHasso Tepper if (link == NULL || link->hl_type != HCI_LINK_ACL) 7520a9108ebSHasso Tepper return; 7530a9108ebSHasso Tepper 7540a9108ebSHasso Tepper if (ep.status == 0) { 7550a9108ebSHasso Tepper if (ep.encryption_enable == 0) 7560a9108ebSHasso Tepper link->hl_flags &= ~HCI_LINK_ENCRYPT; 7570a9108ebSHasso Tepper else 7580a9108ebSHasso Tepper link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_ENCRYPT); 7590a9108ebSHasso Tepper 7600a9108ebSHasso Tepper if (link->hl_state == HCI_LINK_WAIT_ENCRYPT) 7610a9108ebSHasso Tepper link->hl_state = HCI_LINK_OPEN; 7620a9108ebSHasso Tepper 7630a9108ebSHasso Tepper err = hci_acl_setmode(link); 7640a9108ebSHasso Tepper if (err == EINPROGRESS) 7650a9108ebSHasso Tepper return; 7660a9108ebSHasso Tepper } 7670a9108ebSHasso Tepper 7680a9108ebSHasso Tepper hci_acl_linkmode(link); 7690a9108ebSHasso Tepper } 7700a9108ebSHasso Tepper 7710a9108ebSHasso Tepper /* 7720a9108ebSHasso Tepper * Change Connection Link Key Complete 7730a9108ebSHasso Tepper * 7740a9108ebSHasso Tepper * Link keys are handled in userland but if we are waiting to secure 7750a9108ebSHasso Tepper * this link, we should notify the upper protocols. A SECURE request 7760a9108ebSHasso Tepper * only needs a single key change, so we can cancel the request. 7770a9108ebSHasso Tepper */ 7780a9108ebSHasso Tepper static void 7790a9108ebSHasso Tepper hci_event_change_con_link_key_compl(struct hci_unit *unit, struct mbuf *m) 7800a9108ebSHasso Tepper { 7810a9108ebSHasso Tepper hci_change_con_link_key_compl_ep ep; 7820a9108ebSHasso Tepper struct hci_link *link; 7830a9108ebSHasso Tepper int err; 7840a9108ebSHasso Tepper 7850a9108ebSHasso Tepper KKASSERT(m->m_pkthdr.len >= sizeof(ep)); 7860a9108ebSHasso Tepper m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); 7870a9108ebSHasso Tepper m_adj(m, sizeof(ep)); 7880a9108ebSHasso Tepper 7890a9108ebSHasso Tepper ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle)); 7900a9108ebSHasso Tepper 791*83aacedeSHasso Tepper DPRINTFN(1, "(%s) handle #%d, status=0x%x\n", 792*83aacedeSHasso Tepper device_get_nameunit(unit->hci_dev), ep.con_handle, ep.status); 7930a9108ebSHasso Tepper 7940a9108ebSHasso Tepper link = hci_link_lookup_handle(unit, ep.con_handle); 7950a9108ebSHasso Tepper if (link == NULL || link->hl_type != HCI_LINK_ACL) 7960a9108ebSHasso Tepper return; 7970a9108ebSHasso Tepper 7980a9108ebSHasso Tepper link->hl_flags &= ~HCI_LINK_SECURE_REQ; 7990a9108ebSHasso Tepper 8000a9108ebSHasso Tepper if (ep.status == 0) { 8010a9108ebSHasso Tepper link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_SECURE); 8020a9108ebSHasso Tepper 8030a9108ebSHasso Tepper if (link->hl_state == HCI_LINK_WAIT_SECURE) 8040a9108ebSHasso Tepper link->hl_state = HCI_LINK_OPEN; 8050a9108ebSHasso Tepper 8060a9108ebSHasso Tepper err = hci_acl_setmode(link); 8070a9108ebSHasso Tepper if (err == EINPROGRESS) 8080a9108ebSHasso Tepper return; 8090a9108ebSHasso Tepper } 8100a9108ebSHasso Tepper 8110a9108ebSHasso Tepper hci_acl_linkmode(link); 8120a9108ebSHasso Tepper } 8130a9108ebSHasso Tepper 8140a9108ebSHasso Tepper /* 815*83aacedeSHasso Tepper * Read Clock Offset Complete 816*83aacedeSHasso Tepper * 817*83aacedeSHasso Tepper * We keep a note of the clock offset of remote devices when a 818*83aacedeSHasso Tepper * link is made, in order to facilitate reconnections to the device 819*83aacedeSHasso Tepper */ 820*83aacedeSHasso Tepper static void 821*83aacedeSHasso Tepper hci_event_read_clock_offset_compl(struct hci_unit *unit, struct mbuf *m) 822*83aacedeSHasso Tepper { 823*83aacedeSHasso Tepper hci_read_clock_offset_compl_ep ep; 824*83aacedeSHasso Tepper struct hci_link *link; 825*83aacedeSHasso Tepper 826*83aacedeSHasso Tepper KKASSERT(m->m_pkthdr.len >= sizeof(ep)); 827*83aacedeSHasso Tepper m_copydata(m, 0, sizeof(ep), (caddr_t)&ep); 828*83aacedeSHasso Tepper m_adj(m, sizeof(ep)); 829*83aacedeSHasso Tepper 830*83aacedeSHasso Tepper DPRINTFN(1, "handle #%d, offset=%u, status=0x%x\n", 831*83aacedeSHasso Tepper letoh16(ep.con_handle), letoh16(ep.clock_offset), ep.status); 832*83aacedeSHasso Tepper 833*83aacedeSHasso Tepper ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle)); 834*83aacedeSHasso Tepper link = hci_link_lookup_handle(unit, ep.con_handle); 835*83aacedeSHasso Tepper 836*83aacedeSHasso Tepper if (ep.status != 0 || link == NULL) 837*83aacedeSHasso Tepper return; 838*83aacedeSHasso Tepper 839*83aacedeSHasso Tepper link->hl_clock = ep.clock_offset; 840*83aacedeSHasso Tepper } 841*83aacedeSHasso Tepper 842*83aacedeSHasso Tepper /* 8430a9108ebSHasso Tepper * process results of read_bdaddr command_complete event 8440a9108ebSHasso Tepper */ 8450a9108ebSHasso Tepper static void 8460a9108ebSHasso Tepper hci_cmd_read_bdaddr(struct hci_unit *unit, struct mbuf *m) 8470a9108ebSHasso Tepper { 8480a9108ebSHasso Tepper hci_read_bdaddr_rp rp; 8490a9108ebSHasso Tepper 8500a9108ebSHasso Tepper KKASSERT(m->m_pkthdr.len >= sizeof(rp)); 8510a9108ebSHasso Tepper m_copydata(m, 0, sizeof(rp), (caddr_t)&rp); 8520a9108ebSHasso Tepper m_adj(m, sizeof(rp)); 8530a9108ebSHasso Tepper 8540a9108ebSHasso Tepper if (rp.status > 0) 8550a9108ebSHasso Tepper return; 8560a9108ebSHasso Tepper 8570a9108ebSHasso Tepper if ((unit->hci_flags & BTF_INIT_BDADDR) == 0) 8580a9108ebSHasso Tepper return; 8590a9108ebSHasso Tepper 8600a9108ebSHasso Tepper bdaddr_copy(&unit->hci_bdaddr, &rp.bdaddr); 8610a9108ebSHasso Tepper 8620a9108ebSHasso Tepper unit->hci_flags &= ~BTF_INIT_BDADDR; 8630a9108ebSHasso Tepper 8640a9108ebSHasso Tepper wakeup(unit); 8650a9108ebSHasso Tepper } 8660a9108ebSHasso Tepper 8670a9108ebSHasso Tepper /* 8680a9108ebSHasso Tepper * process results of read_buffer_size command_complete event 8690a9108ebSHasso Tepper */ 8700a9108ebSHasso Tepper static void 8710a9108ebSHasso Tepper hci_cmd_read_buffer_size(struct hci_unit *unit, struct mbuf *m) 8720a9108ebSHasso Tepper { 8730a9108ebSHasso Tepper hci_read_buffer_size_rp rp; 8740a9108ebSHasso Tepper 8750a9108ebSHasso Tepper KKASSERT(m->m_pkthdr.len >= sizeof(rp)); 8760a9108ebSHasso Tepper m_copydata(m, 0, sizeof(rp), (caddr_t)&rp); 8770a9108ebSHasso Tepper m_adj(m, sizeof(rp)); 8780a9108ebSHasso Tepper 8790a9108ebSHasso Tepper if (rp.status > 0) 8800a9108ebSHasso Tepper return; 8810a9108ebSHasso Tepper 8820a9108ebSHasso Tepper if ((unit->hci_flags & BTF_INIT_BUFFER_SIZE) == 0) 8830a9108ebSHasso Tepper return; 8840a9108ebSHasso Tepper 8850a9108ebSHasso Tepper unit->hci_max_acl_size = letoh16(rp.max_acl_size); 8860a9108ebSHasso Tepper unit->hci_num_acl_pkts = letoh16(rp.num_acl_pkts); 8870a9108ebSHasso Tepper unit->hci_max_sco_size = rp.max_sco_size; 8880a9108ebSHasso Tepper unit->hci_num_sco_pkts = letoh16(rp.num_sco_pkts); 8890a9108ebSHasso Tepper 8900a9108ebSHasso Tepper unit->hci_flags &= ~BTF_INIT_BUFFER_SIZE; 8910a9108ebSHasso Tepper 8920a9108ebSHasso Tepper wakeup(unit); 8930a9108ebSHasso Tepper } 8940a9108ebSHasso Tepper 8950a9108ebSHasso Tepper /* 8960a9108ebSHasso Tepper * process results of read_local_features command_complete event 8970a9108ebSHasso Tepper */ 8980a9108ebSHasso Tepper static void 8990a9108ebSHasso Tepper hci_cmd_read_local_features(struct hci_unit *unit, struct mbuf *m) 9000a9108ebSHasso Tepper { 9010a9108ebSHasso Tepper hci_read_local_features_rp rp; 9020a9108ebSHasso Tepper 9030a9108ebSHasso Tepper KKASSERT(m->m_pkthdr.len >= sizeof(rp)); 9040a9108ebSHasso Tepper m_copydata(m, 0, sizeof(rp), (caddr_t)&rp); 9050a9108ebSHasso Tepper m_adj(m, sizeof(rp)); 9060a9108ebSHasso Tepper 9070a9108ebSHasso Tepper if (rp.status > 0) 9080a9108ebSHasso Tepper return; 9090a9108ebSHasso Tepper 9100a9108ebSHasso Tepper if ((unit->hci_flags & BTF_INIT_FEATURES) == 0) 9110a9108ebSHasso Tepper return; 9120a9108ebSHasso Tepper 9130a9108ebSHasso Tepper unit->hci_lmp_mask = 0; 9140a9108ebSHasso Tepper 9150a9108ebSHasso Tepper if (rp.features[0] & HCI_LMP_ROLE_SWITCH) 9160a9108ebSHasso Tepper unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_ROLE_SWITCH; 9170a9108ebSHasso Tepper 9180a9108ebSHasso Tepper if (rp.features[0] & HCI_LMP_HOLD_MODE) 9190a9108ebSHasso Tepper unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_HOLD_MODE; 9200a9108ebSHasso Tepper 9210a9108ebSHasso Tepper if (rp.features[0] & HCI_LMP_SNIFF_MODE) 9220a9108ebSHasso Tepper unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_SNIFF_MODE; 9230a9108ebSHasso Tepper 9240a9108ebSHasso Tepper if (rp.features[1] & HCI_LMP_PARK_MODE) 9250a9108ebSHasso Tepper unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_PARK_MODE; 9260a9108ebSHasso Tepper 9270a9108ebSHasso Tepper /* ACL packet mask */ 9280a9108ebSHasso Tepper unit->hci_acl_mask = HCI_PKT_DM1 | HCI_PKT_DH1; 9290a9108ebSHasso Tepper 9300a9108ebSHasso Tepper if (rp.features[0] & HCI_LMP_3SLOT) 9310a9108ebSHasso Tepper unit->hci_acl_mask |= HCI_PKT_DM3 | HCI_PKT_DH3; 9320a9108ebSHasso Tepper 9330a9108ebSHasso Tepper if (rp.features[0] & HCI_LMP_5SLOT) 9340a9108ebSHasso Tepper unit->hci_acl_mask |= HCI_PKT_DM5 | HCI_PKT_DH5; 9350a9108ebSHasso Tepper 9360a9108ebSHasso Tepper if ((rp.features[3] & HCI_LMP_EDR_ACL_2MBPS) == 0) 9370a9108ebSHasso Tepper unit->hci_acl_mask |= HCI_PKT_2MBPS_DH1 9380a9108ebSHasso Tepper | HCI_PKT_2MBPS_DH3 9390a9108ebSHasso Tepper | HCI_PKT_2MBPS_DH5; 9400a9108ebSHasso Tepper 9410a9108ebSHasso Tepper if ((rp.features[3] & HCI_LMP_EDR_ACL_3MBPS) == 0) 9420a9108ebSHasso Tepper unit->hci_acl_mask |= HCI_PKT_3MBPS_DH1 9430a9108ebSHasso Tepper | HCI_PKT_3MBPS_DH3 9440a9108ebSHasso Tepper | HCI_PKT_3MBPS_DH5; 9450a9108ebSHasso Tepper 9460a9108ebSHasso Tepper if ((rp.features[4] & HCI_LMP_3SLOT_EDR_ACL) == 0) 9470a9108ebSHasso Tepper unit->hci_acl_mask |= HCI_PKT_2MBPS_DH3 9480a9108ebSHasso Tepper | HCI_PKT_3MBPS_DH3; 9490a9108ebSHasso Tepper 9500a9108ebSHasso Tepper if ((rp.features[5] & HCI_LMP_5SLOT_EDR_ACL) == 0) 9510a9108ebSHasso Tepper unit->hci_acl_mask |= HCI_PKT_2MBPS_DH5 9520a9108ebSHasso Tepper | HCI_PKT_3MBPS_DH5; 9530a9108ebSHasso Tepper 9540a9108ebSHasso Tepper unit->hci_packet_type = unit->hci_acl_mask; 9550a9108ebSHasso Tepper 9560a9108ebSHasso Tepper /* SCO packet mask */ 9570a9108ebSHasso Tepper unit->hci_sco_mask = 0; 9580a9108ebSHasso Tepper if (rp.features[1] & HCI_LMP_SCO_LINK) 9590a9108ebSHasso Tepper unit->hci_sco_mask |= HCI_PKT_HV1; 9600a9108ebSHasso Tepper 9610a9108ebSHasso Tepper if (rp.features[1] & HCI_LMP_HV2_PKT) 9620a9108ebSHasso Tepper unit->hci_sco_mask |= HCI_PKT_HV2; 9630a9108ebSHasso Tepper 9640a9108ebSHasso Tepper if (rp.features[1] & HCI_LMP_HV3_PKT) 9650a9108ebSHasso Tepper unit->hci_sco_mask |= HCI_PKT_HV3; 9660a9108ebSHasso Tepper 9670a9108ebSHasso Tepper if (rp.features[3] & HCI_LMP_EV3_PKT) 9680a9108ebSHasso Tepper unit->hci_sco_mask |= HCI_PKT_EV3; 9690a9108ebSHasso Tepper 9700a9108ebSHasso Tepper if (rp.features[4] & HCI_LMP_EV4_PKT) 9710a9108ebSHasso Tepper unit->hci_sco_mask |= HCI_PKT_EV4; 9720a9108ebSHasso Tepper 9730a9108ebSHasso Tepper if (rp.features[4] & HCI_LMP_EV5_PKT) 9740a9108ebSHasso Tepper unit->hci_sco_mask |= HCI_PKT_EV5; 9750a9108ebSHasso Tepper 9760a9108ebSHasso Tepper /* XXX what do 2MBPS/3MBPS/3SLOT eSCO mean? */ 9770a9108ebSHasso Tepper 9780a9108ebSHasso Tepper unit->hci_flags &= ~BTF_INIT_FEATURES; 9790a9108ebSHasso Tepper 9800a9108ebSHasso Tepper wakeup(unit); 9810a9108ebSHasso Tepper 9820a9108ebSHasso Tepper DPRINTFN(1, "%s: lmp_mask %4.4x, acl_mask %4.4x, sco_mask %4.4x\n", 983*83aacedeSHasso Tepper device_get_nameunit(unit->hci_dev), unit->hci_lmp_mask, 9840a9108ebSHasso Tepper unit->hci_acl_mask, unit->hci_sco_mask); 9850a9108ebSHasso Tepper } 9860a9108ebSHasso Tepper 9870a9108ebSHasso Tepper /* 988*83aacedeSHasso Tepper * process results of read_local_ver command_complete event 989*83aacedeSHasso Tepper * 990*83aacedeSHasso Tepper * reading local supported commands is only supported from 1.2 spec 991*83aacedeSHasso Tepper */ 992*83aacedeSHasso Tepper static void 993*83aacedeSHasso Tepper hci_cmd_read_local_ver(struct hci_unit *unit, struct mbuf *m) 994*83aacedeSHasso Tepper { 995*83aacedeSHasso Tepper hci_read_local_ver_rp rp; 996*83aacedeSHasso Tepper 997*83aacedeSHasso Tepper KKASSERT(m->m_pkthdr.len >= sizeof(rp)); 998*83aacedeSHasso Tepper m_copydata(m, 0, sizeof(rp), (caddr_t)&rp); 999*83aacedeSHasso Tepper m_adj(m, sizeof(rp)); 1000*83aacedeSHasso Tepper 1001*83aacedeSHasso Tepper if (rp.status != 0) 1002*83aacedeSHasso Tepper return; 1003*83aacedeSHasso Tepper 1004*83aacedeSHasso Tepper if ((unit->hci_flags & BTF_INIT_COMMANDS) == 0) 1005*83aacedeSHasso Tepper return; 1006*83aacedeSHasso Tepper 1007*83aacedeSHasso Tepper if (rp.hci_version < HCI_SPEC_V12) { 1008*83aacedeSHasso Tepper unit->hci_flags &= ~BTF_INIT_COMMANDS; 1009*83aacedeSHasso Tepper wakeup(unit); 1010*83aacedeSHasso Tepper return; 1011*83aacedeSHasso Tepper } 1012*83aacedeSHasso Tepper 1013*83aacedeSHasso Tepper hci_send_cmd(unit, HCI_CMD_READ_LOCAL_COMMANDS, NULL, 0); 1014*83aacedeSHasso Tepper } 1015*83aacedeSHasso Tepper 1016*83aacedeSHasso Tepper /* 1017*83aacedeSHasso Tepper * process results of read_local_commands command_complete event 1018*83aacedeSHasso Tepper */ 1019*83aacedeSHasso Tepper static void 1020*83aacedeSHasso Tepper hci_cmd_read_local_commands(struct hci_unit *unit, struct mbuf *m) 1021*83aacedeSHasso Tepper { 1022*83aacedeSHasso Tepper hci_read_local_commands_rp rp; 1023*83aacedeSHasso Tepper 1024*83aacedeSHasso Tepper KKASSERT(m->m_pkthdr.len >= sizeof(rp)); 1025*83aacedeSHasso Tepper m_copydata(m, 0, sizeof(rp), (caddr_t)&rp); 1026*83aacedeSHasso Tepper m_adj(m, sizeof(rp)); 1027*83aacedeSHasso Tepper 1028*83aacedeSHasso Tepper if (rp.status != 0) 1029*83aacedeSHasso Tepper return; 1030*83aacedeSHasso Tepper 1031*83aacedeSHasso Tepper if ((unit->hci_flags & BTF_INIT_COMMANDS) == 0) 1032*83aacedeSHasso Tepper return; 1033*83aacedeSHasso Tepper 1034*83aacedeSHasso Tepper unit->hci_flags &= ~BTF_INIT_COMMANDS; 1035*83aacedeSHasso Tepper memcpy(unit->hci_cmds, rp.commands, HCI_COMMANDS_SIZE); 1036*83aacedeSHasso Tepper 1037*83aacedeSHasso Tepper wakeup(unit); 1038*83aacedeSHasso Tepper } 1039*83aacedeSHasso Tepper 1040*83aacedeSHasso Tepper /* 10410a9108ebSHasso Tepper * process results of reset command_complete event 10420a9108ebSHasso Tepper * 10430a9108ebSHasso Tepper * This has killed all the connections, so close down anything we have left, 10440a9108ebSHasso Tepper * and reinitialise the unit. 10450a9108ebSHasso Tepper */ 10460a9108ebSHasso Tepper static void 10470a9108ebSHasso Tepper hci_cmd_reset(struct hci_unit *unit, struct mbuf *m) 10480a9108ebSHasso Tepper { 10490a9108ebSHasso Tepper hci_reset_rp rp; 10500a9108ebSHasso Tepper struct hci_link *link, *next; 10510a9108ebSHasso Tepper int acl; 10520a9108ebSHasso Tepper 10530a9108ebSHasso Tepper KKASSERT(m->m_pkthdr.len >= sizeof(rp)); 10540a9108ebSHasso Tepper m_copydata(m, 0, sizeof(rp), (caddr_t)&rp); 10550a9108ebSHasso Tepper m_adj(m, sizeof(rp)); 10560a9108ebSHasso Tepper 10570a9108ebSHasso Tepper if (rp.status != 0) 10580a9108ebSHasso Tepper return; 10590a9108ebSHasso Tepper 10600a9108ebSHasso Tepper /* 10610a9108ebSHasso Tepper * release SCO links first, since they may be holding 10620a9108ebSHasso Tepper * an ACL link reference. 10630a9108ebSHasso Tepper */ 10640a9108ebSHasso Tepper for (acl = 0 ; acl < 2 ; acl++) { 10650a9108ebSHasso Tepper next = TAILQ_FIRST(&unit->hci_links); 10660a9108ebSHasso Tepper while ((link = next) != NULL) { 10670a9108ebSHasso Tepper next = TAILQ_NEXT(link, hl_next); 10680a9108ebSHasso Tepper if (acl || link->hl_type != HCI_LINK_ACL) 10690a9108ebSHasso Tepper hci_link_free(link, ECONNABORTED); 10700a9108ebSHasso Tepper } 10710a9108ebSHasso Tepper } 10720a9108ebSHasso Tepper 10730a9108ebSHasso Tepper unit->hci_num_acl_pkts = 0; 10740a9108ebSHasso Tepper unit->hci_num_sco_pkts = 0; 10750a9108ebSHasso Tepper 10760a9108ebSHasso Tepper if (hci_send_cmd(unit, HCI_CMD_READ_BDADDR, NULL, 0)) 10770a9108ebSHasso Tepper return; 10780a9108ebSHasso Tepper 10790a9108ebSHasso Tepper if (hci_send_cmd(unit, HCI_CMD_READ_BUFFER_SIZE, NULL, 0)) 10800a9108ebSHasso Tepper return; 10810a9108ebSHasso Tepper 10820a9108ebSHasso Tepper if (hci_send_cmd(unit, HCI_CMD_READ_LOCAL_FEATURES, NULL, 0)) 10830a9108ebSHasso Tepper return; 1084*83aacedeSHasso Tepper 1085*83aacedeSHasso Tepper if (hci_send_cmd(unit, HCI_CMD_READ_LOCAL_VER, NULL, 0)) 1086*83aacedeSHasso Tepper return; 10870a9108ebSHasso Tepper } 1088