ng_btsocket_l2cap_raw.c revision 149382
1/*
2 * ng_btsocket_l2cap_raw.c
3 */
4
5/*-
6 * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * $Id: ng_btsocket_l2cap_raw.c,v 1.12 2003/09/14 23:29:06 max Exp $
31 * $FreeBSD: head/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap_raw.c 149382 2005-08-23 00:50:59Z emax $
32 */
33
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>
42#include <sys/lock.h>
43#include <sys/malloc.h>
44#include <sys/mbuf.h>
45#include <sys/mutex.h>
46#include <sys/protosw.h>
47#include <sys/queue.h>
48#include <sys/socket.h>
49#include <sys/socketvar.h>
50#include <sys/sysctl.h>
51#include <sys/taskqueue.h>
52#include <netgraph/ng_message.h>
53#include <netgraph/netgraph.h>
54#include <netgraph/bluetooth/include/ng_bluetooth.h>
55#include <netgraph/bluetooth/include/ng_hci.h>
56#include <netgraph/bluetooth/include/ng_l2cap.h>
57#include <netgraph/bluetooth/include/ng_btsocket.h>
58#include <netgraph/bluetooth/include/ng_btsocket_l2cap.h>
59
60/* MALLOC define */
61#ifdef NG_SEPARATE_MALLOC
62MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_L2CAP_RAW, "netgraph_btsocks_l2cap_raw",
63		"Netgraph Bluetooth raw L2CAP sockets");
64#else
65#define M_NETGRAPH_BTSOCKET_L2CAP_RAW M_NETGRAPH
66#endif /* NG_SEPARATE_MALLOC */
67
68/* Netgraph node methods */
69static ng_constructor_t	ng_btsocket_l2cap_raw_node_constructor;
70static ng_rcvmsg_t	ng_btsocket_l2cap_raw_node_rcvmsg;
71static ng_shutdown_t	ng_btsocket_l2cap_raw_node_shutdown;
72static ng_newhook_t	ng_btsocket_l2cap_raw_node_newhook;
73static ng_connect_t	ng_btsocket_l2cap_raw_node_connect;
74static ng_rcvdata_t	ng_btsocket_l2cap_raw_node_rcvdata;
75static ng_disconnect_t	ng_btsocket_l2cap_raw_node_disconnect;
76
77static void		ng_btsocket_l2cap_raw_input     (void *, int);
78static void		ng_btsocket_l2cap_raw_rtclean   (void *, int);
79static void		ng_btsocket_l2cap_raw_get_token (u_int32_t *);
80
81static int		ng_btsocket_l2cap_raw_send_ngmsg
82				(hook_p, int, void *, int);
83static int		ng_btsocket_l2cap_raw_send_sync_ngmsg
84				(ng_btsocket_l2cap_raw_pcb_p, int, void *, int);
85
86#define ng_btsocket_l2cap_raw_wakeup_input_task() \
87	taskqueue_enqueue(taskqueue_swi, &ng_btsocket_l2cap_raw_queue_task)
88
89#define ng_btsocket_l2cap_raw_wakeup_route_task() \
90	taskqueue_enqueue(taskqueue_swi, &ng_btsocket_l2cap_raw_rt_task)
91
92/* Netgraph type descriptor */
93static struct ng_type	typestruct = {
94	.version =	NG_ABI_VERSION,
95	.name =		NG_BTSOCKET_L2CAP_RAW_NODE_TYPE,
96	.constructor =	ng_btsocket_l2cap_raw_node_constructor,
97	.rcvmsg =	ng_btsocket_l2cap_raw_node_rcvmsg,
98	.shutdown =	ng_btsocket_l2cap_raw_node_shutdown,
99	.newhook =	ng_btsocket_l2cap_raw_node_newhook,
100	.connect =	ng_btsocket_l2cap_raw_node_connect,
101	.rcvdata =	ng_btsocket_l2cap_raw_node_rcvdata,
102	.disconnect =	ng_btsocket_l2cap_raw_node_disconnect,
103};
104
105/* Globals */
106extern int					ifqmaxlen;
107static u_int32_t				ng_btsocket_l2cap_raw_debug_level;
108static u_int32_t				ng_btsocket_l2cap_raw_ioctl_timeout;
109static node_p					ng_btsocket_l2cap_raw_node;
110static struct ng_bt_itemq			ng_btsocket_l2cap_raw_queue;
111static struct mtx				ng_btsocket_l2cap_raw_queue_mtx;
112static struct task				ng_btsocket_l2cap_raw_queue_task;
113static LIST_HEAD(, ng_btsocket_l2cap_raw_pcb)	ng_btsocket_l2cap_raw_sockets;
114static struct mtx				ng_btsocket_l2cap_raw_sockets_mtx;
115static u_int32_t				ng_btsocket_l2cap_raw_token;
116static struct mtx				ng_btsocket_l2cap_raw_token_mtx;
117static LIST_HEAD(, ng_btsocket_l2cap_rtentry)	ng_btsocket_l2cap_raw_rt;
118static struct mtx				ng_btsocket_l2cap_raw_rt_mtx;
119static struct task				ng_btsocket_l2cap_raw_rt_task;
120
121/* Sysctl tree */
122SYSCTL_DECL(_net_bluetooth_l2cap_sockets);
123SYSCTL_NODE(_net_bluetooth_l2cap_sockets, OID_AUTO, raw, CTLFLAG_RW,
124	0, "Bluetooth raw L2CAP sockets family");
125SYSCTL_INT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, debug_level,
126	CTLFLAG_RW,
127	&ng_btsocket_l2cap_raw_debug_level, NG_BTSOCKET_WARN_LEVEL,
128	"Bluetooth raw L2CAP sockets debug level");
129SYSCTL_INT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, ioctl_timeout,
130	CTLFLAG_RW,
131	&ng_btsocket_l2cap_raw_ioctl_timeout, 5,
132	"Bluetooth raw L2CAP sockets ioctl timeout");
133SYSCTL_INT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, queue_len,
134	CTLFLAG_RD,
135	&ng_btsocket_l2cap_raw_queue.len, 0,
136	"Bluetooth raw L2CAP sockets input queue length");
137SYSCTL_INT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, queue_maxlen,
138	CTLFLAG_RD,
139	&ng_btsocket_l2cap_raw_queue.maxlen, 0,
140	"Bluetooth raw L2CAP sockets input queue max. length");
141SYSCTL_INT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, queue_drops,
142	CTLFLAG_RD,
143	&ng_btsocket_l2cap_raw_queue.drops, 0,
144	"Bluetooth raw L2CAP sockets input queue drops");
145
146/* Debug */
147#define NG_BTSOCKET_L2CAP_RAW_INFO \
148	if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_INFO_LEVEL) \
149		printf
150
151#define NG_BTSOCKET_L2CAP_RAW_WARN \
152	if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_WARN_LEVEL) \
153		printf
154
155#define NG_BTSOCKET_L2CAP_RAW_ERR \
156	if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_ERR_LEVEL) \
157		printf
158
159#define NG_BTSOCKET_L2CAP_RAW_ALERT \
160	if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_ALERT_LEVEL) \
161		printf
162
163/*****************************************************************************
164 *****************************************************************************
165 **                        Netgraph node interface
166 *****************************************************************************
167 *****************************************************************************/
168
169/*
170 * Netgraph node constructor. Do not allow to create node of this type.
171 */
172
173static int
174ng_btsocket_l2cap_raw_node_constructor(node_p node)
175{
176	return (EINVAL);
177} /* ng_btsocket_l2cap_raw_node_constructor */
178
179/*
180 * Do local shutdown processing. Let old node go and create new fresh one.
181 */
182
183static int
184ng_btsocket_l2cap_raw_node_shutdown(node_p node)
185{
186	int	error = 0;
187
188	NG_NODE_UNREF(node);
189
190	/* Create new node */
191	error = ng_make_node_common(&typestruct, &ng_btsocket_l2cap_raw_node);
192	if (error != 0) {
193		NG_BTSOCKET_L2CAP_RAW_ALERT(
194"%s: Could not create Netgraph node, error=%d\n", __func__, error);
195
196		ng_btsocket_l2cap_raw_node = NULL;
197
198		return (error);
199	}
200
201	error = ng_name_node(ng_btsocket_l2cap_raw_node,
202				NG_BTSOCKET_L2CAP_RAW_NODE_TYPE);
203	if (error != 0) {
204		NG_BTSOCKET_L2CAP_RAW_ALERT(
205"%s: Could not name Netgraph node, error=%d\n", __func__, error);
206
207		NG_NODE_UNREF(ng_btsocket_l2cap_raw_node);
208		ng_btsocket_l2cap_raw_node = NULL;
209
210		return (error);
211	}
212
213	return (0);
214} /* ng_btsocket_l2cap_raw_node_shutdown */
215
216/*
217 * We allow any hook to be connected to the node.
218 */
219
220static int
221ng_btsocket_l2cap_raw_node_newhook(node_p node, hook_p hook, char const *name)
222{
223	return (0);
224} /* ng_btsocket_l2cap_raw_node_newhook */
225
226/*
227 * Just say "YEP, that's OK by me!"
228 */
229
230static int
231ng_btsocket_l2cap_raw_node_connect(hook_p hook)
232{
233	NG_HOOK_SET_PRIVATE(hook, NULL);
234	NG_HOOK_REF(hook); /* Keep extra reference to the hook */
235
236	return (0);
237} /* ng_btsocket_l2cap_raw_node_connect */
238
239/*
240 * Hook disconnection. Schedule route cleanup task
241 */
242
243static int
244ng_btsocket_l2cap_raw_node_disconnect(hook_p hook)
245{
246	/*
247	 * If hook has private information than we must have this hook in
248	 * the routing table and must schedule cleaning for the routing table.
249	 * Otherwise hook was connected but we never got "hook_info" message,
250	 * so we have never added this hook to the routing table and it save
251	 * to just delete it.
252	 */
253
254	if (NG_HOOK_PRIVATE(hook) != NULL)
255		return (ng_btsocket_l2cap_raw_wakeup_route_task());
256
257	NG_HOOK_UNREF(hook); /* Remove extra reference */
258
259	return (0);
260} /* ng_btsocket_l2cap_raw_node_disconnect */
261
262/*
263 * Process incoming messages
264 */
265
266static int
267ng_btsocket_l2cap_raw_node_rcvmsg(node_p node, item_p item, hook_p hook)
268{
269	struct ng_mesg	*msg = NGI_MSG(item); /* item still has message */
270	int		 error = 0;
271
272	if (msg != NULL && msg->header.typecookie == NGM_L2CAP_COOKIE) {
273
274		/*
275		 * NGM_L2CAP_NODE_HOOK_INFO is special message initiated by
276		 * L2CAP layer. Ignore all other messages if they are not
277		 * replies or token is zero
278		 */
279
280		if (msg->header.cmd != NGM_L2CAP_NODE_HOOK_INFO) {
281			if (msg->header.token == 0 ||
282			    !(msg->header.flags & NGF_RESP)) {
283				NG_FREE_ITEM(item);
284				return (0);
285			}
286		}
287
288		mtx_lock(&ng_btsocket_l2cap_raw_queue_mtx);
289		if (NG_BT_ITEMQ_FULL(&ng_btsocket_l2cap_raw_queue)) {
290			NG_BTSOCKET_L2CAP_RAW_ERR(
291"%s: Input queue is full\n", __func__);
292
293			NG_BT_ITEMQ_DROP(&ng_btsocket_l2cap_raw_queue);
294			NG_FREE_ITEM(item);
295			error = ENOBUFS;
296		} else {
297			if (hook != NULL) {
298				NG_HOOK_REF(hook);
299				NGI_SET_HOOK(item, hook);
300			}
301
302			NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_l2cap_raw_queue, item);
303			error = ng_btsocket_l2cap_raw_wakeup_input_task();
304		}
305		mtx_unlock(&ng_btsocket_l2cap_raw_queue_mtx);
306	} else {
307		NG_FREE_ITEM(item);
308		error = EINVAL;
309	}
310
311	return (error);
312} /* ng_btsocket_l2cap_raw_node_rcvmsg */
313
314/*
315 * Receive data on a hook
316 */
317
318static int
319ng_btsocket_l2cap_raw_node_rcvdata(hook_p hook, item_p item)
320{
321	NG_FREE_ITEM(item);
322
323	return (EINVAL);
324} /* ng_btsocket_l2cap_raw_node_rcvdata */
325
326/*****************************************************************************
327 *****************************************************************************
328 **                              Socket interface
329 *****************************************************************************
330 *****************************************************************************/
331
332/*
333 * L2CAP sockets input routine
334 */
335
336static void
337ng_btsocket_l2cap_raw_input(void *context, int pending)
338{
339	item_p		 item = NULL;
340	hook_p		 hook = NULL;
341	struct ng_mesg  *msg = NULL;
342
343	for (;;) {
344		mtx_lock(&ng_btsocket_l2cap_raw_queue_mtx);
345		NG_BT_ITEMQ_DEQUEUE(&ng_btsocket_l2cap_raw_queue, item);
346		mtx_unlock(&ng_btsocket_l2cap_raw_queue_mtx);
347
348		if (item == NULL)
349			break;
350
351		KASSERT((item->el_flags & NGQF_TYPE) == NGQF_MESG,
352("%s: invalid item type=%ld\n", __func__, (item->el_flags & NGQF_TYPE)));
353
354		NGI_GET_MSG(item, msg);
355		NGI_GET_HOOK(item, hook);
356		NG_FREE_ITEM(item);
357
358		switch (msg->header.cmd) {
359		case NGM_L2CAP_NODE_HOOK_INFO: {
360			ng_btsocket_l2cap_rtentry_t	*rt = NULL;
361
362			if (hook == NULL || NG_HOOK_NOT_VALID(hook) ||
363			    msg->header.arglen != sizeof(bdaddr_t))
364				break;
365
366			if (bcmp(msg->data, NG_HCI_BDADDR_ANY,
367					sizeof(bdaddr_t)) == 0)
368				break;
369
370			rt = (ng_btsocket_l2cap_rtentry_t *)
371				NG_HOOK_PRIVATE(hook);
372			if (rt == NULL) {
373				MALLOC(rt, ng_btsocket_l2cap_rtentry_p,
374					sizeof(*rt),
375					M_NETGRAPH_BTSOCKET_L2CAP_RAW,
376					M_NOWAIT|M_ZERO);
377				if (rt == NULL)
378					break;
379
380				NG_HOOK_SET_PRIVATE(hook, rt);
381
382				mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
383
384				LIST_INSERT_HEAD(&ng_btsocket_l2cap_raw_rt,
385					rt, next);
386			} else
387				mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
388
389			bcopy(msg->data, &rt->src, sizeof(rt->src));
390			rt->hook = hook;
391
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]);
397
398			mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);
399			} break;
400
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;
409
410			mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);
411
412			LIST_FOREACH(pcb,&ng_btsocket_l2cap_raw_sockets,next) {
413				mtx_lock(&pcb->pcb_mtx);
414
415				if (pcb->token == msg->header.token) {
416					pcb->msg = msg;
417					msg = NULL;
418					wakeup(&pcb->msg);
419					mtx_unlock(&pcb->pcb_mtx);
420					break;
421				}
422
423				mtx_unlock(&pcb->pcb_mtx);
424			}
425
426			mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);
427			} break;
428
429		default:
430			NG_BTSOCKET_L2CAP_RAW_WARN(
431"%s: Unknown message, cmd=%d\n", __func__, msg->header.cmd);
432			break;
433		}
434
435		if (hook != NULL)
436			NG_HOOK_UNREF(hook); /* remove extra reference */
437
438		NG_FREE_MSG(msg); /* Checks for msg != NULL */
439	}
440} /* ng_btsocket_l2cap_raw_input */
441
442/*
443 * Route cleanup task. Gets scheduled when hook is disconnected. Here we
444 * will find all sockets that use "invalid" hook and disconnect them.
445 */
446
447static void
448ng_btsocket_l2cap_raw_rtclean(void *context, int pending)
449{
450	ng_btsocket_l2cap_raw_pcb_p	pcb = NULL;
451	ng_btsocket_l2cap_rtentry_p	rt = NULL;
452
453	/*
454	 * First disconnect all sockets that use "invalid" hook
455	 */
456
457	mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);
458
459	LIST_FOREACH(pcb, &ng_btsocket_l2cap_raw_sockets, next) {
460		mtx_lock(&pcb->pcb_mtx);
461
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);
467
468			pcb->rt = NULL;
469		}
470
471		mtx_unlock(&pcb->pcb_mtx);
472	}
473
474	mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);
475
476	/*
477	 * Now cleanup routing table
478	 */
479
480	mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
481
482	for (rt = LIST_FIRST(&ng_btsocket_l2cap_raw_rt); rt != NULL; ) {
483		ng_btsocket_l2cap_rtentry_p	rt_next = LIST_NEXT(rt, next);
484
485		if (rt->hook != NULL && NG_HOOK_NOT_VALID(rt->hook)) {
486			LIST_REMOVE(rt, next);
487
488			NG_HOOK_SET_PRIVATE(rt->hook, NULL);
489			NG_HOOK_UNREF(rt->hook); /* Remove extra reference */
490
491			bzero(rt, sizeof(*rt));
492			FREE(rt, M_NETGRAPH_BTSOCKET_L2CAP_RAW);
493		}
494
495		rt = rt_next;
496	}
497
498	mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);
499} /* ng_btsocket_l2cap_raw_rtclean */
500
501/*
502 * Initialize everything
503 */
504
505void
506ng_btsocket_l2cap_raw_init(void)
507{
508	int	error = 0;
509
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;
513
514	/* Register Netgraph node type */
515	error = ng_newtype(&typestruct);
516	if (error != 0) {
517		NG_BTSOCKET_L2CAP_RAW_ALERT(
518"%s: Could not register Netgraph node type, error=%d\n", __func__, error);
519
520                return;
521	}
522
523	/* Create Netgrapg node */
524	error = ng_make_node_common(&typestruct, &ng_btsocket_l2cap_raw_node);
525	if (error != 0) {
526		NG_BTSOCKET_L2CAP_RAW_ALERT(
527"%s: Could not create Netgraph node, error=%d\n", __func__, error);
528
529		ng_btsocket_l2cap_raw_node = NULL;
530
531		return;
532	}
533
534	error = ng_name_node(ng_btsocket_l2cap_raw_node,
535				NG_BTSOCKET_L2CAP_RAW_NODE_TYPE);
536	if (error != 0) {
537		NG_BTSOCKET_L2CAP_RAW_ALERT(
538"%s: Could not name Netgraph node, error=%d\n", __func__, error);
539
540		NG_NODE_UNREF(ng_btsocket_l2cap_raw_node);
541		ng_btsocket_l2cap_raw_node = NULL;
542
543		return;
544	}
545
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);
552
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);
557
558	/* Tokens */
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);
562
563	/* Routing table */
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 */
570
571/*
572 * Abort connection on socket
573 */
574
575int
576ng_btsocket_l2cap_raw_abort(struct socket *so)
577{
578	return (ng_btsocket_l2cap_raw_detach(so));
579} /* ng_btsocket_l2cap_raw_abort */
580
581/*
582 * Create and attach new socket
583 */
584
585int
586ng_btsocket_l2cap_raw_attach(struct socket *so, int proto, struct thread *td)
587{
588	ng_btsocket_l2cap_raw_pcb_p	pcb = so2l2cap_raw_pcb(so);
589	int				error;
590
591	if (pcb != NULL)
592		return (EISCONN);
593
594	if (ng_btsocket_l2cap_raw_node == NULL)
595		return (EPROTONOSUPPORT);
596	if (so->so_type != SOCK_RAW)
597		return (ESOCKTNOSUPPORT);
598
599	/* Reserve send and receive space if it is not reserved yet */
600	error = soreserve(so, NG_BTSOCKET_L2CAP_RAW_SENDSPACE,
601			NG_BTSOCKET_L2CAP_RAW_RECVSPACE);
602	if (error != 0)
603		return (error);
604
605	/* Allocate the PCB */
606        MALLOC(pcb, ng_btsocket_l2cap_raw_pcb_p, sizeof(*pcb),
607		M_NETGRAPH_BTSOCKET_L2CAP_RAW, M_NOWAIT|M_ZERO);
608        if (pcb == NULL)
609                return (ENOMEM);
610
611	/* Link the PCB and the socket */
612	so->so_pcb = (caddr_t) pcb;
613	pcb->so = so;
614
615	if (suser(td) == 0)
616		pcb->flags |= NG_BTSOCKET_L2CAP_RAW_PRIVILEGED;
617
618	mtx_init(&pcb->pcb_mtx, "btsocks_l2cap_raw_pcb_mtx", NULL, MTX_DEF);
619
620        /* Add the PCB to the list */
621	mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);
622	LIST_INSERT_HEAD(&ng_btsocket_l2cap_raw_sockets, pcb, next);
623	mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);
624
625        return (0);
626} /* ng_btsocket_l2cap_raw_attach */
627
628/*
629 * Bind socket
630 */
631
632int
633ng_btsocket_l2cap_raw_bind(struct socket *so, struct sockaddr *nam,
634		struct thread *td)
635{
636	ng_btsocket_l2cap_raw_pcb_t	*pcb = so2l2cap_raw_pcb(so);
637	struct sockaddr_l2cap		*sa = (struct sockaddr_l2cap *) nam;
638	ng_btsocket_l2cap_rtentry_t	*rt = NULL;
639
640	if (pcb == NULL)
641		return (EINVAL);
642	if (ng_btsocket_l2cap_raw_node == NULL)
643		return (EINVAL);
644
645	if (sa == NULL)
646		return (EINVAL);
647	if (sa->l2cap_family != AF_BLUETOOTH)
648		return (EAFNOSUPPORT);
649	if (sa->l2cap_len != sizeof(*sa))
650		return (EINVAL);
651
652	if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY,
653				sizeof(sa->l2cap_bdaddr)) != 0) {
654		mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
655
656		LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) {
657			if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
658				continue;
659
660			if (bcmp(&sa->l2cap_bdaddr, &rt->src,
661					sizeof(rt->src)) == 0)
662				break;
663		}
664
665		mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);
666
667		if (rt == NULL)
668			return (ENETDOWN);
669	} else
670		rt = NULL;
671
672	mtx_lock(&pcb->pcb_mtx);
673	bcopy(&sa->l2cap_bdaddr, &pcb->src, sizeof(pcb->src));
674	pcb->rt = rt;
675	mtx_unlock(&pcb->pcb_mtx);
676
677	return (0);
678} /* ng_btsocket_l2cap_raw_bind */
679
680/*
681 * Connect socket
682 */
683
684int
685ng_btsocket_l2cap_raw_connect(struct socket *so, struct sockaddr *nam,
686		struct thread *td)
687{
688	ng_btsocket_l2cap_raw_pcb_t	*pcb = so2l2cap_raw_pcb(so);
689	struct sockaddr_l2cap		*sa = (struct sockaddr_l2cap *) nam;
690	ng_btsocket_l2cap_rtentry_t	*rt = NULL;
691	int				 error;
692
693	if (pcb == NULL)
694		return (EINVAL);
695	if (ng_btsocket_l2cap_raw_node == NULL)
696		return (EINVAL);
697
698	if (sa == NULL)
699		return (EINVAL);
700	if (sa->l2cap_family != AF_BLUETOOTH)
701		return (EAFNOSUPPORT);
702	if (sa->l2cap_len != sizeof(*sa))
703		return (EINVAL);
704	if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
705		return (EINVAL);
706
707	mtx_lock(&pcb->pcb_mtx);
708
709	bcopy(&sa->l2cap_bdaddr, &pcb->dst, sizeof(pcb->dst));
710
711	if (bcmp(&pcb->src, &pcb->dst, sizeof(pcb->src)) == 0) {
712		mtx_unlock(&pcb->pcb_mtx);
713
714		return (EADDRNOTAVAIL);
715	}
716
717	/*
718	 * If there is route already - use it
719	 */
720
721	if (pcb->rt != NULL) {
722		soisconnected(so);
723		mtx_unlock(&pcb->pcb_mtx);
724
725		return (0);
726	}
727
728	/*
729	 * Find the first hook that does not match specified destination address
730	 */
731
732	mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
733
734	LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) {
735		if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
736			continue;
737
738		if (bcmp(&pcb->dst, &rt->src, sizeof(rt->src)) != 0)
739			break;
740	}
741
742	if (rt != NULL) {
743		soisconnected(so);
744
745		pcb->rt = rt;
746		bcopy(&rt->src, &pcb->src, sizeof(pcb->src));
747
748		error = 0;
749	} else
750		error = ENETDOWN;
751
752	mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);
753	mtx_unlock(&pcb->pcb_mtx);
754
755	return  (error);
756} /* ng_btsocket_l2cap_raw_connect */
757
758/*
759 * Process ioctl's calls on socket
760 */
761
762int
763ng_btsocket_l2cap_raw_control(struct socket *so, u_long cmd, caddr_t data,
764		struct ifnet *ifp, struct thread *td)
765{
766	ng_btsocket_l2cap_raw_pcb_p	 pcb = so2l2cap_raw_pcb(so);
767	struct ng_mesg			*msg = NULL;
768	int				 error = 0;
769
770	if (pcb == NULL)
771		return (EINVAL);
772	if (ng_btsocket_l2cap_raw_node == NULL)
773		return (EINVAL);
774
775	mtx_lock(&pcb->pcb_mtx);
776
777	/* Check if we route info */
778	if (pcb->rt == NULL) {
779		mtx_unlock(&pcb->pcb_mtx);
780		return (EHOSTUNREACH);
781	}
782
783	/* Check if we have pending ioctl() */
784	if (pcb->token != 0) {
785		mtx_unlock(&pcb->pcb_mtx);
786		return (EBUSY);
787	}
788
789	switch (cmd) {
790	case SIOC_L2CAP_NODE_GET_FLAGS: {
791		struct ng_btsocket_l2cap_raw_node_flags	*p =
792			(struct ng_btsocket_l2cap_raw_node_flags *) data;
793
794		error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,
795				NGM_L2CAP_NODE_GET_FLAGS,
796				&p->flags, sizeof(p->flags));
797		} break;
798
799	case SIOC_L2CAP_NODE_GET_DEBUG: {
800		struct ng_btsocket_l2cap_raw_node_debug	*p =
801			(struct ng_btsocket_l2cap_raw_node_debug *) data;
802
803		error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,
804				NGM_L2CAP_NODE_GET_DEBUG,
805				&p->debug, sizeof(p->debug));
806		} break;
807
808	case SIOC_L2CAP_NODE_SET_DEBUG: {
809		struct ng_btsocket_l2cap_raw_node_debug	*p =
810			(struct ng_btsocket_l2cap_raw_node_debug *) data;
811
812		if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)
813			error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook,
814					NGM_L2CAP_NODE_SET_DEBUG,
815					&p->debug, sizeof(p->debug));
816		else
817			error = EPERM;
818		} break;
819
820	case SIOC_L2CAP_NODE_GET_CON_LIST: {
821		struct ng_btsocket_l2cap_raw_con_list	*p =
822			(struct ng_btsocket_l2cap_raw_con_list *) data;
823		ng_l2cap_node_con_list_ep		*p1 = NULL;
824                ng_l2cap_node_con_ep			*p2 = NULL;
825
826		if (p->num_connections == 0 ||
827		    p->num_connections > NG_L2CAP_MAX_CON_NUM ||
828		    p->connections == NULL) {
829			error = EINVAL;
830			break;
831		}
832
833		NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_NODE_GET_CON_LIST,
834			0, M_NOWAIT);
835		if (msg == NULL) {
836			error = ENOMEM;
837			break;
838		}
839		ng_btsocket_l2cap_raw_get_token(&msg->header.token);
840		pcb->token = msg->header.token;
841		pcb->msg = NULL;
842
843		NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
844			pcb->rt->hook, 0);
845		if (error != 0) {
846			pcb->token = 0;
847			break;
848		}
849
850		error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
851				ng_btsocket_l2cap_raw_ioctl_timeout * hz);
852		pcb->token = 0;
853
854		if (error != 0)
855			break;
856
857		if (pcb->msg != NULL &&
858		    pcb->msg->header.cmd == NGM_L2CAP_NODE_GET_CON_LIST) {
859			/* Return data back to user space */
860			p1 = (ng_l2cap_node_con_list_ep *)(pcb->msg->data);
861			p2 = (ng_l2cap_node_con_ep *)(p1 + 1);
862
863			p->num_connections = min(p->num_connections,
864						p1->num_connections);
865			if (p->num_connections > 0)
866				error = copyout((caddr_t) p2,
867					(caddr_t) p->connections,
868					p->num_connections * sizeof(*p2));
869		} else
870			error = EINVAL;
871
872		NG_FREE_MSG(pcb->msg); /* checks for != NULL */
873		} break;
874
875	case SIOC_L2CAP_NODE_GET_CHAN_LIST: {
876		struct ng_btsocket_l2cap_raw_chan_list	*p =
877			(struct ng_btsocket_l2cap_raw_chan_list *) data;
878		ng_l2cap_node_chan_list_ep		*p1 = NULL;
879                ng_l2cap_node_chan_ep			*p2 = NULL;
880
881		if (p->num_channels == 0 ||
882		    p->num_channels > NG_L2CAP_MAX_CHAN_NUM ||
883		    p->channels == NULL) {
884			error = EINVAL;
885			break;
886		}
887
888		NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE,
889			NGM_L2CAP_NODE_GET_CHAN_LIST, 0, M_NOWAIT);
890		if (msg == NULL) {
891			error = ENOMEM;
892			break;
893		}
894		ng_btsocket_l2cap_raw_get_token(&msg->header.token);
895		pcb->token = msg->header.token;
896		pcb->msg = NULL;
897
898		NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
899			pcb->rt->hook, 0);
900		if (error != 0) {
901			pcb->token = 0;
902			break;
903		}
904
905		error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
906				ng_btsocket_l2cap_raw_ioctl_timeout * hz);
907		pcb->token = 0;
908
909		if (error != 0)
910			break;
911
912		if (pcb->msg != NULL &&
913		    pcb->msg->header.cmd == NGM_L2CAP_NODE_GET_CHAN_LIST) {
914			/* Return data back to user space */
915			p1 = (ng_l2cap_node_chan_list_ep *)(pcb->msg->data);
916			p2 = (ng_l2cap_node_chan_ep *)(p1 + 1);
917
918			p->num_channels = min(p->num_channels,
919						p1->num_channels);
920			if (p->num_channels > 0)
921				error = copyout((caddr_t) p2,
922						(caddr_t) p->channels,
923						p->num_channels * sizeof(*p2));
924		} else
925			error = EINVAL;
926
927		NG_FREE_MSG(pcb->msg); /* checks for != NULL */
928		} break;
929
930	case SIOC_L2CAP_L2CA_PING: {
931		struct ng_btsocket_l2cap_raw_ping	*p =
932			(struct ng_btsocket_l2cap_raw_ping *) data;
933		ng_l2cap_l2ca_ping_ip			*ip = NULL;
934		ng_l2cap_l2ca_ping_op			*op = NULL;
935
936		if (!(pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)) {
937			error = EPERM;
938			break;
939		}
940
941		if ((p->echo_size != 0 && p->echo_data == NULL) ||
942		     p->echo_size > NG_L2CAP_MAX_ECHO_SIZE) {
943			error = EINVAL;
944			break;
945		}
946
947		NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE,
948			NGM_L2CAP_L2CA_PING, sizeof(*ip) + p->echo_size,
949			M_NOWAIT);
950		if (msg == NULL) {
951			error = ENOMEM;
952			break;
953		}
954		ng_btsocket_l2cap_raw_get_token(&msg->header.token);
955		pcb->token = msg->header.token;
956		pcb->msg = NULL;
957
958		ip = (ng_l2cap_l2ca_ping_ip *)(msg->data);
959		bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr));
960		ip->echo_size = p->echo_size;
961
962		if (ip->echo_size > 0) {
963			error = copyin(p->echo_data, ip + 1, p->echo_size);
964			if (error != 0) {
965				NG_FREE_MSG(msg);
966				pcb->token = 0;
967				break;
968			}
969		}
970
971		NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
972			pcb->rt->hook, 0);
973		if (error != 0) {
974			pcb->token = 0;
975			break;
976		}
977
978		error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
979				bluetooth_l2cap_rtx_timeout());
980		pcb->token = 0;
981
982		if (error != 0)
983			break;
984
985		if (pcb->msg != NULL &&
986		    pcb->msg->header.cmd == NGM_L2CAP_L2CA_PING) {
987			/* Return data back to the user space */
988			op = (ng_l2cap_l2ca_ping_op *)(pcb->msg->data);
989			p->result = op->result;
990			p->echo_size = min(p->echo_size, op->echo_size);
991
992			if (p->echo_size > 0)
993				error = copyout(op + 1, p->echo_data,
994						p->echo_size);
995		} else
996			error = EINVAL;
997
998		NG_FREE_MSG(pcb->msg); /* checks for != NULL */
999		} break;
1000
1001	case SIOC_L2CAP_L2CA_GET_INFO: {
1002		struct ng_btsocket_l2cap_raw_get_info	*p =
1003			(struct ng_btsocket_l2cap_raw_get_info *) data;
1004		ng_l2cap_l2ca_get_info_ip		*ip = NULL;
1005		ng_l2cap_l2ca_get_info_op		*op = NULL;
1006
1007		if (!(pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)) {
1008			error = EPERM;
1009			break;
1010		}
1011
1012		if (p->info_size != 0 && p->info_data == NULL) {
1013			error = EINVAL;
1014			break;
1015		}
1016
1017		NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE,
1018			NGM_L2CAP_L2CA_GET_INFO, sizeof(*ip) + p->info_size,
1019			M_NOWAIT);
1020		if (msg == NULL) {
1021			error = ENOMEM;
1022			break;
1023		}
1024		ng_btsocket_l2cap_raw_get_token(&msg->header.token);
1025		pcb->token = msg->header.token;
1026		pcb->msg = NULL;
1027
1028		ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data);
1029		bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr));
1030		ip->info_type = p->info_type;
1031
1032		NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
1033			pcb->rt->hook, 0);
1034		if (error != 0) {
1035			pcb->token = 0;
1036			break;
1037		}
1038
1039		error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
1040				bluetooth_l2cap_rtx_timeout());
1041		pcb->token = 0;
1042
1043		if (error != 0)
1044			break;
1045
1046		if (pcb->msg != NULL &&
1047		    pcb->msg->header.cmd == NGM_L2CAP_L2CA_GET_INFO) {
1048			/* Return data back to the user space */
1049			op = (ng_l2cap_l2ca_get_info_op *)(pcb->msg->data);
1050			p->result = op->result;
1051			p->info_size = min(p->info_size, op->info_size);
1052
1053			if (p->info_size > 0)
1054				error = copyout(op + 1, p->info_data,
1055						p->info_size);
1056		} else
1057			error = EINVAL;
1058
1059		NG_FREE_MSG(pcb->msg); /* checks for != NULL */
1060		} break;
1061
1062	case SIOC_L2CAP_NODE_GET_AUTO_DISCON_TIMO: {
1063		struct ng_btsocket_l2cap_raw_auto_discon_timo	*p =
1064			(struct ng_btsocket_l2cap_raw_auto_discon_timo *) data;
1065
1066		error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,
1067				NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO,
1068				&p->timeout, sizeof(p->timeout));
1069		} break;
1070
1071	case SIOC_L2CAP_NODE_SET_AUTO_DISCON_TIMO: {
1072		struct ng_btsocket_l2cap_raw_auto_discon_timo	*p =
1073			(struct ng_btsocket_l2cap_raw_auto_discon_timo *) data;
1074
1075		if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)
1076			error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook,
1077					NGM_L2CAP_NODE_SET_AUTO_DISCON_TIMO,
1078					&p->timeout, sizeof(p->timeout));
1079		else
1080			error = EPERM;
1081		} break;
1082
1083	default:
1084		error = EINVAL;
1085		break;
1086	}
1087
1088	mtx_unlock(&pcb->pcb_mtx);
1089
1090	return (error);
1091} /* ng_btsocket_l2cap_raw_control */
1092
1093/*
1094 * Detach and destroy socket
1095 */
1096
1097int
1098ng_btsocket_l2cap_raw_detach(struct socket *so)
1099{
1100	ng_btsocket_l2cap_raw_pcb_p	pcb = so2l2cap_raw_pcb(so);
1101
1102	if (pcb == NULL)
1103		return (EINVAL);
1104	if (ng_btsocket_l2cap_raw_node == NULL)
1105		return (EINVAL);
1106
1107	mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);
1108	mtx_lock(&pcb->pcb_mtx);
1109
1110	LIST_REMOVE(pcb, next);
1111
1112	mtx_unlock(&pcb->pcb_mtx);
1113	mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);
1114
1115	mtx_destroy(&pcb->pcb_mtx);
1116
1117	bzero(pcb, sizeof(*pcb));
1118	FREE(pcb, M_NETGRAPH_BTSOCKET_L2CAP_RAW);
1119
1120	ACCEPT_LOCK();
1121	SOCK_LOCK(so);
1122	so->so_pcb = NULL;
1123	sotryfree(so);
1124
1125	return (0);
1126} /* ng_btsocket_l2cap_raw_detach */
1127
1128/*
1129 * Disconnect socket
1130 */
1131
1132int
1133ng_btsocket_l2cap_raw_disconnect(struct socket *so)
1134{
1135	ng_btsocket_l2cap_raw_pcb_p	pcb = so2l2cap_raw_pcb(so);
1136
1137	if (pcb == NULL)
1138		return (EINVAL);
1139	if (ng_btsocket_l2cap_raw_node == NULL)
1140		return (EINVAL);
1141
1142	mtx_lock(&pcb->pcb_mtx);
1143	pcb->rt = NULL;
1144	soisdisconnected(so);
1145	mtx_unlock(&pcb->pcb_mtx);
1146
1147	return (0);
1148} /* ng_btsocket_l2cap_raw_disconnect */
1149
1150/*
1151 * Get peer address
1152 */
1153
1154int
1155ng_btsocket_l2cap_raw_peeraddr(struct socket *so, struct sockaddr **nam)
1156{
1157	ng_btsocket_l2cap_raw_pcb_p	pcb = so2l2cap_raw_pcb(so);
1158	struct sockaddr_l2cap		sa;
1159
1160	if (pcb == NULL)
1161		return (EINVAL);
1162	if (ng_btsocket_l2cap_raw_node == NULL)
1163		return (EINVAL);
1164
1165	mtx_lock(&pcb->pcb_mtx);
1166	bcopy(&pcb->dst, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr));
1167	mtx_unlock(&pcb->pcb_mtx);
1168
1169	sa.l2cap_psm = 0;
1170	sa.l2cap_len = sizeof(sa);
1171	sa.l2cap_family = AF_BLUETOOTH;
1172
1173	*nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT);
1174
1175	return ((*nam == NULL)? ENOMEM : 0);
1176} /* ng_btsocket_l2cap_raw_peeraddr */
1177
1178/*
1179 * Send data to socket
1180 */
1181
1182int
1183ng_btsocket_l2cap_raw_send(struct socket *so, int flags, struct mbuf *m,
1184		struct sockaddr *nam, struct mbuf *control, struct thread *td)
1185{
1186	NG_FREE_M(m); /* Checks for m != NULL */
1187	NG_FREE_M(control);
1188
1189	return (EOPNOTSUPP);
1190} /* ng_btsocket_l2cap_raw_send */
1191
1192/*
1193 * Get socket address
1194 */
1195
1196int
1197ng_btsocket_l2cap_raw_sockaddr(struct socket *so, struct sockaddr **nam)
1198{
1199	ng_btsocket_l2cap_raw_pcb_p	pcb = so2l2cap_raw_pcb(so);
1200	struct sockaddr_l2cap		sa;
1201
1202	if (pcb == NULL)
1203		return (EINVAL);
1204	if (ng_btsocket_l2cap_raw_node == NULL)
1205		return (EINVAL);
1206
1207	mtx_lock(&pcb->pcb_mtx);
1208	bcopy(&pcb->src, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr));
1209	mtx_unlock(&pcb->pcb_mtx);
1210
1211	sa.l2cap_psm = 0;
1212	sa.l2cap_len = sizeof(sa);
1213	sa.l2cap_family = AF_BLUETOOTH;
1214
1215	*nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT);
1216
1217	return ((*nam == NULL)? ENOMEM : 0);
1218} /* ng_btsocket_l2cap_raw_sockaddr */
1219
1220/*
1221 * Get next token
1222 */
1223
1224static void
1225ng_btsocket_l2cap_raw_get_token(u_int32_t *token)
1226{
1227	mtx_lock(&ng_btsocket_l2cap_raw_token_mtx);
1228
1229	if (++ ng_btsocket_l2cap_raw_token == 0)
1230		ng_btsocket_l2cap_raw_token = 1;
1231
1232	*token = ng_btsocket_l2cap_raw_token;
1233
1234	mtx_unlock(&ng_btsocket_l2cap_raw_token_mtx);
1235} /* ng_btsocket_l2cap_raw_get_token */
1236
1237/*
1238 * Send Netgraph message to the node - do not expect reply
1239 */
1240
1241static int
1242ng_btsocket_l2cap_raw_send_ngmsg(hook_p hook, int cmd, void *arg, int arglen)
1243{
1244	struct ng_mesg	*msg = NULL;
1245	int		 error = 0;
1246
1247	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, arglen, M_NOWAIT);
1248	if (msg == NULL)
1249		return (ENOMEM);
1250
1251	if (arg != NULL && arglen > 0)
1252		bcopy(arg, msg->data, arglen);
1253
1254	NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, hook, 0);
1255
1256	return (error);
1257} /* ng_btsocket_l2cap_raw_send_ngmsg */
1258
1259/*
1260 * Send Netgraph message to the node (no data) and wait for reply
1261 */
1262
1263static int
1264ng_btsocket_l2cap_raw_send_sync_ngmsg(ng_btsocket_l2cap_raw_pcb_p pcb,
1265		int cmd, void *rsp, int rsplen)
1266{
1267	struct ng_mesg	*msg = NULL;
1268	int		 error = 0;
1269
1270	mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1271
1272	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, 0, M_NOWAIT);
1273	if (msg == NULL)
1274		return (ENOMEM);
1275
1276	ng_btsocket_l2cap_raw_get_token(&msg->header.token);
1277	pcb->token = msg->header.token;
1278	pcb->msg = NULL;
1279
1280	NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
1281		pcb->rt->hook, 0);
1282	if (error != 0) {
1283		pcb->token = 0;
1284		return (error);
1285	}
1286
1287	error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
1288			ng_btsocket_l2cap_raw_ioctl_timeout * hz);
1289	pcb->token = 0;
1290
1291	if (error != 0)
1292		return (error);
1293
1294	if (pcb->msg != NULL && pcb->msg->header.cmd == cmd)
1295		bcopy(pcb->msg->data, rsp, rsplen);
1296	else
1297		error = EINVAL;
1298
1299	NG_FREE_MSG(pcb->msg); /* checks for != NULL */
1300
1301	return (0);
1302} /* ng_btsocket_l2cap_raw_send_sync_ngmsg */
1303
1304