Home | History | Annotate | Line # | Download | only in netbt
hci_event.c revision 1.9.6.1
      1  1.9.6.1      mjf /*	$NetBSD: hci_event.c,v 1.9.6.1 2007/11/19 00:49:07 mjf 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.9.6.1      mjf __KERNEL_RCSID(0, "$NetBSD: hci_event.c,v 1.9.6.1 2007/11/19 00:49:07 mjf 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.1  gdamore static void hci_event_command_status(struct hci_unit *, struct mbuf *);
     50      1.1  gdamore static void hci_event_command_compl(struct hci_unit *, struct mbuf *);
     51      1.1  gdamore static void hci_event_con_compl(struct hci_unit *, struct mbuf *);
     52      1.1  gdamore static void hci_event_discon_compl(struct hci_unit *, struct mbuf *);
     53      1.1  gdamore static void hci_event_con_req(struct hci_unit *, struct mbuf *);
     54      1.1  gdamore static void hci_event_num_compl_pkts(struct hci_unit *, struct mbuf *);
     55      1.6   plunky static void hci_event_auth_compl(struct hci_unit *, struct mbuf *);
     56      1.6   plunky static void hci_event_encryption_change(struct hci_unit *, struct mbuf *);
     57      1.6   plunky static void hci_event_change_con_link_key_compl(struct hci_unit *, struct mbuf *);
     58      1.9   plunky static void hci_event_read_clock_offset_compl(struct hci_unit *, struct mbuf *);
     59      1.1  gdamore static void hci_cmd_read_bdaddr(struct hci_unit *, struct mbuf *);
     60      1.1  gdamore static void hci_cmd_read_buffer_size(struct hci_unit *, struct mbuf *);
     61      1.1  gdamore static void hci_cmd_read_local_features(struct hci_unit *, struct mbuf *);
     62      1.1  gdamore static void hci_cmd_reset(struct hci_unit *, struct mbuf *);
     63      1.1  gdamore 
     64      1.1  gdamore #ifdef BLUETOOTH_DEBUG
     65      1.5   plunky int bluetooth_debug;
     66      1.1  gdamore 
     67      1.1  gdamore static const char *hci_eventnames[] = {
     68      1.1  gdamore /* 0x00 */ "NULL",
     69      1.1  gdamore /* 0x01 */ "INQUIRY COMPLETE",
     70      1.1  gdamore /* 0x02 */ "INQUIRY RESULT",
     71      1.1  gdamore /* 0x03 */ "CONN COMPLETE",
     72      1.1  gdamore /* 0x04 */ "CONN REQ",
     73      1.1  gdamore /* 0x05 */ "DISCONN COMPLETE",
     74      1.1  gdamore /* 0x06 */ "AUTH COMPLETE",
     75      1.1  gdamore /* 0x07 */ "REMOTE NAME REQ COMPLETE",
     76      1.1  gdamore /* 0x08 */ "ENCRYPTION CHANGE",
     77      1.1  gdamore /* 0x09 */ "CHANGE CONN LINK KEY COMPLETE",
     78      1.1  gdamore /* 0x0a */ "MASTER LINK KEY COMPLETE",
     79      1.1  gdamore /* 0x0b */ "READ REMOTE FEATURES COMPLETE",
     80      1.1  gdamore /* 0x0c */ "READ REMOTE VERSION INFO COMPLETE",
     81      1.1  gdamore /* 0x0d */ "QoS SETUP COMPLETE",
     82      1.1  gdamore /* 0x0e */ "COMMAND COMPLETE",
     83      1.1  gdamore /* 0x0f */ "COMMAND STATUS",
     84      1.1  gdamore /* 0x10 */ "HARDWARE ERROR",
     85      1.1  gdamore /* 0x11 */ "FLUSH OCCUR",
     86      1.1  gdamore /* 0x12 */ "ROLE CHANGE",
     87      1.1  gdamore /* 0x13 */ "NUM COMPLETED PACKETS",
     88      1.1  gdamore /* 0x14 */ "MODE CHANGE",
     89      1.1  gdamore /* 0x15 */ "RETURN LINK KEYS",
     90      1.1  gdamore /* 0x16 */ "PIN CODE REQ",
     91      1.1  gdamore /* 0x17 */ "LINK KEY REQ",
     92      1.1  gdamore /* 0x18 */ "LINK KEY NOTIFICATION",
     93      1.1  gdamore /* 0x19 */ "LOOPBACK COMMAND",
     94      1.1  gdamore /* 0x1a */ "DATA BUFFER OVERFLOW",
     95      1.1  gdamore /* 0x1b */ "MAX SLOT CHANGE",
     96      1.1  gdamore /* 0x1c */ "READ CLOCK OFFSET COMPLETE",
     97      1.1  gdamore /* 0x1d */ "CONN PKT TYPE CHANGED",
     98      1.1  gdamore /* 0x1e */ "QOS VIOLATION",
     99      1.1  gdamore /* 0x1f */ "PAGE SCAN MODE CHANGE",
    100      1.1  gdamore /* 0x20 */ "PAGE SCAN REP MODE CHANGE",
    101      1.1  gdamore /* 0x21 */ "FLOW SPECIFICATION COMPLETE",
    102      1.1  gdamore /* 0x22 */ "RSSI RESULT",
    103      1.1  gdamore /* 0x23 */ "READ REMOTE EXT FEATURES"
    104      1.1  gdamore };
    105      1.1  gdamore 
    106      1.1  gdamore static const char *
    107      1.1  gdamore hci_eventstr(unsigned int event)
    108      1.1  gdamore {
    109      1.1  gdamore 
    110      1.1  gdamore 	if (event < (sizeof(hci_eventnames) / sizeof(*hci_eventnames)))
    111      1.1  gdamore 		return hci_eventnames[event];
    112      1.1  gdamore 
    113      1.1  gdamore 	switch (event) {
    114      1.1  gdamore 	case HCI_EVENT_SCO_CON_COMPL:	/* 0x2c */
    115      1.1  gdamore 		return "SCO CON COMPLETE";
    116      1.1  gdamore 
    117      1.1  gdamore 	case HCI_EVENT_SCO_CON_CHANGED:	/* 0x2d */
    118      1.1  gdamore 		return "SCO CON CHANGED";
    119      1.1  gdamore 
    120      1.1  gdamore 	case HCI_EVENT_BT_LOGO:		/* 0xfe */
    121      1.1  gdamore 		return "BT_LOGO";
    122      1.1  gdamore 
    123      1.1  gdamore 	case HCI_EVENT_VENDOR:		/* 0xff */
    124      1.1  gdamore 		return "VENDOR";
    125      1.1  gdamore 	}
    126      1.1  gdamore 
    127      1.1  gdamore 	return "UNRECOGNISED";
    128      1.1  gdamore }
    129      1.1  gdamore #endif	/* BLUETOOTH_DEBUG */
    130      1.1  gdamore 
    131      1.1  gdamore /*
    132      1.1  gdamore  * process HCI Events
    133      1.1  gdamore  *
    134      1.1  gdamore  * We will free the mbuf at the end, no need for any sub
    135      1.1  gdamore  * functions to handle that. We kind of assume that the
    136      1.1  gdamore  * device sends us valid events.
    137      1.1  gdamore  */
    138      1.1  gdamore void
    139      1.1  gdamore hci_event(struct mbuf *m, struct hci_unit *unit)
    140      1.1  gdamore {
    141      1.1  gdamore 	hci_event_hdr_t hdr;
    142      1.1  gdamore 
    143      1.1  gdamore 	KASSERT(m->m_flags & M_PKTHDR);
    144      1.1  gdamore 
    145      1.1  gdamore 	KASSERT(m->m_pkthdr.len >= sizeof(hdr));
    146      1.1  gdamore 	m_copydata(m, 0, sizeof(hdr), &hdr);
    147      1.1  gdamore 	m_adj(m, sizeof(hdr));
    148      1.1  gdamore 
    149      1.1  gdamore 	KASSERT(hdr.type == HCI_EVENT_PKT);
    150      1.1  gdamore 
    151  1.9.6.1      mjf 	DPRINTFN(1, "(%s) event %s\n",
    152  1.9.6.1      mjf 	    device_xname(unit->hci_dev), hci_eventstr(hdr.event));
    153      1.1  gdamore 
    154      1.1  gdamore 	switch(hdr.event) {
    155      1.1  gdamore 	case HCI_EVENT_COMMAND_STATUS:
    156      1.1  gdamore 		hci_event_command_status(unit, m);
    157      1.1  gdamore 		break;
    158      1.1  gdamore 
    159      1.1  gdamore 	case HCI_EVENT_COMMAND_COMPL:
    160      1.1  gdamore 		hci_event_command_compl(unit, m);
    161      1.1  gdamore 		break;
    162      1.1  gdamore 
    163      1.1  gdamore 	case HCI_EVENT_NUM_COMPL_PKTS:
    164      1.1  gdamore 		hci_event_num_compl_pkts(unit, m);
    165      1.1  gdamore 		break;
    166      1.1  gdamore 
    167      1.1  gdamore 	case HCI_EVENT_INQUIRY_RESULT:
    168      1.1  gdamore 		hci_event_inquiry_result(unit, m);
    169      1.1  gdamore 		break;
    170      1.1  gdamore 
    171      1.8   plunky 	case HCI_EVENT_RSSI_RESULT:
    172      1.8   plunky 		hci_event_rssi_result(unit, m);
    173      1.8   plunky 		break;
    174      1.8   plunky 
    175      1.1  gdamore 	case HCI_EVENT_CON_COMPL:
    176      1.1  gdamore 		hci_event_con_compl(unit, m);
    177      1.1  gdamore 		break;
    178      1.1  gdamore 
    179      1.1  gdamore 	case HCI_EVENT_DISCON_COMPL:
    180      1.1  gdamore 		hci_event_discon_compl(unit, m);
    181      1.1  gdamore 		break;
    182      1.1  gdamore 
    183      1.1  gdamore 	case HCI_EVENT_CON_REQ:
    184      1.1  gdamore 		hci_event_con_req(unit, m);
    185      1.1  gdamore 		break;
    186      1.1  gdamore 
    187      1.6   plunky 	case HCI_EVENT_AUTH_COMPL:
    188      1.6   plunky 		hci_event_auth_compl(unit, m);
    189      1.6   plunky 		break;
    190      1.6   plunky 
    191      1.6   plunky 	case HCI_EVENT_ENCRYPTION_CHANGE:
    192      1.6   plunky 		hci_event_encryption_change(unit, m);
    193      1.6   plunky 		break;
    194      1.6   plunky 
    195      1.6   plunky 	case HCI_EVENT_CHANGE_CON_LINK_KEY_COMPL:
    196      1.6   plunky 		hci_event_change_con_link_key_compl(unit, m);
    197      1.6   plunky 		break;
    198      1.6   plunky 
    199      1.9   plunky 	case HCI_EVENT_READ_CLOCK_OFFSET_COMPL:
    200      1.9   plunky 		hci_event_read_clock_offset_compl(unit, m);
    201      1.9   plunky 		break;
    202      1.9   plunky 
    203      1.1  gdamore 	case HCI_EVENT_SCO_CON_COMPL:
    204      1.1  gdamore 	case HCI_EVENT_INQUIRY_COMPL:
    205      1.1  gdamore 	case HCI_EVENT_REMOTE_NAME_REQ_COMPL:
    206      1.1  gdamore 	case HCI_EVENT_MASTER_LINK_KEY_COMPL:
    207      1.1  gdamore 	case HCI_EVENT_READ_REMOTE_FEATURES_COMPL:
    208      1.1  gdamore 	case HCI_EVENT_READ_REMOTE_VER_INFO_COMPL:
    209      1.1  gdamore 	case HCI_EVENT_QOS_SETUP_COMPL:
    210      1.1  gdamore 	case HCI_EVENT_HARDWARE_ERROR:
    211      1.1  gdamore 	case HCI_EVENT_FLUSH_OCCUR:
    212      1.1  gdamore 	case HCI_EVENT_ROLE_CHANGE:
    213      1.1  gdamore 	case HCI_EVENT_MODE_CHANGE:
    214      1.1  gdamore 	case HCI_EVENT_RETURN_LINK_KEYS:
    215      1.1  gdamore 	case HCI_EVENT_PIN_CODE_REQ:
    216      1.1  gdamore 	case HCI_EVENT_LINK_KEY_REQ:
    217      1.1  gdamore 	case HCI_EVENT_LINK_KEY_NOTIFICATION:
    218      1.1  gdamore 	case HCI_EVENT_LOOPBACK_COMMAND:
    219      1.1  gdamore 	case HCI_EVENT_DATA_BUFFER_OVERFLOW:
    220      1.1  gdamore 	case HCI_EVENT_MAX_SLOT_CHANGE:
    221      1.1  gdamore 	case HCI_EVENT_CON_PKT_TYPE_CHANGED:
    222      1.1  gdamore 	case HCI_EVENT_QOS_VIOLATION:
    223      1.1  gdamore 	case HCI_EVENT_PAGE_SCAN_MODE_CHANGE:
    224      1.1  gdamore 	case HCI_EVENT_PAGE_SCAN_REP_MODE_CHANGE:
    225      1.1  gdamore 	case HCI_EVENT_FLOW_SPECIFICATION_COMPL:
    226      1.1  gdamore 	case HCI_EVENT_READ_REMOTE_EXTENDED_FEATURES:
    227      1.1  gdamore 	case HCI_EVENT_SCO_CON_CHANGED:
    228      1.1  gdamore 	case HCI_EVENT_BT_LOGO:
    229      1.1  gdamore 	case HCI_EVENT_VENDOR:
    230      1.1  gdamore 		break;
    231      1.1  gdamore 
    232      1.1  gdamore 	default:
    233      1.1  gdamore 		UNKNOWN(hdr.event);
    234      1.1  gdamore 		break;
    235      1.1  gdamore 	}
    236      1.1  gdamore 
    237      1.1  gdamore 	m_freem(m);
    238      1.1  gdamore }
    239      1.1  gdamore 
    240      1.1  gdamore /*
    241      1.1  gdamore  * Command Status
    242      1.1  gdamore  *
    243      1.1  gdamore  * Update our record of num_cmd_pkts then post-process any pending commands
    244      1.1  gdamore  * and optionally restart cmd output on the unit.
    245      1.1  gdamore  */
    246      1.1  gdamore static void
    247      1.1  gdamore hci_event_command_status(struct hci_unit *unit, struct mbuf *m)
    248      1.1  gdamore {
    249      1.1  gdamore 	hci_command_status_ep ep;
    250      1.1  gdamore 
    251      1.1  gdamore 	KASSERT(m->m_pkthdr.len >= sizeof(ep));
    252      1.1  gdamore 	m_copydata(m, 0, sizeof(ep), &ep);
    253      1.1  gdamore 	m_adj(m, sizeof(ep));
    254      1.1  gdamore 
    255      1.6   plunky 	DPRINTFN(1, "(%s) opcode (%03x|%04x) status = 0x%x num_cmd_pkts = %d\n",
    256  1.9.6.1      mjf 		device_xname(unit->hci_dev),
    257      1.1  gdamore 		HCI_OGF(le16toh(ep.opcode)), HCI_OCF(le16toh(ep.opcode)),
    258      1.6   plunky 		ep.status,
    259      1.1  gdamore 		ep.num_cmd_pkts);
    260      1.1  gdamore 
    261      1.1  gdamore 	unit->hci_num_cmd_pkts = ep.num_cmd_pkts;
    262      1.1  gdamore 
    263      1.1  gdamore 	/*
    264      1.1  gdamore 	 * post processing of pending commands
    265      1.1  gdamore 	 */
    266      1.1  gdamore 	switch(le16toh(ep.opcode)) {
    267      1.1  gdamore 	default:
    268      1.1  gdamore 		break;
    269      1.1  gdamore 	}
    270      1.1  gdamore 
    271      1.1  gdamore 	while (unit->hci_num_cmd_pkts > 0 && MBUFQ_FIRST(&unit->hci_cmdwait)) {
    272      1.1  gdamore 		MBUFQ_DEQUEUE(&unit->hci_cmdwait, m);
    273      1.1  gdamore 		hci_output_cmd(unit, m);
    274      1.1  gdamore 	}
    275      1.1  gdamore }
    276      1.1  gdamore 
    277      1.1  gdamore /*
    278      1.1  gdamore  * Command Complete
    279      1.1  gdamore  *
    280      1.1  gdamore  * Update our record of num_cmd_pkts then handle the completed command,
    281      1.1  gdamore  * and optionally restart cmd output on the unit.
    282      1.1  gdamore  */
    283      1.1  gdamore static void
    284      1.1  gdamore hci_event_command_compl(struct hci_unit *unit, struct mbuf *m)
    285      1.1  gdamore {
    286      1.1  gdamore 	hci_command_compl_ep ep;
    287      1.1  gdamore 
    288      1.1  gdamore 	KASSERT(m->m_pkthdr.len >= sizeof(ep));
    289      1.1  gdamore 	m_copydata(m, 0, sizeof(ep), &ep);
    290      1.1  gdamore 	m_adj(m, sizeof(ep));
    291      1.1  gdamore 
    292      1.1  gdamore 	DPRINTFN(1, "(%s) opcode (%03x|%04x) num_cmd_pkts = %d\n",
    293  1.9.6.1      mjf 		device_xname(unit->hci_dev),
    294      1.1  gdamore 		HCI_OGF(le16toh(ep.opcode)), HCI_OCF(le16toh(ep.opcode)),
    295      1.1  gdamore 		ep.num_cmd_pkts);
    296      1.1  gdamore 
    297      1.1  gdamore 	unit->hci_num_cmd_pkts = ep.num_cmd_pkts;
    298      1.1  gdamore 
    299      1.1  gdamore 	/*
    300      1.1  gdamore 	 * post processing of completed commands
    301      1.1  gdamore 	 */
    302      1.1  gdamore 	switch(le16toh(ep.opcode)) {
    303      1.1  gdamore 	case HCI_CMD_READ_BDADDR:
    304      1.1  gdamore 		hci_cmd_read_bdaddr(unit, m);
    305      1.1  gdamore 		break;
    306      1.1  gdamore 
    307      1.1  gdamore 	case HCI_CMD_READ_BUFFER_SIZE:
    308      1.1  gdamore 		hci_cmd_read_buffer_size(unit, m);
    309      1.1  gdamore 		break;
    310      1.1  gdamore 
    311      1.1  gdamore 	case HCI_CMD_READ_LOCAL_FEATURES:
    312      1.1  gdamore 		hci_cmd_read_local_features(unit, m);
    313      1.1  gdamore 		break;
    314      1.1  gdamore 
    315      1.1  gdamore 	case HCI_CMD_RESET:
    316      1.1  gdamore 		hci_cmd_reset(unit, m);
    317      1.1  gdamore 		break;
    318      1.1  gdamore 
    319      1.1  gdamore 	default:
    320      1.1  gdamore 		break;
    321      1.1  gdamore 	}
    322      1.1  gdamore 
    323      1.1  gdamore 	while (unit->hci_num_cmd_pkts > 0 && MBUFQ_FIRST(&unit->hci_cmdwait)) {
    324      1.1  gdamore 		MBUFQ_DEQUEUE(&unit->hci_cmdwait, m);
    325      1.1  gdamore 		hci_output_cmd(unit, m);
    326      1.1  gdamore 	}
    327      1.1  gdamore }
    328      1.1  gdamore 
    329      1.1  gdamore /*
    330      1.1  gdamore  * Number of Completed Packets
    331      1.1  gdamore  *
    332      1.1  gdamore  * This is sent periodically by the Controller telling us how many
    333      1.1  gdamore  * buffers are now freed up and which handle was using them. From
    334      1.1  gdamore  * this we determine which type of buffer it was and add the qty
    335      1.1  gdamore  * back into the relevant packet counter, then restart output on
    336      1.1  gdamore  * links that have halted.
    337      1.1  gdamore  */
    338      1.1  gdamore static void
    339      1.1  gdamore hci_event_num_compl_pkts(struct hci_unit *unit, struct mbuf *m)
    340      1.1  gdamore {
    341      1.1  gdamore 	hci_num_compl_pkts_ep ep;
    342      1.1  gdamore 	struct hci_link *link, *next;
    343      1.1  gdamore 	uint16_t handle, num;
    344      1.1  gdamore 	int num_acl = 0, num_sco = 0;
    345      1.1  gdamore 
    346      1.1  gdamore 	KASSERT(m->m_pkthdr.len >= sizeof(ep));
    347      1.1  gdamore 	m_copydata(m, 0, sizeof(ep), &ep);
    348      1.1  gdamore 	m_adj(m, sizeof(ep));
    349      1.1  gdamore 
    350      1.1  gdamore 	while (ep.num_con_handles--) {
    351      1.7   plunky 		m_copydata(m, 0, sizeof(handle), &handle);
    352      1.1  gdamore 		m_adj(m, sizeof(handle));
    353      1.1  gdamore 		handle = le16toh(handle);
    354      1.1  gdamore 
    355      1.7   plunky 		m_copydata(m, 0, sizeof(num), &num);
    356      1.1  gdamore 		m_adj(m, sizeof(num));
    357      1.1  gdamore 		num = le16toh(num);
    358      1.1  gdamore 
    359      1.1  gdamore 		link = hci_link_lookup_handle(unit, handle);
    360      1.1  gdamore 		if (link) {
    361      1.1  gdamore 			if (link->hl_type == HCI_LINK_ACL) {
    362      1.1  gdamore 				num_acl += num;
    363      1.1  gdamore 				hci_acl_complete(link, num);
    364      1.1  gdamore 			} else {
    365      1.1  gdamore 				num_sco += num;
    366      1.1  gdamore 				hci_sco_complete(link, num);
    367      1.1  gdamore 			}
    368      1.1  gdamore 		} else {
    369      1.4   plunky 			/* XXX need to issue Read_Buffer_Size or Reset? */
    370  1.9.6.1      mjf 			aprint_error_dev(unit->hci_dev,
    371  1.9.6.1      mjf 			    "unknown handle %d! (losing track of %d packet buffer%s)\n",
    372  1.9.6.1      mjf 			    handle, num, (num == 1 ? "" : "s"));
    373      1.1  gdamore 		}
    374      1.1  gdamore 	}
    375      1.1  gdamore 
    376      1.1  gdamore 	/*
    377      1.1  gdamore 	 * Move up any queued packets. When a link has sent data, it will move
    378      1.1  gdamore 	 * to the back of the queue - technically then if a link had something
    379      1.1  gdamore 	 * to send and there were still buffers available it could get started
    380      1.1  gdamore 	 * twice but it seemed more important to to handle higher loads fairly
    381      1.1  gdamore 	 * than worry about wasting cycles when we are not busy.
    382      1.1  gdamore 	 */
    383      1.1  gdamore 
    384      1.1  gdamore 	unit->hci_num_acl_pkts += num_acl;
    385      1.1  gdamore 	unit->hci_num_sco_pkts += num_sco;
    386      1.1  gdamore 
    387      1.1  gdamore 	link = TAILQ_FIRST(&unit->hci_links);
    388      1.1  gdamore 	while (link && (unit->hci_num_acl_pkts > 0 || unit->hci_num_sco_pkts > 0)) {
    389      1.1  gdamore 		next = TAILQ_NEXT(link, hl_next);
    390      1.1  gdamore 
    391      1.1  gdamore 		if (link->hl_type == HCI_LINK_ACL) {
    392      1.1  gdamore 			if (unit->hci_num_acl_pkts > 0 && link->hl_txqlen > 0)
    393      1.1  gdamore 				hci_acl_start(link);
    394      1.1  gdamore 		} else {
    395      1.1  gdamore 			if (unit->hci_num_sco_pkts > 0 && link->hl_txqlen > 0)
    396      1.1  gdamore 				hci_sco_start(link);
    397      1.1  gdamore 		}
    398      1.1  gdamore 
    399      1.1  gdamore 		link = next;
    400      1.1  gdamore 	}
    401      1.1  gdamore }
    402      1.1  gdamore 
    403      1.1  gdamore /*
    404      1.1  gdamore  * Inquiry Result
    405      1.1  gdamore  *
    406      1.1  gdamore  * keep a note of devices seen, so we know which unit to use
    407      1.1  gdamore  * on outgoing connections
    408      1.1  gdamore  */
    409      1.1  gdamore static void
    410      1.1  gdamore hci_event_inquiry_result(struct hci_unit *unit, struct mbuf *m)
    411      1.1  gdamore {
    412      1.1  gdamore 	hci_inquiry_result_ep ep;
    413      1.8   plunky 	hci_inquiry_response ir;
    414      1.1  gdamore 	struct hci_memo *memo;
    415      1.1  gdamore 
    416      1.1  gdamore 	KASSERT(m->m_pkthdr.len >= sizeof(ep));
    417      1.1  gdamore 	m_copydata(m, 0, sizeof(ep), &ep);
    418      1.1  gdamore 	m_adj(m, sizeof(ep));
    419      1.1  gdamore 
    420      1.1  gdamore 	DPRINTFN(1, "%d response%s\n", ep.num_responses,
    421      1.1  gdamore 				(ep.num_responses == 1 ? "" : "s"));
    422      1.1  gdamore 
    423      1.1  gdamore 	while(ep.num_responses--) {
    424      1.9   plunky 		KASSERT(m->m_pkthdr.len >= sizeof(ir));
    425      1.9   plunky 		m_copydata(m, 0, sizeof(ir), &ir);
    426      1.9   plunky 		m_adj(m, sizeof(ir));
    427      1.1  gdamore 
    428      1.1  gdamore 		DPRINTFN(1, "bdaddr %02x:%02x:%02x:%02x:%02x:%02x\n",
    429      1.9   plunky 			ir.bdaddr.b[5], ir.bdaddr.b[4], ir.bdaddr.b[3],
    430      1.9   plunky 			ir.bdaddr.b[2], ir.bdaddr.b[1], ir.bdaddr.b[0]);
    431      1.1  gdamore 
    432      1.9   plunky 		memo = hci_memo_new(unit, &ir.bdaddr);
    433      1.9   plunky 		if (memo != NULL) {
    434      1.9   plunky 			memo->page_scan_rep_mode = ir.page_scan_rep_mode;
    435      1.9   plunky 			memo->page_scan_mode = ir.page_scan_mode;
    436      1.9   plunky 			memo->clock_offset = ir.clock_offset;
    437      1.1  gdamore 		}
    438      1.8   plunky 	}
    439      1.8   plunky }
    440      1.8   plunky 
    441      1.8   plunky /*
    442      1.8   plunky  * Inquiry Result with RSSI
    443      1.8   plunky  *
    444      1.8   plunky  * as above but different packet when RSSI result is enabled
    445      1.8   plunky  */
    446      1.8   plunky static void
    447      1.8   plunky hci_event_rssi_result(struct hci_unit *unit, struct mbuf *m)
    448      1.8   plunky {
    449      1.8   plunky 	hci_rssi_result_ep ep;
    450      1.8   plunky 	hci_rssi_response rr;
    451      1.8   plunky 	struct hci_memo *memo;
    452      1.8   plunky 
    453      1.8   plunky 	KASSERT(m->m_pkthdr.len >= sizeof(ep));
    454      1.8   plunky 	m_copydata(m, 0, sizeof(ep), &ep);
    455      1.8   plunky 	m_adj(m, sizeof(ep));
    456      1.8   plunky 
    457      1.8   plunky 	DPRINTFN(1, "%d response%s\n", ep.num_responses,
    458      1.8   plunky 				(ep.num_responses == 1 ? "" : "s"));
    459      1.8   plunky 
    460      1.8   plunky 	while(ep.num_responses--) {
    461      1.9   plunky 		KASSERT(m->m_pkthdr.len >= sizeof(rr));
    462      1.9   plunky 		m_copydata(m, 0, sizeof(rr), &rr);
    463      1.9   plunky 		m_adj(m, sizeof(rr));
    464      1.2   plunky 
    465      1.8   plunky 		DPRINTFN(1, "bdaddr %02x:%02x:%02x:%02x:%02x:%02x\n",
    466      1.9   plunky 			rr.bdaddr.b[5], rr.bdaddr.b[4], rr.bdaddr.b[3],
    467      1.9   plunky 			rr.bdaddr.b[2], rr.bdaddr.b[1], rr.bdaddr.b[0]);
    468      1.8   plunky 
    469      1.9   plunky 		memo = hci_memo_new(unit, &rr.bdaddr);
    470      1.9   plunky 		if (memo != NULL) {
    471      1.9   plunky 			memo->page_scan_rep_mode = rr.page_scan_rep_mode;
    472      1.9   plunky 			memo->page_scan_mode = 0;
    473      1.9   plunky 			memo->clock_offset = rr.clock_offset;
    474      1.8   plunky 		}
    475      1.1  gdamore 	}
    476      1.1  gdamore }
    477      1.1  gdamore 
    478      1.1  gdamore /*
    479      1.1  gdamore  * Connection Complete
    480      1.1  gdamore  *
    481      1.1  gdamore  * Sent to us when a connection is made. If there is no link
    482      1.1  gdamore  * structure already allocated for this, we must have changed
    483      1.1  gdamore  * our mind, so just disconnect.
    484      1.1  gdamore  */
    485      1.1  gdamore static void
    486      1.1  gdamore hci_event_con_compl(struct hci_unit *unit, struct mbuf *m)
    487      1.1  gdamore {
    488      1.1  gdamore 	hci_con_compl_ep ep;
    489      1.1  gdamore 	hci_write_link_policy_settings_cp cp;
    490      1.1  gdamore 	struct hci_link *link;
    491      1.1  gdamore 	int err;
    492      1.1  gdamore 
    493      1.1  gdamore 	KASSERT(m->m_pkthdr.len >= sizeof(ep));
    494      1.1  gdamore 	m_copydata(m, 0, sizeof(ep), &ep);
    495      1.1  gdamore 	m_adj(m, sizeof(ep));
    496      1.1  gdamore 
    497      1.1  gdamore 	DPRINTFN(1, "(%s) %s connection complete for "
    498      1.1  gdamore 		"%02x:%02x:%02x:%02x:%02x:%02x status %#x\n",
    499  1.9.6.1      mjf 		device_xname(unit->hci_dev),
    500      1.1  gdamore 		(ep.link_type == HCI_LINK_ACL ? "ACL" : "SCO"),
    501      1.1  gdamore 		ep.bdaddr.b[5], ep.bdaddr.b[4], ep.bdaddr.b[3],
    502      1.1  gdamore 		ep.bdaddr.b[2], ep.bdaddr.b[1], ep.bdaddr.b[0],
    503      1.1  gdamore 		ep.status);
    504      1.1  gdamore 
    505      1.1  gdamore 	link = hci_link_lookup_bdaddr(unit, &ep.bdaddr, ep.link_type);
    506      1.1  gdamore 
    507      1.1  gdamore 	if (ep.status) {
    508      1.1  gdamore 		if (link != NULL) {
    509      1.1  gdamore 			switch (ep.status) {
    510      1.1  gdamore 			case 0x04: /* "Page Timeout" */
    511      1.1  gdamore 				err = EHOSTDOWN;
    512      1.1  gdamore 				break;
    513      1.1  gdamore 
    514      1.1  gdamore 			case 0x08: /* "Connection Timed Out" */
    515      1.1  gdamore 				err = ETIMEDOUT;
    516      1.1  gdamore 				break;
    517      1.1  gdamore 
    518      1.1  gdamore 			case 0x16: /* "Connection Terminated by Local Host" */
    519      1.1  gdamore 				err = 0;
    520      1.1  gdamore 				break;
    521      1.1  gdamore 
    522      1.1  gdamore 			default:
    523      1.1  gdamore 				err = ECONNREFUSED;
    524      1.1  gdamore 				break;
    525      1.1  gdamore 			}
    526      1.1  gdamore 
    527      1.1  gdamore 			hci_link_free(link, err);
    528      1.1  gdamore 		}
    529      1.1  gdamore 
    530      1.1  gdamore 		return;
    531      1.1  gdamore 	}
    532      1.1  gdamore 
    533      1.1  gdamore 	if (link == NULL) {
    534      1.1  gdamore 		hci_discon_cp dp;
    535      1.1  gdamore 
    536      1.1  gdamore 		dp.con_handle = ep.con_handle;
    537      1.1  gdamore 		dp.reason = 0x13; /* "Remote User Terminated Connection" */
    538      1.1  gdamore 
    539      1.1  gdamore 		hci_send_cmd(unit, HCI_CMD_DISCONNECT, &dp, sizeof(dp));
    540      1.1  gdamore 		return;
    541      1.1  gdamore 	}
    542      1.1  gdamore 
    543      1.6   plunky 	/* XXX could check auth_enable here */
    544      1.6   plunky 
    545      1.6   plunky 	if (ep.encryption_mode)
    546      1.6   plunky 		link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_ENCRYPT);
    547      1.6   plunky 
    548      1.1  gdamore 	link->hl_state = HCI_LINK_OPEN;
    549      1.1  gdamore 	link->hl_handle = HCI_CON_HANDLE(le16toh(ep.con_handle));
    550      1.1  gdamore 
    551      1.1  gdamore 	if (ep.link_type == HCI_LINK_ACL) {
    552      1.1  gdamore 		cp.con_handle = ep.con_handle;
    553      1.1  gdamore 		cp.settings = htole16(unit->hci_link_policy);
    554      1.1  gdamore 		err = hci_send_cmd(unit, HCI_CMD_WRITE_LINK_POLICY_SETTINGS,
    555      1.1  gdamore 						&cp, sizeof(cp));
    556      1.1  gdamore 		if (err)
    557  1.9.6.1      mjf 			aprint_error_dev(unit->hci_dev,
    558  1.9.6.1      mjf 			    "Warning, could not write link policy\n");
    559      1.1  gdamore 
    560      1.9   plunky 		err = hci_send_cmd(unit, HCI_CMD_READ_CLOCK_OFFSET,
    561      1.9   plunky 				    &cp.con_handle, sizeof(cp.con_handle));
    562      1.9   plunky 		if (err)
    563  1.9.6.1      mjf 			aprint_error_dev(unit->hci_dev,
    564  1.9.6.1      mjf 			    "Warning, could not read clock offset\n");
    565      1.9   plunky 
    566      1.6   plunky 		err = hci_acl_setmode(link);
    567      1.6   plunky 		if (err == EINPROGRESS)
    568      1.6   plunky 			return;
    569      1.6   plunky 
    570      1.6   plunky 		hci_acl_linkmode(link);
    571      1.1  gdamore 	} else {
    572      1.1  gdamore 		(*link->hl_sco->sp_proto->connected)(link->hl_sco->sp_upper);
    573      1.1  gdamore 	}
    574      1.1  gdamore }
    575      1.1  gdamore 
    576      1.1  gdamore /*
    577      1.1  gdamore  * Disconnection Complete
    578      1.1  gdamore  *
    579      1.1  gdamore  * This is sent in response to a disconnection request, but also if
    580      1.1  gdamore  * the remote device goes out of range.
    581      1.1  gdamore  */
    582      1.1  gdamore static void
    583      1.1  gdamore hci_event_discon_compl(struct hci_unit *unit, struct mbuf *m)
    584      1.1  gdamore {
    585      1.1  gdamore 	hci_discon_compl_ep ep;
    586      1.1  gdamore 	struct hci_link *link;
    587      1.1  gdamore 
    588      1.1  gdamore 	KASSERT(m->m_pkthdr.len >= sizeof(ep));
    589      1.1  gdamore 	m_copydata(m, 0, sizeof(ep), &ep);
    590      1.1  gdamore 	m_adj(m, sizeof(ep));
    591      1.1  gdamore 
    592      1.1  gdamore 	ep.con_handle = le16toh(ep.con_handle);
    593      1.1  gdamore 
    594      1.1  gdamore 	DPRINTFN(1, "handle #%d, status=0x%x\n", ep.con_handle, ep.status);
    595      1.1  gdamore 
    596      1.1  gdamore 	link = hci_link_lookup_handle(unit, HCI_CON_HANDLE(ep.con_handle));
    597      1.1  gdamore 	if (link)
    598      1.1  gdamore 		hci_link_free(link, ENOLINK);
    599      1.1  gdamore }
    600      1.1  gdamore 
    601      1.1  gdamore /*
    602      1.1  gdamore  * Connect Request
    603      1.1  gdamore  *
    604      1.1  gdamore  * We check upstream for appropriate listeners and accept connections
    605      1.1  gdamore  * that are wanted.
    606      1.1  gdamore  */
    607      1.1  gdamore static void
    608      1.1  gdamore hci_event_con_req(struct hci_unit *unit, struct mbuf *m)
    609      1.1  gdamore {
    610      1.1  gdamore 	hci_con_req_ep ep;
    611      1.1  gdamore 	hci_accept_con_cp ap;
    612      1.1  gdamore 	hci_reject_con_cp rp;
    613      1.1  gdamore 	struct hci_link *link;
    614      1.1  gdamore 
    615      1.1  gdamore 	KASSERT(m->m_pkthdr.len >= sizeof(ep));
    616      1.1  gdamore 	m_copydata(m, 0, sizeof(ep), &ep);
    617      1.1  gdamore 	m_adj(m, sizeof(ep));
    618      1.1  gdamore 
    619      1.1  gdamore 	DPRINTFN(1, "bdaddr %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x "
    620      1.1  gdamore 		"class %2.2x%2.2x%2.2x type %s\n",
    621      1.1  gdamore 		ep.bdaddr.b[5], ep.bdaddr.b[4], ep.bdaddr.b[3],
    622      1.1  gdamore 		ep.bdaddr.b[2], ep.bdaddr.b[1], ep.bdaddr.b[0],
    623      1.1  gdamore 		ep.uclass[0], ep.uclass[1], ep.uclass[2],
    624      1.1  gdamore 		ep.link_type == HCI_LINK_ACL ? "ACL" : "SCO");
    625      1.1  gdamore 
    626      1.1  gdamore 	if (ep.link_type == HCI_LINK_ACL)
    627      1.1  gdamore 		link = hci_acl_newconn(unit, &ep.bdaddr);
    628      1.1  gdamore 	else
    629      1.1  gdamore 		link = hci_sco_newconn(unit, &ep.bdaddr);
    630      1.1  gdamore 
    631      1.1  gdamore 	if (link == NULL) {
    632      1.1  gdamore 		memset(&rp, 0, sizeof(rp));
    633      1.1  gdamore 		bdaddr_copy(&rp.bdaddr, &ep.bdaddr);
    634      1.1  gdamore 		rp.reason = 0x0f;	/* Unacceptable BD_ADDR */
    635      1.1  gdamore 
    636      1.1  gdamore 		hci_send_cmd(unit, HCI_CMD_REJECT_CON, &rp, sizeof(rp));
    637      1.1  gdamore 	} else {
    638      1.1  gdamore 		memset(&ap, 0, sizeof(ap));
    639      1.1  gdamore 		bdaddr_copy(&ap.bdaddr, &ep.bdaddr);
    640      1.1  gdamore 		if (unit->hci_link_policy & HCI_LINK_POLICY_ENABLE_ROLE_SWITCH)
    641      1.1  gdamore 			ap.role = HCI_ROLE_MASTER;
    642      1.1  gdamore 		else
    643      1.1  gdamore 			ap.role = HCI_ROLE_SLAVE;
    644      1.1  gdamore 
    645      1.1  gdamore 		hci_send_cmd(unit, HCI_CMD_ACCEPT_CON, &ap, sizeof(ap));
    646      1.1  gdamore 	}
    647      1.1  gdamore }
    648      1.1  gdamore 
    649      1.1  gdamore /*
    650      1.6   plunky  * Auth Complete
    651      1.6   plunky  *
    652      1.6   plunky  * Authentication has been completed on an ACL link. We can notify the
    653      1.6   plunky  * upper layer protocols unless further mode changes are pending.
    654      1.6   plunky  */
    655      1.6   plunky static void
    656      1.6   plunky hci_event_auth_compl(struct hci_unit *unit, struct mbuf *m)
    657      1.6   plunky {
    658      1.6   plunky 	hci_auth_compl_ep ep;
    659      1.6   plunky 	struct hci_link *link;
    660      1.6   plunky 	int err;
    661      1.6   plunky 
    662      1.6   plunky 	KASSERT(m->m_pkthdr.len >= sizeof(ep));
    663      1.6   plunky 	m_copydata(m, 0, sizeof(ep), &ep);
    664      1.6   plunky 	m_adj(m, sizeof(ep));
    665      1.6   plunky 
    666      1.6   plunky 	ep.con_handle = HCI_CON_HANDLE(le16toh(ep.con_handle));
    667      1.6   plunky 
    668      1.6   plunky 	DPRINTFN(1, "handle #%d, status=0x%x\n", ep.con_handle, ep.status);
    669      1.6   plunky 
    670      1.6   plunky 	link = hci_link_lookup_handle(unit, ep.con_handle);
    671      1.6   plunky 	if (link == NULL || link->hl_type != HCI_LINK_ACL)
    672      1.6   plunky 		return;
    673      1.6   plunky 
    674      1.6   plunky 	if (ep.status == 0) {
    675      1.6   plunky 		link->hl_flags |= HCI_LINK_AUTH;
    676      1.6   plunky 
    677      1.6   plunky 		if (link->hl_state == HCI_LINK_WAIT_AUTH)
    678      1.6   plunky 			link->hl_state = HCI_LINK_OPEN;
    679      1.6   plunky 
    680      1.6   plunky 		err = hci_acl_setmode(link);
    681      1.6   plunky 		if (err == EINPROGRESS)
    682      1.6   plunky 			return;
    683      1.6   plunky 	}
    684      1.6   plunky 
    685      1.6   plunky 	hci_acl_linkmode(link);
    686      1.6   plunky }
    687      1.6   plunky 
    688      1.6   plunky /*
    689      1.6   plunky  * Encryption Change
    690      1.6   plunky  *
    691      1.6   plunky  * The encryption status has changed. Basically, we note the change
    692      1.6   plunky  * then notify the upper layer protocol unless further mode changes
    693      1.6   plunky  * are pending.
    694      1.6   plunky  * Note that if encryption gets disabled when it has been requested,
    695      1.6   plunky  * we will attempt to enable it again.. (its a feature not a bug :)
    696      1.6   plunky  */
    697      1.6   plunky static void
    698      1.6   plunky hci_event_encryption_change(struct hci_unit *unit, struct mbuf *m)
    699      1.6   plunky {
    700      1.6   plunky 	hci_encryption_change_ep ep;
    701      1.6   plunky 	struct hci_link *link;
    702      1.6   plunky 	int err;
    703      1.6   plunky 
    704      1.6   plunky 	KASSERT(m->m_pkthdr.len >= sizeof(ep));
    705      1.6   plunky 	m_copydata(m, 0, sizeof(ep), &ep);
    706      1.6   plunky 	m_adj(m, sizeof(ep));
    707      1.6   plunky 
    708      1.6   plunky 	ep.con_handle = HCI_CON_HANDLE(le16toh(ep.con_handle));
    709      1.6   plunky 
    710      1.6   plunky 	DPRINTFN(1, "handle #%d, status=0x%x, encryption_enable=0x%x\n",
    711      1.6   plunky 		 ep.con_handle, ep.status, ep.encryption_enable);
    712      1.6   plunky 
    713      1.6   plunky 	link = hci_link_lookup_handle(unit, ep.con_handle);
    714      1.6   plunky 	if (link == NULL || link->hl_type != HCI_LINK_ACL)
    715      1.6   plunky 		return;
    716      1.6   plunky 
    717      1.6   plunky 	if (ep.status == 0) {
    718      1.6   plunky 		if (ep.encryption_enable == 0)
    719      1.6   plunky 			link->hl_flags &= ~HCI_LINK_ENCRYPT;
    720      1.6   plunky 		else
    721      1.6   plunky 			link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_ENCRYPT);
    722      1.6   plunky 
    723      1.6   plunky 		if (link->hl_state == HCI_LINK_WAIT_ENCRYPT)
    724      1.6   plunky 			link->hl_state = HCI_LINK_OPEN;
    725      1.6   plunky 
    726      1.6   plunky 		err = hci_acl_setmode(link);
    727      1.6   plunky 		if (err == EINPROGRESS)
    728      1.6   plunky 			return;
    729      1.6   plunky 	}
    730      1.6   plunky 
    731      1.6   plunky 	hci_acl_linkmode(link);
    732      1.6   plunky }
    733      1.6   plunky 
    734      1.6   plunky /*
    735      1.6   plunky  * Change Connection Link Key Complete
    736      1.6   plunky  *
    737      1.6   plunky  * Link keys are handled in userland but if we are waiting to secure
    738      1.6   plunky  * this link, we should notify the upper protocols. A SECURE request
    739      1.6   plunky  * only needs a single key change, so we can cancel the request.
    740      1.6   plunky  */
    741      1.6   plunky static void
    742      1.6   plunky hci_event_change_con_link_key_compl(struct hci_unit *unit, struct mbuf *m)
    743      1.6   plunky {
    744      1.6   plunky 	hci_change_con_link_key_compl_ep ep;
    745      1.6   plunky 	struct hci_link *link;
    746      1.6   plunky 	int err;
    747      1.6   plunky 
    748      1.6   plunky 	KASSERT(m->m_pkthdr.len >= sizeof(ep));
    749      1.6   plunky 	m_copydata(m, 0, sizeof(ep), &ep);
    750      1.6   plunky 	m_adj(m, sizeof(ep));
    751      1.6   plunky 
    752      1.6   plunky 	ep.con_handle = HCI_CON_HANDLE(le16toh(ep.con_handle));
    753      1.6   plunky 
    754      1.6   plunky 	DPRINTFN(1, "handle #%d, status=0x%x\n", ep.con_handle, ep.status);
    755      1.6   plunky 
    756      1.6   plunky 	link = hci_link_lookup_handle(unit, ep.con_handle);
    757      1.6   plunky 	if (link == NULL || link->hl_type != HCI_LINK_ACL)
    758      1.6   plunky 		return;
    759      1.6   plunky 
    760      1.6   plunky 	link->hl_flags &= ~HCI_LINK_SECURE_REQ;
    761      1.6   plunky 
    762      1.6   plunky 	if (ep.status == 0) {
    763      1.6   plunky 		link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_SECURE);
    764      1.6   plunky 
    765      1.6   plunky 		if (link->hl_state == HCI_LINK_WAIT_SECURE)
    766      1.6   plunky 			link->hl_state = HCI_LINK_OPEN;
    767      1.6   plunky 
    768      1.6   plunky 		err = hci_acl_setmode(link);
    769      1.6   plunky 		if (err == EINPROGRESS)
    770      1.6   plunky 			return;
    771      1.6   plunky 	}
    772      1.6   plunky 
    773      1.6   plunky 	hci_acl_linkmode(link);
    774      1.6   plunky }
    775      1.6   plunky 
    776      1.6   plunky /*
    777      1.9   plunky  * Read Clock Offset Complete
    778      1.9   plunky  *
    779      1.9   plunky  * We keep a note of the clock offset of remote devices when a
    780      1.9   plunky  * link is made, in order to facilitate reconnections to the device
    781      1.9   plunky  */
    782      1.9   plunky static void
    783      1.9   plunky hci_event_read_clock_offset_compl(struct hci_unit *unit, struct mbuf *m)
    784      1.9   plunky {
    785      1.9   plunky 	hci_read_clock_offset_compl_ep ep;
    786      1.9   plunky 	struct hci_link *link;
    787      1.9   plunky 
    788      1.9   plunky 	KASSERT(m->m_pkthdr.len >= sizeof(ep));
    789      1.9   plunky 	m_copydata(m, 0, sizeof(ep), &ep);
    790      1.9   plunky 	m_adj(m, sizeof(ep));
    791      1.9   plunky 
    792      1.9   plunky 	DPRINTFN(1, "handle #%d, offset=%u, status=0x%x\n",
    793      1.9   plunky 		le16toh(ep.con_handle), le16toh(ep.clock_offset), ep.status);
    794      1.9   plunky 
    795      1.9   plunky 	ep.con_handle = HCI_CON_HANDLE(le16toh(ep.con_handle));
    796      1.9   plunky 	link = hci_link_lookup_handle(unit, ep.con_handle);
    797      1.9   plunky 
    798      1.9   plunky 	if (ep.status != 0 || link == NULL)
    799      1.9   plunky 		return;
    800      1.9   plunky 
    801      1.9   plunky 	link->hl_clock = ep.clock_offset;
    802      1.9   plunky }
    803      1.9   plunky 
    804      1.9   plunky /*
    805      1.1  gdamore  * process results of read_bdaddr command_complete event
    806      1.1  gdamore  */
    807      1.1  gdamore static void
    808      1.1  gdamore hci_cmd_read_bdaddr(struct hci_unit *unit, struct mbuf *m)
    809      1.1  gdamore {
    810      1.1  gdamore 	hci_read_bdaddr_rp rp;
    811      1.1  gdamore 	int s;
    812      1.1  gdamore 
    813      1.1  gdamore 	KASSERT(m->m_pkthdr.len >= sizeof(rp));
    814      1.1  gdamore 	m_copydata(m, 0, sizeof(rp), &rp);
    815      1.1  gdamore 	m_adj(m, sizeof(rp));
    816      1.1  gdamore 
    817      1.1  gdamore 	if (rp.status > 0)
    818      1.1  gdamore 		return;
    819      1.1  gdamore 
    820      1.1  gdamore 	if ((unit->hci_flags & BTF_INIT_BDADDR) == 0)
    821      1.1  gdamore 		return;
    822      1.1  gdamore 
    823      1.1  gdamore 	bdaddr_copy(&unit->hci_bdaddr, &rp.bdaddr);
    824      1.1  gdamore 
    825      1.1  gdamore 	s = splraiseipl(unit->hci_ipl);
    826      1.1  gdamore 	unit->hci_flags &= ~BTF_INIT_BDADDR;
    827      1.1  gdamore 	splx(s);
    828      1.1  gdamore 
    829      1.1  gdamore 	wakeup(unit);
    830      1.1  gdamore }
    831      1.1  gdamore 
    832      1.1  gdamore /*
    833      1.1  gdamore  * process results of read_buffer_size command_complete event
    834      1.1  gdamore  */
    835      1.1  gdamore static void
    836      1.1  gdamore hci_cmd_read_buffer_size(struct hci_unit *unit, struct mbuf *m)
    837      1.1  gdamore {
    838      1.1  gdamore 	hci_read_buffer_size_rp rp;
    839      1.1  gdamore 	int s;
    840      1.1  gdamore 
    841      1.1  gdamore 	KASSERT(m->m_pkthdr.len >= sizeof(rp));
    842      1.1  gdamore 	m_copydata(m, 0, sizeof(rp), &rp);
    843      1.1  gdamore 	m_adj(m, sizeof(rp));
    844      1.1  gdamore 
    845      1.1  gdamore 	if (rp.status > 0)
    846      1.1  gdamore 		return;
    847      1.1  gdamore 
    848      1.1  gdamore 	if ((unit->hci_flags & BTF_INIT_BUFFER_SIZE) == 0)
    849      1.1  gdamore 		return;
    850      1.1  gdamore 
    851      1.1  gdamore 	unit->hci_max_acl_size = le16toh(rp.max_acl_size);
    852      1.1  gdamore 	unit->hci_num_acl_pkts = le16toh(rp.num_acl_pkts);
    853      1.1  gdamore 	unit->hci_max_sco_size = rp.max_sco_size;
    854      1.1  gdamore 	unit->hci_num_sco_pkts = le16toh(rp.num_sco_pkts);
    855      1.1  gdamore 
    856      1.1  gdamore 	s = splraiseipl(unit->hci_ipl);
    857      1.1  gdamore 	unit->hci_flags &= ~BTF_INIT_BUFFER_SIZE;
    858      1.1  gdamore 	splx(s);
    859      1.1  gdamore 
    860      1.1  gdamore 	wakeup(unit);
    861      1.1  gdamore }
    862      1.1  gdamore 
    863      1.1  gdamore /*
    864      1.1  gdamore  * process results of read_local_features command_complete event
    865      1.1  gdamore  */
    866      1.1  gdamore static void
    867      1.1  gdamore hci_cmd_read_local_features(struct hci_unit *unit, struct mbuf *m)
    868      1.1  gdamore {
    869      1.1  gdamore 	hci_read_local_features_rp rp;
    870      1.1  gdamore 	int s;
    871      1.1  gdamore 
    872      1.1  gdamore 	KASSERT(m->m_pkthdr.len >= sizeof(rp));
    873      1.1  gdamore 	m_copydata(m, 0, sizeof(rp), &rp);
    874      1.1  gdamore 	m_adj(m, sizeof(rp));
    875      1.1  gdamore 
    876      1.1  gdamore 	if (rp.status > 0)
    877      1.1  gdamore 		return;
    878      1.1  gdamore 
    879      1.1  gdamore 	if ((unit->hci_flags & BTF_INIT_FEATURES) == 0)
    880      1.1  gdamore 		return;
    881      1.1  gdamore 
    882      1.1  gdamore 	unit->hci_lmp_mask = 0;
    883      1.1  gdamore 
    884      1.1  gdamore 	if (rp.features[0] & HCI_LMP_ROLE_SWITCH)
    885      1.1  gdamore 		unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_ROLE_SWITCH;
    886      1.1  gdamore 
    887      1.1  gdamore 	if (rp.features[0] & HCI_LMP_HOLD_MODE)
    888      1.1  gdamore 		unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_HOLD_MODE;
    889      1.1  gdamore 
    890      1.1  gdamore 	if (rp.features[0] & HCI_LMP_SNIFF_MODE)
    891      1.1  gdamore 		unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_SNIFF_MODE;
    892      1.1  gdamore 
    893      1.1  gdamore 	if (rp.features[1] & HCI_LMP_PARK_MODE)
    894      1.1  gdamore 		unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_PARK_MODE;
    895      1.1  gdamore 
    896      1.1  gdamore 	/* ACL packet mask */
    897      1.1  gdamore 	unit->hci_acl_mask = HCI_PKT_DM1 | HCI_PKT_DH1;
    898      1.1  gdamore 
    899      1.1  gdamore 	if (rp.features[0] & HCI_LMP_3SLOT)
    900      1.1  gdamore 		unit->hci_acl_mask |= HCI_PKT_DM3 | HCI_PKT_DH3;
    901      1.1  gdamore 
    902      1.1  gdamore 	if (rp.features[0] & HCI_LMP_5SLOT)
    903      1.1  gdamore 		unit->hci_acl_mask |= HCI_PKT_DM5 | HCI_PKT_DH5;
    904      1.1  gdamore 
    905      1.1  gdamore 	if ((rp.features[3] & HCI_LMP_EDR_ACL_2MBPS) == 0)
    906      1.1  gdamore 		unit->hci_acl_mask |= HCI_PKT_2MBPS_DH1
    907      1.1  gdamore 				    | HCI_PKT_2MBPS_DH3
    908      1.1  gdamore 				    | HCI_PKT_2MBPS_DH5;
    909      1.1  gdamore 
    910      1.1  gdamore 	if ((rp.features[3] & HCI_LMP_EDR_ACL_3MBPS) == 0)
    911      1.1  gdamore 		unit->hci_acl_mask |= HCI_PKT_3MBPS_DH1
    912      1.1  gdamore 				    | HCI_PKT_3MBPS_DH3
    913      1.1  gdamore 				    | HCI_PKT_3MBPS_DH5;
    914      1.1  gdamore 
    915      1.1  gdamore 	if ((rp.features[4] & HCI_LMP_3SLOT_EDR_ACL) == 0)
    916      1.1  gdamore 		unit->hci_acl_mask |= HCI_PKT_2MBPS_DH3
    917      1.1  gdamore 				    | HCI_PKT_3MBPS_DH3;
    918      1.1  gdamore 
    919      1.1  gdamore 	if ((rp.features[5] & HCI_LMP_5SLOT_EDR_ACL) == 0)
    920      1.1  gdamore 		unit->hci_acl_mask |= HCI_PKT_2MBPS_DH5
    921      1.1  gdamore 				    | HCI_PKT_3MBPS_DH5;
    922      1.1  gdamore 
    923      1.1  gdamore 	unit->hci_packet_type = unit->hci_acl_mask;
    924      1.1  gdamore 
    925      1.1  gdamore 	/* SCO packet mask */
    926      1.1  gdamore 	unit->hci_sco_mask = 0;
    927      1.1  gdamore 	if (rp.features[1] & HCI_LMP_SCO_LINK)
    928      1.1  gdamore 		unit->hci_sco_mask |= HCI_PKT_HV1;
    929      1.1  gdamore 
    930      1.1  gdamore 	if (rp.features[1] & HCI_LMP_HV2_PKT)
    931      1.1  gdamore 		unit->hci_sco_mask |= HCI_PKT_HV2;
    932      1.1  gdamore 
    933      1.1  gdamore 	if (rp.features[1] & HCI_LMP_HV3_PKT)
    934      1.1  gdamore 		unit->hci_sco_mask |= HCI_PKT_HV3;
    935      1.1  gdamore 
    936      1.1  gdamore 	if (rp.features[3] & HCI_LMP_EV3_PKT)
    937      1.1  gdamore 		unit->hci_sco_mask |= HCI_PKT_EV3;
    938      1.1  gdamore 
    939      1.1  gdamore 	if (rp.features[4] & HCI_LMP_EV4_PKT)
    940      1.1  gdamore 		unit->hci_sco_mask |= HCI_PKT_EV4;
    941      1.1  gdamore 
    942      1.1  gdamore 	if (rp.features[4] & HCI_LMP_EV5_PKT)
    943      1.1  gdamore 		unit->hci_sco_mask |= HCI_PKT_EV5;
    944      1.1  gdamore 
    945      1.4   plunky 	/* XXX what do 2MBPS/3MBPS/3SLOT eSCO mean? */
    946      1.1  gdamore 
    947      1.1  gdamore 	s = splraiseipl(unit->hci_ipl);
    948      1.1  gdamore 	unit->hci_flags &= ~BTF_INIT_FEATURES;
    949      1.1  gdamore 	splx(s);
    950      1.1  gdamore 
    951      1.1  gdamore 	wakeup(unit);
    952      1.1  gdamore 
    953      1.1  gdamore 	DPRINTFN(1, "%s: lmp_mask %4.4x, acl_mask %4.4x, sco_mask %4.4x\n",
    954  1.9.6.1      mjf 		device_xname(unit->hci_dev), unit->hci_lmp_mask,
    955      1.1  gdamore 		unit->hci_acl_mask, unit->hci_sco_mask);
    956      1.1  gdamore }
    957      1.1  gdamore 
    958      1.1  gdamore /*
    959      1.1  gdamore  * process results of reset command_complete event
    960      1.1  gdamore  *
    961      1.1  gdamore  * This has killed all the connections, so close down anything we have left,
    962      1.1  gdamore  * and reinitialise the unit.
    963      1.1  gdamore  */
    964      1.1  gdamore static void
    965      1.1  gdamore hci_cmd_reset(struct hci_unit *unit, struct mbuf *m)
    966      1.1  gdamore {
    967      1.1  gdamore 	hci_reset_rp rp;
    968      1.1  gdamore 	struct hci_link *link, *next;
    969      1.1  gdamore 	int acl;
    970      1.1  gdamore 
    971      1.1  gdamore 	KASSERT(m->m_pkthdr.len >= sizeof(rp));
    972      1.1  gdamore 	m_copydata(m, 0, sizeof(rp), &rp);
    973      1.1  gdamore 	m_adj(m, sizeof(rp));
    974      1.1  gdamore 
    975      1.1  gdamore 	if (rp.status != 0)
    976      1.1  gdamore 		return;
    977      1.1  gdamore 
    978      1.1  gdamore 	/*
    979      1.1  gdamore 	 * release SCO links first, since they may be holding
    980      1.1  gdamore 	 * an ACL link reference.
    981      1.1  gdamore 	 */
    982      1.1  gdamore 	for (acl = 0 ; acl < 2 ; acl++) {
    983      1.1  gdamore 		next = TAILQ_FIRST(&unit->hci_links);
    984      1.1  gdamore 		while ((link = next) != NULL) {
    985      1.1  gdamore 			next = TAILQ_NEXT(link, hl_next);
    986      1.1  gdamore 			if (acl || link->hl_type != HCI_LINK_ACL)
    987      1.1  gdamore 				hci_link_free(link, ECONNABORTED);
    988      1.1  gdamore 		}
    989      1.1  gdamore 	}
    990      1.1  gdamore 
    991      1.1  gdamore 	unit->hci_num_acl_pkts = 0;
    992      1.1  gdamore 	unit->hci_num_sco_pkts = 0;
    993      1.1  gdamore 
    994      1.1  gdamore 	if (hci_send_cmd(unit, HCI_CMD_READ_BDADDR, NULL, 0))
    995      1.1  gdamore 		return;
    996      1.1  gdamore 
    997      1.1  gdamore 	if (hci_send_cmd(unit, HCI_CMD_READ_BUFFER_SIZE, NULL, 0))
    998      1.1  gdamore 		return;
    999      1.1  gdamore 
   1000      1.1  gdamore 	if (hci_send_cmd(unit, HCI_CMD_READ_LOCAL_FEATURES, NULL, 0))
   1001      1.1  gdamore 		return;
   1002      1.1  gdamore }
   1003