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: src/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap_raw.c,v 1.20 2006/11/06 13:42:04 rwatson Exp $
32  * $DragonFly: src/sys/netgraph7/bluetooth/socket/ng_btsocket_l2cap_raw.c,v 1.2 2008/06/26 23:05:40 dillon Exp $
33  */
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/bitstring.h>
38 #include <sys/domain.h>
39 #include <sys/errno.h>
40 #include <sys/filedesc.h>
41 #include <sys/kernel.h>
42 #include <sys/lock.h>
43 #include <sys/malloc.h>
44 #include <sys/mbuf.h>
45 #include <sys/mutex.h>
46 #include <sys/priv.h>
47 #include <sys/protosw.h>
48 #include <sys/queue.h>
49 #include <sys/socket.h>
50 #include <sys/socketvar.h>
51 #include <sys/sysctl.h>
52 #include <sys/taskqueue.h>
53 #include "ng_message.h"
54 #include "netgraph.h"
55 #include "bluetooth/include/ng_bluetooth.h"
56 #include "bluetooth/include/ng_hci.h"
57 #include "bluetooth/include/ng_l2cap.h"
58 #include "bluetooth/include/ng_btsocket.h"
59 #include "bluetooth/include/ng_btsocket_l2cap.h"
60 
61 /* MALLOC define */
62 #ifdef NG_SEPARATE_MALLOC
63 MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_L2CAP_RAW, "netgraph_btsocks_l2cap_raw",
64 		"Netgraph Bluetooth raw L2CAP sockets");
65 #else
66 #define M_NETGRAPH_BTSOCKET_L2CAP_RAW M_NETGRAPH
67 #endif /* NG_SEPARATE_MALLOC */
68 
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;
77 
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 *);
81 
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);
86 
87 #define ng_btsocket_l2cap_raw_wakeup_input_task() \
88 	taskqueue_enqueue(taskqueue_swi, &ng_btsocket_l2cap_raw_queue_task)
89 
90 #define ng_btsocket_l2cap_raw_wakeup_route_task() \
91 	taskqueue_enqueue(taskqueue_swi, &ng_btsocket_l2cap_raw_rt_task)
92 
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,
104 };
105 
106 /* Globals */
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;
121 
122 /* Sysctl tree */
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,
127 	CTLFLAG_RW,
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,
131 	CTLFLAG_RW,
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,
135 	CTLFLAG_RD,
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,
139 	CTLFLAG_RD,
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,
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 
174 static int
175 ng_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 
184 static int
185 ng_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 != 0) {
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 
221 static int
222 ng_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 
231 static int
232 ng_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 
244 static int
245 ng_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 
267 static int
268 ng_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 
319 static int
320 ng_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 
337 static void
338 ng_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 			rt = (ng_btsocket_l2cap_rtentry_t *)
372 				NG_HOOK_PRIVATE(hook);
373 			if (rt == NULL) {
374 				rt = kmalloc(sizeof(*rt),
375 					     M_NETGRAPH_BTSOCKET_L2CAP_RAW,
376 					     M_WAITOK | M_NULLOK | 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 
447 static void
448 ng_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 			kfree(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 
505 void
506 ng_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 
575 void
576 ng_btsocket_l2cap_raw_abort(struct socket *so)
577 {
578 
579 	(void)ng_btsocket_l2cap_raw_disconnect(so);
580 } /* ng_btsocket_l2cap_raw_abort */
581 
582 void
583 ng_btsocket_l2cap_raw_close(struct socket *so)
584 {
585 
586 	(void)ng_btsocket_l2cap_raw_disconnect(so);
587 } /* ng_btsocket_l2cap_raw_close */
588 
589 /*
590  * Create and attach new socket
591  */
592 
593 int
594 ng_btsocket_l2cap_raw_attach(struct socket *so, int proto, struct thread *td)
595 {
596 	ng_btsocket_l2cap_raw_pcb_p	pcb = so2l2cap_raw_pcb(so);
597 	int				error;
598 
599 	if (pcb != NULL)
600 		return (EISCONN);
601 
602 	if (ng_btsocket_l2cap_raw_node == NULL)
603 		return (EPROTONOSUPPORT);
604 	if (so->so_type != SOCK_RAW)
605 		return (ESOCKTNOSUPPORT);
606 
607 	/* Reserve send and receive space if it is not reserved yet */
608 	error = soreserve(so, NG_BTSOCKET_L2CAP_RAW_SENDSPACE,
609 			NG_BTSOCKET_L2CAP_RAW_RECVSPACE);
610 	if (error != 0)
611 		return (error);
612 
613 	/* Allocate the PCB */
614         pcb = kmalloc(sizeof(*pcb), M_NETGRAPH_BTSOCKET_L2CAP_RAW,
615 		      M_WAITOK | M_NULLOK | M_ZERO);
616         if (pcb == NULL)
617                 return (ENOMEM);
618 
619 	/* Link the PCB and the socket */
620 	so->so_pcb = (caddr_t) pcb;
621 	pcb->so = so;
622 
623 	if (priv_check(td, PRIV_NETBLUETOOTH_RAW) == 0)
624 		pcb->flags |= NG_BTSOCKET_L2CAP_RAW_PRIVILEGED;
625 
626 	mtx_init(&pcb->pcb_mtx, "btsocks_l2cap_raw_pcb_mtx", NULL, MTX_DEF);
627 
628         /* Add the PCB to the list */
629 	mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);
630 	LIST_INSERT_HEAD(&ng_btsocket_l2cap_raw_sockets, pcb, next);
631 	mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);
632 
633         return (0);
634 } /* ng_btsocket_l2cap_raw_attach */
635 
636 /*
637  * Bind socket
638  */
639 
640 int
641 ng_btsocket_l2cap_raw_bind(struct socket *so, struct sockaddr *nam,
642 		struct thread *td)
643 {
644 	ng_btsocket_l2cap_raw_pcb_t	*pcb = so2l2cap_raw_pcb(so);
645 	struct sockaddr_l2cap		*sa = (struct sockaddr_l2cap *) nam;
646 	ng_btsocket_l2cap_rtentry_t	*rt = NULL;
647 
648 	if (pcb == NULL)
649 		return (EINVAL);
650 	if (ng_btsocket_l2cap_raw_node == NULL)
651 		return (EINVAL);
652 
653 	if (sa == NULL)
654 		return (EINVAL);
655 	if (sa->l2cap_family != AF_BLUETOOTH)
656 		return (EAFNOSUPPORT);
657 	if (sa->l2cap_len != sizeof(*sa))
658 		return (EINVAL);
659 
660 	if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY,
661 				sizeof(sa->l2cap_bdaddr)) != 0) {
662 		mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
663 
664 		LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) {
665 			if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
666 				continue;
667 
668 			if (bcmp(&sa->l2cap_bdaddr, &rt->src,
669 					sizeof(rt->src)) == 0)
670 				break;
671 		}
672 
673 		mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);
674 
675 		if (rt == NULL)
676 			return (ENETDOWN);
677 	} else
678 		rt = NULL;
679 
680 	mtx_lock(&pcb->pcb_mtx);
681 	bcopy(&sa->l2cap_bdaddr, &pcb->src, sizeof(pcb->src));
682 	pcb->rt = rt;
683 	mtx_unlock(&pcb->pcb_mtx);
684 
685 	return (0);
686 } /* ng_btsocket_l2cap_raw_bind */
687 
688 /*
689  * Connect socket
690  */
691 
692 int
693 ng_btsocket_l2cap_raw_connect(struct socket *so, struct sockaddr *nam,
694 		struct thread *td)
695 {
696 	ng_btsocket_l2cap_raw_pcb_t	*pcb = so2l2cap_raw_pcb(so);
697 	struct sockaddr_l2cap		*sa = (struct sockaddr_l2cap *) nam;
698 	ng_btsocket_l2cap_rtentry_t	*rt = NULL;
699 	int				 error;
700 
701 	if (pcb == NULL)
702 		return (EINVAL);
703 	if (ng_btsocket_l2cap_raw_node == NULL)
704 		return (EINVAL);
705 
706 	if (sa == NULL)
707 		return (EINVAL);
708 	if (sa->l2cap_family != AF_BLUETOOTH)
709 		return (EAFNOSUPPORT);
710 	if (sa->l2cap_len != sizeof(*sa))
711 		return (EINVAL);
712 	if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
713 		return (EINVAL);
714 
715 	mtx_lock(&pcb->pcb_mtx);
716 
717 	bcopy(&sa->l2cap_bdaddr, &pcb->dst, sizeof(pcb->dst));
718 
719 	if (bcmp(&pcb->src, &pcb->dst, sizeof(pcb->src)) == 0) {
720 		mtx_unlock(&pcb->pcb_mtx);
721 
722 		return (EADDRNOTAVAIL);
723 	}
724 
725 	/*
726 	 * If there is route already - use it
727 	 */
728 
729 	if (pcb->rt != NULL) {
730 		soisconnected(so);
731 		mtx_unlock(&pcb->pcb_mtx);
732 
733 		return (0);
734 	}
735 
736 	/*
737 	 * Find the first hook that does not match specified destination address
738 	 */
739 
740 	mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
741 
742 	LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) {
743 		if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
744 			continue;
745 
746 		if (bcmp(&pcb->dst, &rt->src, sizeof(rt->src)) != 0)
747 			break;
748 	}
749 
750 	if (rt != NULL) {
751 		soisconnected(so);
752 
753 		pcb->rt = rt;
754 		bcopy(&rt->src, &pcb->src, sizeof(pcb->src));
755 
756 		error = 0;
757 	} else
758 		error = ENETDOWN;
759 
760 	mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);
761 	mtx_unlock(&pcb->pcb_mtx);
762 
763 	return  (error);
764 } /* ng_btsocket_l2cap_raw_connect */
765 
766 /*
767  * Process ioctl's calls on socket
768  */
769 
770 int
771 ng_btsocket_l2cap_raw_control(struct socket *so, u_long cmd, caddr_t data,
772 		struct ifnet *ifp, struct thread *td)
773 {
774 	ng_btsocket_l2cap_raw_pcb_p	 pcb = so2l2cap_raw_pcb(so);
775 	struct ng_mesg			*msg = NULL;
776 	int				 error = 0;
777 
778 	if (pcb == NULL)
779 		return (EINVAL);
780 	if (ng_btsocket_l2cap_raw_node == NULL)
781 		return (EINVAL);
782 
783 	mtx_lock(&pcb->pcb_mtx);
784 
785 	/* Check if we route info */
786 	if (pcb->rt == NULL) {
787 		mtx_unlock(&pcb->pcb_mtx);
788 		return (EHOSTUNREACH);
789 	}
790 
791 	/* Check if we have pending ioctl() */
792 	if (pcb->token != 0) {
793 		mtx_unlock(&pcb->pcb_mtx);
794 		return (EBUSY);
795 	}
796 
797 	switch (cmd) {
798 	case SIOC_L2CAP_NODE_GET_FLAGS: {
799 		struct ng_btsocket_l2cap_raw_node_flags	*p =
800 			(struct ng_btsocket_l2cap_raw_node_flags *) data;
801 
802 		error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,
803 				NGM_L2CAP_NODE_GET_FLAGS,
804 				&p->flags, sizeof(p->flags));
805 		} break;
806 
807 	case SIOC_L2CAP_NODE_GET_DEBUG: {
808 		struct ng_btsocket_l2cap_raw_node_debug	*p =
809 			(struct ng_btsocket_l2cap_raw_node_debug *) data;
810 
811 		error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,
812 				NGM_L2CAP_NODE_GET_DEBUG,
813 				&p->debug, sizeof(p->debug));
814 		} break;
815 
816 	case SIOC_L2CAP_NODE_SET_DEBUG: {
817 		struct ng_btsocket_l2cap_raw_node_debug	*p =
818 			(struct ng_btsocket_l2cap_raw_node_debug *) data;
819 
820 		if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)
821 			error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook,
822 					NGM_L2CAP_NODE_SET_DEBUG,
823 					&p->debug, sizeof(p->debug));
824 		else
825 			error = EPERM;
826 		} break;
827 
828 	case SIOC_L2CAP_NODE_GET_CON_LIST: {
829 		struct ng_btsocket_l2cap_raw_con_list	*p =
830 			(struct ng_btsocket_l2cap_raw_con_list *) data;
831 		ng_l2cap_node_con_list_ep		*p1 = NULL;
832                 ng_l2cap_node_con_ep			*p2 = NULL;
833 
834 		if (p->num_connections == 0 ||
835 		    p->num_connections > NG_L2CAP_MAX_CON_NUM ||
836 		    p->connections == NULL) {
837 			error = EINVAL;
838 			break;
839 		}
840 
841 		NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_NODE_GET_CON_LIST,
842 			0, M_WAITOK | M_NULLOK);
843 		if (msg == NULL) {
844 			error = ENOMEM;
845 			break;
846 		}
847 		ng_btsocket_l2cap_raw_get_token(&msg->header.token);
848 		pcb->token = msg->header.token;
849 		pcb->msg = NULL;
850 
851 		NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
852 			pcb->rt->hook, 0);
853 		if (error != 0) {
854 			pcb->token = 0;
855 			break;
856 		}
857 
858 		error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
859 				ng_btsocket_l2cap_raw_ioctl_timeout * hz);
860 		pcb->token = 0;
861 
862 		if (error != 0)
863 			break;
864 
865 		if (pcb->msg != NULL &&
866 		    pcb->msg->header.cmd == NGM_L2CAP_NODE_GET_CON_LIST) {
867 			/* Return data back to user space */
868 			p1 = (ng_l2cap_node_con_list_ep *)(pcb->msg->data);
869 			p2 = (ng_l2cap_node_con_ep *)(p1 + 1);
870 
871 			p->num_connections = min(p->num_connections,
872 						p1->num_connections);
873 			if (p->num_connections > 0)
874 				error = copyout((caddr_t) p2,
875 					(caddr_t) p->connections,
876 					p->num_connections * sizeof(*p2));
877 		} else
878 			error = EINVAL;
879 
880 		NG_FREE_MSG(pcb->msg); /* checks for != NULL */
881 		} break;
882 
883 	case SIOC_L2CAP_NODE_GET_CHAN_LIST: {
884 		struct ng_btsocket_l2cap_raw_chan_list	*p =
885 			(struct ng_btsocket_l2cap_raw_chan_list *) data;
886 		ng_l2cap_node_chan_list_ep		*p1 = NULL;
887                 ng_l2cap_node_chan_ep			*p2 = NULL;
888 
889 		if (p->num_channels == 0 ||
890 		    p->num_channels > NG_L2CAP_MAX_CHAN_NUM ||
891 		    p->channels == NULL) {
892 			error = EINVAL;
893 			break;
894 		}
895 
896 		NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE,
897 			NGM_L2CAP_NODE_GET_CHAN_LIST, 0, M_WAITOK | M_NULLOK);
898 		if (msg == NULL) {
899 			error = ENOMEM;
900 			break;
901 		}
902 		ng_btsocket_l2cap_raw_get_token(&msg->header.token);
903 		pcb->token = msg->header.token;
904 		pcb->msg = NULL;
905 
906 		NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
907 			pcb->rt->hook, 0);
908 		if (error != 0) {
909 			pcb->token = 0;
910 			break;
911 		}
912 
913 		error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
914 				ng_btsocket_l2cap_raw_ioctl_timeout * hz);
915 		pcb->token = 0;
916 
917 		if (error != 0)
918 			break;
919 
920 		if (pcb->msg != NULL &&
921 		    pcb->msg->header.cmd == NGM_L2CAP_NODE_GET_CHAN_LIST) {
922 			/* Return data back to user space */
923 			p1 = (ng_l2cap_node_chan_list_ep *)(pcb->msg->data);
924 			p2 = (ng_l2cap_node_chan_ep *)(p1 + 1);
925 
926 			p->num_channels = min(p->num_channels,
927 						p1->num_channels);
928 			if (p->num_channels > 0)
929 				error = copyout((caddr_t) p2,
930 						(caddr_t) p->channels,
931 						p->num_channels * sizeof(*p2));
932 		} else
933 			error = EINVAL;
934 
935 		NG_FREE_MSG(pcb->msg); /* checks for != NULL */
936 		} break;
937 
938 	case SIOC_L2CAP_L2CA_PING: {
939 		struct ng_btsocket_l2cap_raw_ping	*p =
940 			(struct ng_btsocket_l2cap_raw_ping *) data;
941 		ng_l2cap_l2ca_ping_ip			*ip = NULL;
942 		ng_l2cap_l2ca_ping_op			*op = NULL;
943 
944 		if (!(pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)) {
945 			error = EPERM;
946 			break;
947 		}
948 
949 		if ((p->echo_size != 0 && p->echo_data == NULL) ||
950 		     p->echo_size > NG_L2CAP_MAX_ECHO_SIZE) {
951 			error = EINVAL;
952 			break;
953 		}
954 
955 		NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE,
956 			NGM_L2CAP_L2CA_PING, sizeof(*ip) + p->echo_size,
957 			M_WAITOK | M_NULLOK);
958 		if (msg == NULL) {
959 			error = ENOMEM;
960 			break;
961 		}
962 		ng_btsocket_l2cap_raw_get_token(&msg->header.token);
963 		pcb->token = msg->header.token;
964 		pcb->msg = NULL;
965 
966 		ip = (ng_l2cap_l2ca_ping_ip *)(msg->data);
967 		bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr));
968 		ip->echo_size = p->echo_size;
969 
970 		if (ip->echo_size > 0) {
971 			error = copyin(p->echo_data, ip + 1, p->echo_size);
972 			if (error != 0) {
973 				NG_FREE_MSG(msg);
974 				pcb->token = 0;
975 				break;
976 			}
977 		}
978 
979 		NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
980 			pcb->rt->hook, 0);
981 		if (error != 0) {
982 			pcb->token = 0;
983 			break;
984 		}
985 
986 		error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
987 				bluetooth_l2cap_rtx_timeout());
988 		pcb->token = 0;
989 
990 		if (error != 0)
991 			break;
992 
993 		if (pcb->msg != NULL &&
994 		    pcb->msg->header.cmd == NGM_L2CAP_L2CA_PING) {
995 			/* Return data back to the user space */
996 			op = (ng_l2cap_l2ca_ping_op *)(pcb->msg->data);
997 			p->result = op->result;
998 			p->echo_size = min(p->echo_size, op->echo_size);
999 
1000 			if (p->echo_size > 0)
1001 				error = copyout(op + 1, p->echo_data,
1002 						p->echo_size);
1003 		} else
1004 			error = EINVAL;
1005 
1006 		NG_FREE_MSG(pcb->msg); /* checks for != NULL */
1007 		} break;
1008 
1009 	case SIOC_L2CAP_L2CA_GET_INFO: {
1010 		struct ng_btsocket_l2cap_raw_get_info	*p =
1011 			(struct ng_btsocket_l2cap_raw_get_info *) data;
1012 		ng_l2cap_l2ca_get_info_ip		*ip = NULL;
1013 		ng_l2cap_l2ca_get_info_op		*op = NULL;
1014 
1015 		if (!(pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)) {
1016 			error = EPERM;
1017 			break;
1018 		}
1019 
1020 		if (p->info_size != 0 && p->info_data == NULL) {
1021 			error = EINVAL;
1022 			break;
1023 		}
1024 
1025 		NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE,
1026 			NGM_L2CAP_L2CA_GET_INFO, sizeof(*ip) + p->info_size,
1027 			M_WAITOK | M_NULLOK);
1028 		if (msg == NULL) {
1029 			error = ENOMEM;
1030 			break;
1031 		}
1032 		ng_btsocket_l2cap_raw_get_token(&msg->header.token);
1033 		pcb->token = msg->header.token;
1034 		pcb->msg = NULL;
1035 
1036 		ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data);
1037 		bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr));
1038 		ip->info_type = p->info_type;
1039 
1040 		NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
1041 			pcb->rt->hook, 0);
1042 		if (error != 0) {
1043 			pcb->token = 0;
1044 			break;
1045 		}
1046 
1047 		error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
1048 				bluetooth_l2cap_rtx_timeout());
1049 		pcb->token = 0;
1050 
1051 		if (error != 0)
1052 			break;
1053 
1054 		if (pcb->msg != NULL &&
1055 		    pcb->msg->header.cmd == NGM_L2CAP_L2CA_GET_INFO) {
1056 			/* Return data back to the user space */
1057 			op = (ng_l2cap_l2ca_get_info_op *)(pcb->msg->data);
1058 			p->result = op->result;
1059 			p->info_size = min(p->info_size, op->info_size);
1060 
1061 			if (p->info_size > 0)
1062 				error = copyout(op + 1, p->info_data,
1063 						p->info_size);
1064 		} else
1065 			error = EINVAL;
1066 
1067 		NG_FREE_MSG(pcb->msg); /* checks for != NULL */
1068 		} break;
1069 
1070 	case SIOC_L2CAP_NODE_GET_AUTO_DISCON_TIMO: {
1071 		struct ng_btsocket_l2cap_raw_auto_discon_timo	*p =
1072 			(struct ng_btsocket_l2cap_raw_auto_discon_timo *) data;
1073 
1074 		error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,
1075 				NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO,
1076 				&p->timeout, sizeof(p->timeout));
1077 		} break;
1078 
1079 	case SIOC_L2CAP_NODE_SET_AUTO_DISCON_TIMO: {
1080 		struct ng_btsocket_l2cap_raw_auto_discon_timo	*p =
1081 			(struct ng_btsocket_l2cap_raw_auto_discon_timo *) data;
1082 
1083 		if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)
1084 			error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook,
1085 					NGM_L2CAP_NODE_SET_AUTO_DISCON_TIMO,
1086 					&p->timeout, sizeof(p->timeout));
1087 		else
1088 			error = EPERM;
1089 		} break;
1090 
1091 	default:
1092 		error = EINVAL;
1093 		break;
1094 	}
1095 
1096 	mtx_unlock(&pcb->pcb_mtx);
1097 
1098 	return (error);
1099 } /* ng_btsocket_l2cap_raw_control */
1100 
1101 /*
1102  * Detach and destroy socket
1103  */
1104 
1105 void
1106 ng_btsocket_l2cap_raw_detach(struct socket *so)
1107 {
1108 	ng_btsocket_l2cap_raw_pcb_p	pcb = so2l2cap_raw_pcb(so);
1109 
1110 	KASSERT(pcb != NULL, ("nt_btsocket_l2cap_raw_detach: pcb == NULL"));
1111 	if (ng_btsocket_l2cap_raw_node == NULL)
1112 		return;
1113 
1114 	mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);
1115 	mtx_lock(&pcb->pcb_mtx);
1116 
1117 	LIST_REMOVE(pcb, next);
1118 
1119 	mtx_unlock(&pcb->pcb_mtx);
1120 	mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);
1121 
1122 	mtx_destroy(&pcb->pcb_mtx);
1123 
1124 	bzero(pcb, sizeof(*pcb));
1125 	kfree(pcb, M_NETGRAPH_BTSOCKET_L2CAP_RAW);
1126 
1127 	so->so_pcb = NULL;
1128 } /* ng_btsocket_l2cap_raw_detach */
1129 
1130 /*
1131  * Disconnect socket
1132  */
1133 
1134 int
1135 ng_btsocket_l2cap_raw_disconnect(struct socket *so)
1136 {
1137 	ng_btsocket_l2cap_raw_pcb_p	pcb = so2l2cap_raw_pcb(so);
1138 
1139 	if (pcb == NULL)
1140 		return (EINVAL);
1141 	if (ng_btsocket_l2cap_raw_node == NULL)
1142 		return (EINVAL);
1143 
1144 	mtx_lock(&pcb->pcb_mtx);
1145 	pcb->rt = NULL;
1146 	soisdisconnected(so);
1147 	mtx_unlock(&pcb->pcb_mtx);
1148 
1149 	return (0);
1150 } /* ng_btsocket_l2cap_raw_disconnect */
1151 
1152 /*
1153  * Get peer address
1154  */
1155 
1156 int
1157 ng_btsocket_l2cap_raw_peeraddr(struct socket *so, struct sockaddr **nam)
1158 {
1159 	ng_btsocket_l2cap_raw_pcb_p	pcb = so2l2cap_raw_pcb(so);
1160 	struct sockaddr_l2cap		sa;
1161 
1162 	if (pcb == NULL)
1163 		return (EINVAL);
1164 	if (ng_btsocket_l2cap_raw_node == NULL)
1165 		return (EINVAL);
1166 
1167 	mtx_lock(&pcb->pcb_mtx);
1168 	bcopy(&pcb->dst, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr));
1169 	mtx_unlock(&pcb->pcb_mtx);
1170 
1171 	sa.l2cap_psm = 0;
1172 	sa.l2cap_len = sizeof(sa);
1173 	sa.l2cap_family = AF_BLUETOOTH;
1174 
1175 	*nam = sodupsockaddr((struct sockaddr *) &sa, M_WAITOK | M_NULLOK);
1176 
1177 	return ((*nam == NULL)? ENOMEM : 0);
1178 } /* ng_btsocket_l2cap_raw_peeraddr */
1179 
1180 /*
1181  * Send data to socket
1182  */
1183 
1184 int
1185 ng_btsocket_l2cap_raw_send(struct socket *so, int flags, struct mbuf *m,
1186 		struct sockaddr *nam, struct mbuf *control, struct thread *td)
1187 {
1188 	NG_FREE_M(m); /* Checks for m != NULL */
1189 	NG_FREE_M(control);
1190 
1191 	return (EOPNOTSUPP);
1192 } /* ng_btsocket_l2cap_raw_send */
1193 
1194 /*
1195  * Get socket address
1196  */
1197 
1198 int
1199 ng_btsocket_l2cap_raw_sockaddr(struct socket *so, struct sockaddr **nam)
1200 {
1201 	ng_btsocket_l2cap_raw_pcb_p	pcb = so2l2cap_raw_pcb(so);
1202 	struct sockaddr_l2cap		sa;
1203 
1204 	if (pcb == NULL)
1205 		return (EINVAL);
1206 	if (ng_btsocket_l2cap_raw_node == NULL)
1207 		return (EINVAL);
1208 
1209 	mtx_lock(&pcb->pcb_mtx);
1210 	bcopy(&pcb->src, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr));
1211 	mtx_unlock(&pcb->pcb_mtx);
1212 
1213 	sa.l2cap_psm = 0;
1214 	sa.l2cap_len = sizeof(sa);
1215 	sa.l2cap_family = AF_BLUETOOTH;
1216 
1217 	*nam = sodupsockaddr((struct sockaddr *) &sa, M_WAITOK | M_NULLOK);
1218 
1219 	return ((*nam == NULL)? ENOMEM : 0);
1220 } /* ng_btsocket_l2cap_raw_sockaddr */
1221 
1222 /*
1223  * Get next token
1224  */
1225 
1226 static void
1227 ng_btsocket_l2cap_raw_get_token(u_int32_t *token)
1228 {
1229 	mtx_lock(&ng_btsocket_l2cap_raw_token_mtx);
1230 
1231 	if (++ ng_btsocket_l2cap_raw_token == 0)
1232 		ng_btsocket_l2cap_raw_token = 1;
1233 
1234 	*token = ng_btsocket_l2cap_raw_token;
1235 
1236 	mtx_unlock(&ng_btsocket_l2cap_raw_token_mtx);
1237 } /* ng_btsocket_l2cap_raw_get_token */
1238 
1239 /*
1240  * Send Netgraph message to the node - do not expect reply
1241  */
1242 
1243 static int
1244 ng_btsocket_l2cap_raw_send_ngmsg(hook_p hook, int cmd, void *arg, int arglen)
1245 {
1246 	struct ng_mesg	*msg = NULL;
1247 	int		 error = 0;
1248 
1249 	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, arglen, M_WAITOK | M_NULLOK);
1250 	if (msg == NULL)
1251 		return (ENOMEM);
1252 
1253 	if (arg != NULL && arglen > 0)
1254 		bcopy(arg, msg->data, arglen);
1255 
1256 	NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, hook, 0);
1257 
1258 	return (error);
1259 } /* ng_btsocket_l2cap_raw_send_ngmsg */
1260 
1261 /*
1262  * Send Netgraph message to the node (no data) and wait for reply
1263  */
1264 
1265 static int
1266 ng_btsocket_l2cap_raw_send_sync_ngmsg(ng_btsocket_l2cap_raw_pcb_p pcb,
1267 		int cmd, void *rsp, int rsplen)
1268 {
1269 	struct ng_mesg	*msg = NULL;
1270 	int		 error = 0;
1271 
1272 	mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1273 
1274 	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, 0, M_WAITOK | M_NULLOK);
1275 	if (msg == NULL)
1276 		return (ENOMEM);
1277 
1278 	ng_btsocket_l2cap_raw_get_token(&msg->header.token);
1279 	pcb->token = msg->header.token;
1280 	pcb->msg = NULL;
1281 
1282 	NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
1283 		pcb->rt->hook, 0);
1284 	if (error != 0) {
1285 		pcb->token = 0;
1286 		return (error);
1287 	}
1288 
1289 	error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
1290 			ng_btsocket_l2cap_raw_ioctl_timeout * hz);
1291 	pcb->token = 0;
1292 
1293 	if (error != 0)
1294 		return (error);
1295 
1296 	if (pcb->msg != NULL && pcb->msg->header.cmd == cmd)
1297 		bcopy(pcb->msg->data, rsp, rsplen);
1298 	else
1299 		error = EINVAL;
1300 
1301 	NG_FREE_MSG(pcb->msg); /* checks for != NULL */
1302 
1303 	return (0);
1304 } /* ng_btsocket_l2cap_raw_send_sync_ngmsg */
1305 
1306