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