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 $
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>
53 #include <netgraph/ng_message.h>
54 #include <netgraph/netgraph.h>
55 #include <netgraph/bluetooth/include/ng_bluetooth.h>
56 #include <netgraph/bluetooth/include/ng_hci.h>
57 #include <netgraph/bluetooth/include/ng_l2cap.h>
58 #include <netgraph/bluetooth/include/ng_btsocket.h>
59 #include <netgraph/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 MALLOC(rt
, ng_btsocket_l2cap_rtentry_p
,
376 M_NETGRAPH_BTSOCKET_L2CAP_RAW
,
381 NG_HOOK_SET_PRIVATE(hook
, rt
);
383 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx
);
385 LIST_INSERT_HEAD(&ng_btsocket_l2cap_raw_rt
,
388 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx
);
390 bcopy(msg
->data
, &rt
->src
, sizeof(rt
->src
));
393 NG_BTSOCKET_L2CAP_RAW_INFO(
394 "%s: Updating hook \"%s\", src bdaddr=%x:%x:%x:%x:%x:%x\n",
395 __func__
, NG_HOOK_NAME(hook
),
396 rt
->src
.b
[5], rt
->src
.b
[4], rt
->src
.b
[3],
397 rt
->src
.b
[2], rt
->src
.b
[1], rt
->src
.b
[0]);
399 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx
);
402 case NGM_L2CAP_NODE_GET_FLAGS
:
403 case NGM_L2CAP_NODE_GET_DEBUG
:
404 case NGM_L2CAP_NODE_GET_CON_LIST
:
405 case NGM_L2CAP_NODE_GET_CHAN_LIST
:
406 case NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO
:
407 case NGM_L2CAP_L2CA_PING
:
408 case NGM_L2CAP_L2CA_GET_INFO
: {
409 ng_btsocket_l2cap_raw_pcb_p pcb
= NULL
;
411 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx
);
413 LIST_FOREACH(pcb
,&ng_btsocket_l2cap_raw_sockets
,next
) {
414 mtx_lock(&pcb
->pcb_mtx
);
416 if (pcb
->token
== msg
->header
.token
) {
420 mtx_unlock(&pcb
->pcb_mtx
);
424 mtx_unlock(&pcb
->pcb_mtx
);
427 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx
);
431 NG_BTSOCKET_L2CAP_RAW_WARN(
432 "%s: Unknown message, cmd=%d\n", __func__
, msg
->header
.cmd
);
437 NG_HOOK_UNREF(hook
); /* remove extra reference */
439 NG_FREE_MSG(msg
); /* Checks for msg != NULL */
441 } /* ng_btsocket_l2cap_raw_input */
444 * Route cleanup task. Gets scheduled when hook is disconnected. Here we
445 * will find all sockets that use "invalid" hook and disconnect them.
449 ng_btsocket_l2cap_raw_rtclean(void *context
, int pending
)
451 ng_btsocket_l2cap_raw_pcb_p pcb
= NULL
;
452 ng_btsocket_l2cap_rtentry_p rt
= NULL
;
455 * First disconnect all sockets that use "invalid" hook
458 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx
);
460 LIST_FOREACH(pcb
, &ng_btsocket_l2cap_raw_sockets
, next
) {
461 mtx_lock(&pcb
->pcb_mtx
);
463 if (pcb
->rt
!= NULL
&&
464 pcb
->rt
->hook
!= NULL
&& NG_HOOK_NOT_VALID(pcb
->rt
->hook
)) {
465 if (pcb
->so
!= NULL
&&
466 pcb
->so
->so_state
& SS_ISCONNECTED
)
467 soisdisconnected(pcb
->so
);
472 mtx_unlock(&pcb
->pcb_mtx
);
475 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx
);
478 * Now cleanup routing table
481 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx
);
483 for (rt
= LIST_FIRST(&ng_btsocket_l2cap_raw_rt
); rt
!= NULL
; ) {
484 ng_btsocket_l2cap_rtentry_p rt_next
= LIST_NEXT(rt
, next
);
486 if (rt
->hook
!= NULL
&& NG_HOOK_NOT_VALID(rt
->hook
)) {
487 LIST_REMOVE(rt
, next
);
489 NG_HOOK_SET_PRIVATE(rt
->hook
, NULL
);
490 NG_HOOK_UNREF(rt
->hook
); /* Remove extra reference */
492 bzero(rt
, sizeof(*rt
));
493 FREE(rt
, M_NETGRAPH_BTSOCKET_L2CAP_RAW
);
499 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx
);
500 } /* ng_btsocket_l2cap_raw_rtclean */
503 * Initialize everything
507 ng_btsocket_l2cap_raw_init(void)
511 ng_btsocket_l2cap_raw_node
= NULL
;
512 ng_btsocket_l2cap_raw_debug_level
= NG_BTSOCKET_WARN_LEVEL
;
513 ng_btsocket_l2cap_raw_ioctl_timeout
= 5;
515 /* Register Netgraph node type */
516 error
= ng_newtype(&typestruct
);
518 NG_BTSOCKET_L2CAP_RAW_ALERT(
519 "%s: Could not register Netgraph node type, error=%d\n", __func__
, error
);
524 /* Create Netgrapg node */
525 error
= ng_make_node_common(&typestruct
, &ng_btsocket_l2cap_raw_node
);
527 NG_BTSOCKET_L2CAP_RAW_ALERT(
528 "%s: Could not create Netgraph node, error=%d\n", __func__
, error
);
530 ng_btsocket_l2cap_raw_node
= NULL
;
535 error
= ng_name_node(ng_btsocket_l2cap_raw_node
,
536 NG_BTSOCKET_L2CAP_RAW_NODE_TYPE
);
538 NG_BTSOCKET_L2CAP_RAW_ALERT(
539 "%s: Could not name Netgraph node, error=%d\n", __func__
, error
);
541 NG_NODE_UNREF(ng_btsocket_l2cap_raw_node
);
542 ng_btsocket_l2cap_raw_node
= NULL
;
547 /* Create input queue */
548 NG_BT_ITEMQ_INIT(&ng_btsocket_l2cap_raw_queue
, ifqmaxlen
);
549 mtx_init(&ng_btsocket_l2cap_raw_queue_mtx
,
550 "btsocks_l2cap_raw_queue_mtx", NULL
, MTX_DEF
);
551 TASK_INIT(&ng_btsocket_l2cap_raw_queue_task
, 0,
552 ng_btsocket_l2cap_raw_input
, NULL
);
554 /* Create list of sockets */
555 LIST_INIT(&ng_btsocket_l2cap_raw_sockets
);
556 mtx_init(&ng_btsocket_l2cap_raw_sockets_mtx
,
557 "btsocks_l2cap_raw_sockets_mtx", NULL
, MTX_DEF
);
560 ng_btsocket_l2cap_raw_token
= 0;
561 mtx_init(&ng_btsocket_l2cap_raw_token_mtx
,
562 "btsocks_l2cap_raw_token_mtx", NULL
, MTX_DEF
);
565 LIST_INIT(&ng_btsocket_l2cap_raw_rt
);
566 mtx_init(&ng_btsocket_l2cap_raw_rt_mtx
,
567 "btsocks_l2cap_raw_rt_mtx", NULL
, MTX_DEF
);
568 TASK_INIT(&ng_btsocket_l2cap_raw_rt_task
, 0,
569 ng_btsocket_l2cap_raw_rtclean
, NULL
);
570 } /* ng_btsocket_l2cap_raw_init */
573 * Abort connection on socket
577 ng_btsocket_l2cap_raw_abort(struct socket
*so
)
580 (void)ng_btsocket_l2cap_raw_disconnect(so
);
581 } /* ng_btsocket_l2cap_raw_abort */
584 ng_btsocket_l2cap_raw_close(struct socket
*so
)
587 (void)ng_btsocket_l2cap_raw_disconnect(so
);
588 } /* ng_btsocket_l2cap_raw_close */
591 * Create and attach new socket
595 ng_btsocket_l2cap_raw_attach(struct socket
*so
, int proto
, struct thread
*td
)
597 ng_btsocket_l2cap_raw_pcb_p pcb
= so2l2cap_raw_pcb(so
);
603 if (ng_btsocket_l2cap_raw_node
== NULL
)
604 return (EPROTONOSUPPORT
);
605 if (so
->so_type
!= SOCK_RAW
)
606 return (ESOCKTNOSUPPORT
);
608 /* Reserve send and receive space if it is not reserved yet */
609 error
= soreserve(so
, NG_BTSOCKET_L2CAP_RAW_SENDSPACE
,
610 NG_BTSOCKET_L2CAP_RAW_RECVSPACE
);
614 /* Allocate the PCB */
615 MALLOC(pcb
, ng_btsocket_l2cap_raw_pcb_p
, sizeof(*pcb
),
616 M_NETGRAPH_BTSOCKET_L2CAP_RAW
, M_NOWAIT
|M_ZERO
);
620 /* Link the PCB and the socket */
621 so
->so_pcb
= (caddr_t
) pcb
;
624 if (priv_check(td
, PRIV_NETBLUETOOTH_RAW
) == 0)
625 pcb
->flags
|= NG_BTSOCKET_L2CAP_RAW_PRIVILEGED
;
627 mtx_init(&pcb
->pcb_mtx
, "btsocks_l2cap_raw_pcb_mtx", NULL
, MTX_DEF
);
629 /* Add the PCB to the list */
630 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx
);
631 LIST_INSERT_HEAD(&ng_btsocket_l2cap_raw_sockets
, pcb
, next
);
632 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx
);
635 } /* ng_btsocket_l2cap_raw_attach */
642 ng_btsocket_l2cap_raw_bind(struct socket
*so
, struct sockaddr
*nam
,
645 ng_btsocket_l2cap_raw_pcb_t
*pcb
= so2l2cap_raw_pcb(so
);
646 struct sockaddr_l2cap
*sa
= (struct sockaddr_l2cap
*) nam
;
647 ng_btsocket_l2cap_rtentry_t
*rt
= NULL
;
651 if (ng_btsocket_l2cap_raw_node
== NULL
)
656 if (sa
->l2cap_family
!= AF_BLUETOOTH
)
657 return (EAFNOSUPPORT
);
658 if (sa
->l2cap_len
!= sizeof(*sa
))
661 if (bcmp(&sa
->l2cap_bdaddr
, NG_HCI_BDADDR_ANY
,
662 sizeof(sa
->l2cap_bdaddr
)) != 0) {
663 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx
);
665 LIST_FOREACH(rt
, &ng_btsocket_l2cap_raw_rt
, next
) {
666 if (rt
->hook
== NULL
|| NG_HOOK_NOT_VALID(rt
->hook
))
669 if (bcmp(&sa
->l2cap_bdaddr
, &rt
->src
,
670 sizeof(rt
->src
)) == 0)
674 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx
);
681 mtx_lock(&pcb
->pcb_mtx
);
682 bcopy(&sa
->l2cap_bdaddr
, &pcb
->src
, sizeof(pcb
->src
));
684 mtx_unlock(&pcb
->pcb_mtx
);
687 } /* ng_btsocket_l2cap_raw_bind */
694 ng_btsocket_l2cap_raw_connect(struct socket
*so
, struct sockaddr
*nam
,
697 ng_btsocket_l2cap_raw_pcb_t
*pcb
= so2l2cap_raw_pcb(so
);
698 struct sockaddr_l2cap
*sa
= (struct sockaddr_l2cap
*) nam
;
699 ng_btsocket_l2cap_rtentry_t
*rt
= NULL
;
704 if (ng_btsocket_l2cap_raw_node
== NULL
)
709 if (sa
->l2cap_family
!= AF_BLUETOOTH
)
710 return (EAFNOSUPPORT
);
711 if (sa
->l2cap_len
!= sizeof(*sa
))
713 if (bcmp(&sa
->l2cap_bdaddr
, NG_HCI_BDADDR_ANY
, sizeof(bdaddr_t
)) == 0)
716 mtx_lock(&pcb
->pcb_mtx
);
718 bcopy(&sa
->l2cap_bdaddr
, &pcb
->dst
, sizeof(pcb
->dst
));
720 if (bcmp(&pcb
->src
, &pcb
->dst
, sizeof(pcb
->src
)) == 0) {
721 mtx_unlock(&pcb
->pcb_mtx
);
723 return (EADDRNOTAVAIL
);
727 * If there is route already - use it
730 if (pcb
->rt
!= NULL
) {
732 mtx_unlock(&pcb
->pcb_mtx
);
738 * Find the first hook that does not match specified destination address
741 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx
);
743 LIST_FOREACH(rt
, &ng_btsocket_l2cap_raw_rt
, next
) {
744 if (rt
->hook
== NULL
|| NG_HOOK_NOT_VALID(rt
->hook
))
747 if (bcmp(&pcb
->dst
, &rt
->src
, sizeof(rt
->src
)) != 0)
755 bcopy(&rt
->src
, &pcb
->src
, sizeof(pcb
->src
));
761 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx
);
762 mtx_unlock(&pcb
->pcb_mtx
);
765 } /* ng_btsocket_l2cap_raw_connect */
768 * Process ioctl's calls on socket
772 ng_btsocket_l2cap_raw_control(struct socket
*so
, u_long cmd
, caddr_t data
,
773 struct ifnet
*ifp
, struct thread
*td
)
775 ng_btsocket_l2cap_raw_pcb_p pcb
= so2l2cap_raw_pcb(so
);
776 struct ng_mesg
*msg
= NULL
;
781 if (ng_btsocket_l2cap_raw_node
== NULL
)
784 mtx_lock(&pcb
->pcb_mtx
);
786 /* Check if we route info */
787 if (pcb
->rt
== NULL
) {
788 mtx_unlock(&pcb
->pcb_mtx
);
789 return (EHOSTUNREACH
);
792 /* Check if we have pending ioctl() */
793 if (pcb
->token
!= 0) {
794 mtx_unlock(&pcb
->pcb_mtx
);
799 case SIOC_L2CAP_NODE_GET_FLAGS
: {
800 struct ng_btsocket_l2cap_raw_node_flags
*p
=
801 (struct ng_btsocket_l2cap_raw_node_flags
*) data
;
803 error
= ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb
,
804 NGM_L2CAP_NODE_GET_FLAGS
,
805 &p
->flags
, sizeof(p
->flags
));
808 case SIOC_L2CAP_NODE_GET_DEBUG
: {
809 struct ng_btsocket_l2cap_raw_node_debug
*p
=
810 (struct ng_btsocket_l2cap_raw_node_debug
*) data
;
812 error
= ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb
,
813 NGM_L2CAP_NODE_GET_DEBUG
,
814 &p
->debug
, sizeof(p
->debug
));
817 case SIOC_L2CAP_NODE_SET_DEBUG
: {
818 struct ng_btsocket_l2cap_raw_node_debug
*p
=
819 (struct ng_btsocket_l2cap_raw_node_debug
*) data
;
821 if (pcb
->flags
& NG_BTSOCKET_L2CAP_RAW_PRIVILEGED
)
822 error
= ng_btsocket_l2cap_raw_send_ngmsg(pcb
->rt
->hook
,
823 NGM_L2CAP_NODE_SET_DEBUG
,
824 &p
->debug
, sizeof(p
->debug
));
829 case SIOC_L2CAP_NODE_GET_CON_LIST
: {
830 struct ng_btsocket_l2cap_raw_con_list
*p
=
831 (struct ng_btsocket_l2cap_raw_con_list
*) data
;
832 ng_l2cap_node_con_list_ep
*p1
= NULL
;
833 ng_l2cap_node_con_ep
*p2
= NULL
;
835 if (p
->num_connections
== 0 ||
836 p
->num_connections
> NG_L2CAP_MAX_CON_NUM
||
837 p
->connections
== NULL
) {
842 NG_MKMESSAGE(msg
, NGM_L2CAP_COOKIE
, NGM_L2CAP_NODE_GET_CON_LIST
,
848 ng_btsocket_l2cap_raw_get_token(&msg
->header
.token
);
849 pcb
->token
= msg
->header
.token
;
852 NG_SEND_MSG_HOOK(error
, ng_btsocket_l2cap_raw_node
, msg
,
859 error
= msleep(&pcb
->msg
, &pcb
->pcb_mtx
, PZERO
|PCATCH
, "l2ctl",
860 ng_btsocket_l2cap_raw_ioctl_timeout
* hz
);
866 if (pcb
->msg
!= NULL
&&
867 pcb
->msg
->header
.cmd
== NGM_L2CAP_NODE_GET_CON_LIST
) {
868 /* Return data back to user space */
869 p1
= (ng_l2cap_node_con_list_ep
*)(pcb
->msg
->data
);
870 p2
= (ng_l2cap_node_con_ep
*)(p1
+ 1);
872 p
->num_connections
= min(p
->num_connections
,
873 p1
->num_connections
);
874 if (p
->num_connections
> 0)
875 error
= copyout((caddr_t
) p2
,
876 (caddr_t
) p
->connections
,
877 p
->num_connections
* sizeof(*p2
));
881 NG_FREE_MSG(pcb
->msg
); /* checks for != NULL */
884 case SIOC_L2CAP_NODE_GET_CHAN_LIST
: {
885 struct ng_btsocket_l2cap_raw_chan_list
*p
=
886 (struct ng_btsocket_l2cap_raw_chan_list
*) data
;
887 ng_l2cap_node_chan_list_ep
*p1
= NULL
;
888 ng_l2cap_node_chan_ep
*p2
= NULL
;
890 if (p
->num_channels
== 0 ||
891 p
->num_channels
> NG_L2CAP_MAX_CHAN_NUM
||
892 p
->channels
== NULL
) {
897 NG_MKMESSAGE(msg
, NGM_L2CAP_COOKIE
,
898 NGM_L2CAP_NODE_GET_CHAN_LIST
, 0, M_NOWAIT
);
903 ng_btsocket_l2cap_raw_get_token(&msg
->header
.token
);
904 pcb
->token
= msg
->header
.token
;
907 NG_SEND_MSG_HOOK(error
, ng_btsocket_l2cap_raw_node
, msg
,
914 error
= msleep(&pcb
->msg
, &pcb
->pcb_mtx
, PZERO
|PCATCH
, "l2ctl",
915 ng_btsocket_l2cap_raw_ioctl_timeout
* hz
);
921 if (pcb
->msg
!= NULL
&&
922 pcb
->msg
->header
.cmd
== NGM_L2CAP_NODE_GET_CHAN_LIST
) {
923 /* Return data back to user space */
924 p1
= (ng_l2cap_node_chan_list_ep
*)(pcb
->msg
->data
);
925 p2
= (ng_l2cap_node_chan_ep
*)(p1
+ 1);
927 p
->num_channels
= min(p
->num_channels
,
929 if (p
->num_channels
> 0)
930 error
= copyout((caddr_t
) p2
,
931 (caddr_t
) p
->channels
,
932 p
->num_channels
* sizeof(*p2
));
936 NG_FREE_MSG(pcb
->msg
); /* checks for != NULL */
939 case SIOC_L2CAP_L2CA_PING
: {
940 struct ng_btsocket_l2cap_raw_ping
*p
=
941 (struct ng_btsocket_l2cap_raw_ping
*) data
;
942 ng_l2cap_l2ca_ping_ip
*ip
= NULL
;
943 ng_l2cap_l2ca_ping_op
*op
= NULL
;
945 if (!(pcb
->flags
& NG_BTSOCKET_L2CAP_RAW_PRIVILEGED
)) {
950 if ((p
->echo_size
!= 0 && p
->echo_data
== NULL
) ||
951 p
->echo_size
> NG_L2CAP_MAX_ECHO_SIZE
) {
956 NG_MKMESSAGE(msg
, NGM_L2CAP_COOKIE
,
957 NGM_L2CAP_L2CA_PING
, sizeof(*ip
) + p
->echo_size
,
963 ng_btsocket_l2cap_raw_get_token(&msg
->header
.token
);
964 pcb
->token
= msg
->header
.token
;
967 ip
= (ng_l2cap_l2ca_ping_ip
*)(msg
->data
);
968 bcopy(&pcb
->dst
, &ip
->bdaddr
, sizeof(ip
->bdaddr
));
969 ip
->echo_size
= p
->echo_size
;
971 if (ip
->echo_size
> 0) {
972 error
= copyin(p
->echo_data
, ip
+ 1, p
->echo_size
);
980 NG_SEND_MSG_HOOK(error
, ng_btsocket_l2cap_raw_node
, msg
,
987 error
= msleep(&pcb
->msg
, &pcb
->pcb_mtx
, PZERO
|PCATCH
, "l2ctl",
988 bluetooth_l2cap_rtx_timeout());
994 if (pcb
->msg
!= NULL
&&
995 pcb
->msg
->header
.cmd
== NGM_L2CAP_L2CA_PING
) {
996 /* Return data back to the user space */
997 op
= (ng_l2cap_l2ca_ping_op
*)(pcb
->msg
->data
);
998 p
->result
= op
->result
;
999 p
->echo_size
= min(p
->echo_size
, op
->echo_size
);
1001 if (p
->echo_size
> 0)
1002 error
= copyout(op
+ 1, p
->echo_data
,
1007 NG_FREE_MSG(pcb
->msg
); /* checks for != NULL */
1010 case SIOC_L2CAP_L2CA_GET_INFO
: {
1011 struct ng_btsocket_l2cap_raw_get_info
*p
=
1012 (struct ng_btsocket_l2cap_raw_get_info
*) data
;
1013 ng_l2cap_l2ca_get_info_ip
*ip
= NULL
;
1014 ng_l2cap_l2ca_get_info_op
*op
= NULL
;
1016 if (!(pcb
->flags
& NG_BTSOCKET_L2CAP_RAW_PRIVILEGED
)) {
1021 if (p
->info_size
!= 0 && p
->info_data
== NULL
) {
1026 NG_MKMESSAGE(msg
, NGM_L2CAP_COOKIE
,
1027 NGM_L2CAP_L2CA_GET_INFO
, sizeof(*ip
) + p
->info_size
,
1033 ng_btsocket_l2cap_raw_get_token(&msg
->header
.token
);
1034 pcb
->token
= msg
->header
.token
;
1037 ip
= (ng_l2cap_l2ca_get_info_ip
*)(msg
->data
);
1038 bcopy(&pcb
->dst
, &ip
->bdaddr
, sizeof(ip
->bdaddr
));
1039 ip
->info_type
= p
->info_type
;
1041 NG_SEND_MSG_HOOK(error
, ng_btsocket_l2cap_raw_node
, msg
,
1048 error
= msleep(&pcb
->msg
, &pcb
->pcb_mtx
, PZERO
|PCATCH
, "l2ctl",
1049 bluetooth_l2cap_rtx_timeout());
1055 if (pcb
->msg
!= NULL
&&
1056 pcb
->msg
->header
.cmd
== NGM_L2CAP_L2CA_GET_INFO
) {
1057 /* Return data back to the user space */
1058 op
= (ng_l2cap_l2ca_get_info_op
*)(pcb
->msg
->data
);
1059 p
->result
= op
->result
;
1060 p
->info_size
= min(p
->info_size
, op
->info_size
);
1062 if (p
->info_size
> 0)
1063 error
= copyout(op
+ 1, p
->info_data
,
1068 NG_FREE_MSG(pcb
->msg
); /* checks for != NULL */
1071 case SIOC_L2CAP_NODE_GET_AUTO_DISCON_TIMO
: {
1072 struct ng_btsocket_l2cap_raw_auto_discon_timo
*p
=
1073 (struct ng_btsocket_l2cap_raw_auto_discon_timo
*) data
;
1075 error
= ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb
,
1076 NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO
,
1077 &p
->timeout
, sizeof(p
->timeout
));
1080 case SIOC_L2CAP_NODE_SET_AUTO_DISCON_TIMO
: {
1081 struct ng_btsocket_l2cap_raw_auto_discon_timo
*p
=
1082 (struct ng_btsocket_l2cap_raw_auto_discon_timo
*) data
;
1084 if (pcb
->flags
& NG_BTSOCKET_L2CAP_RAW_PRIVILEGED
)
1085 error
= ng_btsocket_l2cap_raw_send_ngmsg(pcb
->rt
->hook
,
1086 NGM_L2CAP_NODE_SET_AUTO_DISCON_TIMO
,
1087 &p
->timeout
, sizeof(p
->timeout
));
1097 mtx_unlock(&pcb
->pcb_mtx
);
1100 } /* ng_btsocket_l2cap_raw_control */
1103 * Detach and destroy socket
1107 ng_btsocket_l2cap_raw_detach(struct socket
*so
)
1109 ng_btsocket_l2cap_raw_pcb_p pcb
= so2l2cap_raw_pcb(so
);
1111 KASSERT(pcb
!= NULL
, ("nt_btsocket_l2cap_raw_detach: pcb == NULL"));
1112 if (ng_btsocket_l2cap_raw_node
== NULL
)
1115 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx
);
1116 mtx_lock(&pcb
->pcb_mtx
);
1118 LIST_REMOVE(pcb
, next
);
1120 mtx_unlock(&pcb
->pcb_mtx
);
1121 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx
);
1123 mtx_destroy(&pcb
->pcb_mtx
);
1125 bzero(pcb
, sizeof(*pcb
));
1126 FREE(pcb
, M_NETGRAPH_BTSOCKET_L2CAP_RAW
);
1129 } /* ng_btsocket_l2cap_raw_detach */
1136 ng_btsocket_l2cap_raw_disconnect(struct socket
*so
)
1138 ng_btsocket_l2cap_raw_pcb_p pcb
= so2l2cap_raw_pcb(so
);
1142 if (ng_btsocket_l2cap_raw_node
== NULL
)
1145 mtx_lock(&pcb
->pcb_mtx
);
1147 soisdisconnected(so
);
1148 mtx_unlock(&pcb
->pcb_mtx
);
1151 } /* ng_btsocket_l2cap_raw_disconnect */
1158 ng_btsocket_l2cap_raw_peeraddr(struct socket
*so
, struct sockaddr
**nam
)
1160 ng_btsocket_l2cap_raw_pcb_p pcb
= so2l2cap_raw_pcb(so
);
1161 struct sockaddr_l2cap sa
;
1165 if (ng_btsocket_l2cap_raw_node
== NULL
)
1168 mtx_lock(&pcb
->pcb_mtx
);
1169 bcopy(&pcb
->dst
, &sa
.l2cap_bdaddr
, sizeof(sa
.l2cap_bdaddr
));
1170 mtx_unlock(&pcb
->pcb_mtx
);
1173 sa
.l2cap_len
= sizeof(sa
);
1174 sa
.l2cap_family
= AF_BLUETOOTH
;
1176 *nam
= sodupsockaddr((struct sockaddr
*) &sa
, M_NOWAIT
);
1178 return ((*nam
== NULL
)? ENOMEM
: 0);
1179 } /* ng_btsocket_l2cap_raw_peeraddr */
1182 * Send data to socket
1186 ng_btsocket_l2cap_raw_send(struct socket
*so
, int flags
, struct mbuf
*m
,
1187 struct sockaddr
*nam
, struct mbuf
*control
, struct thread
*td
)
1189 NG_FREE_M(m
); /* Checks for m != NULL */
1192 return (EOPNOTSUPP
);
1193 } /* ng_btsocket_l2cap_raw_send */
1196 * Get socket address
1200 ng_btsocket_l2cap_raw_sockaddr(struct socket
*so
, struct sockaddr
**nam
)
1202 ng_btsocket_l2cap_raw_pcb_p pcb
= so2l2cap_raw_pcb(so
);
1203 struct sockaddr_l2cap sa
;
1207 if (ng_btsocket_l2cap_raw_node
== NULL
)
1210 mtx_lock(&pcb
->pcb_mtx
);
1211 bcopy(&pcb
->src
, &sa
.l2cap_bdaddr
, sizeof(sa
.l2cap_bdaddr
));
1212 mtx_unlock(&pcb
->pcb_mtx
);
1215 sa
.l2cap_len
= sizeof(sa
);
1216 sa
.l2cap_family
= AF_BLUETOOTH
;
1218 *nam
= sodupsockaddr((struct sockaddr
*) &sa
, M_NOWAIT
);
1220 return ((*nam
== NULL
)? ENOMEM
: 0);
1221 } /* ng_btsocket_l2cap_raw_sockaddr */
1228 ng_btsocket_l2cap_raw_get_token(u_int32_t
*token
)
1230 mtx_lock(&ng_btsocket_l2cap_raw_token_mtx
);
1232 if (++ ng_btsocket_l2cap_raw_token
== 0)
1233 ng_btsocket_l2cap_raw_token
= 1;
1235 *token
= ng_btsocket_l2cap_raw_token
;
1237 mtx_unlock(&ng_btsocket_l2cap_raw_token_mtx
);
1238 } /* ng_btsocket_l2cap_raw_get_token */
1241 * Send Netgraph message to the node - do not expect reply
1245 ng_btsocket_l2cap_raw_send_ngmsg(hook_p hook
, int cmd
, void *arg
, int arglen
)
1247 struct ng_mesg
*msg
= NULL
;
1250 NG_MKMESSAGE(msg
, NGM_L2CAP_COOKIE
, cmd
, arglen
, M_NOWAIT
);
1254 if (arg
!= NULL
&& arglen
> 0)
1255 bcopy(arg
, msg
->data
, arglen
);
1257 NG_SEND_MSG_HOOK(error
, ng_btsocket_l2cap_raw_node
, msg
, hook
, 0);
1260 } /* ng_btsocket_l2cap_raw_send_ngmsg */
1263 * Send Netgraph message to the node (no data) and wait for reply
1267 ng_btsocket_l2cap_raw_send_sync_ngmsg(ng_btsocket_l2cap_raw_pcb_p pcb
,
1268 int cmd
, void *rsp
, int rsplen
)
1270 struct ng_mesg
*msg
= NULL
;
1273 mtx_assert(&pcb
->pcb_mtx
, MA_OWNED
);
1275 NG_MKMESSAGE(msg
, NGM_L2CAP_COOKIE
, cmd
, 0, M_NOWAIT
);
1279 ng_btsocket_l2cap_raw_get_token(&msg
->header
.token
);
1280 pcb
->token
= msg
->header
.token
;
1283 NG_SEND_MSG_HOOK(error
, ng_btsocket_l2cap_raw_node
, msg
,
1290 error
= msleep(&pcb
->msg
, &pcb
->pcb_mtx
, PZERO
|PCATCH
, "l2ctl",
1291 ng_btsocket_l2cap_raw_ioctl_timeout
* hz
);
1297 if (pcb
->msg
!= NULL
&& pcb
->msg
->header
.cmd
== cmd
)
1298 bcopy(pcb
->msg
->data
, rsp
, rsplen
);
1302 NG_FREE_MSG(pcb
->msg
); /* checks for != NULL */
1305 } /* ng_btsocket_l2cap_raw_send_sync_ngmsg */