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