Home | History | Annotate | Line # | Download | only in netbt
hci_event.c revision 1.23.36.1
      1  1.23.36.1   martin /*	$NetBSD: hci_event.c,v 1.23.36.1 2019/09/28 07:51:11 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.23.36.1   martin __KERNEL_RCSID(0, "$NetBSD: hci_event.c,v 1.23.36.1 2019/09/28 07:51:11 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.23.36.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.12   plunky 	m_copydata(m, 0, sizeof(rp), &rp);
    321       1.12   plunky 	if (rp.status > 0)
    322       1.12   plunky 		aprint_error_dev(unit->hci_dev,
    323       1.12   plunky 		    "CommandComplete opcode (%03x|%04x) failed (status=0x%02x)\n",
    324       1.12   plunky 		    HCI_OGF(le16toh(ep.opcode)), HCI_OCF(le16toh(ep.opcode)),
    325       1.12   plunky 		    rp.status);
    326       1.12   plunky 
    327        1.1  gdamore 	/*
    328        1.1  gdamore 	 * post processing of completed commands
    329        1.1  gdamore 	 */
    330        1.1  gdamore 	switch(le16toh(ep.opcode)) {
    331        1.1  gdamore 	case HCI_CMD_READ_BDADDR:
    332        1.1  gdamore 		hci_cmd_read_bdaddr(unit, m);
    333        1.1  gdamore 		break;
    334        1.1  gdamore 
    335        1.1  gdamore 	case HCI_CMD_READ_BUFFER_SIZE:
    336        1.1  gdamore 		hci_cmd_read_buffer_size(unit, m);
    337        1.1  gdamore 		break;
    338        1.1  gdamore 
    339        1.1  gdamore 	case HCI_CMD_READ_LOCAL_FEATURES:
    340        1.1  gdamore 		hci_cmd_read_local_features(unit, m);
    341        1.1  gdamore 		break;
    342        1.1  gdamore 
    343       1.22   plunky 	case HCI_CMD_READ_LOCAL_EXTENDED_FEATURES:
    344       1.22   plunky 		hci_cmd_read_local_extended_features(unit, m);
    345       1.22   plunky 		break;
    346       1.22   plunky 
    347       1.13   plunky 	case HCI_CMD_READ_LOCAL_VER:
    348       1.13   plunky 		hci_cmd_read_local_ver(unit, m);
    349       1.13   plunky 		break;
    350       1.13   plunky 
    351       1.13   plunky 	case HCI_CMD_READ_LOCAL_COMMANDS:
    352       1.13   plunky 		hci_cmd_read_local_commands(unit, m);
    353       1.13   plunky 		break;
    354       1.13   plunky 
    355  1.23.36.1   martin 	case HCI_CMD_READ_ENCRYPTION_KEY_SIZE:
    356  1.23.36.1   martin 		hci_cmd_read_encryption_key_size(unit, m);
    357  1.23.36.1   martin 		break;
    358  1.23.36.1   martin 
    359        1.1  gdamore 	case HCI_CMD_RESET:
    360        1.1  gdamore 		hci_cmd_reset(unit, m);
    361        1.1  gdamore 		break;
    362        1.1  gdamore 
    363        1.1  gdamore 	default:
    364        1.1  gdamore 		break;
    365        1.1  gdamore 	}
    366        1.1  gdamore }
    367        1.1  gdamore 
    368        1.1  gdamore /*
    369        1.1  gdamore  * Number of Completed Packets
    370        1.1  gdamore  *
    371        1.1  gdamore  * This is sent periodically by the Controller telling us how many
    372        1.1  gdamore  * buffers are now freed up and which handle was using them. From
    373        1.1  gdamore  * this we determine which type of buffer it was and add the qty
    374        1.1  gdamore  * back into the relevant packet counter, then restart output on
    375        1.1  gdamore  * links that have halted.
    376        1.1  gdamore  */
    377        1.1  gdamore static void
    378        1.1  gdamore hci_event_num_compl_pkts(struct hci_unit *unit, struct mbuf *m)
    379        1.1  gdamore {
    380        1.1  gdamore 	hci_num_compl_pkts_ep ep;
    381        1.1  gdamore 	struct hci_link *link, *next;
    382        1.1  gdamore 	uint16_t handle, num;
    383        1.1  gdamore 	int num_acl = 0, num_sco = 0;
    384        1.1  gdamore 
    385       1.23   plunky 	if (m->m_pkthdr.len < sizeof(ep))
    386       1.23   plunky 		return;
    387       1.23   plunky 
    388        1.1  gdamore 	m_copydata(m, 0, sizeof(ep), &ep);
    389        1.1  gdamore 	m_adj(m, sizeof(ep));
    390        1.1  gdamore 
    391        1.1  gdamore 	while (ep.num_con_handles--) {
    392        1.7   plunky 		m_copydata(m, 0, sizeof(handle), &handle);
    393        1.1  gdamore 		m_adj(m, sizeof(handle));
    394        1.1  gdamore 		handle = le16toh(handle);
    395        1.1  gdamore 
    396        1.7   plunky 		m_copydata(m, 0, sizeof(num), &num);
    397        1.1  gdamore 		m_adj(m, sizeof(num));
    398        1.1  gdamore 		num = le16toh(num);
    399        1.1  gdamore 
    400        1.1  gdamore 		link = hci_link_lookup_handle(unit, handle);
    401        1.1  gdamore 		if (link) {
    402        1.1  gdamore 			if (link->hl_type == HCI_LINK_ACL) {
    403        1.1  gdamore 				num_acl += num;
    404        1.1  gdamore 				hci_acl_complete(link, num);
    405        1.1  gdamore 			} else {
    406        1.1  gdamore 				num_sco += num;
    407        1.1  gdamore 				hci_sco_complete(link, num);
    408        1.1  gdamore 			}
    409        1.1  gdamore 		} else {
    410        1.4   plunky 			/* XXX need to issue Read_Buffer_Size or Reset? */
    411       1.10   plunky 			aprint_error_dev(unit->hci_dev,
    412       1.10   plunky 			    "unknown handle %d! (losing track of %d packet buffer%s)\n",
    413       1.10   plunky 			    handle, num, (num == 1 ? "" : "s"));
    414        1.1  gdamore 		}
    415        1.1  gdamore 	}
    416        1.1  gdamore 
    417        1.1  gdamore 	/*
    418        1.1  gdamore 	 * Move up any queued packets. When a link has sent data, it will move
    419        1.1  gdamore 	 * to the back of the queue - technically then if a link had something
    420        1.1  gdamore 	 * to send and there were still buffers available it could get started
    421        1.1  gdamore 	 * twice but it seemed more important to to handle higher loads fairly
    422        1.1  gdamore 	 * than worry about wasting cycles when we are not busy.
    423        1.1  gdamore 	 */
    424        1.1  gdamore 
    425        1.1  gdamore 	unit->hci_num_acl_pkts += num_acl;
    426        1.1  gdamore 	unit->hci_num_sco_pkts += num_sco;
    427        1.1  gdamore 
    428        1.1  gdamore 	link = TAILQ_FIRST(&unit->hci_links);
    429        1.1  gdamore 	while (link && (unit->hci_num_acl_pkts > 0 || unit->hci_num_sco_pkts > 0)) {
    430        1.1  gdamore 		next = TAILQ_NEXT(link, hl_next);
    431        1.1  gdamore 
    432        1.1  gdamore 		if (link->hl_type == HCI_LINK_ACL) {
    433        1.1  gdamore 			if (unit->hci_num_acl_pkts > 0 && link->hl_txqlen > 0)
    434        1.1  gdamore 				hci_acl_start(link);
    435        1.1  gdamore 		} else {
    436        1.1  gdamore 			if (unit->hci_num_sco_pkts > 0 && link->hl_txqlen > 0)
    437        1.1  gdamore 				hci_sco_start(link);
    438        1.1  gdamore 		}
    439        1.1  gdamore 
    440        1.1  gdamore 		link = next;
    441        1.1  gdamore 	}
    442        1.1  gdamore }
    443        1.1  gdamore 
    444        1.1  gdamore /*
    445        1.1  gdamore  * Inquiry Result
    446        1.1  gdamore  *
    447        1.1  gdamore  * keep a note of devices seen, so we know which unit to use
    448        1.1  gdamore  * on outgoing connections
    449        1.1  gdamore  */
    450        1.1  gdamore static void
    451        1.1  gdamore hci_event_inquiry_result(struct hci_unit *unit, struct mbuf *m)
    452        1.1  gdamore {
    453        1.1  gdamore 	hci_inquiry_result_ep ep;
    454        1.8   plunky 	hci_inquiry_response ir;
    455        1.1  gdamore 	struct hci_memo *memo;
    456        1.1  gdamore 
    457       1.23   plunky 	if (m->m_pkthdr.len < sizeof(ep))
    458       1.23   plunky 		return;
    459       1.23   plunky 
    460        1.1  gdamore 	m_copydata(m, 0, sizeof(ep), &ep);
    461        1.1  gdamore 	m_adj(m, sizeof(ep));
    462        1.1  gdamore 
    463        1.1  gdamore 	DPRINTFN(1, "%d response%s\n", ep.num_responses,
    464        1.1  gdamore 				(ep.num_responses == 1 ? "" : "s"));
    465        1.1  gdamore 
    466        1.1  gdamore 	while(ep.num_responses--) {
    467       1.23   plunky 		if (m->m_pkthdr.len < sizeof(ir))
    468       1.23   plunky 			return;
    469       1.23   plunky 
    470        1.9   plunky 		m_copydata(m, 0, sizeof(ir), &ir);
    471        1.9   plunky 		m_adj(m, sizeof(ir));
    472        1.1  gdamore 
    473        1.1  gdamore 		DPRINTFN(1, "bdaddr %02x:%02x:%02x:%02x:%02x:%02x\n",
    474        1.9   plunky 			ir.bdaddr.b[5], ir.bdaddr.b[4], ir.bdaddr.b[3],
    475        1.9   plunky 			ir.bdaddr.b[2], ir.bdaddr.b[1], ir.bdaddr.b[0]);
    476        1.1  gdamore 
    477        1.9   plunky 		memo = hci_memo_new(unit, &ir.bdaddr);
    478        1.9   plunky 		if (memo != NULL) {
    479        1.9   plunky 			memo->page_scan_rep_mode = ir.page_scan_rep_mode;
    480        1.9   plunky 			memo->page_scan_mode = ir.page_scan_mode;
    481        1.9   plunky 			memo->clock_offset = ir.clock_offset;
    482        1.1  gdamore 		}
    483        1.8   plunky 	}
    484        1.8   plunky }
    485        1.8   plunky 
    486        1.8   plunky /*
    487        1.8   plunky  * Inquiry Result with RSSI
    488        1.8   plunky  *
    489        1.8   plunky  * as above but different packet when RSSI result is enabled
    490        1.8   plunky  */
    491        1.8   plunky static void
    492        1.8   plunky hci_event_rssi_result(struct hci_unit *unit, struct mbuf *m)
    493        1.8   plunky {
    494        1.8   plunky 	hci_rssi_result_ep ep;
    495        1.8   plunky 	hci_rssi_response rr;
    496        1.8   plunky 	struct hci_memo *memo;
    497        1.8   plunky 
    498       1.23   plunky 	if (m->m_pkthdr.len < sizeof(ep))
    499       1.23   plunky 		return;
    500       1.23   plunky 
    501        1.8   plunky 	m_copydata(m, 0, sizeof(ep), &ep);
    502        1.8   plunky 	m_adj(m, sizeof(ep));
    503        1.8   plunky 
    504        1.8   plunky 	DPRINTFN(1, "%d response%s\n", ep.num_responses,
    505        1.8   plunky 				(ep.num_responses == 1 ? "" : "s"));
    506        1.8   plunky 
    507        1.8   plunky 	while(ep.num_responses--) {
    508       1.23   plunky 		if (m->m_pkthdr.len < sizeof(rr))
    509       1.23   plunky 			return;
    510       1.23   plunky 
    511        1.9   plunky 		m_copydata(m, 0, sizeof(rr), &rr);
    512        1.9   plunky 		m_adj(m, sizeof(rr));
    513        1.2   plunky 
    514        1.8   plunky 		DPRINTFN(1, "bdaddr %02x:%02x:%02x:%02x:%02x:%02x\n",
    515        1.9   plunky 			rr.bdaddr.b[5], rr.bdaddr.b[4], rr.bdaddr.b[3],
    516        1.9   plunky 			rr.bdaddr.b[2], rr.bdaddr.b[1], rr.bdaddr.b[0]);
    517        1.8   plunky 
    518        1.9   plunky 		memo = hci_memo_new(unit, &rr.bdaddr);
    519        1.9   plunky 		if (memo != NULL) {
    520        1.9   plunky 			memo->page_scan_rep_mode = rr.page_scan_rep_mode;
    521        1.9   plunky 			memo->page_scan_mode = 0;
    522        1.9   plunky 			memo->clock_offset = rr.clock_offset;
    523        1.8   plunky 		}
    524        1.1  gdamore 	}
    525        1.1  gdamore }
    526        1.1  gdamore 
    527        1.1  gdamore /*
    528       1.20   plunky  * Extended Inquiry Result
    529       1.20   plunky  *
    530       1.20   plunky  * as above but provides only one response and extended service info
    531       1.20   plunky  */
    532       1.20   plunky static void
    533       1.20   plunky hci_event_extended_result(struct hci_unit *unit, struct mbuf *m)
    534       1.20   plunky {
    535       1.20   plunky 	hci_extended_result_ep ep;
    536       1.20   plunky 	struct hci_memo *memo;
    537       1.20   plunky 
    538       1.23   plunky 	if (m->m_pkthdr.len < sizeof(ep))
    539       1.23   plunky 		return;
    540       1.23   plunky 
    541       1.20   plunky 	m_copydata(m, 0, sizeof(ep), &ep);
    542       1.20   plunky 	m_adj(m, sizeof(ep));
    543       1.20   plunky 
    544       1.20   plunky 	if (ep.num_responses != 1)
    545       1.20   plunky 		return;
    546       1.20   plunky 
    547       1.20   plunky 	DPRINTFN(1, "bdaddr %02x:%02x:%02x:%02x:%02x:%02x\n",
    548       1.20   plunky 		ep.bdaddr.b[5], ep.bdaddr.b[4], ep.bdaddr.b[3],
    549       1.20   plunky 		ep.bdaddr.b[2], ep.bdaddr.b[1], ep.bdaddr.b[0]);
    550       1.20   plunky 
    551       1.20   plunky 	memo = hci_memo_new(unit, &ep.bdaddr);
    552       1.20   plunky 	if (memo != NULL) {
    553       1.20   plunky 		memo->page_scan_rep_mode = ep.page_scan_rep_mode;
    554       1.20   plunky 		memo->page_scan_mode = 0;
    555       1.20   plunky 		memo->clock_offset = ep.clock_offset;
    556       1.20   plunky 	}
    557       1.20   plunky }
    558       1.20   plunky 
    559       1.20   plunky /*
    560        1.1  gdamore  * Connection Complete
    561        1.1  gdamore  *
    562        1.1  gdamore  * Sent to us when a connection is made. If there is no link
    563        1.1  gdamore  * structure already allocated for this, we must have changed
    564        1.1  gdamore  * our mind, so just disconnect.
    565        1.1  gdamore  */
    566        1.1  gdamore static void
    567        1.1  gdamore hci_event_con_compl(struct hci_unit *unit, struct mbuf *m)
    568        1.1  gdamore {
    569        1.1  gdamore 	hci_con_compl_ep ep;
    570        1.1  gdamore 	hci_write_link_policy_settings_cp cp;
    571        1.1  gdamore 	struct hci_link *link;
    572        1.1  gdamore 	int err;
    573        1.1  gdamore 
    574       1.23   plunky 	if (m->m_pkthdr.len < sizeof(ep))
    575       1.23   plunky 		return;
    576       1.23   plunky 
    577        1.1  gdamore 	m_copydata(m, 0, sizeof(ep), &ep);
    578        1.1  gdamore 	m_adj(m, sizeof(ep));
    579        1.1  gdamore 
    580        1.1  gdamore 	DPRINTFN(1, "(%s) %s connection complete for "
    581        1.1  gdamore 		"%02x:%02x:%02x:%02x:%02x:%02x status %#x\n",
    582       1.10   plunky 		device_xname(unit->hci_dev),
    583        1.1  gdamore 		(ep.link_type == HCI_LINK_ACL ? "ACL" : "SCO"),
    584        1.1  gdamore 		ep.bdaddr.b[5], ep.bdaddr.b[4], ep.bdaddr.b[3],
    585        1.1  gdamore 		ep.bdaddr.b[2], ep.bdaddr.b[1], ep.bdaddr.b[0],
    586        1.1  gdamore 		ep.status);
    587        1.1  gdamore 
    588        1.1  gdamore 	link = hci_link_lookup_bdaddr(unit, &ep.bdaddr, ep.link_type);
    589        1.1  gdamore 
    590        1.1  gdamore 	if (ep.status) {
    591        1.1  gdamore 		if (link != NULL) {
    592        1.1  gdamore 			switch (ep.status) {
    593        1.1  gdamore 			case 0x04: /* "Page Timeout" */
    594        1.1  gdamore 				err = EHOSTDOWN;
    595        1.1  gdamore 				break;
    596        1.1  gdamore 
    597        1.1  gdamore 			case 0x08: /* "Connection Timed Out" */
    598        1.1  gdamore 				err = ETIMEDOUT;
    599        1.1  gdamore 				break;
    600        1.1  gdamore 
    601        1.1  gdamore 			case 0x16: /* "Connection Terminated by Local Host" */
    602        1.1  gdamore 				err = 0;
    603        1.1  gdamore 				break;
    604        1.1  gdamore 
    605        1.1  gdamore 			default:
    606        1.1  gdamore 				err = ECONNREFUSED;
    607        1.1  gdamore 				break;
    608        1.1  gdamore 			}
    609        1.1  gdamore 
    610        1.1  gdamore 			hci_link_free(link, err);
    611        1.1  gdamore 		}
    612        1.1  gdamore 
    613        1.1  gdamore 		return;
    614        1.1  gdamore 	}
    615        1.1  gdamore 
    616        1.1  gdamore 	if (link == NULL) {
    617        1.1  gdamore 		hci_discon_cp dp;
    618        1.1  gdamore 
    619        1.1  gdamore 		dp.con_handle = ep.con_handle;
    620        1.1  gdamore 		dp.reason = 0x13; /* "Remote User Terminated Connection" */
    621        1.1  gdamore 
    622        1.1  gdamore 		hci_send_cmd(unit, HCI_CMD_DISCONNECT, &dp, sizeof(dp));
    623        1.1  gdamore 		return;
    624        1.1  gdamore 	}
    625        1.1  gdamore 
    626  1.23.36.1   martin 	/*
    627  1.23.36.1   martin 	 * We purposefully ignore ep.encryption_mode here - if that is set then
    628  1.23.36.1   martin 	 * the link will be authenticated and encrypted, but we still want to
    629  1.23.36.1   martin 	 * verify the key size and setmode sets the right flags
    630  1.23.36.1   martin 	 */
    631        1.6   plunky 
    632        1.1  gdamore 	link->hl_state = HCI_LINK_OPEN;
    633        1.1  gdamore 	link->hl_handle = HCI_CON_HANDLE(le16toh(ep.con_handle));
    634        1.1  gdamore 
    635        1.1  gdamore 	if (ep.link_type == HCI_LINK_ACL) {
    636        1.1  gdamore 		cp.con_handle = ep.con_handle;
    637        1.1  gdamore 		cp.settings = htole16(unit->hci_link_policy);
    638        1.1  gdamore 		err = hci_send_cmd(unit, HCI_CMD_WRITE_LINK_POLICY_SETTINGS,
    639        1.1  gdamore 						&cp, sizeof(cp));
    640        1.1  gdamore 		if (err)
    641       1.10   plunky 			aprint_error_dev(unit->hci_dev,
    642       1.10   plunky 			    "Warning, could not write link policy\n");
    643        1.1  gdamore 
    644        1.9   plunky 		err = hci_send_cmd(unit, HCI_CMD_READ_CLOCK_OFFSET,
    645        1.9   plunky 				    &cp.con_handle, sizeof(cp.con_handle));
    646        1.9   plunky 		if (err)
    647       1.10   plunky 			aprint_error_dev(unit->hci_dev,
    648       1.10   plunky 			    "Warning, could not read clock offset\n");
    649        1.9   plunky 
    650        1.6   plunky 		err = hci_acl_setmode(link);
    651        1.6   plunky 		if (err == EINPROGRESS)
    652        1.6   plunky 			return;
    653        1.6   plunky 
    654        1.6   plunky 		hci_acl_linkmode(link);
    655        1.1  gdamore 	} else {
    656        1.1  gdamore 		(*link->hl_sco->sp_proto->connected)(link->hl_sco->sp_upper);
    657        1.1  gdamore 	}
    658        1.1  gdamore }
    659        1.1  gdamore 
    660        1.1  gdamore /*
    661        1.1  gdamore  * Disconnection Complete
    662        1.1  gdamore  *
    663        1.1  gdamore  * This is sent in response to a disconnection request, but also if
    664        1.1  gdamore  * the remote device goes out of range.
    665        1.1  gdamore  */
    666        1.1  gdamore static void
    667        1.1  gdamore hci_event_discon_compl(struct hci_unit *unit, struct mbuf *m)
    668        1.1  gdamore {
    669        1.1  gdamore 	hci_discon_compl_ep ep;
    670        1.1  gdamore 	struct hci_link *link;
    671        1.1  gdamore 
    672       1.23   plunky 	if (m->m_pkthdr.len < sizeof(ep))
    673       1.23   plunky 		return;
    674       1.23   plunky 
    675        1.1  gdamore 	m_copydata(m, 0, sizeof(ep), &ep);
    676        1.1  gdamore 	m_adj(m, sizeof(ep));
    677        1.1  gdamore 
    678        1.1  gdamore 	ep.con_handle = le16toh(ep.con_handle);
    679        1.1  gdamore 
    680        1.1  gdamore 	DPRINTFN(1, "handle #%d, status=0x%x\n", ep.con_handle, ep.status);
    681        1.1  gdamore 
    682        1.1  gdamore 	link = hci_link_lookup_handle(unit, HCI_CON_HANDLE(ep.con_handle));
    683        1.1  gdamore 	if (link)
    684        1.1  gdamore 		hci_link_free(link, ENOLINK);
    685        1.1  gdamore }
    686        1.1  gdamore 
    687        1.1  gdamore /*
    688        1.1  gdamore  * Connect Request
    689        1.1  gdamore  *
    690        1.1  gdamore  * We check upstream for appropriate listeners and accept connections
    691        1.1  gdamore  * that are wanted.
    692        1.1  gdamore  */
    693        1.1  gdamore static void
    694        1.1  gdamore hci_event_con_req(struct hci_unit *unit, struct mbuf *m)
    695        1.1  gdamore {
    696        1.1  gdamore 	hci_con_req_ep ep;
    697        1.1  gdamore 	hci_accept_con_cp ap;
    698        1.1  gdamore 	hci_reject_con_cp rp;
    699        1.1  gdamore 	struct hci_link *link;
    700        1.1  gdamore 
    701       1.23   plunky 	if (m->m_pkthdr.len < sizeof(ep))
    702       1.23   plunky 		return;
    703       1.23   plunky 
    704        1.1  gdamore 	m_copydata(m, 0, sizeof(ep), &ep);
    705        1.1  gdamore 	m_adj(m, sizeof(ep));
    706        1.1  gdamore 
    707        1.1  gdamore 	DPRINTFN(1, "bdaddr %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x "
    708        1.1  gdamore 		"class %2.2x%2.2x%2.2x type %s\n",
    709        1.1  gdamore 		ep.bdaddr.b[5], ep.bdaddr.b[4], ep.bdaddr.b[3],
    710        1.1  gdamore 		ep.bdaddr.b[2], ep.bdaddr.b[1], ep.bdaddr.b[0],
    711        1.1  gdamore 		ep.uclass[0], ep.uclass[1], ep.uclass[2],
    712        1.1  gdamore 		ep.link_type == HCI_LINK_ACL ? "ACL" : "SCO");
    713        1.1  gdamore 
    714        1.1  gdamore 	if (ep.link_type == HCI_LINK_ACL)
    715        1.1  gdamore 		link = hci_acl_newconn(unit, &ep.bdaddr);
    716        1.1  gdamore 	else
    717        1.1  gdamore 		link = hci_sco_newconn(unit, &ep.bdaddr);
    718        1.1  gdamore 
    719        1.1  gdamore 	if (link == NULL) {
    720        1.1  gdamore 		memset(&rp, 0, sizeof(rp));
    721        1.1  gdamore 		bdaddr_copy(&rp.bdaddr, &ep.bdaddr);
    722        1.1  gdamore 		rp.reason = 0x0f;	/* Unacceptable BD_ADDR */
    723        1.1  gdamore 
    724        1.1  gdamore 		hci_send_cmd(unit, HCI_CMD_REJECT_CON, &rp, sizeof(rp));
    725        1.1  gdamore 	} else {
    726        1.1  gdamore 		memset(&ap, 0, sizeof(ap));
    727        1.1  gdamore 		bdaddr_copy(&ap.bdaddr, &ep.bdaddr);
    728       1.19   plunky 		if (unit->hci_flags & BTF_MASTER)
    729        1.1  gdamore 			ap.role = HCI_ROLE_MASTER;
    730        1.1  gdamore 		else
    731        1.1  gdamore 			ap.role = HCI_ROLE_SLAVE;
    732        1.1  gdamore 
    733        1.1  gdamore 		hci_send_cmd(unit, HCI_CMD_ACCEPT_CON, &ap, sizeof(ap));
    734        1.1  gdamore 	}
    735        1.1  gdamore }
    736        1.1  gdamore 
    737        1.1  gdamore /*
    738        1.6   plunky  * Auth Complete
    739        1.6   plunky  *
    740        1.6   plunky  * Authentication has been completed on an ACL link. We can notify the
    741        1.6   plunky  * upper layer protocols unless further mode changes are pending.
    742        1.6   plunky  */
    743        1.6   plunky static void
    744        1.6   plunky hci_event_auth_compl(struct hci_unit *unit, struct mbuf *m)
    745        1.6   plunky {
    746        1.6   plunky 	hci_auth_compl_ep ep;
    747        1.6   plunky 	struct hci_link *link;
    748        1.6   plunky 	int err;
    749        1.6   plunky 
    750       1.23   plunky 	if (m->m_pkthdr.len < sizeof(ep))
    751       1.23   plunky 		return;
    752       1.23   plunky 
    753        1.6   plunky 	m_copydata(m, 0, sizeof(ep), &ep);
    754        1.6   plunky 	m_adj(m, sizeof(ep));
    755        1.6   plunky 
    756        1.6   plunky 	ep.con_handle = HCI_CON_HANDLE(le16toh(ep.con_handle));
    757        1.6   plunky 
    758        1.6   plunky 	DPRINTFN(1, "handle #%d, status=0x%x\n", ep.con_handle, ep.status);
    759        1.6   plunky 
    760        1.6   plunky 	link = hci_link_lookup_handle(unit, ep.con_handle);
    761        1.6   plunky 	if (link == NULL || link->hl_type != HCI_LINK_ACL)
    762        1.6   plunky 		return;
    763        1.6   plunky 
    764        1.6   plunky 	if (ep.status == 0) {
    765        1.6   plunky 		link->hl_flags |= HCI_LINK_AUTH;
    766        1.6   plunky 
    767        1.6   plunky 		if (link->hl_state == HCI_LINK_WAIT_AUTH)
    768        1.6   plunky 			link->hl_state = HCI_LINK_OPEN;
    769        1.6   plunky 
    770        1.6   plunky 		err = hci_acl_setmode(link);
    771        1.6   plunky 		if (err == EINPROGRESS)
    772        1.6   plunky 			return;
    773        1.6   plunky 	}
    774        1.6   plunky 
    775        1.6   plunky 	hci_acl_linkmode(link);
    776        1.6   plunky }
    777        1.6   plunky 
    778        1.6   plunky /*
    779        1.6   plunky  * Encryption Change
    780        1.6   plunky  *
    781  1.23.36.1   martin  * The encryption status has changed. Make a note if disabled, or
    782  1.23.36.1   martin  * check the key size if possible before allowing it is enabled.
    783  1.23.36.1   martin  * (checking of key size was enabled in 3.0 spec)
    784        1.6   plunky  */
    785        1.6   plunky static void
    786        1.6   plunky hci_event_encryption_change(struct hci_unit *unit, struct mbuf *m)
    787        1.6   plunky {
    788        1.6   plunky 	hci_encryption_change_ep ep;
    789        1.6   plunky 	struct hci_link *link;
    790  1.23.36.1   martin 	uint16_t con_handle;
    791        1.6   plunky 	int err;
    792        1.6   plunky 
    793       1.23   plunky 	if (m->m_pkthdr.len < sizeof(ep))
    794       1.23   plunky 		return;
    795       1.23   plunky 
    796        1.6   plunky 	m_copydata(m, 0, sizeof(ep), &ep);
    797        1.6   plunky 	m_adj(m, sizeof(ep));
    798        1.6   plunky 
    799  1.23.36.1   martin 	con_handle = HCI_CON_HANDLE(le16toh(ep.con_handle));
    800        1.6   plunky 
    801        1.6   plunky 	DPRINTFN(1, "handle #%d, status=0x%x, encryption_enable=0x%x\n",
    802  1.23.36.1   martin 		 con_handle, ep.status, ep.encryption_enable);
    803        1.6   plunky 
    804  1.23.36.1   martin 	link = hci_link_lookup_handle(unit, con_handle);
    805        1.6   plunky 	if (link == NULL || link->hl_type != HCI_LINK_ACL)
    806        1.6   plunky 		return;
    807        1.6   plunky 
    808        1.6   plunky 	if (ep.status == 0) {
    809  1.23.36.1   martin 		if (ep.encryption_enable == 0) {
    810        1.6   plunky 			link->hl_flags &= ~HCI_LINK_ENCRYPT;
    811  1.23.36.1   martin 		} else if (unit->hci_cmds[20] & (1<<4)) {
    812  1.23.36.1   martin 			err = hci_send_cmd(unit, HCI_CMD_READ_ENCRYPTION_KEY_SIZE,
    813  1.23.36.1   martin 			    &ep.con_handle, sizeof(ep.con_handle));
    814  1.23.36.1   martin 
    815  1.23.36.1   martin 			if (err == 0)
    816  1.23.36.1   martin 				return;
    817  1.23.36.1   martin 		} else {
    818        1.6   plunky 			link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_ENCRYPT);
    819        1.6   plunky 
    820  1.23.36.1   martin 			if (link->hl_state == HCI_LINK_WAIT_ENCRYPT)
    821  1.23.36.1   martin 				link->hl_state = HCI_LINK_OPEN;
    822        1.6   plunky 
    823  1.23.36.1   martin 			err = hci_acl_setmode(link);
    824  1.23.36.1   martin 			if (err == EINPROGRESS)
    825  1.23.36.1   martin 				return;
    826  1.23.36.1   martin 		}
    827        1.6   plunky 	}
    828        1.6   plunky 
    829        1.6   plunky 	hci_acl_linkmode(link);
    830        1.6   plunky }
    831        1.6   plunky 
    832        1.6   plunky /*
    833        1.6   plunky  * Change Connection Link Key Complete
    834        1.6   plunky  *
    835        1.6   plunky  * Link keys are handled in userland but if we are waiting to secure
    836        1.6   plunky  * this link, we should notify the upper protocols. A SECURE request
    837        1.6   plunky  * only needs a single key change, so we can cancel the request.
    838        1.6   plunky  */
    839        1.6   plunky static void
    840        1.6   plunky hci_event_change_con_link_key_compl(struct hci_unit *unit, struct mbuf *m)
    841        1.6   plunky {
    842        1.6   plunky 	hci_change_con_link_key_compl_ep ep;
    843        1.6   plunky 	struct hci_link *link;
    844        1.6   plunky 	int err;
    845        1.6   plunky 
    846       1.23   plunky 	if (m->m_pkthdr.len < sizeof(ep))
    847       1.23   plunky 		return;
    848       1.23   plunky 
    849        1.6   plunky 	m_copydata(m, 0, sizeof(ep), &ep);
    850        1.6   plunky 	m_adj(m, sizeof(ep));
    851        1.6   plunky 
    852        1.6   plunky 	ep.con_handle = HCI_CON_HANDLE(le16toh(ep.con_handle));
    853        1.6   plunky 
    854        1.6   plunky 	DPRINTFN(1, "handle #%d, status=0x%x\n", ep.con_handle, ep.status);
    855        1.6   plunky 
    856        1.6   plunky 	link = hci_link_lookup_handle(unit, ep.con_handle);
    857        1.6   plunky 	if (link == NULL || link->hl_type != HCI_LINK_ACL)
    858        1.6   plunky 		return;
    859        1.6   plunky 
    860        1.6   plunky 	link->hl_flags &= ~HCI_LINK_SECURE_REQ;
    861        1.6   plunky 
    862        1.6   plunky 	if (ep.status == 0) {
    863        1.6   plunky 		link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_SECURE);
    864        1.6   plunky 
    865        1.6   plunky 		if (link->hl_state == HCI_LINK_WAIT_SECURE)
    866        1.6   plunky 			link->hl_state = HCI_LINK_OPEN;
    867        1.6   plunky 
    868        1.6   plunky 		err = hci_acl_setmode(link);
    869        1.6   plunky 		if (err == EINPROGRESS)
    870        1.6   plunky 			return;
    871        1.6   plunky 	}
    872        1.6   plunky 
    873        1.6   plunky 	hci_acl_linkmode(link);
    874        1.6   plunky }
    875        1.6   plunky 
    876        1.6   plunky /*
    877        1.9   plunky  * Read Clock Offset Complete
    878        1.9   plunky  *
    879        1.9   plunky  * We keep a note of the clock offset of remote devices when a
    880        1.9   plunky  * link is made, in order to facilitate reconnections to the device
    881        1.9   plunky  */
    882        1.9   plunky static void
    883        1.9   plunky hci_event_read_clock_offset_compl(struct hci_unit *unit, struct mbuf *m)
    884        1.9   plunky {
    885        1.9   plunky 	hci_read_clock_offset_compl_ep ep;
    886        1.9   plunky 	struct hci_link *link;
    887        1.9   plunky 
    888       1.23   plunky 	if (m->m_pkthdr.len < sizeof(ep))
    889       1.23   plunky 		return;
    890       1.23   plunky 
    891        1.9   plunky 	m_copydata(m, 0, sizeof(ep), &ep);
    892        1.9   plunky 	m_adj(m, sizeof(ep));
    893        1.9   plunky 
    894        1.9   plunky 	DPRINTFN(1, "handle #%d, offset=%u, status=0x%x\n",
    895        1.9   plunky 		le16toh(ep.con_handle), le16toh(ep.clock_offset), ep.status);
    896        1.9   plunky 
    897        1.9   plunky 	ep.con_handle = HCI_CON_HANDLE(le16toh(ep.con_handle));
    898        1.9   plunky 	link = hci_link_lookup_handle(unit, ep.con_handle);
    899       1.21   plunky 	if (link == NULL || link->hl_type != HCI_LINK_ACL)
    900        1.9   plunky 		return;
    901        1.9   plunky 
    902       1.21   plunky 	if (ep.status == 0)
    903       1.21   plunky 		link->hl_clock = ep.clock_offset;
    904        1.9   plunky }
    905        1.9   plunky 
    906        1.9   plunky /*
    907        1.1  gdamore  * process results of read_bdaddr command_complete event
    908        1.1  gdamore  */
    909        1.1  gdamore static void
    910        1.1  gdamore hci_cmd_read_bdaddr(struct hci_unit *unit, struct mbuf *m)
    911        1.1  gdamore {
    912        1.1  gdamore 	hci_read_bdaddr_rp rp;
    913        1.1  gdamore 
    914       1.23   plunky 	if (m->m_pkthdr.len < sizeof(rp))
    915       1.23   plunky 		return;
    916       1.23   plunky 
    917        1.1  gdamore 	m_copydata(m, 0, sizeof(rp), &rp);
    918        1.1  gdamore 	m_adj(m, sizeof(rp));
    919        1.1  gdamore 
    920        1.1  gdamore 	if (rp.status > 0)
    921        1.1  gdamore 		return;
    922        1.1  gdamore 
    923        1.1  gdamore 	if ((unit->hci_flags & BTF_INIT_BDADDR) == 0)
    924        1.1  gdamore 		return;
    925        1.1  gdamore 
    926        1.1  gdamore 	bdaddr_copy(&unit->hci_bdaddr, &rp.bdaddr);
    927        1.1  gdamore 
    928        1.1  gdamore 	unit->hci_flags &= ~BTF_INIT_BDADDR;
    929        1.1  gdamore 
    930       1.18       ad 	cv_broadcast(&unit->hci_init);
    931        1.1  gdamore }
    932        1.1  gdamore 
    933        1.1  gdamore /*
    934        1.1  gdamore  * process results of read_buffer_size command_complete event
    935        1.1  gdamore  */
    936        1.1  gdamore static void
    937        1.1  gdamore hci_cmd_read_buffer_size(struct hci_unit *unit, struct mbuf *m)
    938        1.1  gdamore {
    939        1.1  gdamore 	hci_read_buffer_size_rp rp;
    940        1.1  gdamore 
    941       1.23   plunky 	if (m->m_pkthdr.len < sizeof(rp))
    942       1.23   plunky 		return;
    943       1.23   plunky 
    944        1.1  gdamore 	m_copydata(m, 0, sizeof(rp), &rp);
    945        1.1  gdamore 	m_adj(m, sizeof(rp));
    946        1.1  gdamore 
    947        1.1  gdamore 	if (rp.status > 0)
    948        1.1  gdamore 		return;
    949        1.1  gdamore 
    950        1.1  gdamore 	if ((unit->hci_flags & BTF_INIT_BUFFER_SIZE) == 0)
    951        1.1  gdamore 		return;
    952        1.1  gdamore 
    953        1.1  gdamore 	unit->hci_max_acl_size = le16toh(rp.max_acl_size);
    954        1.1  gdamore 	unit->hci_num_acl_pkts = le16toh(rp.num_acl_pkts);
    955       1.22   plunky 	unit->hci_max_acl_pkts = le16toh(rp.num_acl_pkts);
    956        1.1  gdamore 	unit->hci_max_sco_size = rp.max_sco_size;
    957        1.1  gdamore 	unit->hci_num_sco_pkts = le16toh(rp.num_sco_pkts);
    958       1.22   plunky 	unit->hci_max_sco_pkts = le16toh(rp.num_sco_pkts);
    959        1.1  gdamore 
    960        1.1  gdamore 	unit->hci_flags &= ~BTF_INIT_BUFFER_SIZE;
    961        1.1  gdamore 
    962       1.18       ad 	cv_broadcast(&unit->hci_init);
    963        1.1  gdamore }
    964        1.1  gdamore 
    965        1.1  gdamore /*
    966        1.1  gdamore  * process results of read_local_features command_complete event
    967        1.1  gdamore  */
    968        1.1  gdamore static void
    969        1.1  gdamore hci_cmd_read_local_features(struct hci_unit *unit, struct mbuf *m)
    970        1.1  gdamore {
    971        1.1  gdamore 	hci_read_local_features_rp rp;
    972        1.1  gdamore 
    973       1.23   plunky 	if (m->m_pkthdr.len < sizeof(rp))
    974       1.23   plunky 		return;
    975       1.23   plunky 
    976        1.1  gdamore 	m_copydata(m, 0, sizeof(rp), &rp);
    977        1.1  gdamore 	m_adj(m, sizeof(rp));
    978        1.1  gdamore 
    979        1.1  gdamore 	if (rp.status > 0)
    980        1.1  gdamore 		return;
    981        1.1  gdamore 
    982        1.1  gdamore 	if ((unit->hci_flags & BTF_INIT_FEATURES) == 0)
    983        1.1  gdamore 		return;
    984        1.1  gdamore 
    985       1.22   plunky 	memcpy(unit->hci_feat0, rp.features, HCI_FEATURES_SIZE);
    986       1.22   plunky 
    987        1.1  gdamore 	unit->hci_lmp_mask = 0;
    988        1.1  gdamore 
    989        1.1  gdamore 	if (rp.features[0] & HCI_LMP_ROLE_SWITCH)
    990        1.1  gdamore 		unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_ROLE_SWITCH;
    991        1.1  gdamore 
    992        1.1  gdamore 	if (rp.features[0] & HCI_LMP_HOLD_MODE)
    993        1.1  gdamore 		unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_HOLD_MODE;
    994        1.1  gdamore 
    995        1.1  gdamore 	if (rp.features[0] & HCI_LMP_SNIFF_MODE)
    996        1.1  gdamore 		unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_SNIFF_MODE;
    997        1.1  gdamore 
    998        1.1  gdamore 	if (rp.features[1] & HCI_LMP_PARK_MODE)
    999        1.1  gdamore 		unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_PARK_MODE;
   1000        1.1  gdamore 
   1001       1.22   plunky 	DPRINTFN(1, "%s: lmp_mask %4.4x\n",
   1002       1.22   plunky 		device_xname(unit->hci_dev), unit->hci_lmp_mask);
   1003       1.22   plunky 
   1004        1.1  gdamore 	/* ACL packet mask */
   1005        1.1  gdamore 	unit->hci_acl_mask = HCI_PKT_DM1 | HCI_PKT_DH1;
   1006        1.1  gdamore 
   1007        1.1  gdamore 	if (rp.features[0] & HCI_LMP_3SLOT)
   1008        1.1  gdamore 		unit->hci_acl_mask |= HCI_PKT_DM3 | HCI_PKT_DH3;
   1009        1.1  gdamore 
   1010        1.1  gdamore 	if (rp.features[0] & HCI_LMP_5SLOT)
   1011        1.1  gdamore 		unit->hci_acl_mask |= HCI_PKT_DM5 | HCI_PKT_DH5;
   1012        1.1  gdamore 
   1013        1.1  gdamore 	if ((rp.features[3] & HCI_LMP_EDR_ACL_2MBPS) == 0)
   1014        1.1  gdamore 		unit->hci_acl_mask |= HCI_PKT_2MBPS_DH1
   1015        1.1  gdamore 				    | HCI_PKT_2MBPS_DH3
   1016        1.1  gdamore 				    | HCI_PKT_2MBPS_DH5;
   1017        1.1  gdamore 
   1018        1.1  gdamore 	if ((rp.features[3] & HCI_LMP_EDR_ACL_3MBPS) == 0)
   1019        1.1  gdamore 		unit->hci_acl_mask |= HCI_PKT_3MBPS_DH1
   1020        1.1  gdamore 				    | HCI_PKT_3MBPS_DH3
   1021        1.1  gdamore 				    | HCI_PKT_3MBPS_DH5;
   1022        1.1  gdamore 
   1023        1.1  gdamore 	if ((rp.features[4] & HCI_LMP_3SLOT_EDR_ACL) == 0)
   1024        1.1  gdamore 		unit->hci_acl_mask |= HCI_PKT_2MBPS_DH3
   1025        1.1  gdamore 				    | HCI_PKT_3MBPS_DH3;
   1026        1.1  gdamore 
   1027        1.1  gdamore 	if ((rp.features[5] & HCI_LMP_5SLOT_EDR_ACL) == 0)
   1028        1.1  gdamore 		unit->hci_acl_mask |= HCI_PKT_2MBPS_DH5
   1029        1.1  gdamore 				    | HCI_PKT_3MBPS_DH5;
   1030        1.1  gdamore 
   1031       1.22   plunky 	DPRINTFN(1, "%s: acl_mask %4.4x\n",
   1032       1.22   plunky 		device_xname(unit->hci_dev), unit->hci_acl_mask);
   1033       1.22   plunky 
   1034        1.1  gdamore 	unit->hci_packet_type = unit->hci_acl_mask;
   1035        1.1  gdamore 
   1036        1.1  gdamore 	/* SCO packet mask */
   1037        1.1  gdamore 	unit->hci_sco_mask = 0;
   1038        1.1  gdamore 	if (rp.features[1] & HCI_LMP_SCO_LINK)
   1039        1.1  gdamore 		unit->hci_sco_mask |= HCI_PKT_HV1;
   1040        1.1  gdamore 
   1041        1.1  gdamore 	if (rp.features[1] & HCI_LMP_HV2_PKT)
   1042        1.1  gdamore 		unit->hci_sco_mask |= HCI_PKT_HV2;
   1043        1.1  gdamore 
   1044        1.1  gdamore 	if (rp.features[1] & HCI_LMP_HV3_PKT)
   1045        1.1  gdamore 		unit->hci_sco_mask |= HCI_PKT_HV3;
   1046        1.1  gdamore 
   1047        1.1  gdamore 	if (rp.features[3] & HCI_LMP_EV3_PKT)
   1048        1.1  gdamore 		unit->hci_sco_mask |= HCI_PKT_EV3;
   1049        1.1  gdamore 
   1050        1.1  gdamore 	if (rp.features[4] & HCI_LMP_EV4_PKT)
   1051        1.1  gdamore 		unit->hci_sco_mask |= HCI_PKT_EV4;
   1052        1.1  gdamore 
   1053        1.1  gdamore 	if (rp.features[4] & HCI_LMP_EV5_PKT)
   1054        1.1  gdamore 		unit->hci_sco_mask |= HCI_PKT_EV5;
   1055        1.1  gdamore 
   1056        1.4   plunky 	/* XXX what do 2MBPS/3MBPS/3SLOT eSCO mean? */
   1057        1.1  gdamore 
   1058       1.22   plunky 	DPRINTFN(1, "%s: sco_mask %4.4x\n",
   1059       1.22   plunky 		device_xname(unit->hci_dev), unit->hci_sco_mask);
   1060       1.22   plunky 
   1061       1.22   plunky 	/* extended feature masks */
   1062       1.22   plunky 	if (rp.features[7] & HCI_LMP_EXTENDED_FEATURES) {
   1063       1.22   plunky 		hci_read_local_extended_features_cp cp;
   1064       1.22   plunky 
   1065       1.22   plunky 		cp.page = 0;
   1066       1.22   plunky 		hci_send_cmd(unit, HCI_CMD_READ_LOCAL_EXTENDED_FEATURES,
   1067       1.22   plunky 		    &cp, sizeof(cp));
   1068       1.22   plunky 
   1069       1.22   plunky 		return;
   1070       1.22   plunky 	}
   1071       1.22   plunky 
   1072        1.1  gdamore 	unit->hci_flags &= ~BTF_INIT_FEATURES;
   1073       1.22   plunky 	cv_broadcast(&unit->hci_init);
   1074       1.22   plunky }
   1075       1.22   plunky 
   1076       1.22   plunky /*
   1077       1.22   plunky  * process results of read_local_extended_features command_complete event
   1078       1.22   plunky  */
   1079       1.22   plunky static void
   1080       1.22   plunky hci_cmd_read_local_extended_features(struct hci_unit *unit, struct mbuf *m)
   1081       1.22   plunky {
   1082       1.22   plunky 	hci_read_local_extended_features_rp rp;
   1083       1.22   plunky 
   1084       1.23   plunky 	if (m->m_pkthdr.len < sizeof(rp))
   1085       1.23   plunky 		return;
   1086       1.23   plunky 
   1087       1.22   plunky 	m_copydata(m, 0, sizeof(rp), &rp);
   1088       1.22   plunky 	m_adj(m, sizeof(rp));
   1089       1.22   plunky 
   1090       1.22   plunky 	if (rp.status > 0)
   1091       1.22   plunky 		return;
   1092       1.22   plunky 
   1093       1.22   plunky 	if ((unit->hci_flags & BTF_INIT_FEATURES) == 0)
   1094       1.22   plunky 		return;
   1095       1.22   plunky 
   1096       1.22   plunky 	DPRINTFN(1, "%s: page %d of %d\n", device_xname(unit->hci_dev),
   1097       1.22   plunky 	    rp.page, rp.max_page);
   1098       1.22   plunky 
   1099       1.22   plunky 	switch (rp.page) {
   1100       1.22   plunky 	case 1:
   1101       1.22   plunky 		memcpy(unit->hci_feat1, rp.features, HCI_FEATURES_SIZE);
   1102       1.22   plunky 		break;
   1103        1.1  gdamore 
   1104       1.22   plunky 	case 0:	/* (already handled) */
   1105       1.22   plunky 	default:
   1106       1.22   plunky 		break;
   1107       1.22   plunky 	}
   1108       1.22   plunky 
   1109       1.22   plunky 	if (rp.page < rp.max_page) {
   1110       1.22   plunky 		hci_read_local_extended_features_cp cp;
   1111       1.22   plunky 
   1112       1.22   plunky 		cp.page = rp.page + 1;
   1113       1.22   plunky 		hci_send_cmd(unit, HCI_CMD_READ_LOCAL_EXTENDED_FEATURES,
   1114       1.22   plunky 		    &cp, sizeof(cp));
   1115       1.22   plunky 
   1116       1.22   plunky 		return;
   1117       1.22   plunky 	}
   1118       1.22   plunky 
   1119       1.22   plunky 	unit->hci_flags &= ~BTF_INIT_FEATURES;
   1120       1.18       ad 	cv_broadcast(&unit->hci_init);
   1121        1.1  gdamore }
   1122        1.1  gdamore 
   1123        1.1  gdamore /*
   1124       1.13   plunky  * process results of read_local_ver command_complete event
   1125       1.13   plunky  *
   1126       1.13   plunky  * reading local supported commands is only supported from 1.2 spec
   1127       1.13   plunky  */
   1128       1.13   plunky static void
   1129       1.13   plunky hci_cmd_read_local_ver(struct hci_unit *unit, struct mbuf *m)
   1130       1.13   plunky {
   1131       1.13   plunky 	hci_read_local_ver_rp rp;
   1132       1.13   plunky 
   1133       1.23   plunky 	if (m->m_pkthdr.len < sizeof(rp))
   1134       1.23   plunky 		return;
   1135       1.23   plunky 
   1136       1.13   plunky 	m_copydata(m, 0, sizeof(rp), &rp);
   1137       1.13   plunky 	m_adj(m, sizeof(rp));
   1138       1.13   plunky 
   1139       1.13   plunky 	if (rp.status != 0)
   1140       1.13   plunky 		return;
   1141       1.13   plunky 
   1142       1.13   plunky 	if ((unit->hci_flags & BTF_INIT_COMMANDS) == 0)
   1143       1.13   plunky 		return;
   1144       1.13   plunky 
   1145       1.13   plunky 	if (rp.hci_version < HCI_SPEC_V12) {
   1146       1.13   plunky 		unit->hci_flags &= ~BTF_INIT_COMMANDS;
   1147       1.18       ad 		cv_broadcast(&unit->hci_init);
   1148       1.13   plunky 		return;
   1149       1.13   plunky 	}
   1150       1.13   plunky 
   1151       1.13   plunky 	hci_send_cmd(unit, HCI_CMD_READ_LOCAL_COMMANDS, NULL, 0);
   1152       1.13   plunky }
   1153       1.13   plunky 
   1154       1.13   plunky /*
   1155       1.13   plunky  * process results of read_local_commands command_complete event
   1156       1.13   plunky  */
   1157       1.13   plunky static void
   1158       1.13   plunky hci_cmd_read_local_commands(struct hci_unit *unit, struct mbuf *m)
   1159       1.13   plunky {
   1160       1.13   plunky 	hci_read_local_commands_rp rp;
   1161       1.13   plunky 
   1162       1.23   plunky 	if (m->m_pkthdr.len < sizeof(rp))
   1163       1.23   plunky 		return;
   1164       1.23   plunky 
   1165       1.13   plunky 	m_copydata(m, 0, sizeof(rp), &rp);
   1166       1.13   plunky 	m_adj(m, sizeof(rp));
   1167       1.13   plunky 
   1168       1.13   plunky 	if (rp.status != 0)
   1169       1.13   plunky 		return;
   1170       1.13   plunky 
   1171       1.13   plunky 	if ((unit->hci_flags & BTF_INIT_COMMANDS) == 0)
   1172       1.13   plunky 		return;
   1173       1.13   plunky 
   1174       1.13   plunky 	unit->hci_flags &= ~BTF_INIT_COMMANDS;
   1175       1.13   plunky 	memcpy(unit->hci_cmds, rp.commands, HCI_COMMANDS_SIZE);
   1176       1.13   plunky 
   1177       1.18       ad 	cv_broadcast(&unit->hci_init);
   1178       1.13   plunky }
   1179       1.13   plunky 
   1180       1.13   plunky /*
   1181  1.23.36.1   martin  * process results of read_encryption_key_size command_complete event
   1182  1.23.36.1   martin  */
   1183  1.23.36.1   martin static void
   1184  1.23.36.1   martin hci_cmd_read_encryption_key_size(struct hci_unit *unit, struct mbuf *m)
   1185  1.23.36.1   martin {
   1186  1.23.36.1   martin 	hci_read_encryption_key_size_rp rp;
   1187  1.23.36.1   martin 	struct hci_link *link;
   1188  1.23.36.1   martin 	int err;
   1189  1.23.36.1   martin 
   1190  1.23.36.1   martin 	if (m->m_pkthdr.len < sizeof(rp))
   1191  1.23.36.1   martin 		return;
   1192  1.23.36.1   martin 
   1193  1.23.36.1   martin 	m_copydata(m, 0, sizeof(rp), &rp);
   1194  1.23.36.1   martin 	m_adj(m, sizeof(rp));
   1195  1.23.36.1   martin 
   1196  1.23.36.1   martin 	if (rp.status != 0)
   1197  1.23.36.1   martin 		return;
   1198  1.23.36.1   martin 
   1199  1.23.36.1   martin 	rp.con_handle = HCI_CON_HANDLE(le16toh(rp.con_handle));
   1200  1.23.36.1   martin 
   1201  1.23.36.1   martin 	DPRINTFN(1, "handle #%d, status=0x%x, key_size=0x%x\n",
   1202  1.23.36.1   martin 		 rp.con_handle, rp.status, rp.size);
   1203  1.23.36.1   martin 
   1204  1.23.36.1   martin 	link = hci_link_lookup_handle(unit, rp.con_handle);
   1205  1.23.36.1   martin 	if (link == NULL || link->hl_type != HCI_LINK_ACL)
   1206  1.23.36.1   martin 		return;
   1207  1.23.36.1   martin 
   1208  1.23.36.1   martin 	/*
   1209  1.23.36.1   martin 	 * if the key size is less than minimum standard, go straight to
   1210  1.23.36.1   martin 	 * linkmode as this is non-recoverable. Otherwise, we are encrypted
   1211  1.23.36.1   martin 	 * so can proceed with setmode.
   1212  1.23.36.1   martin 	 */
   1213  1.23.36.1   martin 	if (rp.status == 0) {
   1214  1.23.36.1   martin 		if (rp.size < 7) {
   1215  1.23.36.1   martin 			link->hl_flags &= ~HCI_LINK_ENCRYPT;
   1216  1.23.36.1   martin 		} else {
   1217  1.23.36.1   martin 			link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_ENCRYPT);
   1218  1.23.36.1   martin 
   1219  1.23.36.1   martin 			if (link->hl_state == HCI_LINK_WAIT_ENCRYPT)
   1220  1.23.36.1   martin 				link->hl_state = HCI_LINK_OPEN;
   1221  1.23.36.1   martin 
   1222  1.23.36.1   martin 			err = hci_acl_setmode(link);
   1223  1.23.36.1   martin 			if (err == EINPROGRESS)
   1224  1.23.36.1   martin 				return;
   1225  1.23.36.1   martin 		}
   1226  1.23.36.1   martin 	}
   1227  1.23.36.1   martin 
   1228  1.23.36.1   martin 	hci_acl_linkmode(link);
   1229  1.23.36.1   martin }
   1230  1.23.36.1   martin 
   1231  1.23.36.1   martin /*
   1232        1.1  gdamore  * process results of reset command_complete event
   1233        1.1  gdamore  *
   1234        1.1  gdamore  * This has killed all the connections, so close down anything we have left,
   1235        1.1  gdamore  * and reinitialise the unit.
   1236        1.1  gdamore  */
   1237        1.1  gdamore static void
   1238        1.1  gdamore hci_cmd_reset(struct hci_unit *unit, struct mbuf *m)
   1239        1.1  gdamore {
   1240        1.1  gdamore 	hci_reset_rp rp;
   1241        1.1  gdamore 	struct hci_link *link, *next;
   1242        1.1  gdamore 	int acl;
   1243        1.1  gdamore 
   1244       1.23   plunky 	if (m->m_pkthdr.len < sizeof(rp))
   1245       1.23   plunky 		return;
   1246       1.23   plunky 
   1247        1.1  gdamore 	m_copydata(m, 0, sizeof(rp), &rp);
   1248        1.1  gdamore 	m_adj(m, sizeof(rp));
   1249        1.1  gdamore 
   1250        1.1  gdamore 	if (rp.status != 0)
   1251        1.1  gdamore 		return;
   1252        1.1  gdamore 
   1253        1.1  gdamore 	/*
   1254        1.1  gdamore 	 * release SCO links first, since they may be holding
   1255        1.1  gdamore 	 * an ACL link reference.
   1256        1.1  gdamore 	 */
   1257        1.1  gdamore 	for (acl = 0 ; acl < 2 ; acl++) {
   1258        1.1  gdamore 		next = TAILQ_FIRST(&unit->hci_links);
   1259        1.1  gdamore 		while ((link = next) != NULL) {
   1260        1.1  gdamore 			next = TAILQ_NEXT(link, hl_next);
   1261        1.1  gdamore 			if (acl || link->hl_type != HCI_LINK_ACL)
   1262        1.1  gdamore 				hci_link_free(link, ECONNABORTED);
   1263        1.1  gdamore 		}
   1264        1.1  gdamore 	}
   1265        1.1  gdamore 
   1266        1.1  gdamore 	unit->hci_num_acl_pkts = 0;
   1267        1.1  gdamore 	unit->hci_num_sco_pkts = 0;
   1268        1.1  gdamore 
   1269        1.1  gdamore 	if (hci_send_cmd(unit, HCI_CMD_READ_BDADDR, NULL, 0))
   1270        1.1  gdamore 		return;
   1271        1.1  gdamore 
   1272        1.1  gdamore 	if (hci_send_cmd(unit, HCI_CMD_READ_BUFFER_SIZE, NULL, 0))
   1273        1.1  gdamore 		return;
   1274        1.1  gdamore 
   1275        1.1  gdamore 	if (hci_send_cmd(unit, HCI_CMD_READ_LOCAL_FEATURES, NULL, 0))
   1276        1.1  gdamore 		return;
   1277       1.13   plunky 
   1278       1.13   plunky 	if (hci_send_cmd(unit, HCI_CMD_READ_LOCAL_VER, NULL, 0))
   1279       1.13   plunky 		return;
   1280        1.1  gdamore }
   1281       1.15   plunky 
   1282       1.15   plunky /*
   1283       1.15   plunky  * process command_status event for create_con command
   1284       1.15   plunky  *
   1285       1.15   plunky  * a "Create Connection" command can sometimes fail to start for whatever
   1286       1.15   plunky  * reason and the command_status event returns failure but we get no
   1287       1.15   plunky  * indication of which connection failed (for instance in the case where
   1288       1.15   plunky  * we tried to open too many connections all at once) So, we keep a flag
   1289       1.15   plunky  * on the link to indicate pending status until the command_status event
   1290       1.15   plunky  * is returned to help us decide which needs to be failed.
   1291       1.15   plunky  *
   1292       1.16   plunky  * since created links are inserted at the tail of hci_links, we know that
   1293       1.16   plunky  * the first pending link we find will be the one that this command status
   1294       1.16   plunky  * refers to.
   1295       1.15   plunky  */
   1296       1.15   plunky static void
   1297       1.15   plunky hci_cmd_create_con(struct hci_unit *unit, uint8_t status)
   1298       1.15   plunky {
   1299       1.15   plunky 	struct hci_link *link;
   1300       1.15   plunky 
   1301       1.15   plunky 	TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
   1302       1.15   plunky 		if ((link->hl_flags & HCI_LINK_CREATE_CON) == 0)
   1303       1.15   plunky 			continue;
   1304       1.15   plunky 
   1305       1.15   plunky 		link->hl_flags &= ~HCI_LINK_CREATE_CON;
   1306       1.15   plunky 
   1307       1.15   plunky 		switch(status) {
   1308       1.15   plunky 		case 0x00:	/* success */
   1309       1.15   plunky 			break;
   1310       1.15   plunky 
   1311       1.15   plunky 		case 0x0c:	/* "Command Disallowed" */
   1312       1.15   plunky 			hci_link_free(link, EBUSY);
   1313       1.15   plunky 			break;
   1314       1.15   plunky 
   1315       1.15   plunky 		default:	/* some other trouble */
   1316       1.15   plunky 			hci_link_free(link, EPROTO);
   1317       1.15   plunky 			break;
   1318       1.15   plunky 		}
   1319       1.15   plunky 
   1320       1.15   plunky 		return;
   1321       1.15   plunky 	}
   1322       1.15   plunky }
   1323