2 * ng_btsocket_l2cap_raw.c
6 * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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
30 * $Id: ng_btsocket_l2cap_raw.c,v 1.12 2003/09/14 23:29:06 max Exp $
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/ioccom.h>
41 #include <sys/kernel.h>
43 #include <sys/malloc.h>
45 #include <sys/mutex.h>
47 #include <sys/protosw.h>
48 #include <sys/queue.h>
49 #include <sys/socket.h>
50 #include <sys/socketvar.h>
51 #include <sys/sysctl.h>
52 #include <sys/taskqueue.h>
56 #include <netgraph/ng_message.h>
57 #include <netgraph/netgraph.h>
58 #include <netgraph/bluetooth/include/ng_bluetooth.h>
59 #include <netgraph/bluetooth/include/ng_hci.h>
60 #include <netgraph/bluetooth/include/ng_l2cap.h>
61 #include <netgraph/bluetooth/include/ng_btsocket.h>
62 #include <netgraph/bluetooth/include/ng_btsocket_l2cap.h>
65 #ifdef NG_SEPARATE_MALLOC
66 static MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_L2CAP_RAW,
67 "netgraph_btsocks_l2cap_raw", "Netgraph Bluetooth raw L2CAP sockets");
69 #define M_NETGRAPH_BTSOCKET_L2CAP_RAW M_NETGRAPH
70 #endif /* NG_SEPARATE_MALLOC */
72 /* Netgraph node methods */
73 static ng_constructor_t ng_btsocket_l2cap_raw_node_constructor;
74 static ng_rcvmsg_t ng_btsocket_l2cap_raw_node_rcvmsg;
75 static ng_shutdown_t ng_btsocket_l2cap_raw_node_shutdown;
76 static ng_newhook_t ng_btsocket_l2cap_raw_node_newhook;
77 static ng_connect_t ng_btsocket_l2cap_raw_node_connect;
78 static ng_rcvdata_t ng_btsocket_l2cap_raw_node_rcvdata;
79 static ng_disconnect_t ng_btsocket_l2cap_raw_node_disconnect;
81 static void ng_btsocket_l2cap_raw_input (void *, int);
82 static void ng_btsocket_l2cap_raw_rtclean (void *, int);
83 static void ng_btsocket_l2cap_raw_get_token (u_int32_t *);
85 static int ng_btsocket_l2cap_raw_send_ngmsg
86 (hook_p, int, void *, int);
87 static int ng_btsocket_l2cap_raw_send_sync_ngmsg
88 (ng_btsocket_l2cap_raw_pcb_p, int, void *, int);
90 #define ng_btsocket_l2cap_raw_wakeup_input_task() \
91 taskqueue_enqueue(taskqueue_swi, &ng_btsocket_l2cap_raw_queue_task)
93 #define ng_btsocket_l2cap_raw_wakeup_route_task() \
94 taskqueue_enqueue(taskqueue_swi, &ng_btsocket_l2cap_raw_rt_task)
96 /* Netgraph type descriptor */
97 static struct ng_type typestruct = {
98 .version = NG_ABI_VERSION,
99 .name = NG_BTSOCKET_L2CAP_RAW_NODE_TYPE,
100 .constructor = ng_btsocket_l2cap_raw_node_constructor,
101 .rcvmsg = ng_btsocket_l2cap_raw_node_rcvmsg,
102 .shutdown = ng_btsocket_l2cap_raw_node_shutdown,
103 .newhook = ng_btsocket_l2cap_raw_node_newhook,
104 .connect = ng_btsocket_l2cap_raw_node_connect,
105 .rcvdata = ng_btsocket_l2cap_raw_node_rcvdata,
106 .disconnect = ng_btsocket_l2cap_raw_node_disconnect,
110 extern int ifqmaxlen;
111 static u_int32_t ng_btsocket_l2cap_raw_debug_level;
112 static u_int32_t ng_btsocket_l2cap_raw_ioctl_timeout;
113 static node_p ng_btsocket_l2cap_raw_node;
114 static struct ng_bt_itemq ng_btsocket_l2cap_raw_queue;
115 static struct mtx ng_btsocket_l2cap_raw_queue_mtx;
116 static struct task ng_btsocket_l2cap_raw_queue_task;
117 static LIST_HEAD(, ng_btsocket_l2cap_raw_pcb) ng_btsocket_l2cap_raw_sockets;
118 static struct mtx ng_btsocket_l2cap_raw_sockets_mtx;
119 static u_int32_t ng_btsocket_l2cap_raw_token;
120 static struct mtx ng_btsocket_l2cap_raw_token_mtx;
121 static LIST_HEAD(, ng_btsocket_l2cap_rtentry) ng_btsocket_l2cap_raw_rt;
122 static struct mtx ng_btsocket_l2cap_raw_rt_mtx;
123 static struct task ng_btsocket_l2cap_raw_rt_task;
124 static struct timeval ng_btsocket_l2cap_raw_lasttime;
125 static int ng_btsocket_l2cap_raw_curpps;
128 SYSCTL_DECL(_net_bluetooth_l2cap_sockets);
129 static SYSCTL_NODE(_net_bluetooth_l2cap_sockets, OID_AUTO, raw, CTLFLAG_RW,
130 0, "Bluetooth raw L2CAP sockets family");
131 SYSCTL_UINT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, debug_level,
133 &ng_btsocket_l2cap_raw_debug_level, NG_BTSOCKET_WARN_LEVEL,
134 "Bluetooth raw L2CAP sockets debug level");
135 SYSCTL_UINT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, ioctl_timeout,
137 &ng_btsocket_l2cap_raw_ioctl_timeout, 5,
138 "Bluetooth raw L2CAP sockets ioctl timeout");
139 SYSCTL_UINT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, queue_len,
141 &ng_btsocket_l2cap_raw_queue.len, 0,
142 "Bluetooth raw L2CAP sockets input queue length");
143 SYSCTL_UINT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, queue_maxlen,
145 &ng_btsocket_l2cap_raw_queue.maxlen, 0,
146 "Bluetooth raw L2CAP sockets input queue max. length");
147 SYSCTL_UINT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, queue_drops,
149 &ng_btsocket_l2cap_raw_queue.drops, 0,
150 "Bluetooth raw L2CAP sockets input queue drops");
153 #define NG_BTSOCKET_L2CAP_RAW_INFO \
154 if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_INFO_LEVEL && \
155 ppsratecheck(&ng_btsocket_l2cap_raw_lasttime, &ng_btsocket_l2cap_raw_curpps, 1)) \
158 #define NG_BTSOCKET_L2CAP_RAW_WARN \
159 if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_WARN_LEVEL && \
160 ppsratecheck(&ng_btsocket_l2cap_raw_lasttime, &ng_btsocket_l2cap_raw_curpps, 1)) \
163 #define NG_BTSOCKET_L2CAP_RAW_ERR \
164 if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_ERR_LEVEL && \
165 ppsratecheck(&ng_btsocket_l2cap_raw_lasttime, &ng_btsocket_l2cap_raw_curpps, 1)) \
168 #define NG_BTSOCKET_L2CAP_RAW_ALERT \
169 if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_ALERT_LEVEL && \
170 ppsratecheck(&ng_btsocket_l2cap_raw_lasttime, &ng_btsocket_l2cap_raw_curpps, 1)) \
173 /*****************************************************************************
174 *****************************************************************************
175 ** Netgraph node interface
176 *****************************************************************************
177 *****************************************************************************/
180 * Netgraph node constructor. Do not allow to create node of this type.
184 ng_btsocket_l2cap_raw_node_constructor(node_p node)
187 } /* ng_btsocket_l2cap_raw_node_constructor */
190 * Do local shutdown processing. Let old node go and create new fresh one.
194 ng_btsocket_l2cap_raw_node_shutdown(node_p node)
200 /* Create new node */
201 error = ng_make_node_common(&typestruct, &ng_btsocket_l2cap_raw_node);
203 NG_BTSOCKET_L2CAP_RAW_ALERT(
204 "%s: Could not create Netgraph node, error=%d\n", __func__, error);
206 ng_btsocket_l2cap_raw_node = NULL;
211 error = ng_name_node(ng_btsocket_l2cap_raw_node,
212 NG_BTSOCKET_L2CAP_RAW_NODE_TYPE);
214 NG_BTSOCKET_L2CAP_RAW_ALERT(
215 "%s: Could not name Netgraph node, error=%d\n", __func__, error);
217 NG_NODE_UNREF(ng_btsocket_l2cap_raw_node);
218 ng_btsocket_l2cap_raw_node = NULL;
224 } /* ng_btsocket_l2cap_raw_node_shutdown */
227 * We allow any hook to be connected to the node.
231 ng_btsocket_l2cap_raw_node_newhook(node_p node, hook_p hook, char const *name)
234 } /* ng_btsocket_l2cap_raw_node_newhook */
237 * Just say "YEP, that's OK by me!"
241 ng_btsocket_l2cap_raw_node_connect(hook_p hook)
243 NG_HOOK_SET_PRIVATE(hook, NULL);
244 NG_HOOK_REF(hook); /* Keep extra reference to the hook */
247 } /* ng_btsocket_l2cap_raw_node_connect */
250 * Hook disconnection. Schedule route cleanup task
254 ng_btsocket_l2cap_raw_node_disconnect(hook_p hook)
257 * If hook has private information than we must have this hook in
258 * the routing table and must schedule cleaning for the routing table.
259 * Otherwise hook was connected but we never got "hook_info" message,
260 * so we have never added this hook to the routing table and it save
264 if (NG_HOOK_PRIVATE(hook) != NULL)
265 return (ng_btsocket_l2cap_raw_wakeup_route_task());
267 NG_HOOK_UNREF(hook); /* Remove extra reference */
270 } /* ng_btsocket_l2cap_raw_node_disconnect */
273 * Process incoming messages
277 ng_btsocket_l2cap_raw_node_rcvmsg(node_p node, item_p item, hook_p hook)
279 struct ng_mesg *msg = NGI_MSG(item); /* item still has message */
282 if (msg != NULL && msg->header.typecookie == NGM_L2CAP_COOKIE) {
285 * NGM_L2CAP_NODE_HOOK_INFO is special message initiated by
286 * L2CAP layer. Ignore all other messages if they are not
287 * replies or token is zero
290 if (msg->header.cmd != NGM_L2CAP_NODE_HOOK_INFO) {
291 if (msg->header.token == 0 ||
292 !(msg->header.flags & NGF_RESP)) {
298 mtx_lock(&ng_btsocket_l2cap_raw_queue_mtx);
299 if (NG_BT_ITEMQ_FULL(&ng_btsocket_l2cap_raw_queue)) {
300 NG_BTSOCKET_L2CAP_RAW_ERR(
301 "%s: Input queue is full\n", __func__);
303 NG_BT_ITEMQ_DROP(&ng_btsocket_l2cap_raw_queue);
309 NGI_SET_HOOK(item, hook);
312 NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_l2cap_raw_queue, item);
313 error = ng_btsocket_l2cap_raw_wakeup_input_task();
315 mtx_unlock(&ng_btsocket_l2cap_raw_queue_mtx);
322 } /* ng_btsocket_l2cap_raw_node_rcvmsg */
325 * Receive data on a hook
329 ng_btsocket_l2cap_raw_node_rcvdata(hook_p hook, item_p item)
334 } /* ng_btsocket_l2cap_raw_node_rcvdata */
336 /*****************************************************************************
337 *****************************************************************************
339 *****************************************************************************
340 *****************************************************************************/
343 * L2CAP sockets input routine
347 ng_btsocket_l2cap_raw_input(void *context, int pending)
351 struct ng_mesg *msg = NULL;
354 mtx_lock(&ng_btsocket_l2cap_raw_queue_mtx);
355 NG_BT_ITEMQ_DEQUEUE(&ng_btsocket_l2cap_raw_queue, item);
356 mtx_unlock(&ng_btsocket_l2cap_raw_queue_mtx);
361 KASSERT((item->el_flags & NGQF_TYPE) == NGQF_MESG,
362 ("%s: invalid item type=%ld\n", __func__, (item->el_flags & NGQF_TYPE)));
364 NGI_GET_MSG(item, msg);
365 NGI_GET_HOOK(item, hook);
368 switch (msg->header.cmd) {
369 case NGM_L2CAP_NODE_HOOK_INFO: {
370 ng_btsocket_l2cap_rtentry_t *rt = NULL;
372 if (hook == NULL || NG_HOOK_NOT_VALID(hook) ||
373 msg->header.arglen != sizeof(bdaddr_t))
376 if (bcmp(msg->data, NG_HCI_BDADDR_ANY,
377 sizeof(bdaddr_t)) == 0)
380 rt = (ng_btsocket_l2cap_rtentry_t *)
381 NG_HOOK_PRIVATE(hook);
383 rt = malloc(sizeof(*rt),
384 M_NETGRAPH_BTSOCKET_L2CAP_RAW,
389 NG_HOOK_SET_PRIVATE(hook, rt);
391 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
393 LIST_INSERT_HEAD(&ng_btsocket_l2cap_raw_rt,
396 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
398 bcopy(msg->data, &rt->src, sizeof(rt->src));
401 NG_BTSOCKET_L2CAP_RAW_INFO(
402 "%s: Updating hook \"%s\", src bdaddr=%x:%x:%x:%x:%x:%x\n",
403 __func__, NG_HOOK_NAME(hook),
404 rt->src.b[5], rt->src.b[4], rt->src.b[3],
405 rt->src.b[2], rt->src.b[1], rt->src.b[0]);
407 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);
410 case NGM_L2CAP_NODE_GET_FLAGS:
411 case NGM_L2CAP_NODE_GET_DEBUG:
412 case NGM_L2CAP_NODE_GET_CON_LIST:
413 case NGM_L2CAP_NODE_GET_CHAN_LIST:
414 case NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO:
415 case NGM_L2CAP_L2CA_PING:
416 case NGM_L2CAP_L2CA_GET_INFO: {
417 ng_btsocket_l2cap_raw_pcb_p pcb = NULL;
419 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);
421 LIST_FOREACH(pcb,&ng_btsocket_l2cap_raw_sockets,next) {
422 mtx_lock(&pcb->pcb_mtx);
424 if (pcb->token == msg->header.token) {
428 mtx_unlock(&pcb->pcb_mtx);
432 mtx_unlock(&pcb->pcb_mtx);
435 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);
439 NG_BTSOCKET_L2CAP_RAW_WARN(
440 "%s: Unknown message, cmd=%d\n", __func__, msg->header.cmd);
445 NG_HOOK_UNREF(hook); /* remove extra reference */
447 NG_FREE_MSG(msg); /* Checks for msg != NULL */
449 } /* ng_btsocket_l2cap_raw_input */
452 * Route cleanup task. Gets scheduled when hook is disconnected. Here we
453 * will find all sockets that use "invalid" hook and disconnect them.
457 ng_btsocket_l2cap_raw_rtclean(void *context, int pending)
459 ng_btsocket_l2cap_raw_pcb_p pcb = NULL;
460 ng_btsocket_l2cap_rtentry_p rt = NULL;
463 * First disconnect all sockets that use "invalid" hook
466 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);
468 LIST_FOREACH(pcb, &ng_btsocket_l2cap_raw_sockets, next) {
469 mtx_lock(&pcb->pcb_mtx);
471 if (pcb->rt != NULL &&
472 pcb->rt->hook != NULL && NG_HOOK_NOT_VALID(pcb->rt->hook)) {
473 if (pcb->so != NULL &&
474 pcb->so->so_state & SS_ISCONNECTED)
475 soisdisconnected(pcb->so);
480 mtx_unlock(&pcb->pcb_mtx);
483 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);
486 * Now cleanup routing table
489 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
491 for (rt = LIST_FIRST(&ng_btsocket_l2cap_raw_rt); rt != NULL; ) {
492 ng_btsocket_l2cap_rtentry_p rt_next = LIST_NEXT(rt, next);
494 if (rt->hook != NULL && NG_HOOK_NOT_VALID(rt->hook)) {
495 LIST_REMOVE(rt, next);
497 NG_HOOK_SET_PRIVATE(rt->hook, NULL);
498 NG_HOOK_UNREF(rt->hook); /* Remove extra reference */
500 bzero(rt, sizeof(*rt));
501 free(rt, M_NETGRAPH_BTSOCKET_L2CAP_RAW);
507 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);
508 } /* ng_btsocket_l2cap_raw_rtclean */
511 * Initialize everything
515 ng_btsocket_l2cap_raw_init(void)
519 /* Skip initialization of globals for non-default instances. */
520 if (!IS_DEFAULT_VNET(curvnet))
523 ng_btsocket_l2cap_raw_node = NULL;
524 ng_btsocket_l2cap_raw_debug_level = NG_BTSOCKET_WARN_LEVEL;
525 ng_btsocket_l2cap_raw_ioctl_timeout = 5;
527 /* Register Netgraph node type */
528 error = ng_newtype(&typestruct);
530 NG_BTSOCKET_L2CAP_RAW_ALERT(
531 "%s: Could not register Netgraph node type, error=%d\n", __func__, error);
536 /* Create Netgrapg node */
537 error = ng_make_node_common(&typestruct, &ng_btsocket_l2cap_raw_node);
539 NG_BTSOCKET_L2CAP_RAW_ALERT(
540 "%s: Could not create Netgraph node, error=%d\n", __func__, error);
542 ng_btsocket_l2cap_raw_node = NULL;
547 error = ng_name_node(ng_btsocket_l2cap_raw_node,
548 NG_BTSOCKET_L2CAP_RAW_NODE_TYPE);
550 NG_BTSOCKET_L2CAP_RAW_ALERT(
551 "%s: Could not name Netgraph node, error=%d\n", __func__, error);
553 NG_NODE_UNREF(ng_btsocket_l2cap_raw_node);
554 ng_btsocket_l2cap_raw_node = NULL;
559 /* Create input queue */
560 NG_BT_ITEMQ_INIT(&ng_btsocket_l2cap_raw_queue, ifqmaxlen);
561 mtx_init(&ng_btsocket_l2cap_raw_queue_mtx,
562 "btsocks_l2cap_raw_queue_mtx", NULL, MTX_DEF);
563 TASK_INIT(&ng_btsocket_l2cap_raw_queue_task, 0,
564 ng_btsocket_l2cap_raw_input, NULL);
566 /* Create list of sockets */
567 LIST_INIT(&ng_btsocket_l2cap_raw_sockets);
568 mtx_init(&ng_btsocket_l2cap_raw_sockets_mtx,
569 "btsocks_l2cap_raw_sockets_mtx", NULL, MTX_DEF);
572 ng_btsocket_l2cap_raw_token = 0;
573 mtx_init(&ng_btsocket_l2cap_raw_token_mtx,
574 "btsocks_l2cap_raw_token_mtx", NULL, MTX_DEF);
577 LIST_INIT(&ng_btsocket_l2cap_raw_rt);
578 mtx_init(&ng_btsocket_l2cap_raw_rt_mtx,
579 "btsocks_l2cap_raw_rt_mtx", NULL, MTX_DEF);
580 TASK_INIT(&ng_btsocket_l2cap_raw_rt_task, 0,
581 ng_btsocket_l2cap_raw_rtclean, NULL);
582 } /* ng_btsocket_l2cap_raw_init */
585 * Abort connection on socket
589 ng_btsocket_l2cap_raw_abort(struct socket *so)
592 (void)ng_btsocket_l2cap_raw_disconnect(so);
593 } /* ng_btsocket_l2cap_raw_abort */
596 ng_btsocket_l2cap_raw_close(struct socket *so)
599 (void)ng_btsocket_l2cap_raw_disconnect(so);
600 } /* ng_btsocket_l2cap_raw_close */
603 * Create and attach new socket
607 ng_btsocket_l2cap_raw_attach(struct socket *so, int proto, struct thread *td)
609 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
615 if (ng_btsocket_l2cap_raw_node == NULL)
616 return (EPROTONOSUPPORT);
617 if (so->so_type != SOCK_RAW)
618 return (ESOCKTNOSUPPORT);
620 /* Reserve send and receive space if it is not reserved yet */
621 error = soreserve(so, NG_BTSOCKET_L2CAP_RAW_SENDSPACE,
622 NG_BTSOCKET_L2CAP_RAW_RECVSPACE);
626 /* Allocate the PCB */
627 pcb = malloc(sizeof(*pcb),
628 M_NETGRAPH_BTSOCKET_L2CAP_RAW, M_NOWAIT|M_ZERO);
632 /* Link the PCB and the socket */
633 so->so_pcb = (caddr_t) pcb;
636 if (priv_check(td, PRIV_NETBLUETOOTH_RAW) == 0)
637 pcb->flags |= NG_BTSOCKET_L2CAP_RAW_PRIVILEGED;
639 mtx_init(&pcb->pcb_mtx, "btsocks_l2cap_raw_pcb_mtx", NULL, MTX_DEF);
641 /* Add the PCB to the list */
642 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);
643 LIST_INSERT_HEAD(&ng_btsocket_l2cap_raw_sockets, pcb, next);
644 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);
647 } /* ng_btsocket_l2cap_raw_attach */
654 ng_btsocket_l2cap_raw_bind(struct socket *so, struct sockaddr *nam,
657 ng_btsocket_l2cap_raw_pcb_t *pcb = so2l2cap_raw_pcb(so);
658 struct sockaddr_l2cap *sa = (struct sockaddr_l2cap *) nam;
659 ng_btsocket_l2cap_rtentry_t *rt = NULL;
663 if (ng_btsocket_l2cap_raw_node == NULL)
668 if (sa->l2cap_family != AF_BLUETOOTH)
669 return (EAFNOSUPPORT);
670 if (sa->l2cap_len != sizeof(*sa))
673 if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY,
674 sizeof(sa->l2cap_bdaddr)) != 0) {
675 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
677 LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) {
678 if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
681 if (bcmp(&sa->l2cap_bdaddr, &rt->src,
682 sizeof(rt->src)) == 0)
686 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);
693 mtx_lock(&pcb->pcb_mtx);
694 bcopy(&sa->l2cap_bdaddr, &pcb->src, sizeof(pcb->src));
696 mtx_unlock(&pcb->pcb_mtx);
699 } /* ng_btsocket_l2cap_raw_bind */
706 ng_btsocket_l2cap_raw_connect(struct socket *so, struct sockaddr *nam,
709 ng_btsocket_l2cap_raw_pcb_t *pcb = so2l2cap_raw_pcb(so);
710 struct sockaddr_l2cap *sa = (struct sockaddr_l2cap *) nam;
711 ng_btsocket_l2cap_rtentry_t *rt = NULL;
716 if (ng_btsocket_l2cap_raw_node == NULL)
721 if (sa->l2cap_family != AF_BLUETOOTH)
722 return (EAFNOSUPPORT);
723 if (sa->l2cap_len != sizeof(*sa))
725 if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
728 mtx_lock(&pcb->pcb_mtx);
730 bcopy(&sa->l2cap_bdaddr, &pcb->dst, sizeof(pcb->dst));
732 if (bcmp(&pcb->src, &pcb->dst, sizeof(pcb->src)) == 0) {
733 mtx_unlock(&pcb->pcb_mtx);
735 return (EADDRNOTAVAIL);
739 * If there is route already - use it
742 if (pcb->rt != NULL) {
744 mtx_unlock(&pcb->pcb_mtx);
750 * Find the first hook that does not match specified destination address
753 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
755 LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) {
756 if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
759 if (bcmp(&pcb->dst, &rt->src, sizeof(rt->src)) != 0)
767 bcopy(&rt->src, &pcb->src, sizeof(pcb->src));
773 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);
774 mtx_unlock(&pcb->pcb_mtx);
777 } /* ng_btsocket_l2cap_raw_connect */
780 * Process ioctl's calls on socket
784 ng_btsocket_l2cap_raw_control(struct socket *so, u_long cmd, caddr_t data,
785 struct ifnet *ifp, struct thread *td)
787 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
788 struct ng_mesg *msg = NULL;
793 if (ng_btsocket_l2cap_raw_node == NULL)
796 mtx_lock(&pcb->pcb_mtx);
798 /* Check if we route info */
799 if (pcb->rt == NULL) {
800 mtx_unlock(&pcb->pcb_mtx);
801 return (EHOSTUNREACH);
804 /* Check if we have pending ioctl() */
805 if (pcb->token != 0) {
806 mtx_unlock(&pcb->pcb_mtx);
811 case SIOC_L2CAP_NODE_GET_FLAGS: {
812 struct ng_btsocket_l2cap_raw_node_flags *p =
813 (struct ng_btsocket_l2cap_raw_node_flags *) data;
815 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,
816 NGM_L2CAP_NODE_GET_FLAGS,
817 &p->flags, sizeof(p->flags));
820 case SIOC_L2CAP_NODE_GET_DEBUG: {
821 struct ng_btsocket_l2cap_raw_node_debug *p =
822 (struct ng_btsocket_l2cap_raw_node_debug *) data;
824 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,
825 NGM_L2CAP_NODE_GET_DEBUG,
826 &p->debug, sizeof(p->debug));
829 case SIOC_L2CAP_NODE_SET_DEBUG: {
830 struct ng_btsocket_l2cap_raw_node_debug *p =
831 (struct ng_btsocket_l2cap_raw_node_debug *) data;
833 if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)
834 error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook,
835 NGM_L2CAP_NODE_SET_DEBUG,
836 &p->debug, sizeof(p->debug));
841 case SIOC_L2CAP_NODE_GET_CON_LIST: {
842 struct ng_btsocket_l2cap_raw_con_list *p =
843 (struct ng_btsocket_l2cap_raw_con_list *) data;
844 ng_l2cap_node_con_list_ep *p1 = NULL;
845 ng_l2cap_node_con_ep *p2 = NULL;
847 if (p->num_connections == 0 ||
848 p->num_connections > NG_L2CAP_MAX_CON_NUM ||
849 p->connections == NULL) {
854 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_NODE_GET_CON_LIST,
860 ng_btsocket_l2cap_raw_get_token(&msg->header.token);
861 pcb->token = msg->header.token;
864 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
871 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
872 ng_btsocket_l2cap_raw_ioctl_timeout * hz);
878 if (pcb->msg != NULL &&
879 pcb->msg->header.cmd == NGM_L2CAP_NODE_GET_CON_LIST) {
880 /* Return data back to user space */
881 p1 = (ng_l2cap_node_con_list_ep *)(pcb->msg->data);
882 p2 = (ng_l2cap_node_con_ep *)(p1 + 1);
884 p->num_connections = min(p->num_connections,
885 p1->num_connections);
886 if (p->num_connections > 0)
887 error = copyout((caddr_t) p2,
888 (caddr_t) p->connections,
889 p->num_connections * sizeof(*p2));
893 NG_FREE_MSG(pcb->msg); /* checks for != NULL */
896 case SIOC_L2CAP_NODE_GET_CHAN_LIST: {
897 struct ng_btsocket_l2cap_raw_chan_list *p =
898 (struct ng_btsocket_l2cap_raw_chan_list *) data;
899 ng_l2cap_node_chan_list_ep *p1 = NULL;
900 ng_l2cap_node_chan_ep *p2 = NULL;
902 if (p->num_channels == 0 ||
903 p->num_channels > NG_L2CAP_MAX_CHAN_NUM ||
904 p->channels == NULL) {
909 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE,
910 NGM_L2CAP_NODE_GET_CHAN_LIST, 0, M_NOWAIT);
915 ng_btsocket_l2cap_raw_get_token(&msg->header.token);
916 pcb->token = msg->header.token;
919 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
926 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
927 ng_btsocket_l2cap_raw_ioctl_timeout * hz);
933 if (pcb->msg != NULL &&
934 pcb->msg->header.cmd == NGM_L2CAP_NODE_GET_CHAN_LIST) {
935 /* Return data back to user space */
936 p1 = (ng_l2cap_node_chan_list_ep *)(pcb->msg->data);
937 p2 = (ng_l2cap_node_chan_ep *)(p1 + 1);
939 p->num_channels = min(p->num_channels,
941 if (p->num_channels > 0)
942 error = copyout((caddr_t) p2,
943 (caddr_t) p->channels,
944 p->num_channels * sizeof(*p2));
948 NG_FREE_MSG(pcb->msg); /* checks for != NULL */
951 case SIOC_L2CAP_L2CA_PING: {
952 struct ng_btsocket_l2cap_raw_ping *p =
953 (struct ng_btsocket_l2cap_raw_ping *) data;
954 ng_l2cap_l2ca_ping_ip *ip = NULL;
955 ng_l2cap_l2ca_ping_op *op = NULL;
957 if ((p->echo_size != 0 && p->echo_data == NULL) ||
958 p->echo_size > NG_L2CAP_MAX_ECHO_SIZE) {
963 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE,
964 NGM_L2CAP_L2CA_PING, sizeof(*ip) + p->echo_size,
970 ng_btsocket_l2cap_raw_get_token(&msg->header.token);
971 pcb->token = msg->header.token;
974 ip = (ng_l2cap_l2ca_ping_ip *)(msg->data);
975 bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr));
976 ip->echo_size = p->echo_size;
978 if (ip->echo_size > 0) {
979 error = copyin(p->echo_data, ip + 1, p->echo_size);
987 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
994 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
995 bluetooth_l2cap_rtx_timeout());
1001 if (pcb->msg != NULL &&
1002 pcb->msg->header.cmd == NGM_L2CAP_L2CA_PING) {
1003 /* Return data back to the user space */
1004 op = (ng_l2cap_l2ca_ping_op *)(pcb->msg->data);
1005 p->result = op->result;
1006 p->echo_size = min(p->echo_size, op->echo_size);
1008 if (p->echo_size > 0)
1009 error = copyout(op + 1, p->echo_data,
1014 NG_FREE_MSG(pcb->msg); /* checks for != NULL */
1017 case SIOC_L2CAP_L2CA_GET_INFO: {
1018 struct ng_btsocket_l2cap_raw_get_info *p =
1019 (struct ng_btsocket_l2cap_raw_get_info *) data;
1020 ng_l2cap_l2ca_get_info_ip *ip = NULL;
1021 ng_l2cap_l2ca_get_info_op *op = NULL;
1023 if (!(pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)) {
1028 if (p->info_size != 0 && p->info_data == NULL) {
1033 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE,
1034 NGM_L2CAP_L2CA_GET_INFO, sizeof(*ip) + p->info_size,
1040 ng_btsocket_l2cap_raw_get_token(&msg->header.token);
1041 pcb->token = msg->header.token;
1044 ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data);
1045 bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr));
1046 ip->info_type = p->info_type;
1048 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
1055 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
1056 bluetooth_l2cap_rtx_timeout());
1062 if (pcb->msg != NULL &&
1063 pcb->msg->header.cmd == NGM_L2CAP_L2CA_GET_INFO) {
1064 /* Return data back to the user space */
1065 op = (ng_l2cap_l2ca_get_info_op *)(pcb->msg->data);
1066 p->result = op->result;
1067 p->info_size = min(p->info_size, op->info_size);
1069 if (p->info_size > 0)
1070 error = copyout(op + 1, p->info_data,
1075 NG_FREE_MSG(pcb->msg); /* checks for != NULL */
1078 case SIOC_L2CAP_NODE_GET_AUTO_DISCON_TIMO: {
1079 struct ng_btsocket_l2cap_raw_auto_discon_timo *p =
1080 (struct ng_btsocket_l2cap_raw_auto_discon_timo *) data;
1082 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,
1083 NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO,
1084 &p->timeout, sizeof(p->timeout));
1087 case SIOC_L2CAP_NODE_SET_AUTO_DISCON_TIMO: {
1088 struct ng_btsocket_l2cap_raw_auto_discon_timo *p =
1089 (struct ng_btsocket_l2cap_raw_auto_discon_timo *) data;
1091 if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)
1092 error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook,
1093 NGM_L2CAP_NODE_SET_AUTO_DISCON_TIMO,
1094 &p->timeout, sizeof(p->timeout));
1104 mtx_unlock(&pcb->pcb_mtx);
1107 } /* ng_btsocket_l2cap_raw_control */
1110 * Detach and destroy socket
1114 ng_btsocket_l2cap_raw_detach(struct socket *so)
1116 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
1118 KASSERT(pcb != NULL, ("nt_btsocket_l2cap_raw_detach: pcb == NULL"));
1119 if (ng_btsocket_l2cap_raw_node == NULL)
1122 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);
1123 mtx_lock(&pcb->pcb_mtx);
1125 LIST_REMOVE(pcb, next);
1127 mtx_unlock(&pcb->pcb_mtx);
1128 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);
1130 mtx_destroy(&pcb->pcb_mtx);
1132 bzero(pcb, sizeof(*pcb));
1133 free(pcb, M_NETGRAPH_BTSOCKET_L2CAP_RAW);
1136 } /* ng_btsocket_l2cap_raw_detach */
1143 ng_btsocket_l2cap_raw_disconnect(struct socket *so)
1145 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
1149 if (ng_btsocket_l2cap_raw_node == NULL)
1152 mtx_lock(&pcb->pcb_mtx);
1154 soisdisconnected(so);
1155 mtx_unlock(&pcb->pcb_mtx);
1158 } /* ng_btsocket_l2cap_raw_disconnect */
1165 ng_btsocket_l2cap_raw_peeraddr(struct socket *so, struct sockaddr **nam)
1167 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
1168 struct sockaddr_l2cap sa;
1172 if (ng_btsocket_l2cap_raw_node == NULL)
1175 mtx_lock(&pcb->pcb_mtx);
1176 bcopy(&pcb->dst, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr));
1177 mtx_unlock(&pcb->pcb_mtx);
1180 sa.l2cap_len = sizeof(sa);
1181 sa.l2cap_family = AF_BLUETOOTH;
1183 *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT);
1185 return ((*nam == NULL)? ENOMEM : 0);
1186 } /* ng_btsocket_l2cap_raw_peeraddr */
1189 * Send data to socket
1193 ng_btsocket_l2cap_raw_send(struct socket *so, int flags, struct mbuf *m,
1194 struct sockaddr *nam, struct mbuf *control, struct thread *td)
1196 NG_FREE_M(m); /* Checks for m != NULL */
1199 return (EOPNOTSUPP);
1200 } /* ng_btsocket_l2cap_raw_send */
1203 * Get socket address
1207 ng_btsocket_l2cap_raw_sockaddr(struct socket *so, struct sockaddr **nam)
1209 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
1210 struct sockaddr_l2cap sa;
1214 if (ng_btsocket_l2cap_raw_node == NULL)
1217 mtx_lock(&pcb->pcb_mtx);
1218 bcopy(&pcb->src, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr));
1219 mtx_unlock(&pcb->pcb_mtx);
1222 sa.l2cap_len = sizeof(sa);
1223 sa.l2cap_family = AF_BLUETOOTH;
1225 *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT);
1227 return ((*nam == NULL)? ENOMEM : 0);
1228 } /* ng_btsocket_l2cap_raw_sockaddr */
1235 ng_btsocket_l2cap_raw_get_token(u_int32_t *token)
1237 mtx_lock(&ng_btsocket_l2cap_raw_token_mtx);
1239 if (++ ng_btsocket_l2cap_raw_token == 0)
1240 ng_btsocket_l2cap_raw_token = 1;
1242 *token = ng_btsocket_l2cap_raw_token;
1244 mtx_unlock(&ng_btsocket_l2cap_raw_token_mtx);
1245 } /* ng_btsocket_l2cap_raw_get_token */
1248 * Send Netgraph message to the node - do not expect reply
1252 ng_btsocket_l2cap_raw_send_ngmsg(hook_p hook, int cmd, void *arg, int arglen)
1254 struct ng_mesg *msg = NULL;
1257 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, arglen, M_NOWAIT);
1261 if (arg != NULL && arglen > 0)
1262 bcopy(arg, msg->data, arglen);
1264 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, hook, 0);
1267 } /* ng_btsocket_l2cap_raw_send_ngmsg */
1270 * Send Netgraph message to the node (no data) and wait for reply
1274 ng_btsocket_l2cap_raw_send_sync_ngmsg(ng_btsocket_l2cap_raw_pcb_p pcb,
1275 int cmd, void *rsp, int rsplen)
1277 struct ng_mesg *msg = NULL;
1280 mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1282 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, 0, M_NOWAIT);
1286 ng_btsocket_l2cap_raw_get_token(&msg->header.token);
1287 pcb->token = msg->header.token;
1290 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
1297 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
1298 ng_btsocket_l2cap_raw_ioctl_timeout * hz);
1304 if (pcb->msg != NULL && pcb->msg->header.cmd == cmd)
1305 bcopy(pcb->msg->data, rsp, rsplen);
1309 NG_FREE_MSG(pcb->msg); /* checks for != NULL */
1312 } /* ng_btsocket_l2cap_raw_send_sync_ngmsg */