xref: /netbsd/sys/netbt/hci_socket.c (revision e54e5a64)
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