1*e54e5a64Splunky /* $NetBSD: hci_socket.c,v 1.47 2019/09/28 07:10:55 plunky Exp $ */
2a5c89047Sgdamore
3a5c89047Sgdamore /*-
4a5c89047Sgdamore * Copyright (c) 2005 Iain Hibbert.
5a5c89047Sgdamore * Copyright (c) 2006 Itronix Inc.
6a5c89047Sgdamore * All rights reserved.
7a5c89047Sgdamore *
8a5c89047Sgdamore * Redistribution and use in source and binary forms, with or without
9a5c89047Sgdamore * modification, are permitted provided that the following conditions
10a5c89047Sgdamore * are met:
11a5c89047Sgdamore * 1. Redistributions of source code must retain the above copyright
12a5c89047Sgdamore * notice, this list of conditions and the following disclaimer.
13a5c89047Sgdamore * 2. Redistributions in binary form must reproduce the above copyright
14a5c89047Sgdamore * notice, this list of conditions and the following disclaimer in the
15a5c89047Sgdamore * documentation and/or other materials provided with the distribution.
16a5c89047Sgdamore * 3. The name of Itronix Inc. may not be used to endorse
17a5c89047Sgdamore * or promote products derived from this software without specific
18a5c89047Sgdamore * prior written permission.
19a5c89047Sgdamore *
20a5c89047Sgdamore * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
21a5c89047Sgdamore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22a5c89047Sgdamore * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23a5c89047Sgdamore * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
24a5c89047Sgdamore * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25a5c89047Sgdamore * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26a5c89047Sgdamore * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27a5c89047Sgdamore * ON ANY THEORY OF LIABILITY, WHETHER IN
28a5c89047Sgdamore * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29a5c89047Sgdamore * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30a5c89047Sgdamore * POSSIBILITY OF SUCH DAMAGE.
31a5c89047Sgdamore */
32a5c89047Sgdamore
33a5c89047Sgdamore #include <sys/cdefs.h>
34*e54e5a64Splunky __KERNEL_RCSID(0, "$NetBSD: hci_socket.c,v 1.47 2019/09/28 07:10:55 plunky Exp $");
35a5c89047Sgdamore
36fb76dbd4Splunky /* load symbolic names */
37a5c89047Sgdamore #ifdef BLUETOOTH_DEBUG
38fb76dbd4Splunky #define PRUREQUESTS
39a5c89047Sgdamore #define PRCOREQUESTS
40a5c89047Sgdamore #endif
41a5c89047Sgdamore
42a5c89047Sgdamore #include <sys/param.h>
43a5c89047Sgdamore #include <sys/domain.h>
44a5c89047Sgdamore #include <sys/kauth.h>
45a5c89047Sgdamore #include <sys/kernel.h>
4614ecef6dSrmind #include <sys/kmem.h>
47a5c89047Sgdamore #include <sys/mbuf.h>
48a5c89047Sgdamore #include <sys/proc.h>
49a5c89047Sgdamore #include <sys/protosw.h>
50a5c89047Sgdamore #include <sys/socket.h>
51a5c89047Sgdamore #include <sys/socketvar.h>
52a5c89047Sgdamore #include <sys/systm.h>
53a5c89047Sgdamore
54a5c89047Sgdamore #include <netbt/bluetooth.h>
55a5c89047Sgdamore #include <netbt/hci.h>
56a5c89047Sgdamore
57a5c89047Sgdamore /*******************************************************************************
58a5c89047Sgdamore *
59a5c89047Sgdamore * HCI SOCK_RAW Sockets - for control of Bluetooth Devices
60a5c89047Sgdamore *
61a5c89047Sgdamore */
62a5c89047Sgdamore
63a5c89047Sgdamore /*
64a5c89047Sgdamore * the raw HCI protocol control block
65a5c89047Sgdamore */
66a5c89047Sgdamore struct hci_pcb {
67a5c89047Sgdamore struct socket *hp_socket; /* socket */
6880c6ec5dSplunky kauth_cred_t hp_cred; /* owner credential */
69a5c89047Sgdamore unsigned int hp_flags; /* flags */
70a5c89047Sgdamore bdaddr_t hp_laddr; /* local address */
71a5c89047Sgdamore bdaddr_t hp_raddr; /* remote address */
72a5c89047Sgdamore struct hci_filter hp_efilter; /* user event filter */
73a5c89047Sgdamore struct hci_filter hp_pfilter; /* user packet filter */
74a5c89047Sgdamore LIST_ENTRY(hci_pcb) hp_next; /* next HCI pcb */
75a5c89047Sgdamore };
76a5c89047Sgdamore
77a5c89047Sgdamore /* hp_flags */
78a5c89047Sgdamore #define HCI_DIRECTION (1<<1) /* direction control messages */
79a5c89047Sgdamore #define HCI_PROMISCUOUS (1<<2) /* listen to all units */
80a5c89047Sgdamore
81a5c89047Sgdamore LIST_HEAD(hci_pcb_list, hci_pcb) hci_pcb = LIST_HEAD_INITIALIZER(hci_pcb);
82a5c89047Sgdamore
83a5c89047Sgdamore /* sysctl defaults */
84a5c89047Sgdamore int hci_sendspace = HCI_CMD_PKT_SIZE;
85a5c89047Sgdamore int hci_recvspace = 4096;
86a5c89047Sgdamore
8780c6ec5dSplunky /* unprivileged commands opcode table */
88aeab3db8Splunky static const struct {
89aeab3db8Splunky uint16_t opcode;
90aeab3db8Splunky uint8_t offs; /* 0 - 63 */
91aeab3db8Splunky uint8_t mask; /* bit 0 - 7 */
9280c6ec5dSplunky uint8_t length; /* approved length */
93aeab3db8Splunky } hci_cmds[] = {
94aeab3db8Splunky { HCI_CMD_INQUIRY,
95aeab3db8Splunky 0, 0x01, sizeof(hci_inquiry_cp) },
96aeab3db8Splunky { HCI_CMD_REMOTE_NAME_REQ,
97aeab3db8Splunky 2, 0x08, sizeof(hci_remote_name_req_cp) },
98aeab3db8Splunky { HCI_CMD_READ_REMOTE_FEATURES,
99aeab3db8Splunky 2, 0x20, sizeof(hci_read_remote_features_cp) },
100aeab3db8Splunky { HCI_CMD_READ_REMOTE_EXTENDED_FEATURES,
101aeab3db8Splunky 2, 0x40, sizeof(hci_read_remote_extended_features_cp) },
102aeab3db8Splunky { HCI_CMD_READ_REMOTE_VER_INFO,
103aeab3db8Splunky 2, 0x80, sizeof(hci_read_remote_ver_info_cp) },
104aeab3db8Splunky { HCI_CMD_READ_CLOCK_OFFSET,
105aeab3db8Splunky 3, 0x01, sizeof(hci_read_clock_offset_cp) },
106aeab3db8Splunky { HCI_CMD_READ_LMP_HANDLE,
107aeab3db8Splunky 3, 0x02, sizeof(hci_read_lmp_handle_cp) },
108aeab3db8Splunky { HCI_CMD_ROLE_DISCOVERY,
109aeab3db8Splunky 4, 0x80, sizeof(hci_role_discovery_cp) },
110aeab3db8Splunky { HCI_CMD_READ_LINK_POLICY_SETTINGS,
111aeab3db8Splunky 5, 0x02, sizeof(hci_read_link_policy_settings_cp) },
112aeab3db8Splunky { HCI_CMD_READ_DEFAULT_LINK_POLICY_SETTINGS,
113aeab3db8Splunky 5, 0x08, 0 },
114aeab3db8Splunky { HCI_CMD_READ_PIN_TYPE,
115aeab3db8Splunky 6, 0x04, 0 },
116aeab3db8Splunky { HCI_CMD_READ_LOCAL_NAME,
117aeab3db8Splunky 7, 0x02, 0 },
118aeab3db8Splunky { HCI_CMD_READ_CON_ACCEPT_TIMEOUT,
119aeab3db8Splunky 7, 0x04, 0 },
120aeab3db8Splunky { HCI_CMD_READ_PAGE_TIMEOUT,
121aeab3db8Splunky 7, 0x10, 0 },
122aeab3db8Splunky { HCI_CMD_READ_SCAN_ENABLE,
123aeab3db8Splunky 7, 0x40, 0 },
124aeab3db8Splunky { HCI_CMD_READ_PAGE_SCAN_ACTIVITY,
125aeab3db8Splunky 8, 0x01, 0 },
126aeab3db8Splunky { HCI_CMD_READ_INQUIRY_SCAN_ACTIVITY,
127aeab3db8Splunky 8, 0x04, 0 },
128aeab3db8Splunky { HCI_CMD_READ_AUTH_ENABLE,
129aeab3db8Splunky 8, 0x10, 0 },
130aeab3db8Splunky { HCI_CMD_READ_ENCRYPTION_MODE,
131aeab3db8Splunky 8, 0x40, 0 },
132aeab3db8Splunky { HCI_CMD_READ_UNIT_CLASS,
133aeab3db8Splunky 9, 0x01, 0 },
134aeab3db8Splunky { HCI_CMD_READ_VOICE_SETTING,
135aeab3db8Splunky 9, 0x04, 0 },
136aeab3db8Splunky { HCI_CMD_READ_AUTO_FLUSH_TIMEOUT,
137aeab3db8Splunky 9, 0x10, sizeof(hci_read_auto_flush_timeout_cp) },
138aeab3db8Splunky { HCI_CMD_READ_NUM_BROADCAST_RETRANS,
139aeab3db8Splunky 9, 0x40, 0 },
140aeab3db8Splunky { HCI_CMD_READ_HOLD_MODE_ACTIVITY,
141aeab3db8Splunky 10, 0x01, 0 },
142aeab3db8Splunky { HCI_CMD_READ_XMIT_LEVEL,
143aeab3db8Splunky 10, 0x04, sizeof(hci_read_xmit_level_cp) },
144aeab3db8Splunky { HCI_CMD_READ_SCO_FLOW_CONTROL,
145aeab3db8Splunky 10, 0x08, 0 },
146aeab3db8Splunky { HCI_CMD_READ_LINK_SUPERVISION_TIMEOUT,
147aeab3db8Splunky 11, 0x01, sizeof(hci_read_link_supervision_timeout_cp) },
148aeab3db8Splunky { HCI_CMD_READ_NUM_SUPPORTED_IAC,
149aeab3db8Splunky 11, 0x04, 0 },
150aeab3db8Splunky { HCI_CMD_READ_IAC_LAP,
151aeab3db8Splunky 11, 0x08, 0 },
152aeab3db8Splunky { HCI_CMD_READ_PAGE_SCAN_PERIOD,
153aeab3db8Splunky 11, 0x20, 0 },
154aeab3db8Splunky { HCI_CMD_READ_PAGE_SCAN,
155aeab3db8Splunky 11, 0x80, 0 },
156aeab3db8Splunky { HCI_CMD_READ_INQUIRY_SCAN_TYPE,
157aeab3db8Splunky 12, 0x10, 0 },
158aeab3db8Splunky { HCI_CMD_READ_INQUIRY_MODE,
159aeab3db8Splunky 12, 0x40, 0 },
160aeab3db8Splunky { HCI_CMD_READ_PAGE_SCAN_TYPE,
161aeab3db8Splunky 13, 0x01, 0 },
162aeab3db8Splunky { HCI_CMD_READ_AFH_ASSESSMENT,
163aeab3db8Splunky 13, 0x04, 0 },
164aeab3db8Splunky { HCI_CMD_READ_LOCAL_VER,
165aeab3db8Splunky 14, 0x08, 0 },
166aeab3db8Splunky { HCI_CMD_READ_LOCAL_COMMANDS,
167aeab3db8Splunky 14, 0x10, 0 },
168aeab3db8Splunky { HCI_CMD_READ_LOCAL_FEATURES,
169aeab3db8Splunky 14, 0x20, 0 },
170aeab3db8Splunky { HCI_CMD_READ_LOCAL_EXTENDED_FEATURES,
171aeab3db8Splunky 14, 0x40, sizeof(hci_read_local_extended_features_cp) },
172aeab3db8Splunky { HCI_CMD_READ_BUFFER_SIZE,
173aeab3db8Splunky 14, 0x80, 0 },
174aeab3db8Splunky { HCI_CMD_READ_COUNTRY_CODE,
175aeab3db8Splunky 15, 0x01, 0 },
176aeab3db8Splunky { HCI_CMD_READ_BDADDR,
177aeab3db8Splunky 15, 0x02, 0 },
178aeab3db8Splunky { HCI_CMD_READ_FAILED_CONTACT_CNTR,
179aeab3db8Splunky 15, 0x04, sizeof(hci_read_failed_contact_cntr_cp) },
180aeab3db8Splunky { HCI_CMD_READ_LINK_QUALITY,
181aeab3db8Splunky 15, 0x10, sizeof(hci_read_link_quality_cp) },
182aeab3db8Splunky { HCI_CMD_READ_RSSI,
183aeab3db8Splunky 15, 0x20, sizeof(hci_read_rssi_cp) },
184aeab3db8Splunky { HCI_CMD_READ_AFH_CHANNEL_MAP,
185aeab3db8Splunky 15, 0x40, sizeof(hci_read_afh_channel_map_cp) },
186aeab3db8Splunky { HCI_CMD_READ_CLOCK,
187aeab3db8Splunky 15, 0x80, sizeof(hci_read_clock_cp) },
188aeab3db8Splunky { HCI_CMD_READ_LOOPBACK_MODE,
189aeab3db8Splunky 16, 0x01, 0 },
1907acc9392Splunky { HCI_CMD_READ_EXTENDED_INQUIRY_RSP,
1917acc9392Splunky 17, 0x01, 0 },
1927acc9392Splunky { HCI_CMD_READ_SIMPLE_PAIRING_MODE,
1937acc9392Splunky 17, 0x20, 0 },
1947acc9392Splunky { HCI_CMD_READ_INQUIRY_RSP_XMIT_POWER,
1957acc9392Splunky 18, 0x01, 0 },
1967acc9392Splunky { HCI_CMD_READ_DEFAULT_ERRDATA_REPORTING,
1977acc9392Splunky 18, 0x04, 0 },
198*e54e5a64Splunky { HCI_CMD_READ_ENCRYPTION_KEY_SIZE,
199*e54e5a64Splunky 20, 0x10, sizeof(hci_read_encryption_key_size_cp) },
200aeab3db8Splunky };
201aeab3db8Splunky
202a5c89047Sgdamore /*
20380c6ec5dSplunky * supply a basic device send/recv policy
20480c6ec5dSplunky */
20580c6ec5dSplunky static int
hci_device_cb(kauth_cred_t cred,kauth_action_t action,void * cookie,void * arg0,void * arg1,void * arg2,void * arg3)20680c6ec5dSplunky hci_device_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
20780c6ec5dSplunky void *arg0, void *arg1, void *arg2, void *arg3)
20880c6ec5dSplunky {
20980c6ec5dSplunky int i, result;
21080c6ec5dSplunky
21180c6ec5dSplunky result = KAUTH_RESULT_DEFER;
21280c6ec5dSplunky
21380c6ec5dSplunky switch (action) {
2144f6ac133Splunky case KAUTH_DEVICE_BLUETOOTH_SEND: {
21580c6ec5dSplunky struct hci_unit *unit = (struct hci_unit *)arg0;
21680c6ec5dSplunky hci_cmd_hdr_t *hdr = (hci_cmd_hdr_t *)arg1;
21780c6ec5dSplunky
21880c6ec5dSplunky /*
21980c6ec5dSplunky * Allow sending unprivileged commands if the packet size
22080c6ec5dSplunky * is correct and the unit claims to support it
221a5c89047Sgdamore */
222a5c89047Sgdamore
2234f6ac133Splunky if (hdr->type != HCI_CMD_PKT)
2244f6ac133Splunky break;
2254f6ac133Splunky
226aeab3db8Splunky for (i = 0; i < __arraycount(hci_cmds); i++) {
22780c6ec5dSplunky if (hdr->opcode == hci_cmds[i].opcode
22880c6ec5dSplunky && hdr->length == hci_cmds[i].length
22980c6ec5dSplunky && (unit->hci_cmds[hci_cmds[i].offs] & hci_cmds[i].mask)) {
23080c6ec5dSplunky result = KAUTH_RESULT_ALLOW;
23180c6ec5dSplunky break;
23280c6ec5dSplunky }
23380c6ec5dSplunky }
234b1b95bf6Splunky
235aeab3db8Splunky break;
236a5c89047Sgdamore }
237a5c89047Sgdamore
2384f6ac133Splunky case KAUTH_DEVICE_BLUETOOTH_RECV:
2394f6ac133Splunky switch((uint8_t)(uintptr_t)arg0) {
2404f6ac133Splunky case HCI_CMD_PKT: {
2414f6ac133Splunky uint16_t opcode = (uint16_t)(uintptr_t)arg1;
24280c6ec5dSplunky
24380c6ec5dSplunky /*
24480c6ec5dSplunky * Allow to see any unprivileged command packet
24580c6ec5dSplunky */
24680c6ec5dSplunky
24780c6ec5dSplunky for (i = 0; i < __arraycount(hci_cmds); i++) {
24880c6ec5dSplunky if (opcode == hci_cmds[i].opcode) {
24980c6ec5dSplunky result = KAUTH_RESULT_ALLOW;
25080c6ec5dSplunky break;
25180c6ec5dSplunky }
252a5c89047Sgdamore }
253a5c89047Sgdamore
25480c6ec5dSplunky break;
25580c6ec5dSplunky }
25680c6ec5dSplunky
2574f6ac133Splunky case HCI_EVENT_PKT: {
2584f6ac133Splunky uint8_t event = (uint8_t)(uintptr_t)arg1;
25980c6ec5dSplunky
26080c6ec5dSplunky /*
26180c6ec5dSplunky * Allow to receive most events
26280c6ec5dSplunky */
263a5c89047Sgdamore
264b1b95bf6Splunky switch (event) {
265b1b95bf6Splunky case HCI_EVENT_RETURN_LINK_KEYS:
266b1b95bf6Splunky case HCI_EVENT_LINK_KEY_NOTIFICATION:
2677acc9392Splunky case HCI_EVENT_USER_CONFIRM_REQ:
2687acc9392Splunky case HCI_EVENT_USER_PASSKEY_NOTIFICATION:
269b1b95bf6Splunky case HCI_EVENT_VENDOR:
27080c6ec5dSplunky break;
27180c6ec5dSplunky
27280c6ec5dSplunky default:
27380c6ec5dSplunky result = KAUTH_RESULT_ALLOW;
27480c6ec5dSplunky break;
275a5c89047Sgdamore }
276a5c89047Sgdamore
27780c6ec5dSplunky break;
27880c6ec5dSplunky }
27980c6ec5dSplunky
2804f6ac133Splunky case HCI_ACL_DATA_PKT:
2814f6ac133Splunky case HCI_SCO_DATA_PKT: {
2824f6ac133Splunky /* uint16_t handle = (uint16_t)(uintptr_t)arg1; */
28380c6ec5dSplunky /*
28480c6ec5dSplunky * don't normally allow receiving data packets
28580c6ec5dSplunky */
28680c6ec5dSplunky break;
2874f6ac133Splunky }
2884f6ac133Splunky
2894f6ac133Splunky default:
2904f6ac133Splunky break;
2914f6ac133Splunky }
2924f6ac133Splunky
2934f6ac133Splunky break;
29480c6ec5dSplunky
29580c6ec5dSplunky default:
29680c6ec5dSplunky break;
29780c6ec5dSplunky }
29880c6ec5dSplunky
29980c6ec5dSplunky return result;
30080c6ec5dSplunky }
30180c6ec5dSplunky
30280c6ec5dSplunky /*
30380c6ec5dSplunky * HCI protocol init routine,
30480c6ec5dSplunky * - set up a kauth listener to provide basic packet access policy
30580c6ec5dSplunky */
30680c6ec5dSplunky void
hci_init(void)30780c6ec5dSplunky hci_init(void)
30880c6ec5dSplunky {
30980c6ec5dSplunky
31080c6ec5dSplunky if (kauth_listen_scope(KAUTH_SCOPE_DEVICE, hci_device_cb, NULL) == NULL)
31180c6ec5dSplunky panic("Bluetooth HCI: cannot listen on device scope");
312a5c89047Sgdamore }
313a5c89047Sgdamore
314a5c89047Sgdamore /*
315a5c89047Sgdamore * When command packet reaches the device, we can drop
316a5c89047Sgdamore * it from the socket buffer (called from hci_output_acl)
317a5c89047Sgdamore */
318a5c89047Sgdamore void
hci_drop(void * arg)319a5c89047Sgdamore hci_drop(void *arg)
320a5c89047Sgdamore {
321a5c89047Sgdamore struct socket *so = arg;
322a5c89047Sgdamore
323a5c89047Sgdamore sbdroprecord(&so->so_snd);
324a5c89047Sgdamore sowwakeup(so);
325a5c89047Sgdamore }
326a5c89047Sgdamore
327a5c89047Sgdamore /*
328a5c89047Sgdamore * HCI socket is going away and has some pending packets. We let them
329a5c89047Sgdamore * go by design, but remove the context pointer as it will be invalid
330a5c89047Sgdamore * and we no longer need to be notified.
331a5c89047Sgdamore */
332a5c89047Sgdamore static void
hci_cmdwait_flush(struct socket * so)333a5c89047Sgdamore hci_cmdwait_flush(struct socket *so)
334a5c89047Sgdamore {
335a5c89047Sgdamore struct hci_unit *unit;
336a5c89047Sgdamore struct socket *ctx;
337a5c89047Sgdamore struct mbuf *m;
338a5c89047Sgdamore
339a5c89047Sgdamore DPRINTF("flushing %p\n", so);
340a5c89047Sgdamore
341a5c89047Sgdamore SIMPLEQ_FOREACH(unit, &hci_unit_list, hci_next) {
342a5c89047Sgdamore m = MBUFQ_FIRST(&unit->hci_cmdwait);
343a5c89047Sgdamore while (m != NULL) {
344a5c89047Sgdamore ctx = M_GETCTX(m, struct socket *);
345a5c89047Sgdamore if (ctx == so)
346a5c89047Sgdamore M_SETCTX(m, NULL);
347a5c89047Sgdamore
348a5c89047Sgdamore m = MBUFQ_NEXT(m);
349a5c89047Sgdamore }
350a5c89047Sgdamore }
351a5c89047Sgdamore }
352a5c89047Sgdamore
35314ecef6dSrmind static int
hci_attach(struct socket * so,int proto)3548db4ab26Srmind hci_attach(struct socket *so, int proto)
35514ecef6dSrmind {
35614ecef6dSrmind struct hci_pcb *pcb;
35714ecef6dSrmind int error;
35814ecef6dSrmind
35914ecef6dSrmind KASSERT(so->so_pcb == NULL);
36014ecef6dSrmind
36114ecef6dSrmind if (so->so_lock == NULL) {
36214ecef6dSrmind mutex_obj_hold(bt_lock);
36314ecef6dSrmind so->so_lock = bt_lock;
36414ecef6dSrmind solock(so);
36514ecef6dSrmind }
36614ecef6dSrmind KASSERT(solocked(so));
36714ecef6dSrmind
36814ecef6dSrmind error = soreserve(so, hci_sendspace, hci_recvspace);
36914ecef6dSrmind if (error) {
37014ecef6dSrmind return error;
37114ecef6dSrmind }
37214ecef6dSrmind
37314ecef6dSrmind pcb = kmem_zalloc(sizeof(struct hci_pcb), KM_SLEEP);
37414ecef6dSrmind pcb->hp_cred = kauth_cred_dup(curlwp->l_cred);
37514ecef6dSrmind pcb->hp_socket = so;
37614ecef6dSrmind
37714ecef6dSrmind /*
37814ecef6dSrmind * Set default user filter. By default, socket only passes
37914ecef6dSrmind * Command_Complete and Command_Status Events.
38014ecef6dSrmind */
38114ecef6dSrmind hci_filter_set(HCI_EVENT_COMMAND_COMPL, &pcb->hp_efilter);
38214ecef6dSrmind hci_filter_set(HCI_EVENT_COMMAND_STATUS, &pcb->hp_efilter);
38314ecef6dSrmind hci_filter_set(HCI_EVENT_PKT, &pcb->hp_pfilter);
38414ecef6dSrmind
38514ecef6dSrmind LIST_INSERT_HEAD(&hci_pcb, pcb, hp_next);
38614ecef6dSrmind so->so_pcb = pcb;
38714ecef6dSrmind
38814ecef6dSrmind return 0;
38914ecef6dSrmind }
39014ecef6dSrmind
39114ecef6dSrmind static void
hci_detach(struct socket * so)3928db4ab26Srmind hci_detach(struct socket *so)
39314ecef6dSrmind {
39414ecef6dSrmind struct hci_pcb *pcb;
39514ecef6dSrmind
39614ecef6dSrmind pcb = (struct hci_pcb *)so->so_pcb;
39714ecef6dSrmind KASSERT(pcb != NULL);
39814ecef6dSrmind
39914ecef6dSrmind if (so->so_snd.sb_mb != NULL)
40014ecef6dSrmind hci_cmdwait_flush(so);
40114ecef6dSrmind
40214ecef6dSrmind if (pcb->hp_cred != NULL)
40314ecef6dSrmind kauth_cred_free(pcb->hp_cred);
40414ecef6dSrmind
40514ecef6dSrmind so->so_pcb = NULL;
40614ecef6dSrmind LIST_REMOVE(pcb, hp_next);
40714ecef6dSrmind kmem_free(pcb, sizeof(*pcb));
40814ecef6dSrmind }
40914ecef6dSrmind
4104c58642fSrtr static int
hci_accept(struct socket * so,struct sockaddr * nam)4112fe27f5bSrtr hci_accept(struct socket *so, struct sockaddr *nam)
4129e76bf78Srtr {
4139e76bf78Srtr KASSERT(solocked(so));
4149e76bf78Srtr
4159e76bf78Srtr return EOPNOTSUPP;
4169e76bf78Srtr }
4179e76bf78Srtr
4189e76bf78Srtr static int
hci_bind(struct socket * so,struct sockaddr * nam,struct lwp * l)4190da58ac0Srtr hci_bind(struct socket *so, struct sockaddr *nam, struct lwp *l)
42050c78d5eSrtr {
42150c78d5eSrtr struct hci_pcb *pcb = so->so_pcb;
4220da58ac0Srtr struct sockaddr_bt *sa = (struct sockaddr_bt *)nam;
42350c78d5eSrtr
42450c78d5eSrtr KASSERT(solocked(so));
42550c78d5eSrtr KASSERT(pcb != NULL);
42650c78d5eSrtr KASSERT(nam != NULL);
42750c78d5eSrtr
42850c78d5eSrtr if (sa->bt_len != sizeof(struct sockaddr_bt))
42950c78d5eSrtr return EINVAL;
43050c78d5eSrtr
43150c78d5eSrtr if (sa->bt_family != AF_BLUETOOTH)
43250c78d5eSrtr return EAFNOSUPPORT;
43350c78d5eSrtr
43450c78d5eSrtr bdaddr_copy(&pcb->hp_laddr, &sa->bt_bdaddr);
43550c78d5eSrtr
43650c78d5eSrtr if (bdaddr_any(&sa->bt_bdaddr))
43750c78d5eSrtr pcb->hp_flags |= HCI_PROMISCUOUS;
43850c78d5eSrtr else
43950c78d5eSrtr pcb->hp_flags &= ~HCI_PROMISCUOUS;
44050c78d5eSrtr
44150c78d5eSrtr return 0;
44250c78d5eSrtr }
44350c78d5eSrtr
44450c78d5eSrtr static int
hci_listen(struct socket * so,struct lwp * l)4450c9751c6Srtr hci_listen(struct socket *so, struct lwp *l)
44650c78d5eSrtr {
44750c78d5eSrtr KASSERT(solocked(so));
44850c78d5eSrtr
44950c78d5eSrtr return EOPNOTSUPP;
45050c78d5eSrtr }
45150c78d5eSrtr
45250c78d5eSrtr static int
hci_connect(struct socket * so,struct sockaddr * nam,struct lwp * l)453c9ac6aceSrtr hci_connect(struct socket *so, struct sockaddr *nam, struct lwp *l)
4544d1c14a6Srtr {
4554d1c14a6Srtr struct hci_pcb *pcb = so->so_pcb;
456c9ac6aceSrtr struct sockaddr_bt *sa = (struct sockaddr_bt *)nam;
4574d1c14a6Srtr
4584d1c14a6Srtr KASSERT(solocked(so));
4594d1c14a6Srtr KASSERT(pcb != NULL);
4604d1c14a6Srtr KASSERT(nam != NULL);
4614d1c14a6Srtr
4624d1c14a6Srtr if (sa->bt_len != sizeof(struct sockaddr_bt))
4634d1c14a6Srtr return EINVAL;
4644d1c14a6Srtr
4654d1c14a6Srtr if (sa->bt_family != AF_BLUETOOTH)
4664d1c14a6Srtr return EAFNOSUPPORT;
4674d1c14a6Srtr
4684d1c14a6Srtr if (hci_unit_lookup(&sa->bt_bdaddr) == NULL)
4694d1c14a6Srtr return EADDRNOTAVAIL;
4704d1c14a6Srtr
4714d1c14a6Srtr bdaddr_copy(&pcb->hp_raddr, &sa->bt_bdaddr);
4724d1c14a6Srtr soisconnected(so);
4734d1c14a6Srtr return 0;
4744d1c14a6Srtr }
4754d1c14a6Srtr
4764d1c14a6Srtr static int
hci_connect2(struct socket * so,struct socket * so2)477c1ee5d65Srtr hci_connect2(struct socket *so, struct socket *so2)
478c1ee5d65Srtr {
479c1ee5d65Srtr KASSERT(solocked(so));
480c1ee5d65Srtr
481c1ee5d65Srtr return EOPNOTSUPP;
482c1ee5d65Srtr }
483c1ee5d65Srtr
484c1ee5d65Srtr static int
hci_disconnect(struct socket * so)48508e341e4Srtr hci_disconnect(struct socket *so)
48608e341e4Srtr {
48708e341e4Srtr struct hci_pcb *pcb = so->so_pcb;
48808e341e4Srtr
48908e341e4Srtr KASSERT(solocked(so));
49008e341e4Srtr KASSERT(pcb != NULL);
49108e341e4Srtr
49208e341e4Srtr bdaddr_copy(&pcb->hp_raddr, BDADDR_ANY);
49308e341e4Srtr
49408e341e4Srtr /* XXX we cannot call soisdisconnected() here, as it sets
49508e341e4Srtr * SS_CANTRCVMORE and SS_CANTSENDMORE. The problem being,
49608e341e4Srtr * that soisconnected() does not clear these and if you
49708e341e4Srtr * try to reconnect this socket (which is permitted) you
49808e341e4Srtr * get a broken pipe when you try to write any data.
49908e341e4Srtr */
50008e341e4Srtr so->so_state &= ~SS_ISCONNECTED;
50108e341e4Srtr return 0;
50208e341e4Srtr }
50308e341e4Srtr
50408e341e4Srtr static int
hci_shutdown(struct socket * so)50508e341e4Srtr hci_shutdown(struct socket *so)
50608e341e4Srtr {
50708e341e4Srtr KASSERT(solocked(so));
50808e341e4Srtr
50908e341e4Srtr socantsendmore(so);
51008e341e4Srtr return 0;
51108e341e4Srtr }
51208e341e4Srtr
51308e341e4Srtr static int
hci_abort(struct socket * so)51408e341e4Srtr hci_abort(struct socket *so)
51508e341e4Srtr {
51608e341e4Srtr KASSERT(solocked(so));
51708e341e4Srtr
51808e341e4Srtr soisdisconnected(so);
51908e341e4Srtr hci_detach(so);
52008e341e4Srtr return 0;
52108e341e4Srtr }
52208e341e4Srtr
52308e341e4Srtr static int
hci_ioctl(struct socket * so,u_long cmd,void * nam,struct ifnet * ifp)52471b912b6Srtr hci_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp)
5254c58642fSrtr {
5264c58642fSrtr int err;
5274c58642fSrtr mutex_enter(bt_lock);
528ae1253a1Srtr err = hci_ioctl_pcb(cmd, nam);
5294c58642fSrtr mutex_exit(bt_lock);
5304c58642fSrtr return err;
5314c58642fSrtr }
5324c58642fSrtr
533c4feb117Srtr static int
hci_stat(struct socket * so,struct stat * ub)534c4feb117Srtr hci_stat(struct socket *so, struct stat *ub)
535c4feb117Srtr {
53671b912b6Srtr KASSERT(solocked(so));
53771b912b6Srtr
5381b60394dSrtr return 0;
539c4feb117Srtr }
540c4feb117Srtr
5413bb356e9Srtr static int
hci_peeraddr(struct socket * so,struct sockaddr * nam)5422fe27f5bSrtr hci_peeraddr(struct socket *so, struct sockaddr *nam)
5433bb356e9Srtr {
5443bb356e9Srtr struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;
5452fe27f5bSrtr struct sockaddr_bt *sa = (struct sockaddr_bt *)nam;
5463bb356e9Srtr
5473bb356e9Srtr KASSERT(solocked(so));
5483bb356e9Srtr KASSERT(pcb != NULL);
5493bb356e9Srtr KASSERT(nam != NULL);
5503bb356e9Srtr
5513bb356e9Srtr memset(sa, 0, sizeof(struct sockaddr_bt));
5523bb356e9Srtr sa->bt_len = sizeof(struct sockaddr_bt);
5533bb356e9Srtr sa->bt_family = AF_BLUETOOTH;
5543bb356e9Srtr bdaddr_copy(&sa->bt_bdaddr, &pcb->hp_raddr);
5553bb356e9Srtr return 0;
5563bb356e9Srtr }
5573bb356e9Srtr
5583bb356e9Srtr static int
hci_sockaddr(struct socket * so,struct sockaddr * nam)5592fe27f5bSrtr hci_sockaddr(struct socket *so, struct sockaddr *nam)
5603bb356e9Srtr {
5613bb356e9Srtr struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;
5622fe27f5bSrtr struct sockaddr_bt *sa = (struct sockaddr_bt *)nam;
5633bb356e9Srtr
5643bb356e9Srtr KASSERT(solocked(so));
5653bb356e9Srtr KASSERT(pcb != NULL);
5663bb356e9Srtr KASSERT(nam != NULL);
5673bb356e9Srtr
5683bb356e9Srtr memset(sa, 0, sizeof(struct sockaddr_bt));
5693bb356e9Srtr sa->bt_len = sizeof(struct sockaddr_bt);
5703bb356e9Srtr sa->bt_family = AF_BLUETOOTH;
5713bb356e9Srtr bdaddr_copy(&sa->bt_bdaddr, &pcb->hp_laddr);
5723bb356e9Srtr return 0;
5733bb356e9Srtr }
5743bb356e9Srtr
575d2d88be8Srtr static int
hci_rcvd(struct socket * so,int flags,struct lwp * l)576dc24950fSrtr hci_rcvd(struct socket *so, int flags, struct lwp *l)
577dc24950fSrtr {
578dc24950fSrtr KASSERT(solocked(so));
579dc24950fSrtr
580dc24950fSrtr return EOPNOTSUPP;
581dc24950fSrtr }
582dc24950fSrtr
583dc24950fSrtr static int
hci_recvoob(struct socket * so,struct mbuf * m,int flags)584d2d88be8Srtr hci_recvoob(struct socket *so, struct mbuf *m, int flags)
585d2d88be8Srtr {
586d2d88be8Srtr KASSERT(solocked(so));
587d2d88be8Srtr
588d2d88be8Srtr return EOPNOTSUPP;
589d2d88be8Srtr }
590d2d88be8Srtr
591d2d88be8Srtr static int
hci_send(struct socket * so,struct mbuf * m,struct sockaddr * nam,struct mbuf * control,struct lwp * l)592c9ac6aceSrtr hci_send(struct socket *so, struct mbuf *m, struct sockaddr *nam,
593c0e2453cSrtr struct mbuf *control, struct lwp *l)
594c0e2453cSrtr {
595c0e2453cSrtr struct hci_pcb *pcb = so->so_pcb;
596c9ac6aceSrtr struct sockaddr_bt *sa = (struct sockaddr_bt *)nam;
59707dbab06Splunky struct hci_unit *unit;
59807dbab06Splunky struct mbuf *m0;
59907dbab06Splunky hci_cmd_hdr_t hdr;
600c0e2453cSrtr int err = 0;
601c0e2453cSrtr
602c0e2453cSrtr KASSERT(solocked(so));
603c0e2453cSrtr KASSERT(pcb != NULL);
60407dbab06Splunky KASSERT(m != NULL);
605c0e2453cSrtr
606c0e2453cSrtr if (control) /* have no use for this */
607c0e2453cSrtr m_freem(control);
608c0e2453cSrtr
60907dbab06Splunky if (sa) {
610c0e2453cSrtr if (sa->bt_len != sizeof(struct sockaddr_bt)) {
611c0e2453cSrtr err = EINVAL;
61207dbab06Splunky goto bad;
613c0e2453cSrtr }
614c0e2453cSrtr
615c0e2453cSrtr if (sa->bt_family != AF_BLUETOOTH) {
616c0e2453cSrtr err = EAFNOSUPPORT;
61707dbab06Splunky goto bad;
618c0e2453cSrtr }
619c0e2453cSrtr }
620c0e2453cSrtr
62107dbab06Splunky /*
62207dbab06Splunky * this came from userland, so we check it out first
62307dbab06Splunky */
624c0e2453cSrtr
62507dbab06Splunky /* wants at least a header to start with */
62607dbab06Splunky if (m->m_pkthdr.len < sizeof(hdr)) {
62707dbab06Splunky err = EMSGSIZE;
62807dbab06Splunky goto bad;
62907dbab06Splunky }
63007dbab06Splunky m_copydata(m, 0, sizeof(hdr), &hdr);
63107dbab06Splunky hdr.opcode = le16toh(hdr.opcode);
63207dbab06Splunky
63307dbab06Splunky /* only allows CMD packets to be sent */
63407dbab06Splunky if (hdr.type != HCI_CMD_PKT) {
63507dbab06Splunky err = EINVAL;
63607dbab06Splunky goto bad;
63707dbab06Splunky }
63807dbab06Splunky
63907dbab06Splunky /* validates packet length */
64007dbab06Splunky if (m->m_pkthdr.len != sizeof(hdr) + hdr.length) {
64107dbab06Splunky err = EMSGSIZE;
64207dbab06Splunky goto bad;
64307dbab06Splunky }
64407dbab06Splunky
64507dbab06Splunky /* finds destination */
64607dbab06Splunky unit = hci_unit_lookup((sa ? &sa->bt_bdaddr : &pcb->hp_raddr));
64707dbab06Splunky if (unit == NULL) {
64807dbab06Splunky err = ENETDOWN;
64907dbab06Splunky goto bad;
65007dbab06Splunky }
65107dbab06Splunky
65207dbab06Splunky /* security checks for unprivileged users */
65307dbab06Splunky if (pcb->hp_cred != NULL
65407dbab06Splunky && kauth_authorize_device(pcb->hp_cred,
65507dbab06Splunky KAUTH_DEVICE_BLUETOOTH_SEND,
65607dbab06Splunky unit, &hdr, NULL, NULL) != 0) {
65707dbab06Splunky err = EPERM;
65807dbab06Splunky goto bad;
65907dbab06Splunky }
66007dbab06Splunky
66107dbab06Splunky /* makess a copy for precious to keep */
66207dbab06Splunky m0 = m_copypacket(m, M_DONTWAIT);
66307dbab06Splunky if (m0 == NULL) {
66407dbab06Splunky err = ENOMEM;
66507dbab06Splunky goto bad;
66607dbab06Splunky }
66707dbab06Splunky sbappendrecord(&pcb->hp_socket->so_snd, m0);
66807dbab06Splunky M_SETCTX(m, pcb->hp_socket); /* enable drop callback */
66907dbab06Splunky
67007dbab06Splunky DPRINTFN(2, "(%s) opcode (%03x|%04x)\n", device_xname(unit->hci_dev),
67107dbab06Splunky HCI_OGF(hdr.opcode), HCI_OCF(hdr.opcode));
67207dbab06Splunky
67307dbab06Splunky /* Sendss it */
67407dbab06Splunky if (unit->hci_num_cmd_pkts == 0)
67507dbab06Splunky MBUFQ_ENQUEUE(&unit->hci_cmdwait, m);
67607dbab06Splunky else
67707dbab06Splunky hci_output_cmd(unit, m);
67807dbab06Splunky
67907dbab06Splunky return 0;
68007dbab06Splunky
68107dbab06Splunky bad:
68207dbab06Splunky DPRINTF("packet (%d bytes) not sent (error %d)\n",
68307dbab06Splunky m->m_pkthdr.len, err);
684c0e2453cSrtr if (m)
685c0e2453cSrtr m_freem(m);
686c0e2453cSrtr
687c0e2453cSrtr return err;
688c0e2453cSrtr }
689c0e2453cSrtr
690c0e2453cSrtr static int
hci_sendoob(struct socket * so,struct mbuf * m,struct mbuf * control)691d2d88be8Srtr hci_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control)
692d2d88be8Srtr {
693d2d88be8Srtr KASSERT(solocked(so));
694d2d88be8Srtr
695d2d88be8Srtr m_freem(m);
696d2d88be8Srtr m_freem(control);
697d2d88be8Srtr
698d2d88be8Srtr return EOPNOTSUPP;
699d2d88be8Srtr }
700d2d88be8Srtr
701c1ee5d65Srtr static int
hci_purgeif(struct socket * so,struct ifnet * ifp)702c1ee5d65Srtr hci_purgeif(struct socket *so, struct ifnet *ifp)
703c1ee5d65Srtr {
704c1ee5d65Srtr
705c1ee5d65Srtr return EOPNOTSUPP;
706c1ee5d65Srtr }
707c1ee5d65Srtr
708a5c89047Sgdamore /*
709a5c89047Sgdamore * get/set socket options
710a5c89047Sgdamore */
711a5c89047Sgdamore int
hci_ctloutput(int req,struct socket * so,struct sockopt * sopt)712fd7356a9Splunky hci_ctloutput(int req, struct socket *so, struct sockopt *sopt)
713a5c89047Sgdamore {
714a5c89047Sgdamore struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;
715fd7356a9Splunky int optval, err = 0;
716a5c89047Sgdamore
717a5c89047Sgdamore DPRINTFN(2, "req %s\n", prcorequests[req]);
718a5c89047Sgdamore
719a5c89047Sgdamore if (pcb == NULL)
720a5c89047Sgdamore return EINVAL;
721a5c89047Sgdamore
722fd7356a9Splunky if (sopt->sopt_level != BTPROTO_HCI)
723162ec756Splunky return ENOPROTOOPT;
724a5c89047Sgdamore
725a5c89047Sgdamore switch(req) {
726a5c89047Sgdamore case PRCO_GETOPT:
727fd7356a9Splunky switch (sopt->sopt_name) {
728a5c89047Sgdamore case SO_HCI_EVT_FILTER:
729fd7356a9Splunky err = sockopt_set(sopt, &pcb->hp_efilter,
730fd7356a9Splunky sizeof(struct hci_filter));
731fd7356a9Splunky
732a5c89047Sgdamore break;
733a5c89047Sgdamore
734a5c89047Sgdamore case SO_HCI_PKT_FILTER:
735fd7356a9Splunky err = sockopt_set(sopt, &pcb->hp_pfilter,
736fd7356a9Splunky sizeof(struct hci_filter));
737fd7356a9Splunky
738a5c89047Sgdamore break;
739a5c89047Sgdamore
740a5c89047Sgdamore case SO_HCI_DIRECTION:
741fd7356a9Splunky err = sockopt_setint(sopt,
742fd7356a9Splunky (pcb->hp_flags & HCI_DIRECTION ? 1 : 0));
743fd7356a9Splunky
744a5c89047Sgdamore break;
745a5c89047Sgdamore
746a5c89047Sgdamore default:
747162ec756Splunky err = ENOPROTOOPT;
748a5c89047Sgdamore break;
749a5c89047Sgdamore }
750a5c89047Sgdamore break;
751a5c89047Sgdamore
752a5c89047Sgdamore case PRCO_SETOPT:
753fd7356a9Splunky switch (sopt->sopt_name) {
754a5c89047Sgdamore case SO_HCI_EVT_FILTER: /* set event filter */
755fd7356a9Splunky err = sockopt_get(sopt, &pcb->hp_efilter,
756fd7356a9Splunky sizeof(pcb->hp_efilter));
757fd7356a9Splunky
758a5c89047Sgdamore break;
759a5c89047Sgdamore
760a5c89047Sgdamore case SO_HCI_PKT_FILTER: /* set packet filter */
761fd7356a9Splunky err = sockopt_get(sopt, &pcb->hp_pfilter,
762fd7356a9Splunky sizeof(pcb->hp_pfilter));
763fd7356a9Splunky
764a5c89047Sgdamore break;
765a5c89047Sgdamore
766a5c89047Sgdamore case SO_HCI_DIRECTION: /* request direction ctl messages */
767fd7356a9Splunky err = sockopt_getint(sopt, &optval);
768fd7356a9Splunky if (err)
769fd7356a9Splunky break;
770fd7356a9Splunky
771fd7356a9Splunky if (optval)
772a5c89047Sgdamore pcb->hp_flags |= HCI_DIRECTION;
773a5c89047Sgdamore else
774a5c89047Sgdamore pcb->hp_flags &= ~HCI_DIRECTION;
775a5c89047Sgdamore break;
776a5c89047Sgdamore
777a5c89047Sgdamore default:
778162ec756Splunky err = ENOPROTOOPT;
779a5c89047Sgdamore break;
780a5c89047Sgdamore }
781a5c89047Sgdamore break;
782a5c89047Sgdamore
783a5c89047Sgdamore default:
784162ec756Splunky err = ENOPROTOOPT;
785a5c89047Sgdamore break;
786a5c89047Sgdamore }
787a5c89047Sgdamore
788a5c89047Sgdamore return err;
789a5c89047Sgdamore }
790a5c89047Sgdamore
791a5c89047Sgdamore /*
792a5c89047Sgdamore * HCI mbuf tap routine
793a5c89047Sgdamore *
794a5c89047Sgdamore * copy packets to any raw HCI sockets that wish (and are
795a5c89047Sgdamore * permitted) to see them
796a5c89047Sgdamore */
797a5c89047Sgdamore void
hci_mtap(struct mbuf * m,struct hci_unit * unit)798a5c89047Sgdamore hci_mtap(struct mbuf *m, struct hci_unit *unit)
799a5c89047Sgdamore {
800a5c89047Sgdamore struct hci_pcb *pcb;
801a5c89047Sgdamore struct mbuf *m0, *ctlmsg, **ctl;
802a5c89047Sgdamore struct sockaddr_bt sa;
803a5c89047Sgdamore uint8_t type;
804a5c89047Sgdamore uint8_t event;
8054f6ac133Splunky uint16_t arg1;
806a5c89047Sgdamore
807a5c89047Sgdamore KASSERT(m->m_len >= sizeof(type));
808a5c89047Sgdamore
809a5c89047Sgdamore type = *mtod(m, uint8_t *);
810a5c89047Sgdamore
811a5c89047Sgdamore memset(&sa, 0, sizeof(sa));
812a5c89047Sgdamore sa.bt_len = sizeof(struct sockaddr_bt);
813a5c89047Sgdamore sa.bt_family = AF_BLUETOOTH;
814a5c89047Sgdamore bdaddr_copy(&sa.bt_bdaddr, &unit->hci_bdaddr);
815a5c89047Sgdamore
816a5c89047Sgdamore LIST_FOREACH(pcb, &hci_pcb, hp_next) {
817a5c89047Sgdamore /*
818a5c89047Sgdamore * filter according to source address
819a5c89047Sgdamore */
820a5c89047Sgdamore if ((pcb->hp_flags & HCI_PROMISCUOUS) == 0
821a5c89047Sgdamore && bdaddr_same(&pcb->hp_laddr, &sa.bt_bdaddr) == 0)
822a5c89047Sgdamore continue;
823a5c89047Sgdamore
824a5c89047Sgdamore /*
825a5c89047Sgdamore * filter according to packet type filter
826a5c89047Sgdamore */
827a5c89047Sgdamore if (hci_filter_test(type, &pcb->hp_pfilter) == 0)
828a5c89047Sgdamore continue;
829a5c89047Sgdamore
830a5c89047Sgdamore /*
831a5c89047Sgdamore * filter according to event/security filters
832a5c89047Sgdamore */
833a5c89047Sgdamore switch(type) {
834a5c89047Sgdamore case HCI_EVENT_PKT:
835a5c89047Sgdamore KASSERT(m->m_len >= sizeof(hci_event_hdr_t));
836a5c89047Sgdamore
837a5c89047Sgdamore event = mtod(m, hci_event_hdr_t *)->event;
838a5c89047Sgdamore
839a5c89047Sgdamore if (hci_filter_test(event, &pcb->hp_efilter) == 0)
840a5c89047Sgdamore continue;
841a5c89047Sgdamore
8424f6ac133Splunky arg1 = event;
843a5c89047Sgdamore break;
844a5c89047Sgdamore
845a5c89047Sgdamore case HCI_CMD_PKT:
846a5c89047Sgdamore KASSERT(m->m_len >= sizeof(hci_cmd_hdr_t));
8474f6ac133Splunky arg1 = le16toh(mtod(m, hci_cmd_hdr_t *)->opcode);
848a5c89047Sgdamore break;
849a5c89047Sgdamore
850a5c89047Sgdamore case HCI_ACL_DATA_PKT:
8514f6ac133Splunky KASSERT(m->m_len >= sizeof(hci_acldata_hdr_t));
8524f6ac133Splunky arg1 = le16toh(mtod(m, hci_acldata_hdr_t *)->con_handle);
8534f6ac133Splunky arg1 = HCI_CON_HANDLE(arg1);
8544f6ac133Splunky break;
855a5c89047Sgdamore
8564f6ac133Splunky case HCI_SCO_DATA_PKT:
8574f6ac133Splunky KASSERT(m->m_len >= sizeof(hci_scodata_hdr_t));
8584f6ac133Splunky arg1 = le16toh(mtod(m, hci_scodata_hdr_t *)->con_handle);
8594f6ac133Splunky arg1 = HCI_CON_HANDLE(arg1);
8604f6ac133Splunky break;
8614f6ac133Splunky
8624f6ac133Splunky default:
8634f6ac133Splunky arg1 = 0;
864a5c89047Sgdamore break;
865a5c89047Sgdamore }
866a5c89047Sgdamore
8674f6ac133Splunky if (pcb->hp_cred != NULL
8684f6ac133Splunky && kauth_authorize_device(pcb->hp_cred,
8694f6ac133Splunky KAUTH_DEVICE_BLUETOOTH_RECV,
8704f6ac133Splunky KAUTH_ARG(type), KAUTH_ARG(arg1), NULL, NULL) != 0)
8714f6ac133Splunky continue;
8724f6ac133Splunky
873a5c89047Sgdamore /*
874a5c89047Sgdamore * create control messages
875a5c89047Sgdamore */
876a5c89047Sgdamore ctlmsg = NULL;
877a5c89047Sgdamore ctl = &ctlmsg;
878a5c89047Sgdamore if (pcb->hp_flags & HCI_DIRECTION) {
879a5c89047Sgdamore int dir = m->m_flags & M_LINK0 ? 1 : 0;
880a5c89047Sgdamore
8818e15db75Splunky *ctl = sbcreatecontrol(&dir, sizeof(dir),
882a5c89047Sgdamore SCM_HCI_DIRECTION, BTPROTO_HCI);
883a5c89047Sgdamore
884a5c89047Sgdamore if (*ctl != NULL)
885a5c89047Sgdamore ctl = &((*ctl)->m_next);
886a5c89047Sgdamore }
887d06cf72aSplunky if (pcb->hp_socket->so_options & SO_TIMESTAMP) {
888d06cf72aSplunky struct timeval tv;
889d06cf72aSplunky
890d06cf72aSplunky microtime(&tv);
891d06cf72aSplunky *ctl = sbcreatecontrol(&tv, sizeof(tv),
892d06cf72aSplunky SCM_TIMESTAMP, SOL_SOCKET);
893d06cf72aSplunky
894d06cf72aSplunky if (*ctl != NULL)
895d06cf72aSplunky ctl = &((*ctl)->m_next);
896d06cf72aSplunky }
897a5c89047Sgdamore
898a5c89047Sgdamore /*
899a5c89047Sgdamore * copy to socket
900a5c89047Sgdamore */
901a5c89047Sgdamore m0 = m_copypacket(m, M_DONTWAIT);
902a5c89047Sgdamore if (m0 && sbappendaddr(&pcb->hp_socket->so_rcv,
903a5c89047Sgdamore (struct sockaddr *)&sa, m0, ctlmsg)) {
904a5c89047Sgdamore sorwakeup(pcb->hp_socket);
905a5c89047Sgdamore } else {
906a5c89047Sgdamore m_freem(ctlmsg);
907a5c89047Sgdamore m_freem(m0);
908a5c89047Sgdamore }
909a5c89047Sgdamore }
910a5c89047Sgdamore }
911be0111acSrmind
9124aab7272Srmind PR_WRAP_USRREQS(hci)
913be0111acSrmind
9144aab7272Srmind #define hci_attach hci_attach_wrapper
9154aab7272Srmind #define hci_detach hci_detach_wrapper
9169e76bf78Srtr #define hci_accept hci_accept_wrapper
91750c78d5eSrtr #define hci_bind hci_bind_wrapper
91850c78d5eSrtr #define hci_listen hci_listen_wrapper
9194d1c14a6Srtr #define hci_connect hci_connect_wrapper
920c1ee5d65Srtr #define hci_connect2 hci_connect2_wrapper
92108e341e4Srtr #define hci_disconnect hci_disconnect_wrapper
92208e341e4Srtr #define hci_shutdown hci_shutdown_wrapper
92308e341e4Srtr #define hci_abort hci_abort_wrapper
9244c58642fSrtr #define hci_ioctl hci_ioctl_wrapper
925c4feb117Srtr #define hci_stat hci_stat_wrapper
9263bb356e9Srtr #define hci_peeraddr hci_peeraddr_wrapper
9273bb356e9Srtr #define hci_sockaddr hci_sockaddr_wrapper
928dc24950fSrtr #define hci_rcvd hci_rcvd_wrapper
929d2d88be8Srtr #define hci_recvoob hci_recvoob_wrapper
930c0e2453cSrtr #define hci_send hci_send_wrapper
931d2d88be8Srtr #define hci_sendoob hci_sendoob_wrapper
932c1ee5d65Srtr #define hci_purgeif hci_purgeif_wrapper
933be0111acSrmind
934be0111acSrmind const struct pr_usrreqs hci_usrreqs = {
9358db4ab26Srmind .pr_attach = hci_attach,
9368db4ab26Srmind .pr_detach = hci_detach,
9379e76bf78Srtr .pr_accept = hci_accept,
93850c78d5eSrtr .pr_bind = hci_bind,
93950c78d5eSrtr .pr_listen = hci_listen,
9404d1c14a6Srtr .pr_connect = hci_connect,
941c1ee5d65Srtr .pr_connect2 = hci_connect2,
94208e341e4Srtr .pr_disconnect = hci_disconnect,
94308e341e4Srtr .pr_shutdown = hci_shutdown,
94408e341e4Srtr .pr_abort = hci_abort,
9454c58642fSrtr .pr_ioctl = hci_ioctl,
946c4feb117Srtr .pr_stat = hci_stat,
9473bb356e9Srtr .pr_peeraddr = hci_peeraddr,
9483bb356e9Srtr .pr_sockaddr = hci_sockaddr,
949dc24950fSrtr .pr_rcvd = hci_rcvd,
950d2d88be8Srtr .pr_recvoob = hci_recvoob,
951c0e2453cSrtr .pr_send = hci_send,
952d2d88be8Srtr .pr_sendoob = hci_sendoob,
953c1ee5d65Srtr .pr_purgeif = hci_purgeif,
954be0111acSrmind };
955