xref: /dragonfly/sys/netbt/hci_event.c (revision 05d02a38)
183aacedeSHasso Tepper /* $OpenBSD: src/sys/netbt/hci_event.c,v 1.7 2008/02/24 21:34:48 uwe Exp $ */
283aacedeSHasso Tepper /* $NetBSD: hci_event.c,v 1.14 2008/02/10 17:40:54 plunky Exp $ */
30a9108ebSHasso Tepper 
40a9108ebSHasso Tepper /*-
50a9108ebSHasso Tepper  * Copyright (c) 2005 Iain Hibbert.
60a9108ebSHasso Tepper  * Copyright (c) 2006 Itronix Inc.
70a9108ebSHasso Tepper  * All rights reserved.
80a9108ebSHasso Tepper  *
90a9108ebSHasso Tepper  * Redistribution and use in source and binary forms, with or without
100a9108ebSHasso Tepper  * modification, are permitted provided that the following conditions
110a9108ebSHasso Tepper  * are met:
120a9108ebSHasso Tepper  * 1. Redistributions of source code must retain the above copyright
130a9108ebSHasso Tepper  *    notice, this list of conditions and the following disclaimer.
140a9108ebSHasso Tepper  * 2. Redistributions in binary form must reproduce the above copyright
150a9108ebSHasso Tepper  *    notice, this list of conditions and the following disclaimer in the
160a9108ebSHasso Tepper  *    documentation and/or other materials provided with the distribution.
170a9108ebSHasso Tepper  * 3. The name of Itronix Inc. may not be used to endorse
180a9108ebSHasso Tepper  *    or promote products derived from this software without specific
190a9108ebSHasso Tepper  *    prior written permission.
200a9108ebSHasso Tepper  *
210a9108ebSHasso Tepper  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
220a9108ebSHasso Tepper  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
230a9108ebSHasso Tepper  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
240a9108ebSHasso Tepper  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
250a9108ebSHasso Tepper  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
260a9108ebSHasso Tepper  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
270a9108ebSHasso Tepper  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
280a9108ebSHasso Tepper  * ON ANY THEORY OF LIABILITY, WHETHER IN
290a9108ebSHasso Tepper  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
300a9108ebSHasso Tepper  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
310a9108ebSHasso Tepper  * POSSIBILITY OF SUCH DAMAGE.
320a9108ebSHasso Tepper  */
330a9108ebSHasso Tepper 
340a9108ebSHasso Tepper #include <sys/param.h>
350a9108ebSHasso Tepper #include <sys/kernel.h>
360a9108ebSHasso Tepper #include <sys/malloc.h>
370a9108ebSHasso Tepper #include <sys/mbuf.h>
380a9108ebSHasso Tepper #include <sys/proc.h>
390a9108ebSHasso Tepper #include <sys/systm.h>
400a9108ebSHasso Tepper #include <sys/endian.h>
410a9108ebSHasso Tepper #include <sys/bus.h>
420a9108ebSHasso Tepper 
430a9108ebSHasso Tepper #include <netbt/bluetooth.h>
440a9108ebSHasso Tepper #include <netbt/hci.h>
450a9108ebSHasso Tepper #include <netbt/sco.h>
460a9108ebSHasso Tepper 
470a9108ebSHasso Tepper static void hci_event_inquiry_result(struct hci_unit *, struct mbuf *);
4883aacedeSHasso Tepper static void hci_event_rssi_result(struct hci_unit *, struct mbuf *);
490a9108ebSHasso Tepper static void hci_event_command_status(struct hci_unit *, struct mbuf *);
500a9108ebSHasso Tepper static void hci_event_command_compl(struct hci_unit *, struct mbuf *);
510a9108ebSHasso Tepper static void hci_event_con_compl(struct hci_unit *, struct mbuf *);
520a9108ebSHasso Tepper static void hci_event_discon_compl(struct hci_unit *, struct mbuf *);
530a9108ebSHasso Tepper static void hci_event_con_req(struct hci_unit *, struct mbuf *);
540a9108ebSHasso Tepper static void hci_event_num_compl_pkts(struct hci_unit *, struct mbuf *);
550a9108ebSHasso Tepper static void hci_event_auth_compl(struct hci_unit *, struct mbuf *);
560a9108ebSHasso Tepper static void hci_event_encryption_change(struct hci_unit *, struct mbuf *);
570a9108ebSHasso Tepper static void hci_event_change_con_link_key_compl(struct hci_unit *, struct mbuf *);
5883aacedeSHasso Tepper static void hci_event_read_clock_offset_compl(struct hci_unit *, struct mbuf *);
590a9108ebSHasso Tepper static void hci_cmd_read_bdaddr(struct hci_unit *, struct mbuf *);
600a9108ebSHasso Tepper static void hci_cmd_read_buffer_size(struct hci_unit *, struct mbuf *);
610a9108ebSHasso Tepper static void hci_cmd_read_local_features(struct hci_unit *, struct mbuf *);
6283aacedeSHasso Tepper static void hci_cmd_read_local_ver(struct hci_unit *, struct mbuf *);
6383aacedeSHasso Tepper static void hci_cmd_read_local_commands(struct hci_unit *, struct mbuf *);
640a9108ebSHasso Tepper static void hci_cmd_reset(struct hci_unit *, struct mbuf *);
650a9108ebSHasso Tepper 
660a9108ebSHasso Tepper #ifdef BLUETOOTH_DEBUG
670a9108ebSHasso Tepper int bluetooth_debug = BLUETOOTH_DEBUG;
680a9108ebSHasso Tepper 
690a9108ebSHasso Tepper static const char *hci_eventnames[] = {
700a9108ebSHasso Tepper /* 0x00 */ "NULL",
710a9108ebSHasso Tepper /* 0x01 */ "INQUIRY COMPLETE",
720a9108ebSHasso Tepper /* 0x02 */ "INQUIRY RESULT",
730a9108ebSHasso Tepper /* 0x03 */ "CONN COMPLETE",
740a9108ebSHasso Tepper /* 0x04 */ "CONN REQ",
750a9108ebSHasso Tepper /* 0x05 */ "DISCONN COMPLETE",
760a9108ebSHasso Tepper /* 0x06 */ "AUTH COMPLETE",
770a9108ebSHasso Tepper /* 0x07 */ "REMOTE NAME REQ COMPLETE",
780a9108ebSHasso Tepper /* 0x08 */ "ENCRYPTION CHANGE",
790a9108ebSHasso Tepper /* 0x09 */ "CHANGE CONN LINK KEY COMPLETE",
800a9108ebSHasso Tepper /* 0x0a */ "MASTER LINK KEY COMPLETE",
810a9108ebSHasso Tepper /* 0x0b */ "READ REMOTE FEATURES COMPLETE",
820a9108ebSHasso Tepper /* 0x0c */ "READ REMOTE VERSION INFO COMPLETE",
830a9108ebSHasso Tepper /* 0x0d */ "QoS SETUP COMPLETE",
840a9108ebSHasso Tepper /* 0x0e */ "COMMAND COMPLETE",
850a9108ebSHasso Tepper /* 0x0f */ "COMMAND STATUS",
860a9108ebSHasso Tepper /* 0x10 */ "HARDWARE ERROR",
870a9108ebSHasso Tepper /* 0x11 */ "FLUSH OCCUR",
880a9108ebSHasso Tepper /* 0x12 */ "ROLE CHANGE",
890a9108ebSHasso Tepper /* 0x13 */ "NUM COMPLETED PACKETS",
900a9108ebSHasso Tepper /* 0x14 */ "MODE CHANGE",
910a9108ebSHasso Tepper /* 0x15 */ "RETURN LINK KEYS",
920a9108ebSHasso Tepper /* 0x16 */ "PIN CODE REQ",
930a9108ebSHasso Tepper /* 0x17 */ "LINK KEY REQ",
940a9108ebSHasso Tepper /* 0x18 */ "LINK KEY NOTIFICATION",
950a9108ebSHasso Tepper /* 0x19 */ "LOOPBACK COMMAND",
960a9108ebSHasso Tepper /* 0x1a */ "DATA BUFFER OVERFLOW",
970a9108ebSHasso Tepper /* 0x1b */ "MAX SLOT CHANGE",
980a9108ebSHasso Tepper /* 0x1c */ "READ CLOCK OFFSET COMPLETE",
990a9108ebSHasso Tepper /* 0x1d */ "CONN PKT TYPE CHANGED",
1000a9108ebSHasso Tepper /* 0x1e */ "QOS VIOLATION",
1010a9108ebSHasso Tepper /* 0x1f */ "PAGE SCAN MODE CHANGE",
1020a9108ebSHasso Tepper /* 0x20 */ "PAGE SCAN REP MODE CHANGE",
1030a9108ebSHasso Tepper /* 0x21 */ "FLOW SPECIFICATION COMPLETE",
1040a9108ebSHasso Tepper /* 0x22 */ "RSSI RESULT",
10583aacedeSHasso Tepper /* 0x23 */ "READ REMOTE EXT FEATURES",
10683aacedeSHasso Tepper /* 0x24 */ "UNKNOWN",
10783aacedeSHasso Tepper /* 0x25 */ "UNKNOWN",
10883aacedeSHasso Tepper /* 0x26 */ "UNKNOWN",
10983aacedeSHasso Tepper /* 0x27 */ "UNKNOWN",
11083aacedeSHasso Tepper /* 0x28 */ "UNKNOWN",
11183aacedeSHasso Tepper /* 0x29 */ "UNKNOWN",
11283aacedeSHasso Tepper /* 0x2a */ "UNKNOWN",
11383aacedeSHasso Tepper /* 0x2b */ "UNKNOWN",
11483aacedeSHasso Tepper /* 0x2c */ "SCO CON COMPLETE",
11583aacedeSHasso Tepper /* 0x2d */ "SCO CON CHANGED",
11683aacedeSHasso Tepper /* 0x2e */ "SNIFF SUBRATING",
11783aacedeSHasso Tepper /* 0x2f */ "EXTENDED INQUIRY RESULT",
11883aacedeSHasso Tepper /* 0x30 */ "ENCRYPTION KEY REFRESH",
11983aacedeSHasso Tepper /* 0x31 */ "IO CAPABILITY REQUEST",
12083aacedeSHasso Tepper /* 0x32 */ "IO CAPABILITY RESPONSE",
12183aacedeSHasso Tepper /* 0x33 */ "USER CONFIRM REQUEST",
12283aacedeSHasso Tepper /* 0x34 */ "USER PASSKEY REQUEST",
12383aacedeSHasso Tepper /* 0x35 */ "REMOTE OOB DATA REQUEST",
12483aacedeSHasso Tepper /* 0x36 */ "SIMPLE PAIRING COMPLETE",
12583aacedeSHasso Tepper /* 0x37 */ "UNKNOWN",
12683aacedeSHasso Tepper /* 0x38 */ "LINK SUPERVISION TIMEOUT CHANGED",
12783aacedeSHasso Tepper /* 0x39 */ "ENHANCED FLUSH COMPLETE",
12883aacedeSHasso Tepper /* 0x3a */ "UNKNOWN",
12983aacedeSHasso Tepper /* 0x3b */ "USER PASSKEY NOTIFICATION",
13083aacedeSHasso Tepper /* 0x3c */ "KEYPRESS NOTIFICATION",
13183aacedeSHasso Tepper /* 0x3d */ "REMOTE HOST FEATURES NOTIFICATION",
1320a9108ebSHasso Tepper };
1330a9108ebSHasso Tepper 
1340a9108ebSHasso Tepper static const char *
hci_eventstr(unsigned int event)1350a9108ebSHasso Tepper hci_eventstr(unsigned int event)
1360a9108ebSHasso Tepper {
1370a9108ebSHasso Tepper 
138b370aff7SSascha Wildner 	if (event < NELEM(hci_eventnames))
1390a9108ebSHasso Tepper 		return hci_eventnames[event];
1400a9108ebSHasso Tepper 
1410a9108ebSHasso Tepper 	switch (event) {
1420a9108ebSHasso Tepper 	case HCI_EVENT_BT_LOGO:		/* 0xfe */
1430a9108ebSHasso Tepper 		return "BT_LOGO";
1440a9108ebSHasso Tepper 
1450a9108ebSHasso Tepper 	case HCI_EVENT_VENDOR:		/* 0xff */
1460a9108ebSHasso Tepper 		return "VENDOR";
1470a9108ebSHasso Tepper 	}
1480a9108ebSHasso Tepper 
14983aacedeSHasso Tepper 	return "UNKNOWN";
1500a9108ebSHasso Tepper }
1510a9108ebSHasso Tepper #endif	/* BLUETOOTH_DEBUG */
1520a9108ebSHasso Tepper 
1530a9108ebSHasso Tepper /*
1540a9108ebSHasso Tepper  * process HCI Events
1550a9108ebSHasso Tepper  *
1560a9108ebSHasso Tepper  * We will free the mbuf at the end, no need for any sub
1570a9108ebSHasso Tepper  * functions to handle that. We kind of assume that the
1580a9108ebSHasso Tepper  * device sends us valid events.
1590a9108ebSHasso Tepper  */
1600a9108ebSHasso Tepper void
hci_event(struct mbuf * m,struct hci_unit * unit)1610a9108ebSHasso Tepper hci_event(struct mbuf *m, struct hci_unit *unit)
1620a9108ebSHasso Tepper {
1630a9108ebSHasso Tepper 	hci_event_hdr_t hdr;
1640a9108ebSHasso Tepper 
1650a9108ebSHasso Tepper 	KKASSERT(m->m_flags & M_PKTHDR);
1660a9108ebSHasso Tepper 
1670a9108ebSHasso Tepper 	KKASSERT(m->m_pkthdr.len >= sizeof(hdr));
168*05d02a38SAaron LI 	m_copydata(m, 0, sizeof(hdr), &hdr);
1690a9108ebSHasso Tepper 	m_adj(m, sizeof(hdr));
1700a9108ebSHasso Tepper 
1710a9108ebSHasso Tepper 	KKASSERT(hdr.type == HCI_EVENT_PKT);
1720a9108ebSHasso Tepper 
17383aacedeSHasso Tepper 	DPRINTFN(1, "(%s) event %s\n",
17483aacedeSHasso Tepper 	    device_get_nameunit(unit->hci_dev), hci_eventstr(hdr.event));
1750a9108ebSHasso Tepper 
1760a9108ebSHasso Tepper 	switch(hdr.event) {
1770a9108ebSHasso Tepper 	case HCI_EVENT_COMMAND_STATUS:
1780a9108ebSHasso Tepper 		hci_event_command_status(unit, m);
1790a9108ebSHasso Tepper 		break;
1800a9108ebSHasso Tepper 
1810a9108ebSHasso Tepper 	case HCI_EVENT_COMMAND_COMPL:
1820a9108ebSHasso Tepper 		hci_event_command_compl(unit, m);
1830a9108ebSHasso Tepper 		break;
1840a9108ebSHasso Tepper 
1850a9108ebSHasso Tepper 	case HCI_EVENT_NUM_COMPL_PKTS:
1860a9108ebSHasso Tepper 		hci_event_num_compl_pkts(unit, m);
1870a9108ebSHasso Tepper 		break;
1880a9108ebSHasso Tepper 
1890a9108ebSHasso Tepper 	case HCI_EVENT_INQUIRY_RESULT:
1900a9108ebSHasso Tepper 		hci_event_inquiry_result(unit, m);
1910a9108ebSHasso Tepper 		break;
1920a9108ebSHasso Tepper 
19383aacedeSHasso Tepper 	case HCI_EVENT_RSSI_RESULT:
19483aacedeSHasso Tepper 		hci_event_rssi_result(unit, m);
19583aacedeSHasso Tepper 		break;
19683aacedeSHasso Tepper 
1970a9108ebSHasso Tepper 	case HCI_EVENT_CON_COMPL:
1980a9108ebSHasso Tepper 		hci_event_con_compl(unit, m);
1990a9108ebSHasso Tepper 		break;
2000a9108ebSHasso Tepper 
2010a9108ebSHasso Tepper 	case HCI_EVENT_DISCON_COMPL:
2020a9108ebSHasso Tepper 		hci_event_discon_compl(unit, m);
2030a9108ebSHasso Tepper 		break;
2040a9108ebSHasso Tepper 
2050a9108ebSHasso Tepper 	case HCI_EVENT_CON_REQ:
2060a9108ebSHasso Tepper 		hci_event_con_req(unit, m);
2070a9108ebSHasso Tepper 		break;
2080a9108ebSHasso Tepper 
2090a9108ebSHasso Tepper 	case HCI_EVENT_AUTH_COMPL:
2100a9108ebSHasso Tepper 		hci_event_auth_compl(unit, m);
2110a9108ebSHasso Tepper 		break;
2120a9108ebSHasso Tepper 
2130a9108ebSHasso Tepper 	case HCI_EVENT_ENCRYPTION_CHANGE:
2140a9108ebSHasso Tepper 		hci_event_encryption_change(unit, m);
2150a9108ebSHasso Tepper 		break;
2160a9108ebSHasso Tepper 
2170a9108ebSHasso Tepper 	case HCI_EVENT_CHANGE_CON_LINK_KEY_COMPL:
2180a9108ebSHasso Tepper 		hci_event_change_con_link_key_compl(unit, m);
2190a9108ebSHasso Tepper 		break;
2200a9108ebSHasso Tepper 
2210a9108ebSHasso Tepper 	case HCI_EVENT_READ_CLOCK_OFFSET_COMPL:
22283aacedeSHasso Tepper 		hci_event_read_clock_offset_compl(unit, m);
2230a9108ebSHasso Tepper 		break;
2240a9108ebSHasso Tepper 
2250a9108ebSHasso Tepper 	default:
2260a9108ebSHasso Tepper 		break;
2270a9108ebSHasso Tepper 	}
2280a9108ebSHasso Tepper 
2290a9108ebSHasso Tepper 	m_freem(m);
2300a9108ebSHasso Tepper }
2310a9108ebSHasso Tepper 
2320a9108ebSHasso Tepper /*
2330a9108ebSHasso Tepper  * Command Status
2340a9108ebSHasso Tepper  *
2350a9108ebSHasso Tepper  * Update our record of num_cmd_pkts then post-process any pending commands
2360a9108ebSHasso Tepper  * and optionally restart cmd output on the unit.
2370a9108ebSHasso Tepper  */
2380a9108ebSHasso Tepper static void
hci_event_command_status(struct hci_unit * unit,struct mbuf * m)2390a9108ebSHasso Tepper hci_event_command_status(struct hci_unit *unit, struct mbuf *m)
2400a9108ebSHasso Tepper {
2410a9108ebSHasso Tepper 	hci_command_status_ep ep;
2420a9108ebSHasso Tepper 	struct hci_link *link;
2430a9108ebSHasso Tepper 
2440a9108ebSHasso Tepper 	KKASSERT(m->m_pkthdr.len >= sizeof(ep));
245*05d02a38SAaron LI 	m_copydata(m, 0, sizeof(ep), &ep);
2460a9108ebSHasso Tepper 	m_adj(m, sizeof(ep));
2470a9108ebSHasso Tepper 
2480a9108ebSHasso Tepper 	DPRINTFN(1, "(%s) opcode (%03x|%04x) status = 0x%x num_cmd_pkts = %d\n",
24983aacedeSHasso Tepper 		device_get_nameunit(unit->hci_dev),
2500a9108ebSHasso Tepper 		HCI_OGF(letoh16(ep.opcode)), HCI_OCF(letoh16(ep.opcode)),
2510a9108ebSHasso Tepper 		ep.status,
2520a9108ebSHasso Tepper 		ep.num_cmd_pkts);
2530a9108ebSHasso Tepper 
25483aacedeSHasso Tepper 	if (ep.status > 0)
25583aacedeSHasso Tepper 		kprintf("%s: CommandStatus opcode (%03x|%04x) failed "
25683aacedeSHasso Tepper 		    "(status=0x%02x)\n", device_get_nameunit(unit->hci_dev),
25783aacedeSHasso Tepper 		    HCI_OGF(letoh16(ep.opcode)),
25883aacedeSHasso Tepper 		    HCI_OCF(letoh16(ep.opcode)), ep.status);
25983aacedeSHasso Tepper 
2600a9108ebSHasso Tepper 	unit->hci_num_cmd_pkts = ep.num_cmd_pkts;
2610a9108ebSHasso Tepper 
2620a9108ebSHasso Tepper 	/*
2630a9108ebSHasso Tepper 	 * post processing of pending commands
2640a9108ebSHasso Tepper 	 */
2650a9108ebSHasso Tepper 	switch(letoh16(ep.opcode)) {
2660a9108ebSHasso Tepper 	case HCI_CMD_CREATE_CON:
2670a9108ebSHasso Tepper 		switch (ep.status) {
2680a9108ebSHasso Tepper 		case 0x12:	/* Invalid HCI command parameters */
2690a9108ebSHasso Tepper 			DPRINTF("(%s) Invalid HCI command parameters\n",
27083aacedeSHasso Tepper 			    device_get_nameunit(unit->hci_dev));
2710a9108ebSHasso Tepper 			while ((link = hci_link_lookup_state(unit,
2720a9108ebSHasso Tepper 			    HCI_LINK_ACL, HCI_LINK_WAIT_CONNECT)) != NULL)
2730a9108ebSHasso Tepper 				hci_link_free(link, ECONNABORTED);
2740a9108ebSHasso Tepper 			break;
2750a9108ebSHasso Tepper 		}
2760a9108ebSHasso Tepper 		break;
2770a9108ebSHasso Tepper 	default:
2780a9108ebSHasso Tepper 		break;
2790a9108ebSHasso Tepper 	}
2800a9108ebSHasso Tepper 
2810a9108ebSHasso Tepper 	while (unit->hci_num_cmd_pkts > 0 && !IF_QEMPTY(&unit->hci_cmdwait)) {
2820a9108ebSHasso Tepper 		IF_DEQUEUE(&unit->hci_cmdwait, m);
2830a9108ebSHasso Tepper 		hci_output_cmd(unit, m);
2840a9108ebSHasso Tepper 	}
2850a9108ebSHasso Tepper }
2860a9108ebSHasso Tepper 
2870a9108ebSHasso Tepper /*
2880a9108ebSHasso Tepper  * Command Complete
2890a9108ebSHasso Tepper  *
2900a9108ebSHasso Tepper  * Update our record of num_cmd_pkts then handle the completed command,
2910a9108ebSHasso Tepper  * and optionally restart cmd output on the unit.
2920a9108ebSHasso Tepper  */
2930a9108ebSHasso Tepper static void
hci_event_command_compl(struct hci_unit * unit,struct mbuf * m)2940a9108ebSHasso Tepper hci_event_command_compl(struct hci_unit *unit, struct mbuf *m)
2950a9108ebSHasso Tepper {
2960a9108ebSHasso Tepper 	hci_command_compl_ep ep;
29783aacedeSHasso Tepper 	hci_status_rp rp;
2980a9108ebSHasso Tepper 
2990a9108ebSHasso Tepper 	KKASSERT(m->m_pkthdr.len >= sizeof(ep));
300*05d02a38SAaron LI 	m_copydata(m, 0, sizeof(ep), &ep);
3010a9108ebSHasso Tepper 	m_adj(m, sizeof(ep));
3020a9108ebSHasso Tepper 
3030a9108ebSHasso Tepper 	DPRINTFN(1, "(%s) opcode (%03x|%04x) num_cmd_pkts = %d\n",
30483aacedeSHasso Tepper 		device_get_nameunit(unit->hci_dev),
3050a9108ebSHasso Tepper 		HCI_OGF(letoh16(ep.opcode)), HCI_OCF(letoh16(ep.opcode)),
3060a9108ebSHasso Tepper 		ep.num_cmd_pkts);
3070a9108ebSHasso Tepper 
30883aacedeSHasso Tepper 	/*
30983aacedeSHasso Tepper 	 * I am not sure if this is completely correct, it is not guaranteed
31083aacedeSHasso Tepper 	 * that a command_complete packet will contain the status though most
31183aacedeSHasso Tepper 	 * do seem to.
31283aacedeSHasso Tepper 	 */
313*05d02a38SAaron LI 	m_copydata(m, 0, sizeof(rp), &rp);
31483aacedeSHasso Tepper 	if (rp.status > 0)
31583aacedeSHasso Tepper 		kprintf("%s: CommandComplete opcode (%03x|%04x) failed (status=0x%02x)\n",
31683aacedeSHasso Tepper 		    device_get_nameunit(unit->hci_dev), HCI_OGF(letoh16(ep.opcode)),
31783aacedeSHasso Tepper 		    HCI_OCF(letoh16(ep.opcode)), rp.status);
31883aacedeSHasso Tepper 
3190a9108ebSHasso Tepper 	unit->hci_num_cmd_pkts = ep.num_cmd_pkts;
3200a9108ebSHasso Tepper 
3210a9108ebSHasso Tepper 	/*
3220a9108ebSHasso Tepper 	 * post processing of completed commands
3230a9108ebSHasso Tepper 	 */
3240a9108ebSHasso Tepper 	switch(letoh16(ep.opcode)) {
3250a9108ebSHasso Tepper 	case HCI_CMD_READ_BDADDR:
3260a9108ebSHasso Tepper 		hci_cmd_read_bdaddr(unit, m);
3270a9108ebSHasso Tepper 		break;
3280a9108ebSHasso Tepper 
3290a9108ebSHasso Tepper 	case HCI_CMD_READ_BUFFER_SIZE:
3300a9108ebSHasso Tepper 		hci_cmd_read_buffer_size(unit, m);
3310a9108ebSHasso Tepper 		break;
3320a9108ebSHasso Tepper 
3330a9108ebSHasso Tepper 	case HCI_CMD_READ_LOCAL_FEATURES:
3340a9108ebSHasso Tepper 		hci_cmd_read_local_features(unit, m);
3350a9108ebSHasso Tepper 		break;
3360a9108ebSHasso Tepper 
33783aacedeSHasso Tepper 	case HCI_CMD_READ_LOCAL_VER:
33883aacedeSHasso Tepper 		hci_cmd_read_local_ver(unit, m);
33983aacedeSHasso Tepper 		break;
34083aacedeSHasso Tepper 
34183aacedeSHasso Tepper 	case HCI_CMD_READ_LOCAL_COMMANDS:
34283aacedeSHasso Tepper 		hci_cmd_read_local_commands(unit, m);
34383aacedeSHasso Tepper 		break;
34483aacedeSHasso Tepper 
3450a9108ebSHasso Tepper 	case HCI_CMD_RESET:
3460a9108ebSHasso Tepper 		hci_cmd_reset(unit, m);
3470a9108ebSHasso Tepper 		break;
3480a9108ebSHasso Tepper 
3490a9108ebSHasso Tepper 	default:
3500a9108ebSHasso Tepper 		break;
3510a9108ebSHasso Tepper 	}
3520a9108ebSHasso Tepper 
3530a9108ebSHasso Tepper 	while (unit->hci_num_cmd_pkts > 0 && !IF_QEMPTY(&unit->hci_cmdwait)) {
3540a9108ebSHasso Tepper 		IF_DEQUEUE(&unit->hci_cmdwait, m);
3550a9108ebSHasso Tepper 		hci_output_cmd(unit, m);
3560a9108ebSHasso Tepper 	}
3570a9108ebSHasso Tepper }
3580a9108ebSHasso Tepper 
3590a9108ebSHasso Tepper /*
3600a9108ebSHasso Tepper  * Number of Completed Packets
3610a9108ebSHasso Tepper  *
3620a9108ebSHasso Tepper  * This is sent periodically by the Controller telling us how many
3630a9108ebSHasso Tepper  * buffers are now freed up and which handle was using them. From
3640a9108ebSHasso Tepper  * this we determine which type of buffer it was and add the qty
3650a9108ebSHasso Tepper  * back into the relevant packet counter, then restart output on
3660a9108ebSHasso Tepper  * links that have halted.
3670a9108ebSHasso Tepper  */
3680a9108ebSHasso Tepper static void
hci_event_num_compl_pkts(struct hci_unit * unit,struct mbuf * m)3690a9108ebSHasso Tepper hci_event_num_compl_pkts(struct hci_unit *unit, struct mbuf *m)
3700a9108ebSHasso Tepper {
3710a9108ebSHasso Tepper 	hci_num_compl_pkts_ep ep;
3720a9108ebSHasso Tepper 	struct hci_link *link, *next;
3730a9108ebSHasso Tepper 	uint16_t handle, num;
3740a9108ebSHasso Tepper 	int num_acl = 0, num_sco = 0;
3750a9108ebSHasso Tepper 
3760a9108ebSHasso Tepper 	KKASSERT(m->m_pkthdr.len >= sizeof(ep));
377*05d02a38SAaron LI 	m_copydata(m, 0, sizeof(ep), &ep);
3780a9108ebSHasso Tepper 	m_adj(m, sizeof(ep));
3790a9108ebSHasso Tepper 
3800a9108ebSHasso Tepper 	while (ep.num_con_handles--) {
381*05d02a38SAaron LI 		m_copydata(m, 0, sizeof(handle), &handle);
3820a9108ebSHasso Tepper 		m_adj(m, sizeof(handle));
3830a9108ebSHasso Tepper 		handle = letoh16(handle);
3840a9108ebSHasso Tepper 
385*05d02a38SAaron LI 		m_copydata(m, 0, sizeof(num), &num);
3860a9108ebSHasso Tepper 		m_adj(m, sizeof(num));
3870a9108ebSHasso Tepper 		num = letoh16(num);
3880a9108ebSHasso Tepper 
3890a9108ebSHasso Tepper 		link = hci_link_lookup_handle(unit, handle);
3900a9108ebSHasso Tepper 		if (link) {
3910a9108ebSHasso Tepper 			if (link->hl_type == HCI_LINK_ACL) {
3920a9108ebSHasso Tepper 				num_acl += num;
3930a9108ebSHasso Tepper 				hci_acl_complete(link, num);
3940a9108ebSHasso Tepper 			} else {
3950a9108ebSHasso Tepper 				num_sco += num;
3960a9108ebSHasso Tepper 				hci_sco_complete(link, num);
3970a9108ebSHasso Tepper 			}
3980a9108ebSHasso Tepper 		} else {
3990a9108ebSHasso Tepper 			/* XXX need to issue Read_Buffer_Size or Reset? */
4000a9108ebSHasso Tepper 			kprintf("%s: unknown handle %d! "
4010a9108ebSHasso Tepper 			    "(losing track of %d packet buffer%s)\n",
40283aacedeSHasso Tepper 			    device_get_nameunit(unit->hci_dev), handle,
4030a9108ebSHasso Tepper 			    num, (num == 1 ? "" : "s"));
4040a9108ebSHasso Tepper 		}
4050a9108ebSHasso Tepper 	}
4060a9108ebSHasso Tepper 
4070a9108ebSHasso Tepper 	/*
4080a9108ebSHasso Tepper 	 * Move up any queued packets. When a link has sent data, it will move
4090a9108ebSHasso Tepper 	 * to the back of the queue - technically then if a link had something
4100a9108ebSHasso Tepper 	 * to send and there were still buffers available it could get started
4110a9108ebSHasso Tepper 	 * twice but it seemed more important to to handle higher loads fairly
4120a9108ebSHasso Tepper 	 * than worry about wasting cycles when we are not busy.
4130a9108ebSHasso Tepper 	 */
4140a9108ebSHasso Tepper 
4150a9108ebSHasso Tepper 	unit->hci_num_acl_pkts += num_acl;
4160a9108ebSHasso Tepper 	unit->hci_num_sco_pkts += num_sco;
4170a9108ebSHasso Tepper 
4180a9108ebSHasso Tepper 	link = TAILQ_FIRST(&unit->hci_links);
4190a9108ebSHasso Tepper 	while (link && (unit->hci_num_acl_pkts > 0 || unit->hci_num_sco_pkts > 0)) {
4200a9108ebSHasso Tepper 		next = TAILQ_NEXT(link, hl_next);
4210a9108ebSHasso Tepper 
4220a9108ebSHasso Tepper 		if (link->hl_type == HCI_LINK_ACL) {
4230a9108ebSHasso Tepper 			if (unit->hci_num_acl_pkts > 0 && link->hl_txqlen > 0)
4240a9108ebSHasso Tepper 				hci_acl_start(link);
4250a9108ebSHasso Tepper 		} else {
4260a9108ebSHasso Tepper 			if (unit->hci_num_sco_pkts > 0 && link->hl_txqlen > 0)
4270a9108ebSHasso Tepper 				hci_sco_start(link);
4280a9108ebSHasso Tepper 		}
4290a9108ebSHasso Tepper 
4300a9108ebSHasso Tepper 		link = next;
4310a9108ebSHasso Tepper 	}
4320a9108ebSHasso Tepper }
4330a9108ebSHasso Tepper 
4340a9108ebSHasso Tepper /*
4350a9108ebSHasso Tepper  * Inquiry Result
4360a9108ebSHasso Tepper  *
4370a9108ebSHasso Tepper  * keep a note of devices seen, so we know which unit to use
4380a9108ebSHasso Tepper  * on outgoing connections
4390a9108ebSHasso Tepper  */
4400a9108ebSHasso Tepper static void
hci_event_inquiry_result(struct hci_unit * unit,struct mbuf * m)4410a9108ebSHasso Tepper hci_event_inquiry_result(struct hci_unit *unit, struct mbuf *m)
4420a9108ebSHasso Tepper {
4430a9108ebSHasso Tepper 	hci_inquiry_result_ep ep;
44483aacedeSHasso Tepper 	hci_inquiry_response ir;
4450a9108ebSHasso Tepper 	struct hci_memo *memo;
44683aacedeSHasso Tepper 
44783aacedeSHasso Tepper 	KKASSERT(m->m_pkthdr.len >= sizeof(ep));
448*05d02a38SAaron LI 	m_copydata(m, 0, sizeof(ep), &ep);
44983aacedeSHasso Tepper 	m_adj(m, sizeof(ep));
45083aacedeSHasso Tepper 
45183aacedeSHasso Tepper 	DPRINTFN(1, "(%s) %d response%s\n", device_get_nameunit(unit->hci_dev),
45283aacedeSHasso Tepper 	    ep.num_responses, (ep.num_responses == 1 ? "" : "s"));
45383aacedeSHasso Tepper 
45483aacedeSHasso Tepper 	while(ep.num_responses--) {
45583aacedeSHasso Tepper 		KKASSERT(m->m_pkthdr.len >= sizeof(ir));
456*05d02a38SAaron LI 		m_copydata(m, 0, sizeof(ir), &ir);
45783aacedeSHasso Tepper 		m_adj(m, sizeof(ir));
45883aacedeSHasso Tepper 
45983aacedeSHasso Tepper 		DPRINTFN(1, "bdaddr %02x:%02x:%02x:%02x:%02x:%02x\n",
46083aacedeSHasso Tepper 			ir.bdaddr.b[5], ir.bdaddr.b[4], ir.bdaddr.b[3],
46183aacedeSHasso Tepper 			ir.bdaddr.b[2], ir.bdaddr.b[1], ir.bdaddr.b[0]);
46283aacedeSHasso Tepper 
46383aacedeSHasso Tepper 		memo = hci_memo_new(unit, &ir.bdaddr);
46483aacedeSHasso Tepper 		if (memo != NULL) {
46583aacedeSHasso Tepper 			memo->page_scan_rep_mode = ir.page_scan_rep_mode;
46683aacedeSHasso Tepper 			memo->page_scan_mode = ir.page_scan_mode;
46783aacedeSHasso Tepper 			memo->clock_offset = ir.clock_offset;
46883aacedeSHasso Tepper 		}
46983aacedeSHasso Tepper 	}
47083aacedeSHasso Tepper }
47183aacedeSHasso Tepper 
47283aacedeSHasso Tepper /*
47383aacedeSHasso Tepper  * Inquiry Result with RSSI
47483aacedeSHasso Tepper  *
47583aacedeSHasso Tepper  * as above but different packet when RSSI result is enabled
47683aacedeSHasso Tepper  */
47783aacedeSHasso Tepper static void
hci_event_rssi_result(struct hci_unit * unit,struct mbuf * m)47883aacedeSHasso Tepper hci_event_rssi_result(struct hci_unit *unit, struct mbuf *m)
47983aacedeSHasso Tepper {
48083aacedeSHasso Tepper 	hci_rssi_result_ep ep;
48183aacedeSHasso Tepper 	hci_rssi_response rr;
48283aacedeSHasso Tepper 	struct hci_memo *memo;
4830a9108ebSHasso Tepper 
4840a9108ebSHasso Tepper 	KKASSERT(m->m_pkthdr.len >= sizeof(ep));
485*05d02a38SAaron LI 	m_copydata(m, 0, sizeof(ep), &ep);
4860a9108ebSHasso Tepper 	m_adj(m, sizeof(ep));
4870a9108ebSHasso Tepper 
4880a9108ebSHasso Tepper 	DPRINTFN(1, "%d response%s\n", ep.num_responses,
4890a9108ebSHasso Tepper 				(ep.num_responses == 1 ? "" : "s"));
4900a9108ebSHasso Tepper 
4910a9108ebSHasso Tepper 	while(ep.num_responses--) {
49283aacedeSHasso Tepper 		KKASSERT(m->m_pkthdr.len >= sizeof(rr));
493*05d02a38SAaron LI 		m_copydata(m, 0, sizeof(rr), &rr);
49483aacedeSHasso Tepper 		m_adj(m, sizeof(rr));
4950a9108ebSHasso Tepper 
4960a9108ebSHasso Tepper 		DPRINTFN(1, "bdaddr %02x:%02x:%02x:%02x:%02x:%02x\n",
49783aacedeSHasso Tepper 			rr.bdaddr.b[5], rr.bdaddr.b[4], rr.bdaddr.b[3],
49883aacedeSHasso Tepper 			rr.bdaddr.b[2], rr.bdaddr.b[1], rr.bdaddr.b[0]);
4990a9108ebSHasso Tepper 
50083aacedeSHasso Tepper 		memo = hci_memo_new(unit, &rr.bdaddr);
50183aacedeSHasso Tepper 		if (memo != NULL) {
50283aacedeSHasso Tepper 			memo->page_scan_rep_mode = rr.page_scan_rep_mode;
50383aacedeSHasso Tepper 			memo->page_scan_mode = 0;
50483aacedeSHasso Tepper 			memo->clock_offset = rr.clock_offset;
5050a9108ebSHasso Tepper 		}
5060a9108ebSHasso Tepper 	}
5070a9108ebSHasso Tepper }
5080a9108ebSHasso Tepper 
5090a9108ebSHasso Tepper /*
5100a9108ebSHasso Tepper  * Connection Complete
5110a9108ebSHasso Tepper  *
5120a9108ebSHasso Tepper  * Sent to us when a connection is made. If there is no link
5130a9108ebSHasso Tepper  * structure already allocated for this, we must have changed
5140a9108ebSHasso Tepper  * our mind, so just disconnect.
5150a9108ebSHasso Tepper  */
5160a9108ebSHasso Tepper static void
hci_event_con_compl(struct hci_unit * unit,struct mbuf * m)5170a9108ebSHasso Tepper hci_event_con_compl(struct hci_unit *unit, struct mbuf *m)
5180a9108ebSHasso Tepper {
5190a9108ebSHasso Tepper 	hci_con_compl_ep ep;
5200a9108ebSHasso Tepper 	hci_write_link_policy_settings_cp cp;
5210a9108ebSHasso Tepper 	struct hci_link *link;
5220a9108ebSHasso Tepper 	int err;
5230a9108ebSHasso Tepper 
5240a9108ebSHasso Tepper 	KKASSERT(m->m_pkthdr.len >= sizeof(ep));
525*05d02a38SAaron LI 	m_copydata(m, 0, sizeof(ep), &ep);
5260a9108ebSHasso Tepper 	m_adj(m, sizeof(ep));
5270a9108ebSHasso Tepper 
5280a9108ebSHasso Tepper 	DPRINTFN(1, "(%s) %s connection complete for "
5290a9108ebSHasso Tepper 		"%02x:%02x:%02x:%02x:%02x:%02x status %#x\n",
53083aacedeSHasso Tepper 		device_get_nameunit(unit->hci_dev),
5310a9108ebSHasso Tepper 		(ep.link_type == HCI_LINK_ACL ? "ACL" : "SCO"),
5320a9108ebSHasso Tepper 		ep.bdaddr.b[5], ep.bdaddr.b[4], ep.bdaddr.b[3],
5330a9108ebSHasso Tepper 		ep.bdaddr.b[2], ep.bdaddr.b[1], ep.bdaddr.b[0],
5340a9108ebSHasso Tepper 		ep.status);
5350a9108ebSHasso Tepper 
5360a9108ebSHasso Tepper 	link = hci_link_lookup_bdaddr(unit, &ep.bdaddr, ep.link_type);
5370a9108ebSHasso Tepper 
5380a9108ebSHasso Tepper 	if (ep.status) {
5390a9108ebSHasso Tepper 		if (link != NULL) {
5400a9108ebSHasso Tepper 			switch (ep.status) {
5410a9108ebSHasso Tepper 			case 0x04: /* "Page Timeout" */
5420a9108ebSHasso Tepper 				err = EHOSTDOWN;
5430a9108ebSHasso Tepper 				break;
5440a9108ebSHasso Tepper 
5450a9108ebSHasso Tepper 			case 0x08: /* "Connection Timed Out" */
5460a9108ebSHasso Tepper 			case 0x10: /* "Connection Accept Timeout Exceeded" */
5470a9108ebSHasso Tepper 				err = ETIMEDOUT;
5480a9108ebSHasso Tepper 				break;
5490a9108ebSHasso Tepper 
5500a9108ebSHasso Tepper 			case 0x16: /* "Connection Terminated by Local Host" */
5510a9108ebSHasso Tepper 				err = 0;
5520a9108ebSHasso Tepper 				break;
5530a9108ebSHasso Tepper 
5540a9108ebSHasso Tepper 			default:
5550a9108ebSHasso Tepper 				err = ECONNREFUSED;
5560a9108ebSHasso Tepper 				break;
5570a9108ebSHasso Tepper 			}
5580a9108ebSHasso Tepper 
5590a9108ebSHasso Tepper 			hci_link_free(link, err);
5600a9108ebSHasso Tepper 		}
5610a9108ebSHasso Tepper 
5620a9108ebSHasso Tepper 		return;
5630a9108ebSHasso Tepper 	}
5640a9108ebSHasso Tepper 
5650a9108ebSHasso Tepper 	if (link == NULL) {
5660a9108ebSHasso Tepper 		hci_discon_cp dp;
5670a9108ebSHasso Tepper 
5680a9108ebSHasso Tepper 		dp.con_handle = ep.con_handle;
5690a9108ebSHasso Tepper 		dp.reason = 0x13; /* "Remote User Terminated Connection" */
5700a9108ebSHasso Tepper 
5710a9108ebSHasso Tepper 		hci_send_cmd(unit, HCI_CMD_DISCONNECT, &dp, sizeof(dp));
5720a9108ebSHasso Tepper 		return;
5730a9108ebSHasso Tepper 	}
5740a9108ebSHasso Tepper 
5750a9108ebSHasso Tepper 	/* XXX could check auth_enable here */
5760a9108ebSHasso Tepper 
5770a9108ebSHasso Tepper 	if (ep.encryption_mode)
5780a9108ebSHasso Tepper 		link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_ENCRYPT);
5790a9108ebSHasso Tepper 
5800a9108ebSHasso Tepper 	link->hl_state = HCI_LINK_OPEN;
5810a9108ebSHasso Tepper 	link->hl_handle = HCI_CON_HANDLE(letoh16(ep.con_handle));
5820a9108ebSHasso Tepper 
5830a9108ebSHasso Tepper 	if (ep.link_type == HCI_LINK_ACL) {
5840a9108ebSHasso Tepper 		cp.con_handle = ep.con_handle;
5850a9108ebSHasso Tepper 		cp.settings = htole16(unit->hci_link_policy);
5860a9108ebSHasso Tepper 		err = hci_send_cmd(unit, HCI_CMD_WRITE_LINK_POLICY_SETTINGS,
5870a9108ebSHasso Tepper 						&cp, sizeof(cp));
5880a9108ebSHasso Tepper 		if (err)
5890a9108ebSHasso Tepper 			kprintf("%s: Warning, could not write link policy\n",
59083aacedeSHasso Tepper 			    device_get_nameunit(unit->hci_dev));
59183aacedeSHasso Tepper 
59283aacedeSHasso Tepper 		err = hci_send_cmd(unit, HCI_CMD_READ_CLOCK_OFFSET,
59383aacedeSHasso Tepper 				    &cp.con_handle, sizeof(cp.con_handle));
59483aacedeSHasso Tepper 		if (err)
59583aacedeSHasso Tepper 			kprintf("%s: Warning, could not read clock offset\n",
59683aacedeSHasso Tepper 			    device_get_nameunit(unit->hci_dev));
5970a9108ebSHasso Tepper 
5980a9108ebSHasso Tepper 		err = hci_acl_setmode(link);
5990a9108ebSHasso Tepper 		if (err == EINPROGRESS)
6000a9108ebSHasso Tepper 			return;
6010a9108ebSHasso Tepper 
6020a9108ebSHasso Tepper 		hci_acl_linkmode(link);
6030a9108ebSHasso Tepper 	} else {
6040a9108ebSHasso Tepper 		(*link->hl_sco->sp_proto->connected)(link->hl_sco->sp_upper);
6050a9108ebSHasso Tepper 	}
6060a9108ebSHasso Tepper }
6070a9108ebSHasso Tepper 
6080a9108ebSHasso Tepper /*
6090a9108ebSHasso Tepper  * Disconnection Complete
6100a9108ebSHasso Tepper  *
6110a9108ebSHasso Tepper  * This is sent in response to a disconnection request, but also if
6120a9108ebSHasso Tepper  * the remote device goes out of range.
6130a9108ebSHasso Tepper  */
6140a9108ebSHasso Tepper static void
hci_event_discon_compl(struct hci_unit * unit,struct mbuf * m)6150a9108ebSHasso Tepper hci_event_discon_compl(struct hci_unit *unit, struct mbuf *m)
6160a9108ebSHasso Tepper {
6170a9108ebSHasso Tepper 	hci_discon_compl_ep ep;
6180a9108ebSHasso Tepper 	struct hci_link *link;
6190a9108ebSHasso Tepper 
6200a9108ebSHasso Tepper 	KKASSERT(m->m_pkthdr.len >= sizeof(ep));
621*05d02a38SAaron LI 	m_copydata(m, 0, sizeof(ep), &ep);
6220a9108ebSHasso Tepper 	m_adj(m, sizeof(ep));
6230a9108ebSHasso Tepper 
6240a9108ebSHasso Tepper 	ep.con_handle = letoh16(ep.con_handle);
6250a9108ebSHasso Tepper 
62683aacedeSHasso Tepper 	DPRINTFN(1, "(%s) handle #%d, status=0x%x\n",
62783aacedeSHasso Tepper 	    device_get_nameunit(unit->hci_dev), ep.con_handle, ep.status);
6280a9108ebSHasso Tepper 
6290a9108ebSHasso Tepper 	link = hci_link_lookup_handle(unit, HCI_CON_HANDLE(ep.con_handle));
6300a9108ebSHasso Tepper 	if (link)
6310a9108ebSHasso Tepper 		hci_link_free(link, ENOENT); /* XXX NetBSD used ENOLINK here */
6320a9108ebSHasso Tepper }
6330a9108ebSHasso Tepper 
6340a9108ebSHasso Tepper /*
6350a9108ebSHasso Tepper  * Connect Request
6360a9108ebSHasso Tepper  *
6370a9108ebSHasso Tepper  * We check upstream for appropriate listeners and accept connections
6380a9108ebSHasso Tepper  * that are wanted.
6390a9108ebSHasso Tepper  */
6400a9108ebSHasso Tepper static void
hci_event_con_req(struct hci_unit * unit,struct mbuf * m)6410a9108ebSHasso Tepper hci_event_con_req(struct hci_unit *unit, struct mbuf *m)
6420a9108ebSHasso Tepper {
6430a9108ebSHasso Tepper 	hci_con_req_ep ep;
6440a9108ebSHasso Tepper 	hci_accept_con_cp ap;
6450a9108ebSHasso Tepper 	hci_reject_con_cp rp;
6460a9108ebSHasso Tepper 	struct hci_link *link;
6470a9108ebSHasso Tepper 
6480a9108ebSHasso Tepper 	KKASSERT(m->m_pkthdr.len >= sizeof(ep));
649*05d02a38SAaron LI 	m_copydata(m, 0, sizeof(ep), &ep);
6500a9108ebSHasso Tepper 	m_adj(m, sizeof(ep));
6510a9108ebSHasso Tepper 
65283aacedeSHasso Tepper 	DPRINTFN(1, "(%s) bdaddr %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x "
6530a9108ebSHasso Tepper 		"class %2.2x%2.2x%2.2x type %s\n",
65483aacedeSHasso Tepper 	    device_get_nameunit(unit->hci_dev),
6550a9108ebSHasso Tepper 	    ep.bdaddr.b[5], ep.bdaddr.b[4], ep.bdaddr.b[3],
6560a9108ebSHasso Tepper 	    ep.bdaddr.b[2], ep.bdaddr.b[1], ep.bdaddr.b[0],
6570a9108ebSHasso Tepper 	    ep.uclass[0], ep.uclass[1], ep.uclass[2],
6580a9108ebSHasso Tepper 	    ep.link_type == HCI_LINK_ACL ? "ACL" : "SCO");
6590a9108ebSHasso Tepper 
6600a9108ebSHasso Tepper 	if (ep.link_type == HCI_LINK_ACL)
6610a9108ebSHasso Tepper 		link = hci_acl_newconn(unit, &ep.bdaddr);
6620a9108ebSHasso Tepper 	else
6630a9108ebSHasso Tepper 		link = hci_sco_newconn(unit, &ep.bdaddr);
6640a9108ebSHasso Tepper 
6650a9108ebSHasso Tepper 	if (link == NULL) {
6660a9108ebSHasso Tepper 		memset(&rp, 0, sizeof(rp));
6670a9108ebSHasso Tepper 		bdaddr_copy(&rp.bdaddr, &ep.bdaddr);
6680a9108ebSHasso Tepper 		rp.reason = 0x0f;	/* Unacceptable BD_ADDR */
6690a9108ebSHasso Tepper 
6700a9108ebSHasso Tepper 		hci_send_cmd(unit, HCI_CMD_REJECT_CON, &rp, sizeof(rp));
6710a9108ebSHasso Tepper 	} else {
6720a9108ebSHasso Tepper 		memset(&ap, 0, sizeof(ap));
6730a9108ebSHasso Tepper 		bdaddr_copy(&ap.bdaddr, &ep.bdaddr);
6740a9108ebSHasso Tepper 		if (unit->hci_link_policy & HCI_LINK_POLICY_ENABLE_ROLE_SWITCH)
6750a9108ebSHasso Tepper 			ap.role = HCI_ROLE_MASTER;
6760a9108ebSHasso Tepper 		else
6770a9108ebSHasso Tepper 			ap.role = HCI_ROLE_SLAVE;
6780a9108ebSHasso Tepper 
6790a9108ebSHasso Tepper 		hci_send_cmd(unit, HCI_CMD_ACCEPT_CON, &ap, sizeof(ap));
6800a9108ebSHasso Tepper 	}
6810a9108ebSHasso Tepper }
6820a9108ebSHasso Tepper 
6830a9108ebSHasso Tepper /*
6840a9108ebSHasso Tepper  * Auth Complete
6850a9108ebSHasso Tepper  *
6860a9108ebSHasso Tepper  * Authentication has been completed on an ACL link. We can notify the
6870a9108ebSHasso Tepper  * upper layer protocols unless further mode changes are pending.
6880a9108ebSHasso Tepper  */
6890a9108ebSHasso Tepper static void
hci_event_auth_compl(struct hci_unit * unit,struct mbuf * m)6900a9108ebSHasso Tepper hci_event_auth_compl(struct hci_unit *unit, struct mbuf *m)
6910a9108ebSHasso Tepper {
6920a9108ebSHasso Tepper 	hci_auth_compl_ep ep;
6930a9108ebSHasso Tepper 	struct hci_link *link;
6940a9108ebSHasso Tepper 	int err;
6950a9108ebSHasso Tepper 
6960a9108ebSHasso Tepper 	KKASSERT(m->m_pkthdr.len >= sizeof(ep));
697*05d02a38SAaron LI 	m_copydata(m, 0, sizeof(ep), &ep);
6980a9108ebSHasso Tepper 	m_adj(m, sizeof(ep));
6990a9108ebSHasso Tepper 
7000a9108ebSHasso Tepper 	ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle));
7010a9108ebSHasso Tepper 
70283aacedeSHasso Tepper 	DPRINTFN(1, "(%s) handle #%d, status=0x%x\n",
70383aacedeSHasso Tepper 	    device_get_nameunit(unit->hci_dev), ep.con_handle, ep.status);
7040a9108ebSHasso Tepper 
7050a9108ebSHasso Tepper 	link = hci_link_lookup_handle(unit, ep.con_handle);
7060a9108ebSHasso Tepper 	if (link == NULL || link->hl_type != HCI_LINK_ACL)
7070a9108ebSHasso Tepper 		return;
7080a9108ebSHasso Tepper 
7090a9108ebSHasso Tepper 	if (ep.status == 0) {
7100a9108ebSHasso Tepper 		link->hl_flags |= HCI_LINK_AUTH;
7110a9108ebSHasso Tepper 
7120a9108ebSHasso Tepper 		if (link->hl_state == HCI_LINK_WAIT_AUTH)
7130a9108ebSHasso Tepper 			link->hl_state = HCI_LINK_OPEN;
7140a9108ebSHasso Tepper 
7150a9108ebSHasso Tepper 		err = hci_acl_setmode(link);
7160a9108ebSHasso Tepper 		if (err == EINPROGRESS)
7170a9108ebSHasso Tepper 			return;
7180a9108ebSHasso Tepper 	}
7190a9108ebSHasso Tepper 
7200a9108ebSHasso Tepper 	hci_acl_linkmode(link);
7210a9108ebSHasso Tepper }
7220a9108ebSHasso Tepper 
7230a9108ebSHasso Tepper /*
7240a9108ebSHasso Tepper  * Encryption Change
7250a9108ebSHasso Tepper  *
7260a9108ebSHasso Tepper  * The encryption status has changed. Basically, we note the change
7270a9108ebSHasso Tepper  * then notify the upper layer protocol unless further mode changes
7280a9108ebSHasso Tepper  * are pending.
7290a9108ebSHasso Tepper  * Note that if encryption gets disabled when it has been requested,
7300a9108ebSHasso Tepper  * we will attempt to enable it again.. (its a feature not a bug :)
7310a9108ebSHasso Tepper  */
7320a9108ebSHasso Tepper static void
hci_event_encryption_change(struct hci_unit * unit,struct mbuf * m)7330a9108ebSHasso Tepper hci_event_encryption_change(struct hci_unit *unit, struct mbuf *m)
7340a9108ebSHasso Tepper {
7350a9108ebSHasso Tepper 	hci_encryption_change_ep ep;
7360a9108ebSHasso Tepper 	struct hci_link *link;
7370a9108ebSHasso Tepper 	int err;
7380a9108ebSHasso Tepper 
7390a9108ebSHasso Tepper 	KKASSERT(m->m_pkthdr.len >= sizeof(ep));
740*05d02a38SAaron LI 	m_copydata(m, 0, sizeof(ep), &ep);
7410a9108ebSHasso Tepper 	m_adj(m, sizeof(ep));
7420a9108ebSHasso Tepper 
7430a9108ebSHasso Tepper 	ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle));
7440a9108ebSHasso Tepper 
74583aacedeSHasso Tepper 	DPRINTFN(1, "(%s) handle #%d, status=0x%x, encryption_enable=0x%x\n",
74683aacedeSHasso Tepper 	    device_get_nameunit(unit->hci_dev), ep.con_handle, ep.status,
74783aacedeSHasso Tepper 	    ep.encryption_enable);
7480a9108ebSHasso Tepper 
7490a9108ebSHasso Tepper 	link = hci_link_lookup_handle(unit, ep.con_handle);
7500a9108ebSHasso Tepper 	if (link == NULL || link->hl_type != HCI_LINK_ACL)
7510a9108ebSHasso Tepper 		return;
7520a9108ebSHasso Tepper 
7530a9108ebSHasso Tepper 	if (ep.status == 0) {
7540a9108ebSHasso Tepper 		if (ep.encryption_enable == 0)
7550a9108ebSHasso Tepper 			link->hl_flags &= ~HCI_LINK_ENCRYPT;
7560a9108ebSHasso Tepper 		else
7570a9108ebSHasso Tepper 			link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_ENCRYPT);
7580a9108ebSHasso Tepper 
7590a9108ebSHasso Tepper 		if (link->hl_state == HCI_LINK_WAIT_ENCRYPT)
7600a9108ebSHasso Tepper 			link->hl_state = HCI_LINK_OPEN;
7610a9108ebSHasso Tepper 
7620a9108ebSHasso Tepper 		err = hci_acl_setmode(link);
7630a9108ebSHasso Tepper 		if (err == EINPROGRESS)
7640a9108ebSHasso Tepper 			return;
7650a9108ebSHasso Tepper 	}
7660a9108ebSHasso Tepper 
7670a9108ebSHasso Tepper 	hci_acl_linkmode(link);
7680a9108ebSHasso Tepper }
7690a9108ebSHasso Tepper 
7700a9108ebSHasso Tepper /*
7710a9108ebSHasso Tepper  * Change Connection Link Key Complete
7720a9108ebSHasso Tepper  *
7730a9108ebSHasso Tepper  * Link keys are handled in userland but if we are waiting to secure
7740a9108ebSHasso Tepper  * this link, we should notify the upper protocols. A SECURE request
7750a9108ebSHasso Tepper  * only needs a single key change, so we can cancel the request.
7760a9108ebSHasso Tepper  */
7770a9108ebSHasso Tepper static void
hci_event_change_con_link_key_compl(struct hci_unit * unit,struct mbuf * m)7780a9108ebSHasso Tepper hci_event_change_con_link_key_compl(struct hci_unit *unit, struct mbuf *m)
7790a9108ebSHasso Tepper {
7800a9108ebSHasso Tepper 	hci_change_con_link_key_compl_ep ep;
7810a9108ebSHasso Tepper 	struct hci_link *link;
7820a9108ebSHasso Tepper 	int err;
7830a9108ebSHasso Tepper 
7840a9108ebSHasso Tepper 	KKASSERT(m->m_pkthdr.len >= sizeof(ep));
785*05d02a38SAaron LI 	m_copydata(m, 0, sizeof(ep), &ep);
7860a9108ebSHasso Tepper 	m_adj(m, sizeof(ep));
7870a9108ebSHasso Tepper 
7880a9108ebSHasso Tepper 	ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle));
7890a9108ebSHasso Tepper 
79083aacedeSHasso Tepper 	DPRINTFN(1, "(%s) handle #%d, status=0x%x\n",
79183aacedeSHasso Tepper 	    device_get_nameunit(unit->hci_dev), ep.con_handle, ep.status);
7920a9108ebSHasso Tepper 
7930a9108ebSHasso Tepper 	link = hci_link_lookup_handle(unit, ep.con_handle);
7940a9108ebSHasso Tepper 	if (link == NULL || link->hl_type != HCI_LINK_ACL)
7950a9108ebSHasso Tepper 		return;
7960a9108ebSHasso Tepper 
7970a9108ebSHasso Tepper 	link->hl_flags &= ~HCI_LINK_SECURE_REQ;
7980a9108ebSHasso Tepper 
7990a9108ebSHasso Tepper 	if (ep.status == 0) {
8000a9108ebSHasso Tepper 		link->hl_flags |= (HCI_LINK_AUTH | HCI_LINK_SECURE);
8010a9108ebSHasso Tepper 
8020a9108ebSHasso Tepper 		if (link->hl_state == HCI_LINK_WAIT_SECURE)
8030a9108ebSHasso Tepper 			link->hl_state = HCI_LINK_OPEN;
8040a9108ebSHasso Tepper 
8050a9108ebSHasso Tepper 		err = hci_acl_setmode(link);
8060a9108ebSHasso Tepper 		if (err == EINPROGRESS)
8070a9108ebSHasso Tepper 			return;
8080a9108ebSHasso Tepper 	}
8090a9108ebSHasso Tepper 
8100a9108ebSHasso Tepper 	hci_acl_linkmode(link);
8110a9108ebSHasso Tepper }
8120a9108ebSHasso Tepper 
8130a9108ebSHasso Tepper /*
81483aacedeSHasso Tepper  * Read Clock Offset Complete
81583aacedeSHasso Tepper  *
81683aacedeSHasso Tepper  * We keep a note of the clock offset of remote devices when a
81783aacedeSHasso Tepper  * link is made, in order to facilitate reconnections to the device
81883aacedeSHasso Tepper  */
81983aacedeSHasso Tepper static void
hci_event_read_clock_offset_compl(struct hci_unit * unit,struct mbuf * m)82083aacedeSHasso Tepper hci_event_read_clock_offset_compl(struct hci_unit *unit, struct mbuf *m)
82183aacedeSHasso Tepper {
82283aacedeSHasso Tepper 	hci_read_clock_offset_compl_ep ep;
82383aacedeSHasso Tepper 	struct hci_link *link;
82483aacedeSHasso Tepper 
82583aacedeSHasso Tepper 	KKASSERT(m->m_pkthdr.len >= sizeof(ep));
826*05d02a38SAaron LI 	m_copydata(m, 0, sizeof(ep), &ep);
82783aacedeSHasso Tepper 	m_adj(m, sizeof(ep));
82883aacedeSHasso Tepper 
82983aacedeSHasso Tepper 	DPRINTFN(1, "handle #%d, offset=%u, status=0x%x\n",
83083aacedeSHasso Tepper 	    letoh16(ep.con_handle), letoh16(ep.clock_offset), ep.status);
83183aacedeSHasso Tepper 
83283aacedeSHasso Tepper 	ep.con_handle = HCI_CON_HANDLE(letoh16(ep.con_handle));
83383aacedeSHasso Tepper 	link = hci_link_lookup_handle(unit, ep.con_handle);
83483aacedeSHasso Tepper 
83583aacedeSHasso Tepper 	if (ep.status != 0 || link == NULL)
83683aacedeSHasso Tepper 		return;
83783aacedeSHasso Tepper 
83883aacedeSHasso Tepper 	link->hl_clock = ep.clock_offset;
83983aacedeSHasso Tepper }
84083aacedeSHasso Tepper 
84183aacedeSHasso Tepper /*
8420a9108ebSHasso Tepper  * process results of read_bdaddr command_complete event
8430a9108ebSHasso Tepper  */
8440a9108ebSHasso Tepper static void
hci_cmd_read_bdaddr(struct hci_unit * unit,struct mbuf * m)8450a9108ebSHasso Tepper hci_cmd_read_bdaddr(struct hci_unit *unit, struct mbuf *m)
8460a9108ebSHasso Tepper {
8470a9108ebSHasso Tepper 	hci_read_bdaddr_rp rp;
8480a9108ebSHasso Tepper 
8490a9108ebSHasso Tepper 	KKASSERT(m->m_pkthdr.len >= sizeof(rp));
850*05d02a38SAaron LI 	m_copydata(m, 0, sizeof(rp), &rp);
8510a9108ebSHasso Tepper 	m_adj(m, sizeof(rp));
8520a9108ebSHasso Tepper 
8530a9108ebSHasso Tepper 	if (rp.status > 0)
8540a9108ebSHasso Tepper 		return;
8550a9108ebSHasso Tepper 
8560a9108ebSHasso Tepper 	if ((unit->hci_flags & BTF_INIT_BDADDR) == 0)
8570a9108ebSHasso Tepper 		return;
8580a9108ebSHasso Tepper 
8590a9108ebSHasso Tepper 	bdaddr_copy(&unit->hci_bdaddr, &rp.bdaddr);
8600a9108ebSHasso Tepper 
8610a9108ebSHasso Tepper 	unit->hci_flags &= ~BTF_INIT_BDADDR;
8620a9108ebSHasso Tepper 
8630a9108ebSHasso Tepper 	wakeup(unit);
8640a9108ebSHasso Tepper }
8650a9108ebSHasso Tepper 
8660a9108ebSHasso Tepper /*
8670a9108ebSHasso Tepper  * process results of read_buffer_size command_complete event
8680a9108ebSHasso Tepper  */
8690a9108ebSHasso Tepper static void
hci_cmd_read_buffer_size(struct hci_unit * unit,struct mbuf * m)8700a9108ebSHasso Tepper hci_cmd_read_buffer_size(struct hci_unit *unit, struct mbuf *m)
8710a9108ebSHasso Tepper {
8720a9108ebSHasso Tepper 	hci_read_buffer_size_rp rp;
8730a9108ebSHasso Tepper 
8740a9108ebSHasso Tepper 	KKASSERT(m->m_pkthdr.len >= sizeof(rp));
875*05d02a38SAaron LI 	m_copydata(m, 0, sizeof(rp), &rp);
8760a9108ebSHasso Tepper 	m_adj(m, sizeof(rp));
8770a9108ebSHasso Tepper 
8780a9108ebSHasso Tepper 	if (rp.status > 0)
8790a9108ebSHasso Tepper 		return;
8800a9108ebSHasso Tepper 
8810a9108ebSHasso Tepper 	if ((unit->hci_flags & BTF_INIT_BUFFER_SIZE) == 0)
8820a9108ebSHasso Tepper 		return;
8830a9108ebSHasso Tepper 
8840a9108ebSHasso Tepper 	unit->hci_max_acl_size = letoh16(rp.max_acl_size);
8850a9108ebSHasso Tepper 	unit->hci_num_acl_pkts = letoh16(rp.num_acl_pkts);
8860a9108ebSHasso Tepper 	unit->hci_max_sco_size = rp.max_sco_size;
8870a9108ebSHasso Tepper 	unit->hci_num_sco_pkts = letoh16(rp.num_sco_pkts);
8880a9108ebSHasso Tepper 
8890a9108ebSHasso Tepper 	unit->hci_flags &= ~BTF_INIT_BUFFER_SIZE;
8900a9108ebSHasso Tepper 
8910a9108ebSHasso Tepper 	wakeup(unit);
8920a9108ebSHasso Tepper }
8930a9108ebSHasso Tepper 
8940a9108ebSHasso Tepper /*
8950a9108ebSHasso Tepper  * process results of read_local_features command_complete event
8960a9108ebSHasso Tepper  */
8970a9108ebSHasso Tepper static void
hci_cmd_read_local_features(struct hci_unit * unit,struct mbuf * m)8980a9108ebSHasso Tepper hci_cmd_read_local_features(struct hci_unit *unit, struct mbuf *m)
8990a9108ebSHasso Tepper {
9000a9108ebSHasso Tepper 	hci_read_local_features_rp rp;
9010a9108ebSHasso Tepper 
9020a9108ebSHasso Tepper 	KKASSERT(m->m_pkthdr.len >= sizeof(rp));
903*05d02a38SAaron LI 	m_copydata(m, 0, sizeof(rp), &rp);
9040a9108ebSHasso Tepper 	m_adj(m, sizeof(rp));
9050a9108ebSHasso Tepper 
9060a9108ebSHasso Tepper 	if (rp.status > 0)
9070a9108ebSHasso Tepper 		return;
9080a9108ebSHasso Tepper 
9090a9108ebSHasso Tepper 	if ((unit->hci_flags & BTF_INIT_FEATURES) == 0)
9100a9108ebSHasso Tepper 		return;
9110a9108ebSHasso Tepper 
9120a9108ebSHasso Tepper 	unit->hci_lmp_mask = 0;
9130a9108ebSHasso Tepper 
9140a9108ebSHasso Tepper 	if (rp.features[0] & HCI_LMP_ROLE_SWITCH)
9150a9108ebSHasso Tepper 		unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_ROLE_SWITCH;
9160a9108ebSHasso Tepper 
9170a9108ebSHasso Tepper 	if (rp.features[0] & HCI_LMP_HOLD_MODE)
9180a9108ebSHasso Tepper 		unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_HOLD_MODE;
9190a9108ebSHasso Tepper 
9200a9108ebSHasso Tepper 	if (rp.features[0] & HCI_LMP_SNIFF_MODE)
9210a9108ebSHasso Tepper 		unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_SNIFF_MODE;
9220a9108ebSHasso Tepper 
9230a9108ebSHasso Tepper 	if (rp.features[1] & HCI_LMP_PARK_MODE)
9240a9108ebSHasso Tepper 		unit->hci_lmp_mask |= HCI_LINK_POLICY_ENABLE_PARK_MODE;
9250a9108ebSHasso Tepper 
9260a9108ebSHasso Tepper 	/* ACL packet mask */
9270a9108ebSHasso Tepper 	unit->hci_acl_mask = HCI_PKT_DM1 | HCI_PKT_DH1;
9280a9108ebSHasso Tepper 
9290a9108ebSHasso Tepper 	if (rp.features[0] & HCI_LMP_3SLOT)
9300a9108ebSHasso Tepper 		unit->hci_acl_mask |= HCI_PKT_DM3 | HCI_PKT_DH3;
9310a9108ebSHasso Tepper 
9320a9108ebSHasso Tepper 	if (rp.features[0] & HCI_LMP_5SLOT)
9330a9108ebSHasso Tepper 		unit->hci_acl_mask |= HCI_PKT_DM5 | HCI_PKT_DH5;
9340a9108ebSHasso Tepper 
9350a9108ebSHasso Tepper 	if ((rp.features[3] & HCI_LMP_EDR_ACL_2MBPS) == 0)
9360a9108ebSHasso Tepper 		unit->hci_acl_mask |= HCI_PKT_2MBPS_DH1
9370a9108ebSHasso Tepper 				    | HCI_PKT_2MBPS_DH3
9380a9108ebSHasso Tepper 				    | HCI_PKT_2MBPS_DH5;
9390a9108ebSHasso Tepper 
9400a9108ebSHasso Tepper 	if ((rp.features[3] & HCI_LMP_EDR_ACL_3MBPS) == 0)
9410a9108ebSHasso Tepper 		unit->hci_acl_mask |= HCI_PKT_3MBPS_DH1
9420a9108ebSHasso Tepper 				    | HCI_PKT_3MBPS_DH3
9430a9108ebSHasso Tepper 				    | HCI_PKT_3MBPS_DH5;
9440a9108ebSHasso Tepper 
9450a9108ebSHasso Tepper 	if ((rp.features[4] & HCI_LMP_3SLOT_EDR_ACL) == 0)
9460a9108ebSHasso Tepper 		unit->hci_acl_mask |= HCI_PKT_2MBPS_DH3
9470a9108ebSHasso Tepper 				    | HCI_PKT_3MBPS_DH3;
9480a9108ebSHasso Tepper 
9490a9108ebSHasso Tepper 	if ((rp.features[5] & HCI_LMP_5SLOT_EDR_ACL) == 0)
9500a9108ebSHasso Tepper 		unit->hci_acl_mask |= HCI_PKT_2MBPS_DH5
9510a9108ebSHasso Tepper 				    | HCI_PKT_3MBPS_DH5;
9520a9108ebSHasso Tepper 
9530a9108ebSHasso Tepper 	unit->hci_packet_type = unit->hci_acl_mask;
9540a9108ebSHasso Tepper 
9550a9108ebSHasso Tepper 	/* SCO packet mask */
9560a9108ebSHasso Tepper 	unit->hci_sco_mask = 0;
9570a9108ebSHasso Tepper 	if (rp.features[1] & HCI_LMP_SCO_LINK)
9580a9108ebSHasso Tepper 		unit->hci_sco_mask |= HCI_PKT_HV1;
9590a9108ebSHasso Tepper 
9600a9108ebSHasso Tepper 	if (rp.features[1] & HCI_LMP_HV2_PKT)
9610a9108ebSHasso Tepper 		unit->hci_sco_mask |= HCI_PKT_HV2;
9620a9108ebSHasso Tepper 
9630a9108ebSHasso Tepper 	if (rp.features[1] & HCI_LMP_HV3_PKT)
9640a9108ebSHasso Tepper 		unit->hci_sco_mask |= HCI_PKT_HV3;
9650a9108ebSHasso Tepper 
9660a9108ebSHasso Tepper 	if (rp.features[3] & HCI_LMP_EV3_PKT)
9670a9108ebSHasso Tepper 		unit->hci_sco_mask |= HCI_PKT_EV3;
9680a9108ebSHasso Tepper 
9690a9108ebSHasso Tepper 	if (rp.features[4] & HCI_LMP_EV4_PKT)
9700a9108ebSHasso Tepper 		unit->hci_sco_mask |= HCI_PKT_EV4;
9710a9108ebSHasso Tepper 
9720a9108ebSHasso Tepper 	if (rp.features[4] & HCI_LMP_EV5_PKT)
9730a9108ebSHasso Tepper 		unit->hci_sco_mask |= HCI_PKT_EV5;
9740a9108ebSHasso Tepper 
9750a9108ebSHasso Tepper 	/* XXX what do 2MBPS/3MBPS/3SLOT eSCO mean? */
9760a9108ebSHasso Tepper 
9770a9108ebSHasso Tepper 	unit->hci_flags &= ~BTF_INIT_FEATURES;
9780a9108ebSHasso Tepper 
9790a9108ebSHasso Tepper 	wakeup(unit);
9800a9108ebSHasso Tepper 
9810a9108ebSHasso Tepper 	DPRINTFN(1, "%s: lmp_mask %4.4x, acl_mask %4.4x, sco_mask %4.4x\n",
98283aacedeSHasso Tepper 		device_get_nameunit(unit->hci_dev), unit->hci_lmp_mask,
9830a9108ebSHasso Tepper 		unit->hci_acl_mask, unit->hci_sco_mask);
9840a9108ebSHasso Tepper }
9850a9108ebSHasso Tepper 
9860a9108ebSHasso Tepper /*
98783aacedeSHasso Tepper  * process results of read_local_ver command_complete event
98883aacedeSHasso Tepper  *
98983aacedeSHasso Tepper  * reading local supported commands is only supported from 1.2 spec
99083aacedeSHasso Tepper  */
99183aacedeSHasso Tepper static void
hci_cmd_read_local_ver(struct hci_unit * unit,struct mbuf * m)99283aacedeSHasso Tepper hci_cmd_read_local_ver(struct hci_unit *unit, struct mbuf *m)
99383aacedeSHasso Tepper {
99483aacedeSHasso Tepper 	hci_read_local_ver_rp rp;
99583aacedeSHasso Tepper 
99683aacedeSHasso Tepper 	KKASSERT(m->m_pkthdr.len >= sizeof(rp));
997*05d02a38SAaron LI 	m_copydata(m, 0, sizeof(rp), &rp);
99883aacedeSHasso Tepper 	m_adj(m, sizeof(rp));
99983aacedeSHasso Tepper 
100083aacedeSHasso Tepper 	if (rp.status != 0)
100183aacedeSHasso Tepper 		return;
100283aacedeSHasso Tepper 
100383aacedeSHasso Tepper 	if ((unit->hci_flags & BTF_INIT_COMMANDS) == 0)
100483aacedeSHasso Tepper 		return;
100583aacedeSHasso Tepper 
100683aacedeSHasso Tepper 	if (rp.hci_version < HCI_SPEC_V12) {
100783aacedeSHasso Tepper 		unit->hci_flags &= ~BTF_INIT_COMMANDS;
100883aacedeSHasso Tepper 		wakeup(unit);
100983aacedeSHasso Tepper 		return;
101083aacedeSHasso Tepper 	}
101183aacedeSHasso Tepper 
101283aacedeSHasso Tepper 	hci_send_cmd(unit, HCI_CMD_READ_LOCAL_COMMANDS, NULL, 0);
101383aacedeSHasso Tepper }
101483aacedeSHasso Tepper 
101583aacedeSHasso Tepper /*
101683aacedeSHasso Tepper  * process results of read_local_commands command_complete event
101783aacedeSHasso Tepper  */
101883aacedeSHasso Tepper static void
hci_cmd_read_local_commands(struct hci_unit * unit,struct mbuf * m)101983aacedeSHasso Tepper hci_cmd_read_local_commands(struct hci_unit *unit, struct mbuf *m)
102083aacedeSHasso Tepper {
102183aacedeSHasso Tepper 	hci_read_local_commands_rp rp;
102283aacedeSHasso Tepper 
102383aacedeSHasso Tepper 	KKASSERT(m->m_pkthdr.len >= sizeof(rp));
1024*05d02a38SAaron LI 	m_copydata(m, 0, sizeof(rp), &rp);
102583aacedeSHasso Tepper 	m_adj(m, sizeof(rp));
102683aacedeSHasso Tepper 
102783aacedeSHasso Tepper 	if (rp.status != 0)
102883aacedeSHasso Tepper 		return;
102983aacedeSHasso Tepper 
103083aacedeSHasso Tepper 	if ((unit->hci_flags & BTF_INIT_COMMANDS) == 0)
103183aacedeSHasso Tepper 		return;
103283aacedeSHasso Tepper 
103383aacedeSHasso Tepper 	unit->hci_flags &= ~BTF_INIT_COMMANDS;
103483aacedeSHasso Tepper 	memcpy(unit->hci_cmds, rp.commands, HCI_COMMANDS_SIZE);
103583aacedeSHasso Tepper 
103683aacedeSHasso Tepper 	wakeup(unit);
103783aacedeSHasso Tepper }
103883aacedeSHasso Tepper 
103983aacedeSHasso Tepper /*
10400a9108ebSHasso Tepper  * process results of reset command_complete event
10410a9108ebSHasso Tepper  *
10420a9108ebSHasso Tepper  * This has killed all the connections, so close down anything we have left,
10430a9108ebSHasso Tepper  * and reinitialise the unit.
10440a9108ebSHasso Tepper  */
10450a9108ebSHasso Tepper static void
hci_cmd_reset(struct hci_unit * unit,struct mbuf * m)10460a9108ebSHasso Tepper hci_cmd_reset(struct hci_unit *unit, struct mbuf *m)
10470a9108ebSHasso Tepper {
10480a9108ebSHasso Tepper 	hci_reset_rp rp;
10490a9108ebSHasso Tepper 	struct hci_link *link, *next;
10500a9108ebSHasso Tepper 	int acl;
10510a9108ebSHasso Tepper 
10520a9108ebSHasso Tepper 	KKASSERT(m->m_pkthdr.len >= sizeof(rp));
1053*05d02a38SAaron LI 	m_copydata(m, 0, sizeof(rp), &rp);
10540a9108ebSHasso Tepper 	m_adj(m, sizeof(rp));
10550a9108ebSHasso Tepper 
10560a9108ebSHasso Tepper 	if (rp.status != 0)
10570a9108ebSHasso Tepper 		return;
10580a9108ebSHasso Tepper 
10590a9108ebSHasso Tepper 	/*
10600a9108ebSHasso Tepper 	 * release SCO links first, since they may be holding
10610a9108ebSHasso Tepper 	 * an ACL link reference.
10620a9108ebSHasso Tepper 	 */
10630a9108ebSHasso Tepper 	for (acl = 0 ; acl < 2 ; acl++) {
10640a9108ebSHasso Tepper 		next = TAILQ_FIRST(&unit->hci_links);
10650a9108ebSHasso Tepper 		while ((link = next) != NULL) {
10660a9108ebSHasso Tepper 			next = TAILQ_NEXT(link, hl_next);
10670a9108ebSHasso Tepper 			if (acl || link->hl_type != HCI_LINK_ACL)
10680a9108ebSHasso Tepper 				hci_link_free(link, ECONNABORTED);
10690a9108ebSHasso Tepper 		}
10700a9108ebSHasso Tepper 	}
10710a9108ebSHasso Tepper 
10720a9108ebSHasso Tepper 	unit->hci_num_acl_pkts = 0;
10730a9108ebSHasso Tepper 	unit->hci_num_sco_pkts = 0;
10740a9108ebSHasso Tepper 
10750a9108ebSHasso Tepper 	if (hci_send_cmd(unit, HCI_CMD_READ_BDADDR, NULL, 0))
10760a9108ebSHasso Tepper 		return;
10770a9108ebSHasso Tepper 
10780a9108ebSHasso Tepper 	if (hci_send_cmd(unit, HCI_CMD_READ_BUFFER_SIZE, NULL, 0))
10790a9108ebSHasso Tepper 		return;
10800a9108ebSHasso Tepper 
10810a9108ebSHasso Tepper 	if (hci_send_cmd(unit, HCI_CMD_READ_LOCAL_FEATURES, NULL, 0))
10820a9108ebSHasso Tepper 		return;
108383aacedeSHasso Tepper 
108483aacedeSHasso Tepper 	if (hci_send_cmd(unit, HCI_CMD_READ_LOCAL_VER, NULL, 0))
108583aacedeSHasso Tepper 		return;
10860a9108ebSHasso Tepper }
1087