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/ioccom.h>
42 #include <sys/kernel.h>
44 #include <sys/malloc.h>
46 #include <sys/mutex.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"
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"
63 #ifdef NG_SEPARATE_MALLOC
64 MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_L2CAP_RAW
, "netgraph_btsocks_l2cap_raw",
65 "Netgraph Bluetooth raw L2CAP sockets");
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
,
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
;
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
,
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
,
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
,
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
,
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
,
145 &ng_btsocket_l2cap_raw_queue
.drops
, 0,
146 "Bluetooth raw L2CAP sockets input queue drops");
149 #define NG_BTSOCKET_L2CAP_RAW_INFO \
150 if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_INFO_LEVEL) \
153 #define NG_BTSOCKET_L2CAP_RAW_WARN \
154 if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_WARN_LEVEL) \
157 #define NG_BTSOCKET_L2CAP_RAW_ERR \
158 if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_ERR_LEVEL) \
161 #define NG_BTSOCKET_L2CAP_RAW_ALERT \
162 if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_ALERT_LEVEL) \
165 /*****************************************************************************
166 *****************************************************************************
167 ** Netgraph node interface
168 *****************************************************************************
169 *****************************************************************************/
172 * Netgraph node constructor. Do not allow to create node of this type.
176 ng_btsocket_l2cap_raw_node_constructor(node_p node
)
179 } /* ng_btsocket_l2cap_raw_node_constructor */
182 * Do local shutdown processing. Let old node go and create new fresh one.
186 ng_btsocket_l2cap_raw_node_shutdown(node_p node
)
192 /* Create new node */
193 error
= ng_make_node_common(&typestruct
, &ng_btsocket_l2cap_raw_node
);
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
;
203 error
= ng_name_node(ng_btsocket_l2cap_raw_node
,
204 NG_BTSOCKET_L2CAP_RAW_NODE_TYPE
);
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
;
216 } /* ng_btsocket_l2cap_raw_node_shutdown */
219 * We allow any hook to be connected to the node.
223 ng_btsocket_l2cap_raw_node_newhook(node_p node
, hook_p hook
, char const *name
)
226 } /* ng_btsocket_l2cap_raw_node_newhook */
229 * Just say "YEP, that's OK by me!"
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 */
239 } /* ng_btsocket_l2cap_raw_node_connect */
242 * Hook disconnection. Schedule route cleanup task
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
256 if (NG_HOOK_PRIVATE(hook
) != NULL
)
257 return (ng_btsocket_l2cap_raw_wakeup_route_task());
259 NG_HOOK_UNREF(hook
); /* Remove extra reference */
262 } /* ng_btsocket_l2cap_raw_node_disconnect */
265 * Process incoming messages
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 */
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
)) {
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
);
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
);
314 } /* ng_btsocket_l2cap_raw_node_rcvmsg */
317 * Receive data on a hook
321 ng_btsocket_l2cap_raw_node_rcvdata(hook_p hook
, item_p item
)
326 } /* ng_btsocket_l2cap_raw_node_rcvdata */
328 /*****************************************************************************
329 *****************************************************************************
331 *****************************************************************************
332 *****************************************************************************/
335 * L2CAP sockets input routine
339 ng_btsocket_l2cap_raw_input(void *context
, int pending
)
343 struct ng_mesg
*msg
= NULL
;
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
);
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
);
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
))
368 if (bcmp(msg
->data
, NG_HCI_BDADDR_ANY
,
369 sizeof(bdaddr_t
)) == 0)
372 rt
= (ng_btsocket_l2cap_rtentry_t
*)
373 NG_HOOK_PRIVATE(hook
);
375 MALLOC(rt
, ng_btsocket_l2cap_rtentry_p
,
377 M_NETGRAPH_BTSOCKET_L2CAP_RAW
,
378 M_WAITOK
| M_NULLOK
| M_ZERO
);
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
,
389 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx
);
391 bcopy(msg
->data
, &rt
->src
, sizeof(rt
->src
));
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
);
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
) {
421 mtx_unlock(&pcb
->pcb_mtx
);
425 mtx_unlock(&pcb
->pcb_mtx
);
428 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx
);
432 NG_BTSOCKET_L2CAP_RAW_WARN(
433 "%s: Unknown message, cmd=%d\n", __func__
, msg
->header
.cmd
);
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.
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
);
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
);
500 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx
);
501 } /* ng_btsocket_l2cap_raw_rtclean */
504 * Initialize everything
508 ng_btsocket_l2cap_raw_init(void)
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
);
519 NG_BTSOCKET_L2CAP_RAW_ALERT(
520 "%s: Could not register Netgraph node type, error=%d\n", __func__
, error
);
525 /* Create Netgrapg node */
526 error
= ng_make_node_common(&typestruct
, &ng_btsocket_l2cap_raw_node
);
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
;
536 error
= ng_name_node(ng_btsocket_l2cap_raw_node
,
537 NG_BTSOCKET_L2CAP_RAW_NODE_TYPE
);
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
;
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
);
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
);
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
578 ng_btsocket_l2cap_raw_abort(struct socket
*so
)
581 (void)ng_btsocket_l2cap_raw_disconnect(so
);
582 } /* ng_btsocket_l2cap_raw_abort */
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
);
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
);
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
);
621 /* Link the PCB and the socket */
622 so
->so_pcb
= (caddr_t
) pcb
;
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
);
636 } /* ng_btsocket_l2cap_raw_attach */
643 ng_btsocket_l2cap_raw_bind(struct socket
*so
, struct sockaddr
*nam
,
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
;
652 if (ng_btsocket_l2cap_raw_node
== NULL
)
657 if (sa
->l2cap_family
!= AF_BLUETOOTH
)
658 return (EAFNOSUPPORT
);
659 if (sa
->l2cap_len
!= sizeof(*sa
))
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
))
670 if (bcmp(&sa
->l2cap_bdaddr
, &rt
->src
,
671 sizeof(rt
->src
)) == 0)
675 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx
);
682 mtx_lock(&pcb
->pcb_mtx
);
683 bcopy(&sa
->l2cap_bdaddr
, &pcb
->src
, sizeof(pcb
->src
));
685 mtx_unlock(&pcb
->pcb_mtx
);
688 } /* ng_btsocket_l2cap_raw_bind */
695 ng_btsocket_l2cap_raw_connect(struct socket
*so
, struct sockaddr
*nam
,
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
;
705 if (ng_btsocket_l2cap_raw_node
== NULL
)
710 if (sa
->l2cap_family
!= AF_BLUETOOTH
)
711 return (EAFNOSUPPORT
);
712 if (sa
->l2cap_len
!= sizeof(*sa
))
714 if (bcmp(&sa
->l2cap_bdaddr
, NG_HCI_BDADDR_ANY
, sizeof(bdaddr_t
)) == 0)
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
) {
733 mtx_unlock(&pcb
->pcb_mtx
);
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
))
748 if (bcmp(&pcb
->dst
, &rt
->src
, sizeof(rt
->src
)) != 0)
756 bcopy(&rt
->src
, &pcb
->src
, sizeof(pcb
->src
));
762 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx
);
763 mtx_unlock(&pcb
->pcb_mtx
);
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
;
782 if (ng_btsocket_l2cap_raw_node
== NULL
)
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
);
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
));
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
));
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
));
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
) {
843 NG_MKMESSAGE(msg
, NGM_L2CAP_COOKIE
, NGM_L2CAP_NODE_GET_CON_LIST
,
844 0, M_WAITOK
| M_NULLOK
);
849 ng_btsocket_l2cap_raw_get_token(&msg
->header
.token
);
850 pcb
->token
= msg
->header
.token
;
853 NG_SEND_MSG_HOOK(error
, ng_btsocket_l2cap_raw_node
, msg
,
860 error
= msleep(&pcb
->msg
, &pcb
->pcb_mtx
, PZERO
|PCATCH
, "l2ctl",
861 ng_btsocket_l2cap_raw_ioctl_timeout
* hz
);
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
));
882 NG_FREE_MSG(pcb
->msg
); /* checks for != NULL */
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
) {
898 NG_MKMESSAGE(msg
, NGM_L2CAP_COOKIE
,
899 NGM_L2CAP_NODE_GET_CHAN_LIST
, 0, M_WAITOK
| M_NULLOK
);
904 ng_btsocket_l2cap_raw_get_token(&msg
->header
.token
);
905 pcb
->token
= msg
->header
.token
;
908 NG_SEND_MSG_HOOK(error
, ng_btsocket_l2cap_raw_node
, msg
,
915 error
= msleep(&pcb
->msg
, &pcb
->pcb_mtx
, PZERO
|PCATCH
, "l2ctl",
916 ng_btsocket_l2cap_raw_ioctl_timeout
* hz
);
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
,
930 if (p
->num_channels
> 0)
931 error
= copyout((caddr_t
) p2
,
932 (caddr_t
) p
->channels
,
933 p
->num_channels
* sizeof(*p2
));
937 NG_FREE_MSG(pcb
->msg
); /* checks for != NULL */
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
)) {
951 if ((p
->echo_size
!= 0 && p
->echo_data
== NULL
) ||
952 p
->echo_size
> NG_L2CAP_MAX_ECHO_SIZE
) {
957 NG_MKMESSAGE(msg
, NGM_L2CAP_COOKIE
,
958 NGM_L2CAP_L2CA_PING
, sizeof(*ip
) + p
->echo_size
,
959 M_WAITOK
| M_NULLOK
);
964 ng_btsocket_l2cap_raw_get_token(&msg
->header
.token
);
965 pcb
->token
= msg
->header
.token
;
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
);
981 NG_SEND_MSG_HOOK(error
, ng_btsocket_l2cap_raw_node
, msg
,
988 error
= msleep(&pcb
->msg
, &pcb
->pcb_mtx
, PZERO
|PCATCH
, "l2ctl",
989 bluetooth_l2cap_rtx_timeout());
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
,
1008 NG_FREE_MSG(pcb
->msg
); /* checks for != NULL */
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
)) {
1022 if (p
->info_size
!= 0 && p
->info_data
== NULL
) {
1027 NG_MKMESSAGE(msg
, NGM_L2CAP_COOKIE
,
1028 NGM_L2CAP_L2CA_GET_INFO
, sizeof(*ip
) + p
->info_size
,
1029 M_WAITOK
| M_NULLOK
);
1034 ng_btsocket_l2cap_raw_get_token(&msg
->header
.token
);
1035 pcb
->token
= msg
->header
.token
;
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
,
1049 error
= msleep(&pcb
->msg
, &pcb
->pcb_mtx
, PZERO
|PCATCH
, "l2ctl",
1050 bluetooth_l2cap_rtx_timeout());
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
,
1069 NG_FREE_MSG(pcb
->msg
); /* checks for != NULL */
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
));
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
));
1098 mtx_unlock(&pcb
->pcb_mtx
);
1101 } /* ng_btsocket_l2cap_raw_control */
1104 * Detach and destroy socket
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
)
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
);
1130 } /* ng_btsocket_l2cap_raw_detach */
1137 ng_btsocket_l2cap_raw_disconnect(struct socket
*so
)
1139 ng_btsocket_l2cap_raw_pcb_p pcb
= so2l2cap_raw_pcb(so
);
1143 if (ng_btsocket_l2cap_raw_node
== NULL
)
1146 mtx_lock(&pcb
->pcb_mtx
);
1148 soisdisconnected(so
);
1149 mtx_unlock(&pcb
->pcb_mtx
);
1152 } /* ng_btsocket_l2cap_raw_disconnect */
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
;
1166 if (ng_btsocket_l2cap_raw_node
== NULL
)
1169 mtx_lock(&pcb
->pcb_mtx
);
1170 bcopy(&pcb
->dst
, &sa
.l2cap_bdaddr
, sizeof(sa
.l2cap_bdaddr
));
1171 mtx_unlock(&pcb
->pcb_mtx
);
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 */
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
;
1208 if (ng_btsocket_l2cap_raw_node
== NULL
)
1211 mtx_lock(&pcb
->pcb_mtx
);
1212 bcopy(&pcb
->src
, &sa
.l2cap_bdaddr
, sizeof(sa
.l2cap_bdaddr
));
1213 mtx_unlock(&pcb
->pcb_mtx
);
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 */
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
1246 ng_btsocket_l2cap_raw_send_ngmsg(hook_p hook
, int cmd
, void *arg
, int arglen
)
1248 struct ng_mesg
*msg
= NULL
;
1251 NG_MKMESSAGE(msg
, NGM_L2CAP_COOKIE
, cmd
, arglen
, M_WAITOK
| M_NULLOK
);
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);
1261 } /* ng_btsocket_l2cap_raw_send_ngmsg */
1264 * Send Netgraph message to the node (no data) and wait for reply
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
;
1274 mtx_assert(&pcb
->pcb_mtx
, MA_OWNED
);
1276 NG_MKMESSAGE(msg
, NGM_L2CAP_COOKIE
, cmd
, 0, M_WAITOK
| M_NULLOK
);
1280 ng_btsocket_l2cap_raw_get_token(&msg
->header
.token
);
1281 pcb
->token
= msg
->header
.token
;
1284 NG_SEND_MSG_HOOK(error
, ng_btsocket_l2cap_raw_node
, msg
,
1291 error
= msleep(&pcb
->msg
, &pcb
->pcb_mtx
, PZERO
|PCATCH
, "l2ctl",
1292 ng_btsocket_l2cap_raw_ioctl_timeout
* hz
);
1298 if (pcb
->msg
!= NULL
&& pcb
->msg
->header
.cmd
== cmd
)
1299 bcopy(pcb
->msg
->data
, rsp
, rsplen
);
1303 NG_FREE_MSG(pcb
->msg
); /* checks for != NULL */
1306 } /* ng_btsocket_l2cap_raw_send_sync_ngmsg */