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