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 $
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/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>
53 #include "ng_message.h"
55 #include "bluetooth/include/ng_bluetooth.h"
56 #include "bluetooth/include/ng_hci.h"
57 #include "bluetooth/include/ng_l2cap.h"
58 #include "bluetooth/include/ng_btsocket.h"
59 #include "bluetooth/include/ng_btsocket_l2cap.h"
62 #ifdef NG_SEPARATE_MALLOC
63 MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_L2CAP_RAW, "netgraph_btsocks_l2cap_raw",
64 "Netgraph Bluetooth raw L2CAP sockets");
66 #define M_NETGRAPH_BTSOCKET_L2CAP_RAW M_NETGRAPH
67 #endif /* NG_SEPARATE_MALLOC */
69 /* Netgraph node methods */
70 static ng_constructor_t ng_btsocket_l2cap_raw_node_constructor;
71 static ng_rcvmsg_t ng_btsocket_l2cap_raw_node_rcvmsg;
72 static ng_shutdown_t ng_btsocket_l2cap_raw_node_shutdown;
73 static ng_newhook_t ng_btsocket_l2cap_raw_node_newhook;
74 static ng_connect_t ng_btsocket_l2cap_raw_node_connect;
75 static ng_rcvdata_t ng_btsocket_l2cap_raw_node_rcvdata;
76 static ng_disconnect_t ng_btsocket_l2cap_raw_node_disconnect;
78 static void ng_btsocket_l2cap_raw_input (void *, int);
79 static void ng_btsocket_l2cap_raw_rtclean (void *, int);
80 static void ng_btsocket_l2cap_raw_get_token (u_int32_t *);
82 static int ng_btsocket_l2cap_raw_send_ngmsg
83 (hook_p, int, void *, int);
84 static int ng_btsocket_l2cap_raw_send_sync_ngmsg
85 (ng_btsocket_l2cap_raw_pcb_p, int, void *, int);
87 #define ng_btsocket_l2cap_raw_wakeup_input_task() \
88 taskqueue_enqueue(taskqueue_swi, &ng_btsocket_l2cap_raw_queue_task)
90 #define ng_btsocket_l2cap_raw_wakeup_route_task() \
91 taskqueue_enqueue(taskqueue_swi, &ng_btsocket_l2cap_raw_rt_task)
93 /* Netgraph type descriptor */
94 static struct ng_type typestruct = {
95 .version = NG_ABI_VERSION,
96 .name = NG_BTSOCKET_L2CAP_RAW_NODE_TYPE,
97 .constructor = ng_btsocket_l2cap_raw_node_constructor,
98 .rcvmsg = ng_btsocket_l2cap_raw_node_rcvmsg,
99 .shutdown = ng_btsocket_l2cap_raw_node_shutdown,
100 .newhook = ng_btsocket_l2cap_raw_node_newhook,
101 .connect = ng_btsocket_l2cap_raw_node_connect,
102 .rcvdata = ng_btsocket_l2cap_raw_node_rcvdata,
103 .disconnect = ng_btsocket_l2cap_raw_node_disconnect,
107 extern int ifqmaxlen;
108 static u_int32_t ng_btsocket_l2cap_raw_debug_level;
109 static u_int32_t ng_btsocket_l2cap_raw_ioctl_timeout;
110 static node_p ng_btsocket_l2cap_raw_node;
111 static struct ng_bt_itemq ng_btsocket_l2cap_raw_queue;
112 static struct mtx ng_btsocket_l2cap_raw_queue_mtx;
113 static struct task ng_btsocket_l2cap_raw_queue_task;
114 static LIST_HEAD(, ng_btsocket_l2cap_raw_pcb) ng_btsocket_l2cap_raw_sockets;
115 static struct mtx ng_btsocket_l2cap_raw_sockets_mtx;
116 static u_int32_t ng_btsocket_l2cap_raw_token;
117 static struct mtx ng_btsocket_l2cap_raw_token_mtx;
118 static LIST_HEAD(, ng_btsocket_l2cap_rtentry) ng_btsocket_l2cap_raw_rt;
119 static struct mtx ng_btsocket_l2cap_raw_rt_mtx;
120 static struct task ng_btsocket_l2cap_raw_rt_task;
123 SYSCTL_DECL(_net_bluetooth_l2cap_sockets);
124 SYSCTL_NODE(_net_bluetooth_l2cap_sockets, OID_AUTO, raw, CTLFLAG_RW,
125 0, "Bluetooth raw L2CAP sockets family");
126 SYSCTL_INT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, debug_level,
128 &ng_btsocket_l2cap_raw_debug_level, NG_BTSOCKET_WARN_LEVEL,
129 "Bluetooth raw L2CAP sockets debug level");
130 SYSCTL_INT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, ioctl_timeout,
132 &ng_btsocket_l2cap_raw_ioctl_timeout, 5,
133 "Bluetooth raw L2CAP sockets ioctl timeout");
134 SYSCTL_INT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, queue_len,
136 &ng_btsocket_l2cap_raw_queue.len, 0,
137 "Bluetooth raw L2CAP sockets input queue length");
138 SYSCTL_INT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, queue_maxlen,
140 &ng_btsocket_l2cap_raw_queue.maxlen, 0,
141 "Bluetooth raw L2CAP sockets input queue max. length");
142 SYSCTL_INT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, queue_drops,
144 &ng_btsocket_l2cap_raw_queue.drops, 0,
145 "Bluetooth raw L2CAP sockets input queue drops");
148 #define NG_BTSOCKET_L2CAP_RAW_INFO \
149 if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_INFO_LEVEL) \
152 #define NG_BTSOCKET_L2CAP_RAW_WARN \
153 if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_WARN_LEVEL) \
156 #define NG_BTSOCKET_L2CAP_RAW_ERR \
157 if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_ERR_LEVEL) \
160 #define NG_BTSOCKET_L2CAP_RAW_ALERT \
161 if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_ALERT_LEVEL) \
164 /*****************************************************************************
165 *****************************************************************************
166 ** Netgraph node interface
167 *****************************************************************************
168 *****************************************************************************/
171 * Netgraph node constructor. Do not allow to create node of this type.
175 ng_btsocket_l2cap_raw_node_constructor(node_p node)
178 } /* ng_btsocket_l2cap_raw_node_constructor */
181 * Do local shutdown processing. Let old node go and create new fresh one.
185 ng_btsocket_l2cap_raw_node_shutdown(node_p node)
191 /* Create new node */
192 error = ng_make_node_common(&typestruct, &ng_btsocket_l2cap_raw_node);
194 NG_BTSOCKET_L2CAP_RAW_ALERT(
195 "%s: Could not create Netgraph node, error=%d\n", __func__, error);
197 ng_btsocket_l2cap_raw_node = NULL;
202 error = ng_name_node(ng_btsocket_l2cap_raw_node,
203 NG_BTSOCKET_L2CAP_RAW_NODE_TYPE);
205 NG_BTSOCKET_L2CAP_RAW_ALERT(
206 "%s: Could not name Netgraph node, error=%d\n", __func__, error);
208 NG_NODE_UNREF(ng_btsocket_l2cap_raw_node);
209 ng_btsocket_l2cap_raw_node = NULL;
215 } /* ng_btsocket_l2cap_raw_node_shutdown */
218 * We allow any hook to be connected to the node.
222 ng_btsocket_l2cap_raw_node_newhook(node_p node, hook_p hook, char const *name)
225 } /* ng_btsocket_l2cap_raw_node_newhook */
228 * Just say "YEP, that's OK by me!"
232 ng_btsocket_l2cap_raw_node_connect(hook_p hook)
234 NG_HOOK_SET_PRIVATE(hook, NULL);
235 NG_HOOK_REF(hook); /* Keep extra reference to the hook */
238 } /* ng_btsocket_l2cap_raw_node_connect */
241 * Hook disconnection. Schedule route cleanup task
245 ng_btsocket_l2cap_raw_node_disconnect(hook_p hook)
248 * If hook has private information than we must have this hook in
249 * the routing table and must schedule cleaning for the routing table.
250 * Otherwise hook was connected but we never got "hook_info" message,
251 * so we have never added this hook to the routing table and it save
255 if (NG_HOOK_PRIVATE(hook) != NULL)
256 return (ng_btsocket_l2cap_raw_wakeup_route_task());
258 NG_HOOK_UNREF(hook); /* Remove extra reference */
261 } /* ng_btsocket_l2cap_raw_node_disconnect */
264 * Process incoming messages
268 ng_btsocket_l2cap_raw_node_rcvmsg(node_p node, item_p item, hook_p hook)
270 struct ng_mesg *msg = NGI_MSG(item); /* item still has message */
273 if (msg != NULL && msg->header.typecookie == NGM_L2CAP_COOKIE) {
276 * NGM_L2CAP_NODE_HOOK_INFO is special message initiated by
277 * L2CAP layer. Ignore all other messages if they are not
278 * replies or token is zero
281 if (msg->header.cmd != NGM_L2CAP_NODE_HOOK_INFO) {
282 if (msg->header.token == 0 ||
283 !(msg->header.flags & NGF_RESP)) {
289 mtx_lock(&ng_btsocket_l2cap_raw_queue_mtx);
290 if (NG_BT_ITEMQ_FULL(&ng_btsocket_l2cap_raw_queue)) {
291 NG_BTSOCKET_L2CAP_RAW_ERR(
292 "%s: Input queue is full\n", __func__);
294 NG_BT_ITEMQ_DROP(&ng_btsocket_l2cap_raw_queue);
300 NGI_SET_HOOK(item, hook);
303 NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_l2cap_raw_queue, item);
304 error = ng_btsocket_l2cap_raw_wakeup_input_task();
306 mtx_unlock(&ng_btsocket_l2cap_raw_queue_mtx);
313 } /* ng_btsocket_l2cap_raw_node_rcvmsg */
316 * Receive data on a hook
320 ng_btsocket_l2cap_raw_node_rcvdata(hook_p hook, item_p item)
325 } /* ng_btsocket_l2cap_raw_node_rcvdata */
327 /*****************************************************************************
328 *****************************************************************************
330 *****************************************************************************
331 *****************************************************************************/
334 * L2CAP sockets input routine
338 ng_btsocket_l2cap_raw_input(void *context, int pending)
342 struct ng_mesg *msg = NULL;
345 mtx_lock(&ng_btsocket_l2cap_raw_queue_mtx);
346 NG_BT_ITEMQ_DEQUEUE(&ng_btsocket_l2cap_raw_queue, item);
347 mtx_unlock(&ng_btsocket_l2cap_raw_queue_mtx);
352 KASSERT((item->el_flags & NGQF_TYPE) == NGQF_MESG,
353 ("%s: invalid item type=%ld\n", __func__, (item->el_flags & NGQF_TYPE)));
355 NGI_GET_MSG(item, msg);
356 NGI_GET_HOOK(item, hook);
359 switch (msg->header.cmd) {
360 case NGM_L2CAP_NODE_HOOK_INFO: {
361 ng_btsocket_l2cap_rtentry_t *rt = NULL;
363 if (hook == NULL || NG_HOOK_NOT_VALID(hook) ||
364 msg->header.arglen != sizeof(bdaddr_t))
367 if (bcmp(msg->data, NG_HCI_BDADDR_ANY,
368 sizeof(bdaddr_t)) == 0)
371 rt = (ng_btsocket_l2cap_rtentry_t *)
372 NG_HOOK_PRIVATE(hook);
374 rt = kmalloc(sizeof(*rt),
375 M_NETGRAPH_BTSOCKET_L2CAP_RAW,
376 M_WAITOK | M_NULLOK | M_ZERO);
380 NG_HOOK_SET_PRIVATE(hook, rt);
382 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
384 LIST_INSERT_HEAD(&ng_btsocket_l2cap_raw_rt,
387 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
389 bcopy(msg->data, &rt->src, sizeof(rt->src));
392 NG_BTSOCKET_L2CAP_RAW_INFO(
393 "%s: Updating hook \"%s\", src bdaddr=%x:%x:%x:%x:%x:%x\n",
394 __func__, NG_HOOK_NAME(hook),
395 rt->src.b[5], rt->src.b[4], rt->src.b[3],
396 rt->src.b[2], rt->src.b[1], rt->src.b[0]);
398 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);
401 case NGM_L2CAP_NODE_GET_FLAGS:
402 case NGM_L2CAP_NODE_GET_DEBUG:
403 case NGM_L2CAP_NODE_GET_CON_LIST:
404 case NGM_L2CAP_NODE_GET_CHAN_LIST:
405 case NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO:
406 case NGM_L2CAP_L2CA_PING:
407 case NGM_L2CAP_L2CA_GET_INFO: {
408 ng_btsocket_l2cap_raw_pcb_p pcb = NULL;
410 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);
412 LIST_FOREACH(pcb,&ng_btsocket_l2cap_raw_sockets,next) {
413 mtx_lock(&pcb->pcb_mtx);
415 if (pcb->token == msg->header.token) {
419 mtx_unlock(&pcb->pcb_mtx);
423 mtx_unlock(&pcb->pcb_mtx);
426 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);
430 NG_BTSOCKET_L2CAP_RAW_WARN(
431 "%s: Unknown message, cmd=%d\n", __func__, msg->header.cmd);
436 NG_HOOK_UNREF(hook); /* remove extra reference */
438 NG_FREE_MSG(msg); /* Checks for msg != NULL */
440 } /* ng_btsocket_l2cap_raw_input */
443 * Route cleanup task. Gets scheduled when hook is disconnected. Here we
444 * will find all sockets that use "invalid" hook and disconnect them.
448 ng_btsocket_l2cap_raw_rtclean(void *context, int pending)
450 ng_btsocket_l2cap_raw_pcb_p pcb = NULL;
451 ng_btsocket_l2cap_rtentry_p rt = NULL;
454 * First disconnect all sockets that use "invalid" hook
457 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);
459 LIST_FOREACH(pcb, &ng_btsocket_l2cap_raw_sockets, next) {
460 mtx_lock(&pcb->pcb_mtx);
462 if (pcb->rt != NULL &&
463 pcb->rt->hook != NULL && NG_HOOK_NOT_VALID(pcb->rt->hook)) {
464 if (pcb->so != NULL &&
465 pcb->so->so_state & SS_ISCONNECTED)
466 soisdisconnected(pcb->so);
471 mtx_unlock(&pcb->pcb_mtx);
474 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);
477 * Now cleanup routing table
480 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
482 for (rt = LIST_FIRST(&ng_btsocket_l2cap_raw_rt); rt != NULL; ) {
483 ng_btsocket_l2cap_rtentry_p rt_next = LIST_NEXT(rt, next);
485 if (rt->hook != NULL && NG_HOOK_NOT_VALID(rt->hook)) {
486 LIST_REMOVE(rt, next);
488 NG_HOOK_SET_PRIVATE(rt->hook, NULL);
489 NG_HOOK_UNREF(rt->hook); /* Remove extra reference */
491 bzero(rt, sizeof(*rt));
492 kfree(rt, M_NETGRAPH_BTSOCKET_L2CAP_RAW);
498 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);
499 } /* ng_btsocket_l2cap_raw_rtclean */
502 * Initialize everything
506 ng_btsocket_l2cap_raw_init(void)
510 ng_btsocket_l2cap_raw_node = NULL;
511 ng_btsocket_l2cap_raw_debug_level = NG_BTSOCKET_WARN_LEVEL;
512 ng_btsocket_l2cap_raw_ioctl_timeout = 5;
514 /* Register Netgraph node type */
515 error = ng_newtype(&typestruct);
517 NG_BTSOCKET_L2CAP_RAW_ALERT(
518 "%s: Could not register Netgraph node type, error=%d\n", __func__, error);
523 /* Create Netgrapg node */
524 error = ng_make_node_common(&typestruct, &ng_btsocket_l2cap_raw_node);
526 NG_BTSOCKET_L2CAP_RAW_ALERT(
527 "%s: Could not create Netgraph node, error=%d\n", __func__, error);
529 ng_btsocket_l2cap_raw_node = NULL;
534 error = ng_name_node(ng_btsocket_l2cap_raw_node,
535 NG_BTSOCKET_L2CAP_RAW_NODE_TYPE);
537 NG_BTSOCKET_L2CAP_RAW_ALERT(
538 "%s: Could not name Netgraph node, error=%d\n", __func__, error);
540 NG_NODE_UNREF(ng_btsocket_l2cap_raw_node);
541 ng_btsocket_l2cap_raw_node = NULL;
546 /* Create input queue */
547 NG_BT_ITEMQ_INIT(&ng_btsocket_l2cap_raw_queue, ifqmaxlen);
548 mtx_init(&ng_btsocket_l2cap_raw_queue_mtx,
549 "btsocks_l2cap_raw_queue_mtx", NULL, MTX_DEF);
550 TASK_INIT(&ng_btsocket_l2cap_raw_queue_task, 0,
551 ng_btsocket_l2cap_raw_input, NULL);
553 /* Create list of sockets */
554 LIST_INIT(&ng_btsocket_l2cap_raw_sockets);
555 mtx_init(&ng_btsocket_l2cap_raw_sockets_mtx,
556 "btsocks_l2cap_raw_sockets_mtx", NULL, MTX_DEF);
559 ng_btsocket_l2cap_raw_token = 0;
560 mtx_init(&ng_btsocket_l2cap_raw_token_mtx,
561 "btsocks_l2cap_raw_token_mtx", NULL, MTX_DEF);
564 LIST_INIT(&ng_btsocket_l2cap_raw_rt);
565 mtx_init(&ng_btsocket_l2cap_raw_rt_mtx,
566 "btsocks_l2cap_raw_rt_mtx", NULL, MTX_DEF);
567 TASK_INIT(&ng_btsocket_l2cap_raw_rt_task, 0,
568 ng_btsocket_l2cap_raw_rtclean, NULL);
569 } /* ng_btsocket_l2cap_raw_init */
572 * Abort connection on socket
576 ng_btsocket_l2cap_raw_abort(struct socket *so)
579 (void)ng_btsocket_l2cap_raw_disconnect(so);
580 } /* ng_btsocket_l2cap_raw_abort */
583 ng_btsocket_l2cap_raw_close(struct socket *so)
586 (void)ng_btsocket_l2cap_raw_disconnect(so);
587 } /* ng_btsocket_l2cap_raw_close */
590 * Create and attach new socket
594 ng_btsocket_l2cap_raw_attach(struct socket *so, int proto, struct thread *td)
596 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
602 if (ng_btsocket_l2cap_raw_node == NULL)
603 return (EPROTONOSUPPORT);
604 if (so->so_type != SOCK_RAW)
605 return (ESOCKTNOSUPPORT);
607 /* Reserve send and receive space if it is not reserved yet */
608 error = soreserve(so, NG_BTSOCKET_L2CAP_RAW_SENDSPACE,
609 NG_BTSOCKET_L2CAP_RAW_RECVSPACE);
613 /* Allocate the PCB */
614 pcb = kmalloc(sizeof(*pcb), M_NETGRAPH_BTSOCKET_L2CAP_RAW,
615 M_WAITOK | M_NULLOK | M_ZERO);
619 /* Link the PCB and the socket */
620 so->so_pcb = (caddr_t) pcb;
623 if (priv_check(td, PRIV_NETBLUETOOTH_RAW) == 0)
624 pcb->flags |= NG_BTSOCKET_L2CAP_RAW_PRIVILEGED;
626 mtx_init(&pcb->pcb_mtx, "btsocks_l2cap_raw_pcb_mtx", NULL, MTX_DEF);
628 /* Add the PCB to the list */
629 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);
630 LIST_INSERT_HEAD(&ng_btsocket_l2cap_raw_sockets, pcb, next);
631 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);
634 } /* ng_btsocket_l2cap_raw_attach */
641 ng_btsocket_l2cap_raw_bind(struct socket *so, struct sockaddr *nam,
644 ng_btsocket_l2cap_raw_pcb_t *pcb = so2l2cap_raw_pcb(so);
645 struct sockaddr_l2cap *sa = (struct sockaddr_l2cap *) nam;
646 ng_btsocket_l2cap_rtentry_t *rt = NULL;
650 if (ng_btsocket_l2cap_raw_node == NULL)
655 if (sa->l2cap_family != AF_BLUETOOTH)
656 return (EAFNOSUPPORT);
657 if (sa->l2cap_len != sizeof(*sa))
660 if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY,
661 sizeof(sa->l2cap_bdaddr)) != 0) {
662 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
664 LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) {
665 if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
668 if (bcmp(&sa->l2cap_bdaddr, &rt->src,
669 sizeof(rt->src)) == 0)
673 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);
680 mtx_lock(&pcb->pcb_mtx);
681 bcopy(&sa->l2cap_bdaddr, &pcb->src, sizeof(pcb->src));
683 mtx_unlock(&pcb->pcb_mtx);
686 } /* ng_btsocket_l2cap_raw_bind */
693 ng_btsocket_l2cap_raw_connect(struct socket *so, struct sockaddr *nam,
696 ng_btsocket_l2cap_raw_pcb_t *pcb = so2l2cap_raw_pcb(so);
697 struct sockaddr_l2cap *sa = (struct sockaddr_l2cap *) nam;
698 ng_btsocket_l2cap_rtentry_t *rt = NULL;
703 if (ng_btsocket_l2cap_raw_node == NULL)
708 if (sa->l2cap_family != AF_BLUETOOTH)
709 return (EAFNOSUPPORT);
710 if (sa->l2cap_len != sizeof(*sa))
712 if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
715 mtx_lock(&pcb->pcb_mtx);
717 bcopy(&sa->l2cap_bdaddr, &pcb->dst, sizeof(pcb->dst));
719 if (bcmp(&pcb->src, &pcb->dst, sizeof(pcb->src)) == 0) {
720 mtx_unlock(&pcb->pcb_mtx);
722 return (EADDRNOTAVAIL);
726 * If there is route already - use it
729 if (pcb->rt != NULL) {
731 mtx_unlock(&pcb->pcb_mtx);
737 * Find the first hook that does not match specified destination address
740 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
742 LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) {
743 if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
746 if (bcmp(&pcb->dst, &rt->src, sizeof(rt->src)) != 0)
754 bcopy(&rt->src, &pcb->src, sizeof(pcb->src));
760 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);
761 mtx_unlock(&pcb->pcb_mtx);
764 } /* ng_btsocket_l2cap_raw_connect */
767 * Process ioctl's calls on socket
771 ng_btsocket_l2cap_raw_control(struct socket *so, u_long cmd, caddr_t data,
772 struct ifnet *ifp, struct thread *td)
774 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
775 struct ng_mesg *msg = NULL;
780 if (ng_btsocket_l2cap_raw_node == NULL)
783 mtx_lock(&pcb->pcb_mtx);
785 /* Check if we route info */
786 if (pcb->rt == NULL) {
787 mtx_unlock(&pcb->pcb_mtx);
788 return (EHOSTUNREACH);
791 /* Check if we have pending ioctl() */
792 if (pcb->token != 0) {
793 mtx_unlock(&pcb->pcb_mtx);
798 case SIOC_L2CAP_NODE_GET_FLAGS: {
799 struct ng_btsocket_l2cap_raw_node_flags *p =
800 (struct ng_btsocket_l2cap_raw_node_flags *) data;
802 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,
803 NGM_L2CAP_NODE_GET_FLAGS,
804 &p->flags, sizeof(p->flags));
807 case SIOC_L2CAP_NODE_GET_DEBUG: {
808 struct ng_btsocket_l2cap_raw_node_debug *p =
809 (struct ng_btsocket_l2cap_raw_node_debug *) data;
811 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,
812 NGM_L2CAP_NODE_GET_DEBUG,
813 &p->debug, sizeof(p->debug));
816 case SIOC_L2CAP_NODE_SET_DEBUG: {
817 struct ng_btsocket_l2cap_raw_node_debug *p =
818 (struct ng_btsocket_l2cap_raw_node_debug *) data;
820 if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)
821 error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook,
822 NGM_L2CAP_NODE_SET_DEBUG,
823 &p->debug, sizeof(p->debug));
828 case SIOC_L2CAP_NODE_GET_CON_LIST: {
829 struct ng_btsocket_l2cap_raw_con_list *p =
830 (struct ng_btsocket_l2cap_raw_con_list *) data;
831 ng_l2cap_node_con_list_ep *p1 = NULL;
832 ng_l2cap_node_con_ep *p2 = NULL;
834 if (p->num_connections == 0 ||
835 p->num_connections > NG_L2CAP_MAX_CON_NUM ||
836 p->connections == NULL) {
841 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_NODE_GET_CON_LIST,
842 0, M_WAITOK | M_NULLOK);
847 ng_btsocket_l2cap_raw_get_token(&msg->header.token);
848 pcb->token = msg->header.token;
851 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
858 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
859 ng_btsocket_l2cap_raw_ioctl_timeout * hz);
865 if (pcb->msg != NULL &&
866 pcb->msg->header.cmd == NGM_L2CAP_NODE_GET_CON_LIST) {
867 /* Return data back to user space */
868 p1 = (ng_l2cap_node_con_list_ep *)(pcb->msg->data);
869 p2 = (ng_l2cap_node_con_ep *)(p1 + 1);
871 p->num_connections = min(p->num_connections,
872 p1->num_connections);
873 if (p->num_connections > 0)
874 error = copyout((caddr_t) p2,
875 (caddr_t) p->connections,
876 p->num_connections * sizeof(*p2));
880 NG_FREE_MSG(pcb->msg); /* checks for != NULL */
883 case SIOC_L2CAP_NODE_GET_CHAN_LIST: {
884 struct ng_btsocket_l2cap_raw_chan_list *p =
885 (struct ng_btsocket_l2cap_raw_chan_list *) data;
886 ng_l2cap_node_chan_list_ep *p1 = NULL;
887 ng_l2cap_node_chan_ep *p2 = NULL;
889 if (p->num_channels == 0 ||
890 p->num_channels > NG_L2CAP_MAX_CHAN_NUM ||
891 p->channels == NULL) {
896 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE,
897 NGM_L2CAP_NODE_GET_CHAN_LIST, 0, M_WAITOK | M_NULLOK);
902 ng_btsocket_l2cap_raw_get_token(&msg->header.token);
903 pcb->token = msg->header.token;
906 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
913 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
914 ng_btsocket_l2cap_raw_ioctl_timeout * hz);
920 if (pcb->msg != NULL &&
921 pcb->msg->header.cmd == NGM_L2CAP_NODE_GET_CHAN_LIST) {
922 /* Return data back to user space */
923 p1 = (ng_l2cap_node_chan_list_ep *)(pcb->msg->data);
924 p2 = (ng_l2cap_node_chan_ep *)(p1 + 1);
926 p->num_channels = min(p->num_channels,
928 if (p->num_channels > 0)
929 error = copyout((caddr_t) p2,
930 (caddr_t) p->channels,
931 p->num_channels * sizeof(*p2));
935 NG_FREE_MSG(pcb->msg); /* checks for != NULL */
938 case SIOC_L2CAP_L2CA_PING: {
939 struct ng_btsocket_l2cap_raw_ping *p =
940 (struct ng_btsocket_l2cap_raw_ping *) data;
941 ng_l2cap_l2ca_ping_ip *ip = NULL;
942 ng_l2cap_l2ca_ping_op *op = NULL;
944 if (!(pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)) {
949 if ((p->echo_size != 0 && p->echo_data == NULL) ||
950 p->echo_size > NG_L2CAP_MAX_ECHO_SIZE) {
955 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE,
956 NGM_L2CAP_L2CA_PING, sizeof(*ip) + p->echo_size,
957 M_WAITOK | M_NULLOK);
962 ng_btsocket_l2cap_raw_get_token(&msg->header.token);
963 pcb->token = msg->header.token;
966 ip = (ng_l2cap_l2ca_ping_ip *)(msg->data);
967 bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr));
968 ip->echo_size = p->echo_size;
970 if (ip->echo_size > 0) {
971 error = copyin(p->echo_data, ip + 1, p->echo_size);
979 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
986 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
987 bluetooth_l2cap_rtx_timeout());
993 if (pcb->msg != NULL &&
994 pcb->msg->header.cmd == NGM_L2CAP_L2CA_PING) {
995 /* Return data back to the user space */
996 op = (ng_l2cap_l2ca_ping_op *)(pcb->msg->data);
997 p->result = op->result;
998 p->echo_size = min(p->echo_size, op->echo_size);
1000 if (p->echo_size > 0)
1001 error = copyout(op + 1, p->echo_data,
1006 NG_FREE_MSG(pcb->msg); /* checks for != NULL */
1009 case SIOC_L2CAP_L2CA_GET_INFO: {
1010 struct ng_btsocket_l2cap_raw_get_info *p =
1011 (struct ng_btsocket_l2cap_raw_get_info *) data;
1012 ng_l2cap_l2ca_get_info_ip *ip = NULL;
1013 ng_l2cap_l2ca_get_info_op *op = NULL;
1015 if (!(pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)) {
1020 if (p->info_size != 0 && p->info_data == NULL) {
1025 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE,
1026 NGM_L2CAP_L2CA_GET_INFO, sizeof(*ip) + p->info_size,
1027 M_WAITOK | M_NULLOK);
1032 ng_btsocket_l2cap_raw_get_token(&msg->header.token);
1033 pcb->token = msg->header.token;
1036 ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data);
1037 bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr));
1038 ip->info_type = p->info_type;
1040 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
1047 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
1048 bluetooth_l2cap_rtx_timeout());
1054 if (pcb->msg != NULL &&
1055 pcb->msg->header.cmd == NGM_L2CAP_L2CA_GET_INFO) {
1056 /* Return data back to the user space */
1057 op = (ng_l2cap_l2ca_get_info_op *)(pcb->msg->data);
1058 p->result = op->result;
1059 p->info_size = min(p->info_size, op->info_size);
1061 if (p->info_size > 0)
1062 error = copyout(op + 1, p->info_data,
1067 NG_FREE_MSG(pcb->msg); /* checks for != NULL */
1070 case SIOC_L2CAP_NODE_GET_AUTO_DISCON_TIMO: {
1071 struct ng_btsocket_l2cap_raw_auto_discon_timo *p =
1072 (struct ng_btsocket_l2cap_raw_auto_discon_timo *) data;
1074 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,
1075 NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO,
1076 &p->timeout, sizeof(p->timeout));
1079 case SIOC_L2CAP_NODE_SET_AUTO_DISCON_TIMO: {
1080 struct ng_btsocket_l2cap_raw_auto_discon_timo *p =
1081 (struct ng_btsocket_l2cap_raw_auto_discon_timo *) data;
1083 if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)
1084 error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook,
1085 NGM_L2CAP_NODE_SET_AUTO_DISCON_TIMO,
1086 &p->timeout, sizeof(p->timeout));
1096 mtx_unlock(&pcb->pcb_mtx);
1099 } /* ng_btsocket_l2cap_raw_control */
1102 * Detach and destroy socket
1106 ng_btsocket_l2cap_raw_detach(struct socket *so)
1108 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
1110 KASSERT(pcb != NULL, ("nt_btsocket_l2cap_raw_detach: pcb == NULL"));
1111 if (ng_btsocket_l2cap_raw_node == NULL)
1114 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);
1115 mtx_lock(&pcb->pcb_mtx);
1117 LIST_REMOVE(pcb, next);
1119 mtx_unlock(&pcb->pcb_mtx);
1120 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);
1122 mtx_destroy(&pcb->pcb_mtx);
1124 bzero(pcb, sizeof(*pcb));
1125 kfree(pcb, M_NETGRAPH_BTSOCKET_L2CAP_RAW);
1128 } /* ng_btsocket_l2cap_raw_detach */
1135 ng_btsocket_l2cap_raw_disconnect(struct socket *so)
1137 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
1141 if (ng_btsocket_l2cap_raw_node == NULL)
1144 mtx_lock(&pcb->pcb_mtx);
1146 soisdisconnected(so);
1147 mtx_unlock(&pcb->pcb_mtx);
1150 } /* ng_btsocket_l2cap_raw_disconnect */
1157 ng_btsocket_l2cap_raw_peeraddr(struct socket *so, struct sockaddr **nam)
1159 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
1160 struct sockaddr_l2cap sa;
1164 if (ng_btsocket_l2cap_raw_node == NULL)
1167 mtx_lock(&pcb->pcb_mtx);
1168 bcopy(&pcb->dst, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr));
1169 mtx_unlock(&pcb->pcb_mtx);
1172 sa.l2cap_len = sizeof(sa);
1173 sa.l2cap_family = AF_BLUETOOTH;
1175 *nam = sodupsockaddr((struct sockaddr *) &sa, M_WAITOK | M_NULLOK);
1177 return ((*nam == NULL)? ENOMEM : 0);
1178 } /* ng_btsocket_l2cap_raw_peeraddr */
1181 * Send data to socket
1185 ng_btsocket_l2cap_raw_send(struct socket *so, int flags, struct mbuf *m,
1186 struct sockaddr *nam, struct mbuf *control, struct thread *td)
1188 NG_FREE_M(m); /* Checks for m != NULL */
1191 return (EOPNOTSUPP);
1192 } /* ng_btsocket_l2cap_raw_send */
1195 * Get socket address
1199 ng_btsocket_l2cap_raw_sockaddr(struct socket *so, struct sockaddr **nam)
1201 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
1202 struct sockaddr_l2cap sa;
1206 if (ng_btsocket_l2cap_raw_node == NULL)
1209 mtx_lock(&pcb->pcb_mtx);
1210 bcopy(&pcb->src, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr));
1211 mtx_unlock(&pcb->pcb_mtx);
1214 sa.l2cap_len = sizeof(sa);
1215 sa.l2cap_family = AF_BLUETOOTH;
1217 *nam = sodupsockaddr((struct sockaddr *) &sa, M_WAITOK | M_NULLOK);
1219 return ((*nam == NULL)? ENOMEM : 0);
1220 } /* ng_btsocket_l2cap_raw_sockaddr */
1227 ng_btsocket_l2cap_raw_get_token(u_int32_t *token)
1229 mtx_lock(&ng_btsocket_l2cap_raw_token_mtx);
1231 if (++ ng_btsocket_l2cap_raw_token == 0)
1232 ng_btsocket_l2cap_raw_token = 1;
1234 *token = ng_btsocket_l2cap_raw_token;
1236 mtx_unlock(&ng_btsocket_l2cap_raw_token_mtx);
1237 } /* ng_btsocket_l2cap_raw_get_token */
1240 * Send Netgraph message to the node - do not expect reply
1244 ng_btsocket_l2cap_raw_send_ngmsg(hook_p hook, int cmd, void *arg, int arglen)
1246 struct ng_mesg *msg = NULL;
1249 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, arglen, M_WAITOK | M_NULLOK);
1253 if (arg != NULL && arglen > 0)
1254 bcopy(arg, msg->data, arglen);
1256 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, hook, 0);
1259 } /* ng_btsocket_l2cap_raw_send_ngmsg */
1262 * Send Netgraph message to the node (no data) and wait for reply
1266 ng_btsocket_l2cap_raw_send_sync_ngmsg(ng_btsocket_l2cap_raw_pcb_p pcb,
1267 int cmd, void *rsp, int rsplen)
1269 struct ng_mesg *msg = NULL;
1272 mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1274 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, 0, M_WAITOK | M_NULLOK);
1278 ng_btsocket_l2cap_raw_get_token(&msg->header.token);
1279 pcb->token = msg->header.token;
1282 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
1289 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
1290 ng_btsocket_l2cap_raw_ioctl_timeout * hz);
1296 if (pcb->msg != NULL && pcb->msg->header.cmd == cmd)
1297 bcopy(pcb->msg->data, rsp, rsplen);
1301 NG_FREE_MSG(pcb->msg); /* checks for != NULL */
1304 } /* ng_btsocket_l2cap_raw_send_sync_ngmsg */