Home | History | Annotate | Line # | Download | only in netbt
hci_event.c revision 1.25.4.1
      1  1.25.4.1   martin /*	$NetBSD: hci_event.c,v 1.25.4.1 2019/09/28 07:32:02 martin 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.25.4.1   martin __KERNEL_RCSID(0, "$NetBSD: hci_event.c,v 1.25.4.1 2019/09/28 07:32:02 martin 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.25.4.1   martin 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.25.4.1   martin 	case HCI_CMD_READ_ENCRYPTION_KEY_SIZE:
    358  1.25.4.1   martin 		hci_cmd_read_encryption_key_size(unit, m);
    359  1.25.4.1   martin 		break;
    360  1.25.4.1   martin 
    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.25.4.1   martin 	/*
    632  1.25.4.1   martin 	 * We purposefully ignore ep.encryption_mode here - if that is set then
    633  1.25.4.1   martin 	 * the link will be authenticated and encrypted, but we still want to
    634  1.25.4.1   martin 	 * verify the key size and setmode sets the right flags
    635  1.25.4.1   martin 	 */
    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.25.4.1   martin  * The encryption status has changed. Make a note if disabled, or
    787  1.25.4.1   martin  * check the key size if possible before allowing it is enabled.
    788  1.25.4.1   martin  * (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.25.4.1   martin 	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.25.4.1   martin 	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.25.4.1   martin 		 con_handle, ep.status, ep.encryption_enable);
    808       1.6   plunky 
    809  1.25.4.1   martin 	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.25.4.1   martin 		if (ep.encryption_enable == 0) {
    815       1.6   plunky 			link->hl_flags &= ~HCI_LINK_ENCRYPT;
    816  1.25.4.1   martin 		} else if (unit->hci_cmds[20] & (1<<4)) {
    817  1.25.4.1   martin 			err = hci_send_cmd(unit, HCI_CMD_READ_ENCRYPTION_KEY_SIZE,
    818  1.25.4.1   martin 			    &ep.con_handle, sizeof(ep.con_handle));
    819  1.25.4.1   martin 
    820  1.25.4.1   martin 			if (err == 0)
    821  1.25.4.1   martin 				return;
    822  1.25.4.1   martin 		} else {
    823       1.6   plunky 			link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_ENCRYPT);
    824       1.6   plunky 
    825  1.25.4.1   martin 			if (link->hl_state == HCI_LINK_WAIT_ENCRYPT)
    826  1.25.4.1   martin 				link->hl_state = HCI_LINK_OPEN;
    827       1.6   plunky 
    828  1.25.4.1   martin 			err = hci_acl_setmode(link);
    829  1.25.4.1   martin 			if (err == EINPROGRESS)
    830  1.25.4.1   martin 				return;
    831  1.25.4.1   martin 		}
    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.25.4.1   martin  * process results of read_encryption_key_size command_complete event
   1191  1.25.4.1   martin  */
   1192  1.25.4.1   martin static void
   1193  1.25.4.1   martin hci_cmd_read_encryption_key_size(struct hci_unit *unit, struct mbuf *m)
   1194  1.25.4.1   martin {
   1195  1.25.4.1   martin 	hci_read_encryption_key_size_rp rp;
   1196  1.25.4.1   martin 	struct hci_link *link;
   1197  1.25.4.1   martin 	int err;
   1198  1.25.4.1   martin 
   1199  1.25.4.1   martin 	if (m->m_pkthdr.len < sizeof(rp))
   1200  1.25.4.1   martin 		return;
   1201  1.25.4.1   martin 
   1202  1.25.4.1   martin 	m_copydata(m, 0, sizeof(rp), &rp);
   1203  1.25.4.1   martin 	m_adj(m, sizeof(rp));
   1204  1.25.4.1   martin 
   1205  1.25.4.1   martin 	if (rp.status != 0)
   1206  1.25.4.1   martin 		return;
   1207  1.25.4.1   martin 
   1208  1.25.4.1   martin 	rp.con_handle = HCI_CON_HANDLE(le16toh(rp.con_handle));
   1209  1.25.4.1   martin 
   1210  1.25.4.1   martin 	DPRINTFN(1, "handle #%d, status=0x%x, key_size=0x%x\n",
   1211  1.25.4.1   martin 		 rp.con_handle, rp.status, rp.size);
   1212  1.25.4.1   martin 
   1213  1.25.4.1   martin 	link = hci_link_lookup_handle(unit, rp.con_handle);
   1214  1.25.4.1   martin 	if (link == NULL || link->hl_type != HCI_LINK_ACL)
   1215  1.25.4.1   martin 		return;
   1216  1.25.4.1   martin 
   1217  1.25.4.1   martin 	/*
   1218  1.25.4.1   martin 	 * if the key size is less than minimum standard, go straight to
   1219  1.25.4.1   martin 	 * linkmode as this is non-recoverable. Otherwise, we are encrypted
   1220  1.25.4.1   martin 	 * so can proceed with setmode.
   1221  1.25.4.1   martin 	 */
   1222  1.25.4.1   martin 	if (rp.status == 0) {
   1223  1.25.4.1   martin 		if (rp.size < 7) {
   1224  1.25.4.1   martin 			link->hl_flags &= ~HCI_LINK_ENCRYPT;
   1225  1.25.4.1   martin 		} else {
   1226  1.25.4.1   martin 			link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_ENCRYPT);
   1227  1.25.4.1   martin 
   1228  1.25.4.1   martin 			if (link->hl_state == HCI_LINK_WAIT_ENCRYPT)
   1229  1.25.4.1   martin 				link->hl_state = HCI_LINK_OPEN;
   1230  1.25.4.1   martin 
   1231  1.25.4.1   martin 			err = hci_acl_setmode(link);
   1232  1.25.4.1   martin 			if (err == EINPROGRESS)
   1233  1.25.4.1   martin 				return;
   1234  1.25.4.1   martin 		}
   1235  1.25.4.1   martin 	}
   1236  1.25.4.1   martin 
   1237  1.25.4.1   martin 	hci_acl_linkmode(link);
   1238  1.25.4.1   martin }
   1239  1.25.4.1   martin 
   1240  1.25.4.1   martin /*
   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