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