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