Netgraph port from FreeBSD - initial porting work
[dragonfly.git] / sys / netgraph7 / bluetooth / socket / ng_btsocket_l2cap_raw.c
blob2bb4234ac5a76232126f7d71361985f804baf5c4
1 /*
2 * ng_btsocket_l2cap_raw.c
3 */
5 /*-
6 * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7 * All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
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.
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 * $DragonFly: src/sys/netgraph7/bluetooth/socket/ng_btsocket_l2cap_raw.c,v 1.2 2008/06/26 23:05:40 dillon Exp $
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/bitstring.h>
38 #include <sys/domain.h>
39 #include <sys/errno.h>
40 #include <sys/filedesc.h>
41 #include <sys/ioccom.h>
42 #include <sys/kernel.h>
43 #include <sys/lock.h>
44 #include <sys/malloc.h>
45 #include <sys/mbuf.h>
46 #include <sys/mutex.h>
47 #include <sys/priv.h>
48 #include <sys/protosw.h>
49 #include <sys/queue.h>
50 #include <sys/socket.h>
51 #include <sys/socketvar.h>
52 #include <sys/sysctl.h>
53 #include <sys/taskqueue.h>
54 #include "ng_message.h"
55 #include "netgraph.h"
56 #include "bluetooth/include/ng_bluetooth.h"
57 #include "bluetooth/include/ng_hci.h"
58 #include "bluetooth/include/ng_l2cap.h"
59 #include "bluetooth/include/ng_btsocket.h"
60 #include "bluetooth/include/ng_btsocket_l2cap.h"
62 /* MALLOC define */
63 #ifdef NG_SEPARATE_MALLOC
64 MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_L2CAP_RAW, "netgraph_btsocks_l2cap_raw",
65 "Netgraph Bluetooth raw L2CAP sockets");
66 #else
67 #define M_NETGRAPH_BTSOCKET_L2CAP_RAW M_NETGRAPH
68 #endif /* NG_SEPARATE_MALLOC */
70 /* Netgraph node methods */
71 static ng_constructor_t ng_btsocket_l2cap_raw_node_constructor;
72 static ng_rcvmsg_t ng_btsocket_l2cap_raw_node_rcvmsg;
73 static ng_shutdown_t ng_btsocket_l2cap_raw_node_shutdown;
74 static ng_newhook_t ng_btsocket_l2cap_raw_node_newhook;
75 static ng_connect_t ng_btsocket_l2cap_raw_node_connect;
76 static ng_rcvdata_t ng_btsocket_l2cap_raw_node_rcvdata;
77 static ng_disconnect_t ng_btsocket_l2cap_raw_node_disconnect;
79 static void ng_btsocket_l2cap_raw_input (void *, int);
80 static void ng_btsocket_l2cap_raw_rtclean (void *, int);
81 static void ng_btsocket_l2cap_raw_get_token (u_int32_t *);
83 static int ng_btsocket_l2cap_raw_send_ngmsg
84 (hook_p, int, void *, int);
85 static int ng_btsocket_l2cap_raw_send_sync_ngmsg
86 (ng_btsocket_l2cap_raw_pcb_p, int, void *, int);
88 #define ng_btsocket_l2cap_raw_wakeup_input_task() \
89 taskqueue_enqueue(taskqueue_swi, &ng_btsocket_l2cap_raw_queue_task)
91 #define ng_btsocket_l2cap_raw_wakeup_route_task() \
92 taskqueue_enqueue(taskqueue_swi, &ng_btsocket_l2cap_raw_rt_task)
94 /* Netgraph type descriptor */
95 static struct ng_type typestruct = {
96 .version = NG_ABI_VERSION,
97 .name = NG_BTSOCKET_L2CAP_RAW_NODE_TYPE,
98 .constructor = ng_btsocket_l2cap_raw_node_constructor,
99 .rcvmsg = ng_btsocket_l2cap_raw_node_rcvmsg,
100 .shutdown = ng_btsocket_l2cap_raw_node_shutdown,
101 .newhook = ng_btsocket_l2cap_raw_node_newhook,
102 .connect = ng_btsocket_l2cap_raw_node_connect,
103 .rcvdata = ng_btsocket_l2cap_raw_node_rcvdata,
104 .disconnect = ng_btsocket_l2cap_raw_node_disconnect,
107 /* Globals */
108 extern int ifqmaxlen;
109 static u_int32_t ng_btsocket_l2cap_raw_debug_level;
110 static u_int32_t ng_btsocket_l2cap_raw_ioctl_timeout;
111 static node_p ng_btsocket_l2cap_raw_node;
112 static struct ng_bt_itemq ng_btsocket_l2cap_raw_queue;
113 static struct mtx ng_btsocket_l2cap_raw_queue_mtx;
114 static struct task ng_btsocket_l2cap_raw_queue_task;
115 static LIST_HEAD(, ng_btsocket_l2cap_raw_pcb) ng_btsocket_l2cap_raw_sockets;
116 static struct mtx ng_btsocket_l2cap_raw_sockets_mtx;
117 static u_int32_t ng_btsocket_l2cap_raw_token;
118 static struct mtx ng_btsocket_l2cap_raw_token_mtx;
119 static LIST_HEAD(, ng_btsocket_l2cap_rtentry) ng_btsocket_l2cap_raw_rt;
120 static struct mtx ng_btsocket_l2cap_raw_rt_mtx;
121 static struct task ng_btsocket_l2cap_raw_rt_task;
123 /* Sysctl tree */
124 SYSCTL_DECL(_net_bluetooth_l2cap_sockets);
125 SYSCTL_NODE(_net_bluetooth_l2cap_sockets, OID_AUTO, raw, CTLFLAG_RW,
126 0, "Bluetooth raw L2CAP sockets family");
127 SYSCTL_INT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, debug_level,
128 CTLFLAG_RW,
129 &ng_btsocket_l2cap_raw_debug_level, NG_BTSOCKET_WARN_LEVEL,
130 "Bluetooth raw L2CAP sockets debug level");
131 SYSCTL_INT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, ioctl_timeout,
132 CTLFLAG_RW,
133 &ng_btsocket_l2cap_raw_ioctl_timeout, 5,
134 "Bluetooth raw L2CAP sockets ioctl timeout");
135 SYSCTL_INT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, queue_len,
136 CTLFLAG_RD,
137 &ng_btsocket_l2cap_raw_queue.len, 0,
138 "Bluetooth raw L2CAP sockets input queue length");
139 SYSCTL_INT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, queue_maxlen,
140 CTLFLAG_RD,
141 &ng_btsocket_l2cap_raw_queue.maxlen, 0,
142 "Bluetooth raw L2CAP sockets input queue max. length");
143 SYSCTL_INT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, queue_drops,
144 CTLFLAG_RD,
145 &ng_btsocket_l2cap_raw_queue.drops, 0,
146 "Bluetooth raw L2CAP sockets input queue drops");
148 /* Debug */
149 #define NG_BTSOCKET_L2CAP_RAW_INFO \
150 if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_INFO_LEVEL) \
151 printf
153 #define NG_BTSOCKET_L2CAP_RAW_WARN \
154 if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_WARN_LEVEL) \
155 printf
157 #define NG_BTSOCKET_L2CAP_RAW_ERR \
158 if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_ERR_LEVEL) \
159 printf
161 #define NG_BTSOCKET_L2CAP_RAW_ALERT \
162 if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_ALERT_LEVEL) \
163 printf
165 /*****************************************************************************
166 *****************************************************************************
167 ** Netgraph node interface
168 *****************************************************************************
169 *****************************************************************************/
172 * Netgraph node constructor. Do not allow to create node of this type.
175 static int
176 ng_btsocket_l2cap_raw_node_constructor(node_p node)
178 return (EINVAL);
179 } /* ng_btsocket_l2cap_raw_node_constructor */
182 * Do local shutdown processing. Let old node go and create new fresh one.
185 static int
186 ng_btsocket_l2cap_raw_node_shutdown(node_p node)
188 int error = 0;
190 NG_NODE_UNREF(node);
192 /* Create new node */
193 error = ng_make_node_common(&typestruct, &ng_btsocket_l2cap_raw_node);
194 if (error != 0) {
195 NG_BTSOCKET_L2CAP_RAW_ALERT(
196 "%s: Could not create Netgraph node, error=%d\n", __func__, error);
198 ng_btsocket_l2cap_raw_node = NULL;
200 return (error);
203 error = ng_name_node(ng_btsocket_l2cap_raw_node,
204 NG_BTSOCKET_L2CAP_RAW_NODE_TYPE);
205 if (error != 0) {
206 NG_BTSOCKET_L2CAP_RAW_ALERT(
207 "%s: Could not name Netgraph node, error=%d\n", __func__, error);
209 NG_NODE_UNREF(ng_btsocket_l2cap_raw_node);
210 ng_btsocket_l2cap_raw_node = NULL;
212 return (error);
215 return (0);
216 } /* ng_btsocket_l2cap_raw_node_shutdown */
219 * We allow any hook to be connected to the node.
222 static int
223 ng_btsocket_l2cap_raw_node_newhook(node_p node, hook_p hook, char const *name)
225 return (0);
226 } /* ng_btsocket_l2cap_raw_node_newhook */
229 * Just say "YEP, that's OK by me!"
232 static int
233 ng_btsocket_l2cap_raw_node_connect(hook_p hook)
235 NG_HOOK_SET_PRIVATE(hook, NULL);
236 NG_HOOK_REF(hook); /* Keep extra reference to the hook */
238 return (0);
239 } /* ng_btsocket_l2cap_raw_node_connect */
242 * Hook disconnection. Schedule route cleanup task
245 static int
246 ng_btsocket_l2cap_raw_node_disconnect(hook_p hook)
249 * If hook has private information than we must have this hook in
250 * the routing table and must schedule cleaning for the routing table.
251 * Otherwise hook was connected but we never got "hook_info" message,
252 * so we have never added this hook to the routing table and it save
253 * to just delete it.
256 if (NG_HOOK_PRIVATE(hook) != NULL)
257 return (ng_btsocket_l2cap_raw_wakeup_route_task());
259 NG_HOOK_UNREF(hook); /* Remove extra reference */
261 return (0);
262 } /* ng_btsocket_l2cap_raw_node_disconnect */
265 * Process incoming messages
268 static int
269 ng_btsocket_l2cap_raw_node_rcvmsg(node_p node, item_p item, hook_p hook)
271 struct ng_mesg *msg = NGI_MSG(item); /* item still has message */
272 int error = 0;
274 if (msg != NULL && msg->header.typecookie == NGM_L2CAP_COOKIE) {
277 * NGM_L2CAP_NODE_HOOK_INFO is special message initiated by
278 * L2CAP layer. Ignore all other messages if they are not
279 * replies or token is zero
282 if (msg->header.cmd != NGM_L2CAP_NODE_HOOK_INFO) {
283 if (msg->header.token == 0 ||
284 !(msg->header.flags & NGF_RESP)) {
285 NG_FREE_ITEM(item);
286 return (0);
290 mtx_lock(&ng_btsocket_l2cap_raw_queue_mtx);
291 if (NG_BT_ITEMQ_FULL(&ng_btsocket_l2cap_raw_queue)) {
292 NG_BTSOCKET_L2CAP_RAW_ERR(
293 "%s: Input queue is full\n", __func__);
295 NG_BT_ITEMQ_DROP(&ng_btsocket_l2cap_raw_queue);
296 NG_FREE_ITEM(item);
297 error = ENOBUFS;
298 } else {
299 if (hook != NULL) {
300 NG_HOOK_REF(hook);
301 NGI_SET_HOOK(item, hook);
304 NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_l2cap_raw_queue, item);
305 error = ng_btsocket_l2cap_raw_wakeup_input_task();
307 mtx_unlock(&ng_btsocket_l2cap_raw_queue_mtx);
308 } else {
309 NG_FREE_ITEM(item);
310 error = EINVAL;
313 return (error);
314 } /* ng_btsocket_l2cap_raw_node_rcvmsg */
317 * Receive data on a hook
320 static int
321 ng_btsocket_l2cap_raw_node_rcvdata(hook_p hook, item_p item)
323 NG_FREE_ITEM(item);
325 return (EINVAL);
326 } /* ng_btsocket_l2cap_raw_node_rcvdata */
328 /*****************************************************************************
329 *****************************************************************************
330 ** Socket interface
331 *****************************************************************************
332 *****************************************************************************/
335 * L2CAP sockets input routine
338 static void
339 ng_btsocket_l2cap_raw_input(void *context, int pending)
341 item_p item = NULL;
342 hook_p hook = NULL;
343 struct ng_mesg *msg = NULL;
345 for (;;) {
346 mtx_lock(&ng_btsocket_l2cap_raw_queue_mtx);
347 NG_BT_ITEMQ_DEQUEUE(&ng_btsocket_l2cap_raw_queue, item);
348 mtx_unlock(&ng_btsocket_l2cap_raw_queue_mtx);
350 if (item == NULL)
351 break;
353 KASSERT((item->el_flags & NGQF_TYPE) == NGQF_MESG,
354 ("%s: invalid item type=%ld\n", __func__, (item->el_flags & NGQF_TYPE)));
356 NGI_GET_MSG(item, msg);
357 NGI_GET_HOOK(item, hook);
358 NG_FREE_ITEM(item);
360 switch (msg->header.cmd) {
361 case NGM_L2CAP_NODE_HOOK_INFO: {
362 ng_btsocket_l2cap_rtentry_t *rt = NULL;
364 if (hook == NULL || NG_HOOK_NOT_VALID(hook) ||
365 msg->header.arglen != sizeof(bdaddr_t))
366 break;
368 if (bcmp(msg->data, NG_HCI_BDADDR_ANY,
369 sizeof(bdaddr_t)) == 0)
370 break;
372 rt = (ng_btsocket_l2cap_rtentry_t *)
373 NG_HOOK_PRIVATE(hook);
374 if (rt == NULL) {
375 MALLOC(rt, ng_btsocket_l2cap_rtentry_p,
376 sizeof(*rt),
377 M_NETGRAPH_BTSOCKET_L2CAP_RAW,
378 M_WAITOK | M_NULLOK | M_ZERO);
379 if (rt == NULL)
380 break;
382 NG_HOOK_SET_PRIVATE(hook, rt);
384 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
386 LIST_INSERT_HEAD(&ng_btsocket_l2cap_raw_rt,
387 rt, next);
388 } else
389 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
391 bcopy(msg->data, &rt->src, sizeof(rt->src));
392 rt->hook = hook;
394 NG_BTSOCKET_L2CAP_RAW_INFO(
395 "%s: Updating hook \"%s\", src bdaddr=%x:%x:%x:%x:%x:%x\n",
396 __func__, NG_HOOK_NAME(hook),
397 rt->src.b[5], rt->src.b[4], rt->src.b[3],
398 rt->src.b[2], rt->src.b[1], rt->src.b[0]);
400 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);
401 } break;
403 case NGM_L2CAP_NODE_GET_FLAGS:
404 case NGM_L2CAP_NODE_GET_DEBUG:
405 case NGM_L2CAP_NODE_GET_CON_LIST:
406 case NGM_L2CAP_NODE_GET_CHAN_LIST:
407 case NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO:
408 case NGM_L2CAP_L2CA_PING:
409 case NGM_L2CAP_L2CA_GET_INFO: {
410 ng_btsocket_l2cap_raw_pcb_p pcb = NULL;
412 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);
414 LIST_FOREACH(pcb,&ng_btsocket_l2cap_raw_sockets,next) {
415 mtx_lock(&pcb->pcb_mtx);
417 if (pcb->token == msg->header.token) {
418 pcb->msg = msg;
419 msg = NULL;
420 wakeup(&pcb->msg);
421 mtx_unlock(&pcb->pcb_mtx);
422 break;
425 mtx_unlock(&pcb->pcb_mtx);
428 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);
429 } break;
431 default:
432 NG_BTSOCKET_L2CAP_RAW_WARN(
433 "%s: Unknown message, cmd=%d\n", __func__, msg->header.cmd);
434 break;
437 if (hook != NULL)
438 NG_HOOK_UNREF(hook); /* remove extra reference */
440 NG_FREE_MSG(msg); /* Checks for msg != NULL */
442 } /* ng_btsocket_l2cap_raw_input */
445 * Route cleanup task. Gets scheduled when hook is disconnected. Here we
446 * will find all sockets that use "invalid" hook and disconnect them.
449 static void
450 ng_btsocket_l2cap_raw_rtclean(void *context, int pending)
452 ng_btsocket_l2cap_raw_pcb_p pcb = NULL;
453 ng_btsocket_l2cap_rtentry_p rt = NULL;
456 * First disconnect all sockets that use "invalid" hook
459 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);
461 LIST_FOREACH(pcb, &ng_btsocket_l2cap_raw_sockets, next) {
462 mtx_lock(&pcb->pcb_mtx);
464 if (pcb->rt != NULL &&
465 pcb->rt->hook != NULL && NG_HOOK_NOT_VALID(pcb->rt->hook)) {
466 if (pcb->so != NULL &&
467 pcb->so->so_state & SS_ISCONNECTED)
468 soisdisconnected(pcb->so);
470 pcb->rt = NULL;
473 mtx_unlock(&pcb->pcb_mtx);
476 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);
479 * Now cleanup routing table
482 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
484 for (rt = LIST_FIRST(&ng_btsocket_l2cap_raw_rt); rt != NULL; ) {
485 ng_btsocket_l2cap_rtentry_p rt_next = LIST_NEXT(rt, next);
487 if (rt->hook != NULL && NG_HOOK_NOT_VALID(rt->hook)) {
488 LIST_REMOVE(rt, next);
490 NG_HOOK_SET_PRIVATE(rt->hook, NULL);
491 NG_HOOK_UNREF(rt->hook); /* Remove extra reference */
493 bzero(rt, sizeof(*rt));
494 FREE(rt, M_NETGRAPH_BTSOCKET_L2CAP_RAW);
497 rt = rt_next;
500 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);
501 } /* ng_btsocket_l2cap_raw_rtclean */
504 * Initialize everything
507 void
508 ng_btsocket_l2cap_raw_init(void)
510 int error = 0;
512 ng_btsocket_l2cap_raw_node = NULL;
513 ng_btsocket_l2cap_raw_debug_level = NG_BTSOCKET_WARN_LEVEL;
514 ng_btsocket_l2cap_raw_ioctl_timeout = 5;
516 /* Register Netgraph node type */
517 error = ng_newtype(&typestruct);
518 if (error != 0) {
519 NG_BTSOCKET_L2CAP_RAW_ALERT(
520 "%s: Could not register Netgraph node type, error=%d\n", __func__, error);
522 return;
525 /* Create Netgrapg node */
526 error = ng_make_node_common(&typestruct, &ng_btsocket_l2cap_raw_node);
527 if (error != 0) {
528 NG_BTSOCKET_L2CAP_RAW_ALERT(
529 "%s: Could not create Netgraph node, error=%d\n", __func__, error);
531 ng_btsocket_l2cap_raw_node = NULL;
533 return;
536 error = ng_name_node(ng_btsocket_l2cap_raw_node,
537 NG_BTSOCKET_L2CAP_RAW_NODE_TYPE);
538 if (error != 0) {
539 NG_BTSOCKET_L2CAP_RAW_ALERT(
540 "%s: Could not name Netgraph node, error=%d\n", __func__, error);
542 NG_NODE_UNREF(ng_btsocket_l2cap_raw_node);
543 ng_btsocket_l2cap_raw_node = NULL;
545 return;
548 /* Create input queue */
549 NG_BT_ITEMQ_INIT(&ng_btsocket_l2cap_raw_queue, ifqmaxlen);
550 mtx_init(&ng_btsocket_l2cap_raw_queue_mtx,
551 "btsocks_l2cap_raw_queue_mtx", NULL, MTX_DEF);
552 TASK_INIT(&ng_btsocket_l2cap_raw_queue_task, 0,
553 ng_btsocket_l2cap_raw_input, NULL);
555 /* Create list of sockets */
556 LIST_INIT(&ng_btsocket_l2cap_raw_sockets);
557 mtx_init(&ng_btsocket_l2cap_raw_sockets_mtx,
558 "btsocks_l2cap_raw_sockets_mtx", NULL, MTX_DEF);
560 /* Tokens */
561 ng_btsocket_l2cap_raw_token = 0;
562 mtx_init(&ng_btsocket_l2cap_raw_token_mtx,
563 "btsocks_l2cap_raw_token_mtx", NULL, MTX_DEF);
565 /* Routing table */
566 LIST_INIT(&ng_btsocket_l2cap_raw_rt);
567 mtx_init(&ng_btsocket_l2cap_raw_rt_mtx,
568 "btsocks_l2cap_raw_rt_mtx", NULL, MTX_DEF);
569 TASK_INIT(&ng_btsocket_l2cap_raw_rt_task, 0,
570 ng_btsocket_l2cap_raw_rtclean, NULL);
571 } /* ng_btsocket_l2cap_raw_init */
574 * Abort connection on socket
577 void
578 ng_btsocket_l2cap_raw_abort(struct socket *so)
581 (void)ng_btsocket_l2cap_raw_disconnect(so);
582 } /* ng_btsocket_l2cap_raw_abort */
584 void
585 ng_btsocket_l2cap_raw_close(struct socket *so)
588 (void)ng_btsocket_l2cap_raw_disconnect(so);
589 } /* ng_btsocket_l2cap_raw_close */
592 * Create and attach new socket
596 ng_btsocket_l2cap_raw_attach(struct socket *so, int proto, struct thread *td)
598 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
599 int error;
601 if (pcb != NULL)
602 return (EISCONN);
604 if (ng_btsocket_l2cap_raw_node == NULL)
605 return (EPROTONOSUPPORT);
606 if (so->so_type != SOCK_RAW)
607 return (ESOCKTNOSUPPORT);
609 /* Reserve send and receive space if it is not reserved yet */
610 error = soreserve(so, NG_BTSOCKET_L2CAP_RAW_SENDSPACE,
611 NG_BTSOCKET_L2CAP_RAW_RECVSPACE);
612 if (error != 0)
613 return (error);
615 /* Allocate the PCB */
616 MALLOC(pcb, ng_btsocket_l2cap_raw_pcb_p, sizeof(*pcb),
617 M_NETGRAPH_BTSOCKET_L2CAP_RAW, M_WAITOK | M_NULLOK | M_ZERO);
618 if (pcb == NULL)
619 return (ENOMEM);
621 /* Link the PCB and the socket */
622 so->so_pcb = (caddr_t) pcb;
623 pcb->so = so;
625 if (priv_check(td, PRIV_NETBLUETOOTH_RAW) == 0)
626 pcb->flags |= NG_BTSOCKET_L2CAP_RAW_PRIVILEGED;
628 mtx_init(&pcb->pcb_mtx, "btsocks_l2cap_raw_pcb_mtx", NULL, MTX_DEF);
630 /* Add the PCB to the list */
631 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);
632 LIST_INSERT_HEAD(&ng_btsocket_l2cap_raw_sockets, pcb, next);
633 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);
635 return (0);
636 } /* ng_btsocket_l2cap_raw_attach */
639 * Bind socket
643 ng_btsocket_l2cap_raw_bind(struct socket *so, struct sockaddr *nam,
644 struct thread *td)
646 ng_btsocket_l2cap_raw_pcb_t *pcb = so2l2cap_raw_pcb(so);
647 struct sockaddr_l2cap *sa = (struct sockaddr_l2cap *) nam;
648 ng_btsocket_l2cap_rtentry_t *rt = NULL;
650 if (pcb == NULL)
651 return (EINVAL);
652 if (ng_btsocket_l2cap_raw_node == NULL)
653 return (EINVAL);
655 if (sa == NULL)
656 return (EINVAL);
657 if (sa->l2cap_family != AF_BLUETOOTH)
658 return (EAFNOSUPPORT);
659 if (sa->l2cap_len != sizeof(*sa))
660 return (EINVAL);
662 if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY,
663 sizeof(sa->l2cap_bdaddr)) != 0) {
664 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
666 LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) {
667 if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
668 continue;
670 if (bcmp(&sa->l2cap_bdaddr, &rt->src,
671 sizeof(rt->src)) == 0)
672 break;
675 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);
677 if (rt == NULL)
678 return (ENETDOWN);
679 } else
680 rt = NULL;
682 mtx_lock(&pcb->pcb_mtx);
683 bcopy(&sa->l2cap_bdaddr, &pcb->src, sizeof(pcb->src));
684 pcb->rt = rt;
685 mtx_unlock(&pcb->pcb_mtx);
687 return (0);
688 } /* ng_btsocket_l2cap_raw_bind */
691 * Connect socket
695 ng_btsocket_l2cap_raw_connect(struct socket *so, struct sockaddr *nam,
696 struct thread *td)
698 ng_btsocket_l2cap_raw_pcb_t *pcb = so2l2cap_raw_pcb(so);
699 struct sockaddr_l2cap *sa = (struct sockaddr_l2cap *) nam;
700 ng_btsocket_l2cap_rtentry_t *rt = NULL;
701 int error;
703 if (pcb == NULL)
704 return (EINVAL);
705 if (ng_btsocket_l2cap_raw_node == NULL)
706 return (EINVAL);
708 if (sa == NULL)
709 return (EINVAL);
710 if (sa->l2cap_family != AF_BLUETOOTH)
711 return (EAFNOSUPPORT);
712 if (sa->l2cap_len != sizeof(*sa))
713 return (EINVAL);
714 if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
715 return (EINVAL);
717 mtx_lock(&pcb->pcb_mtx);
719 bcopy(&sa->l2cap_bdaddr, &pcb->dst, sizeof(pcb->dst));
721 if (bcmp(&pcb->src, &pcb->dst, sizeof(pcb->src)) == 0) {
722 mtx_unlock(&pcb->pcb_mtx);
724 return (EADDRNOTAVAIL);
728 * If there is route already - use it
731 if (pcb->rt != NULL) {
732 soisconnected(so);
733 mtx_unlock(&pcb->pcb_mtx);
735 return (0);
739 * Find the first hook that does not match specified destination address
742 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
744 LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) {
745 if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
746 continue;
748 if (bcmp(&pcb->dst, &rt->src, sizeof(rt->src)) != 0)
749 break;
752 if (rt != NULL) {
753 soisconnected(so);
755 pcb->rt = rt;
756 bcopy(&rt->src, &pcb->src, sizeof(pcb->src));
758 error = 0;
759 } else
760 error = ENETDOWN;
762 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);
763 mtx_unlock(&pcb->pcb_mtx);
765 return (error);
766 } /* ng_btsocket_l2cap_raw_connect */
769 * Process ioctl's calls on socket
773 ng_btsocket_l2cap_raw_control(struct socket *so, u_long cmd, caddr_t data,
774 struct ifnet *ifp, struct thread *td)
776 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
777 struct ng_mesg *msg = NULL;
778 int error = 0;
780 if (pcb == NULL)
781 return (EINVAL);
782 if (ng_btsocket_l2cap_raw_node == NULL)
783 return (EINVAL);
785 mtx_lock(&pcb->pcb_mtx);
787 /* Check if we route info */
788 if (pcb->rt == NULL) {
789 mtx_unlock(&pcb->pcb_mtx);
790 return (EHOSTUNREACH);
793 /* Check if we have pending ioctl() */
794 if (pcb->token != 0) {
795 mtx_unlock(&pcb->pcb_mtx);
796 return (EBUSY);
799 switch (cmd) {
800 case SIOC_L2CAP_NODE_GET_FLAGS: {
801 struct ng_btsocket_l2cap_raw_node_flags *p =
802 (struct ng_btsocket_l2cap_raw_node_flags *) data;
804 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,
805 NGM_L2CAP_NODE_GET_FLAGS,
806 &p->flags, sizeof(p->flags));
807 } break;
809 case SIOC_L2CAP_NODE_GET_DEBUG: {
810 struct ng_btsocket_l2cap_raw_node_debug *p =
811 (struct ng_btsocket_l2cap_raw_node_debug *) data;
813 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,
814 NGM_L2CAP_NODE_GET_DEBUG,
815 &p->debug, sizeof(p->debug));
816 } break;
818 case SIOC_L2CAP_NODE_SET_DEBUG: {
819 struct ng_btsocket_l2cap_raw_node_debug *p =
820 (struct ng_btsocket_l2cap_raw_node_debug *) data;
822 if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)
823 error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook,
824 NGM_L2CAP_NODE_SET_DEBUG,
825 &p->debug, sizeof(p->debug));
826 else
827 error = EPERM;
828 } break;
830 case SIOC_L2CAP_NODE_GET_CON_LIST: {
831 struct ng_btsocket_l2cap_raw_con_list *p =
832 (struct ng_btsocket_l2cap_raw_con_list *) data;
833 ng_l2cap_node_con_list_ep *p1 = NULL;
834 ng_l2cap_node_con_ep *p2 = NULL;
836 if (p->num_connections == 0 ||
837 p->num_connections > NG_L2CAP_MAX_CON_NUM ||
838 p->connections == NULL) {
839 error = EINVAL;
840 break;
843 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_NODE_GET_CON_LIST,
844 0, M_WAITOK | M_NULLOK);
845 if (msg == NULL) {
846 error = ENOMEM;
847 break;
849 ng_btsocket_l2cap_raw_get_token(&msg->header.token);
850 pcb->token = msg->header.token;
851 pcb->msg = NULL;
853 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
854 pcb->rt->hook, 0);
855 if (error != 0) {
856 pcb->token = 0;
857 break;
860 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
861 ng_btsocket_l2cap_raw_ioctl_timeout * hz);
862 pcb->token = 0;
864 if (error != 0)
865 break;
867 if (pcb->msg != NULL &&
868 pcb->msg->header.cmd == NGM_L2CAP_NODE_GET_CON_LIST) {
869 /* Return data back to user space */
870 p1 = (ng_l2cap_node_con_list_ep *)(pcb->msg->data);
871 p2 = (ng_l2cap_node_con_ep *)(p1 + 1);
873 p->num_connections = min(p->num_connections,
874 p1->num_connections);
875 if (p->num_connections > 0)
876 error = copyout((caddr_t) p2,
877 (caddr_t) p->connections,
878 p->num_connections * sizeof(*p2));
879 } else
880 error = EINVAL;
882 NG_FREE_MSG(pcb->msg); /* checks for != NULL */
883 } break;
885 case SIOC_L2CAP_NODE_GET_CHAN_LIST: {
886 struct ng_btsocket_l2cap_raw_chan_list *p =
887 (struct ng_btsocket_l2cap_raw_chan_list *) data;
888 ng_l2cap_node_chan_list_ep *p1 = NULL;
889 ng_l2cap_node_chan_ep *p2 = NULL;
891 if (p->num_channels == 0 ||
892 p->num_channels > NG_L2CAP_MAX_CHAN_NUM ||
893 p->channels == NULL) {
894 error = EINVAL;
895 break;
898 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE,
899 NGM_L2CAP_NODE_GET_CHAN_LIST, 0, M_WAITOK | M_NULLOK);
900 if (msg == NULL) {
901 error = ENOMEM;
902 break;
904 ng_btsocket_l2cap_raw_get_token(&msg->header.token);
905 pcb->token = msg->header.token;
906 pcb->msg = NULL;
908 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
909 pcb->rt->hook, 0);
910 if (error != 0) {
911 pcb->token = 0;
912 break;
915 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
916 ng_btsocket_l2cap_raw_ioctl_timeout * hz);
917 pcb->token = 0;
919 if (error != 0)
920 break;
922 if (pcb->msg != NULL &&
923 pcb->msg->header.cmd == NGM_L2CAP_NODE_GET_CHAN_LIST) {
924 /* Return data back to user space */
925 p1 = (ng_l2cap_node_chan_list_ep *)(pcb->msg->data);
926 p2 = (ng_l2cap_node_chan_ep *)(p1 + 1);
928 p->num_channels = min(p->num_channels,
929 p1->num_channels);
930 if (p->num_channels > 0)
931 error = copyout((caddr_t) p2,
932 (caddr_t) p->channels,
933 p->num_channels * sizeof(*p2));
934 } else
935 error = EINVAL;
937 NG_FREE_MSG(pcb->msg); /* checks for != NULL */
938 } break;
940 case SIOC_L2CAP_L2CA_PING: {
941 struct ng_btsocket_l2cap_raw_ping *p =
942 (struct ng_btsocket_l2cap_raw_ping *) data;
943 ng_l2cap_l2ca_ping_ip *ip = NULL;
944 ng_l2cap_l2ca_ping_op *op = NULL;
946 if (!(pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)) {
947 error = EPERM;
948 break;
951 if ((p->echo_size != 0 && p->echo_data == NULL) ||
952 p->echo_size > NG_L2CAP_MAX_ECHO_SIZE) {
953 error = EINVAL;
954 break;
957 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE,
958 NGM_L2CAP_L2CA_PING, sizeof(*ip) + p->echo_size,
959 M_WAITOK | M_NULLOK);
960 if (msg == NULL) {
961 error = ENOMEM;
962 break;
964 ng_btsocket_l2cap_raw_get_token(&msg->header.token);
965 pcb->token = msg->header.token;
966 pcb->msg = NULL;
968 ip = (ng_l2cap_l2ca_ping_ip *)(msg->data);
969 bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr));
970 ip->echo_size = p->echo_size;
972 if (ip->echo_size > 0) {
973 error = copyin(p->echo_data, ip + 1, p->echo_size);
974 if (error != 0) {
975 NG_FREE_MSG(msg);
976 pcb->token = 0;
977 break;
981 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
982 pcb->rt->hook, 0);
983 if (error != 0) {
984 pcb->token = 0;
985 break;
988 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
989 bluetooth_l2cap_rtx_timeout());
990 pcb->token = 0;
992 if (error != 0)
993 break;
995 if (pcb->msg != NULL &&
996 pcb->msg->header.cmd == NGM_L2CAP_L2CA_PING) {
997 /* Return data back to the user space */
998 op = (ng_l2cap_l2ca_ping_op *)(pcb->msg->data);
999 p->result = op->result;
1000 p->echo_size = min(p->echo_size, op->echo_size);
1002 if (p->echo_size > 0)
1003 error = copyout(op + 1, p->echo_data,
1004 p->echo_size);
1005 } else
1006 error = EINVAL;
1008 NG_FREE_MSG(pcb->msg); /* checks for != NULL */
1009 } break;
1011 case SIOC_L2CAP_L2CA_GET_INFO: {
1012 struct ng_btsocket_l2cap_raw_get_info *p =
1013 (struct ng_btsocket_l2cap_raw_get_info *) data;
1014 ng_l2cap_l2ca_get_info_ip *ip = NULL;
1015 ng_l2cap_l2ca_get_info_op *op = NULL;
1017 if (!(pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)) {
1018 error = EPERM;
1019 break;
1022 if (p->info_size != 0 && p->info_data == NULL) {
1023 error = EINVAL;
1024 break;
1027 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE,
1028 NGM_L2CAP_L2CA_GET_INFO, sizeof(*ip) + p->info_size,
1029 M_WAITOK | M_NULLOK);
1030 if (msg == NULL) {
1031 error = ENOMEM;
1032 break;
1034 ng_btsocket_l2cap_raw_get_token(&msg->header.token);
1035 pcb->token = msg->header.token;
1036 pcb->msg = NULL;
1038 ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data);
1039 bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr));
1040 ip->info_type = p->info_type;
1042 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
1043 pcb->rt->hook, 0);
1044 if (error != 0) {
1045 pcb->token = 0;
1046 break;
1049 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
1050 bluetooth_l2cap_rtx_timeout());
1051 pcb->token = 0;
1053 if (error != 0)
1054 break;
1056 if (pcb->msg != NULL &&
1057 pcb->msg->header.cmd == NGM_L2CAP_L2CA_GET_INFO) {
1058 /* Return data back to the user space */
1059 op = (ng_l2cap_l2ca_get_info_op *)(pcb->msg->data);
1060 p->result = op->result;
1061 p->info_size = min(p->info_size, op->info_size);
1063 if (p->info_size > 0)
1064 error = copyout(op + 1, p->info_data,
1065 p->info_size);
1066 } else
1067 error = EINVAL;
1069 NG_FREE_MSG(pcb->msg); /* checks for != NULL */
1070 } break;
1072 case SIOC_L2CAP_NODE_GET_AUTO_DISCON_TIMO: {
1073 struct ng_btsocket_l2cap_raw_auto_discon_timo *p =
1074 (struct ng_btsocket_l2cap_raw_auto_discon_timo *) data;
1076 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,
1077 NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO,
1078 &p->timeout, sizeof(p->timeout));
1079 } break;
1081 case SIOC_L2CAP_NODE_SET_AUTO_DISCON_TIMO: {
1082 struct ng_btsocket_l2cap_raw_auto_discon_timo *p =
1083 (struct ng_btsocket_l2cap_raw_auto_discon_timo *) data;
1085 if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)
1086 error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook,
1087 NGM_L2CAP_NODE_SET_AUTO_DISCON_TIMO,
1088 &p->timeout, sizeof(p->timeout));
1089 else
1090 error = EPERM;
1091 } break;
1093 default:
1094 error = EINVAL;
1095 break;
1098 mtx_unlock(&pcb->pcb_mtx);
1100 return (error);
1101 } /* ng_btsocket_l2cap_raw_control */
1104 * Detach and destroy socket
1107 void
1108 ng_btsocket_l2cap_raw_detach(struct socket *so)
1110 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
1112 KASSERT(pcb != NULL, ("nt_btsocket_l2cap_raw_detach: pcb == NULL"));
1113 if (ng_btsocket_l2cap_raw_node == NULL)
1114 return;
1116 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);
1117 mtx_lock(&pcb->pcb_mtx);
1119 LIST_REMOVE(pcb, next);
1121 mtx_unlock(&pcb->pcb_mtx);
1122 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);
1124 mtx_destroy(&pcb->pcb_mtx);
1126 bzero(pcb, sizeof(*pcb));
1127 FREE(pcb, M_NETGRAPH_BTSOCKET_L2CAP_RAW);
1129 so->so_pcb = NULL;
1130 } /* ng_btsocket_l2cap_raw_detach */
1133 * Disconnect socket
1137 ng_btsocket_l2cap_raw_disconnect(struct socket *so)
1139 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
1141 if (pcb == NULL)
1142 return (EINVAL);
1143 if (ng_btsocket_l2cap_raw_node == NULL)
1144 return (EINVAL);
1146 mtx_lock(&pcb->pcb_mtx);
1147 pcb->rt = NULL;
1148 soisdisconnected(so);
1149 mtx_unlock(&pcb->pcb_mtx);
1151 return (0);
1152 } /* ng_btsocket_l2cap_raw_disconnect */
1155 * Get peer address
1159 ng_btsocket_l2cap_raw_peeraddr(struct socket *so, struct sockaddr **nam)
1161 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
1162 struct sockaddr_l2cap sa;
1164 if (pcb == NULL)
1165 return (EINVAL);
1166 if (ng_btsocket_l2cap_raw_node == NULL)
1167 return (EINVAL);
1169 mtx_lock(&pcb->pcb_mtx);
1170 bcopy(&pcb->dst, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr));
1171 mtx_unlock(&pcb->pcb_mtx);
1173 sa.l2cap_psm = 0;
1174 sa.l2cap_len = sizeof(sa);
1175 sa.l2cap_family = AF_BLUETOOTH;
1177 *nam = sodupsockaddr((struct sockaddr *) &sa, M_WAITOK | M_NULLOK);
1179 return ((*nam == NULL)? ENOMEM : 0);
1180 } /* ng_btsocket_l2cap_raw_peeraddr */
1183 * Send data to socket
1187 ng_btsocket_l2cap_raw_send(struct socket *so, int flags, struct mbuf *m,
1188 struct sockaddr *nam, struct mbuf *control, struct thread *td)
1190 NG_FREE_M(m); /* Checks for m != NULL */
1191 NG_FREE_M(control);
1193 return (EOPNOTSUPP);
1194 } /* ng_btsocket_l2cap_raw_send */
1197 * Get socket address
1201 ng_btsocket_l2cap_raw_sockaddr(struct socket *so, struct sockaddr **nam)
1203 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
1204 struct sockaddr_l2cap sa;
1206 if (pcb == NULL)
1207 return (EINVAL);
1208 if (ng_btsocket_l2cap_raw_node == NULL)
1209 return (EINVAL);
1211 mtx_lock(&pcb->pcb_mtx);
1212 bcopy(&pcb->src, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr));
1213 mtx_unlock(&pcb->pcb_mtx);
1215 sa.l2cap_psm = 0;
1216 sa.l2cap_len = sizeof(sa);
1217 sa.l2cap_family = AF_BLUETOOTH;
1219 *nam = sodupsockaddr((struct sockaddr *) &sa, M_WAITOK | M_NULLOK);
1221 return ((*nam == NULL)? ENOMEM : 0);
1222 } /* ng_btsocket_l2cap_raw_sockaddr */
1225 * Get next token
1228 static void
1229 ng_btsocket_l2cap_raw_get_token(u_int32_t *token)
1231 mtx_lock(&ng_btsocket_l2cap_raw_token_mtx);
1233 if (++ ng_btsocket_l2cap_raw_token == 0)
1234 ng_btsocket_l2cap_raw_token = 1;
1236 *token = ng_btsocket_l2cap_raw_token;
1238 mtx_unlock(&ng_btsocket_l2cap_raw_token_mtx);
1239 } /* ng_btsocket_l2cap_raw_get_token */
1242 * Send Netgraph message to the node - do not expect reply
1245 static int
1246 ng_btsocket_l2cap_raw_send_ngmsg(hook_p hook, int cmd, void *arg, int arglen)
1248 struct ng_mesg *msg = NULL;
1249 int error = 0;
1251 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, arglen, M_WAITOK | M_NULLOK);
1252 if (msg == NULL)
1253 return (ENOMEM);
1255 if (arg != NULL && arglen > 0)
1256 bcopy(arg, msg->data, arglen);
1258 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, hook, 0);
1260 return (error);
1261 } /* ng_btsocket_l2cap_raw_send_ngmsg */
1264 * Send Netgraph message to the node (no data) and wait for reply
1267 static int
1268 ng_btsocket_l2cap_raw_send_sync_ngmsg(ng_btsocket_l2cap_raw_pcb_p pcb,
1269 int cmd, void *rsp, int rsplen)
1271 struct ng_mesg *msg = NULL;
1272 int error = 0;
1274 mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1276 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, 0, M_WAITOK | M_NULLOK);
1277 if (msg == NULL)
1278 return (ENOMEM);
1280 ng_btsocket_l2cap_raw_get_token(&msg->header.token);
1281 pcb->token = msg->header.token;
1282 pcb->msg = NULL;
1284 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
1285 pcb->rt->hook, 0);
1286 if (error != 0) {
1287 pcb->token = 0;
1288 return (error);
1291 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
1292 ng_btsocket_l2cap_raw_ioctl_timeout * hz);
1293 pcb->token = 0;
1295 if (error != 0)
1296 return (error);
1298 if (pcb->msg != NULL && pcb->msg->header.cmd == cmd)
1299 bcopy(pcb->msg->data, rsp, rsplen);
1300 else
1301 error = EINVAL;
1303 NG_FREE_MSG(pcb->msg); /* checks for != NULL */
1305 return (0);
1306 } /* ng_btsocket_l2cap_raw_send_sync_ngmsg */