iwm: Fix S:N reporting in ifconfig(8)
[dragonfly.git] / sys / netgraph7 / bluetooth / socket / ng_btsocket_hci_raw.c
1 /*
2  * ng_btsocket_hci_raw.c
3  */
4
5 /*-
6  * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7  * All rights reserved.
8  *
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  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * $Id: ng_btsocket_hci_raw.c,v 1.14 2003/09/14 23:29:06 max Exp $
31  * $FreeBSD: src/sys/netgraph/bluetooth/socket/ng_btsocket_hci_raw.c,v 1.23 2006/11/06 13:42:04 rwatson Exp $
32  */
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/bitstring.h>
37 #include <sys/domain.h>
38 #include <sys/endian.h>
39 #include <sys/errno.h>
40 #include <sys/filedesc.h>
41 #include <sys/kernel.h>
42 #include <sys/lock.h>
43 #include <sys/malloc.h>
44 #include <sys/mbuf.h>
45 #include <sys/caps.h>
46 #include <sys/protosw.h>
47 #include <sys/queue.h>
48 #include <sys/socket.h>
49 #include <sys/socketvar.h>
50 #include <sys/sysctl.h>
51 #include <sys/taskqueue.h>
52 #include <sys/msgport2.h>
53 #include <sys/refcount.h>
54 #include <netgraph7/ng_message.h>
55 #include <netgraph7/netgraph.h>
56 #include <netgraph7/netgraph2.h>
57 #include <netgraph7/bluetooth/include/ng_bluetooth.h>
58 #include <netgraph7/bluetooth/include/ng_hci.h>
59 #include <netgraph7/bluetooth/include/ng_l2cap.h>
60 #include <netgraph7/bluetooth/include/ng_btsocket.h>
61 #include <netgraph7/bluetooth/include/ng_btsocket_hci_raw.h>
62
63 /* MALLOC define */
64 #ifdef NG_SEPARATE_MALLOC
65 MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_HCI_RAW, "netgraph_btsocks_hci_raw",
66         "Netgraph Bluetooth raw HCI sockets");
67 #else
68 #define M_NETGRAPH_BTSOCKET_HCI_RAW M_NETGRAPH
69 #endif /* NG_SEPARATE_MALLOC */
70
71 /* Netgraph node methods */
72 static ng_constructor_t ng_btsocket_hci_raw_node_constructor;
73 static ng_rcvmsg_t      ng_btsocket_hci_raw_node_rcvmsg;
74 static ng_shutdown_t    ng_btsocket_hci_raw_node_shutdown;
75 static ng_newhook_t     ng_btsocket_hci_raw_node_newhook;
76 static ng_connect_t     ng_btsocket_hci_raw_node_connect;
77 static ng_rcvdata_t     ng_btsocket_hci_raw_node_rcvdata;
78 static ng_disconnect_t  ng_btsocket_hci_raw_node_disconnect;
79
80 static void             ng_btsocket_hci_raw_input (void *, int);
81 static void             ng_btsocket_hci_raw_output(node_p, hook_p, void *, int);
82 static void             ng_btsocket_hci_raw_savctl(ng_btsocket_hci_raw_pcb_p,
83                                                    struct mbuf **,
84                                                    struct mbuf *);
85 static int              ng_btsocket_hci_raw_filter(ng_btsocket_hci_raw_pcb_p,
86                                                    struct mbuf *, int);
87
88 #define ng_btsocket_hci_raw_wakeup_input_task() \
89         taskqueue_enqueue(taskqueue_swi, &ng_btsocket_hci_raw_task)
90
91 /* Security filter */
92 struct ng_btsocket_hci_raw_sec_filter {
93         bitstr_t        bit_decl(events, 0xff);
94         bitstr_t        bit_decl(commands[0x3f], 0x3ff);
95 };
96
97 /* Netgraph type descriptor */
98 static struct ng_type typestruct = {
99         .version =      NG_ABI_VERSION,
100         .name =         NG_BTSOCKET_HCI_RAW_NODE_TYPE,
101         .constructor =  ng_btsocket_hci_raw_node_constructor,
102         .rcvmsg =       ng_btsocket_hci_raw_node_rcvmsg,
103         .shutdown =     ng_btsocket_hci_raw_node_shutdown,
104         .newhook =      ng_btsocket_hci_raw_node_newhook,
105         .connect =      ng_btsocket_hci_raw_node_connect,
106         .rcvdata =      ng_btsocket_hci_raw_node_rcvdata,
107         .disconnect =   ng_btsocket_hci_raw_node_disconnect,
108 };
109
110 /* Globals */
111 extern int                                      ifqmaxlen;
112 static u_int32_t                                ng_btsocket_hci_raw_debug_level;
113 static u_int32_t                                ng_btsocket_hci_raw_ioctl_timeout;
114 static node_p                                   ng_btsocket_hci_raw_node;
115 static struct ng_bt_itemq                       ng_btsocket_hci_raw_queue;
116 static struct lock                              ng_btsocket_hci_raw_queue_lock;
117 static struct task                              ng_btsocket_hci_raw_task;
118 static LIST_HEAD(, ng_btsocket_hci_raw_pcb)     ng_btsocket_hci_raw_sockets;
119 static struct lock                              ng_btsocket_hci_raw_sockets_lock;
120 static u_int32_t                                ng_btsocket_hci_raw_token;
121 static struct lock                              ng_btsocket_hci_raw_token_lock;
122 static struct ng_btsocket_hci_raw_sec_filter    *ng_btsocket_hci_raw_sec_filter;
123
124 /* Sysctl tree */
125 SYSCTL_DECL(_net_bluetooth_hci_sockets);
126 SYSCTL_NODE(_net_bluetooth_hci_sockets, OID_AUTO, raw, CTLFLAG_RW,
127         0, "Bluetooth raw HCI sockets family");
128 SYSCTL_INT(_net_bluetooth_hci_sockets_raw, OID_AUTO, debug_level, CTLFLAG_RW,
129         &ng_btsocket_hci_raw_debug_level, NG_BTSOCKET_WARN_LEVEL,
130         "Bluetooth raw HCI sockets debug level");
131 SYSCTL_INT(_net_bluetooth_hci_sockets_raw, OID_AUTO, ioctl_timeout, CTLFLAG_RW,
132         &ng_btsocket_hci_raw_ioctl_timeout, 5,
133         "Bluetooth raw HCI sockets ioctl timeout");
134 SYSCTL_INT(_net_bluetooth_hci_sockets_raw, OID_AUTO, queue_len, CTLFLAG_RD,
135         &ng_btsocket_hci_raw_queue.len, 0,
136         "Bluetooth raw HCI sockets input queue length");
137 SYSCTL_INT(_net_bluetooth_hci_sockets_raw, OID_AUTO, queue_maxlen, CTLFLAG_RD,
138         &ng_btsocket_hci_raw_queue.maxlen, 0,
139         "Bluetooth raw HCI sockets input queue max. length");
140 SYSCTL_INT(_net_bluetooth_hci_sockets_raw, OID_AUTO, queue_drops, CTLFLAG_RD,
141         &ng_btsocket_hci_raw_queue.drops, 0,
142         "Bluetooth raw HCI sockets input queue drops");
143
144 /* Debug */
145 #define NG_BTSOCKET_HCI_RAW_INFO \
146         if (ng_btsocket_hci_raw_debug_level >= NG_BTSOCKET_INFO_LEVEL) \
147                 kprintf
148
149 #define NG_BTSOCKET_HCI_RAW_WARN \
150         if (ng_btsocket_hci_raw_debug_level >= NG_BTSOCKET_WARN_LEVEL) \
151                 kprintf
152
153 #define NG_BTSOCKET_HCI_RAW_ERR \
154         if (ng_btsocket_hci_raw_debug_level >= NG_BTSOCKET_ERR_LEVEL) \
155                 kprintf
156
157 #define NG_BTSOCKET_HCI_RAW_ALERT \
158         if (ng_btsocket_hci_raw_debug_level >= NG_BTSOCKET_ALERT_LEVEL) \
159                 kprintf
160
161 /****************************************************************************
162  ****************************************************************************
163  **                          Netgraph specific
164  ****************************************************************************
165  ****************************************************************************/
166
167 /*
168  * Netgraph node constructor. Do not allow to create node of this type.
169  */
170
171 static int
172 ng_btsocket_hci_raw_node_constructor(node_p node)
173 {
174         return (EINVAL);
175 } /* ng_btsocket_hci_raw_node_constructor */
176
177 /*
178  * Netgraph node destructor. Just let old node go and create new fresh one.
179  */
180
181 static int
182 ng_btsocket_hci_raw_node_shutdown(node_p node)
183 {
184         int     error = 0;
185
186         NG_NODE_UNREF(node);
187
188         error = ng_make_node_common(&typestruct, &ng_btsocket_hci_raw_node);
189         if (error  != 0) {
190                 NG_BTSOCKET_HCI_RAW_ALERT(
191 "%s: Could not create Netgraph node, error=%d\n", __func__, error);
192
193                 ng_btsocket_hci_raw_node = NULL;
194
195                 return (ENOMEM);
196         }
197
198         error = ng_name_node(ng_btsocket_hci_raw_node,
199                                 NG_BTSOCKET_HCI_RAW_NODE_TYPE);
200         if (error != 0) {
201                 NG_BTSOCKET_HCI_RAW_ALERT(
202 "%s: Could not name Netgraph node, error=%d\n", __func__, error);
203
204                 NG_NODE_UNREF(ng_btsocket_hci_raw_node);
205                 ng_btsocket_hci_raw_node = NULL;
206
207                 return (EINVAL);
208         }
209
210         return (0);
211 } /* ng_btsocket_hci_raw_node_shutdown */
212
213 /*
214  * Create new hook. Just say "yes"
215  */
216
217 static int
218 ng_btsocket_hci_raw_node_newhook(node_p node, hook_p hook, char const *name)
219 {
220         return (0);
221 } /* ng_btsocket_hci_raw_node_newhook */
222
223 /*
224  * Connect hook. Just say "yes"
225  */
226
227 static int
228 ng_btsocket_hci_raw_node_connect(hook_p hook)
229 {
230         return (0);
231 } /* ng_btsocket_hci_raw_node_connect */
232
233 /*
234  * Disconnect hook
235  */
236
237 static int
238 ng_btsocket_hci_raw_node_disconnect(hook_p hook)
239 {
240         return (0);
241 } /* ng_btsocket_hci_raw_node_disconnect */
242
243 /*
244  * Receive control message.
245  * Make sure it is a message from HCI node and it is a response.
246  * Enqueue item and schedule input task.
247  */
248
249 static int
250 ng_btsocket_hci_raw_node_rcvmsg(node_p node, item_p item, hook_p lasthook)
251 {
252         struct ng_mesg  *msg = NGI_MSG(item); /* item still has message */
253         int              error = 0;
254
255         /*
256          * Check for empty sockets list creates LOR when both sender and
257          * receiver device are connected to the same host, so remove it
258          * for now
259          */
260
261         if (msg != NULL &&
262             (msg->header.typecookie == NGM_HCI_COOKIE ||
263              msg->header.typecookie == NGM_GENERIC_COOKIE) &&
264             msg->header.flags & NGF_RESP) {
265                 if (msg->header.token == 0) {
266                         NG_FREE_ITEM(item);
267                         return (0);
268                 }
269
270                 lockmgr(&ng_btsocket_hci_raw_queue_lock, LK_EXCLUSIVE);
271                 if (NG_BT_ITEMQ_FULL(&ng_btsocket_hci_raw_queue)) {
272                         NG_BTSOCKET_HCI_RAW_ERR(
273 "%s: Input queue is full\n", __func__);
274
275                         NG_BT_ITEMQ_DROP(&ng_btsocket_hci_raw_queue);
276                         NG_FREE_ITEM(item);
277                         error = ENOBUFS;
278                 } else {
279                         ng_ref_item(item);
280                         NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_hci_raw_queue, item);
281                         error = ng_btsocket_hci_raw_wakeup_input_task();
282                 }
283                 lockmgr(&ng_btsocket_hci_raw_queue_lock, LK_RELEASE);
284         } else {
285                 NG_FREE_ITEM(item);
286                 error = EINVAL;
287         }
288
289         return (error);
290 } /* ng_btsocket_hci_raw_node_rcvmsg */
291
292 /*
293  * Receive packet from the one of our hook.
294  * Prepend every packet with sockaddr_hci and record sender's node name.
295  * Enqueue item and schedule input task.
296  */
297
298 static int
299 ng_btsocket_hci_raw_node_rcvdata(hook_p hook, item_p item)
300 {
301         struct mbuf     *nam = NULL;
302         int              error;
303
304         /*
305          * Check for empty sockets list creates LOR when both sender and
306          * receiver device are connected to the same host, so remove it
307          * for now
308          */
309
310         MGET(nam, M_NOWAIT, MT_SONAME);
311         if (nam != NULL) {
312                 struct sockaddr_hci     *sa = mtod(nam, struct sockaddr_hci *);
313
314                 nam->m_len = sizeof(struct sockaddr_hci);
315
316                 sa->hci_len = sizeof(*sa);
317                 sa->hci_family = AF_BLUETOOTH;
318                 strlcpy(sa->hci_node, NG_PEER_NODE_NAME(hook),
319                         sizeof(sa->hci_node));
320
321                 NGI_GET_M(item, nam->m_next);
322                 NGI_M(item) = nam;
323
324                 lockmgr(&ng_btsocket_hci_raw_queue_lock, LK_EXCLUSIVE);
325                 if (NG_BT_ITEMQ_FULL(&ng_btsocket_hci_raw_queue)) {
326                         NG_BTSOCKET_HCI_RAW_ERR(
327 "%s: Input queue is full\n", __func__);
328
329                         NG_BT_ITEMQ_DROP(&ng_btsocket_hci_raw_queue);
330                         NG_FREE_ITEM(item);
331                         error = ENOBUFS;
332                 } else {
333                         ng_ref_item(item);
334                         NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_hci_raw_queue, item);
335                         error = ng_btsocket_hci_raw_wakeup_input_task();
336                 }
337                 lockmgr(&ng_btsocket_hci_raw_queue_lock, LK_RELEASE);
338         } else {
339                 NG_BTSOCKET_HCI_RAW_ERR(
340 "%s: Failed to allocate address mbuf\n", __func__);
341
342                 NG_FREE_ITEM(item);
343                 error = ENOBUFS;
344         }
345
346         return (error);
347 } /* ng_btsocket_hci_raw_node_rcvdata */
348
349 /****************************************************************************
350  ****************************************************************************
351  **                              Sockets specific
352  ****************************************************************************
353  ****************************************************************************/
354
355 /*
356  * Get next token. We need token to avoid theoretical race where process
357  * submits ioctl() message then interrupts ioctl() and re-submits another
358  * ioctl() on the same socket *before* first ioctl() complete.
359  */
360
361 static void
362 ng_btsocket_hci_raw_get_token(u_int32_t *token)
363 {
364         lockmgr(&ng_btsocket_hci_raw_token_lock, LK_EXCLUSIVE);
365
366         if (++ ng_btsocket_hci_raw_token == 0)
367                 ng_btsocket_hci_raw_token = 1;
368
369         *token = ng_btsocket_hci_raw_token;
370
371         lockmgr(&ng_btsocket_hci_raw_token_lock, LK_RELEASE);
372 } /* ng_btsocket_hci_raw_get_token */
373
374 /*
375  * Send Netgraph message to the node - do not expect reply
376  */
377
378 static int
379 ng_btsocket_hci_raw_send_ngmsg(char *path, int cmd, void *arg, int arglen)
380 {
381         struct ng_mesg  *msg = NULL;
382         int              error = 0;
383
384         NG_MKMESSAGE(msg, NGM_HCI_COOKIE, cmd, arglen, M_WAITOK | M_NULLOK);
385         if (msg == NULL)
386                 return (ENOMEM);
387
388         if (arg != NULL && arglen > 0)
389                 bcopy(arg, msg->data, arglen);
390
391         NG_SEND_MSG_PATH(error, ng_btsocket_hci_raw_node, msg, path, 0);
392
393         return (error);
394 } /* ng_btsocket_hci_raw_send_ngmsg */
395
396 /*
397  * Send Netgraph message to the node (no data) and wait for reply
398  */
399
400 static int
401 ng_btsocket_hci_raw_send_sync_ngmsg(ng_btsocket_hci_raw_pcb_p pcb, char *path,
402                 int cmd, void *rsp, int rsplen)
403 {
404         struct ng_mesg  *msg = NULL;
405         int              error = 0;
406
407         KKASSERT(lockowned(&pcb->pcb_lock) != 0);
408
409         NG_MKMESSAGE(msg, NGM_HCI_COOKIE, cmd, 0, M_WAITOK | M_NULLOK);
410         if (msg == NULL)
411                 return (ENOMEM);
412
413         ng_btsocket_hci_raw_get_token(&msg->header.token);
414         pcb->token = msg->header.token;
415         pcb->msg = NULL;
416
417         NG_SEND_MSG_PATH(error, ng_btsocket_hci_raw_node, msg, path, 0);
418         if (error != 0) {
419                 pcb->token = 0;
420                 return (error);
421         }
422
423         error = lksleep(&pcb->msg, &pcb->pcb_lock, PCATCH, "hcictl",
424                         ng_btsocket_hci_raw_ioctl_timeout * hz);
425         pcb->token = 0;
426
427         if (error != 0)
428                 return (error);
429
430         if (pcb->msg != NULL && pcb->msg->header.cmd == cmd)
431                 bcopy(pcb->msg->data, rsp, rsplen);
432         else
433                 error = EINVAL;
434
435         NG_FREE_MSG(pcb->msg); /* checks for != NULL */
436
437         return (0);
438 } /* ng_btsocket_hci_raw_send_sync_ngmsg */
439
440 /*
441  * Create control information for the packet
442  */
443
444 static void
445 ng_btsocket_hci_raw_savctl(ng_btsocket_hci_raw_pcb_p pcb, struct mbuf **ctl,
446                 struct mbuf *m)
447 {
448         int             dir;
449         struct timeval  tv;
450
451         KKASSERT(lockowned(&pcb->pcb_lock) != 0);
452
453         if (pcb->flags & NG_BTSOCKET_HCI_RAW_DIRECTION) {
454                 dir = (m->m_flags & M_PROTO1)? 1 : 0;
455                 *ctl = sbcreatecontrol(&dir, sizeof(dir),
456                                         SCM_HCI_RAW_DIRECTION, SOL_HCI_RAW);
457                 if (*ctl != NULL)
458                         ctl = &((*ctl)->m_next);
459         }
460
461         if (pcb->so->so_options & SO_TIMESTAMP) {
462                 microtime(&tv);
463                 *ctl = sbcreatecontrol(&tv, sizeof(tv),
464                                         SCM_TIMESTAMP, SOL_SOCKET);
465                 if (*ctl != NULL)
466                         ctl = &((*ctl)->m_next);
467         }
468 } /* ng_btsocket_hci_raw_savctl */
469
470 /*
471  * Raw HCI sockets data input routine
472  */
473
474 static void
475 ng_btsocket_hci_raw_data_input(struct mbuf *nam)
476 {
477         ng_btsocket_hci_raw_pcb_p        pcb = NULL;
478         struct mbuf                     *m0 = NULL, *m = NULL;
479         struct sockaddr_hci             *sa = NULL;
480
481         m0 = nam->m_next;
482         nam->m_next = NULL;
483
484         KASSERT((nam->m_type == MT_SONAME),
485                 ("%s: m_type=%d\n", __func__, nam->m_type));
486         KASSERT((m0->m_flags & M_PKTHDR),
487                 ("%s: m_flags=%#x\n", __func__, m0->m_flags));
488
489         sa = mtod(nam, struct sockaddr_hci *);
490
491         lockmgr(&ng_btsocket_hci_raw_sockets_lock, LK_EXCLUSIVE);
492
493         LIST_FOREACH(pcb, &ng_btsocket_hci_raw_sockets, next) {
494
495                 lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
496
497                 /*
498                  * If socket was bound then check address and
499                  *  make sure it matches.
500                  */
501
502                 if (pcb->addr.hci_node[0] != 0 &&
503                     strcmp(sa->hci_node, pcb->addr.hci_node) != 0)
504                         goto next;
505
506                 /*
507                  * Check packet against filters
508                  * XXX do we have to call m_pullup() here?
509                  */
510
511                 if (ng_btsocket_hci_raw_filter(pcb, m0, 1) != 0)
512                         goto next;
513
514                 /*
515                  * Make a copy of the packet, append to the socket's
516                  * receive queue and wakeup socket. sbappendaddr()
517                  * will check if socket has enough buffer space.
518                  */
519
520                 m = m_dup(m0, M_NOWAIT);
521                 if (m != NULL) {
522                         struct mbuf     *ctl = NULL;
523
524                         ng_btsocket_hci_raw_savctl(pcb, &ctl, m);
525
526                         if (sbappendaddr(&pcb->so->so_rcv.sb,
527                                         (struct sockaddr *) sa, m, ctl))
528                                 sorwakeup(pcb->so);
529                         else {
530                                 NG_BTSOCKET_HCI_RAW_INFO(
531 "%s: sbappendaddr() failed\n", __func__);
532
533                                 NG_FREE_M(m);
534                                 NG_FREE_M(ctl);
535                         }
536                 }
537 next:
538                 lockmgr(&pcb->pcb_lock, LK_RELEASE);
539         }
540
541         lockmgr(&ng_btsocket_hci_raw_sockets_lock, LK_RELEASE);
542
543         NG_FREE_M(nam);
544         NG_FREE_M(m0);
545 } /* ng_btsocket_hci_raw_data_input */
546
547 /*
548  * Raw HCI sockets message input routine
549  */
550
551 static void
552 ng_btsocket_hci_raw_msg_input(struct ng_mesg *msg)
553 {
554         ng_btsocket_hci_raw_pcb_p       pcb = NULL;
555
556         lockmgr(&ng_btsocket_hci_raw_sockets_lock, LK_EXCLUSIVE);
557
558         LIST_FOREACH(pcb, &ng_btsocket_hci_raw_sockets, next) {
559                 lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
560
561                 if (msg->header.token == pcb->token) {
562                         pcb->msg = msg;
563                         wakeup(&pcb->msg);
564
565                         lockmgr(&pcb->pcb_lock, LK_RELEASE);
566                         lockmgr(&ng_btsocket_hci_raw_sockets_lock, LK_RELEASE);
567
568                         return;
569                 }
570
571                 lockmgr(&pcb->pcb_lock, LK_RELEASE);
572         }
573
574         lockmgr(&ng_btsocket_hci_raw_sockets_lock, LK_RELEASE);
575
576         NG_FREE_MSG(msg); /* checks for != NULL */
577 } /* ng_btsocket_hci_raw_msg_input */
578
579 /*
580  * Raw HCI sockets input routines
581  */
582
583 static void
584 ng_btsocket_hci_raw_input(void *context, int pending)
585 {
586         item_p  item = NULL;
587
588         for (;;) {
589                 lockmgr(&ng_btsocket_hci_raw_queue_lock, LK_EXCLUSIVE);
590                 NG_BT_ITEMQ_DEQUEUE(&ng_btsocket_hci_raw_queue, item);
591                 lockmgr(&ng_btsocket_hci_raw_queue_lock, LK_RELEASE);
592
593                 if (item == NULL)
594                         break;
595
596                 switch(item->el_flags & NGQF_TYPE) {
597                 case NGQF_DATA: {
598                         struct mbuf     *m = NULL;
599
600                         NGI_GET_M(item, m);
601                         ng_btsocket_hci_raw_data_input(m);
602                         } break;
603
604                 case NGQF_MESG: {
605                         struct ng_mesg  *msg = NULL;
606
607                         NGI_GET_MSG(item, msg);
608                         ng_btsocket_hci_raw_msg_input(msg);
609                         } break;
610
611                 default:
612                         KASSERT(0,
613 ("%s: invalid item type=%ld\n", __func__, (item->el_flags & NGQF_TYPE)));
614                         break;
615                 }
616
617                 NG_FREE_ITEM(item);
618                 ng_unref_item(item, 0);
619         }
620 } /* ng_btsocket_hci_raw_input */
621
622 /*
623  * Raw HCI sockets output routine
624  */
625
626 static void
627 ng_btsocket_hci_raw_output(node_p node, hook_p hook, void *arg1, int arg2)
628 {
629         struct mbuf             *nam = (struct mbuf *) arg1, *m = NULL;
630         struct sockaddr_hci     *sa = NULL;
631         int                      error;
632
633         m = nam->m_next;
634         nam->m_next = NULL;
635
636         KASSERT((nam->m_type == MT_SONAME),
637                 ("%s: m_type=%d\n", __func__, nam->m_type));
638         KASSERT((m->m_flags & M_PKTHDR),
639                 ("%s: m_flags=%#x\n", __func__, m->m_flags));
640
641         sa = mtod(nam, struct sockaddr_hci *);
642
643         /*
644          * Find downstream hook
645          * XXX For now access node hook list directly. Should be safe because
646          * we used ng_send_fn() and we should have exclusive lock on the node.
647          */
648
649         LIST_FOREACH(hook, &node->nd_hooks, hk_hooks) {
650                 if (hook == NULL || NG_HOOK_NOT_VALID(hook) ||
651                     NG_NODE_NOT_VALID(NG_PEER_NODE(hook)))
652                         continue;
653
654                 if (strcmp(sa->hci_node, NG_PEER_NODE_NAME(hook)) == 0) {
655                         NG_SEND_DATA_ONLY(error, hook, m); /* sets m to NULL */
656                         break;
657                 }
658         }
659
660         NG_FREE_M(nam); /* check for != NULL */
661         NG_FREE_M(m);
662 } /* ng_btsocket_hci_raw_output */
663
664 /*
665  * Check frame against security and socket filters.
666  * d (direction bit) == 1 means incoming frame.
667  */
668
669 static int
670 ng_btsocket_hci_raw_filter(ng_btsocket_hci_raw_pcb_p pcb, struct mbuf *m, int d)
671 {
672         int     type, event, opcode;
673
674         KKASSERT(lockowned(&pcb->pcb_lock) != 0);
675
676         switch ((type = *mtod(m, u_int8_t *))) {
677         case NG_HCI_CMD_PKT:
678                 if (!(pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED)) {
679                         opcode = le16toh(mtod(m, ng_hci_cmd_pkt_t *)->opcode);
680
681                         if (!bit_test(
682 ng_btsocket_hci_raw_sec_filter->commands[NG_HCI_OGF(opcode) - 1],
683 NG_HCI_OCF(opcode) - 1))
684                                 return (EPERM);
685                 }
686
687                 if (d && !bit_test(pcb->filter.packet_mask, NG_HCI_CMD_PKT - 1))
688                         return (EPERM);
689                 break;
690
691         case NG_HCI_ACL_DATA_PKT:
692         case NG_HCI_SCO_DATA_PKT:
693                 if (!(pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED) ||
694                     !bit_test(pcb->filter.packet_mask, type - 1) ||
695                     !d)
696                         return (EPERM);
697                 break;
698
699         case NG_HCI_EVENT_PKT:
700                 if (!d)
701                         return (EINVAL);
702
703                 event = mtod(m, ng_hci_event_pkt_t *)->event - 1;
704
705                 if (!(pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED))
706                         if (!bit_test(ng_btsocket_hci_raw_sec_filter->events, event))
707                                 return (EPERM);
708
709                 if (!bit_test(pcb->filter.event_mask, event))
710                         return (EPERM);
711                 break;
712
713         default:
714                 return (EINVAL);
715         }
716
717         return (0);
718 } /* ng_btsocket_hci_raw_filter */
719
720 /*
721  * Initialize everything
722  */
723
724 void
725 ng_btsocket_hci_raw_init(void)
726 {
727         bitstr_t        *f = NULL;
728         int              error = 0;
729
730         ng_btsocket_hci_raw_node = NULL;
731         ng_btsocket_hci_raw_debug_level = NG_BTSOCKET_WARN_LEVEL;
732         ng_btsocket_hci_raw_ioctl_timeout = 5;
733
734         /* Register Netgraph node type */
735         error = ng_newtype(&typestruct);
736         if (error != 0) {
737                 NG_BTSOCKET_HCI_RAW_ALERT(
738 "%s: Could not register Netgraph node type, error=%d\n", __func__, error);
739
740                 return;
741         }
742
743         /* Create Netgrapg node */
744         error = ng_make_node_common(&typestruct, &ng_btsocket_hci_raw_node);
745         if (error != 0) {
746                 NG_BTSOCKET_HCI_RAW_ALERT(
747 "%s: Could not create Netgraph node, error=%d\n", __func__, error);
748
749                 ng_btsocket_hci_raw_node = NULL;
750
751                 return;
752         }
753
754         error = ng_name_node(ng_btsocket_hci_raw_node,
755                                 NG_BTSOCKET_HCI_RAW_NODE_TYPE);
756         if (error != 0) {
757                 NG_BTSOCKET_HCI_RAW_ALERT(
758 "%s: Could not name Netgraph node, error=%d\n", __func__, error);
759
760                 NG_NODE_UNREF(ng_btsocket_hci_raw_node);
761                 ng_btsocket_hci_raw_node = NULL;
762
763                 return;
764         }
765
766         /* Create input queue */
767         NG_BT_ITEMQ_INIT(&ng_btsocket_hci_raw_queue, ifqmaxlen);
768         lockinit(&ng_btsocket_hci_raw_queue_lock,
769                 "btsocks_hci_raw_queue_lock", 0, 0);
770         TASK_INIT(&ng_btsocket_hci_raw_task, 0,
771                 ng_btsocket_hci_raw_input, NULL);
772
773         /* Create list of sockets */
774         LIST_INIT(&ng_btsocket_hci_raw_sockets);
775         lockinit(&ng_btsocket_hci_raw_sockets_lock,
776                 "btsocks_hci_raw_sockets_lock", 0, 0);
777
778         /* Tokens */
779         ng_btsocket_hci_raw_token = 0;
780         lockinit(&ng_btsocket_hci_raw_token_lock,
781                 "btsocks_hci_raw_token_lock", 0, 0);
782
783         /*
784          * Security filter
785          * XXX never FREE()ed
786          */
787
788         ng_btsocket_hci_raw_sec_filter = NULL;
789
790         ng_btsocket_hci_raw_sec_filter = kmalloc(sizeof(struct ng_btsocket_hci_raw_sec_filter),
791                                                  M_NETGRAPH_BTSOCKET_HCI_RAW,
792                                                  M_WAITOK | M_NULLOK | M_ZERO);
793         if (ng_btsocket_hci_raw_sec_filter == NULL) {
794                 kprintf("%s: Could not allocate security filter!\n", __func__);
795                 return;
796         }
797
798         /*
799          * XXX How paranoid can we get?
800          *
801          * Initialize security filter. If bit is set in the mask then
802          * unprivileged socket is allowed to send (receive) this command
803          * (event).
804          */
805
806         /* Enable all events */
807         memset(&ng_btsocket_hci_raw_sec_filter->events, 0xff,
808                 sizeof(ng_btsocket_hci_raw_sec_filter->events));
809
810         /* Disable some critical events */
811         f = ng_btsocket_hci_raw_sec_filter->events;
812         bit_clear(f, NG_HCI_EVENT_RETURN_LINK_KEYS - 1);
813         bit_clear(f, NG_HCI_EVENT_LINK_KEY_NOTIFICATION - 1);
814         bit_clear(f, NG_HCI_EVENT_VENDOR - 1);
815
816         /* Commands - Link control */
817         f = ng_btsocket_hci_raw_sec_filter->commands[NG_HCI_OGF_LINK_CONTROL-1];
818         bit_set(f, NG_HCI_OCF_INQUIRY - 1);
819         bit_set(f, NG_HCI_OCF_INQUIRY_CANCEL - 1);
820         bit_set(f, NG_HCI_OCF_PERIODIC_INQUIRY - 1);
821         bit_set(f, NG_HCI_OCF_EXIT_PERIODIC_INQUIRY - 1);
822         bit_set(f, NG_HCI_OCF_REMOTE_NAME_REQ - 1);
823         bit_set(f, NG_HCI_OCF_READ_REMOTE_FEATURES - 1);
824         bit_set(f, NG_HCI_OCF_READ_REMOTE_VER_INFO - 1);
825         bit_set(f, NG_HCI_OCF_READ_CLOCK_OFFSET - 1);
826
827         /* Commands - Link policy */
828         f = ng_btsocket_hci_raw_sec_filter->commands[NG_HCI_OGF_LINK_POLICY-1];
829         bit_set(f, NG_HCI_OCF_ROLE_DISCOVERY - 1);
830         bit_set(f, NG_HCI_OCF_READ_LINK_POLICY_SETTINGS - 1);
831
832         /* Commands - Host controller and baseband */
833         f = ng_btsocket_hci_raw_sec_filter->commands[NG_HCI_OGF_HC_BASEBAND-1];
834         bit_set(f, NG_HCI_OCF_READ_PIN_TYPE - 1);
835         bit_set(f, NG_HCI_OCF_READ_LOCAL_NAME - 1);
836         bit_set(f, NG_HCI_OCF_READ_CON_ACCEPT_TIMO - 1);
837         bit_set(f, NG_HCI_OCF_READ_PAGE_TIMO - 1);
838         bit_set(f, NG_HCI_OCF_READ_SCAN_ENABLE - 1);
839         bit_set(f, NG_HCI_OCF_READ_PAGE_SCAN_ACTIVITY - 1);
840         bit_set(f, NG_HCI_OCF_READ_INQUIRY_SCAN_ACTIVITY - 1);
841         bit_set(f, NG_HCI_OCF_READ_AUTH_ENABLE - 1);
842         bit_set(f, NG_HCI_OCF_READ_ENCRYPTION_MODE - 1);
843         bit_set(f, NG_HCI_OCF_READ_UNIT_CLASS - 1);
844         bit_set(f, NG_HCI_OCF_READ_VOICE_SETTINGS - 1);
845         bit_set(f, NG_HCI_OCF_READ_AUTO_FLUSH_TIMO - 1);
846         bit_set(f, NG_HCI_OCF_READ_NUM_BROADCAST_RETRANS - 1);
847         bit_set(f, NG_HCI_OCF_READ_HOLD_MODE_ACTIVITY - 1);
848         bit_set(f, NG_HCI_OCF_READ_XMIT_LEVEL - 1);
849         bit_set(f, NG_HCI_OCF_READ_SCO_FLOW_CONTROL - 1);
850         bit_set(f, NG_HCI_OCF_READ_LINK_SUPERVISION_TIMO - 1);
851         bit_set(f, NG_HCI_OCF_READ_SUPPORTED_IAC_NUM - 1);
852         bit_set(f, NG_HCI_OCF_READ_IAC_LAP - 1);
853         bit_set(f, NG_HCI_OCF_READ_PAGE_SCAN_PERIOD - 1);
854         bit_set(f, NG_HCI_OCF_READ_PAGE_SCAN - 1);
855
856         /* Commands - Informational */
857         f = ng_btsocket_hci_raw_sec_filter->commands[NG_HCI_OGF_INFO - 1];
858         bit_set(f, NG_HCI_OCF_READ_LOCAL_VER - 1);
859         bit_set(f, NG_HCI_OCF_READ_LOCAL_FEATURES - 1);
860         bit_set(f, NG_HCI_OCF_READ_BUFFER_SIZE - 1);
861         bit_set(f, NG_HCI_OCF_READ_COUNTRY_CODE - 1);
862         bit_set(f, NG_HCI_OCF_READ_BDADDR - 1);
863
864         /* Commands - Status */
865         f = ng_btsocket_hci_raw_sec_filter->commands[NG_HCI_OGF_STATUS - 1];
866         bit_set(f, NG_HCI_OCF_READ_FAILED_CONTACT_CNTR - 1);
867         bit_set(f, NG_HCI_OCF_GET_LINK_QUALITY - 1);
868         bit_set(f, NG_HCI_OCF_READ_RSSI - 1);
869
870         /* Commands - Testing */
871         f = ng_btsocket_hci_raw_sec_filter->commands[NG_HCI_OGF_TESTING - 1];
872         bit_set(f, NG_HCI_OCF_READ_LOOPBACK_MODE - 1);
873 } /* ng_btsocket_hci_raw_init */
874
875 /*
876  * Abort connection on socket
877  */
878
879 void
880 ng_btsocket_hci_raw_abort(netmsg_t msg)
881 {
882 } /* ng_btsocket_hci_raw_abort */
883
884 #if 0 /* XXX */
885 void
886 ng_btsocket_hci_raw_close(struct socket *so)
887 {
888 } /* ng_btsocket_hci_raw_close */
889 #endif
890
891 /*
892  * Create new raw HCI socket
893  */
894
895 void
896 ng_btsocket_hci_raw_attach(netmsg_t msg)
897 {
898         struct socket                   *so = msg->attach.base.nm_so;
899         int                              proto = msg->attach.nm_proto;
900         ng_btsocket_hci_raw_pcb_p        pcb = so2hci_raw_pcb(so);
901         int                              error = 0;
902
903         if (pcb != NULL) {
904                 error = EISCONN;
905                 goto out;
906         }
907
908         if (ng_btsocket_hci_raw_node == NULL) {
909                 error = EPROTONOSUPPORT;
910                 goto out;
911         }
912         if (proto != BLUETOOTH_PROTO_HCI) {
913                 error = EPROTONOSUPPORT;
914                 goto out;
915         }
916         if (so->so_type != SOCK_RAW) {
917                 error = ESOCKTNOSUPPORT;
918                 goto out;
919         }
920
921         error = soreserve(so, NG_BTSOCKET_HCI_RAW_SENDSPACE,
922                                 NG_BTSOCKET_HCI_RAW_RECVSPACE, NULL);
923         if (error != 0)
924                 goto out;
925
926         pcb = kmalloc(sizeof(*pcb), M_NETGRAPH_BTSOCKET_HCI_RAW,
927                       M_WAITOK | M_NULLOK | M_ZERO);
928         if (pcb == NULL) {
929                 error = ENOMEM;
930                 goto out;
931         }
932
933         so->so_pcb = (caddr_t) pcb;
934         pcb->so = so;
935
936         if (curproc == NULL ||
937             caps_priv_check_self(SYSCAP_NONET_BT_RAW) == 0)
938                 pcb->flags |= NG_BTSOCKET_HCI_RAW_PRIVILEGED;
939
940         /*
941          * Set default socket filter. By default socket only accepts HCI
942          * Command_Complete and Command_Status event packets.
943          */
944
945         bit_set(pcb->filter.event_mask, NG_HCI_EVENT_COMMAND_COMPL - 1);
946         bit_set(pcb->filter.event_mask, NG_HCI_EVENT_COMMAND_STATUS - 1);
947
948         lockinit(&pcb->pcb_lock, "btsocks_hci_raw_pcb_lock", 0, 0);
949
950         lockmgr(&ng_btsocket_hci_raw_sockets_lock, LK_EXCLUSIVE);
951         LIST_INSERT_HEAD(&ng_btsocket_hci_raw_sockets, pcb, next);
952         lockmgr(&ng_btsocket_hci_raw_sockets_lock, LK_RELEASE);
953
954 out:
955         lwkt_replymsg(&msg->attach.base.lmsg, error);
956 } /* ng_btsocket_hci_raw_attach */
957
958 /*
959  * Bind raw HCI socket
960  */
961
962 void
963 ng_btsocket_hci_raw_bind(netmsg_t msg)
964 {
965         struct socket                   *so = msg->bind.base.nm_so;
966         struct sockaddr                 *nam = msg->bind.nm_nam;
967         ng_btsocket_hci_raw_pcb_p        pcb = so2hci_raw_pcb(so);
968         struct sockaddr_hci             *sa = (struct sockaddr_hci *) nam;
969         int                              error = 0;
970
971         if (pcb == NULL) {
972                 error = EINVAL;
973                 goto out;
974         }
975         if (ng_btsocket_hci_raw_node == NULL) {
976                 error = EINVAL;
977                 goto out;
978         }
979
980         if (sa == NULL) {
981                 error = EINVAL;
982                 goto out;
983         }
984         if (sa->hci_family != AF_BLUETOOTH) {
985                 error = EAFNOSUPPORT;
986                 goto out;
987         }
988         if (sa->hci_len != sizeof(*sa)) {
989                 error = EINVAL;
990                 goto out;
991         }
992         if (sa->hci_node[0] == 0) {
993                 error = EINVAL;
994                 goto out;
995         }
996
997         lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
998         bcopy(sa, &pcb->addr, sizeof(pcb->addr));
999         lockmgr(&pcb->pcb_lock, LK_RELEASE);
1000
1001 out:
1002         lwkt_replymsg(&msg->bind.base.lmsg, error);
1003 } /* ng_btsocket_hci_raw_bind */
1004
1005 /*
1006  * Connect raw HCI socket
1007  */
1008
1009 void
1010 ng_btsocket_hci_raw_connect(netmsg_t msg)
1011 {
1012         struct socket                   *so = msg->connect.base.nm_so;
1013         struct sockaddr                 *nam = msg->connect.nm_nam;
1014         ng_btsocket_hci_raw_pcb_p        pcb = so2hci_raw_pcb(so);
1015         struct sockaddr_hci             *sa = (struct sockaddr_hci *) nam;
1016         int                              error = 0;
1017
1018         if (pcb == NULL) {
1019                 error = EINVAL;
1020                 goto out;
1021         }
1022         if (ng_btsocket_hci_raw_node == NULL) {
1023                 error = EINVAL;
1024                 goto out;
1025         }
1026
1027         if (sa == NULL) {
1028                 error = EINVAL;
1029                 goto out;
1030         }
1031         if (sa->hci_family != AF_BLUETOOTH) {
1032                 error = EAFNOSUPPORT;
1033                 goto out;
1034         }
1035         if (sa->hci_len != sizeof(*sa)) {
1036                 error = EINVAL;
1037                 goto out;
1038         }
1039         if (sa->hci_node[0] == 0) {
1040                 error = EDESTADDRREQ;
1041                 goto out;
1042         }
1043
1044         lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
1045
1046         if (bcmp(sa, &pcb->addr, sizeof(pcb->addr)) != 0) {
1047                 lockmgr(&pcb->pcb_lock, LK_RELEASE);
1048                 error = EADDRNOTAVAIL;
1049                 goto out;
1050         }
1051
1052         soisconnected(so);
1053
1054         lockmgr(&pcb->pcb_lock, LK_RELEASE);
1055
1056 out:
1057         lwkt_replymsg(&msg->connect.base.lmsg, error);
1058 } /* ng_btsocket_hci_raw_connect */
1059
1060 /*
1061  * Process ioctl on socket
1062  */
1063
1064 void
1065 ng_btsocket_hci_raw_control(netmsg_t msg)
1066 {
1067         struct socket                   *so = msg->control.base.nm_so;
1068         u_long                           cmd = msg->control.nm_cmd;
1069         caddr_t                          data = msg->control.nm_data;
1070         ng_btsocket_hci_raw_pcb_p        pcb = so2hci_raw_pcb(so);
1071         char                             path[NG_NODESIZ + 1];
1072         struct ng_mesg                  *ngmsg = NULL;
1073         int                              error = 0;
1074
1075         if (pcb == NULL) {
1076                 error = EINVAL;
1077                 goto out;
1078         }
1079         if (ng_btsocket_hci_raw_node == NULL) {
1080                 error = EINVAL;
1081                 goto out;
1082         }
1083
1084         lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
1085
1086         /* Check if we have device name */
1087         if (pcb->addr.hci_node[0] == 0) {
1088                 lockmgr(&pcb->pcb_lock, LK_RELEASE);
1089                 error = EHOSTUNREACH;
1090                 goto out;
1091         }
1092
1093         /* Check if we have pending ioctl() */
1094         if (pcb->token != 0) {
1095                 lockmgr(&pcb->pcb_lock, LK_RELEASE);
1096                 error = EBUSY;
1097                 goto out;
1098         }
1099
1100         ksnprintf(path, sizeof(path), "%s:", pcb->addr.hci_node);
1101
1102         switch (cmd) {
1103         case SIOC_HCI_RAW_NODE_GET_STATE: {
1104                 struct ng_btsocket_hci_raw_node_state   *p =
1105                         (struct ng_btsocket_hci_raw_node_state *) data;
1106
1107                 error = ng_btsocket_hci_raw_send_sync_ngmsg(pcb, path,
1108                                 NGM_HCI_NODE_GET_STATE,
1109                                 &p->state, sizeof(p->state));
1110                 } break;
1111
1112         case SIOC_HCI_RAW_NODE_INIT:
1113                 if (pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED)
1114                         error = ng_btsocket_hci_raw_send_ngmsg(path,
1115                                         NGM_HCI_NODE_INIT, NULL, 0);
1116                 else
1117                         error = EPERM;
1118                 break;
1119
1120         case SIOC_HCI_RAW_NODE_GET_DEBUG: {
1121                 struct ng_btsocket_hci_raw_node_debug   *p =
1122                         (struct ng_btsocket_hci_raw_node_debug *) data;
1123
1124                 error = ng_btsocket_hci_raw_send_sync_ngmsg(pcb, path,
1125                                 NGM_HCI_NODE_GET_DEBUG,
1126                                 &p->debug, sizeof(p->debug));
1127                 } break;
1128
1129         case SIOC_HCI_RAW_NODE_SET_DEBUG: {
1130                 struct ng_btsocket_hci_raw_node_debug   *p =
1131                         (struct ng_btsocket_hci_raw_node_debug *) data;
1132
1133                 if (pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED)
1134                         error = ng_btsocket_hci_raw_send_ngmsg(path,
1135                                         NGM_HCI_NODE_SET_DEBUG, &p->debug,
1136                                         sizeof(p->debug));
1137                 else
1138                         error = EPERM;
1139                 } break;
1140
1141         case SIOC_HCI_RAW_NODE_GET_BUFFER: {
1142                 struct ng_btsocket_hci_raw_node_buffer  *p =
1143                         (struct ng_btsocket_hci_raw_node_buffer *) data;
1144
1145                 error = ng_btsocket_hci_raw_send_sync_ngmsg(pcb, path,
1146                                 NGM_HCI_NODE_GET_BUFFER,
1147                                 &p->buffer, sizeof(p->buffer));
1148                 } break;
1149
1150         case SIOC_HCI_RAW_NODE_GET_BDADDR: {
1151                 struct ng_btsocket_hci_raw_node_bdaddr  *p =
1152                         (struct ng_btsocket_hci_raw_node_bdaddr *) data;
1153
1154                 error = ng_btsocket_hci_raw_send_sync_ngmsg(pcb, path,
1155                                 NGM_HCI_NODE_GET_BDADDR,
1156                                 &p->bdaddr, sizeof(p->bdaddr));
1157                 } break;
1158
1159         case SIOC_HCI_RAW_NODE_GET_FEATURES: {
1160                 struct ng_btsocket_hci_raw_node_features        *p =
1161                         (struct ng_btsocket_hci_raw_node_features *) data;
1162
1163                 error = ng_btsocket_hci_raw_send_sync_ngmsg(pcb, path,
1164                                 NGM_HCI_NODE_GET_FEATURES,
1165                                 &p->features, sizeof(p->features));
1166                 } break;
1167
1168         case SIOC_HCI_RAW_NODE_GET_STAT: {
1169                 struct ng_btsocket_hci_raw_node_stat    *p =
1170                         (struct ng_btsocket_hci_raw_node_stat *) data;
1171
1172                 error = ng_btsocket_hci_raw_send_sync_ngmsg(pcb, path,
1173                                 NGM_HCI_NODE_GET_STAT,
1174                                 &p->stat, sizeof(p->stat));
1175                 } break;
1176
1177         case SIOC_HCI_RAW_NODE_RESET_STAT:
1178                 if (pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED)
1179                         error = ng_btsocket_hci_raw_send_ngmsg(path,
1180                                         NGM_HCI_NODE_RESET_STAT, NULL, 0);
1181                 else
1182                         error = EPERM;
1183                 break;
1184
1185         case SIOC_HCI_RAW_NODE_FLUSH_NEIGHBOR_CACHE:
1186                 if (pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED)
1187                         error = ng_btsocket_hci_raw_send_ngmsg(path,
1188                                         NGM_HCI_NODE_FLUSH_NEIGHBOR_CACHE,
1189                                         NULL, 0);
1190                 else
1191                         error = EPERM;
1192                 break;
1193
1194         case SIOC_HCI_RAW_NODE_GET_NEIGHBOR_CACHE:  {
1195                 struct ng_btsocket_hci_raw_node_neighbor_cache  *p =
1196                         (struct ng_btsocket_hci_raw_node_neighbor_cache *) data;
1197                 ng_hci_node_get_neighbor_cache_ep               *p1 = NULL;
1198                 ng_hci_node_neighbor_cache_entry_ep             *p2 = NULL;
1199
1200                 if (p->num_entries <= 0 ||
1201                     p->num_entries > NG_HCI_MAX_NEIGHBOR_NUM ||
1202                     p->entries == NULL) {
1203                         error = EINVAL;
1204                         break;
1205                 }
1206
1207                 NG_MKMESSAGE(ngmsg, NGM_HCI_COOKIE,
1208                         NGM_HCI_NODE_GET_NEIGHBOR_CACHE, 0, M_WAITOK | M_NULLOK);
1209                 if (ngmsg == NULL) {
1210                         error = ENOMEM;
1211                         break;
1212                 }
1213                 ng_btsocket_hci_raw_get_token(&ngmsg->header.token);
1214                 pcb->token = ngmsg->header.token;
1215                 pcb->msg = NULL;
1216
1217                 NG_SEND_MSG_PATH(error, ng_btsocket_hci_raw_node, ngmsg, path, 0);
1218                 if (error != 0) {
1219                         pcb->token = 0;
1220                         break;
1221                 }
1222
1223                 error = lksleep(&pcb->msg, &pcb->pcb_lock,
1224                                 PCATCH, "hcictl",
1225                                 ng_btsocket_hci_raw_ioctl_timeout * hz);
1226                 pcb->token = 0;
1227
1228                 if (error != 0)
1229                         break;
1230
1231                 if (pcb->msg != NULL &&
1232                     pcb->msg->header.cmd == NGM_HCI_NODE_GET_NEIGHBOR_CACHE) {
1233                         /* Return data back to user space */
1234                         p1 = (ng_hci_node_get_neighbor_cache_ep *)
1235                                 (pcb->msg->data);
1236                         p2 = (ng_hci_node_neighbor_cache_entry_ep *)
1237                                 (p1 + 1);
1238
1239                         p->num_entries = min(p->num_entries, p1->num_entries);
1240                         if (p->num_entries > 0)
1241                                 error = copyout((caddr_t) p2,
1242                                                 (caddr_t) p->entries,
1243                                                 p->num_entries * sizeof(*p2));
1244                 } else
1245                         error = EINVAL;
1246
1247                 NG_FREE_MSG(pcb->msg); /* checks for != NULL */
1248                 }break;
1249
1250         case SIOC_HCI_RAW_NODE_GET_CON_LIST: {
1251                 struct ng_btsocket_hci_raw_con_list     *p =
1252                         (struct ng_btsocket_hci_raw_con_list *) data;
1253                 ng_hci_node_con_list_ep                 *p1 = NULL;
1254                 ng_hci_node_con_ep                      *p2 = NULL;
1255
1256                 if (p->num_connections == 0 ||
1257                     p->num_connections > NG_HCI_MAX_CON_NUM ||
1258                     p->connections == NULL) {
1259                         error = EINVAL;
1260                         break;
1261                 }
1262
1263                 NG_MKMESSAGE(ngmsg, NGM_HCI_COOKIE, NGM_HCI_NODE_GET_CON_LIST,
1264                         0, M_WAITOK | M_NULLOK);
1265                 if (ngmsg == NULL) {
1266                         error = ENOMEM;
1267                         break;
1268                 }
1269                 ng_btsocket_hci_raw_get_token(&ngmsg->header.token);
1270                 pcb->token = ngmsg->header.token;
1271                 pcb->msg = NULL;
1272
1273                 NG_SEND_MSG_PATH(error, ng_btsocket_hci_raw_node, ngmsg, path, 0);
1274                 if (error != 0) {
1275                         pcb->token = 0;
1276                         break;
1277                 }
1278
1279                 error = lksleep(&pcb->msg, &pcb->pcb_lock,
1280                                 PCATCH, "hcictl",
1281                                 ng_btsocket_hci_raw_ioctl_timeout * hz);
1282                 pcb->token = 0;
1283
1284                 if (error != 0)
1285                         break;
1286
1287                 if (pcb->msg != NULL &&
1288                     pcb->msg->header.cmd == NGM_HCI_NODE_GET_CON_LIST) {
1289                         /* Return data back to user space */
1290                         p1 = (ng_hci_node_con_list_ep *)(pcb->msg->data);
1291                         p2 = (ng_hci_node_con_ep *)(p1 + 1);
1292
1293                         p->num_connections = min(p->num_connections,
1294                                                 p1->num_connections);
1295                         if (p->num_connections > 0)
1296                                 error = copyout((caddr_t) p2,
1297                                         (caddr_t) p->connections,
1298                                         p->num_connections * sizeof(*p2));
1299                 } else
1300                         error = EINVAL;
1301
1302                 NG_FREE_MSG(pcb->msg); /* checks for != NULL */
1303                 } break;
1304
1305         case SIOC_HCI_RAW_NODE_GET_LINK_POLICY_MASK: {
1306                 struct ng_btsocket_hci_raw_node_link_policy_mask        *p =
1307                         (struct ng_btsocket_hci_raw_node_link_policy_mask *)
1308                                 data;
1309
1310                 error = ng_btsocket_hci_raw_send_sync_ngmsg(pcb, path,
1311                                 NGM_HCI_NODE_GET_LINK_POLICY_SETTINGS_MASK,
1312                                 &p->policy_mask, sizeof(p->policy_mask));
1313                 } break;
1314
1315         case SIOC_HCI_RAW_NODE_SET_LINK_POLICY_MASK: {
1316                 struct ng_btsocket_hci_raw_node_link_policy_mask        *p =
1317                         (struct ng_btsocket_hci_raw_node_link_policy_mask *)
1318                                 data;
1319
1320                 if (pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED)
1321                         error = ng_btsocket_hci_raw_send_ngmsg(path,
1322                                         NGM_HCI_NODE_SET_LINK_POLICY_SETTINGS_MASK,
1323                                         &p->policy_mask,
1324                                         sizeof(p->policy_mask));
1325                 else
1326                         error = EPERM;
1327                 } break;
1328
1329         case SIOC_HCI_RAW_NODE_GET_PACKET_MASK: {
1330                 struct ng_btsocket_hci_raw_node_packet_mask     *p =
1331                         (struct ng_btsocket_hci_raw_node_packet_mask *) data;
1332
1333                 error = ng_btsocket_hci_raw_send_sync_ngmsg(pcb, path,
1334                                 NGM_HCI_NODE_GET_PACKET_MASK,
1335                                 &p->packet_mask, sizeof(p->packet_mask));
1336                 } break;
1337
1338         case SIOC_HCI_RAW_NODE_SET_PACKET_MASK: {
1339                 struct ng_btsocket_hci_raw_node_packet_mask     *p =
1340                         (struct ng_btsocket_hci_raw_node_packet_mask *) data;
1341
1342                 if (pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED)
1343                         error = ng_btsocket_hci_raw_send_ngmsg(path,
1344                                         NGM_HCI_NODE_SET_PACKET_MASK,
1345                                         &p->packet_mask,
1346                                         sizeof(p->packet_mask));
1347                 else
1348                         error = EPERM;
1349                 } break;
1350
1351         case SIOC_HCI_RAW_NODE_GET_ROLE_SWITCH: {
1352                 struct ng_btsocket_hci_raw_node_role_switch     *p =
1353                         (struct ng_btsocket_hci_raw_node_role_switch *) data;
1354
1355                 error = ng_btsocket_hci_raw_send_sync_ngmsg(pcb, path,
1356                                 NGM_HCI_NODE_GET_ROLE_SWITCH,
1357                                 &p->role_switch, sizeof(p->role_switch));
1358                 } break;
1359
1360         case SIOC_HCI_RAW_NODE_SET_ROLE_SWITCH: {
1361                 struct ng_btsocket_hci_raw_node_role_switch     *p =
1362                         (struct ng_btsocket_hci_raw_node_role_switch *) data;
1363
1364                 if (pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED)
1365                         error = ng_btsocket_hci_raw_send_ngmsg(path,
1366                                         NGM_HCI_NODE_SET_ROLE_SWITCH,
1367                                         &p->role_switch,
1368                                         sizeof(p->role_switch));
1369                 else
1370                         error = EPERM;
1371                 } break;
1372
1373         case SIOC_HCI_RAW_NODE_LIST_NAMES: {
1374                 struct ng_btsocket_hci_raw_node_list_names      *nl =
1375                         (struct ng_btsocket_hci_raw_node_list_names *) data;
1376                 struct nodeinfo                                 *ni = nl->names;
1377
1378                 if (nl->num_names == 0) {
1379                         error = EINVAL;
1380                         break;
1381                 }
1382
1383                 NG_MKMESSAGE(ngmsg, NGM_GENERIC_COOKIE, NGM_LISTNAMES,
1384                         0, M_WAITOK | M_NULLOK);
1385                 if (ngmsg == NULL) {
1386                         error = ENOMEM;
1387                         break;
1388                 }
1389                 ng_btsocket_hci_raw_get_token(&ngmsg->header.token);
1390                 pcb->token = ngmsg->header.token;
1391                 pcb->msg = NULL;
1392
1393                 NG_SEND_MSG_PATH(error, ng_btsocket_hci_raw_node, ngmsg, ".:", 0);
1394                 if (error != 0) {
1395                         pcb->token = 0;
1396                         break;
1397                 }
1398
1399                 error = lksleep(&pcb->msg, &pcb->pcb_lock,
1400                                 PCATCH, "hcictl",
1401                                 ng_btsocket_hci_raw_ioctl_timeout * hz);
1402                 pcb->token = 0;
1403
1404                 if (error != 0)
1405                         break;
1406
1407                 if (pcb->msg != NULL && pcb->msg->header.cmd == NGM_LISTNAMES) {
1408                         /* Return data back to user space */
1409                         struct namelist *nl1 = (struct namelist *) pcb->msg->data;
1410                         struct nodeinfo *ni1 = &nl1->nodeinfo[0];
1411
1412                         while (nl->num_names > 0 && nl1->numnames > 0) {
1413                                 if (strcmp(ni1->type, NG_HCI_NODE_TYPE) == 0) {
1414                                         error = copyout((caddr_t) ni1,
1415                                                         (caddr_t) ni,
1416                                                         sizeof(*ni));
1417                                         if (error != 0)
1418                                                 break;
1419
1420                                         nl->num_names --;
1421                                         ni ++;
1422                                 }
1423
1424                                 nl1->numnames --;
1425                                 ni1 ++;
1426                         }
1427
1428                         nl->num_names = ni - nl->names;
1429                 } else
1430                         error = EINVAL;
1431
1432                 NG_FREE_MSG(pcb->msg); /* checks for != NULL */
1433                 } break;
1434
1435         default:
1436                 error = EINVAL;
1437                 break;
1438         }
1439
1440         lockmgr(&pcb->pcb_lock, LK_RELEASE);
1441
1442 out:
1443         lwkt_replymsg(&msg->control.base.lmsg, error);
1444 } /* ng_btsocket_hci_raw_control */
1445
1446 /*
1447  * Process getsockopt/setsockopt system calls
1448  */
1449
1450 void
1451 ng_btsocket_hci_raw_ctloutput(netmsg_t msg)
1452 {
1453         struct socket                           *so = msg->ctloutput.base.nm_so;
1454         struct sockopt                          *sopt = msg->ctloutput.nm_sopt;
1455         ng_btsocket_hci_raw_pcb_p                pcb = so2hci_raw_pcb(so);
1456         struct ng_btsocket_hci_raw_filter        filter;
1457         int                                      error = 0, dir;
1458
1459         if (pcb == NULL) {
1460                 error = EINVAL;
1461                 goto out;
1462         }
1463         if (ng_btsocket_hci_raw_node == NULL) {
1464                 error = EINVAL;
1465                 goto out;
1466         }
1467
1468         if (sopt->sopt_level != SOL_HCI_RAW)
1469                 goto out;
1470
1471         lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
1472
1473         switch (sopt->sopt_dir) {
1474         case SOPT_GET:
1475                 switch (sopt->sopt_name) {
1476                 case SO_HCI_RAW_FILTER:
1477                         error = sooptcopyout(sopt, &pcb->filter,
1478                                                 sizeof(pcb->filter));
1479                         break;
1480
1481                 case SO_HCI_RAW_DIRECTION:
1482                         dir = (pcb->flags & NG_BTSOCKET_HCI_RAW_DIRECTION)?1:0;
1483                         error = sooptcopyout(sopt, &dir, sizeof(dir));
1484                         break;
1485
1486                 default:
1487                         error = EINVAL;
1488                         break;
1489                 }
1490                 break;
1491
1492         case SOPT_SET:
1493                 switch (sopt->sopt_name) {
1494                 case SO_HCI_RAW_FILTER:
1495                         error = sooptcopyin(sopt, &filter, sizeof(filter),
1496                                                 sizeof(filter));
1497                         if (error == 0)
1498                                 bcopy(&filter, &pcb->filter,
1499                                                 sizeof(pcb->filter));
1500                         break;
1501
1502                 case SO_HCI_RAW_DIRECTION:
1503                         error = sooptcopyin(sopt, &dir, sizeof(dir),
1504                                                 sizeof(dir));
1505                         if (error != 0)
1506                                 break;
1507
1508                         if (dir)
1509                                 pcb->flags |= NG_BTSOCKET_HCI_RAW_DIRECTION;
1510                         else
1511                                 pcb->flags &= ~NG_BTSOCKET_HCI_RAW_DIRECTION;
1512                         break;
1513
1514                 default:
1515                         error = EINVAL;
1516                         break;
1517                 }
1518                 break;
1519
1520         default:
1521                 error = EINVAL;
1522                 break;
1523         }
1524
1525         lockmgr(&pcb->pcb_lock, LK_RELEASE);
1526
1527 out:
1528         lwkt_replymsg(&msg->ctloutput.base.lmsg, error);
1529 } /* ng_btsocket_hci_raw_ctloutput */
1530
1531 /*
1532  * Detach raw HCI socket
1533  */
1534
1535 void
1536 ng_btsocket_hci_raw_detach(netmsg_t msg)
1537 {
1538         struct socket                   *so = msg->detach.base.nm_so;
1539         ng_btsocket_hci_raw_pcb_p        pcb = so2hci_raw_pcb(so);
1540         int                              error = 0;
1541
1542         KASSERT(pcb != NULL, ("ng_btsocket_hci_raw_detach: pcb == NULL"));
1543
1544         if (ng_btsocket_hci_raw_node == NULL)
1545                 goto out;
1546
1547         lockmgr(&ng_btsocket_hci_raw_sockets_lock, LK_EXCLUSIVE);
1548         lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
1549
1550         LIST_REMOVE(pcb, next);
1551
1552         lockmgr(&pcb->pcb_lock, LK_RELEASE);
1553         lockmgr(&ng_btsocket_hci_raw_sockets_lock, LK_RELEASE);
1554
1555         lockuninit(&pcb->pcb_lock);
1556
1557         bzero(pcb, sizeof(*pcb));
1558         kfree(pcb, M_NETGRAPH_BTSOCKET_HCI_RAW);
1559
1560         so->so_pcb = NULL;
1561
1562 out:
1563         lwkt_replymsg(&msg->detach.base.lmsg, error);
1564 } /* ng_btsocket_hci_raw_detach */
1565
1566 /*
1567  * Disconnect raw HCI socket
1568  */
1569
1570 void
1571 ng_btsocket_hci_raw_disconnect(netmsg_t msg)
1572 {
1573         struct socket                   *so = msg->disconnect.base.nm_so;
1574         ng_btsocket_hci_raw_pcb_p        pcb = so2hci_raw_pcb(so);
1575         int                              error = 0;
1576
1577         if (pcb == NULL) {
1578                 error = EINVAL;
1579                 goto out;
1580         }
1581         if (ng_btsocket_hci_raw_node == NULL) {
1582                 error = EINVAL;
1583                 goto out;
1584         }
1585
1586         lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
1587         soisdisconnected(so);
1588         lockmgr(&pcb->pcb_lock, LK_RELEASE);
1589
1590 out:
1591         lwkt_replymsg(&msg->disconnect.base.lmsg, error);
1592 } /* ng_btsocket_hci_raw_disconnect */
1593
1594 /*
1595  * Get socket peer's address
1596  */
1597
1598 void
1599 ng_btsocket_hci_raw_peeraddr(netmsg_t msg)
1600 {
1601         return (ng_btsocket_hci_raw_sockaddr(msg));
1602 } /* ng_btsocket_hci_raw_peeraddr */
1603
1604 /*
1605  * Send data
1606  */
1607
1608 void
1609 ng_btsocket_hci_raw_send(netmsg_t msg)
1610 {
1611         struct socket                   *so = msg->send.base.nm_so;
1612         struct mbuf                     *control = msg->send.nm_control;
1613         struct mbuf                     *m = msg->send.nm_m;
1614         struct sockaddr                 *sa = msg->send.nm_addr;
1615         ng_btsocket_hci_raw_pcb_p        pcb = so2hci_raw_pcb(so);
1616         struct mbuf                     *nam = NULL;
1617         int                              error = 0;
1618
1619         if (ng_btsocket_hci_raw_node == NULL) {
1620                 error = ENETDOWN;
1621                 goto drop;
1622         }
1623         if (pcb == NULL) {
1624                 error = EINVAL;
1625                 goto drop;
1626         }
1627         if (control != NULL) {
1628                 error = EINVAL;
1629                 goto drop;
1630         }
1631
1632         if (m->m_pkthdr.len < sizeof(ng_hci_cmd_pkt_t) ||
1633             m->m_pkthdr.len > sizeof(ng_hci_cmd_pkt_t) + NG_HCI_CMD_PKT_SIZE) {
1634                 error = EMSGSIZE;
1635                 goto drop;
1636         }
1637
1638         if (m->m_len < sizeof(ng_hci_cmd_pkt_t)) {
1639                 if ((m = m_pullup(m, sizeof(ng_hci_cmd_pkt_t))) == NULL) {
1640                         error = ENOBUFS;
1641                         goto drop;
1642                 }
1643         }
1644         if (*mtod(m, u_int8_t *) != NG_HCI_CMD_PKT) {
1645                 error = ENOTSUP;
1646                 goto drop;
1647         }
1648
1649         lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
1650
1651         error = ng_btsocket_hci_raw_filter(pcb, m, 0);
1652         if (error != 0) {
1653                 lockmgr(&pcb->pcb_lock, LK_RELEASE);
1654                 goto drop;
1655         }
1656
1657         if (sa == NULL) {
1658                 if (pcb->addr.hci_node[0] == 0) {
1659                         lockmgr(&pcb->pcb_lock, LK_RELEASE);
1660                         error = EDESTADDRREQ;
1661                         goto drop;
1662                 }
1663
1664                 sa = (struct sockaddr *) &pcb->addr;
1665         }
1666
1667         MGET(nam, M_NOWAIT, MT_SONAME);
1668         if (nam == NULL) {
1669                 lockmgr(&pcb->pcb_lock, LK_RELEASE);
1670                 error = ENOBUFS;
1671                 goto drop;
1672         }
1673
1674         nam->m_len = sizeof(struct sockaddr_hci);
1675         bcopy(sa,mtod(nam, struct sockaddr_hci *),sizeof(struct sockaddr_hci));
1676
1677         nam->m_next = m;
1678         m = NULL;
1679
1680         lockmgr(&pcb->pcb_lock, LK_RELEASE);
1681
1682         error = ng_send_fn(ng_btsocket_hci_raw_node, NULL,
1683                                 ng_btsocket_hci_raw_output, nam, 0);
1684         goto out;
1685
1686 drop:
1687         NG_FREE_M(control); /* NG_FREE_M checks for != NULL */
1688         NG_FREE_M(nam);
1689         NG_FREE_M(m);
1690
1691 out:
1692         lwkt_replymsg(&msg->send.base.lmsg, error);
1693 } /* ng_btsocket_hci_raw_send */
1694
1695 /*
1696  * Get socket address
1697  */
1698
1699 void
1700 ng_btsocket_hci_raw_sockaddr(netmsg_t msg)
1701 {
1702         struct socket                    *so = msg->sockaddr.base.nm_so;
1703         struct sockaddr                 **nam = msg->sockaddr.nm_nam;
1704         ng_btsocket_hci_raw_pcb_p         pcb = so2hci_raw_pcb(so);
1705         struct sockaddr_hci               sa;
1706         int                               error = 0;
1707
1708         if (pcb == NULL) {
1709                 error = EINVAL;
1710                 goto out;
1711         }
1712         if (ng_btsocket_hci_raw_node == NULL) {
1713                 error = EINVAL;
1714                 goto out;
1715         }
1716
1717         bzero(&sa, sizeof(sa));
1718         sa.hci_len = sizeof(sa);
1719         sa.hci_family = AF_BLUETOOTH;
1720
1721         lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE);
1722         strlcpy(sa.hci_node, pcb->addr.hci_node, sizeof(sa.hci_node));
1723         lockmgr(&pcb->pcb_lock, LK_RELEASE);
1724
1725         *nam = dup_sockaddr((struct sockaddr *) &sa);
1726
1727         if (*nam == NULL)
1728                 error = ENOMEM;
1729
1730 out:
1731         lwkt_replymsg(&msg->sockaddr.base.lmsg, error);
1732 } /* ng_btsocket_hci_raw_sockaddr */
1733