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