1/*
2 * ng_btsocket_l2cap.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.c,v 1.16 2003/09/14 23:29:06 max Exp $
31 * $FreeBSD$
32 */
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/bitstring.h>
37#include <sys/domain.h>
38#include <sys/endian.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/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
54#include <net/vnet.h>
55
56#include <netgraph/ng_message.h>
57#include <netgraph/netgraph.h>
58#include <netgraph/bluetooth/include/ng_bluetooth.h>
59#include <netgraph/bluetooth/include/ng_hci.h>
60#include <netgraph/bluetooth/include/ng_l2cap.h>
61#include <netgraph/bluetooth/include/ng_btsocket.h>
62#include <netgraph/bluetooth/include/ng_btsocket_l2cap.h>
63
64/* MALLOC define */
65#ifdef NG_SEPARATE_MALLOC
66static MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_L2CAP, "netgraph_btsocks_l2cap",
67		"Netgraph Bluetooth L2CAP sockets");
68#else
69#define M_NETGRAPH_BTSOCKET_L2CAP M_NETGRAPH
70#endif /* NG_SEPARATE_MALLOC */
71
72/* Netgraph node methods */
73static ng_constructor_t	ng_btsocket_l2cap_node_constructor;
74static ng_rcvmsg_t	ng_btsocket_l2cap_node_rcvmsg;
75static ng_shutdown_t	ng_btsocket_l2cap_node_shutdown;
76static ng_newhook_t	ng_btsocket_l2cap_node_newhook;
77static ng_connect_t	ng_btsocket_l2cap_node_connect;
78static ng_rcvdata_t	ng_btsocket_l2cap_node_rcvdata;
79static ng_disconnect_t	ng_btsocket_l2cap_node_disconnect;
80
81static void		ng_btsocket_l2cap_input   (void *, int);
82static void		ng_btsocket_l2cap_rtclean (void *, int);
83
84/* Netgraph type descriptor */
85static struct ng_type	typestruct = {
86	.version =	NG_ABI_VERSION,
87	.name =		NG_BTSOCKET_L2CAP_NODE_TYPE,
88	.constructor =	ng_btsocket_l2cap_node_constructor,
89	.rcvmsg =	ng_btsocket_l2cap_node_rcvmsg,
90	.shutdown =	ng_btsocket_l2cap_node_shutdown,
91	.newhook =	ng_btsocket_l2cap_node_newhook,
92	.connect =	ng_btsocket_l2cap_node_connect,
93	.rcvdata =	ng_btsocket_l2cap_node_rcvdata,
94	.disconnect =	ng_btsocket_l2cap_node_disconnect,
95};
96
97/* Globals */
98extern int					ifqmaxlen;
99static u_int32_t				ng_btsocket_l2cap_debug_level;
100static node_p					ng_btsocket_l2cap_node;
101static struct ng_bt_itemq			ng_btsocket_l2cap_queue;
102static struct mtx				ng_btsocket_l2cap_queue_mtx;
103static struct task				ng_btsocket_l2cap_queue_task;
104static LIST_HEAD(, ng_btsocket_l2cap_pcb)	ng_btsocket_l2cap_sockets;
105static struct mtx				ng_btsocket_l2cap_sockets_mtx;
106static LIST_HEAD(, ng_btsocket_l2cap_rtentry)	ng_btsocket_l2cap_rt;
107static struct mtx				ng_btsocket_l2cap_rt_mtx;
108static struct task				ng_btsocket_l2cap_rt_task;
109static struct timeval				ng_btsocket_l2cap_lasttime;
110static int					ng_btsocket_l2cap_curpps;
111
112/* Sysctl tree */
113SYSCTL_DECL(_net_bluetooth_l2cap_sockets);
114static SYSCTL_NODE(_net_bluetooth_l2cap_sockets, OID_AUTO, seq, CTLFLAG_RW,
115	0, "Bluetooth SEQPACKET L2CAP sockets family");
116SYSCTL_UINT(_net_bluetooth_l2cap_sockets_seq, OID_AUTO, debug_level,
117	CTLFLAG_RW,
118	&ng_btsocket_l2cap_debug_level, NG_BTSOCKET_WARN_LEVEL,
119	"Bluetooth SEQPACKET L2CAP sockets debug level");
120SYSCTL_UINT(_net_bluetooth_l2cap_sockets_seq, OID_AUTO, queue_len,
121	CTLFLAG_RD,
122	&ng_btsocket_l2cap_queue.len, 0,
123	"Bluetooth SEQPACKET L2CAP sockets input queue length");
124SYSCTL_UINT(_net_bluetooth_l2cap_sockets_seq, OID_AUTO, queue_maxlen,
125	CTLFLAG_RD,
126	&ng_btsocket_l2cap_queue.maxlen, 0,
127	"Bluetooth SEQPACKET L2CAP sockets input queue max. length");
128SYSCTL_UINT(_net_bluetooth_l2cap_sockets_seq, OID_AUTO, queue_drops,
129	CTLFLAG_RD,
130	&ng_btsocket_l2cap_queue.drops, 0,
131	"Bluetooth SEQPACKET L2CAP sockets input queue drops");
132
133/* Debug */
134#define NG_BTSOCKET_L2CAP_INFO \
135	if (ng_btsocket_l2cap_debug_level >= NG_BTSOCKET_INFO_LEVEL && \
136	    ppsratecheck(&ng_btsocket_l2cap_lasttime, &ng_btsocket_l2cap_curpps, 1)) \
137		printf
138
139#define NG_BTSOCKET_L2CAP_WARN \
140	if (ng_btsocket_l2cap_debug_level >= NG_BTSOCKET_WARN_LEVEL && \
141	    ppsratecheck(&ng_btsocket_l2cap_lasttime, &ng_btsocket_l2cap_curpps, 1)) \
142		printf
143
144#define NG_BTSOCKET_L2CAP_ERR \
145	if (ng_btsocket_l2cap_debug_level >= NG_BTSOCKET_ERR_LEVEL && \
146	    ppsratecheck(&ng_btsocket_l2cap_lasttime, &ng_btsocket_l2cap_curpps, 1)) \
147		printf
148
149#define NG_BTSOCKET_L2CAP_ALERT \
150	if (ng_btsocket_l2cap_debug_level >= NG_BTSOCKET_ALERT_LEVEL && \
151	    ppsratecheck(&ng_btsocket_l2cap_lasttime, &ng_btsocket_l2cap_curpps, 1)) \
152		printf
153
154/*
155 * Netgraph message processing routines
156 */
157
158static int ng_btsocket_l2cap_process_l2ca_con_req_rsp
159	(struct ng_mesg *, ng_btsocket_l2cap_rtentry_p);
160static int ng_btsocket_l2cap_process_l2ca_con_rsp_rsp
161	(struct ng_mesg *, ng_btsocket_l2cap_rtentry_p);
162static int ng_btsocket_l2cap_process_l2ca_con_ind
163	(struct ng_mesg *, ng_btsocket_l2cap_rtentry_p);
164
165static int ng_btsocket_l2cap_process_l2ca_cfg_req_rsp
166	(struct ng_mesg *, ng_btsocket_l2cap_rtentry_p);
167static int ng_btsocket_l2cap_process_l2ca_cfg_rsp_rsp
168	(struct ng_mesg *, ng_btsocket_l2cap_rtentry_p);
169static int ng_btsocket_l2cap_process_l2ca_cfg_ind
170	(struct ng_mesg *, ng_btsocket_l2cap_rtentry_p);
171
172static int ng_btsocket_l2cap_process_l2ca_discon_rsp
173	(struct ng_mesg *, ng_btsocket_l2cap_rtentry_p);
174static int ng_btsocket_l2cap_process_l2ca_discon_ind
175	(struct ng_mesg *, ng_btsocket_l2cap_rtentry_p);
176
177static int ng_btsocket_l2cap_process_l2ca_write_rsp
178	(struct ng_mesg *, ng_btsocket_l2cap_rtentry_p);
179
180/*
181 * Send L2CA_xxx messages to the lower layer
182 */
183
184static int  ng_btsocket_l2cap_send_l2ca_con_req
185	(ng_btsocket_l2cap_pcb_p);
186static int  ng_btsocket_l2cap_send_l2ca_con_rsp_req
187	(u_int32_t, ng_btsocket_l2cap_rtentry_p, bdaddr_p, int, int, int);
188static int  ng_btsocket_l2cap_send_l2ca_cfg_req
189	(ng_btsocket_l2cap_pcb_p);
190static int  ng_btsocket_l2cap_send_l2ca_cfg_rsp
191	(ng_btsocket_l2cap_pcb_p);
192static int  ng_btsocket_l2cap_send_l2ca_discon_req
193	(u_int32_t, ng_btsocket_l2cap_pcb_p);
194
195static int ng_btsocket_l2cap_send2
196	(ng_btsocket_l2cap_pcb_p);
197
198/*
199 * Timeout processing routines
200 */
201
202static void ng_btsocket_l2cap_timeout         (ng_btsocket_l2cap_pcb_p);
203static void ng_btsocket_l2cap_untimeout       (ng_btsocket_l2cap_pcb_p);
204static void ng_btsocket_l2cap_process_timeout (void *);
205
206/*
207 * Other stuff
208 */
209
210static ng_btsocket_l2cap_pcb_p     ng_btsocket_l2cap_pcb_by_addr(bdaddr_p, int);
211static ng_btsocket_l2cap_pcb_p     ng_btsocket_l2cap_pcb_by_token(u_int32_t);
212static ng_btsocket_l2cap_pcb_p     ng_btsocket_l2cap_pcb_by_cid (bdaddr_p, int);
213static int                         ng_btsocket_l2cap_result2errno(int);
214
215#define ng_btsocket_l2cap_wakeup_input_task() \
216	taskqueue_enqueue(taskqueue_swi_giant, &ng_btsocket_l2cap_queue_task)
217
218#define ng_btsocket_l2cap_wakeup_route_task() \
219	taskqueue_enqueue(taskqueue_swi_giant, &ng_btsocket_l2cap_rt_task)
220
221/*****************************************************************************
222 *****************************************************************************
223 **                        Netgraph node interface
224 *****************************************************************************
225 *****************************************************************************/
226
227/*
228 * Netgraph node constructor. Do not allow to create node of this type.
229 */
230
231static int
232ng_btsocket_l2cap_node_constructor(node_p node)
233{
234	return (EINVAL);
235} /* ng_btsocket_l2cap_node_constructor */
236
237/*
238 * Do local shutdown processing. Let old node go and create new fresh one.
239 */
240
241static int
242ng_btsocket_l2cap_node_shutdown(node_p node)
243{
244	int	error = 0;
245
246	NG_NODE_UNREF(node);
247
248	/* Create new node */
249	error = ng_make_node_common(&typestruct, &ng_btsocket_l2cap_node);
250	if (error != 0) {
251		NG_BTSOCKET_L2CAP_ALERT(
252"%s: Could not create Netgraph node, error=%d\n", __func__, error);
253
254		ng_btsocket_l2cap_node = NULL;
255
256		return (error);
257	}
258
259	error = ng_name_node(ng_btsocket_l2cap_node,
260				NG_BTSOCKET_L2CAP_NODE_TYPE);
261	if (error != 0) {
262		NG_BTSOCKET_L2CAP_ALERT(
263"%s: Could not name Netgraph node, error=%d\n", __func__, error);
264
265		NG_NODE_UNREF(ng_btsocket_l2cap_node);
266		ng_btsocket_l2cap_node = NULL;
267
268		return (error);
269	}
270
271	return (0);
272} /* ng_btsocket_l2cap_node_shutdown */
273
274/*
275 * We allow any hook to be connected to the node.
276 */
277
278static int
279ng_btsocket_l2cap_node_newhook(node_p node, hook_p hook, char const *name)
280{
281	return (0);
282} /* ng_btsocket_l2cap_node_newhook */
283
284/*
285 * Just say "YEP, that's OK by me!"
286 */
287
288static int
289ng_btsocket_l2cap_node_connect(hook_p hook)
290{
291	NG_HOOK_SET_PRIVATE(hook, NULL);
292	NG_HOOK_REF(hook); /* Keep extra reference to the hook */
293
294#if 0
295	NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
296	NG_HOOK_FORCE_QUEUE(hook);
297#endif
298
299	return (0);
300} /* ng_btsocket_l2cap_node_connect */
301
302/*
303 * Hook disconnection. Schedule route cleanup task
304 */
305
306static int
307ng_btsocket_l2cap_node_disconnect(hook_p hook)
308{
309	/*
310	 * If hook has private information than we must have this hook in
311	 * the routing table and must schedule cleaning for the routing table.
312	 * Otherwise hook was connected but we never got "hook_info" message,
313	 * so we have never added this hook to the routing table and it save
314	 * to just delete it.
315	 */
316
317	if (NG_HOOK_PRIVATE(hook) != NULL)
318		return (ng_btsocket_l2cap_wakeup_route_task());
319
320	NG_HOOK_UNREF(hook); /* Remove extra reference */
321
322	return (0);
323} /* ng_btsocket_l2cap_node_disconnect */
324
325/*
326 * Process incoming messages
327 */
328
329static int
330ng_btsocket_l2cap_node_rcvmsg(node_p node, item_p item, hook_p hook)
331{
332	struct ng_mesg	*msg = NGI_MSG(item); /* item still has message */
333	int		 error = 0;
334
335	if (msg != NULL && msg->header.typecookie == NGM_L2CAP_COOKIE) {
336		mtx_lock(&ng_btsocket_l2cap_queue_mtx);
337		if (NG_BT_ITEMQ_FULL(&ng_btsocket_l2cap_queue)) {
338			NG_BTSOCKET_L2CAP_ERR(
339"%s: Input queue is full (msg)\n", __func__);
340
341			NG_BT_ITEMQ_DROP(&ng_btsocket_l2cap_queue);
342			NG_FREE_ITEM(item);
343			error = ENOBUFS;
344		} else {
345			if (hook != NULL) {
346				NG_HOOK_REF(hook);
347				NGI_SET_HOOK(item, hook);
348			}
349
350			NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_l2cap_queue, item);
351			error = ng_btsocket_l2cap_wakeup_input_task();
352		}
353		mtx_unlock(&ng_btsocket_l2cap_queue_mtx);
354	} else {
355		NG_FREE_ITEM(item);
356		error = EINVAL;
357	}
358
359	return (error);
360} /* ng_btsocket_l2cap_node_rcvmsg */
361
362/*
363 * Receive data on a hook
364 */
365
366static int
367ng_btsocket_l2cap_node_rcvdata(hook_p hook, item_p item)
368{
369	int	error = 0;
370
371	mtx_lock(&ng_btsocket_l2cap_queue_mtx);
372	if (NG_BT_ITEMQ_FULL(&ng_btsocket_l2cap_queue)) {
373		NG_BTSOCKET_L2CAP_ERR(
374"%s: Input queue is full (data)\n", __func__);
375
376		NG_BT_ITEMQ_DROP(&ng_btsocket_l2cap_queue);
377		NG_FREE_ITEM(item);
378		error = ENOBUFS;
379	} else {
380		NG_HOOK_REF(hook);
381		NGI_SET_HOOK(item, hook);
382
383		NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_l2cap_queue, item);
384		error = ng_btsocket_l2cap_wakeup_input_task();
385	}
386	mtx_unlock(&ng_btsocket_l2cap_queue_mtx);
387
388	return (error);
389} /* ng_btsocket_l2cap_node_rcvdata */
390
391/*
392 * Process L2CA_Connect respose. Socket layer must have initiated connection,
393 * so we have to have a socket associated with message token.
394 */
395
396static int
397ng_btsocket_l2cap_process_l2ca_con_req_rsp(struct ng_mesg *msg,
398		ng_btsocket_l2cap_rtentry_p rt)
399{
400	ng_l2cap_l2ca_con_op	*op = NULL;
401	ng_btsocket_l2cap_pcb_t	*pcb = NULL;
402	int			 error = 0;
403
404	if (msg->header.arglen != sizeof(*op))
405		return (EMSGSIZE);
406
407	op = (ng_l2cap_l2ca_con_op *)(msg->data);
408
409	mtx_lock(&ng_btsocket_l2cap_sockets_mtx);
410
411	/* Look for the socket with the token */
412	pcb = ng_btsocket_l2cap_pcb_by_token(msg->header.token);
413	if (pcb == NULL) {
414		mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
415		return (ENOENT);
416	}
417
418	mtx_lock(&pcb->pcb_mtx);
419
420	NG_BTSOCKET_L2CAP_INFO(
421"%s: Got L2CA_Connect response, token=%d, src bdaddr=%x:%x:%x:%x:%x:%x, " \
422"dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, result=%d, status=%d, " \
423"state=%d\n",	__func__, msg->header.token,
424		pcb->src.b[5], pcb->src.b[4], pcb->src.b[3],
425		pcb->src.b[2], pcb->src.b[1], pcb->src.b[0],
426		pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3],
427		pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0],
428		pcb->psm, op->lcid, op->result, op->status,
429		pcb->state);
430
431	if (pcb->state != NG_BTSOCKET_L2CAP_CONNECTING) {
432		mtx_unlock(&pcb->pcb_mtx);
433		mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
434
435		return (ENOENT);
436	}
437
438	ng_btsocket_l2cap_untimeout(pcb);
439
440	if (op->result == NG_L2CAP_PENDING) {
441		ng_btsocket_l2cap_timeout(pcb);
442		mtx_unlock(&pcb->pcb_mtx);
443		mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
444
445		return (0);
446	}
447
448	if (op->result == NG_L2CAP_SUCCESS) {
449		/*
450		 * Channel is now open, so update local channel ID and
451		 * start configuration process. Source and destination
452		 * addresses as well as route must be already set.
453		 */
454
455		pcb->cid = op->lcid;
456
457		error = ng_btsocket_l2cap_send_l2ca_cfg_req(pcb);
458		if (error != 0) {
459			/* Send disconnect request with "zero" token */
460			ng_btsocket_l2cap_send_l2ca_discon_req(0, pcb);
461
462			/* ... and close the socket */
463			pcb->state = NG_BTSOCKET_L2CAP_CLOSED;
464			soisdisconnected(pcb->so);
465		} else {
466			pcb->cfg_state = NG_BTSOCKET_L2CAP_CFG_IN_SENT;
467			pcb->state = NG_BTSOCKET_L2CAP_CONFIGURING;
468
469			ng_btsocket_l2cap_timeout(pcb);
470		}
471	} else {
472		/*
473		 * We have failed to open connection, so convert result
474		 * code to "errno" code and disconnect the socket. Channel
475		 * already has been closed.
476		 */
477
478		pcb->so->so_error = ng_btsocket_l2cap_result2errno(op->result);
479		pcb->state = NG_BTSOCKET_L2CAP_CLOSED;
480		soisdisconnected(pcb->so);
481	}
482
483	mtx_unlock(&pcb->pcb_mtx);
484	mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
485
486	return (error);
487} /* ng_btsocket_l2cap_process_l2ca_con_req_rsp */
488
489/*
490 * Process L2CA_ConnectRsp response
491 */
492
493static int
494ng_btsocket_l2cap_process_l2ca_con_rsp_rsp(struct ng_mesg *msg,
495		ng_btsocket_l2cap_rtentry_p rt)
496{
497	ng_l2cap_l2ca_con_rsp_op	*op = NULL;
498	ng_btsocket_l2cap_pcb_t		*pcb = NULL;
499
500	if (msg->header.arglen != sizeof(*op))
501		return (EMSGSIZE);
502
503	op = (ng_l2cap_l2ca_con_rsp_op *)(msg->data);
504
505	mtx_lock(&ng_btsocket_l2cap_sockets_mtx);
506
507	/* Look for the socket with the token */
508	pcb = ng_btsocket_l2cap_pcb_by_token(msg->header.token);
509	if (pcb == NULL) {
510		mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
511		return (ENOENT);
512	}
513
514	mtx_lock(&pcb->pcb_mtx);
515
516	NG_BTSOCKET_L2CAP_INFO(
517"%s: Got L2CA_ConnectRsp response, token=%d, src bdaddr=%x:%x:%x:%x:%x:%x, " \
518"dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, result=%d, state=%d\n",
519		__func__, msg->header.token,
520		pcb->src.b[5], pcb->src.b[4], pcb->src.b[3],
521		pcb->src.b[2], pcb->src.b[1], pcb->src.b[0],
522		pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3],
523		pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0],
524		pcb->psm, pcb->cid, op->result, pcb->state);
525
526	if (pcb->state != NG_BTSOCKET_L2CAP_CONNECTING) {
527		mtx_unlock(&pcb->pcb_mtx);
528		mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
529
530		return (ENOENT);
531	}
532
533	ng_btsocket_l2cap_untimeout(pcb);
534
535	/* Check the result and disconnect the socket on failure */
536	if (op->result != NG_L2CAP_SUCCESS) {
537		/* Close the socket - channel already closed */
538		pcb->so->so_error = ng_btsocket_l2cap_result2errno(op->result);
539		pcb->state = NG_BTSOCKET_L2CAP_CLOSED;
540		soisdisconnected(pcb->so);
541	} else {
542		/* Move to CONFIGURING state and wait for CONFIG_IND */
543		pcb->cfg_state = 0;
544		pcb->state = NG_BTSOCKET_L2CAP_CONFIGURING;
545		ng_btsocket_l2cap_timeout(pcb);
546	}
547
548	mtx_unlock(&pcb->pcb_mtx);
549	mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
550
551	return (0);
552} /* ng_btsocket_process_l2ca_con_rsp_rsp */
553
554/*
555 * Process L2CA_Connect indicator. Find socket that listens on address
556 * and PSM. Find exact or closest match. Create new socket and initiate
557 * connection.
558 */
559
560static int
561ng_btsocket_l2cap_process_l2ca_con_ind(struct ng_mesg *msg,
562		ng_btsocket_l2cap_rtentry_p rt)
563{
564	ng_l2cap_l2ca_con_ind_ip	*ip = NULL;
565	ng_btsocket_l2cap_pcb_t		*pcb = NULL, *pcb1 = NULL;
566	int				 error = 0;
567	u_int32_t			 token = 0;
568	u_int16_t			 result = 0;
569
570	if (msg->header.arglen != sizeof(*ip))
571		return (EMSGSIZE);
572
573	ip = (ng_l2cap_l2ca_con_ind_ip *)(msg->data);
574
575	NG_BTSOCKET_L2CAP_INFO(
576"%s: Got L2CA_Connect indicator, src bdaddr=%x:%x:%x:%x:%x:%x, " \
577"dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, ident=%d\n",
578		__func__,
579		rt->src.b[5], rt->src.b[4], rt->src.b[3],
580		rt->src.b[2], rt->src.b[1], rt->src.b[0],
581		ip->bdaddr.b[5], ip->bdaddr.b[4], ip->bdaddr.b[3],
582		ip->bdaddr.b[2], ip->bdaddr.b[1], ip->bdaddr.b[0],
583		ip->psm, ip->lcid, ip->ident);
584
585	mtx_lock(&ng_btsocket_l2cap_sockets_mtx);
586
587	pcb = ng_btsocket_l2cap_pcb_by_addr(&rt->src, ip->psm);
588	if (pcb != NULL) {
589		struct socket	*so1 = NULL;
590
591		mtx_lock(&pcb->pcb_mtx);
592
593		/*
594		 * First check the pending connections queue and if we have
595		 * space then create new socket and set proper source address.
596		 */
597
598		if (pcb->so->so_qlen <= pcb->so->so_qlimit) {
599			CURVNET_SET(pcb->so->so_vnet);
600			so1 = sonewconn(pcb->so, 0);
601			CURVNET_RESTORE();
602		}
603
604		if (so1 == NULL) {
605			result = NG_L2CAP_NO_RESOURCES;
606			goto respond;
607		}
608
609		/*
610		 * If we got here than we have created new socket. So complete
611		 * connection. If we we listening on specific address then copy
612		 * source address from listening socket, otherwise copy source
613		 * address from hook's routing information.
614		 */
615
616		pcb1 = so2l2cap_pcb(so1);
617		KASSERT((pcb1 != NULL),
618("%s: pcb1 == NULL\n", __func__));
619
620 		mtx_lock(&pcb1->pcb_mtx);
621
622		if (bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(pcb->src)) != 0)
623			bcopy(&pcb->src, &pcb1->src, sizeof(pcb1->src));
624		else
625			bcopy(&rt->src, &pcb1->src, sizeof(pcb1->src));
626
627		pcb1->flags &= ~NG_BTSOCKET_L2CAP_CLIENT;
628
629		bcopy(&ip->bdaddr, &pcb1->dst, sizeof(pcb1->dst));
630		pcb1->psm = ip->psm;
631		pcb1->cid = ip->lcid;
632		pcb1->rt = rt;
633
634		/* Copy socket settings */
635		pcb1->imtu = pcb->imtu;
636		bcopy(&pcb->oflow, &pcb1->oflow, sizeof(pcb1->oflow));
637		pcb1->flush_timo = pcb->flush_timo;
638
639		token = pcb1->token;
640	} else
641		/* Nobody listens on requested BDADDR/PSM */
642		result = NG_L2CAP_PSM_NOT_SUPPORTED;
643
644respond:
645	error = ng_btsocket_l2cap_send_l2ca_con_rsp_req(token, rt,
646			&ip->bdaddr, ip->ident, ip->lcid, result);
647	if (pcb1 != NULL) {
648		if (error != 0) {
649			pcb1->so->so_error = error;
650			pcb1->state = NG_BTSOCKET_L2CAP_CLOSED;
651			soisdisconnected(pcb1->so);
652		} else {
653			pcb1->state = NG_BTSOCKET_L2CAP_CONNECTING;
654			soisconnecting(pcb1->so);
655
656			ng_btsocket_l2cap_timeout(pcb1);
657		}
658
659		mtx_unlock(&pcb1->pcb_mtx);
660	}
661
662	if (pcb != NULL)
663		mtx_unlock(&pcb->pcb_mtx);
664
665	mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
666
667	return (error);
668} /* ng_btsocket_l2cap_process_l2ca_con_ind */
669
670/*
671 * Process L2CA_Config response
672 */
673
674static int
675ng_btsocket_l2cap_process_l2ca_cfg_req_rsp(struct ng_mesg *msg,
676		ng_btsocket_l2cap_rtentry_p rt)
677{
678	ng_l2cap_l2ca_cfg_op	*op = NULL;
679	ng_btsocket_l2cap_pcb_p	 pcb = NULL;
680
681	if (msg->header.arglen != sizeof(*op))
682		return (EMSGSIZE);
683
684	op = (ng_l2cap_l2ca_cfg_op *)(msg->data);
685
686	mtx_lock(&ng_btsocket_l2cap_sockets_mtx);
687
688	/*
689	 * Socket must have issued a Configure request, so we must have a
690	 * socket that wants to be configured. Use Netgraph message token
691	 * to find it
692	 */
693
694	pcb = ng_btsocket_l2cap_pcb_by_token(msg->header.token);
695	if (pcb == NULL) {
696		/*
697		 * XXX FIXME what to do here? We could not find a
698		 * socket with requested token. We even can not send
699		 * Disconnect, because we do not know channel ID
700		 */
701
702		mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
703		return (ENOENT);
704	}
705
706	mtx_lock(&pcb->pcb_mtx);
707
708        NG_BTSOCKET_L2CAP_INFO(
709"%s: Got L2CA_Config response, token=%d, src bdaddr=%x:%x:%x:%x:%x:%x, " \
710"dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, result=%d, state=%d, " \
711"cfg_state=%x\n",
712		__func__, msg->header.token,
713		pcb->src.b[5], pcb->src.b[4], pcb->src.b[3],
714		pcb->src.b[2], pcb->src.b[1], pcb->src.b[0],
715		pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3],
716		pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0],
717		pcb->psm, pcb->cid, op->result, pcb->state, pcb->cfg_state);
718
719	if (pcb->state != NG_BTSOCKET_L2CAP_CONFIGURING) {
720		mtx_unlock(&pcb->pcb_mtx);
721		mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
722
723		return (ENOENT);
724	}
725
726	if (op->result == NG_L2CAP_SUCCESS) {
727		/*
728		 * XXX FIXME Actually set flush and link timeout.
729		 * Set QoS here if required. Resolve conficts (flush_timo).
730		 * Save incoming MTU (peer's outgoing MTU) and outgoing flow
731		 * spec.
732		 */
733
734		pcb->imtu = op->imtu;
735		bcopy(&op->oflow, &pcb->oflow, sizeof(pcb->oflow));
736		pcb->flush_timo = op->flush_timo;
737
738		/*
739		 * We have configured incoming side, so record it and check
740		 * if configuration is complete. If complete then mark socket
741		 * as connected, otherwise wait for the peer.
742		 */
743
744		pcb->cfg_state &= ~NG_BTSOCKET_L2CAP_CFG_IN_SENT;
745		pcb->cfg_state |= NG_BTSOCKET_L2CAP_CFG_IN;
746
747		if (pcb->cfg_state == NG_BTSOCKET_L2CAP_CFG_BOTH) {
748			/* Configuration complete - mark socket as open */
749			ng_btsocket_l2cap_untimeout(pcb);
750			pcb->state = NG_BTSOCKET_L2CAP_OPEN;
751			soisconnected(pcb->so);
752		}
753	} else {
754		/*
755		 * Something went wrong. Could be unacceptable parameters,
756		 * reject or unknown option. That's too bad, but we will
757		 * not negotiate. Send Disconnect and close the channel.
758		 */
759
760		ng_btsocket_l2cap_untimeout(pcb);
761
762		switch (op->result) {
763		case NG_L2CAP_UNACCEPTABLE_PARAMS:
764		case NG_L2CAP_UNKNOWN_OPTION:
765			pcb->so->so_error = EINVAL;
766			break;
767
768		default:
769			pcb->so->so_error = ECONNRESET;
770			break;
771		}
772
773		/* Send disconnect with "zero" token */
774		ng_btsocket_l2cap_send_l2ca_discon_req(0, pcb);
775
776		/* ... and close the socket */
777		pcb->state = NG_BTSOCKET_L2CAP_CLOSED;
778		soisdisconnected(pcb->so);
779	}
780
781	mtx_unlock(&pcb->pcb_mtx);
782	mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
783
784	return (0);
785} /* ng_btsocket_l2cap_process_l2ca_cfg_req_rsp */
786
787/*
788 * Process L2CA_ConfigRsp response
789 */
790
791static int
792ng_btsocket_l2cap_process_l2ca_cfg_rsp_rsp(struct ng_mesg *msg,
793		ng_btsocket_l2cap_rtentry_p rt)
794{
795	ng_l2cap_l2ca_cfg_rsp_op	*op = NULL;
796	ng_btsocket_l2cap_pcb_t		*pcb = NULL;
797	int				 error = 0;
798
799	if (msg->header.arglen != sizeof(*op))
800		return (EMSGSIZE);
801
802	op = (ng_l2cap_l2ca_cfg_rsp_op *)(msg->data);
803
804	mtx_lock(&ng_btsocket_l2cap_sockets_mtx);
805
806	/* Look for the socket with the token */
807	pcb = ng_btsocket_l2cap_pcb_by_token(msg->header.token);
808	if (pcb == NULL) {
809		mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
810		return (ENOENT);
811	}
812
813	mtx_lock(&pcb->pcb_mtx);
814
815        NG_BTSOCKET_L2CAP_INFO(
816"%s: Got L2CA_ConfigRsp response, token=%d, src bdaddr=%x:%x:%x:%x:%x:%x, " \
817"dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, result=%d, state=%d, " \
818"cfg_state=%x\n",
819		__func__, msg->header.token,
820		pcb->src.b[5], pcb->src.b[4], pcb->src.b[3],
821		pcb->src.b[2], pcb->src.b[1], pcb->src.b[0],
822		pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3],
823		pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0],
824		pcb->psm, pcb->cid, op->result, pcb->state, pcb->cfg_state);
825
826	if (pcb->state != NG_BTSOCKET_L2CAP_CONFIGURING) {
827		mtx_unlock(&pcb->pcb_mtx);
828		mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
829
830		return (ENOENT);
831	}
832
833	/* Check the result and disconnect socket of failure */
834	if (op->result != NG_L2CAP_SUCCESS)
835		goto disconnect;
836
837	/*
838	 * Now we done with remote side configuration. Configure local
839	 * side if we have not done it yet.
840	 */
841
842	pcb->cfg_state &= ~NG_BTSOCKET_L2CAP_CFG_OUT_SENT;
843	pcb->cfg_state |= NG_BTSOCKET_L2CAP_CFG_OUT;
844
845	if (pcb->cfg_state == NG_BTSOCKET_L2CAP_CFG_BOTH) {
846		/* Configuration complete - mask socket as open */
847		ng_btsocket_l2cap_untimeout(pcb);
848		pcb->state = NG_BTSOCKET_L2CAP_OPEN;
849		soisconnected(pcb->so);
850	} else {
851		if (!(pcb->cfg_state & NG_BTSOCKET_L2CAP_CFG_IN_SENT)) {
852			/* Send L2CA_Config request - incoming path */
853			error = ng_btsocket_l2cap_send_l2ca_cfg_req(pcb);
854			if (error != 0)
855				goto disconnect;
856
857			pcb->cfg_state |= NG_BTSOCKET_L2CAP_CFG_IN_SENT;
858		}
859	}
860
861	mtx_unlock(&pcb->pcb_mtx);
862	mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
863
864	return (error);
865
866disconnect:
867	ng_btsocket_l2cap_untimeout(pcb);
868
869	/* Send disconnect with "zero" token */
870	ng_btsocket_l2cap_send_l2ca_discon_req(0, pcb);
871
872	/* ... and close the socket */
873	pcb->state = NG_BTSOCKET_L2CAP_CLOSED;
874	soisdisconnected(pcb->so);
875
876	mtx_unlock(&pcb->pcb_mtx);
877	mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
878
879	return (error);
880} /* ng_btsocket_l2cap_process_l2ca_cfg_rsp_rsp */
881
882/*
883 * Process L2CA_Config indicator
884 */
885
886static int
887ng_btsocket_l2cap_process_l2ca_cfg_ind(struct ng_mesg *msg,
888		ng_btsocket_l2cap_rtentry_p rt)
889{
890	ng_l2cap_l2ca_cfg_ind_ip	*ip = NULL;
891	ng_btsocket_l2cap_pcb_t		*pcb = NULL;
892	int				 error = 0;
893
894	if (msg->header.arglen != sizeof(*ip))
895		return (EMSGSIZE);
896
897	ip = (ng_l2cap_l2ca_cfg_ind_ip *)(msg->data);
898
899	mtx_lock(&ng_btsocket_l2cap_sockets_mtx);
900
901	/* Check for the open socket that has given channel ID */
902	pcb = ng_btsocket_l2cap_pcb_by_cid(&rt->src, ip->lcid);
903	if (pcb == NULL) {
904		mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
905		return (ENOENT);
906	}
907
908	mtx_lock(&pcb->pcb_mtx);
909
910        NG_BTSOCKET_L2CAP_INFO(
911"%s: Got L2CA_Config indicator, src bdaddr=%x:%x:%x:%x:%x:%x, " \
912"dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, state=%d, cfg_state=%x\n",
913		__func__,
914		pcb->src.b[5], pcb->src.b[4], pcb->src.b[3],
915		pcb->src.b[2], pcb->src.b[1], pcb->src.b[0],
916		pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3],
917		pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0],
918		pcb->psm, pcb->cid, pcb->state, pcb->cfg_state);
919
920	/* XXX FIXME re-configuration on open socket */
921 	if (pcb->state != NG_BTSOCKET_L2CAP_CONFIGURING) {
922		mtx_unlock(&pcb->pcb_mtx);
923		mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
924
925		return (ENOENT);
926	}
927
928	/*
929	 * XXX FIXME Actually set flush and link timeout. Set QoS here if
930	 * required. Resolve conficts (flush_timo). Note outgoing MTU (peer's
931	 * incoming MTU) and incoming flow spec.
932	 */
933
934	pcb->omtu = ip->omtu;
935	bcopy(&ip->iflow, &pcb->iflow, sizeof(pcb->iflow));
936	pcb->flush_timo = ip->flush_timo;
937
938	/*
939	 * Send L2CA_Config response to our peer and check for the errors,
940	 * if any send disconnect to close the channel.
941	 */
942
943	if (!(pcb->cfg_state & NG_BTSOCKET_L2CAP_CFG_OUT_SENT)) {
944		error = ng_btsocket_l2cap_send_l2ca_cfg_rsp(pcb);
945		if (error != 0) {
946			ng_btsocket_l2cap_untimeout(pcb);
947
948			pcb->so->so_error = error;
949
950			/* Send disconnect with "zero" token */
951			ng_btsocket_l2cap_send_l2ca_discon_req(0, pcb);
952
953			/* ... and close the socket */
954			pcb->state = NG_BTSOCKET_L2CAP_CLOSED;
955			soisdisconnected(pcb->so);
956		} else
957			pcb->cfg_state |= NG_BTSOCKET_L2CAP_CFG_OUT_SENT;
958	}
959
960	mtx_unlock(&pcb->pcb_mtx);
961	mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
962
963	return (error);
964} /* ng_btsocket_l2cap_process_l2cap_cfg_ind */
965
966/*
967 * Process L2CA_Disconnect response
968 */
969
970static int
971ng_btsocket_l2cap_process_l2ca_discon_rsp(struct ng_mesg *msg,
972		ng_btsocket_l2cap_rtentry_p rt)
973{
974	ng_l2cap_l2ca_discon_op	*op = NULL;
975	ng_btsocket_l2cap_pcb_t	*pcb = NULL;
976
977	/* Check message */
978	if (msg->header.arglen != sizeof(*op))
979		return (EMSGSIZE);
980
981	op = (ng_l2cap_l2ca_discon_op *)(msg->data);
982
983	mtx_lock(&ng_btsocket_l2cap_sockets_mtx);
984
985	/*
986	 * Socket layer must have issued L2CA_Disconnect request, so there
987	 * must be a socket that wants to be disconnected. Use Netgraph
988	 * message token to find it.
989	 */
990
991	pcb = ng_btsocket_l2cap_pcb_by_token(msg->header.token);
992	if (pcb == NULL) {
993		mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
994		return (0);
995	}
996
997	mtx_lock(&pcb->pcb_mtx);
998
999	/* XXX Close socket no matter what op->result says */
1000	if (pcb->state != NG_BTSOCKET_L2CAP_CLOSED) {
1001       		NG_BTSOCKET_L2CAP_INFO(
1002"%s: Got L2CA_Disconnect response, token=%d, src bdaddr=%x:%x:%x:%x:%x:%x, " \
1003"dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, result=%d, state=%d\n",
1004			__func__, msg->header.token,
1005			pcb->src.b[5], pcb->src.b[4], pcb->src.b[3],
1006			pcb->src.b[2], pcb->src.b[1], pcb->src.b[0],
1007			pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3],
1008			pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0],
1009			pcb->psm, pcb->cid, op->result, pcb->state);
1010
1011		ng_btsocket_l2cap_untimeout(pcb);
1012
1013		pcb->state = NG_BTSOCKET_L2CAP_CLOSED;
1014		soisdisconnected(pcb->so);
1015	}
1016
1017	mtx_unlock(&pcb->pcb_mtx);
1018	mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
1019
1020	return (0);
1021} /* ng_btsocket_l2cap_process_l2ca_discon_rsp */
1022
1023/*
1024 * Process L2CA_Disconnect indicator
1025 */
1026
1027static int
1028ng_btsocket_l2cap_process_l2ca_discon_ind(struct ng_mesg *msg,
1029		ng_btsocket_l2cap_rtentry_p rt)
1030{
1031	ng_l2cap_l2ca_discon_ind_ip	*ip = NULL;
1032	ng_btsocket_l2cap_pcb_t		*pcb = NULL;
1033
1034	/* Check message */
1035	if (msg->header.arglen != sizeof(*ip))
1036		return (EMSGSIZE);
1037
1038	ip = (ng_l2cap_l2ca_discon_ind_ip *)(msg->data);
1039
1040	mtx_lock(&ng_btsocket_l2cap_sockets_mtx);
1041
1042	/* Look for the socket with given channel ID */
1043	pcb = ng_btsocket_l2cap_pcb_by_cid(&rt->src, ip->lcid);
1044	if (pcb == NULL) {
1045		mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
1046		return (0);
1047	}
1048
1049	/*
1050	 * Channel has already been destroyed, so disconnect the socket
1051	 * and be done with it. If there was any pending request we can
1052	 * not do anything here anyway.
1053	 */
1054
1055	mtx_lock(&pcb->pcb_mtx);
1056
1057       	NG_BTSOCKET_L2CAP_INFO(
1058"%s: Got L2CA_Disconnect indicator, src bdaddr=%x:%x:%x:%x:%x:%x, " \
1059"dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, state=%d\n",
1060		__func__,
1061		pcb->src.b[5], pcb->src.b[4], pcb->src.b[3],
1062		pcb->src.b[2], pcb->src.b[1], pcb->src.b[0],
1063		pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3],
1064		pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0],
1065		pcb->psm, pcb->cid, pcb->state);
1066
1067	if (pcb->flags & NG_BTSOCKET_L2CAP_TIMO)
1068		ng_btsocket_l2cap_untimeout(pcb);
1069
1070	pcb->state = NG_BTSOCKET_L2CAP_CLOSED;
1071	soisdisconnected(pcb->so);
1072
1073	mtx_unlock(&pcb->pcb_mtx);
1074	mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
1075
1076	return (0);
1077} /* ng_btsocket_l2cap_process_l2ca_discon_ind */
1078
1079/*
1080 * Process L2CA_Write response
1081 */
1082
1083static int
1084ng_btsocket_l2cap_process_l2ca_write_rsp(struct ng_mesg *msg,
1085		ng_btsocket_l2cap_rtentry_p rt)
1086{
1087	ng_l2cap_l2ca_write_op	*op = NULL;
1088	ng_btsocket_l2cap_pcb_t	*pcb = NULL;
1089
1090	/* Check message */
1091	if (msg->header.arglen != sizeof(*op))
1092		return (EMSGSIZE);
1093
1094	op = (ng_l2cap_l2ca_write_op *)(msg->data);
1095
1096	mtx_lock(&ng_btsocket_l2cap_sockets_mtx);
1097
1098	/* Look for the socket with given token */
1099	pcb = ng_btsocket_l2cap_pcb_by_token(msg->header.token);
1100	if (pcb == NULL) {
1101		mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
1102		return (ENOENT);
1103	}
1104
1105	mtx_lock(&pcb->pcb_mtx);
1106
1107       	NG_BTSOCKET_L2CAP_INFO(
1108"%s: Got L2CA_Write response, src bdaddr=%x:%x:%x:%x:%x:%x, " \
1109"dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, result=%d, length=%d, " \
1110"state=%d\n",		__func__,
1111			pcb->src.b[5], pcb->src.b[4], pcb->src.b[3],
1112			pcb->src.b[2], pcb->src.b[1], pcb->src.b[0],
1113			pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3],
1114			pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0],
1115			pcb->psm, pcb->cid, op->result, op->length,
1116			pcb->state);
1117
1118	if (pcb->state != NG_BTSOCKET_L2CAP_OPEN) {
1119		mtx_unlock(&pcb->pcb_mtx);
1120		mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
1121
1122		return (ENOENT);
1123	}
1124
1125	ng_btsocket_l2cap_untimeout(pcb);
1126
1127	/*
1128 	 * Check if we have more data to send
1129 	 */
1130
1131	sbdroprecord(&pcb->so->so_snd);
1132	if (pcb->so->so_snd.sb_cc > 0) {
1133		if (ng_btsocket_l2cap_send2(pcb) == 0)
1134			ng_btsocket_l2cap_timeout(pcb);
1135		else
1136			sbdroprecord(&pcb->so->so_snd); /* XXX */
1137	}
1138
1139	/*
1140	 * Now set the result, drop packet from the socket send queue and
1141	 * ask for more (wakeup sender)
1142	 */
1143
1144	pcb->so->so_error = ng_btsocket_l2cap_result2errno(op->result);
1145	sowwakeup(pcb->so);
1146
1147	mtx_unlock(&pcb->pcb_mtx);
1148	mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
1149
1150	return (0);
1151} /* ng_btsocket_l2cap_process_l2ca_write_rsp */
1152
1153/*
1154 * Send L2CA_Connect request
1155 */
1156
1157static int
1158ng_btsocket_l2cap_send_l2ca_con_req(ng_btsocket_l2cap_pcb_p pcb)
1159{
1160	struct ng_mesg		*msg = NULL;
1161	ng_l2cap_l2ca_con_ip	*ip = NULL;
1162	int			 error = 0;
1163
1164	mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1165
1166	if (pcb->rt == NULL ||
1167	    pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook))
1168		return (ENETDOWN);
1169
1170	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON,
1171		sizeof(*ip), M_NOWAIT);
1172	if (msg == NULL)
1173		return (ENOMEM);
1174
1175	msg->header.token = pcb->token;
1176
1177	ip = (ng_l2cap_l2ca_con_ip *)(msg->data);
1178	bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr));
1179	ip->psm = pcb->psm;
1180
1181	NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_node, msg,pcb->rt->hook, 0);
1182
1183	return (error);
1184} /* ng_btsocket_l2cap_send_l2ca_con_req */
1185
1186/*
1187 * Send L2CA_Connect response
1188 */
1189
1190static int
1191ng_btsocket_l2cap_send_l2ca_con_rsp_req(u_int32_t token,
1192		ng_btsocket_l2cap_rtentry_p rt, bdaddr_p dst, int ident,
1193		int lcid, int result)
1194{
1195	struct ng_mesg			*msg = NULL;
1196	ng_l2cap_l2ca_con_rsp_ip	*ip = NULL;
1197	int				 error = 0;
1198
1199	if (rt == NULL || rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
1200		return (ENETDOWN);
1201
1202	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON_RSP,
1203		sizeof(*ip), M_NOWAIT);
1204	if (msg == NULL)
1205		return (ENOMEM);
1206
1207	msg->header.token = token;
1208
1209	ip = (ng_l2cap_l2ca_con_rsp_ip *)(msg->data);
1210	bcopy(dst, &ip->bdaddr, sizeof(ip->bdaddr));
1211	ip->ident = ident;
1212	ip->lcid = lcid;
1213	ip->result = result;
1214	ip->status = 0;
1215
1216	NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_node, msg, rt->hook, 0);
1217
1218	return (error);
1219} /* ng_btsocket_l2cap_send_l2ca_con_rsp_req */
1220
1221/*
1222 * Send L2CA_Config request
1223 */
1224
1225static int
1226ng_btsocket_l2cap_send_l2ca_cfg_req(ng_btsocket_l2cap_pcb_p pcb)
1227{
1228	struct ng_mesg		*msg = NULL;
1229	ng_l2cap_l2ca_cfg_ip	*ip = NULL;
1230	int			 error = 0;
1231
1232	mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1233
1234	if (pcb->rt == NULL ||
1235	    pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook))
1236		return (ENETDOWN);
1237
1238	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG,
1239		sizeof(*ip), M_NOWAIT);
1240	if (msg == NULL)
1241		return (ENOMEM);
1242
1243	msg->header.token = pcb->token;
1244
1245	ip = (ng_l2cap_l2ca_cfg_ip *)(msg->data);
1246	ip->lcid = pcb->cid;
1247	ip->imtu = pcb->imtu;
1248	bcopy(&pcb->oflow, &ip->oflow, sizeof(ip->oflow));
1249	ip->flush_timo = pcb->flush_timo;
1250	ip->link_timo = pcb->link_timo;
1251
1252	NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_node, msg,pcb->rt->hook, 0);
1253
1254	return (error);
1255} /* ng_btsocket_l2cap_send_l2ca_cfg_req */
1256
1257/*
1258 * Send L2CA_Config response
1259 */
1260
1261static int
1262ng_btsocket_l2cap_send_l2ca_cfg_rsp(ng_btsocket_l2cap_pcb_p pcb)
1263{
1264	struct ng_mesg			*msg = NULL;
1265	ng_l2cap_l2ca_cfg_rsp_ip	*ip = NULL;
1266	int				 error = 0;
1267
1268	mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1269
1270	if (pcb->rt == NULL ||
1271	    pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook))
1272		return (ENETDOWN);
1273
1274	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_RSP,
1275		sizeof(*ip), M_NOWAIT);
1276	if (msg == NULL)
1277		return (ENOMEM);
1278
1279	msg->header.token = pcb->token;
1280
1281	ip = (ng_l2cap_l2ca_cfg_rsp_ip *)(msg->data);
1282	ip->lcid = pcb->cid;
1283	ip->omtu = pcb->omtu;
1284	bcopy(&pcb->iflow, &ip->iflow, sizeof(ip->iflow));
1285
1286	NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_node, msg, pcb->rt->hook, 0);
1287
1288	return (error);
1289} /* ng_btsocket_l2cap_send_l2ca_cfg_rsp */
1290
1291/*
1292 * Send L2CA_Disconnect request
1293 */
1294
1295static int
1296ng_btsocket_l2cap_send_l2ca_discon_req(u_int32_t token,
1297		ng_btsocket_l2cap_pcb_p pcb)
1298{
1299	struct ng_mesg		*msg = NULL;
1300	ng_l2cap_l2ca_discon_ip	*ip = NULL;
1301	int			 error = 0;
1302
1303	mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1304
1305	if (pcb->rt == NULL ||
1306	    pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook))
1307		return (ENETDOWN);
1308
1309	NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON,
1310		sizeof(*ip), M_NOWAIT);
1311	if (msg == NULL)
1312		return (ENOMEM);
1313
1314	msg->header.token = token;
1315
1316	ip = (ng_l2cap_l2ca_discon_ip *)(msg->data);
1317	ip->lcid = pcb->cid;
1318
1319	NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_node, msg,pcb->rt->hook, 0);
1320
1321	return (error);
1322} /* ng_btsocket_l2cap_send_l2ca_discon_req */
1323
1324/*****************************************************************************
1325 *****************************************************************************
1326 **                              Socket interface
1327 *****************************************************************************
1328 *****************************************************************************/
1329
1330/*
1331 * L2CAP sockets data input routine
1332 */
1333
1334static void
1335ng_btsocket_l2cap_data_input(struct mbuf *m, hook_p hook)
1336{
1337	ng_l2cap_hdr_t			*hdr = NULL;
1338	ng_l2cap_clt_hdr_t		*clt_hdr = NULL;
1339	ng_btsocket_l2cap_pcb_t		*pcb = NULL;
1340	ng_btsocket_l2cap_rtentry_t	*rt = NULL;
1341
1342	if (hook == NULL) {
1343		NG_BTSOCKET_L2CAP_ALERT(
1344"%s: Invalid source hook for L2CAP data packet\n", __func__);
1345		goto drop;
1346	}
1347
1348	rt = (ng_btsocket_l2cap_rtentry_t *) NG_HOOK_PRIVATE(hook);
1349	if (rt == NULL) {
1350		NG_BTSOCKET_L2CAP_ALERT(
1351"%s: Could not find out source bdaddr for L2CAP data packet\n", __func__);
1352		goto drop;
1353	}
1354
1355	/* Make sure we can access header */
1356	if (m->m_pkthdr.len < sizeof(*hdr)) {
1357		NG_BTSOCKET_L2CAP_ERR(
1358"%s: L2CAP data packet too small, len=%d\n", __func__, m->m_pkthdr.len);
1359		goto drop;
1360	}
1361
1362	if (m->m_len < sizeof(*hdr)) {
1363		m = m_pullup(m, sizeof(*hdr));
1364		if (m == NULL)
1365			goto drop;
1366	}
1367
1368	/* Strip L2CAP packet header and verify packet length */
1369	hdr = mtod(m, ng_l2cap_hdr_t *);
1370	m_adj(m, sizeof(*hdr));
1371
1372	if (hdr->length != m->m_pkthdr.len) {
1373		NG_BTSOCKET_L2CAP_ERR(
1374"%s: Bad L2CAP data packet length, len=%d, length=%d\n",
1375			__func__, m->m_pkthdr.len, hdr->length);
1376		goto drop;
1377	}
1378
1379	/*
1380	 * Now process packet. Two cases:
1381	 *
1382	 * 1) Normal packet (cid != 2) then find connected socket and append
1383	 *    mbuf to the socket queue. Wakeup socket.
1384	 *
1385	 * 2) Broadcast packet (cid == 2) then find all sockets that connected
1386	 *    to the given PSM and have SO_BROADCAST bit set and append mbuf
1387	 *    to the socket queue. Wakeup socket.
1388	 */
1389
1390	NG_BTSOCKET_L2CAP_INFO(
1391"%s: Received L2CAP data packet: src bdaddr=%x:%x:%x:%x:%x:%x, " \
1392"dcid=%d, length=%d\n",
1393		__func__,
1394		rt->src.b[5], rt->src.b[4], rt->src.b[3],
1395		rt->src.b[2], rt->src.b[1], rt->src.b[0],
1396		hdr->dcid, hdr->length);
1397
1398	if (hdr->dcid >= NG_L2CAP_FIRST_CID) {
1399
1400		mtx_lock(&ng_btsocket_l2cap_sockets_mtx);
1401
1402		/* Normal packet: find connected socket */
1403		pcb = ng_btsocket_l2cap_pcb_by_cid(&rt->src, hdr->dcid);
1404		if (pcb == NULL) {
1405			mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
1406			goto drop;
1407		}
1408
1409		mtx_lock(&pcb->pcb_mtx);
1410
1411		if (pcb->state != NG_BTSOCKET_L2CAP_OPEN) {
1412			NG_BTSOCKET_L2CAP_ERR(
1413"%s: No connected socket found, src bdaddr=%x:%x:%x:%x:%x:%x, dcid=%d, " \
1414"state=%d\n",			__func__,
1415				rt->src.b[5], rt->src.b[4], rt->src.b[3],
1416				rt->src.b[2], rt->src.b[1], rt->src.b[0],
1417				hdr->dcid, pcb->state);
1418
1419			mtx_unlock(&pcb->pcb_mtx);
1420			mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
1421			goto drop;
1422		}
1423
1424		/* Check packet size against socket's incoming MTU */
1425		if (hdr->length > pcb->imtu) {
1426			NG_BTSOCKET_L2CAP_ERR(
1427"%s: L2CAP data packet too big, src bdaddr=%x:%x:%x:%x:%x:%x, " \
1428"dcid=%d, length=%d, imtu=%d\n",
1429				__func__,
1430				rt->src.b[5], rt->src.b[4], rt->src.b[3],
1431				rt->src.b[2], rt->src.b[1], rt->src.b[0],
1432				hdr->dcid, hdr->length, pcb->imtu);
1433
1434			mtx_unlock(&pcb->pcb_mtx);
1435			mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
1436			goto drop;
1437		}
1438
1439		/* Check if we have enough space in socket receive queue */
1440		if (m->m_pkthdr.len > sbspace(&pcb->so->so_rcv)) {
1441
1442			/*
1443			 * This is really bad. Receive queue on socket does
1444			 * not have enough space for the packet. We do not
1445			 * have any other choice but drop the packet. L2CAP
1446			 * does not provide any flow control.
1447			 */
1448
1449			NG_BTSOCKET_L2CAP_ERR(
1450"%s: Not enough space in socket receive queue. Dropping L2CAP data packet, " \
1451"src bdaddr=%x:%x:%x:%x:%x:%x, dcid=%d, len=%d, space=%ld\n",
1452				__func__,
1453				rt->src.b[5], rt->src.b[4], rt->src.b[3],
1454				rt->src.b[2], rt->src.b[1], rt->src.b[0],
1455				hdr->dcid, m->m_pkthdr.len,
1456				sbspace(&pcb->so->so_rcv));
1457
1458			mtx_unlock(&pcb->pcb_mtx);
1459			mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
1460			goto drop;
1461		}
1462
1463		/* Append packet to the socket receive queue and wakeup */
1464		sbappendrecord(&pcb->so->so_rcv, m);
1465		m = NULL;
1466
1467		sorwakeup(pcb->so);
1468
1469		mtx_unlock(&pcb->pcb_mtx);
1470		mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
1471	} else if (hdr->dcid == NG_L2CAP_CLT_CID) {
1472		/* Broadcast packet: give packet to all sockets  */
1473
1474		/* Check packet size against connectionless MTU */
1475		if (hdr->length > NG_L2CAP_MTU_DEFAULT) {
1476			NG_BTSOCKET_L2CAP_ERR(
1477"%s: Connectionless L2CAP data packet too big, " \
1478"src bdaddr=%x:%x:%x:%x:%x:%x, length=%d\n",
1479				__func__,
1480				rt->src.b[5], rt->src.b[4], rt->src.b[3],
1481				rt->src.b[2], rt->src.b[1], rt->src.b[0],
1482				hdr->length);
1483			goto drop;
1484		}
1485
1486		/* Make sure we can access connectionless header */
1487		if (m->m_pkthdr.len < sizeof(*clt_hdr)) {
1488			NG_BTSOCKET_L2CAP_ERR(
1489"%s: Can not get L2CAP connectionless packet header, " \
1490"src bdaddr=%x:%x:%x:%x:%x:%x, length=%d\n",
1491				__func__,
1492				rt->src.b[5], rt->src.b[4], rt->src.b[3],
1493				rt->src.b[2], rt->src.b[1], rt->src.b[0],
1494				hdr->length);
1495			goto drop;
1496		}
1497
1498		if (m->m_len < sizeof(*clt_hdr)) {
1499			m = m_pullup(m, sizeof(*clt_hdr));
1500			if (m == NULL)
1501				goto drop;
1502		}
1503
1504		/* Strip connectionless header and deliver packet */
1505		clt_hdr = mtod(m, ng_l2cap_clt_hdr_t *);
1506		m_adj(m, sizeof(*clt_hdr));
1507
1508		NG_BTSOCKET_L2CAP_INFO(
1509"%s: Got L2CAP connectionless data packet, " \
1510"src bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, length=%d\n",
1511			__func__,
1512			rt->src.b[5], rt->src.b[4], rt->src.b[3],
1513			rt->src.b[2], rt->src.b[1], rt->src.b[0],
1514			clt_hdr->psm, hdr->length);
1515
1516		mtx_lock(&ng_btsocket_l2cap_sockets_mtx);
1517
1518		LIST_FOREACH(pcb, &ng_btsocket_l2cap_sockets, next) {
1519			struct mbuf	*copy = NULL;
1520
1521			mtx_lock(&pcb->pcb_mtx);
1522
1523			if (bcmp(&rt->src, &pcb->src, sizeof(pcb->src)) != 0 ||
1524			    pcb->psm != clt_hdr->psm ||
1525			    pcb->state != NG_BTSOCKET_L2CAP_OPEN ||
1526			    (pcb->so->so_options & SO_BROADCAST) == 0 ||
1527			    m->m_pkthdr.len > sbspace(&pcb->so->so_rcv))
1528				goto next;
1529
1530			/*
1531			 * Create a copy of the packet and append it to the
1532			 * socket's queue. If m_dup() failed - no big deal
1533			 * it is a broadcast traffic after all
1534			 */
1535
1536			copy = m_dup(m, M_DONTWAIT);
1537			if (copy != NULL) {
1538				sbappendrecord(&pcb->so->so_rcv, copy);
1539				sorwakeup(pcb->so);
1540			}
1541next:
1542			mtx_unlock(&pcb->pcb_mtx);
1543		}
1544
1545		mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
1546	}
1547drop:
1548	NG_FREE_M(m); /* checks for m != NULL */
1549} /* ng_btsocket_l2cap_data_input */
1550
1551/*
1552 * L2CAP sockets default message input routine
1553 */
1554
1555static void
1556ng_btsocket_l2cap_default_msg_input(struct ng_mesg *msg, hook_p hook)
1557{
1558	switch (msg->header.cmd) {
1559	case NGM_L2CAP_NODE_HOOK_INFO: {
1560		ng_btsocket_l2cap_rtentry_t	*rt = NULL;
1561
1562		if (hook == NULL || msg->header.arglen != sizeof(bdaddr_t))
1563			break;
1564
1565		if (bcmp(msg->data, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
1566			break;
1567
1568		mtx_lock(&ng_btsocket_l2cap_rt_mtx);
1569
1570		rt = (ng_btsocket_l2cap_rtentry_t *) NG_HOOK_PRIVATE(hook);
1571		if (rt == NULL) {
1572			rt = malloc(sizeof(*rt),
1573				M_NETGRAPH_BTSOCKET_L2CAP, M_NOWAIT|M_ZERO);
1574			if (rt == NULL) {
1575				mtx_unlock(&ng_btsocket_l2cap_rt_mtx);
1576				break;
1577			}
1578
1579			LIST_INSERT_HEAD(&ng_btsocket_l2cap_rt, rt, next);
1580
1581			NG_HOOK_SET_PRIVATE(hook, rt);
1582		}
1583
1584		bcopy(msg->data, &rt->src, sizeof(rt->src));
1585		rt->hook = hook;
1586
1587		mtx_unlock(&ng_btsocket_l2cap_rt_mtx);
1588
1589		NG_BTSOCKET_L2CAP_INFO(
1590"%s: Updating hook \"%s\", src bdaddr=%x:%x:%x:%x:%x:%x\n",
1591			__func__, NG_HOOK_NAME(hook),
1592			rt->src.b[5], rt->src.b[4], rt->src.b[3],
1593			rt->src.b[2], rt->src.b[1], rt->src.b[0]);
1594		} break;
1595
1596	default:
1597		NG_BTSOCKET_L2CAP_WARN(
1598"%s: Unknown message, cmd=%d\n", __func__, msg->header.cmd);
1599		break;
1600	}
1601
1602	NG_FREE_MSG(msg); /* Checks for msg != NULL */
1603} /* ng_btsocket_l2cap_default_msg_input */
1604
1605/*
1606 * L2CAP sockets L2CA message input routine
1607 */
1608
1609static void
1610ng_btsocket_l2cap_l2ca_msg_input(struct ng_mesg *msg, hook_p hook)
1611{
1612	ng_btsocket_l2cap_rtentry_p	rt = NULL;
1613
1614	if (hook == NULL) {
1615		NG_BTSOCKET_L2CAP_ALERT(
1616"%s: Invalid source hook for L2CA message\n", __func__);
1617		goto drop;
1618	}
1619
1620	rt = (ng_btsocket_l2cap_rtentry_p) NG_HOOK_PRIVATE(hook);
1621	if (rt == NULL) {
1622		NG_BTSOCKET_L2CAP_ALERT(
1623"%s: Could not find out source bdaddr for L2CA message\n", __func__);
1624		goto drop;
1625	}
1626
1627	switch (msg->header.cmd) {
1628	case NGM_L2CAP_L2CA_CON: /* L2CA_Connect response */
1629		ng_btsocket_l2cap_process_l2ca_con_req_rsp(msg, rt);
1630		break;
1631
1632	case NGM_L2CAP_L2CA_CON_RSP: /* L2CA_ConnectRsp response */
1633		ng_btsocket_l2cap_process_l2ca_con_rsp_rsp(msg, rt);
1634		break;
1635
1636	case NGM_L2CAP_L2CA_CON_IND: /* L2CA_Connect indicator */
1637		ng_btsocket_l2cap_process_l2ca_con_ind(msg, rt);
1638		break;
1639
1640	case NGM_L2CAP_L2CA_CFG: /* L2CA_Config response */
1641		ng_btsocket_l2cap_process_l2ca_cfg_req_rsp(msg, rt);
1642		break;
1643
1644	case NGM_L2CAP_L2CA_CFG_RSP: /* L2CA_ConfigRsp response */
1645		ng_btsocket_l2cap_process_l2ca_cfg_rsp_rsp(msg, rt);
1646		break;
1647
1648	case NGM_L2CAP_L2CA_CFG_IND: /* L2CA_Config indicator */
1649		ng_btsocket_l2cap_process_l2ca_cfg_ind(msg, rt);
1650		break;
1651
1652	case NGM_L2CAP_L2CA_DISCON: /* L2CA_Disconnect response */
1653		ng_btsocket_l2cap_process_l2ca_discon_rsp(msg, rt);
1654		break;
1655
1656	case NGM_L2CAP_L2CA_DISCON_IND: /* L2CA_Disconnect indicator */
1657		ng_btsocket_l2cap_process_l2ca_discon_ind(msg, rt);
1658		break;
1659
1660	case NGM_L2CAP_L2CA_WRITE: /* L2CA_Write response */
1661		ng_btsocket_l2cap_process_l2ca_write_rsp(msg, rt);
1662		break;
1663
1664	/* XXX FIXME add other L2CA messages */
1665
1666	default:
1667		NG_BTSOCKET_L2CAP_WARN(
1668"%s: Unknown L2CA message, cmd=%d\n", __func__, msg->header.cmd);
1669		break;
1670	}
1671drop:
1672	NG_FREE_MSG(msg);
1673} /* ng_btsocket_l2cap_l2ca_msg_input */
1674
1675/*
1676 * L2CAP sockets input routine
1677 */
1678
1679static void
1680ng_btsocket_l2cap_input(void *context, int pending)
1681{
1682	item_p	item = NULL;
1683	hook_p	hook = NULL;
1684
1685	for (;;) {
1686		mtx_lock(&ng_btsocket_l2cap_queue_mtx);
1687		NG_BT_ITEMQ_DEQUEUE(&ng_btsocket_l2cap_queue, item);
1688		mtx_unlock(&ng_btsocket_l2cap_queue_mtx);
1689
1690		if (item == NULL)
1691			break;
1692
1693		NGI_GET_HOOK(item, hook);
1694		if (hook != NULL && NG_HOOK_NOT_VALID(hook))
1695			goto drop;
1696
1697		switch(item->el_flags & NGQF_TYPE) {
1698		case NGQF_DATA: {
1699			struct mbuf     *m = NULL;
1700
1701			NGI_GET_M(item, m);
1702			ng_btsocket_l2cap_data_input(m, hook);
1703			} break;
1704
1705		case NGQF_MESG: {
1706			struct ng_mesg  *msg = NULL;
1707
1708			NGI_GET_MSG(item, msg);
1709
1710			switch (msg->header.cmd) {
1711			case NGM_L2CAP_L2CA_CON:
1712			case NGM_L2CAP_L2CA_CON_RSP:
1713			case NGM_L2CAP_L2CA_CON_IND:
1714			case NGM_L2CAP_L2CA_CFG:
1715			case NGM_L2CAP_L2CA_CFG_RSP:
1716			case NGM_L2CAP_L2CA_CFG_IND:
1717			case NGM_L2CAP_L2CA_DISCON:
1718			case NGM_L2CAP_L2CA_DISCON_IND:
1719			case NGM_L2CAP_L2CA_WRITE:
1720			/* XXX FIXME add other L2CA messages */
1721				ng_btsocket_l2cap_l2ca_msg_input(msg, hook);
1722				break;
1723
1724			default:
1725				ng_btsocket_l2cap_default_msg_input(msg, hook);
1726				break;
1727			}
1728			} break;
1729
1730		default:
1731			KASSERT(0,
1732("%s: invalid item type=%ld\n", __func__, (item->el_flags & NGQF_TYPE)));
1733			break;
1734		}
1735drop:
1736		if (hook != NULL)
1737			NG_HOOK_UNREF(hook);
1738
1739		NG_FREE_ITEM(item);
1740	}
1741} /* ng_btsocket_l2cap_input */
1742
1743/*
1744 * Route cleanup task. Gets scheduled when hook is disconnected. Here we
1745 * will find all sockets that use "invalid" hook and disconnect them.
1746 */
1747
1748static void
1749ng_btsocket_l2cap_rtclean(void *context, int pending)
1750{
1751	ng_btsocket_l2cap_pcb_p		pcb = NULL, pcb_next = NULL;
1752	ng_btsocket_l2cap_rtentry_p	rt = NULL;
1753
1754	mtx_lock(&ng_btsocket_l2cap_rt_mtx);
1755	mtx_lock(&ng_btsocket_l2cap_sockets_mtx);
1756
1757	/*
1758	 * First disconnect all sockets that use "invalid" hook
1759	 */
1760
1761	for (pcb = LIST_FIRST(&ng_btsocket_l2cap_sockets); pcb != NULL; ) {
1762		mtx_lock(&pcb->pcb_mtx);
1763		pcb_next = LIST_NEXT(pcb, next);
1764
1765		if (pcb->rt != NULL &&
1766		    pcb->rt->hook != NULL && NG_HOOK_NOT_VALID(pcb->rt->hook)) {
1767			if (pcb->flags & NG_BTSOCKET_L2CAP_TIMO)
1768				ng_btsocket_l2cap_untimeout(pcb);
1769
1770			pcb->so->so_error = ENETDOWN;
1771			pcb->state = NG_BTSOCKET_L2CAP_CLOSED;
1772			soisdisconnected(pcb->so);
1773
1774			pcb->token = 0;
1775			pcb->cid = 0;
1776			pcb->rt = NULL;
1777		}
1778
1779		mtx_unlock(&pcb->pcb_mtx);
1780		pcb = pcb_next;
1781	}
1782
1783	/*
1784	 * Now cleanup routing table
1785	 */
1786
1787	for (rt = LIST_FIRST(&ng_btsocket_l2cap_rt); rt != NULL; ) {
1788		ng_btsocket_l2cap_rtentry_p	rt_next = LIST_NEXT(rt, next);
1789
1790		if (rt->hook != NULL && NG_HOOK_NOT_VALID(rt->hook)) {
1791			LIST_REMOVE(rt, next);
1792
1793			NG_HOOK_SET_PRIVATE(rt->hook, NULL);
1794			NG_HOOK_UNREF(rt->hook); /* Remove extra reference */
1795
1796			bzero(rt, sizeof(*rt));
1797			free(rt, M_NETGRAPH_BTSOCKET_L2CAP);
1798		}
1799
1800		rt = rt_next;
1801	}
1802
1803	mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
1804	mtx_unlock(&ng_btsocket_l2cap_rt_mtx);
1805} /* ng_btsocket_l2cap_rtclean */
1806
1807/*
1808 * Initialize everything
1809 */
1810
1811void
1812ng_btsocket_l2cap_init(void)
1813{
1814	int	error = 0;
1815
1816	ng_btsocket_l2cap_node = NULL;
1817	ng_btsocket_l2cap_debug_level = NG_BTSOCKET_WARN_LEVEL;
1818
1819	/* Register Netgraph node type */
1820	error = ng_newtype(&typestruct);
1821	if (error != 0) {
1822		NG_BTSOCKET_L2CAP_ALERT(
1823"%s: Could not register Netgraph node type, error=%d\n", __func__, error);
1824
1825                return;
1826	}
1827
1828	/* Create Netgrapg node */
1829	error = ng_make_node_common(&typestruct, &ng_btsocket_l2cap_node);
1830	if (error != 0) {
1831		NG_BTSOCKET_L2CAP_ALERT(
1832"%s: Could not create Netgraph node, error=%d\n", __func__, error);
1833
1834		ng_btsocket_l2cap_node = NULL;
1835
1836		return;
1837	}
1838
1839	error = ng_name_node(ng_btsocket_l2cap_node,
1840				NG_BTSOCKET_L2CAP_NODE_TYPE);
1841	if (error != 0) {
1842		NG_BTSOCKET_L2CAP_ALERT(
1843"%s: Could not name Netgraph node, error=%d\n", __func__, error);
1844
1845		NG_NODE_UNREF(ng_btsocket_l2cap_node);
1846		ng_btsocket_l2cap_node = NULL;
1847
1848		return;
1849	}
1850
1851	/* Create input queue */
1852	NG_BT_ITEMQ_INIT(&ng_btsocket_l2cap_queue, ifqmaxlen);
1853	mtx_init(&ng_btsocket_l2cap_queue_mtx,
1854		"btsocks_l2cap_queue_mtx", NULL, MTX_DEF);
1855	TASK_INIT(&ng_btsocket_l2cap_queue_task, 0,
1856		ng_btsocket_l2cap_input, NULL);
1857
1858	/* Create list of sockets */
1859	LIST_INIT(&ng_btsocket_l2cap_sockets);
1860	mtx_init(&ng_btsocket_l2cap_sockets_mtx,
1861		"btsocks_l2cap_sockets_mtx", NULL, MTX_DEF);
1862
1863	/* Routing table */
1864	LIST_INIT(&ng_btsocket_l2cap_rt);
1865	mtx_init(&ng_btsocket_l2cap_rt_mtx,
1866		"btsocks_l2cap_rt_mtx", NULL, MTX_DEF);
1867	TASK_INIT(&ng_btsocket_l2cap_rt_task, 0,
1868		ng_btsocket_l2cap_rtclean, NULL);
1869} /* ng_btsocket_l2cap_init */
1870
1871/*
1872 * Abort connection on socket
1873 */
1874
1875void
1876ng_btsocket_l2cap_abort(struct socket *so)
1877{
1878	so->so_error = ECONNABORTED;
1879
1880	(void)ng_btsocket_l2cap_disconnect(so);
1881} /* ng_btsocket_l2cap_abort */
1882
1883void
1884ng_btsocket_l2cap_close(struct socket *so)
1885{
1886
1887	(void)ng_btsocket_l2cap_disconnect(so);
1888} /* ng_btsocket_l2cap_close */
1889
1890/*
1891 * Accept connection on socket. Nothing to do here, socket must be connected
1892 * and ready, so just return peer address and be done with it.
1893 */
1894
1895int
1896ng_btsocket_l2cap_accept(struct socket *so, struct sockaddr **nam)
1897{
1898	if (ng_btsocket_l2cap_node == NULL)
1899		return (EINVAL);
1900
1901	return (ng_btsocket_l2cap_peeraddr(so, nam));
1902} /* ng_btsocket_l2cap_accept */
1903
1904/*
1905 * Create and attach new socket
1906 */
1907
1908int
1909ng_btsocket_l2cap_attach(struct socket *so, int proto, struct thread *td)
1910{
1911	static u_int32_t	token = 0;
1912	ng_btsocket_l2cap_pcb_p	pcb = so2l2cap_pcb(so);
1913	int			error;
1914
1915	/* Check socket and protocol */
1916	if (ng_btsocket_l2cap_node == NULL)
1917		return (EPROTONOSUPPORT);
1918	if (so->so_type != SOCK_SEQPACKET)
1919		return (ESOCKTNOSUPPORT);
1920
1921#if 0 /* XXX sonewconn() calls "pru_attach" with proto == 0 */
1922	if (proto != 0)
1923		if (proto != BLUETOOTH_PROTO_L2CAP)
1924			return (EPROTONOSUPPORT);
1925#endif /* XXX */
1926
1927	if (pcb != NULL)
1928		return (EISCONN);
1929
1930	/* Reserve send and receive space if it is not reserved yet */
1931	if ((so->so_snd.sb_hiwat == 0) || (so->so_rcv.sb_hiwat == 0)) {
1932		error = soreserve(so, NG_BTSOCKET_L2CAP_SENDSPACE,
1933					NG_BTSOCKET_L2CAP_RECVSPACE);
1934		if (error != 0)
1935			return (error);
1936	}
1937
1938	/* Allocate the PCB */
1939        pcb = malloc(sizeof(*pcb),
1940		M_NETGRAPH_BTSOCKET_L2CAP, M_NOWAIT | M_ZERO);
1941        if (pcb == NULL)
1942                return (ENOMEM);
1943
1944	/* Link the PCB and the socket */
1945	so->so_pcb = (caddr_t) pcb;
1946	pcb->so = so;
1947	pcb->state = NG_BTSOCKET_L2CAP_CLOSED;
1948
1949	/* Initialize PCB */
1950	pcb->imtu = pcb->omtu = NG_L2CAP_MTU_DEFAULT;
1951
1952	/* Default flow */
1953	pcb->iflow.flags = 0x0;
1954	pcb->iflow.service_type = NG_HCI_SERVICE_TYPE_BEST_EFFORT;
1955	pcb->iflow.token_rate = 0xffffffff; /* maximum */
1956	pcb->iflow.token_bucket_size = 0xffffffff; /* maximum */
1957	pcb->iflow.peak_bandwidth = 0x00000000; /* maximum */
1958	pcb->iflow.latency = 0xffffffff; /* don't care */
1959	pcb->iflow.delay_variation = 0xffffffff; /* don't care */
1960
1961	bcopy(&pcb->iflow, &pcb->oflow, sizeof(pcb->oflow));
1962
1963	pcb->flush_timo = NG_L2CAP_FLUSH_TIMO_DEFAULT;
1964	pcb->link_timo = NG_L2CAP_LINK_TIMO_DEFAULT;
1965
1966	callout_handle_init(&pcb->timo);
1967
1968	/*
1969	 * XXX Mark PCB mutex as DUPOK to prevent "duplicated lock of
1970	 * the same type" message. When accepting new L2CAP connection
1971	 * ng_btsocket_l2cap_process_l2ca_con_ind() holds both PCB mutexes
1972	 * for "old" (accepting) PCB and "new" (created) PCB.
1973	 */
1974
1975	mtx_init(&pcb->pcb_mtx, "btsocks_l2cap_pcb_mtx", NULL,
1976		MTX_DEF|MTX_DUPOK);
1977
1978        /*
1979	 * Add the PCB to the list
1980	 *
1981	 * XXX FIXME VERY IMPORTANT!
1982	 *
1983	 * This is totally FUBAR. We could get here in two cases:
1984	 *
1985	 * 1) When user calls socket()
1986	 * 2) When we need to accept new incomming connection and call
1987	 *    sonewconn()
1988	 *
1989	 * In the first case we must acquire ng_btsocket_l2cap_sockets_mtx.
1990	 * In the second case we hold ng_btsocket_l2cap_sockets_mtx already.
1991	 * So we now need to distinguish between these cases. From reading
1992	 * /sys/kern/uipc_socket.c we can find out that sonewconn() calls
1993	 * pru_attach with proto == 0 and td == NULL. For now use this fact
1994	 * to figure out if we were called from socket() or from sonewconn().
1995	 */
1996
1997	if (td != NULL)
1998		mtx_lock(&ng_btsocket_l2cap_sockets_mtx);
1999	else
2000		mtx_assert(&ng_btsocket_l2cap_sockets_mtx, MA_OWNED);
2001
2002	/* Set PCB token. Use ng_btsocket_l2cap_sockets_mtx for protection */
2003	if (++ token == 0)
2004		token ++;
2005
2006	pcb->token = token;
2007
2008	LIST_INSERT_HEAD(&ng_btsocket_l2cap_sockets, pcb, next);
2009
2010	if (td != NULL)
2011		mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
2012
2013        return (0);
2014} /* ng_btsocket_l2cap_attach */
2015
2016/*
2017 * Bind socket
2018 */
2019
2020int
2021ng_btsocket_l2cap_bind(struct socket *so, struct sockaddr *nam,
2022		struct thread *td)
2023{
2024	ng_btsocket_l2cap_pcb_t	*pcb = NULL;
2025	struct sockaddr_l2cap	*sa = (struct sockaddr_l2cap *) nam;
2026	int			 psm, error = 0;
2027
2028	if (ng_btsocket_l2cap_node == NULL)
2029		return (EINVAL);
2030
2031	/* Verify address */
2032	if (sa == NULL)
2033		return (EINVAL);
2034	if (sa->l2cap_family != AF_BLUETOOTH)
2035		return (EAFNOSUPPORT);
2036	if (sa->l2cap_len != sizeof(*sa))
2037		return (EINVAL);
2038
2039	psm = le16toh(sa->l2cap_psm);
2040
2041	/*
2042	 * Check if other socket has this address already (look for exact
2043	 * match PSM and bdaddr) and assign socket address if it's available.
2044	 *
2045	 * Note: socket can be bound to ANY PSM (zero) thus allowing several
2046	 * channels with the same PSM between the same pair of BD_ADDR'es.
2047	 */
2048
2049	mtx_lock(&ng_btsocket_l2cap_sockets_mtx);
2050
2051	LIST_FOREACH(pcb, &ng_btsocket_l2cap_sockets, next)
2052		if (psm != 0 && psm == pcb->psm &&
2053		    bcmp(&pcb->src, &sa->l2cap_bdaddr, sizeof(bdaddr_t)) == 0)
2054			break;
2055
2056	if (pcb == NULL) {
2057		/* Set socket address */
2058		pcb = so2l2cap_pcb(so);
2059		if (pcb != NULL) {
2060			bcopy(&sa->l2cap_bdaddr, &pcb->src, sizeof(pcb->src));
2061			pcb->psm = psm;
2062		} else
2063			error = EINVAL;
2064	} else
2065		error = EADDRINUSE;
2066
2067	mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
2068
2069	return (error);
2070} /* ng_btsocket_l2cap_bind */
2071
2072/*
2073 * Connect socket
2074 */
2075
2076int
2077ng_btsocket_l2cap_connect(struct socket *so, struct sockaddr *nam,
2078		struct thread *td)
2079{
2080	ng_btsocket_l2cap_pcb_t		*pcb = so2l2cap_pcb(so);
2081	struct sockaddr_l2cap		*sa = (struct sockaddr_l2cap *) nam;
2082	ng_btsocket_l2cap_rtentry_t	*rt = NULL;
2083	int				 have_src, error = 0;
2084
2085	/* Check socket */
2086	if (pcb == NULL)
2087		return (EINVAL);
2088	if (ng_btsocket_l2cap_node == NULL)
2089		return (EINVAL);
2090	if (pcb->state == NG_BTSOCKET_L2CAP_CONNECTING)
2091		return (EINPROGRESS);
2092
2093	/* Verify address */
2094	if (sa == NULL)
2095		return (EINVAL);
2096	if (sa->l2cap_family != AF_BLUETOOTH)
2097		return (EAFNOSUPPORT);
2098	if (sa->l2cap_len != sizeof(*sa))
2099		return (EINVAL);
2100	if (sa->l2cap_psm == 0 ||
2101	    bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
2102		return (EDESTADDRREQ);
2103	if (pcb->psm != 0 && pcb->psm != le16toh(sa->l2cap_psm))
2104		return (EINVAL);
2105
2106	/*
2107	 * Routing. Socket should be bound to some source address. The source
2108	 * address can be ANY. Destination address must be set and it must not
2109	 * be ANY. If source address is ANY then find first rtentry that has
2110	 * src != dst.
2111	 */
2112
2113	mtx_lock(&ng_btsocket_l2cap_rt_mtx);
2114	mtx_lock(&ng_btsocket_l2cap_sockets_mtx);
2115	mtx_lock(&pcb->pcb_mtx);
2116
2117	/* Send destination address and PSM */
2118	bcopy(&sa->l2cap_bdaddr, &pcb->dst, sizeof(pcb->dst));
2119	pcb->psm = le16toh(sa->l2cap_psm);
2120
2121	pcb->rt = NULL;
2122	have_src = bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(pcb->src));
2123
2124	LIST_FOREACH(rt, &ng_btsocket_l2cap_rt, next) {
2125		if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
2126			continue;
2127
2128		/* Match src and dst */
2129		if (have_src) {
2130			if (bcmp(&pcb->src, &rt->src, sizeof(rt->src)) == 0)
2131				break;
2132		} else {
2133			if (bcmp(&pcb->dst, &rt->src, sizeof(rt->src)) != 0)
2134				break;
2135		}
2136	}
2137
2138	if (rt != NULL) {
2139		pcb->rt = rt;
2140
2141		if (!have_src)
2142			bcopy(&rt->src, &pcb->src, sizeof(pcb->src));
2143	} else
2144		error = EHOSTUNREACH;
2145
2146	/*
2147	 * Send L2CA_Connect request
2148	 */
2149
2150	if (error == 0) {
2151		error = ng_btsocket_l2cap_send_l2ca_con_req(pcb);
2152		if (error == 0) {
2153			pcb->flags |= NG_BTSOCKET_L2CAP_CLIENT;
2154			pcb->state = NG_BTSOCKET_L2CAP_CONNECTING;
2155			soisconnecting(pcb->so);
2156
2157			ng_btsocket_l2cap_timeout(pcb);
2158		}
2159	}
2160
2161	mtx_unlock(&pcb->pcb_mtx);
2162	mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
2163	mtx_unlock(&ng_btsocket_l2cap_rt_mtx);
2164
2165	return (error);
2166} /* ng_btsocket_l2cap_connect */
2167
2168/*
2169 * Process ioctl's calls on socket
2170 */
2171
2172int
2173ng_btsocket_l2cap_control(struct socket *so, u_long cmd, caddr_t data,
2174		struct ifnet *ifp, struct thread *td)
2175{
2176	return (EINVAL);
2177} /* ng_btsocket_l2cap_control */
2178
2179/*
2180 * Process getsockopt/setsockopt system calls
2181 */
2182
2183int
2184ng_btsocket_l2cap_ctloutput(struct socket *so, struct sockopt *sopt)
2185{
2186	ng_btsocket_l2cap_pcb_p	pcb = so2l2cap_pcb(so);
2187	int			error = 0;
2188	ng_l2cap_cfg_opt_val_t	v;
2189
2190	if (pcb == NULL)
2191		return (EINVAL);
2192	if (ng_btsocket_l2cap_node == NULL)
2193		return (EINVAL);
2194
2195	if (sopt->sopt_level != SOL_L2CAP)
2196		return (0);
2197
2198	mtx_lock(&pcb->pcb_mtx);
2199
2200	switch (sopt->sopt_dir) {
2201	case SOPT_GET:
2202		switch (sopt->sopt_name) {
2203		case SO_L2CAP_IMTU: /* get incoming MTU */
2204			error = sooptcopyout(sopt, &pcb->imtu,
2205						sizeof(pcb->imtu));
2206			break;
2207
2208		case SO_L2CAP_OMTU: /* get outgoing (peer incoming) MTU */
2209			error = sooptcopyout(sopt, &pcb->omtu,
2210						sizeof(pcb->omtu));
2211			break;
2212
2213		case SO_L2CAP_IFLOW: /* get incoming flow spec. */
2214			error = sooptcopyout(sopt, &pcb->iflow,
2215						sizeof(pcb->iflow));
2216			break;
2217
2218		case SO_L2CAP_OFLOW: /* get outgoing flow spec. */
2219			error = sooptcopyout(sopt, &pcb->oflow,
2220						sizeof(pcb->oflow));
2221			break;
2222
2223		case SO_L2CAP_FLUSH: /* get flush timeout */
2224			error = sooptcopyout(sopt, &pcb->flush_timo,
2225						sizeof(pcb->flush_timo));
2226			break;
2227
2228		default:
2229			error = ENOPROTOOPT;
2230			break;
2231		}
2232		break;
2233
2234	case SOPT_SET:
2235		/*
2236		 * XXX
2237		 * We do not allow to change these parameters while socket is
2238		 * connected or we are in the process of creating a connection.
2239		 * May be this should indicate re-configuration of the open
2240		 * channel?
2241		 */
2242
2243		if (pcb->state != NG_BTSOCKET_L2CAP_CLOSED) {
2244			error = EACCES;
2245			break;
2246		}
2247
2248		switch (sopt->sopt_name) {
2249		case SO_L2CAP_IMTU: /* set incoming MTU */
2250			error = sooptcopyin(sopt, &v, sizeof(v), sizeof(v.mtu));
2251			if (error == 0)
2252				pcb->imtu = v.mtu;
2253			break;
2254
2255		case SO_L2CAP_OFLOW: /* set outgoing flow spec. */
2256			error = sooptcopyin(sopt, &v, sizeof(v),sizeof(v.flow));
2257			if (error == 0)
2258				bcopy(&v.flow, &pcb->oflow, sizeof(pcb->oflow));
2259			break;
2260
2261		case SO_L2CAP_FLUSH: /* set flush timeout */
2262			error = sooptcopyin(sopt, &v, sizeof(v),
2263						sizeof(v.flush_timo));
2264			if (error == 0)
2265				pcb->flush_timo = v.flush_timo;
2266			break;
2267
2268		default:
2269			error = ENOPROTOOPT;
2270			break;
2271		}
2272		break;
2273
2274	default:
2275		error = EINVAL;
2276		break;
2277	}
2278
2279	mtx_unlock(&pcb->pcb_mtx);
2280
2281	return (error);
2282} /* ng_btsocket_l2cap_ctloutput */
2283
2284/*
2285 * Detach and destroy socket
2286 */
2287
2288void
2289ng_btsocket_l2cap_detach(struct socket *so)
2290{
2291	ng_btsocket_l2cap_pcb_p	pcb = so2l2cap_pcb(so);
2292
2293	KASSERT(pcb != NULL, ("ng_btsocket_l2cap_detach: pcb == NULL"));
2294
2295	if (ng_btsocket_l2cap_node == NULL)
2296		return;
2297
2298	mtx_lock(&ng_btsocket_l2cap_sockets_mtx);
2299	mtx_lock(&pcb->pcb_mtx);
2300
2301	/* XXX what to do with pending request? */
2302	if (pcb->flags & NG_BTSOCKET_L2CAP_TIMO)
2303		ng_btsocket_l2cap_untimeout(pcb);
2304
2305	if (pcb->state != NG_BTSOCKET_L2CAP_CLOSED &&
2306	    pcb->state != NG_BTSOCKET_L2CAP_DISCONNECTING)
2307		/* Send disconnect request with "zero" token */
2308		ng_btsocket_l2cap_send_l2ca_discon_req(0, pcb);
2309
2310	pcb->state = NG_BTSOCKET_L2CAP_CLOSED;
2311
2312	LIST_REMOVE(pcb, next);
2313
2314	mtx_unlock(&pcb->pcb_mtx);
2315	mtx_unlock(&ng_btsocket_l2cap_sockets_mtx);
2316
2317	mtx_destroy(&pcb->pcb_mtx);
2318	bzero(pcb, sizeof(*pcb));
2319	free(pcb, M_NETGRAPH_BTSOCKET_L2CAP);
2320
2321	soisdisconnected(so);
2322	so->so_pcb = NULL;
2323} /* ng_btsocket_l2cap_detach */
2324
2325/*
2326 * Disconnect socket
2327 */
2328
2329int
2330ng_btsocket_l2cap_disconnect(struct socket *so)
2331{
2332	ng_btsocket_l2cap_pcb_p	pcb = so2l2cap_pcb(so);
2333	int			error = 0;
2334
2335	if (pcb == NULL)
2336		return (EINVAL);
2337	if (ng_btsocket_l2cap_node == NULL)
2338		return (EINVAL);
2339
2340	mtx_lock(&pcb->pcb_mtx);
2341
2342	if (pcb->state == NG_BTSOCKET_L2CAP_DISCONNECTING) {
2343		mtx_unlock(&pcb->pcb_mtx);
2344		return (EINPROGRESS);
2345	}
2346
2347	if (pcb->state != NG_BTSOCKET_L2CAP_CLOSED) {
2348		/* XXX FIXME what to do with pending request? */
2349		if (pcb->flags & NG_BTSOCKET_L2CAP_TIMO)
2350			ng_btsocket_l2cap_untimeout(pcb);
2351
2352		error = ng_btsocket_l2cap_send_l2ca_discon_req(pcb->token, pcb);
2353		if (error == 0) {
2354			pcb->state = NG_BTSOCKET_L2CAP_DISCONNECTING;
2355			soisdisconnecting(so);
2356
2357			ng_btsocket_l2cap_timeout(pcb);
2358		}
2359
2360		/* XXX FIXME what to do if error != 0 */
2361	}
2362
2363	mtx_unlock(&pcb->pcb_mtx);
2364
2365	return (error);
2366} /* ng_btsocket_l2cap_disconnect */
2367
2368/*
2369 * Listen on socket
2370 */
2371
2372int
2373ng_btsocket_l2cap_listen(struct socket *so, int backlog, struct thread *td)
2374{
2375	ng_btsocket_l2cap_pcb_p	pcb = so2l2cap_pcb(so);
2376	int error;
2377
2378	SOCK_LOCK(so);
2379	error = solisten_proto_check(so);
2380	if (error != 0)
2381		goto out;
2382	if (pcb == NULL) {
2383		error = EINVAL;
2384		goto out;
2385	}
2386	if (ng_btsocket_l2cap_node == NULL) {
2387		error = EINVAL;
2388		goto out;
2389	}
2390	if (pcb->psm == 0) {
2391		error = EADDRNOTAVAIL;
2392		goto out;
2393	}
2394	solisten_proto(so, backlog);
2395out:
2396	SOCK_UNLOCK(so);
2397	return (error);
2398} /* ng_btsocket_listen */
2399
2400/*
2401 * Get peer address
2402 */
2403
2404int
2405ng_btsocket_l2cap_peeraddr(struct socket *so, struct sockaddr **nam)
2406{
2407	ng_btsocket_l2cap_pcb_p	pcb = so2l2cap_pcb(so);
2408	struct sockaddr_l2cap	sa;
2409
2410	if (pcb == NULL)
2411		return (EINVAL);
2412	if (ng_btsocket_l2cap_node == NULL)
2413		return (EINVAL);
2414
2415	bcopy(&pcb->dst, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr));
2416	sa.l2cap_psm = htole16(pcb->psm);
2417	sa.l2cap_len = sizeof(sa);
2418	sa.l2cap_family = AF_BLUETOOTH;
2419
2420	*nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT);
2421
2422	return ((*nam == NULL)? ENOMEM : 0);
2423} /* ng_btsocket_l2cap_peeraddr */
2424
2425/*
2426 * Send data to socket
2427 */
2428
2429int
2430ng_btsocket_l2cap_send(struct socket *so, int flags, struct mbuf *m,
2431		struct sockaddr *nam, struct mbuf *control, struct thread *td)
2432{
2433	ng_btsocket_l2cap_pcb_t	*pcb = so2l2cap_pcb(so);
2434	int			 error = 0;
2435
2436	if (ng_btsocket_l2cap_node == NULL) {
2437		error = ENETDOWN;
2438		goto drop;
2439	}
2440
2441	/* Check socket and input */
2442	if (pcb == NULL || m == NULL || control != NULL) {
2443		error = EINVAL;
2444		goto drop;
2445	}
2446
2447	mtx_lock(&pcb->pcb_mtx);
2448
2449	/* Make sure socket is connected */
2450	if (pcb->state != NG_BTSOCKET_L2CAP_OPEN) {
2451		mtx_unlock(&pcb->pcb_mtx);
2452		error = ENOTCONN;
2453		goto drop;
2454	}
2455
2456	/* Check route */
2457	if (pcb->rt == NULL ||
2458	    pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook)) {
2459		mtx_unlock(&pcb->pcb_mtx);
2460		error = ENETDOWN;
2461		goto drop;
2462	}
2463
2464	/* Check packet size agains outgoing (peer's incoming) MTU) */
2465	if (m->m_pkthdr.len > pcb->omtu) {
2466		NG_BTSOCKET_L2CAP_ERR(
2467"%s: Packet too big, len=%d, omtu=%d\n", __func__, m->m_pkthdr.len, pcb->omtu);
2468
2469		mtx_unlock(&pcb->pcb_mtx);
2470		error = EMSGSIZE;
2471		goto drop;
2472	}
2473
2474	/*
2475	 * First put packet on socket send queue. Then check if we have
2476	 * pending timeout. If we do not have timeout then we must send
2477	 * packet and schedule timeout. Otherwise do nothing and wait for
2478	 * L2CA_WRITE_RSP.
2479	 */
2480
2481	sbappendrecord(&pcb->so->so_snd, m);
2482	m = NULL;
2483
2484	if (!(pcb->flags & NG_BTSOCKET_L2CAP_TIMO)) {
2485		error = ng_btsocket_l2cap_send2(pcb);
2486		if (error == 0)
2487			ng_btsocket_l2cap_timeout(pcb);
2488		else
2489			sbdroprecord(&pcb->so->so_snd); /* XXX */
2490	}
2491
2492	mtx_unlock(&pcb->pcb_mtx);
2493drop:
2494	NG_FREE_M(m); /* checks for != NULL */
2495	NG_FREE_M(control);
2496
2497	return (error);
2498} /* ng_btsocket_l2cap_send */
2499
2500/*
2501 * Send first packet in the socket queue to the L2CAP layer
2502 */
2503
2504static int
2505ng_btsocket_l2cap_send2(ng_btsocket_l2cap_pcb_p pcb)
2506{
2507	struct	mbuf		*m = NULL;
2508	ng_l2cap_l2ca_hdr_t	*hdr = NULL;
2509	int			 error = 0;
2510
2511	mtx_assert(&pcb->pcb_mtx, MA_OWNED);
2512
2513	if (pcb->so->so_snd.sb_cc == 0)
2514		return (EINVAL); /* XXX */
2515
2516	m = m_dup(pcb->so->so_snd.sb_mb, M_DONTWAIT);
2517	if (m == NULL)
2518		return (ENOBUFS);
2519
2520	/* Create L2CA packet header */
2521	M_PREPEND(m, sizeof(*hdr), M_DONTWAIT);
2522	if (m != NULL)
2523		if (m->m_len < sizeof(*hdr))
2524			m = m_pullup(m, sizeof(*hdr));
2525
2526	if (m == NULL) {
2527		NG_BTSOCKET_L2CAP_ERR(
2528"%s: Failed to create L2CA packet header\n", __func__);
2529
2530		return (ENOBUFS);
2531	}
2532
2533	hdr = mtod(m, ng_l2cap_l2ca_hdr_t *);
2534	hdr->token = pcb->token;
2535	hdr->length = m->m_pkthdr.len - sizeof(*hdr);
2536	hdr->lcid = pcb->cid;
2537
2538	NG_BTSOCKET_L2CAP_INFO(
2539"%s: Sending packet: len=%d, length=%d, lcid=%d, token=%d, state=%d\n",
2540		__func__, m->m_pkthdr.len, hdr->length, hdr->lcid,
2541		hdr->token, pcb->state);
2542
2543	/*
2544	 * If we got here than we have successfuly creates new L2CAP
2545	 * data packet and now we can send it to the L2CAP layer
2546	 */
2547
2548	NG_SEND_DATA_ONLY(error, pcb->rt->hook, m);
2549
2550	return (error);
2551} /* ng_btsocket_l2cap_send2 */
2552
2553/*
2554 * Get socket address
2555 */
2556
2557int
2558ng_btsocket_l2cap_sockaddr(struct socket *so, struct sockaddr **nam)
2559{
2560	ng_btsocket_l2cap_pcb_p	pcb = so2l2cap_pcb(so);
2561	struct sockaddr_l2cap	sa;
2562
2563	if (pcb == NULL)
2564		return (EINVAL);
2565	if (ng_btsocket_l2cap_node == NULL)
2566		return (EINVAL);
2567
2568	bcopy(&pcb->src, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr));
2569	sa.l2cap_psm = htole16(pcb->psm);
2570	sa.l2cap_len = sizeof(sa);
2571	sa.l2cap_family = AF_BLUETOOTH;
2572
2573	*nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT);
2574
2575	return ((*nam == NULL)? ENOMEM : 0);
2576} /* ng_btsocket_l2cap_sockaddr */
2577
2578/*****************************************************************************
2579 *****************************************************************************
2580 **                              Misc. functions
2581 *****************************************************************************
2582 *****************************************************************************/
2583
2584/*
2585 * Look for the socket that listens on given PSM and bdaddr. Returns exact or
2586 * close match (if any). Caller must hold ng_btsocket_l2cap_sockets_mtx.
2587 */
2588
2589static ng_btsocket_l2cap_pcb_p
2590ng_btsocket_l2cap_pcb_by_addr(bdaddr_p bdaddr, int psm)
2591{
2592	ng_btsocket_l2cap_pcb_p	p = NULL, p1 = NULL;
2593
2594	mtx_assert(&ng_btsocket_l2cap_sockets_mtx, MA_OWNED);
2595
2596	LIST_FOREACH(p, &ng_btsocket_l2cap_sockets, next) {
2597		if (p->so == NULL || !(p->so->so_options & SO_ACCEPTCONN) ||
2598		    p->psm != psm)
2599			continue;
2600
2601		if (bcmp(&p->src, bdaddr, sizeof(p->src)) == 0)
2602			break;
2603
2604		if (bcmp(&p->src, NG_HCI_BDADDR_ANY, sizeof(p->src)) == 0)
2605			p1 = p;
2606	}
2607
2608	return ((p != NULL)? p : p1);
2609} /* ng_btsocket_l2cap_pcb_by_addr */
2610
2611/*
2612 * Look for the socket that has given token.
2613 * Caller must hold ng_btsocket_l2cap_sockets_mtx.
2614 */
2615
2616static ng_btsocket_l2cap_pcb_p
2617ng_btsocket_l2cap_pcb_by_token(u_int32_t token)
2618{
2619	ng_btsocket_l2cap_pcb_p	p = NULL;
2620
2621	if (token == 0)
2622		return (NULL);
2623
2624	mtx_assert(&ng_btsocket_l2cap_sockets_mtx, MA_OWNED);
2625
2626	LIST_FOREACH(p, &ng_btsocket_l2cap_sockets, next)
2627		if (p->token == token)
2628			break;
2629
2630	return (p);
2631} /* ng_btsocket_l2cap_pcb_by_token */
2632
2633/*
2634 * Look for the socket that assigned to given source address and channel ID.
2635 * Caller must hold ng_btsocket_l2cap_sockets_mtx
2636 */
2637
2638static ng_btsocket_l2cap_pcb_p
2639ng_btsocket_l2cap_pcb_by_cid(bdaddr_p src, int cid)
2640{
2641	ng_btsocket_l2cap_pcb_p	p = NULL;
2642
2643	mtx_assert(&ng_btsocket_l2cap_sockets_mtx, MA_OWNED);
2644
2645	LIST_FOREACH(p, &ng_btsocket_l2cap_sockets, next)
2646		if (p->cid == cid && bcmp(src, &p->src, sizeof(p->src)) == 0)
2647			break;
2648
2649	return (p);
2650} /* ng_btsocket_l2cap_pcb_by_cid */
2651
2652/*
2653 * Set timeout on socket
2654 */
2655
2656static void
2657ng_btsocket_l2cap_timeout(ng_btsocket_l2cap_pcb_p pcb)
2658{
2659	mtx_assert(&pcb->pcb_mtx, MA_OWNED);
2660
2661	if (!(pcb->flags & NG_BTSOCKET_L2CAP_TIMO)) {
2662		pcb->flags |= NG_BTSOCKET_L2CAP_TIMO;
2663		pcb->timo = timeout(ng_btsocket_l2cap_process_timeout, pcb,
2664					bluetooth_l2cap_ertx_timeout());
2665	} else
2666		KASSERT(0,
2667("%s: Duplicated socket timeout?!\n", __func__));
2668} /* ng_btsocket_l2cap_timeout */
2669
2670/*
2671 * Unset timeout on socket
2672 */
2673
2674static void
2675ng_btsocket_l2cap_untimeout(ng_btsocket_l2cap_pcb_p pcb)
2676{
2677	mtx_assert(&pcb->pcb_mtx, MA_OWNED);
2678
2679	if (pcb->flags & NG_BTSOCKET_L2CAP_TIMO) {
2680		untimeout(ng_btsocket_l2cap_process_timeout, pcb, pcb->timo);
2681		pcb->flags &= ~NG_BTSOCKET_L2CAP_TIMO;
2682	} else
2683		KASSERT(0,
2684("%s: No socket timeout?!\n", __func__));
2685} /* ng_btsocket_l2cap_untimeout */
2686
2687/*
2688 * Process timeout on socket
2689 */
2690
2691static void
2692ng_btsocket_l2cap_process_timeout(void *xpcb)
2693{
2694	ng_btsocket_l2cap_pcb_p	pcb = (ng_btsocket_l2cap_pcb_p) xpcb;
2695
2696	mtx_lock(&pcb->pcb_mtx);
2697
2698	pcb->flags &= ~NG_BTSOCKET_L2CAP_TIMO;
2699	pcb->so->so_error = ETIMEDOUT;
2700
2701	switch (pcb->state) {
2702	case NG_BTSOCKET_L2CAP_CONNECTING:
2703	case NG_BTSOCKET_L2CAP_CONFIGURING:
2704		/* Send disconnect request with "zero" token */
2705		if (pcb->cid != 0)
2706			ng_btsocket_l2cap_send_l2ca_discon_req(0, pcb);
2707
2708		/* ... and close the socket */
2709		pcb->state = NG_BTSOCKET_L2CAP_CLOSED;
2710		soisdisconnected(pcb->so);
2711		break;
2712
2713	case NG_BTSOCKET_L2CAP_OPEN:
2714		/* Send timeout - drop packet and wakeup sender */
2715		sbdroprecord(&pcb->so->so_snd);
2716		sowwakeup(pcb->so);
2717		break;
2718
2719	case NG_BTSOCKET_L2CAP_DISCONNECTING:
2720		/* Disconnect timeout - disconnect the socket anyway */
2721		pcb->state = NG_BTSOCKET_L2CAP_CLOSED;
2722		soisdisconnected(pcb->so);
2723		break;
2724
2725	default:
2726		NG_BTSOCKET_L2CAP_ERR(
2727"%s: Invalid socket state=%d\n", __func__, pcb->state);
2728		break;
2729	}
2730
2731	mtx_unlock(&pcb->pcb_mtx);
2732} /* ng_btsocket_l2cap_process_timeout */
2733
2734/*
2735 * Translate HCI/L2CAP error code into "errno" code
2736 * XXX Note: Some L2CAP and HCI error codes have the same value, but
2737 *     different meaning
2738 */
2739
2740static int
2741ng_btsocket_l2cap_result2errno(int result)
2742{
2743	switch (result) {
2744	case 0x00: /* No error */
2745		return (0);
2746
2747	case 0x01: /* Unknown HCI command */
2748		return (ENODEV);
2749
2750	case 0x02: /* No connection */
2751		return (ENOTCONN);
2752
2753	case 0x03: /* Hardware failure */
2754		return (EIO);
2755
2756	case 0x04: /* Page timeout */
2757		return (EHOSTDOWN);
2758
2759	case 0x05: /* Authentication failure */
2760	case 0x06: /* Key missing */
2761	case 0x18: /* Pairing not allowed */
2762	case 0x21: /* Role change not allowed */
2763	case 0x24: /* LMP PSU not allowed */
2764	case 0x25: /* Encryption mode not acceptable */
2765	case 0x26: /* Unit key used */
2766		return (EACCES);
2767
2768	case 0x07: /* Memory full */
2769		return (ENOMEM);
2770
2771	case 0x08:   /* Connection timeout */
2772	case 0x10:   /* Host timeout */
2773	case 0x22:   /* LMP response timeout */
2774	case 0xee:   /* HCI timeout */
2775	case 0xeeee: /* L2CAP timeout */
2776		return (ETIMEDOUT);
2777
2778	case 0x09: /* Max number of connections */
2779	case 0x0a: /* Max number of SCO connections to a unit */
2780		return (EMLINK);
2781
2782	case 0x0b: /* ACL connection already exists */
2783		return (EEXIST);
2784
2785	case 0x0c: /* Command disallowed */
2786		return (EBUSY);
2787
2788	case 0x0d: /* Host rejected due to limited resources */
2789	case 0x0e: /* Host rejected due to securiity reasons */
2790	case 0x0f: /* Host rejected due to remote unit is a personal unit */
2791	case 0x1b: /* SCO offset rejected */
2792	case 0x1c: /* SCO interval rejected */
2793	case 0x1d: /* SCO air mode rejected */
2794		return (ECONNREFUSED);
2795
2796	case 0x11: /* Unsupported feature or parameter value */
2797	case 0x19: /* Unknown LMP PDU */
2798	case 0x1a: /* Unsupported remote feature */
2799	case 0x20: /* Unsupported LMP parameter value */
2800	case 0x27: /* QoS is not supported */
2801	case 0x29: /* Paring with unit key not supported */
2802		return (EOPNOTSUPP);
2803
2804	case 0x12: /* Invalid HCI command parameter */
2805	case 0x1e: /* Invalid LMP parameters */
2806		return (EINVAL);
2807
2808	case 0x13: /* Other end terminated connection: User ended connection */
2809	case 0x14: /* Other end terminated connection: Low resources */
2810	case 0x15: /* Other end terminated connection: About to power off */
2811		return (ECONNRESET);
2812
2813	case 0x16: /* Connection terminated by local host */
2814		return (ECONNABORTED);
2815
2816#if 0 /* XXX not yet */
2817	case 0x17: /* Repeated attempts */
2818	case 0x1f: /* Unspecified error */
2819	case 0x23: /* LMP error transaction collision */
2820	case 0x28: /* Instant passed */
2821#endif
2822	}
2823
2824	return (ENOSYS);
2825} /* ng_btsocket_l2cap_result2errno */
2826
2827