]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netgraph/bluetooth/socket/ng_btsocket_l2cap_raw.c
net: clean up empty lines in .c and .h files
[FreeBSD/FreeBSD.git] / sys / netgraph / bluetooth / socket / ng_btsocket_l2cap_raw.c
1 /*
2  * ng_btsocket_l2cap_raw.c
3  */
4
5 /*-
6  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
7  *
8  * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $Id: ng_btsocket_l2cap_raw.c,v 1.12 2003/09/14 23:29:06 max Exp $
33  * $FreeBSD$
34  */
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/bitstring.h>
39 #include <sys/domain.h>
40 #include <sys/errno.h>
41 #include <sys/filedesc.h>
42 #include <sys/ioccom.h>
43 #include <sys/kernel.h>
44 #include <sys/lock.h>
45 #include <sys/malloc.h>
46 #include <sys/mbuf.h>
47 #include <sys/mutex.h>
48 #include <sys/priv.h>
49 #include <sys/protosw.h>
50 #include <sys/queue.h>
51 #include <sys/socket.h>
52 #include <sys/socketvar.h>
53 #include <sys/sysctl.h>
54 #include <sys/taskqueue.h>
55
56 #include <net/vnet.h>
57
58 #include <netgraph/ng_message.h>
59 #include <netgraph/netgraph.h>
60 #include <netgraph/bluetooth/include/ng_bluetooth.h>
61 #include <netgraph/bluetooth/include/ng_hci.h>
62 #include <netgraph/bluetooth/include/ng_l2cap.h>
63 #include <netgraph/bluetooth/include/ng_btsocket.h>
64 #include <netgraph/bluetooth/include/ng_btsocket_l2cap.h>
65
66 /* MALLOC define */
67 #ifdef NG_SEPARATE_MALLOC
68 static MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_L2CAP_RAW,
69     "netgraph_btsocks_l2cap_raw", "Netgraph Bluetooth raw L2CAP sockets");
70 #else
71 #define M_NETGRAPH_BTSOCKET_L2CAP_RAW M_NETGRAPH
72 #endif /* NG_SEPARATE_MALLOC */
73
74 /* Netgraph node methods */
75 static ng_constructor_t ng_btsocket_l2cap_raw_node_constructor;
76 static ng_rcvmsg_t      ng_btsocket_l2cap_raw_node_rcvmsg;
77 static ng_shutdown_t    ng_btsocket_l2cap_raw_node_shutdown;
78 static ng_newhook_t     ng_btsocket_l2cap_raw_node_newhook;
79 static ng_connect_t     ng_btsocket_l2cap_raw_node_connect;
80 static ng_rcvdata_t     ng_btsocket_l2cap_raw_node_rcvdata;
81 static ng_disconnect_t  ng_btsocket_l2cap_raw_node_disconnect;
82
83 static void             ng_btsocket_l2cap_raw_input     (void *, int);
84 static void             ng_btsocket_l2cap_raw_rtclean   (void *, int);
85 static void             ng_btsocket_l2cap_raw_get_token (u_int32_t *);
86
87 static int              ng_btsocket_l2cap_raw_send_ngmsg
88                                 (hook_p, int, void *, int);
89 static int              ng_btsocket_l2cap_raw_send_sync_ngmsg
90                                 (ng_btsocket_l2cap_raw_pcb_p, int, void *, int);
91
92 #define ng_btsocket_l2cap_raw_wakeup_input_task() \
93         taskqueue_enqueue(taskqueue_swi, &ng_btsocket_l2cap_raw_queue_task)
94
95 #define ng_btsocket_l2cap_raw_wakeup_route_task() \
96         taskqueue_enqueue(taskqueue_swi, &ng_btsocket_l2cap_raw_rt_task)
97
98 /* Netgraph type descriptor */
99 static struct ng_type   typestruct = {
100         .version =      NG_ABI_VERSION,
101         .name =         NG_BTSOCKET_L2CAP_RAW_NODE_TYPE,
102         .constructor =  ng_btsocket_l2cap_raw_node_constructor,
103         .rcvmsg =       ng_btsocket_l2cap_raw_node_rcvmsg,
104         .shutdown =     ng_btsocket_l2cap_raw_node_shutdown,
105         .newhook =      ng_btsocket_l2cap_raw_node_newhook,
106         .connect =      ng_btsocket_l2cap_raw_node_connect,
107         .rcvdata =      ng_btsocket_l2cap_raw_node_rcvdata,
108         .disconnect =   ng_btsocket_l2cap_raw_node_disconnect,
109 };
110
111 /* Globals */
112 extern int                                      ifqmaxlen;
113 static u_int32_t                                ng_btsocket_l2cap_raw_debug_level;
114 static u_int32_t                                ng_btsocket_l2cap_raw_ioctl_timeout;
115 static node_p                                   ng_btsocket_l2cap_raw_node;
116 static struct ng_bt_itemq                       ng_btsocket_l2cap_raw_queue;
117 static struct mtx                               ng_btsocket_l2cap_raw_queue_mtx;
118 static struct task                              ng_btsocket_l2cap_raw_queue_task;
119 static LIST_HEAD(, ng_btsocket_l2cap_raw_pcb)   ng_btsocket_l2cap_raw_sockets;
120 static struct mtx                               ng_btsocket_l2cap_raw_sockets_mtx;
121 static u_int32_t                                ng_btsocket_l2cap_raw_token;
122 static struct mtx                               ng_btsocket_l2cap_raw_token_mtx;
123 static LIST_HEAD(, ng_btsocket_l2cap_rtentry)   ng_btsocket_l2cap_raw_rt;
124 static struct mtx                               ng_btsocket_l2cap_raw_rt_mtx;
125 static struct task                              ng_btsocket_l2cap_raw_rt_task;
126 static struct timeval                           ng_btsocket_l2cap_raw_lasttime;
127 static int                                      ng_btsocket_l2cap_raw_curpps;
128
129 /* Sysctl tree */
130 SYSCTL_DECL(_net_bluetooth_l2cap_sockets);
131 static SYSCTL_NODE(_net_bluetooth_l2cap_sockets, OID_AUTO, raw,
132     CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
133     "Bluetooth raw L2CAP sockets family");
134 SYSCTL_UINT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, debug_level,
135         CTLFLAG_RW,
136         &ng_btsocket_l2cap_raw_debug_level, NG_BTSOCKET_WARN_LEVEL,
137         "Bluetooth raw L2CAP sockets debug level");
138 SYSCTL_UINT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, ioctl_timeout,
139         CTLFLAG_RW,
140         &ng_btsocket_l2cap_raw_ioctl_timeout, 5,
141         "Bluetooth raw L2CAP sockets ioctl timeout");
142 SYSCTL_UINT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, queue_len,
143         CTLFLAG_RD,
144         &ng_btsocket_l2cap_raw_queue.len, 0,
145         "Bluetooth raw L2CAP sockets input queue length");
146 SYSCTL_UINT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, queue_maxlen,
147         CTLFLAG_RD,
148         &ng_btsocket_l2cap_raw_queue.maxlen, 0,
149         "Bluetooth raw L2CAP sockets input queue max. length");
150 SYSCTL_UINT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, queue_drops,
151         CTLFLAG_RD,
152         &ng_btsocket_l2cap_raw_queue.drops, 0,
153         "Bluetooth raw L2CAP sockets input queue drops");
154
155 /* Debug */
156 #define NG_BTSOCKET_L2CAP_RAW_INFO \
157         if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_INFO_LEVEL && \
158             ppsratecheck(&ng_btsocket_l2cap_raw_lasttime, &ng_btsocket_l2cap_raw_curpps, 1)) \
159                 printf
160
161 #define NG_BTSOCKET_L2CAP_RAW_WARN \
162         if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_WARN_LEVEL && \
163             ppsratecheck(&ng_btsocket_l2cap_raw_lasttime, &ng_btsocket_l2cap_raw_curpps, 1)) \
164                 printf
165
166 #define NG_BTSOCKET_L2CAP_RAW_ERR \
167         if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_ERR_LEVEL && \
168             ppsratecheck(&ng_btsocket_l2cap_raw_lasttime, &ng_btsocket_l2cap_raw_curpps, 1)) \
169                 printf
170
171 #define NG_BTSOCKET_L2CAP_RAW_ALERT \
172         if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_ALERT_LEVEL && \
173             ppsratecheck(&ng_btsocket_l2cap_raw_lasttime, &ng_btsocket_l2cap_raw_curpps, 1)) \
174                 printf
175
176 /*****************************************************************************
177  *****************************************************************************
178  **                        Netgraph node interface
179  *****************************************************************************
180  *****************************************************************************/
181
182 /*
183  * Netgraph node constructor. Do not allow to create node of this type.
184  */
185
186 static int
187 ng_btsocket_l2cap_raw_node_constructor(node_p node)
188 {
189         return (EINVAL);
190 } /* ng_btsocket_l2cap_raw_node_constructor */
191
192 /*
193  * Do local shutdown processing. Let old node go and create new fresh one.
194  */
195
196 static int
197 ng_btsocket_l2cap_raw_node_shutdown(node_p node)
198 {
199         int     error = 0;
200
201         NG_NODE_UNREF(node);
202
203         /* Create new node */
204         error = ng_make_node_common(&typestruct, &ng_btsocket_l2cap_raw_node);
205         if (error != 0) {
206                 NG_BTSOCKET_L2CAP_RAW_ALERT(
207 "%s: Could not create Netgraph node, error=%d\n", __func__, error);
208
209                 ng_btsocket_l2cap_raw_node = NULL;
210
211                 return (error);
212         }
213
214         error = ng_name_node(ng_btsocket_l2cap_raw_node,
215                                 NG_BTSOCKET_L2CAP_RAW_NODE_TYPE);
216         if (error != 0) {
217                 NG_BTSOCKET_L2CAP_RAW_ALERT(
218 "%s: Could not name Netgraph node, error=%d\n", __func__, error);
219
220                 NG_NODE_UNREF(ng_btsocket_l2cap_raw_node);
221                 ng_btsocket_l2cap_raw_node = NULL;
222
223                 return (error);
224         }
225                 
226         return (0);
227 } /* ng_btsocket_l2cap_raw_node_shutdown */
228
229 /*
230  * We allow any hook to be connected to the node.
231  */
232
233 static int
234 ng_btsocket_l2cap_raw_node_newhook(node_p node, hook_p hook, char const *name)
235 {
236         return (0);
237 } /* ng_btsocket_l2cap_raw_node_newhook */
238
239 /* 
240  * Just say "YEP, that's OK by me!"
241  */
242
243 static int
244 ng_btsocket_l2cap_raw_node_connect(hook_p hook)
245 {
246         NG_HOOK_SET_PRIVATE(hook, NULL);
247         NG_HOOK_REF(hook); /* Keep extra reference to the hook */
248
249         return (0);
250 } /* ng_btsocket_l2cap_raw_node_connect */
251
252 /*
253  * Hook disconnection. Schedule route cleanup task
254  */
255
256 static int
257 ng_btsocket_l2cap_raw_node_disconnect(hook_p hook)
258 {
259         /*
260          * If hook has private information than we must have this hook in
261          * the routing table and must schedule cleaning for the routing table.
262          * Otherwise hook was connected but we never got "hook_info" message,
263          * so we have never added this hook to the routing table and it save
264          * to just delete it.
265          */
266
267         if (NG_HOOK_PRIVATE(hook) != NULL)
268                 return (ng_btsocket_l2cap_raw_wakeup_route_task());
269
270         NG_HOOK_UNREF(hook); /* Remove extra reference */
271
272         return (0);
273 } /* ng_btsocket_l2cap_raw_node_disconnect */
274
275 /*
276  * Process incoming messages 
277  */
278
279 static int
280 ng_btsocket_l2cap_raw_node_rcvmsg(node_p node, item_p item, hook_p hook)
281 {
282         struct ng_mesg  *msg = NGI_MSG(item); /* item still has message */
283         int              error = 0;
284
285         if (msg != NULL && msg->header.typecookie == NGM_L2CAP_COOKIE) {
286                 /*
287                  * NGM_L2CAP_NODE_HOOK_INFO is special message initiated by
288                  * L2CAP layer. Ignore all other messages if they are not
289                  * replies or token is zero 
290                  */
291
292                 if (msg->header.cmd != NGM_L2CAP_NODE_HOOK_INFO) {
293                         if (msg->header.token == 0 ||
294                             !(msg->header.flags & NGF_RESP)) {
295                                 NG_FREE_ITEM(item);
296                                 return (0);
297                         }
298                 }
299
300                 mtx_lock(&ng_btsocket_l2cap_raw_queue_mtx);
301                 if (NG_BT_ITEMQ_FULL(&ng_btsocket_l2cap_raw_queue)) {
302                         NG_BTSOCKET_L2CAP_RAW_ERR(
303 "%s: Input queue is full\n", __func__);
304
305                         NG_BT_ITEMQ_DROP(&ng_btsocket_l2cap_raw_queue);
306                         NG_FREE_ITEM(item);
307                         error = ENOBUFS;
308                 } else {
309                         if (hook != NULL) {
310                                 NG_HOOK_REF(hook);
311                                 NGI_SET_HOOK(item, hook);
312                         }
313
314                         NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_l2cap_raw_queue, item);
315                         error = ng_btsocket_l2cap_raw_wakeup_input_task();
316                 }
317                 mtx_unlock(&ng_btsocket_l2cap_raw_queue_mtx);
318         } else {
319                 NG_FREE_ITEM(item);
320                 error = EINVAL;
321         }
322
323         return (error);
324 } /* ng_btsocket_l2cap_raw_node_rcvmsg */
325
326 /*
327  * Receive data on a hook
328  */
329
330 static int
331 ng_btsocket_l2cap_raw_node_rcvdata(hook_p hook, item_p item)
332 {
333         NG_FREE_ITEM(item);
334
335         return (EINVAL);
336 } /* ng_btsocket_l2cap_raw_node_rcvdata */
337
338 /*****************************************************************************
339  *****************************************************************************
340  **                              Socket interface
341  *****************************************************************************
342  *****************************************************************************/
343
344 /*
345  * L2CAP sockets input routine
346  */
347
348 static void
349 ng_btsocket_l2cap_raw_input(void *context, int pending)
350 {
351         item_p           item = NULL;
352         hook_p           hook = NULL;
353         struct ng_mesg  *msg = NULL;
354
355         for (;;) {
356                 mtx_lock(&ng_btsocket_l2cap_raw_queue_mtx);
357                 NG_BT_ITEMQ_DEQUEUE(&ng_btsocket_l2cap_raw_queue, item);
358                 mtx_unlock(&ng_btsocket_l2cap_raw_queue_mtx);
359
360                 if (item == NULL)
361                         break;
362
363                 KASSERT((item->el_flags & NGQF_TYPE) == NGQF_MESG,
364 ("%s: invalid item type=%ld\n", __func__, (item->el_flags & NGQF_TYPE)));
365
366                 NGI_GET_MSG(item, msg);
367                 NGI_GET_HOOK(item, hook);
368                 NG_FREE_ITEM(item);
369
370                 switch (msg->header.cmd) {
371                 case NGM_L2CAP_NODE_HOOK_INFO: {
372                         ng_btsocket_l2cap_rtentry_t     *rt = NULL;
373
374                         if (hook == NULL || NG_HOOK_NOT_VALID(hook) ||
375                             msg->header.arglen != sizeof(bdaddr_t))
376                                 break;
377
378                         if (bcmp(msg->data, NG_HCI_BDADDR_ANY,
379                                         sizeof(bdaddr_t)) == 0)
380                                 break;
381
382                         rt = (ng_btsocket_l2cap_rtentry_t *) 
383                                 NG_HOOK_PRIVATE(hook);
384                         if (rt == NULL) {
385                                 rt = malloc(sizeof(*rt),
386                                         M_NETGRAPH_BTSOCKET_L2CAP_RAW,
387                                         M_NOWAIT|M_ZERO);
388                                 if (rt == NULL)
389                                         break;
390
391                                 NG_HOOK_SET_PRIVATE(hook, rt);
392
393                                 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
394
395                                 LIST_INSERT_HEAD(&ng_btsocket_l2cap_raw_rt, 
396                                         rt, next);
397                         } else
398                                 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
399                 
400                         bcopy(msg->data, &rt->src, sizeof(rt->src));
401                         rt->hook = hook;
402
403                         NG_BTSOCKET_L2CAP_RAW_INFO(
404 "%s: Updating hook \"%s\", src bdaddr=%x:%x:%x:%x:%x:%x\n",
405                                 __func__, NG_HOOK_NAME(hook), 
406                                 rt->src.b[5], rt->src.b[4], rt->src.b[3],
407                                 rt->src.b[2], rt->src.b[1], rt->src.b[0]);
408
409                         mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);
410                         } break;
411
412                 case NGM_L2CAP_NODE_GET_FLAGS:
413                 case NGM_L2CAP_NODE_GET_DEBUG:
414                 case NGM_L2CAP_NODE_GET_CON_LIST:
415                 case NGM_L2CAP_NODE_GET_CHAN_LIST:
416                 case NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO:
417                 case NGM_L2CAP_L2CA_PING:
418                 case NGM_L2CAP_L2CA_GET_INFO: {
419                         ng_btsocket_l2cap_raw_pcb_p     pcb = NULL;
420
421                         mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);
422
423                         LIST_FOREACH(pcb,&ng_btsocket_l2cap_raw_sockets,next) {
424                                 mtx_lock(&pcb->pcb_mtx);
425
426                                 if (pcb->token == msg->header.token) {
427                                         pcb->msg = msg;
428                                         msg = NULL;
429                                         wakeup(&pcb->msg);
430                                         mtx_unlock(&pcb->pcb_mtx);
431                                         break;
432                                 }
433
434                                 mtx_unlock(&pcb->pcb_mtx);
435                         }
436
437                         mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);
438                         } break;
439
440                 default:
441                         NG_BTSOCKET_L2CAP_RAW_WARN(
442 "%s: Unknown message, cmd=%d\n", __func__, msg->header.cmd);
443                         break;
444                 }
445
446                 if (hook != NULL)
447                         NG_HOOK_UNREF(hook); /* remove extra reference */
448
449                 NG_FREE_MSG(msg); /* Checks for msg != NULL */
450         }
451 } /* ng_btsocket_l2cap_raw_input */
452
453 /*
454  * Route cleanup task. Gets scheduled when hook is disconnected. Here we 
455  * will find all sockets that use "invalid" hook and disconnect them.
456  */
457
458 static void
459 ng_btsocket_l2cap_raw_rtclean(void *context, int pending)
460 {
461         ng_btsocket_l2cap_raw_pcb_p     pcb = NULL;
462         ng_btsocket_l2cap_rtentry_p     rt = NULL;
463
464         /*
465          * First disconnect all sockets that use "invalid" hook
466          */
467
468         mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);
469
470         LIST_FOREACH(pcb, &ng_btsocket_l2cap_raw_sockets, next) {
471                 mtx_lock(&pcb->pcb_mtx);
472
473                 if (pcb->rt != NULL &&
474                     pcb->rt->hook != NULL && NG_HOOK_NOT_VALID(pcb->rt->hook)) {
475                         if (pcb->so != NULL &&
476                             pcb->so->so_state & SS_ISCONNECTED)
477                                 soisdisconnected(pcb->so);
478
479                         pcb->rt = NULL;
480                 }
481
482                 mtx_unlock(&pcb->pcb_mtx);
483         }
484
485         mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);
486
487         /*
488          * Now cleanup routing table
489          */
490
491         mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
492
493         for (rt = LIST_FIRST(&ng_btsocket_l2cap_raw_rt); rt != NULL; ) {
494                 ng_btsocket_l2cap_rtentry_p     rt_next = LIST_NEXT(rt, next);
495
496                 if (rt->hook != NULL && NG_HOOK_NOT_VALID(rt->hook)) {
497                         LIST_REMOVE(rt, next);
498
499                         NG_HOOK_SET_PRIVATE(rt->hook, NULL);
500                         NG_HOOK_UNREF(rt->hook); /* Remove extra reference */
501
502                         bzero(rt, sizeof(*rt));
503                         free(rt, M_NETGRAPH_BTSOCKET_L2CAP_RAW);
504                 }
505
506                 rt = rt_next;
507         }
508
509         mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);
510 } /* ng_btsocket_l2cap_raw_rtclean */
511
512 /*
513  * Initialize everything
514  */
515
516 void
517 ng_btsocket_l2cap_raw_init(void)
518 {
519         int     error = 0;
520
521         /* Skip initialization of globals for non-default instances. */
522         if (!IS_DEFAULT_VNET(curvnet))
523                 return;
524
525         ng_btsocket_l2cap_raw_node = NULL;
526         ng_btsocket_l2cap_raw_debug_level = NG_BTSOCKET_WARN_LEVEL;
527         ng_btsocket_l2cap_raw_ioctl_timeout = 5;
528
529         /* Register Netgraph node type */
530         error = ng_newtype(&typestruct);
531         if (error != 0) {
532                 NG_BTSOCKET_L2CAP_RAW_ALERT(
533 "%s: Could not register Netgraph node type, error=%d\n", __func__, error);
534
535                 return;
536         }
537
538         /* Create Netgrapg node */
539         error = ng_make_node_common(&typestruct, &ng_btsocket_l2cap_raw_node);
540         if (error != 0) {
541                 NG_BTSOCKET_L2CAP_RAW_ALERT(
542 "%s: Could not create Netgraph node, error=%d\n", __func__, error);
543
544                 ng_btsocket_l2cap_raw_node = NULL;
545
546                 return;
547         }
548
549         error = ng_name_node(ng_btsocket_l2cap_raw_node,
550                                 NG_BTSOCKET_L2CAP_RAW_NODE_TYPE);
551         if (error != 0) {
552                 NG_BTSOCKET_L2CAP_RAW_ALERT(
553 "%s: Could not name Netgraph node, error=%d\n", __func__, error);
554
555                 NG_NODE_UNREF(ng_btsocket_l2cap_raw_node);
556                 ng_btsocket_l2cap_raw_node = NULL;
557
558                 return;
559         }
560
561         /* Create input queue */
562         NG_BT_ITEMQ_INIT(&ng_btsocket_l2cap_raw_queue, ifqmaxlen);
563         mtx_init(&ng_btsocket_l2cap_raw_queue_mtx,
564                 "btsocks_l2cap_raw_queue_mtx", NULL, MTX_DEF);
565         TASK_INIT(&ng_btsocket_l2cap_raw_queue_task, 0,
566                 ng_btsocket_l2cap_raw_input, NULL);
567
568         /* Create list of sockets */
569         LIST_INIT(&ng_btsocket_l2cap_raw_sockets);
570         mtx_init(&ng_btsocket_l2cap_raw_sockets_mtx,
571                 "btsocks_l2cap_raw_sockets_mtx", NULL, MTX_DEF);
572
573         /* Tokens */
574         ng_btsocket_l2cap_raw_token = 0;
575         mtx_init(&ng_btsocket_l2cap_raw_token_mtx,
576                 "btsocks_l2cap_raw_token_mtx", NULL, MTX_DEF);
577
578         /* Routing table */
579         LIST_INIT(&ng_btsocket_l2cap_raw_rt);
580         mtx_init(&ng_btsocket_l2cap_raw_rt_mtx,
581                 "btsocks_l2cap_raw_rt_mtx", NULL, MTX_DEF);
582         TASK_INIT(&ng_btsocket_l2cap_raw_rt_task, 0,
583                 ng_btsocket_l2cap_raw_rtclean, NULL);
584 } /* ng_btsocket_l2cap_raw_init */
585
586 /*
587  * Abort connection on socket
588  */
589
590 void
591 ng_btsocket_l2cap_raw_abort(struct socket *so)
592 {
593
594         (void)ng_btsocket_l2cap_raw_disconnect(so);
595 } /* ng_btsocket_l2cap_raw_abort */
596
597 void
598 ng_btsocket_l2cap_raw_close(struct socket *so)
599 {
600
601         (void)ng_btsocket_l2cap_raw_disconnect(so);
602 } /* ng_btsocket_l2cap_raw_close */
603
604 /*
605  * Create and attach new socket
606  */
607
608 int
609 ng_btsocket_l2cap_raw_attach(struct socket *so, int proto, struct thread *td)
610 {
611         ng_btsocket_l2cap_raw_pcb_p     pcb = so2l2cap_raw_pcb(so);
612         int                             error;
613
614         if (pcb != NULL)
615                 return (EISCONN);
616
617         if (ng_btsocket_l2cap_raw_node == NULL) 
618                 return (EPROTONOSUPPORT);
619         if (so->so_type != SOCK_RAW)
620                 return (ESOCKTNOSUPPORT);
621
622         /* Reserve send and receive space if it is not reserved yet */
623         error = soreserve(so, NG_BTSOCKET_L2CAP_RAW_SENDSPACE,
624                         NG_BTSOCKET_L2CAP_RAW_RECVSPACE);
625         if (error != 0)
626                 return (error);
627
628         /* Allocate the PCB */
629         pcb = malloc(sizeof(*pcb),
630                 M_NETGRAPH_BTSOCKET_L2CAP_RAW, M_NOWAIT|M_ZERO);
631         if (pcb == NULL)
632                 return (ENOMEM);
633
634         /* Link the PCB and the socket */
635         so->so_pcb = (caddr_t) pcb;
636         pcb->so = so;
637
638         if (priv_check(td, PRIV_NETBLUETOOTH_RAW) == 0)
639                 pcb->flags |= NG_BTSOCKET_L2CAP_RAW_PRIVILEGED;
640
641         mtx_init(&pcb->pcb_mtx, "btsocks_l2cap_raw_pcb_mtx", NULL, MTX_DEF);
642
643         /* Add the PCB to the list */
644         mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);
645         LIST_INSERT_HEAD(&ng_btsocket_l2cap_raw_sockets, pcb, next);
646         mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);
647
648         return (0);
649 } /* ng_btsocket_l2cap_raw_attach */
650
651 /*
652  * Bind socket
653  */
654
655 int
656 ng_btsocket_l2cap_raw_bind(struct socket *so, struct sockaddr *nam, 
657                 struct thread *td)
658 {
659         ng_btsocket_l2cap_raw_pcb_t     *pcb = so2l2cap_raw_pcb(so);
660         struct sockaddr_l2cap           *sa = (struct sockaddr_l2cap *) nam;
661         ng_btsocket_l2cap_rtentry_t     *rt = NULL;
662
663         if (pcb == NULL)
664                 return (EINVAL);
665         if (ng_btsocket_l2cap_raw_node == NULL) 
666                 return (EINVAL);
667
668         if (sa == NULL)
669                 return (EINVAL);
670         if (sa->l2cap_family != AF_BLUETOOTH)
671                 return (EAFNOSUPPORT);
672         if((sa->l2cap_len != sizeof(*sa))&&
673            (sa->l2cap_len != sizeof(struct sockaddr_l2cap_compat)))
674                 return (EINVAL);
675
676         if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY,
677                                 sizeof(sa->l2cap_bdaddr)) != 0) {
678                 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
679
680                 LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) {
681                         if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
682                                 continue;
683
684                         if (bcmp(&sa->l2cap_bdaddr, &rt->src,
685                                         sizeof(rt->src)) == 0)
686                                 break;
687                 }
688
689                 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);
690
691                 if (rt == NULL)
692                         return (ENETDOWN);
693         } else
694                 rt = NULL;
695
696         mtx_lock(&pcb->pcb_mtx);
697         bcopy(&sa->l2cap_bdaddr, &pcb->src, sizeof(pcb->src));
698         pcb->rt = rt;
699         mtx_unlock(&pcb->pcb_mtx);
700
701         return (0);
702 } /* ng_btsocket_l2cap_raw_bind */
703
704 /*
705  * Connect socket
706  */
707
708 int
709 ng_btsocket_l2cap_raw_connect(struct socket *so, struct sockaddr *nam, 
710                 struct thread *td)
711 {
712         ng_btsocket_l2cap_raw_pcb_t     *pcb = so2l2cap_raw_pcb(so);
713         struct sockaddr_l2cap           *sa = (struct sockaddr_l2cap *) nam;
714         ng_btsocket_l2cap_rtentry_t     *rt = NULL;
715         int                              error;
716
717         if (pcb == NULL)
718                 return (EINVAL);
719         if (ng_btsocket_l2cap_raw_node == NULL) 
720                 return (EINVAL);
721
722         if (sa == NULL)
723                 return (EINVAL);
724         if (sa->l2cap_family != AF_BLUETOOTH)
725                 return (EAFNOSUPPORT);
726         if((sa->l2cap_len != sizeof(*sa))&&
727            (sa->l2cap_len != sizeof(struct sockaddr_l2cap_compat)))
728                 return (EINVAL);
729
730         if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
731                 return (EINVAL);
732
733         mtx_lock(&pcb->pcb_mtx);
734
735         bcopy(&sa->l2cap_bdaddr, &pcb->dst, sizeof(pcb->dst));
736
737         if (bcmp(&pcb->src, &pcb->dst, sizeof(pcb->src)) == 0) {
738                 mtx_unlock(&pcb->pcb_mtx);
739
740                 return (EADDRNOTAVAIL);
741         }
742
743         /*
744          * If there is route already - use it
745          */
746
747         if (pcb->rt != NULL) {
748                 soisconnected(so);
749                 mtx_unlock(&pcb->pcb_mtx);
750
751                 return (0);
752         }
753
754         /*
755          * Find the first hook that does not match specified destination address
756          */
757
758         mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
759
760         LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) {
761                 if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
762                         continue;
763
764                 if (bcmp(&pcb->dst, &rt->src, sizeof(rt->src)) != 0)
765                         break;
766         }
767
768         if (rt != NULL) {
769                 soisconnected(so);
770
771                 pcb->rt = rt;
772                 bcopy(&rt->src, &pcb->src, sizeof(pcb->src));
773
774                 error = 0;
775         } else
776                 error = ENETDOWN;
777
778         mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);
779         mtx_unlock(&pcb->pcb_mtx);
780
781         return  (error);
782 } /* ng_btsocket_l2cap_raw_connect */
783
784 /*
785  * Process ioctl's calls on socket
786  */
787
788 int
789 ng_btsocket_l2cap_raw_control(struct socket *so, u_long cmd, caddr_t data,
790                 struct ifnet *ifp, struct thread *td)
791 {
792         ng_btsocket_l2cap_raw_pcb_p      pcb = so2l2cap_raw_pcb(so);
793         struct ng_mesg                  *msg = NULL;
794         int                              error = 0;
795
796         if (pcb == NULL)
797                 return (EINVAL);
798         if (ng_btsocket_l2cap_raw_node == NULL)
799                 return (EINVAL);
800
801         mtx_lock(&pcb->pcb_mtx);
802
803         /* Check if we route info */
804         if (pcb->rt == NULL) {
805                 mtx_unlock(&pcb->pcb_mtx);
806                 return (EHOSTUNREACH);
807         }
808
809         /* Check if we have pending ioctl() */
810         if (pcb->token != 0) {
811                 mtx_unlock(&pcb->pcb_mtx);
812                 return (EBUSY);
813         }  
814
815         switch (cmd) {
816         case SIOC_L2CAP_NODE_GET_FLAGS: {
817                 struct ng_btsocket_l2cap_raw_node_flags *p =
818                         (struct ng_btsocket_l2cap_raw_node_flags *) data;
819
820                 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,
821                                 NGM_L2CAP_NODE_GET_FLAGS,
822                                 &p->flags, sizeof(p->flags));
823                 } break;
824
825         case SIOC_L2CAP_NODE_GET_DEBUG: {
826                 struct ng_btsocket_l2cap_raw_node_debug *p =
827                         (struct ng_btsocket_l2cap_raw_node_debug *) data;
828
829                 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,
830                                 NGM_L2CAP_NODE_GET_DEBUG,
831                                 &p->debug, sizeof(p->debug));
832                 } break;
833
834         case SIOC_L2CAP_NODE_SET_DEBUG: {
835                 struct ng_btsocket_l2cap_raw_node_debug *p = 
836                         (struct ng_btsocket_l2cap_raw_node_debug *) data;
837
838                 if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)
839                         error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook,
840                                         NGM_L2CAP_NODE_SET_DEBUG,
841                                         &p->debug, sizeof(p->debug));
842                 else
843                         error = EPERM;
844                 } break;
845
846         case SIOC_L2CAP_NODE_GET_CON_LIST: {
847                 struct ng_btsocket_l2cap_raw_con_list   *p =
848                         (struct ng_btsocket_l2cap_raw_con_list *) data;
849                 ng_l2cap_node_con_list_ep               *p1 = NULL;
850                 ng_l2cap_node_con_ep                    *p2 = NULL;
851
852                 if (p->num_connections == 0 ||
853                     p->num_connections > NG_L2CAP_MAX_CON_NUM ||
854                     p->connections == NULL) {
855                         mtx_unlock(&pcb->pcb_mtx);
856                         return (EINVAL);
857                 }
858
859                 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_NODE_GET_CON_LIST,
860                         0, M_NOWAIT);
861                 if (msg == NULL) {
862                         mtx_unlock(&pcb->pcb_mtx);
863                         return (ENOMEM);
864                 }
865                 ng_btsocket_l2cap_raw_get_token(&msg->header.token);
866                 pcb->token = msg->header.token;
867                 pcb->msg = NULL;
868
869                 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
870                         pcb->rt->hook, 0);
871                 if (error != 0) {
872                         pcb->token = 0;
873                         mtx_unlock(&pcb->pcb_mtx);
874                         return (error);
875                 }
876
877                 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
878                                 ng_btsocket_l2cap_raw_ioctl_timeout * hz);
879                 pcb->token = 0;
880
881                 if (error != 0) {
882                         mtx_unlock(&pcb->pcb_mtx);
883                         return (error);
884                 }
885
886                 msg = pcb->msg;
887                 pcb->msg = NULL;
888
889                 mtx_unlock(&pcb->pcb_mtx);
890
891                 if (msg != NULL &&
892                     msg->header.cmd == NGM_L2CAP_NODE_GET_CON_LIST) {
893                         /* Return data back to user space */
894                         p1 = (ng_l2cap_node_con_list_ep *)(msg->data);
895                         p2 = (ng_l2cap_node_con_ep *)(p1 + 1);
896
897                         p->num_connections = min(p->num_connections,
898                                                 p1->num_connections);
899                         if (p->num_connections > 0)
900                                 error = copyout((caddr_t) p2, 
901                                         (caddr_t) p->connections,
902                                         p->num_connections * sizeof(*p2));
903                 } else
904                         error = EINVAL;
905
906                 NG_FREE_MSG(msg); /* checks for != NULL */
907                 return (error);
908                 } /* NOTREACHED */
909
910         case SIOC_L2CAP_NODE_GET_CHAN_LIST: {
911                 struct ng_btsocket_l2cap_raw_chan_list  *p =
912                         (struct ng_btsocket_l2cap_raw_chan_list *) data;
913                 ng_l2cap_node_chan_list_ep              *p1 = NULL;
914                 ng_l2cap_node_chan_ep                   *p2 = NULL;
915
916                 if (p->num_channels == 0 ||
917                     p->num_channels > NG_L2CAP_MAX_CHAN_NUM ||
918                     p->channels == NULL) {
919                         mtx_unlock(&pcb->pcb_mtx);
920                         return (EINVAL);
921                 }
922
923                 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE,
924                         NGM_L2CAP_NODE_GET_CHAN_LIST, 0, M_NOWAIT);
925                 if (msg == NULL) {
926                         mtx_unlock(&pcb->pcb_mtx);
927                         return (ENOMEM);
928                 }
929                 ng_btsocket_l2cap_raw_get_token(&msg->header.token);
930                 pcb->token = msg->header.token;
931                 pcb->msg = NULL;
932
933                 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
934                         pcb->rt->hook, 0);
935                 if (error != 0) {
936                         pcb->token = 0;
937                         mtx_unlock(&pcb->pcb_mtx);
938                         return (error);
939                 }
940
941                 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
942                                 ng_btsocket_l2cap_raw_ioctl_timeout * hz);
943                 pcb->token = 0;
944
945                 if (error != 0) {
946                         mtx_unlock(&pcb->pcb_mtx);
947                         return (error);
948                 }
949
950                 msg = pcb->msg;
951                 pcb->msg = NULL;
952
953                 mtx_unlock(&pcb->pcb_mtx);
954
955                 if (msg != NULL &&
956                     msg->header.cmd == NGM_L2CAP_NODE_GET_CHAN_LIST) {
957                         /* Return data back to user space */
958                         p1 = (ng_l2cap_node_chan_list_ep *)(msg->data);
959                         p2 = (ng_l2cap_node_chan_ep *)(p1 + 1);
960
961                         p->num_channels = min(p->num_channels, 
962                                                 p1->num_channels);
963                         if (p->num_channels > 0)
964                                 error = copyout((caddr_t) p2, 
965                                                 (caddr_t) p->channels,
966                                                 p->num_channels * sizeof(*p2));
967                 } else
968                         error = EINVAL;
969
970                 NG_FREE_MSG(msg); /* checks for != NULL */
971                 return (error);
972                 } /* NOTREACHED */
973
974         case SIOC_L2CAP_L2CA_PING: {
975                 struct ng_btsocket_l2cap_raw_ping       *p = 
976                         (struct ng_btsocket_l2cap_raw_ping *) data;
977                 ng_l2cap_l2ca_ping_ip                   *ip = NULL;
978                 ng_l2cap_l2ca_ping_op                   *op = NULL;
979
980                 if ((p->echo_size != 0 && p->echo_data == NULL) ||
981                      p->echo_size > NG_L2CAP_MAX_ECHO_SIZE) {
982                         mtx_unlock(&pcb->pcb_mtx);
983                         return (EINVAL);
984                 }
985
986                 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE,
987                         NGM_L2CAP_L2CA_PING, sizeof(*ip) + p->echo_size,
988                         M_NOWAIT);
989                 if (msg == NULL) {
990                         mtx_unlock(&pcb->pcb_mtx);
991                         return (ENOMEM);
992                 }
993                 ng_btsocket_l2cap_raw_get_token(&msg->header.token);
994                 pcb->token = msg->header.token;
995                 pcb->msg = NULL;
996
997                 ip = (ng_l2cap_l2ca_ping_ip *)(msg->data);
998                 bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr));
999                 ip->echo_size = p->echo_size;
1000
1001                 if (ip->echo_size > 0) {
1002                         mtx_unlock(&pcb->pcb_mtx);
1003                         error = copyin(p->echo_data, ip + 1, p->echo_size);
1004                         mtx_lock(&pcb->pcb_mtx);
1005
1006                         if (error != 0) {
1007                                 NG_FREE_MSG(msg);
1008                                 pcb->token = 0;
1009                                 mtx_unlock(&pcb->pcb_mtx);
1010                                 return (error);
1011                         }
1012                 }
1013
1014                 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
1015                         pcb->rt->hook, 0);
1016                 if (error != 0) {
1017                         pcb->token = 0;
1018                         mtx_unlock(&pcb->pcb_mtx);
1019                         return (error);
1020                 }
1021
1022                 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
1023                                 bluetooth_l2cap_rtx_timeout());
1024                 pcb->token = 0;
1025
1026                 if (error != 0) {
1027                         mtx_unlock(&pcb->pcb_mtx);
1028                         return (error);
1029                 }
1030
1031                 msg = pcb->msg;
1032                 pcb->msg = NULL;
1033
1034                 mtx_unlock(&pcb->pcb_mtx);
1035
1036                 if (msg != NULL &&
1037                     msg->header.cmd == NGM_L2CAP_L2CA_PING) {
1038                         /* Return data back to the user space */
1039                         op = (ng_l2cap_l2ca_ping_op *)(msg->data);
1040                         p->result = op->result;
1041                         p->echo_size = min(p->echo_size, op->echo_size);
1042
1043                         if (p->echo_size > 0)
1044                                 error = copyout(op + 1, p->echo_data, 
1045                                                 p->echo_size);
1046                 } else
1047                         error = EINVAL;
1048
1049                 NG_FREE_MSG(msg); /* checks for != NULL */
1050                 return (error);
1051                 } /* NOTREACHED */
1052
1053         case SIOC_L2CAP_L2CA_GET_INFO: {
1054                 struct ng_btsocket_l2cap_raw_get_info   *p = 
1055                         (struct ng_btsocket_l2cap_raw_get_info *) data;
1056                 ng_l2cap_l2ca_get_info_ip               *ip = NULL;
1057                 ng_l2cap_l2ca_get_info_op               *op = NULL;
1058
1059                 if (!(pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)) {
1060                         mtx_unlock(&pcb->pcb_mtx);
1061                         return (EPERM);
1062                 }
1063
1064                 if (p->info_size != 0 && p->info_data == NULL) {
1065                         mtx_unlock(&pcb->pcb_mtx);
1066                         return (EINVAL);
1067                 }
1068
1069                 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE,
1070                         NGM_L2CAP_L2CA_GET_INFO, sizeof(*ip) + p->info_size,
1071                         M_NOWAIT);
1072                 if (msg == NULL) {
1073                         mtx_unlock(&pcb->pcb_mtx);
1074                         return (ENOMEM);
1075                 }
1076                 ng_btsocket_l2cap_raw_get_token(&msg->header.token);
1077                 pcb->token = msg->header.token;
1078                 pcb->msg = NULL;
1079
1080                 ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data);
1081                 bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr));
1082                 ip->info_type = p->info_type;
1083
1084                 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
1085                         pcb->rt->hook, 0);
1086                 if (error != 0) {
1087                         pcb->token = 0;
1088                         mtx_unlock(&pcb->pcb_mtx);
1089                         return (error);
1090                 }
1091
1092                 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
1093                                 bluetooth_l2cap_rtx_timeout());
1094                 pcb->token = 0;
1095
1096                 if (error != 0) {
1097                         mtx_unlock(&pcb->pcb_mtx);
1098                         return (error);
1099                 }
1100
1101                 msg = pcb->msg;
1102                 pcb->msg = NULL;
1103
1104                 mtx_unlock(&pcb->pcb_mtx);
1105
1106                 if (msg != NULL &&
1107                     msg->header.cmd == NGM_L2CAP_L2CA_GET_INFO) {
1108                         /* Return data back to the user space */
1109                         op = (ng_l2cap_l2ca_get_info_op *)(msg->data);
1110                         p->result = op->result;
1111                         p->info_size = min(p->info_size, op->info_size);
1112
1113                         if (p->info_size > 0)
1114                                 error = copyout(op + 1, p->info_data, 
1115                                                 p->info_size);
1116                 } else
1117                         error = EINVAL;
1118
1119                 NG_FREE_MSG(msg); /* checks for != NULL */
1120                 return (error);
1121                 } /* NOTREACHED */
1122
1123         case SIOC_L2CAP_NODE_GET_AUTO_DISCON_TIMO: {
1124                 struct ng_btsocket_l2cap_raw_auto_discon_timo   *p =
1125                         (struct ng_btsocket_l2cap_raw_auto_discon_timo *) data;
1126
1127                 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,
1128                                 NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO,
1129                                 &p->timeout, sizeof(p->timeout));
1130                 } break;
1131
1132         case SIOC_L2CAP_NODE_SET_AUTO_DISCON_TIMO: {
1133                 struct ng_btsocket_l2cap_raw_auto_discon_timo   *p =
1134                         (struct ng_btsocket_l2cap_raw_auto_discon_timo *) data;
1135
1136                 if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)
1137                         error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook,
1138                                         NGM_L2CAP_NODE_SET_AUTO_DISCON_TIMO,
1139                                         &p->timeout, sizeof(p->timeout));
1140                 else
1141                         error = EPERM;
1142                 } break;
1143
1144         default:
1145                 error = EINVAL;
1146                 break;
1147         }
1148
1149         mtx_unlock(&pcb->pcb_mtx);
1150
1151         return (error);
1152 } /* ng_btsocket_l2cap_raw_control */
1153
1154 /*
1155  * Detach and destroy socket
1156  */
1157
1158 void
1159 ng_btsocket_l2cap_raw_detach(struct socket *so)
1160 {
1161         ng_btsocket_l2cap_raw_pcb_p     pcb = so2l2cap_raw_pcb(so);
1162
1163         KASSERT(pcb != NULL, ("nt_btsocket_l2cap_raw_detach: pcb == NULL"));
1164         if (ng_btsocket_l2cap_raw_node == NULL) 
1165                 return;
1166
1167         mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);
1168         mtx_lock(&pcb->pcb_mtx);
1169
1170         LIST_REMOVE(pcb, next);
1171
1172         mtx_unlock(&pcb->pcb_mtx);
1173         mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);
1174
1175         mtx_destroy(&pcb->pcb_mtx);
1176
1177         bzero(pcb, sizeof(*pcb));
1178         free(pcb, M_NETGRAPH_BTSOCKET_L2CAP_RAW);
1179
1180         so->so_pcb = NULL;
1181 } /* ng_btsocket_l2cap_raw_detach */
1182
1183 /*
1184  * Disconnect socket
1185  */
1186
1187 int
1188 ng_btsocket_l2cap_raw_disconnect(struct socket *so)
1189 {
1190         ng_btsocket_l2cap_raw_pcb_p     pcb = so2l2cap_raw_pcb(so);
1191
1192         if (pcb == NULL)
1193                 return (EINVAL);
1194         if (ng_btsocket_l2cap_raw_node == NULL)
1195                 return (EINVAL);
1196
1197         mtx_lock(&pcb->pcb_mtx);
1198         pcb->rt = NULL;
1199         soisdisconnected(so);
1200         mtx_unlock(&pcb->pcb_mtx);
1201
1202         return (0);
1203 } /* ng_btsocket_l2cap_raw_disconnect */
1204
1205 /*
1206  * Get peer address
1207  */
1208
1209 int
1210 ng_btsocket_l2cap_raw_peeraddr(struct socket *so, struct sockaddr **nam)
1211 {
1212         ng_btsocket_l2cap_raw_pcb_p     pcb = so2l2cap_raw_pcb(so);
1213         struct sockaddr_l2cap           sa;
1214
1215         if (pcb == NULL)
1216                 return (EINVAL);
1217         if (ng_btsocket_l2cap_raw_node == NULL) 
1218                 return (EINVAL);
1219
1220         mtx_lock(&pcb->pcb_mtx);
1221         bcopy(&pcb->dst, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr));
1222         mtx_unlock(&pcb->pcb_mtx);
1223
1224         sa.l2cap_psm = 0;
1225         sa.l2cap_len = sizeof(sa);
1226         sa.l2cap_family = AF_BLUETOOTH;
1227         sa.l2cap_cid = 0;
1228         sa.l2cap_bdaddr_type = BDADDR_BREDR;
1229
1230         *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT);
1231
1232         return ((*nam == NULL)? ENOMEM : 0);
1233 } /* ng_btsocket_l2cap_raw_peeraddr */
1234
1235 /*
1236  * Send data to socket
1237  */
1238
1239 int
1240 ng_btsocket_l2cap_raw_send(struct socket *so, int flags, struct mbuf *m,
1241                 struct sockaddr *nam, struct mbuf *control, struct thread *td)
1242 {
1243         NG_FREE_M(m); /* Checks for m != NULL */
1244         NG_FREE_M(control);
1245
1246         return (EOPNOTSUPP);
1247 } /* ng_btsocket_l2cap_raw_send */
1248
1249 /*
1250  * Get socket address
1251  */
1252
1253 int
1254 ng_btsocket_l2cap_raw_sockaddr(struct socket *so, struct sockaddr **nam)
1255 {
1256         ng_btsocket_l2cap_raw_pcb_p     pcb = so2l2cap_raw_pcb(so);
1257         struct sockaddr_l2cap           sa;
1258
1259         if (pcb == NULL)
1260                 return (EINVAL);
1261         if (ng_btsocket_l2cap_raw_node == NULL) 
1262                 return (EINVAL);
1263
1264         mtx_lock(&pcb->pcb_mtx);
1265         bcopy(&pcb->src, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr));
1266         mtx_unlock(&pcb->pcb_mtx);
1267
1268         sa.l2cap_psm = 0;
1269         sa.l2cap_len = sizeof(sa);
1270         sa.l2cap_family = AF_BLUETOOTH;
1271         sa.l2cap_cid = 0;
1272         sa.l2cap_bdaddr_type = BDADDR_BREDR;
1273         *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT);
1274
1275         return ((*nam == NULL)? ENOMEM : 0);
1276 } /* ng_btsocket_l2cap_raw_sockaddr */
1277
1278 /*
1279  * Get next token
1280  */
1281
1282 static void
1283 ng_btsocket_l2cap_raw_get_token(u_int32_t *token)
1284 {
1285         mtx_lock(&ng_btsocket_l2cap_raw_token_mtx);
1286   
1287         if (++ ng_btsocket_l2cap_raw_token == 0)
1288                 ng_btsocket_l2cap_raw_token = 1;
1289
1290         *token = ng_btsocket_l2cap_raw_token;
1291
1292         mtx_unlock(&ng_btsocket_l2cap_raw_token_mtx);
1293 } /* ng_btsocket_l2cap_raw_get_token */
1294
1295 /*
1296  * Send Netgraph message to the node - do not expect reply
1297  */
1298
1299 static int
1300 ng_btsocket_l2cap_raw_send_ngmsg(hook_p hook, int cmd, void *arg, int arglen)
1301 {
1302         struct ng_mesg  *msg = NULL;
1303         int              error = 0;
1304
1305         NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, arglen, M_NOWAIT);
1306         if (msg == NULL)
1307                 return (ENOMEM);
1308
1309         if (arg != NULL && arglen > 0)
1310                 bcopy(arg, msg->data, arglen);
1311
1312         NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, hook, 0);
1313
1314         return (error);
1315 } /* ng_btsocket_l2cap_raw_send_ngmsg */
1316
1317 /*
1318  * Send Netgraph message to the node (no data) and wait for reply
1319  */
1320
1321 static int
1322 ng_btsocket_l2cap_raw_send_sync_ngmsg(ng_btsocket_l2cap_raw_pcb_p pcb,
1323                 int cmd, void *rsp, int rsplen)
1324 {
1325         struct ng_mesg  *msg = NULL;
1326         int              error = 0;
1327
1328         mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1329
1330         NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, 0, M_NOWAIT);
1331         if (msg == NULL)
1332                 return (ENOMEM);
1333
1334         ng_btsocket_l2cap_raw_get_token(&msg->header.token);
1335         pcb->token = msg->header.token;
1336         pcb->msg = NULL;
1337
1338         NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
1339                 pcb->rt->hook, 0);
1340         if (error != 0) {
1341                 pcb->token = 0;
1342                 return (error);
1343         }
1344
1345         error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
1346                         ng_btsocket_l2cap_raw_ioctl_timeout * hz);
1347         pcb->token = 0;
1348
1349         if (error != 0)
1350                 return (error);
1351
1352         if (pcb->msg != NULL && pcb->msg->header.cmd == cmd)
1353                 bcopy(pcb->msg->data, rsp, rsplen);
1354         else
1355                 error = EINVAL;
1356
1357         NG_FREE_MSG(pcb->msg); /* checks for != NULL */
1358
1359         return (0);
1360 } /* ng_btsocket_l2cap_raw_send_sync_ngmsg */