libpthread: Document some more functions.
[dragonfly.git] / sys / netbt / hci_socket.c
blobbededfc096c14647a1497f7254f2b55eb1eebc5b
1 /* $OpenBSD: src/sys/netbt/hci_socket.c,v 1.5 2008/02/24 21:34:48 uwe Exp $ */
2 /* $NetBSD: hci_socket.c,v 1.14 2008/02/10 17:40:54 plunky Exp $ */
4 /*-
5 * Copyright (c) 2005 Iain Hibbert.
6 * Copyright (c) 2006 Itronix Inc.
7 * All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. The name of Itronix Inc. may not be used to endorse
18 * or promote products derived from this software without specific
19 * prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28 * ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
34 /* load symbolic names */
35 #ifdef BLUETOOTH_DEBUG
36 #define PRUREQUESTS
37 #define PRCOREQUESTS
38 #endif
40 #include <sys/param.h>
41 #include <sys/domain.h>
42 #include <sys/kernel.h>
43 #include <sys/mbuf.h>
44 #include <sys/proc.h>
45 #include <sys/priv.h>
46 #include <sys/protosw.h>
47 #include <sys/socket.h>
48 #include <sys/socketvar.h>
49 #include <sys/systm.h>
50 #include <sys/endian.h>
51 #include <net/if.h>
52 #include <net/if_var.h>
53 #include <sys/sysctl.h>
55 #include <sys/thread2.h>
56 #include <sys/socketvar2.h>
57 #include <sys/msgport2.h>
59 #include <netbt/bluetooth.h>
60 #include <netbt/hci.h>
62 /*******************************************************************************
64 * HCI SOCK_RAW Sockets - for control of Bluetooth Devices
69 * the raw HCI protocol control block
71 struct hci_pcb {
72 struct socket *hp_socket; /* socket */
73 unsigned int hp_flags; /* flags */
74 bdaddr_t hp_laddr; /* local address */
75 bdaddr_t hp_raddr; /* remote address */
76 struct hci_filter hp_efilter; /* user event filter */
77 struct hci_filter hp_pfilter; /* user packet filter */
78 LIST_ENTRY(hci_pcb) hp_next; /* next HCI pcb */
81 /* hp_flags */
82 #define HCI_PRIVILEGED (1<<0) /* no security filter for root */
83 #define HCI_DIRECTION (1<<1) /* direction control messages */
84 #define HCI_PROMISCUOUS (1<<2) /* listen to all units */
86 LIST_HEAD(hci_pcb_list, hci_pcb) hci_pcb = LIST_HEAD_INITIALIZER(hci_pcb);
88 /* sysctl defaults */
89 int hci_sendspace = HCI_CMD_PKT_SIZE;
90 int hci_recvspace = 4096;
92 extern struct pr_usrreqs hci_usrreqs;
94 /* Prototypes for usrreqs methods. */
95 static void hci_sdetach(netmsg_t msg);
97 /* supported commands opcode table */
98 static const struct {
99 uint16_t opcode;
100 uint8_t offs; /* 0 - 63 */
101 uint8_t mask; /* bit 0 - 7 */
102 int16_t length; /* -1 if privileged */
103 } hci_cmds[] = {
104 { HCI_CMD_INQUIRY,
105 0, 0x01, sizeof(hci_inquiry_cp) },
106 { HCI_CMD_INQUIRY_CANCEL,
107 0, 0x02, -1 },
108 { HCI_CMD_PERIODIC_INQUIRY,
109 0, 0x04, -1 },
110 { HCI_CMD_EXIT_PERIODIC_INQUIRY,
111 0, 0x08, -1 },
112 { HCI_CMD_CREATE_CON,
113 0, 0x10, -1 },
114 { HCI_CMD_DISCONNECT,
115 0, 0x20, -1 },
116 { HCI_CMD_ADD_SCO_CON,
117 0, 0x40, -1 },
118 { HCI_CMD_CREATE_CON_CANCEL,
119 0, 0x80, -1 },
120 { HCI_CMD_ACCEPT_CON,
121 1, 0x01, -1 },
122 { HCI_CMD_REJECT_CON,
123 1, 0x02, -1 },
124 { HCI_CMD_LINK_KEY_REP,
125 1, 0x04, -1 },
126 { HCI_CMD_LINK_KEY_NEG_REP,
127 1, 0x08, -1 },
128 { HCI_CMD_PIN_CODE_REP,
129 1, 0x10, -1 },
130 { HCI_CMD_PIN_CODE_NEG_REP,
131 1, 0x20, -1 },
132 { HCI_CMD_CHANGE_CON_PACKET_TYPE,
133 1, 0x40, -1 },
134 { HCI_CMD_AUTH_REQ,
135 1, 0x80, -1 },
136 { HCI_CMD_SET_CON_ENCRYPTION,
137 2, 0x01, -1 },
138 { HCI_CMD_CHANGE_CON_LINK_KEY,
139 2, 0x02, -1 },
140 { HCI_CMD_MASTER_LINK_KEY,
141 2, 0x04, -1 },
142 { HCI_CMD_REMOTE_NAME_REQ,
143 2, 0x08, sizeof(hci_remote_name_req_cp) },
144 { HCI_CMD_REMOTE_NAME_REQ_CANCEL,
145 2, 0x10, -1 },
146 { HCI_CMD_READ_REMOTE_FEATURES,
147 2, 0x20, sizeof(hci_read_remote_features_cp) },
148 { HCI_CMD_READ_REMOTE_EXTENDED_FEATURES,
149 2, 0x40, sizeof(hci_read_remote_extended_features_cp) },
150 { HCI_CMD_READ_REMOTE_VER_INFO,
151 2, 0x80, sizeof(hci_read_remote_ver_info_cp) },
152 { HCI_CMD_READ_CLOCK_OFFSET,
153 3, 0x01, sizeof(hci_read_clock_offset_cp) },
154 { HCI_CMD_READ_LMP_HANDLE,
155 3, 0x02, sizeof(hci_read_lmp_handle_cp) },
156 { HCI_CMD_HOLD_MODE,
157 4, 0x02, -1 },
158 { HCI_CMD_SNIFF_MODE,
159 4, 0x04, -1 },
160 { HCI_CMD_EXIT_SNIFF_MODE,
161 4, 0x08, -1 },
162 { HCI_CMD_PARK_MODE,
163 4, 0x10, -1 },
164 { HCI_CMD_EXIT_PARK_MODE,
165 4, 0x20, -1 },
166 { HCI_CMD_QOS_SETUP,
167 4, 0x40, -1 },
168 { HCI_CMD_ROLE_DISCOVERY,
169 4, 0x80, sizeof(hci_role_discovery_cp) },
170 { HCI_CMD_SWITCH_ROLE,
171 5, 0x01, -1 },
172 { HCI_CMD_READ_LINK_POLICY_SETTINGS,
173 5, 0x02, sizeof(hci_read_link_policy_settings_cp) },
174 { HCI_CMD_WRITE_LINK_POLICY_SETTINGS,
175 5, 0x04, -1 },
176 { HCI_CMD_READ_DEFAULT_LINK_POLICY_SETTINGS,
177 5, 0x08, 0 },
178 { HCI_CMD_WRITE_DEFAULT_LINK_POLICY_SETTINGS,
179 5, 0x10, -1 },
180 { HCI_CMD_FLOW_SPECIFICATION,
181 5, 0x20, -1 },
182 { HCI_CMD_SET_EVENT_MASK,
183 5, 0x40, -1 },
184 { HCI_CMD_RESET,
185 5, 0x80, -1 },
186 { HCI_CMD_SET_EVENT_FILTER,
187 6, 0x01, -1 },
188 { HCI_CMD_FLUSH,
189 6, 0x02, -1 },
190 { HCI_CMD_READ_PIN_TYPE,
191 6, 0x04, 0 },
192 { HCI_CMD_WRITE_PIN_TYPE,
193 6, 0x08, -1 },
194 { HCI_CMD_CREATE_NEW_UNIT_KEY,
195 6, 0x10, -1 },
196 { HCI_CMD_READ_STORED_LINK_KEY,
197 6, 0x20, -1 },
198 { HCI_CMD_WRITE_STORED_LINK_KEY,
199 6, 0x40, -1 },
200 { HCI_CMD_DELETE_STORED_LINK_KEY,
201 6, 0x80, -1 },
202 { HCI_CMD_WRITE_LOCAL_NAME,
203 7, 0x01, -1 },
204 { HCI_CMD_READ_LOCAL_NAME,
205 7, 0x02, 0 },
206 { HCI_CMD_READ_CON_ACCEPT_TIMEOUT,
207 7, 0x04, 0 },
208 { HCI_CMD_WRITE_CON_ACCEPT_TIMEOUT,
209 7, 0x08, -1 },
210 { HCI_CMD_READ_PAGE_TIMEOUT,
211 7, 0x10, 0 },
212 { HCI_CMD_WRITE_PAGE_TIMEOUT,
213 7, 0x20, -1 },
214 { HCI_CMD_READ_SCAN_ENABLE,
215 7, 0x40, 0 },
216 { HCI_CMD_WRITE_SCAN_ENABLE,
217 7, 0x80, -1 },
218 { HCI_CMD_READ_PAGE_SCAN_ACTIVITY,
219 8, 0x01, 0 },
220 { HCI_CMD_WRITE_PAGE_SCAN_ACTIVITY,
221 8, 0x02, -1 },
222 { HCI_CMD_READ_INQUIRY_SCAN_ACTIVITY,
223 8, 0x04, 0 },
224 { HCI_CMD_WRITE_INQUIRY_SCAN_ACTIVITY,
225 8, 0x08, -1 },
226 { HCI_CMD_READ_AUTH_ENABLE,
227 8, 0x10, 0 },
228 { HCI_CMD_WRITE_AUTH_ENABLE,
229 8, 0x20, -1 },
230 { HCI_CMD_READ_ENCRYPTION_MODE,
231 8, 0x40, 0 },
232 { HCI_CMD_WRITE_ENCRYPTION_MODE,
233 8, 0x80, -1 },
234 { HCI_CMD_READ_UNIT_CLASS,
235 9, 0x01, 0 },
236 { HCI_CMD_WRITE_UNIT_CLASS,
237 9, 0x02, -1 },
238 { HCI_CMD_READ_VOICE_SETTING,
239 9, 0x04, 0 },
240 { HCI_CMD_WRITE_VOICE_SETTING,
241 9, 0x08, -1 },
242 { HCI_CMD_READ_AUTO_FLUSH_TIMEOUT,
243 9, 0x10, sizeof(hci_read_auto_flush_timeout_cp) },
244 { HCI_CMD_WRITE_AUTO_FLUSH_TIMEOUT,
245 9, 0x20, -1 },
246 { HCI_CMD_READ_NUM_BROADCAST_RETRANS,
247 9, 0x40, 0 },
248 { HCI_CMD_WRITE_NUM_BROADCAST_RETRANS,
249 9, 0x80, -1 },
250 { HCI_CMD_READ_HOLD_MODE_ACTIVITY,
251 10, 0x01, 0 },
252 { HCI_CMD_WRITE_HOLD_MODE_ACTIVITY,
253 10, 0x02, -1 },
254 { HCI_CMD_READ_XMIT_LEVEL,
255 10, 0x04, sizeof(hci_read_xmit_level_cp) },
256 { HCI_CMD_READ_SCO_FLOW_CONTROL,
257 10, 0x08, 0 },
258 { HCI_CMD_WRITE_SCO_FLOW_CONTROL,
259 10, 0x10, -1 },
260 { HCI_CMD_HC2H_FLOW_CONTROL,
261 10, 0x20, -1 },
262 { HCI_CMD_HOST_BUFFER_SIZE,
263 10, 0x40, -1 },
264 { HCI_CMD_HOST_NUM_COMPL_PKTS,
265 10, 0x80, -1 },
266 { HCI_CMD_READ_LINK_SUPERVISION_TIMEOUT,
267 11, 0x01, sizeof(hci_read_link_supervision_timeout_cp) },
268 { HCI_CMD_WRITE_LINK_SUPERVISION_TIMEOUT,
269 11, 0x02, -1 },
270 { HCI_CMD_READ_NUM_SUPPORTED_IAC,
271 11, 0x04, 0 },
272 { HCI_CMD_READ_IAC_LAP,
273 11, 0x08, 0 },
274 { HCI_CMD_WRITE_IAC_LAP,
275 11, 0x10, -1 },
276 { HCI_CMD_READ_PAGE_SCAN_PERIOD,
277 11, 0x20, 0 },
278 { HCI_CMD_WRITE_PAGE_SCAN_PERIOD,
279 11, 0x40, -1 },
280 { HCI_CMD_READ_PAGE_SCAN,
281 11, 0x80, 0 },
282 { HCI_CMD_WRITE_PAGE_SCAN,
283 12, 0x01, -1 },
284 { HCI_CMD_SET_AFH_CLASSIFICATION,
285 12, 0x02, -1 },
286 { HCI_CMD_READ_INQUIRY_SCAN_TYPE,
287 12, 0x10, 0 },
288 { HCI_CMD_WRITE_INQUIRY_SCAN_TYPE,
289 12, 0x20, -1 },
290 { HCI_CMD_READ_INQUIRY_MODE,
291 12, 0x40, 0 },
292 { HCI_CMD_WRITE_INQUIRY_MODE,
293 12, 0x80, -1 },
294 { HCI_CMD_READ_PAGE_SCAN_TYPE,
295 13, 0x01, 0 },
296 { HCI_CMD_WRITE_PAGE_SCAN_TYPE,
297 13, 0x02, -1 },
298 { HCI_CMD_READ_AFH_ASSESSMENT,
299 13, 0x04, 0 },
300 { HCI_CMD_WRITE_AFH_ASSESSMENT,
301 13, 0x08, -1 },
302 { HCI_CMD_READ_LOCAL_VER,
303 14, 0x08, 0 },
304 { HCI_CMD_READ_LOCAL_COMMANDS,
305 14, 0x10, 0 },
306 { HCI_CMD_READ_LOCAL_FEATURES,
307 14, 0x20, 0 },
308 { HCI_CMD_READ_LOCAL_EXTENDED_FEATURES,
309 14, 0x40, sizeof(hci_read_local_extended_features_cp) },
310 { HCI_CMD_READ_BUFFER_SIZE,
311 14, 0x80, 0 },
312 { HCI_CMD_READ_COUNTRY_CODE,
313 15, 0x01, 0 },
314 { HCI_CMD_READ_BDADDR,
315 15, 0x02, 0 },
316 { HCI_CMD_READ_FAILED_CONTACT_CNTR,
317 15, 0x04, sizeof(hci_read_failed_contact_cntr_cp) },
318 { HCI_CMD_RESET_FAILED_CONTACT_CNTR,
319 15, 0x08, -1 },
320 { HCI_CMD_READ_LINK_QUALITY,
321 15, 0x10, sizeof(hci_read_link_quality_cp) },
322 { HCI_CMD_READ_RSSI,
323 15, 0x20, sizeof(hci_read_rssi_cp) },
324 { HCI_CMD_READ_AFH_CHANNEL_MAP,
325 15, 0x40, sizeof(hci_read_afh_channel_map_cp) },
326 { HCI_CMD_READ_CLOCK,
327 15, 0x80, sizeof(hci_read_clock_cp) },
328 { HCI_CMD_READ_LOOPBACK_MODE,
329 16, 0x01, 0 },
330 { HCI_CMD_WRITE_LOOPBACK_MODE,
331 16, 0x02, -1 },
332 { HCI_CMD_ENABLE_UNIT_UNDER_TEST,
333 16, 0x04, -1 },
334 { HCI_CMD_SETUP_SCO_CON,
335 16, 0x08, -1 },
336 { HCI_CMD_ACCEPT_SCO_CON_REQ,
337 16, 0x10, -1 },
338 { HCI_CMD_REJECT_SCO_CON_REQ,
339 16, 0x20, -1 },
340 { HCI_CMD_READ_EXTENDED_INQUIRY_RSP,
341 17, 0x01, 0 },
342 { HCI_CMD_WRITE_EXTENDED_INQUIRY_RSP,
343 17, 0x02, -1 },
344 { HCI_CMD_REFRESH_ENCRYPTION_KEY,
345 17, 0x04, -1 },
346 { HCI_CMD_SNIFF_SUBRATING,
347 17, 0x10, -1 },
348 { HCI_CMD_READ_SIMPLE_PAIRING_MODE,
349 17, 0x20, 0 },
350 { HCI_CMD_WRITE_SIMPLE_PAIRING_MODE,
351 17, 0x40, -1 },
352 { HCI_CMD_READ_LOCAL_OOB_DATA,
353 17, 0x80, -1 },
354 { HCI_CMD_READ_INQUIRY_RSP_XMIT_POWER,
355 18, 0x01, 0 },
356 { HCI_CMD_WRITE_INQUIRY_RSP_XMIT_POWER,
357 18, 0x02, -1 },
358 { HCI_CMD_READ_DEFAULT_ERRDATA_REPORTING,
359 18, 0x04, 0 },
360 { HCI_CMD_WRITE_DEFAULT_ERRDATA_REPORTING,
361 18, 0x08, -1 },
362 { HCI_CMD_IO_CAPABILITY_REP,
363 18, 0x80, -1 },
364 { HCI_CMD_USER_CONFIRM_REP,
365 19, 0x01, -1 },
366 { HCI_CMD_USER_CONFIRM_NEG_REP,
367 19, 0x02, -1 },
368 { HCI_CMD_USER_PASSKEY_REP,
369 19, 0x04, -1 },
370 { HCI_CMD_USER_PASSKEY_NEG_REP,
371 19, 0x08, -1 },
372 { HCI_CMD_OOB_DATA_REP,
373 19, 0x10, -1 },
374 { HCI_CMD_WRITE_SIMPLE_PAIRING_DEBUG_MODE,
375 19, 0x20, -1 },
376 { HCI_CMD_ENHANCED_FLUSH,
377 19, 0x40, -1 },
378 { HCI_CMD_OOB_DATA_NEG_REP,
379 19, 0x80, -1 },
380 { HCI_CMD_SEND_KEYPRESS_NOTIFICATION,
381 20, 0x40, -1 },
382 { HCI_CMD_IO_CAPABILITY_NEG_REP,
383 20, 0x80, -1 },
387 * Security filter routines for unprivileged users.
388 * Allow all but a few critical events, and only permit read commands.
389 * If a unit is given, verify the command is supported.
392 static int
393 hci_security_check_opcode(struct hci_unit *unit, uint16_t opcode)
395 int i;
397 for (i = 0 ; i < NELEM(hci_cmds); i++) {
398 if (opcode != hci_cmds[i].opcode)
399 continue;
401 if (unit == NULL
402 || (unit->hci_cmds[hci_cmds[i].offs] & hci_cmds[i].mask))
403 return hci_cmds[i].length;
405 break;
408 return -1;
411 static int
412 hci_security_check_event(uint8_t event)
415 switch (event) {
416 case HCI_EVENT_RETURN_LINK_KEYS:
417 case HCI_EVENT_LINK_KEY_NOTIFICATION:
418 case HCI_EVENT_USER_CONFIRM_REQ:
419 case HCI_EVENT_USER_PASSKEY_NOTIFICATION:
420 case HCI_EVENT_VENDOR:
421 return -1; /* disallowed */
424 return 0; /* ok */
428 * When command packet reaches the device, we can drop
429 * it from the socket buffer (called from hci_output_acl)
431 void
432 hci_drop(void *arg)
434 struct socket *so = arg;
436 sbdroprecord(&so->so_snd.sb);
437 sowwakeup(so);
441 * HCI socket is going away and has some pending packets. We let them
442 * go by design, but remove the context pointer as it will be invalid
443 * and we no longer need to be notified.
445 static void
446 hci_cmdwait_flush(struct socket *so)
448 struct hci_unit *unit;
449 struct socket *ctx;
450 struct mbuf *m;
452 DPRINTF("flushing %p\n", so);
454 TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
455 IF_POLL(&unit->hci_cmdwait, m);
456 while (m != NULL) {
457 ctx = M_GETCTX(m, struct socket *);
458 if (ctx == so)
459 M_SETCTX(m, NULL);
461 m = m->m_nextpkt;
467 * HCI send packet
468 * This came from userland, so check it out.
470 static int
471 hci_send(struct hci_pcb *pcb, struct mbuf *m, bdaddr_t *addr)
473 struct hci_unit *unit;
474 struct mbuf *m0;
475 hci_cmd_hdr_t hdr;
476 int err;
478 KKASSERT(m != NULL);
479 KKASSERT(addr != NULL);
481 /* wants at least a header to start with */
482 if (m->m_pkthdr.len < sizeof(hdr)) {
483 err = EMSGSIZE;
484 goto bad;
486 m_copydata(m, 0, sizeof(hdr), (caddr_t)&hdr);
487 hdr.opcode = letoh16(hdr.opcode);
489 /* only allows CMD packets to be sent */
490 if (hdr.type != HCI_CMD_PKT) {
491 err = EINVAL;
492 goto bad;
495 /* validates packet length */
496 if (m->m_pkthdr.len != sizeof(hdr) + hdr.length) {
497 err = EMSGSIZE;
498 goto bad;
501 /* finds destination */
502 unit = hci_unit_lookup(addr);
503 if (unit == NULL) {
504 err = ENETDOWN;
505 goto bad;
508 /* security checks for unprivileged users */
509 if ((pcb->hp_flags & HCI_PRIVILEGED) == 0
510 && hci_security_check_opcode(unit, hdr.opcode) != hdr.length) {
511 err = EPERM;
512 goto bad;
515 /* makes a copy for precious to keep */
516 m0 = m_copym(m, 0, M_COPYALL, M_NOWAIT);
517 if (m0 == NULL) {
518 err = ENOMEM;
519 goto bad;
521 sbappendrecord(&pcb->hp_socket->so_snd.sb, m0);
522 M_SETCTX(m, pcb->hp_socket); /* enable drop callback */
524 DPRINTFN(2, "(%s) opcode (%03x|%04x)\n",
525 device_get_nameunit(unit->hci_dev),
526 HCI_OGF(hdr.opcode), HCI_OCF(hdr.opcode));
528 /* Sendss it */
529 if (unit->hci_num_cmd_pkts == 0)
530 IF_ENQUEUE(&unit->hci_cmdwait, m);
531 else
532 hci_output_cmd(unit, m);
534 return 0;
536 bad:
537 DPRINTF("packet (%d bytes) not sent (error %d)\n",
538 m->m_pkthdr.len, err);
539 if (m) m_freem(m);
540 return err;
544 * Implementation of usrreqs.
546 * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort()
547 * will sofree() it when we return.
549 static void
550 hci_sabort(netmsg_t msg)
552 /* struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb; */
554 soisdisconnected(msg->abort.base.nm_so);
555 hci_sdetach(msg);
556 /* msg now invalid */
559 static void
560 hci_sdetach(netmsg_t msg)
562 struct socket *so = msg->detach.base.nm_so;
563 struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;
564 int error;
566 if (pcb == NULL) {
567 error = EINVAL;
568 } else {
569 if (so->so_snd.ssb_mb != NULL)
570 hci_cmdwait_flush(so);
572 so->so_pcb = NULL;
573 sofree(so); /* remove pcb ref */
575 LIST_REMOVE(pcb, hp_next);
576 kfree(pcb, M_PCB);
577 error = 0;
579 lwkt_replymsg(&msg->detach.base.lmsg, error);
582 static void
583 hci_sdisconnect(netmsg_t msg)
585 struct socket *so = msg->disconnect.base.nm_so;
586 struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;
587 int error;
589 if (pcb) {
590 bdaddr_copy(&pcb->hp_raddr, BDADDR_ANY);
592 * XXX We cannot call soisdisconnected() here, as it sets
593 * SS_CANTRCVMORE and SS_CANTSENDMORE. The problem is that
594 * soisconnected() does not clear these and if you try to
595 * reconnect this socket (which is permitted) you get a
596 * broken pipe when you try to write any data.
598 soclrstate(so, SS_ISCONNECTED);
599 error = 0;
600 } else {
601 error = EINVAL;
603 lwkt_replymsg(&msg->disconnect.base.lmsg, error);
606 static void
607 hci_scontrol(netmsg_t msg)
609 int error;
611 error = hci_ioctl(msg->control.nm_cmd,
612 (void *)msg->control.nm_data,
613 NULL);
614 lwkt_replymsg(&msg->control.base.lmsg, error);
617 static void
618 hci_sattach(netmsg_t msg)
620 struct socket *so = msg->attach.base.nm_so;
621 struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;
622 int error;
624 if (pcb) {
625 error = EINVAL;
626 goto out;
629 error = soreserve(so, hci_sendspace, hci_recvspace,NULL);
630 if (error)
631 goto out;
633 pcb = kmalloc(sizeof *pcb, M_PCB, M_NOWAIT | M_ZERO);
634 if (pcb == NULL) {
635 error = ENOMEM;
636 goto out;
639 soreference(so);
640 so->so_pcb = pcb;
641 pcb->hp_socket = so;
643 if (curproc == NULL || priv_check(curthread, PRIV_ROOT) == 0)
644 pcb->hp_flags |= HCI_PRIVILEGED;
647 * Set default user filter. By default, socket only passes
648 * Command_Complete and Command_Status Events.
650 hci_filter_set(HCI_EVENT_COMMAND_COMPL, &pcb->hp_efilter);
651 hci_filter_set(HCI_EVENT_COMMAND_STATUS, &pcb->hp_efilter);
652 hci_filter_set(HCI_EVENT_PKT, &pcb->hp_pfilter);
654 crit_enter();
655 LIST_INSERT_HEAD(&hci_pcb, pcb, hp_next);
656 crit_exit();
657 error = 0;
658 out:
659 lwkt_replymsg(&msg->attach.base.lmsg, error);
662 static void
663 hci_sbind(netmsg_t msg)
665 struct socket *so = msg->bind.base.nm_so;
666 struct sockaddr *nam = msg->bind.nm_nam;
667 struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;
668 struct sockaddr_bt *sa;
669 int error;
671 KKASSERT(nam != NULL);
672 sa = (struct sockaddr_bt *)nam;
674 if (sa->bt_len != sizeof(struct sockaddr_bt)) {
675 error = EINVAL;
676 goto out;
679 if (sa->bt_family != AF_BLUETOOTH) {
680 error = EAFNOSUPPORT;
681 goto out;
684 bdaddr_copy(&pcb->hp_laddr, &sa->bt_bdaddr);
686 if (bdaddr_any(&sa->bt_bdaddr))
687 pcb->hp_flags |= HCI_PROMISCUOUS;
688 else
689 pcb->hp_flags &= ~HCI_PROMISCUOUS;
690 error = 0;
691 out:
692 lwkt_replymsg(&msg->bind.base.lmsg, error);
695 static void
696 hci_sconnect(netmsg_t msg)
698 struct socket *so = msg->connect.base.nm_so;
699 struct sockaddr *nam = msg->connect.nm_nam;
700 struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;
701 struct sockaddr_bt *sa;
702 int error;
704 KKASSERT(nam != NULL);
705 sa = (struct sockaddr_bt *)nam;
707 if (sa->bt_len != sizeof(struct sockaddr_bt)) {
708 error = EINVAL;
709 goto out;
712 if (sa->bt_family != AF_BLUETOOTH) {
713 error = EAFNOSUPPORT;
714 goto out;
717 if (hci_unit_lookup(&sa->bt_bdaddr) == NULL) {
718 error = EADDRNOTAVAIL;
719 goto out;
721 bdaddr_copy(&pcb->hp_raddr, &sa->bt_bdaddr);
722 soisconnected(so);
723 error = 0;
724 out:
725 lwkt_replymsg(&msg->connect.base.lmsg, error);
728 static void
729 hci_speeraddr(netmsg_t msg)
731 struct socket *so = msg->peeraddr.base.nm_so;
732 struct sockaddr **nam = msg->peeraddr.nm_nam;
733 struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;
734 struct sockaddr_bt *sa;
736 KKASSERT(nam != NULL);
737 sa = (struct sockaddr_bt *)nam;
739 memset(sa, 0, sizeof(struct sockaddr_bt));
740 sa->bt_len = sizeof(struct sockaddr_bt);
741 sa->bt_family = AF_BLUETOOTH;
742 bdaddr_copy(&sa->bt_bdaddr, &pcb->hp_raddr);
744 lwkt_replymsg(&msg->connect.base.lmsg, 0);
747 static void
748 hci_ssockaddr(netmsg_t msg)
750 struct socket *so = msg->sockaddr.base.nm_so;
751 struct sockaddr **nam = msg->sockaddr.nm_nam;
752 struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;
753 struct sockaddr_bt *sa;
755 KKASSERT(nam != NULL);
756 sa = (struct sockaddr_bt *)nam;
758 memset(sa, 0, sizeof(struct sockaddr_bt));
759 sa->bt_len = sizeof(struct sockaddr_bt);
760 sa->bt_family = AF_BLUETOOTH;
761 bdaddr_copy(&sa->bt_bdaddr, &pcb->hp_laddr);
763 lwkt_replymsg(&msg->connect.base.lmsg, 0);
766 static void
767 hci_sshutdown(netmsg_t msg)
769 struct socket *so = msg->shutdown.base.nm_so;
771 socantsendmore(so);
772 lwkt_replymsg(&msg->connect.base.lmsg, 0);
775 static void
776 hci_ssend(netmsg_t msg)
778 struct socket *so = msg->send.base.nm_so;
779 struct mbuf *m = msg->send.nm_m;
780 struct sockaddr *addr = msg->send.nm_addr;
781 struct mbuf *control = msg->send.nm_control;
782 struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;
783 struct sockaddr_bt *sa;
784 int error;
786 sa = NULL;
787 if (addr) {
788 sa = (struct sockaddr_bt *)addr;
790 if (sa->bt_len != sizeof(struct sockaddr_bt)) {
791 error = EINVAL;
792 goto out;
795 if (sa->bt_family != AF_BLUETOOTH) {
796 error = EAFNOSUPPORT;
797 goto out;
801 /* have no use for this */
802 if (control) {
803 m_freem(control);
804 control = NULL;
806 error = hci_send(pcb, m, (sa ? &sa->bt_bdaddr : &pcb->hp_raddr));
807 m = NULL;
809 out:
810 if (m)
811 m_freem(m);
812 if (control)
813 m_freem(control);
814 lwkt_replymsg(&msg->send.base.lmsg, error);
818 * get/set socket options
820 void
821 hci_ctloutput(netmsg_t msg)
823 struct socket *so = msg->ctloutput.base.nm_so;
824 struct sockopt *sopt = msg->ctloutput.nm_sopt;
825 struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;
826 int idir = 0;
827 int error = 0;
829 #ifdef notyet /* XXX */
830 DPRINTFN(2, "req %s\n", prcorequests[req]);
831 #endif
833 if (pcb == NULL) {
834 error = EINVAL;
835 goto out;
838 if (sopt->sopt_level != BTPROTO_HCI) {
839 error = ENOPROTOOPT;
840 goto out;
843 switch(sopt->sopt_dir) {
844 case PRCO_GETOPT:
845 switch (sopt->sopt_name) {
846 case SO_HCI_EVT_FILTER:
847 soopt_from_kbuf(sopt, &pcb->hp_efilter,
848 sizeof(struct hci_filter));
849 break;
851 case SO_HCI_PKT_FILTER:
852 soopt_from_kbuf(sopt, &pcb->hp_pfilter,
853 sizeof(struct hci_filter));
854 break;
856 case SO_HCI_DIRECTION:
857 if (pcb->hp_flags & HCI_DIRECTION)
858 idir = 1;
859 else
860 idir = 0;
861 soopt_from_kbuf(sopt, &idir, sizeof(int));
862 break;
864 default:
865 error = ENOPROTOOPT;
866 break;
868 break;
870 case PRCO_SETOPT:
871 switch (sopt->sopt_name) {
872 case SO_HCI_EVT_FILTER: /* set event filter */
873 error = soopt_to_kbuf(sopt, &pcb->hp_efilter,
874 sizeof(struct hci_filter),
875 sizeof(struct hci_filter));
876 break;
878 case SO_HCI_PKT_FILTER: /* set packet filter */
879 error = soopt_to_kbuf(sopt, &pcb->hp_pfilter,
880 sizeof(struct hci_filter),
881 sizeof(struct hci_filter));
882 break;
884 case SO_HCI_DIRECTION: /* request direction ctl messages */
885 error = soopt_to_kbuf(sopt, &idir, sizeof(int),
886 sizeof(int));
887 if (error)
888 break;
889 if (idir)
890 pcb->hp_flags |= HCI_DIRECTION;
891 else
892 pcb->hp_flags &= ~HCI_DIRECTION;
893 break;
895 default:
896 error = ENOPROTOOPT;
897 break;
899 break;
901 default:
902 error = ENOPROTOOPT;
903 break;
905 out:
906 lwkt_replymsg(&msg->ctloutput.base.lmsg, error);
910 * HCI mbuf tap routine
912 * copy packets to any raw HCI sockets that wish (and are
913 * permitted) to see them
915 void
916 hci_mtap(struct mbuf *m, struct hci_unit *unit)
918 struct hci_pcb *pcb;
919 struct mbuf *m0, *ctlmsg, **ctl;
920 struct sockaddr_bt sa;
921 uint8_t type;
922 uint8_t event;
923 uint16_t opcode;
925 KKASSERT(m->m_len >= sizeof(type));
927 type = *mtod(m, uint8_t *);
929 memset(&sa, 0, sizeof(sa));
930 sa.bt_len = sizeof(struct sockaddr_bt);
931 sa.bt_family = AF_BLUETOOTH;
932 bdaddr_copy(&sa.bt_bdaddr, &unit->hci_bdaddr);
934 LIST_FOREACH(pcb, &hci_pcb, hp_next) {
936 * filter according to source address
938 if ((pcb->hp_flags & HCI_PROMISCUOUS) == 0
939 && bdaddr_same(&pcb->hp_laddr, &sa.bt_bdaddr) == 0)
940 continue;
943 * filter according to packet type filter
945 if (hci_filter_test(type, &pcb->hp_pfilter) == 0)
946 continue;
949 * filter according to event/security filters
951 switch(type) {
952 case HCI_EVENT_PKT:
953 KKASSERT(m->m_len >= sizeof(hci_event_hdr_t));
955 event = mtod(m, hci_event_hdr_t *)->event;
957 if (hci_filter_test(event, &pcb->hp_efilter) == 0)
958 continue;
960 if ((pcb->hp_flags & HCI_PRIVILEGED) == 0
961 && hci_security_check_event(event) == -1)
962 continue;
963 break;
965 case HCI_CMD_PKT:
966 KKASSERT(m->m_len >= sizeof(hci_cmd_hdr_t));
968 opcode = letoh16(mtod(m, hci_cmd_hdr_t *)->opcode);
970 if ((pcb->hp_flags & HCI_PRIVILEGED) == 0
971 && hci_security_check_opcode(NULL, opcode) == -1)
972 continue;
973 break;
975 case HCI_ACL_DATA_PKT:
976 case HCI_SCO_DATA_PKT:
977 default:
978 if ((pcb->hp_flags & HCI_PRIVILEGED) == 0)
979 continue;
981 break;
985 * create control messages
987 ctlmsg = NULL;
988 ctl = &ctlmsg;
989 if (pcb->hp_flags & HCI_DIRECTION) {
990 int dir = m->m_flags & IFF_LINK0 ? 1 : 0;
992 *ctl = sbcreatecontrol((void *)&dir, sizeof(dir),
993 SCM_HCI_DIRECTION, BTPROTO_HCI);
995 if (*ctl != NULL)
996 ctl = &((*ctl)->m_next);
1000 * copy to socket
1002 m0 = m_copym(m, 0, M_COPYALL, M_NOWAIT);
1003 if (m0 && sbappendaddr(&pcb->hp_socket->so_rcv.sb,
1004 (struct sockaddr *)&sa, m0, ctlmsg)) {
1005 sorwakeup(pcb->hp_socket);
1006 } else {
1007 m_freem(ctlmsg);
1008 m_freem(m0);
1013 struct pr_usrreqs hci_usrreqs = {
1014 .pru_abort = hci_sabort,
1015 .pru_accept = pr_generic_notsupp,
1016 .pru_attach = hci_sattach,
1017 .pru_bind = hci_sbind,
1018 .pru_connect = hci_sconnect,
1019 .pru_connect2 = pr_generic_notsupp,
1020 .pru_control = hci_scontrol,
1021 .pru_detach = hci_sdetach,
1022 .pru_disconnect = hci_sdisconnect,
1023 .pru_listen = pr_generic_notsupp,
1024 .pru_peeraddr = hci_speeraddr,
1025 .pru_rcvd = pr_generic_notsupp,
1026 .pru_rcvoob = pr_generic_notsupp,
1027 .pru_send = hci_ssend,
1028 .pru_sense = pru_sense_null,
1029 .pru_shutdown = hci_sshutdown,
1030 .pru_sockaddr = hci_ssockaddr,
1031 .pru_sosend = sosend,
1032 .pru_soreceive = soreceive