xref: /freebsd/sys/netgraph/bluetooth/socket/ng_btsocket_sco.c (revision ff0ba87247820afbdfdc1b307c803f7923d0e4d3)
1 /*
2  * ng_btsocket_sco.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_sco.c,v 1.2 2005/10/31 18:08:51 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_sco.h>
63 
64 /* MALLOC define */
65 #ifdef NG_SEPARATE_MALLOC
66 static MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_SCO, "netgraph_btsocks_sco",
67 		"Netgraph Bluetooth SCO sockets");
68 #else
69 #define M_NETGRAPH_BTSOCKET_SCO M_NETGRAPH
70 #endif /* NG_SEPARATE_MALLOC */
71 
72 /* Netgraph node methods */
73 static ng_constructor_t	ng_btsocket_sco_node_constructor;
74 static ng_rcvmsg_t	ng_btsocket_sco_node_rcvmsg;
75 static ng_shutdown_t	ng_btsocket_sco_node_shutdown;
76 static ng_newhook_t	ng_btsocket_sco_node_newhook;
77 static ng_connect_t	ng_btsocket_sco_node_connect;
78 static ng_rcvdata_t	ng_btsocket_sco_node_rcvdata;
79 static ng_disconnect_t	ng_btsocket_sco_node_disconnect;
80 
81 static void		ng_btsocket_sco_input   (void *, int);
82 static void		ng_btsocket_sco_rtclean (void *, int);
83 
84 /* Netgraph type descriptor */
85 static struct ng_type	typestruct = {
86 	.version =	NG_ABI_VERSION,
87 	.name =		NG_BTSOCKET_SCO_NODE_TYPE,
88 	.constructor =	ng_btsocket_sco_node_constructor,
89 	.rcvmsg =	ng_btsocket_sco_node_rcvmsg,
90 	.shutdown =	ng_btsocket_sco_node_shutdown,
91 	.newhook =	ng_btsocket_sco_node_newhook,
92 	.connect =	ng_btsocket_sco_node_connect,
93 	.rcvdata =	ng_btsocket_sco_node_rcvdata,
94 	.disconnect =	ng_btsocket_sco_node_disconnect,
95 };
96 
97 /* Globals */
98 static u_int32_t				ng_btsocket_sco_debug_level;
99 static node_p					ng_btsocket_sco_node;
100 static struct ng_bt_itemq			ng_btsocket_sco_queue;
101 static struct mtx				ng_btsocket_sco_queue_mtx;
102 static struct task				ng_btsocket_sco_queue_task;
103 static struct mtx				ng_btsocket_sco_sockets_mtx;
104 static LIST_HEAD(, ng_btsocket_sco_pcb)		ng_btsocket_sco_sockets;
105 static LIST_HEAD(, ng_btsocket_sco_rtentry)	ng_btsocket_sco_rt;
106 static struct mtx				ng_btsocket_sco_rt_mtx;
107 static struct task				ng_btsocket_sco_rt_task;
108 static struct timeval				ng_btsocket_sco_lasttime;
109 static int					ng_btsocket_sco_curpps;
110 
111 /* Sysctl tree */
112 SYSCTL_DECL(_net_bluetooth_sco_sockets);
113 static SYSCTL_NODE(_net_bluetooth_sco_sockets, OID_AUTO, seq, CTLFLAG_RW,
114 	0, "Bluetooth SEQPACKET SCO sockets family");
115 SYSCTL_UINT(_net_bluetooth_sco_sockets_seq, OID_AUTO, debug_level,
116 	CTLFLAG_RW,
117 	&ng_btsocket_sco_debug_level, NG_BTSOCKET_WARN_LEVEL,
118 	"Bluetooth SEQPACKET SCO sockets debug level");
119 SYSCTL_UINT(_net_bluetooth_sco_sockets_seq, OID_AUTO, queue_len,
120 	CTLFLAG_RD,
121 	&ng_btsocket_sco_queue.len, 0,
122 	"Bluetooth SEQPACKET SCO sockets input queue length");
123 SYSCTL_UINT(_net_bluetooth_sco_sockets_seq, OID_AUTO, queue_maxlen,
124 	CTLFLAG_RD,
125 	&ng_btsocket_sco_queue.maxlen, 0,
126 	"Bluetooth SEQPACKET SCO sockets input queue max. length");
127 SYSCTL_UINT(_net_bluetooth_sco_sockets_seq, OID_AUTO, queue_drops,
128 	CTLFLAG_RD,
129 	&ng_btsocket_sco_queue.drops, 0,
130 	"Bluetooth SEQPACKET SCO sockets input queue drops");
131 
132 /* Debug */
133 #define NG_BTSOCKET_SCO_INFO \
134 	if (ng_btsocket_sco_debug_level >= NG_BTSOCKET_INFO_LEVEL && \
135 	    ppsratecheck(&ng_btsocket_sco_lasttime, &ng_btsocket_sco_curpps, 1)) \
136 		printf
137 
138 #define NG_BTSOCKET_SCO_WARN \
139 	if (ng_btsocket_sco_debug_level >= NG_BTSOCKET_WARN_LEVEL && \
140 	    ppsratecheck(&ng_btsocket_sco_lasttime, &ng_btsocket_sco_curpps, 1)) \
141 		printf
142 
143 #define NG_BTSOCKET_SCO_ERR \
144 	if (ng_btsocket_sco_debug_level >= NG_BTSOCKET_ERR_LEVEL && \
145 	    ppsratecheck(&ng_btsocket_sco_lasttime, &ng_btsocket_sco_curpps, 1)) \
146 		printf
147 
148 #define NG_BTSOCKET_SCO_ALERT \
149 	if (ng_btsocket_sco_debug_level >= NG_BTSOCKET_ALERT_LEVEL && \
150 	    ppsratecheck(&ng_btsocket_sco_lasttime, &ng_btsocket_sco_curpps, 1)) \
151 		printf
152 
153 /*
154  * Netgraph message processing routines
155  */
156 
157 static int ng_btsocket_sco_process_lp_con_cfm
158 	(struct ng_mesg *, ng_btsocket_sco_rtentry_p);
159 static int ng_btsocket_sco_process_lp_con_ind
160 	(struct ng_mesg *, ng_btsocket_sco_rtentry_p);
161 static int ng_btsocket_sco_process_lp_discon_ind
162 	(struct ng_mesg *, ng_btsocket_sco_rtentry_p);
163 
164 /*
165  * Send LP messages to the lower layer
166  */
167 
168 static int  ng_btsocket_sco_send_lp_con_req
169 	(ng_btsocket_sco_pcb_p);
170 static int  ng_btsocket_sco_send_lp_con_rsp
171 	(ng_btsocket_sco_rtentry_p, bdaddr_p, int);
172 static int  ng_btsocket_sco_send_lp_discon_req
173 	(ng_btsocket_sco_pcb_p);
174 
175 static int ng_btsocket_sco_send2
176 	(ng_btsocket_sco_pcb_p);
177 
178 /*
179  * Timeout processing routines
180  */
181 
182 static void ng_btsocket_sco_timeout         (ng_btsocket_sco_pcb_p);
183 static void ng_btsocket_sco_untimeout       (ng_btsocket_sco_pcb_p);
184 static void ng_btsocket_sco_process_timeout (void *);
185 
186 /*
187  * Other stuff
188  */
189 
190 static ng_btsocket_sco_pcb_p	ng_btsocket_sco_pcb_by_addr(bdaddr_p);
191 static ng_btsocket_sco_pcb_p	ng_btsocket_sco_pcb_by_handle(bdaddr_p, int);
192 static ng_btsocket_sco_pcb_p	ng_btsocket_sco_pcb_by_addrs(bdaddr_p, bdaddr_p);
193 
194 #define ng_btsocket_sco_wakeup_input_task() \
195 	taskqueue_enqueue(taskqueue_swi, &ng_btsocket_sco_queue_task)
196 
197 #define ng_btsocket_sco_wakeup_route_task() \
198 	taskqueue_enqueue(taskqueue_swi, &ng_btsocket_sco_rt_task)
199 
200 /*****************************************************************************
201  *****************************************************************************
202  **                        Netgraph node interface
203  *****************************************************************************
204  *****************************************************************************/
205 
206 /*
207  * Netgraph node constructor. Do not allow to create node of this type.
208  */
209 
210 static int
211 ng_btsocket_sco_node_constructor(node_p node)
212 {
213 	return (EINVAL);
214 } /* ng_btsocket_sco_node_constructor */
215 
216 /*
217  * Do local shutdown processing. Let old node go and create new fresh one.
218  */
219 
220 static int
221 ng_btsocket_sco_node_shutdown(node_p node)
222 {
223 	int	error = 0;
224 
225 	NG_NODE_UNREF(node);
226 
227 	/* Create new node */
228 	error = ng_make_node_common(&typestruct, &ng_btsocket_sco_node);
229 	if (error != 0) {
230 		NG_BTSOCKET_SCO_ALERT(
231 "%s: Could not create Netgraph node, error=%d\n", __func__, error);
232 
233 		ng_btsocket_sco_node = NULL;
234 
235 		return (error);
236 	}
237 
238 	error = ng_name_node(ng_btsocket_sco_node,
239 				NG_BTSOCKET_SCO_NODE_TYPE);
240 	if (error != 0) {
241 		NG_BTSOCKET_SCO_ALERT(
242 "%s: Could not name Netgraph node, error=%d\n", __func__, error);
243 
244 		NG_NODE_UNREF(ng_btsocket_sco_node);
245 		ng_btsocket_sco_node = NULL;
246 
247 		return (error);
248 	}
249 
250 	return (0);
251 } /* ng_btsocket_sco_node_shutdown */
252 
253 /*
254  * We allow any hook to be connected to the node.
255  */
256 
257 static int
258 ng_btsocket_sco_node_newhook(node_p node, hook_p hook, char const *name)
259 {
260 	return (0);
261 } /* ng_btsocket_sco_node_newhook */
262 
263 /*
264  * Just say "YEP, that's OK by me!"
265  */
266 
267 static int
268 ng_btsocket_sco_node_connect(hook_p hook)
269 {
270 	NG_HOOK_SET_PRIVATE(hook, NULL);
271 	NG_HOOK_REF(hook); /* Keep extra reference to the hook */
272 
273 #if 0
274 	NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
275 	NG_HOOK_FORCE_QUEUE(hook);
276 #endif
277 
278 	return (0);
279 } /* ng_btsocket_sco_node_connect */
280 
281 /*
282  * Hook disconnection. Schedule route cleanup task
283  */
284 
285 static int
286 ng_btsocket_sco_node_disconnect(hook_p hook)
287 {
288 	/*
289 	 * If hook has private information than we must have this hook in
290 	 * the routing table and must schedule cleaning for the routing table.
291 	 * Otherwise hook was connected but we never got "hook_info" message,
292 	 * so we have never added this hook to the routing table and it save
293 	 * to just delete it.
294 	 */
295 
296 	if (NG_HOOK_PRIVATE(hook) != NULL)
297 		return (ng_btsocket_sco_wakeup_route_task());
298 
299 	NG_HOOK_UNREF(hook); /* Remove extra reference */
300 
301 	return (0);
302 } /* ng_btsocket_sco_node_disconnect */
303 
304 /*
305  * Process incoming messages
306  */
307 
308 static int
309 ng_btsocket_sco_node_rcvmsg(node_p node, item_p item, hook_p hook)
310 {
311 	struct ng_mesg	*msg = NGI_MSG(item); /* item still has message */
312 	int		 error = 0;
313 
314 	if (msg != NULL && msg->header.typecookie == NGM_HCI_COOKIE) {
315 		mtx_lock(&ng_btsocket_sco_queue_mtx);
316 		if (NG_BT_ITEMQ_FULL(&ng_btsocket_sco_queue)) {
317 			NG_BTSOCKET_SCO_ERR(
318 "%s: Input queue is full (msg)\n", __func__);
319 
320 			NG_BT_ITEMQ_DROP(&ng_btsocket_sco_queue);
321 			NG_FREE_ITEM(item);
322 			error = ENOBUFS;
323 		} else {
324 			if (hook != NULL) {
325 				NG_HOOK_REF(hook);
326 				NGI_SET_HOOK(item, hook);
327 			}
328 
329 			NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_sco_queue, item);
330 			error = ng_btsocket_sco_wakeup_input_task();
331 		}
332 		mtx_unlock(&ng_btsocket_sco_queue_mtx);
333 	} else {
334 		NG_FREE_ITEM(item);
335 		error = EINVAL;
336 	}
337 
338 	return (error);
339 } /* ng_btsocket_sco_node_rcvmsg */
340 
341 /*
342  * Receive data on a hook
343  */
344 
345 static int
346 ng_btsocket_sco_node_rcvdata(hook_p hook, item_p item)
347 {
348 	int	error = 0;
349 
350 	mtx_lock(&ng_btsocket_sco_queue_mtx);
351 	if (NG_BT_ITEMQ_FULL(&ng_btsocket_sco_queue)) {
352 		NG_BTSOCKET_SCO_ERR(
353 "%s: Input queue is full (data)\n", __func__);
354 
355 		NG_BT_ITEMQ_DROP(&ng_btsocket_sco_queue);
356 		NG_FREE_ITEM(item);
357 		error = ENOBUFS;
358 	} else {
359 		NG_HOOK_REF(hook);
360 		NGI_SET_HOOK(item, hook);
361 
362 		NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_sco_queue, item);
363 		error = ng_btsocket_sco_wakeup_input_task();
364 	}
365 	mtx_unlock(&ng_btsocket_sco_queue_mtx);
366 
367 	return (error);
368 } /* ng_btsocket_sco_node_rcvdata */
369 
370 /*
371  * Process LP_ConnectCfm event from the lower layer protocol
372  */
373 
374 static int
375 ng_btsocket_sco_process_lp_con_cfm(struct ng_mesg *msg,
376 		ng_btsocket_sco_rtentry_p rt)
377 {
378 	ng_hci_lp_con_cfm_ep	*ep = NULL;
379 	ng_btsocket_sco_pcb_t	*pcb = NULL;
380 	int			 error = 0;
381 
382 	if (msg->header.arglen != sizeof(*ep))
383 		return (EMSGSIZE);
384 
385 	ep = (ng_hci_lp_con_cfm_ep *)(msg->data);
386 
387 	mtx_lock(&ng_btsocket_sco_sockets_mtx);
388 
389 	/* Look for the socket with the token */
390 	pcb = ng_btsocket_sco_pcb_by_addrs(&rt->src, &ep->bdaddr);
391 	if (pcb == NULL) {
392 		mtx_unlock(&ng_btsocket_sco_sockets_mtx);
393 		return (ENOENT);
394 	}
395 
396 	/* pcb is locked */
397 
398 	NG_BTSOCKET_SCO_INFO(
399 "%s: Got LP_ConnectCfm response, src bdaddr=%x:%x:%x:%x:%x:%x, " \
400 "dst bdaddr=%x:%x:%x:%x:%x:%x, status=%d, handle=%d, state=%d\n",
401 		__func__,
402 		pcb->src.b[5], pcb->src.b[4], pcb->src.b[3],
403 		pcb->src.b[2], pcb->src.b[1], pcb->src.b[0],
404 		pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3],
405 		pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0],
406 		ep->status, ep->con_handle, pcb->state);
407 
408 	if (pcb->state != NG_BTSOCKET_SCO_CONNECTING) {
409 		mtx_unlock(&pcb->pcb_mtx);
410 		mtx_unlock(&ng_btsocket_sco_sockets_mtx);
411 
412 		return (ENOENT);
413 	}
414 
415 	ng_btsocket_sco_untimeout(pcb);
416 
417 	if (ep->status == 0) {
418 		/*
419 		 * Connection is open. Update connection handle and
420 		 * socket state
421 		 */
422 
423 		pcb->con_handle = ep->con_handle;
424 		pcb->state = NG_BTSOCKET_SCO_OPEN;
425 		soisconnected(pcb->so);
426 	} else {
427 		/*
428 		 * We have failed to open connection, so disconnect the socket
429 		 */
430 
431 		pcb->so->so_error = ECONNREFUSED; /* XXX convert status ??? */
432 		pcb->state = NG_BTSOCKET_SCO_CLOSED;
433 		soisdisconnected(pcb->so);
434 	}
435 
436 	mtx_unlock(&pcb->pcb_mtx);
437 	mtx_unlock(&ng_btsocket_sco_sockets_mtx);
438 
439 	return (error);
440 } /* ng_btsocket_sco_process_lp_con_cfm */
441 
442 /*
443  * Process LP_ConnectInd indicator. Find socket that listens on address.
444  * Find exact or closest match.
445  */
446 
447 static int
448 ng_btsocket_sco_process_lp_con_ind(struct ng_mesg *msg,
449 		ng_btsocket_sco_rtentry_p rt)
450 {
451 	ng_hci_lp_con_ind_ep	*ep = NULL;
452 	ng_btsocket_sco_pcb_t	*pcb = NULL, *pcb1 = NULL;
453 	int			 error = 0;
454 	u_int16_t		 status = 0;
455 
456 	if (msg->header.arglen != sizeof(*ep))
457 		return (EMSGSIZE);
458 
459 	ep = (ng_hci_lp_con_ind_ep *)(msg->data);
460 
461 	NG_BTSOCKET_SCO_INFO(
462 "%s: Got LP_ConnectInd indicator, src bdaddr=%x:%x:%x:%x:%x:%x, " \
463 "dst bdaddr=%x:%x:%x:%x:%x:%x\n",
464 		__func__,
465 		rt->src.b[5], rt->src.b[4], rt->src.b[3],
466 		rt->src.b[2], rt->src.b[1], rt->src.b[0],
467 		ep->bdaddr.b[5], ep->bdaddr.b[4], ep->bdaddr.b[3],
468 		ep->bdaddr.b[2], ep->bdaddr.b[1], ep->bdaddr.b[0]);
469 
470 	mtx_lock(&ng_btsocket_sco_sockets_mtx);
471 
472 	pcb = ng_btsocket_sco_pcb_by_addr(&rt->src);
473 	if (pcb != NULL) {
474 		struct socket	*so1 = NULL;
475 
476 		/* pcb is locked */
477 
478 		/*
479 		 * First check the pending connections queue and if we have
480 		 * space then create new socket and set proper source address.
481 		 */
482 
483 		if (pcb->so->so_qlen <= pcb->so->so_qlimit) {
484 			CURVNET_SET(pcb->so->so_vnet);
485 			so1 = sonewconn(pcb->so, 0);
486 			CURVNET_RESTORE();
487 		}
488 
489 		if (so1 == NULL) {
490 			status = 0x0d; /* Rejected due to limited resources */
491 			goto respond;
492 		}
493 
494 		/*
495 		 * If we got here than we have created new socket. So complete
496 		 * connection. If we we listening on specific address then copy
497 		 * source address from listening socket, otherwise copy source
498 		 * address from hook's routing information.
499 		 */
500 
501 		pcb1 = so2sco_pcb(so1);
502 		KASSERT((pcb1 != NULL),
503 ("%s: pcb1 == NULL\n", __func__));
504 
505  		mtx_lock(&pcb1->pcb_mtx);
506 
507 		if (bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(pcb->src)) != 0)
508 			bcopy(&pcb->src, &pcb1->src, sizeof(pcb1->src));
509 		else
510 			bcopy(&rt->src, &pcb1->src, sizeof(pcb1->src));
511 
512 		pcb1->flags &= ~NG_BTSOCKET_SCO_CLIENT;
513 
514 		bcopy(&ep->bdaddr, &pcb1->dst, sizeof(pcb1->dst));
515 		pcb1->rt = rt;
516 	} else
517 		/* Nobody listens on requested BDADDR */
518 		status = 0x1f; /* Unspecified Error */
519 
520 respond:
521 	error = ng_btsocket_sco_send_lp_con_rsp(rt, &ep->bdaddr, status);
522 	if (pcb1 != NULL) {
523 		if (error != 0) {
524 			pcb1->so->so_error = error;
525 			pcb1->state = NG_BTSOCKET_SCO_CLOSED;
526 			soisdisconnected(pcb1->so);
527 		} else {
528 			pcb1->state = NG_BTSOCKET_SCO_CONNECTING;
529 			soisconnecting(pcb1->so);
530 
531 			ng_btsocket_sco_timeout(pcb1);
532 		}
533 
534 		mtx_unlock(&pcb1->pcb_mtx);
535 	}
536 
537 	if (pcb != NULL)
538 		mtx_unlock(&pcb->pcb_mtx);
539 
540 	mtx_unlock(&ng_btsocket_sco_sockets_mtx);
541 
542 	return (error);
543 } /* ng_btsocket_sco_process_lp_con_ind */
544 
545 /*
546  * Process LP_DisconnectInd indicator
547  */
548 
549 static int
550 ng_btsocket_sco_process_lp_discon_ind(struct ng_mesg *msg,
551 		ng_btsocket_sco_rtentry_p rt)
552 {
553 	ng_hci_lp_discon_ind_ep	*ep = NULL;
554 	ng_btsocket_sco_pcb_t	*pcb = NULL;
555 
556 	/* Check message */
557 	if (msg->header.arglen != sizeof(*ep))
558 		return (EMSGSIZE);
559 
560 	ep = (ng_hci_lp_discon_ind_ep *)(msg->data);
561 
562 	mtx_lock(&ng_btsocket_sco_sockets_mtx);
563 
564 	/* Look for the socket with given channel ID */
565 	pcb = ng_btsocket_sco_pcb_by_handle(&rt->src, ep->con_handle);
566 	if (pcb == NULL) {
567 		mtx_unlock(&ng_btsocket_sco_sockets_mtx);
568 		return (0);
569 	}
570 
571 	/*
572 	 * Disconnect the socket. If there was any pending request we can
573 	 * not do anything here anyway.
574 	 */
575 
576 	/* pcb is locked */
577 
578        	NG_BTSOCKET_SCO_INFO(
579 "%s: Got LP_DisconnectInd indicator, src bdaddr=%x:%x:%x:%x:%x:%x, " \
580 "dst bdaddr=%x:%x:%x:%x:%x:%x, handle=%d, state=%d\n",
581 		__func__,
582 		pcb->src.b[5], pcb->src.b[4], pcb->src.b[3],
583 		pcb->src.b[2], pcb->src.b[1], pcb->src.b[0],
584 		pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3],
585 		pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0],
586 		pcb->con_handle, pcb->state);
587 
588 	if (pcb->flags & NG_BTSOCKET_SCO_TIMO)
589 		ng_btsocket_sco_untimeout(pcb);
590 
591 	pcb->state = NG_BTSOCKET_SCO_CLOSED;
592 	soisdisconnected(pcb->so);
593 
594 	mtx_unlock(&pcb->pcb_mtx);
595 	mtx_unlock(&ng_btsocket_sco_sockets_mtx);
596 
597 	return (0);
598 } /* ng_btsocket_sco_process_lp_discon_ind */
599 
600 /*
601  * Send LP_ConnectReq request
602  */
603 
604 static int
605 ng_btsocket_sco_send_lp_con_req(ng_btsocket_sco_pcb_p pcb)
606 {
607 	struct ng_mesg		*msg = NULL;
608 	ng_hci_lp_con_req_ep	*ep = NULL;
609 	int			 error = 0;
610 
611 	mtx_assert(&pcb->pcb_mtx, MA_OWNED);
612 
613 	if (pcb->rt == NULL ||
614 	    pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook))
615 		return (ENETDOWN);
616 
617 	NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_REQ,
618 		sizeof(*ep), M_NOWAIT);
619 	if (msg == NULL)
620 		return (ENOMEM);
621 
622 	ep = (ng_hci_lp_con_req_ep *)(msg->data);
623 	ep->link_type = NG_HCI_LINK_SCO;
624 	bcopy(&pcb->dst, &ep->bdaddr, sizeof(ep->bdaddr));
625 
626 	NG_SEND_MSG_HOOK(error, ng_btsocket_sco_node, msg, pcb->rt->hook, 0);
627 
628 	return (error);
629 } /* ng_btsocket_sco_send_lp_con_req */
630 
631 /*
632  * Send LP_ConnectRsp response
633  */
634 
635 static int
636 ng_btsocket_sco_send_lp_con_rsp(ng_btsocket_sco_rtentry_p rt, bdaddr_p dst, int status)
637 {
638 	struct ng_mesg		*msg = NULL;
639 	ng_hci_lp_con_rsp_ep	*ep = NULL;
640 	int			 error = 0;
641 
642 	if (rt == NULL || rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
643 		return (ENETDOWN);
644 
645 	NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_RSP,
646 		sizeof(*ep), M_NOWAIT);
647 	if (msg == NULL)
648 		return (ENOMEM);
649 
650 	ep = (ng_hci_lp_con_rsp_ep *)(msg->data);
651 	ep->status = status;
652 	ep->link_type = NG_HCI_LINK_SCO;
653 	bcopy(dst, &ep->bdaddr, sizeof(ep->bdaddr));
654 
655 	NG_SEND_MSG_HOOK(error, ng_btsocket_sco_node, msg, rt->hook, 0);
656 
657 	return (error);
658 } /* ng_btsocket_sco_send_lp_con_rsp */
659 
660 /*
661  * Send LP_DisconReq request
662  */
663 
664 static int
665 ng_btsocket_sco_send_lp_discon_req(ng_btsocket_sco_pcb_p pcb)
666 {
667 	struct ng_mesg		*msg = NULL;
668 	ng_hci_lp_discon_req_ep	*ep = NULL;
669 	int			 error = 0;
670 
671 	mtx_assert(&pcb->pcb_mtx, MA_OWNED);
672 
673 	if (pcb->rt == NULL ||
674 	    pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook))
675 		return (ENETDOWN);
676 
677 	NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_DISCON_REQ,
678 		sizeof(*ep), M_NOWAIT);
679 	if (msg == NULL)
680 		return (ENOMEM);
681 
682 	ep = (ng_hci_lp_discon_req_ep *)(msg->data);
683 	ep->con_handle = pcb->con_handle;
684 	ep->reason = 0x13; /* User Ended Connection */
685 
686 	NG_SEND_MSG_HOOK(error, ng_btsocket_sco_node, msg, pcb->rt->hook, 0);
687 
688 	return (error);
689 } /* ng_btsocket_sco_send_lp_discon_req */
690 
691 /*****************************************************************************
692  *****************************************************************************
693  **                              Socket interface
694  *****************************************************************************
695  *****************************************************************************/
696 
697 /*
698  * SCO sockets data input routine
699  */
700 
701 static void
702 ng_btsocket_sco_data_input(struct mbuf *m, hook_p hook)
703 {
704 	ng_hci_scodata_pkt_t		*hdr = NULL;
705 	ng_btsocket_sco_pcb_t		*pcb = NULL;
706 	ng_btsocket_sco_rtentry_t	*rt = NULL;
707 	u_int16_t			 con_handle;
708 
709 	if (hook == NULL) {
710 		NG_BTSOCKET_SCO_ALERT(
711 "%s: Invalid source hook for SCO data packet\n", __func__);
712 		goto drop;
713 	}
714 
715 	rt = (ng_btsocket_sco_rtentry_t *) NG_HOOK_PRIVATE(hook);
716 	if (rt == NULL) {
717 		NG_BTSOCKET_SCO_ALERT(
718 "%s: Could not find out source bdaddr for SCO data packet\n", __func__);
719 		goto drop;
720 	}
721 
722 	/* Make sure we can access header */
723 	if (m->m_pkthdr.len < sizeof(*hdr)) {
724 		NG_BTSOCKET_SCO_ERR(
725 "%s: SCO data packet too small, len=%d\n", __func__, m->m_pkthdr.len);
726 		goto drop;
727 	}
728 
729 	if (m->m_len < sizeof(*hdr)) {
730 		m = m_pullup(m, sizeof(*hdr));
731 		if (m == NULL)
732 			goto drop;
733 	}
734 
735 	/* Strip SCO packet header and verify packet length */
736 	hdr = mtod(m, ng_hci_scodata_pkt_t *);
737 	m_adj(m, sizeof(*hdr));
738 
739 	if (hdr->length != m->m_pkthdr.len) {
740 		NG_BTSOCKET_SCO_ERR(
741 "%s: Bad SCO data packet length, len=%d, length=%d\n",
742 			__func__, m->m_pkthdr.len, hdr->length);
743 		goto drop;
744 	}
745 
746 	/*
747 	 * Now process packet
748 	 */
749 
750 	con_handle = NG_HCI_CON_HANDLE(le16toh(hdr->con_handle));
751 
752 	NG_BTSOCKET_SCO_INFO(
753 "%s: Received SCO data packet: src bdaddr=%x:%x:%x:%x:%x:%x, handle=%d, " \
754 "length=%d\n",	__func__,
755 		rt->src.b[5], rt->src.b[4], rt->src.b[3],
756 		rt->src.b[2], rt->src.b[1], rt->src.b[0],
757 		con_handle, hdr->length);
758 
759 	mtx_lock(&ng_btsocket_sco_sockets_mtx);
760 
761 	/* Find socket */
762 	pcb = ng_btsocket_sco_pcb_by_handle(&rt->src, con_handle);
763 	if (pcb == NULL) {
764 		mtx_unlock(&ng_btsocket_sco_sockets_mtx);
765 		goto drop;
766 	}
767 
768 	/* pcb is locked */
769 
770 	if (pcb->state != NG_BTSOCKET_SCO_OPEN) {
771 		NG_BTSOCKET_SCO_ERR(
772 "%s: No connected socket found, src bdaddr=%x:%x:%x:%x:%x:%x, state=%d\n",
773 			__func__,
774 			rt->src.b[5], rt->src.b[4], rt->src.b[3],
775 			rt->src.b[2], rt->src.b[1], rt->src.b[0],
776 			pcb->state);
777 
778 		mtx_unlock(&pcb->pcb_mtx);
779 		mtx_unlock(&ng_btsocket_sco_sockets_mtx);
780 		goto drop;
781 	}
782 
783 	/* Check if we have enough space in socket receive queue */
784 	if (m->m_pkthdr.len > sbspace(&pcb->so->so_rcv)) {
785 		NG_BTSOCKET_SCO_ERR(
786 "%s: Not enough space in socket receive queue. Dropping SCO data packet, " \
787 "src bdaddr=%x:%x:%x:%x:%x:%x, len=%d, space=%ld\n",
788 			__func__,
789 			rt->src.b[5], rt->src.b[4], rt->src.b[3],
790 			rt->src.b[2], rt->src.b[1], rt->src.b[0],
791 			m->m_pkthdr.len,
792 			sbspace(&pcb->so->so_rcv));
793 
794 		mtx_unlock(&pcb->pcb_mtx);
795 		mtx_unlock(&ng_btsocket_sco_sockets_mtx);
796 		goto drop;
797 	}
798 
799 	/* Append packet to the socket receive queue and wakeup */
800 	sbappendrecord(&pcb->so->so_rcv, m);
801 	m = NULL;
802 
803 	sorwakeup(pcb->so);
804 
805 	mtx_unlock(&pcb->pcb_mtx);
806 	mtx_unlock(&ng_btsocket_sco_sockets_mtx);
807 drop:
808 	NG_FREE_M(m); /* checks for m != NULL */
809 } /* ng_btsocket_sco_data_input */
810 
811 /*
812  * SCO sockets default message input routine
813  */
814 
815 static void
816 ng_btsocket_sco_default_msg_input(struct ng_mesg *msg, hook_p hook)
817 {
818 	ng_btsocket_sco_rtentry_t	*rt = NULL;
819 
820 	if (hook == NULL || NG_HOOK_NOT_VALID(hook))
821 		return;
822 
823 	rt = (ng_btsocket_sco_rtentry_t *) NG_HOOK_PRIVATE(hook);
824 
825 	switch (msg->header.cmd) {
826 	case NGM_HCI_NODE_UP: {
827 		ng_hci_node_up_ep	*ep = NULL;
828 
829 		if (msg->header.arglen != sizeof(*ep))
830 			break;
831 
832 		ep = (ng_hci_node_up_ep *)(msg->data);
833 		if (bcmp(&ep->bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
834 			break;
835 
836 		if (rt == NULL) {
837 			rt = malloc(sizeof(*rt),
838 				M_NETGRAPH_BTSOCKET_SCO, M_NOWAIT|M_ZERO);
839 			if (rt == NULL)
840 				break;
841 
842 			NG_HOOK_SET_PRIVATE(hook, rt);
843 
844 			mtx_lock(&ng_btsocket_sco_rt_mtx);
845 
846 			LIST_INSERT_HEAD(&ng_btsocket_sco_rt, rt, next);
847 		} else
848 			mtx_lock(&ng_btsocket_sco_rt_mtx);
849 
850 		bcopy(&ep->bdaddr, &rt->src, sizeof(rt->src));
851 		rt->pkt_size = (ep->pkt_size == 0)? 60 : ep->pkt_size;
852 		rt->num_pkts = ep->num_pkts;
853 		rt->hook = hook;
854 
855 		mtx_unlock(&ng_btsocket_sco_rt_mtx);
856 
857 		NG_BTSOCKET_SCO_INFO(
858 "%s: Updating hook \"%s\", src bdaddr=%x:%x:%x:%x:%x:%x, pkt_size=%d, " \
859 "num_pkts=%d\n",	__func__, NG_HOOK_NAME(hook),
860 			rt->src.b[5], rt->src.b[4], rt->src.b[3],
861 			rt->src.b[2], rt->src.b[1], rt->src.b[0],
862 			rt->pkt_size, rt->num_pkts);
863 		} break;
864 
865 	case NGM_HCI_SYNC_CON_QUEUE: {
866 		ng_hci_sync_con_queue_ep	*ep = NULL;
867 		ng_btsocket_sco_pcb_t		*pcb = NULL;
868 
869 		if (rt == NULL || msg->header.arglen != sizeof(*ep))
870 			break;
871 
872 		ep = (ng_hci_sync_con_queue_ep *)(msg->data);
873 
874 		rt->pending -= ep->completed;
875 		if (rt->pending < 0) {
876 			NG_BTSOCKET_SCO_WARN(
877 "%s: Pending packet counter is out of sync! bdaddr=%x:%x:%x:%x:%x:%x, " \
878 "handle=%d, pending=%d, completed=%d\n",
879 				__func__,
880 				rt->src.b[5], rt->src.b[4], rt->src.b[3],
881 				rt->src.b[2], rt->src.b[1], rt->src.b[0],
882 				ep->con_handle, rt->pending,
883 				ep->completed);
884 
885 			rt->pending = 0;
886 		}
887 
888 		mtx_lock(&ng_btsocket_sco_sockets_mtx);
889 
890 		/* Find socket */
891 		pcb = ng_btsocket_sco_pcb_by_handle(&rt->src, ep->con_handle);
892 		if (pcb == NULL) {
893 			mtx_unlock(&ng_btsocket_sco_sockets_mtx);
894 			break;
895 		}
896 
897 		/* pcb is locked */
898 
899 		/* Check state */
900 		if (pcb->state == NG_BTSOCKET_SCO_OPEN) {
901 			/* Remove timeout */
902 			ng_btsocket_sco_untimeout(pcb);
903 
904 			/* Drop completed packets from the send queue */
905 			for (; ep->completed > 0; ep->completed --)
906 				sbdroprecord(&pcb->so->so_snd);
907 
908 			/* Send more if we have any */
909 			if (sbavail(&pcb->so->so_snd) > 0)
910 				if (ng_btsocket_sco_send2(pcb) == 0)
911 					ng_btsocket_sco_timeout(pcb);
912 
913 			/* Wake up writers */
914 			sowwakeup(pcb->so);
915 		}
916 
917 		mtx_unlock(&pcb->pcb_mtx);
918 		mtx_unlock(&ng_btsocket_sco_sockets_mtx);
919 	} break;
920 
921 	default:
922 		NG_BTSOCKET_SCO_WARN(
923 "%s: Unknown message, cmd=%d\n", __func__, msg->header.cmd);
924 		break;
925 	}
926 
927 	NG_FREE_MSG(msg); /* Checks for msg != NULL */
928 } /* ng_btsocket_sco_default_msg_input */
929 
930 /*
931  * SCO sockets LP message input routine
932  */
933 
934 static void
935 ng_btsocket_sco_lp_msg_input(struct ng_mesg *msg, hook_p hook)
936 {
937 	ng_btsocket_sco_rtentry_p	 rt = NULL;
938 
939 	if (hook == NULL) {
940 		NG_BTSOCKET_SCO_ALERT(
941 "%s: Invalid source hook for LP message\n", __func__);
942 		goto drop;
943 	}
944 
945 	rt = (ng_btsocket_sco_rtentry_p) NG_HOOK_PRIVATE(hook);
946 	if (rt == NULL) {
947 		NG_BTSOCKET_SCO_ALERT(
948 "%s: Could not find out source bdaddr for LP message\n", __func__);
949 		goto drop;
950 	}
951 
952 	switch (msg->header.cmd) {
953 	case NGM_HCI_LP_CON_CFM: /* Connection Confirmation Event */
954 		ng_btsocket_sco_process_lp_con_cfm(msg, rt);
955 		break;
956 
957 	case NGM_HCI_LP_CON_IND: /* Connection Indication Event */
958 		ng_btsocket_sco_process_lp_con_ind(msg, rt);
959 		break;
960 
961 	case NGM_HCI_LP_DISCON_IND: /* Disconnection Indication Event */
962 		ng_btsocket_sco_process_lp_discon_ind(msg, rt);
963 		break;
964 
965 	/* XXX FIXME add other LP messages */
966 
967 	default:
968 		NG_BTSOCKET_SCO_WARN(
969 "%s: Unknown LP message, cmd=%d\n", __func__, msg->header.cmd);
970 		break;
971 	}
972 drop:
973 	NG_FREE_MSG(msg);
974 } /* ng_btsocket_sco_lp_msg_input */
975 
976 /*
977  * SCO sockets input routine
978  */
979 
980 static void
981 ng_btsocket_sco_input(void *context, int pending)
982 {
983 	item_p	item = NULL;
984 	hook_p	hook = NULL;
985 
986 	for (;;) {
987 		mtx_lock(&ng_btsocket_sco_queue_mtx);
988 		NG_BT_ITEMQ_DEQUEUE(&ng_btsocket_sco_queue, item);
989 		mtx_unlock(&ng_btsocket_sco_queue_mtx);
990 
991 		if (item == NULL)
992 			break;
993 
994 		NGI_GET_HOOK(item, hook);
995 		if (hook != NULL && NG_HOOK_NOT_VALID(hook))
996 			goto drop;
997 
998 		switch(item->el_flags & NGQF_TYPE) {
999 		case NGQF_DATA: {
1000 			struct mbuf     *m = NULL;
1001 
1002 			NGI_GET_M(item, m);
1003 			ng_btsocket_sco_data_input(m, hook);
1004 			} break;
1005 
1006 		case NGQF_MESG: {
1007 			struct ng_mesg  *msg = NULL;
1008 
1009 			NGI_GET_MSG(item, msg);
1010 
1011 			switch (msg->header.cmd) {
1012 			case NGM_HCI_LP_CON_CFM:
1013 			case NGM_HCI_LP_CON_IND:
1014 			case NGM_HCI_LP_DISCON_IND:
1015 			/* XXX FIXME add other LP messages */
1016 				ng_btsocket_sco_lp_msg_input(msg, hook);
1017 				break;
1018 
1019 			default:
1020 				ng_btsocket_sco_default_msg_input(msg, hook);
1021 				break;
1022 			}
1023 			} break;
1024 
1025 		default:
1026 			KASSERT(0,
1027 ("%s: invalid item type=%ld\n", __func__, (item->el_flags & NGQF_TYPE)));
1028 			break;
1029 		}
1030 drop:
1031 		if (hook != NULL)
1032 			NG_HOOK_UNREF(hook);
1033 
1034 		NG_FREE_ITEM(item);
1035 	}
1036 } /* ng_btsocket_sco_input */
1037 
1038 /*
1039  * Route cleanup task. Gets scheduled when hook is disconnected. Here we
1040  * will find all sockets that use "invalid" hook and disconnect them.
1041  */
1042 
1043 static void
1044 ng_btsocket_sco_rtclean(void *context, int pending)
1045 {
1046 	ng_btsocket_sco_pcb_p		pcb = NULL, pcb_next = NULL;
1047 	ng_btsocket_sco_rtentry_p	rt = NULL;
1048 
1049 	/*
1050 	 * First disconnect all sockets that use "invalid" hook
1051 	 */
1052 
1053 	mtx_lock(&ng_btsocket_sco_sockets_mtx);
1054 
1055 	for(pcb = LIST_FIRST(&ng_btsocket_sco_sockets); pcb != NULL; ) {
1056 		mtx_lock(&pcb->pcb_mtx);
1057 		pcb_next = LIST_NEXT(pcb, next);
1058 
1059 		if (pcb->rt != NULL &&
1060 		    pcb->rt->hook != NULL && NG_HOOK_NOT_VALID(pcb->rt->hook)) {
1061 			if (pcb->flags & NG_BTSOCKET_SCO_TIMO)
1062 				ng_btsocket_sco_untimeout(pcb);
1063 
1064 			pcb->rt = NULL;
1065 			pcb->so->so_error = ENETDOWN;
1066 			pcb->state = NG_BTSOCKET_SCO_CLOSED;
1067 			soisdisconnected(pcb->so);
1068 		}
1069 
1070 		mtx_unlock(&pcb->pcb_mtx);
1071 		pcb = pcb_next;
1072 	}
1073 
1074 	mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1075 
1076 	/*
1077 	 * Now cleanup routing table
1078 	 */
1079 
1080 	mtx_lock(&ng_btsocket_sco_rt_mtx);
1081 
1082 	for (rt = LIST_FIRST(&ng_btsocket_sco_rt); rt != NULL; ) {
1083 		ng_btsocket_sco_rtentry_p	rt_next = LIST_NEXT(rt, next);
1084 
1085 		if (rt->hook != NULL && NG_HOOK_NOT_VALID(rt->hook)) {
1086 			LIST_REMOVE(rt, next);
1087 
1088 			NG_HOOK_SET_PRIVATE(rt->hook, NULL);
1089 			NG_HOOK_UNREF(rt->hook); /* Remove extra reference */
1090 
1091 			bzero(rt, sizeof(*rt));
1092 			free(rt, M_NETGRAPH_BTSOCKET_SCO);
1093 		}
1094 
1095 		rt = rt_next;
1096 	}
1097 
1098 	mtx_unlock(&ng_btsocket_sco_rt_mtx);
1099 } /* ng_btsocket_sco_rtclean */
1100 
1101 /*
1102  * Initialize everything
1103  */
1104 
1105 void
1106 ng_btsocket_sco_init(void)
1107 {
1108 	int	error = 0;
1109 
1110 	/* Skip initialization of globals for non-default instances. */
1111 	if (!IS_DEFAULT_VNET(curvnet))
1112 		return;
1113 
1114 	ng_btsocket_sco_node = NULL;
1115 	ng_btsocket_sco_debug_level = NG_BTSOCKET_WARN_LEVEL;
1116 
1117 	/* Register Netgraph node type */
1118 	error = ng_newtype(&typestruct);
1119 	if (error != 0) {
1120 		NG_BTSOCKET_SCO_ALERT(
1121 "%s: Could not register Netgraph node type, error=%d\n", __func__, error);
1122 
1123                 return;
1124 	}
1125 
1126 	/* Create Netgrapg node */
1127 	error = ng_make_node_common(&typestruct, &ng_btsocket_sco_node);
1128 	if (error != 0) {
1129 		NG_BTSOCKET_SCO_ALERT(
1130 "%s: Could not create Netgraph node, error=%d\n", __func__, error);
1131 
1132 		ng_btsocket_sco_node = NULL;
1133 
1134 		return;
1135 	}
1136 
1137 	error = ng_name_node(ng_btsocket_sco_node, NG_BTSOCKET_SCO_NODE_TYPE);
1138 	if (error != 0) {
1139 		NG_BTSOCKET_SCO_ALERT(
1140 "%s: Could not name Netgraph node, error=%d\n", __func__, error);
1141 
1142 		NG_NODE_UNREF(ng_btsocket_sco_node);
1143 		ng_btsocket_sco_node = NULL;
1144 
1145 		return;
1146 	}
1147 
1148 	/* Create input queue */
1149 	NG_BT_ITEMQ_INIT(&ng_btsocket_sco_queue, 300);
1150 	mtx_init(&ng_btsocket_sco_queue_mtx,
1151 		"btsocks_sco_queue_mtx", NULL, MTX_DEF);
1152 	TASK_INIT(&ng_btsocket_sco_queue_task, 0,
1153 		ng_btsocket_sco_input, NULL);
1154 
1155 	/* Create list of sockets */
1156 	LIST_INIT(&ng_btsocket_sco_sockets);
1157 	mtx_init(&ng_btsocket_sco_sockets_mtx,
1158 		"btsocks_sco_sockets_mtx", NULL, MTX_DEF);
1159 
1160 	/* Routing table */
1161 	LIST_INIT(&ng_btsocket_sco_rt);
1162 	mtx_init(&ng_btsocket_sco_rt_mtx,
1163 		"btsocks_sco_rt_mtx", NULL, MTX_DEF);
1164 	TASK_INIT(&ng_btsocket_sco_rt_task, 0,
1165 		ng_btsocket_sco_rtclean, NULL);
1166 } /* ng_btsocket_sco_init */
1167 
1168 /*
1169  * Abort connection on socket
1170  */
1171 
1172 void
1173 ng_btsocket_sco_abort(struct socket *so)
1174 {
1175 	so->so_error = ECONNABORTED;
1176 
1177 	(void) ng_btsocket_sco_disconnect(so);
1178 } /* ng_btsocket_sco_abort */
1179 
1180 void
1181 ng_btsocket_sco_close(struct socket *so)
1182 {
1183 	(void) ng_btsocket_sco_disconnect(so);
1184 } /* ng_btsocket_sco_close */
1185 
1186 /*
1187  * Accept connection on socket. Nothing to do here, socket must be connected
1188  * and ready, so just return peer address and be done with it.
1189  */
1190 
1191 int
1192 ng_btsocket_sco_accept(struct socket *so, struct sockaddr **nam)
1193 {
1194 	if (ng_btsocket_sco_node == NULL)
1195 		return (EINVAL);
1196 
1197 	return (ng_btsocket_sco_peeraddr(so, nam));
1198 } /* ng_btsocket_sco_accept */
1199 
1200 /*
1201  * Create and attach new socket
1202  */
1203 
1204 int
1205 ng_btsocket_sco_attach(struct socket *so, int proto, struct thread *td)
1206 {
1207 	ng_btsocket_sco_pcb_p	pcb = so2sco_pcb(so);
1208 	int			error;
1209 
1210 	/* Check socket and protocol */
1211 	if (ng_btsocket_sco_node == NULL)
1212 		return (EPROTONOSUPPORT);
1213 	if (so->so_type != SOCK_SEQPACKET)
1214 		return (ESOCKTNOSUPPORT);
1215 
1216 #if 0 /* XXX sonewconn() calls "pru_attach" with proto == 0 */
1217 	if (proto != 0)
1218 		if (proto != BLUETOOTH_PROTO_SCO)
1219 			return (EPROTONOSUPPORT);
1220 #endif /* XXX */
1221 
1222 	if (pcb != NULL)
1223 		return (EISCONN);
1224 
1225 	/* Reserve send and receive space if it is not reserved yet */
1226 	if ((so->so_snd.sb_hiwat == 0) || (so->so_rcv.sb_hiwat == 0)) {
1227 		error = soreserve(so, NG_BTSOCKET_SCO_SENDSPACE,
1228 					NG_BTSOCKET_SCO_RECVSPACE);
1229 		if (error != 0)
1230 			return (error);
1231 	}
1232 
1233 	/* Allocate the PCB */
1234         pcb = malloc(sizeof(*pcb),
1235 		M_NETGRAPH_BTSOCKET_SCO, M_NOWAIT | M_ZERO);
1236         if (pcb == NULL)
1237                 return (ENOMEM);
1238 
1239 	/* Link the PCB and the socket */
1240 	so->so_pcb = (caddr_t) pcb;
1241 	pcb->so = so;
1242 	pcb->state = NG_BTSOCKET_SCO_CLOSED;
1243 
1244 	callout_init(&pcb->timo, 1);
1245 
1246 	/*
1247 	 * Mark PCB mutex as DUPOK to prevent "duplicated lock of
1248 	 * the same type" message. When accepting new SCO connection
1249 	 * ng_btsocket_sco_process_lp_con_ind() holds both PCB mutexes
1250 	 * for "old" (accepting) PCB and "new" (created) PCB.
1251 	 */
1252 
1253 	mtx_init(&pcb->pcb_mtx, "btsocks_sco_pcb_mtx", NULL,
1254 		MTX_DEF|MTX_DUPOK);
1255 
1256 	/*
1257 	 * Add the PCB to the list
1258 	 *
1259 	 * XXX FIXME VERY IMPORTANT!
1260 	 *
1261 	 * This is totally FUBAR. We could get here in two cases:
1262 	 *
1263 	 * 1) When user calls socket()
1264 	 * 2) When we need to accept new incomming connection and call
1265 	 *    sonewconn()
1266 	 *
1267 	 * In the first case we must aquire ng_btsocket_sco_sockets_mtx.
1268 	 * In the second case we hold ng_btsocket_sco_sockets_mtx already.
1269 	 * So we now need to distinguish between these cases. From reading
1270 	 * /sys/kern/uipc_socket2.c we can find out that sonewconn() calls
1271 	 * pru_attach with proto == 0 and td == NULL. For now use this fact
1272 	 * to figure out if we were called from socket() or from sonewconn().
1273 	 */
1274 
1275 	if (td != NULL)
1276 		mtx_lock(&ng_btsocket_sco_sockets_mtx);
1277 	else
1278 		mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED);
1279 
1280 	LIST_INSERT_HEAD(&ng_btsocket_sco_sockets, pcb, next);
1281 
1282 	if (td != NULL)
1283 		mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1284 
1285         return (0);
1286 } /* ng_btsocket_sco_attach */
1287 
1288 /*
1289  * Bind socket
1290  */
1291 
1292 int
1293 ng_btsocket_sco_bind(struct socket *so, struct sockaddr *nam,
1294 		struct thread *td)
1295 {
1296 	ng_btsocket_sco_pcb_t	*pcb = NULL;
1297 	struct sockaddr_sco	*sa = (struct sockaddr_sco *) nam;
1298 
1299 	if (ng_btsocket_sco_node == NULL)
1300 		return (EINVAL);
1301 
1302 	/* Verify address */
1303 	if (sa == NULL)
1304 		return (EINVAL);
1305 	if (sa->sco_family != AF_BLUETOOTH)
1306 		return (EAFNOSUPPORT);
1307 	if (sa->sco_len != sizeof(*sa))
1308 		return (EINVAL);
1309 
1310 	mtx_lock(&ng_btsocket_sco_sockets_mtx);
1311 
1312 	/*
1313 	 * Check if other socket has this address already (look for exact
1314 	 * match in bdaddr) and assign socket address if it's available.
1315 	 */
1316 
1317 	if (bcmp(&sa->sco_bdaddr, NG_HCI_BDADDR_ANY, sizeof(sa->sco_bdaddr)) != 0) {
1318  		LIST_FOREACH(pcb, &ng_btsocket_sco_sockets, next) {
1319 			mtx_lock(&pcb->pcb_mtx);
1320 
1321 			if (bcmp(&pcb->src, &sa->sco_bdaddr, sizeof(bdaddr_t)) == 0) {
1322 				mtx_unlock(&pcb->pcb_mtx);
1323 				mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1324 
1325 				return (EADDRINUSE);
1326 			}
1327 
1328 			mtx_unlock(&pcb->pcb_mtx);
1329 		}
1330 
1331 	}
1332 
1333 	pcb = so2sco_pcb(so);
1334 	if (pcb == NULL) {
1335 		mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1336 		return (EINVAL);
1337 	}
1338 
1339 	mtx_lock(&pcb->pcb_mtx);
1340 	bcopy(&sa->sco_bdaddr, &pcb->src, sizeof(pcb->src));
1341 	mtx_unlock(&pcb->pcb_mtx);
1342 
1343 	mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1344 
1345 	return (0);
1346 } /* ng_btsocket_sco_bind */
1347 
1348 /*
1349  * Connect socket
1350  */
1351 
1352 int
1353 ng_btsocket_sco_connect(struct socket *so, struct sockaddr *nam,
1354 		struct thread *td)
1355 {
1356 	ng_btsocket_sco_pcb_t		*pcb = so2sco_pcb(so);
1357 	struct sockaddr_sco		*sa = (struct sockaddr_sco *) nam;
1358 	ng_btsocket_sco_rtentry_t	*rt = NULL;
1359 	int				 have_src, error = 0;
1360 
1361 	/* Check socket */
1362 	if (pcb == NULL)
1363 		return (EINVAL);
1364 	if (ng_btsocket_sco_node == NULL)
1365 		return (EINVAL);
1366 
1367 	/* Verify address */
1368 	if (sa == NULL)
1369 		return (EINVAL);
1370 	if (sa->sco_family != AF_BLUETOOTH)
1371 		return (EAFNOSUPPORT);
1372 	if (sa->sco_len != sizeof(*sa))
1373 		return (EINVAL);
1374 	if (bcmp(&sa->sco_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
1375 		return (EDESTADDRREQ);
1376 
1377 	/*
1378 	 * Routing. Socket should be bound to some source address. The source
1379 	 * address can be ANY. Destination address must be set and it must not
1380 	 * be ANY. If source address is ANY then find first rtentry that has
1381 	 * src != dst.
1382 	 */
1383 
1384 	mtx_lock(&ng_btsocket_sco_rt_mtx);
1385 	mtx_lock(&pcb->pcb_mtx);
1386 
1387 	if (pcb->state == NG_BTSOCKET_SCO_CONNECTING) {
1388 		mtx_unlock(&pcb->pcb_mtx);
1389 		mtx_unlock(&ng_btsocket_sco_rt_mtx);
1390 
1391 		return (EINPROGRESS);
1392 	}
1393 
1394 	if (bcmp(&sa->sco_bdaddr, &pcb->src, sizeof(pcb->src)) == 0) {
1395 		mtx_unlock(&pcb->pcb_mtx);
1396 		mtx_unlock(&ng_btsocket_sco_rt_mtx);
1397 
1398 		return (EINVAL);
1399 	}
1400 
1401 	/* Send destination address and PSM */
1402 	bcopy(&sa->sco_bdaddr, &pcb->dst, sizeof(pcb->dst));
1403 
1404 	pcb->rt = NULL;
1405 	have_src = bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(pcb->src));
1406 
1407 	LIST_FOREACH(rt, &ng_btsocket_sco_rt, next) {
1408 		if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
1409 			continue;
1410 
1411 		/* Match src and dst */
1412 		if (have_src) {
1413 			if (bcmp(&pcb->src, &rt->src, sizeof(rt->src)) == 0)
1414 				break;
1415 		} else {
1416 			if (bcmp(&pcb->dst, &rt->src, sizeof(rt->src)) != 0)
1417 				break;
1418 		}
1419 	}
1420 
1421 	if (rt != NULL) {
1422 		pcb->rt = rt;
1423 
1424 		if (!have_src)
1425 			bcopy(&rt->src, &pcb->src, sizeof(pcb->src));
1426 	} else
1427 		error = EHOSTUNREACH;
1428 
1429 	/*
1430 	 * Send LP_Connect request
1431 	 */
1432 
1433 	if (error == 0) {
1434 		error = ng_btsocket_sco_send_lp_con_req(pcb);
1435 		if (error == 0) {
1436 			pcb->flags |= NG_BTSOCKET_SCO_CLIENT;
1437 			pcb->state = NG_BTSOCKET_SCO_CONNECTING;
1438 			soisconnecting(pcb->so);
1439 
1440 			ng_btsocket_sco_timeout(pcb);
1441 		}
1442 	}
1443 
1444 	mtx_unlock(&pcb->pcb_mtx);
1445 	mtx_unlock(&ng_btsocket_sco_rt_mtx);
1446 
1447 	return (error);
1448 } /* ng_btsocket_sco_connect */
1449 
1450 /*
1451  * Process ioctl's calls on socket
1452  */
1453 
1454 int
1455 ng_btsocket_sco_control(struct socket *so, u_long cmd, caddr_t data,
1456 		struct ifnet *ifp, struct thread *td)
1457 {
1458 	return (EINVAL);
1459 } /* ng_btsocket_sco_control */
1460 
1461 /*
1462  * Process getsockopt/setsockopt system calls
1463  */
1464 
1465 int
1466 ng_btsocket_sco_ctloutput(struct socket *so, struct sockopt *sopt)
1467 {
1468 	ng_btsocket_sco_pcb_p	pcb = so2sco_pcb(so);
1469         int			error, tmp;
1470 
1471 	if (ng_btsocket_sco_node == NULL)
1472 		return (EINVAL);
1473 	if (pcb == NULL)
1474 		return (EINVAL);
1475 
1476 	if (sopt->sopt_level != SOL_SCO)
1477 		return (0);
1478 
1479 	mtx_lock(&pcb->pcb_mtx);
1480 
1481 	switch (sopt->sopt_dir) {
1482 	case SOPT_GET:
1483 		if (pcb->state != NG_BTSOCKET_SCO_OPEN) {
1484 			error = ENOTCONN;
1485 			break;
1486 		}
1487 
1488 		switch (sopt->sopt_name) {
1489 		case SO_SCO_MTU:
1490 			tmp = pcb->rt->pkt_size;
1491 			error = sooptcopyout(sopt, &tmp, sizeof(tmp));
1492 			break;
1493 
1494 		case SO_SCO_CONNINFO:
1495 			tmp = pcb->con_handle;
1496 			error = sooptcopyout(sopt, &tmp, sizeof(tmp));
1497 			break;
1498 
1499 		default:
1500 			error = EINVAL;
1501 			break;
1502 		}
1503 		break;
1504 
1505 	case SOPT_SET:
1506 		error = ENOPROTOOPT;
1507 		break;
1508 
1509 	default:
1510 		error = EINVAL;
1511 		break;
1512 	}
1513 
1514 	mtx_unlock(&pcb->pcb_mtx);
1515 
1516 	return (error);
1517 } /* ng_btsocket_sco_ctloutput */
1518 
1519 /*
1520  * Detach and destroy socket
1521  */
1522 
1523 void
1524 ng_btsocket_sco_detach(struct socket *so)
1525 {
1526 	ng_btsocket_sco_pcb_p	pcb = so2sco_pcb(so);
1527 
1528 	KASSERT(pcb != NULL, ("ng_btsocket_sco_detach: pcb == NULL"));
1529 
1530 	if (ng_btsocket_sco_node == NULL)
1531 		return;
1532 
1533 	mtx_lock(&ng_btsocket_sco_sockets_mtx);
1534 	mtx_lock(&pcb->pcb_mtx);
1535 
1536 	if (pcb->flags & NG_BTSOCKET_SCO_TIMO)
1537 		ng_btsocket_sco_untimeout(pcb);
1538 
1539 	if (pcb->state == NG_BTSOCKET_SCO_OPEN)
1540 		ng_btsocket_sco_send_lp_discon_req(pcb);
1541 
1542 	pcb->state = NG_BTSOCKET_SCO_CLOSED;
1543 
1544 	LIST_REMOVE(pcb, next);
1545 
1546 	mtx_unlock(&pcb->pcb_mtx);
1547 	mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1548 
1549 	mtx_destroy(&pcb->pcb_mtx);
1550 	bzero(pcb, sizeof(*pcb));
1551 	free(pcb, M_NETGRAPH_BTSOCKET_SCO);
1552 
1553 	soisdisconnected(so);
1554 	so->so_pcb = NULL;
1555 } /* ng_btsocket_sco_detach */
1556 
1557 /*
1558  * Disconnect socket
1559  */
1560 
1561 int
1562 ng_btsocket_sco_disconnect(struct socket *so)
1563 {
1564 	ng_btsocket_sco_pcb_p	pcb = so2sco_pcb(so);
1565 
1566 	if (pcb == NULL)
1567 		return (EINVAL);
1568 	if (ng_btsocket_sco_node == NULL)
1569 		return (EINVAL);
1570 
1571 	mtx_lock(&pcb->pcb_mtx);
1572 
1573 	if (pcb->state == NG_BTSOCKET_SCO_DISCONNECTING) {
1574 		mtx_unlock(&pcb->pcb_mtx);
1575 
1576 		return (EINPROGRESS);
1577 	}
1578 
1579 	if (pcb->flags & NG_BTSOCKET_SCO_TIMO)
1580 		ng_btsocket_sco_untimeout(pcb);
1581 
1582 	if (pcb->state == NG_BTSOCKET_SCO_OPEN) {
1583 		ng_btsocket_sco_send_lp_discon_req(pcb);
1584 
1585 		pcb->state = NG_BTSOCKET_SCO_DISCONNECTING;
1586 		soisdisconnecting(so);
1587 
1588 		ng_btsocket_sco_timeout(pcb);
1589 	} else {
1590 		pcb->state = NG_BTSOCKET_SCO_CLOSED;
1591 		soisdisconnected(so);
1592 	}
1593 
1594 	mtx_unlock(&pcb->pcb_mtx);
1595 
1596 	return (0);
1597 } /* ng_btsocket_sco_disconnect */
1598 
1599 /*
1600  * Listen on socket
1601  */
1602 
1603 int
1604 ng_btsocket_sco_listen(struct socket *so, int backlog, struct thread *td)
1605 {
1606 	ng_btsocket_sco_pcb_p	pcb = so2sco_pcb(so);
1607 	int			error;
1608 
1609 	if (pcb == NULL)
1610 		return (EINVAL);
1611 	if (ng_btsocket_sco_node == NULL)
1612 		return (EINVAL);
1613 
1614 	SOCK_LOCK(so);
1615 	mtx_lock(&pcb->pcb_mtx);
1616 
1617 	error = solisten_proto_check(so);
1618 	if (error != 0)
1619 		goto out;
1620 #if 0
1621 	if (bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0) {
1622 		error = EDESTADDRREQ;
1623 		goto out;
1624 	}
1625 #endif
1626 	solisten_proto(so, backlog);
1627 out:
1628 	mtx_unlock(&pcb->pcb_mtx);
1629 	SOCK_UNLOCK(so);
1630 
1631 	return (error);
1632 } /* ng_btsocket_listen */
1633 
1634 /*
1635  * Get peer address
1636  */
1637 
1638 int
1639 ng_btsocket_sco_peeraddr(struct socket *so, struct sockaddr **nam)
1640 {
1641 	ng_btsocket_sco_pcb_p	pcb = so2sco_pcb(so);
1642 	struct sockaddr_sco	sa;
1643 
1644 	if (pcb == NULL)
1645 		return (EINVAL);
1646 	if (ng_btsocket_sco_node == NULL)
1647 		return (EINVAL);
1648 
1649 	mtx_lock(&pcb->pcb_mtx);
1650 	bcopy(&pcb->dst, &sa.sco_bdaddr, sizeof(sa.sco_bdaddr));
1651 	mtx_unlock(&pcb->pcb_mtx);
1652 
1653 	sa.sco_len = sizeof(sa);
1654 	sa.sco_family = AF_BLUETOOTH;
1655 
1656 	*nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT);
1657 
1658 	return ((*nam == NULL)? ENOMEM : 0);
1659 } /* ng_btsocket_sco_peeraddr */
1660 
1661 /*
1662  * Send data to socket
1663  */
1664 
1665 int
1666 ng_btsocket_sco_send(struct socket *so, int flags, struct mbuf *m,
1667 		struct sockaddr *nam, struct mbuf *control, struct thread *td)
1668 {
1669 	ng_btsocket_sco_pcb_t	*pcb = so2sco_pcb(so);
1670 	int			 error = 0;
1671 
1672 	if (ng_btsocket_sco_node == NULL) {
1673 		error = ENETDOWN;
1674 		goto drop;
1675 	}
1676 
1677 	/* Check socket and input */
1678 	if (pcb == NULL || m == NULL || control != NULL) {
1679 		error = EINVAL;
1680 		goto drop;
1681 	}
1682 
1683 	mtx_lock(&pcb->pcb_mtx);
1684 
1685 	/* Make sure socket is connected */
1686 	if (pcb->state != NG_BTSOCKET_SCO_OPEN) {
1687 		mtx_unlock(&pcb->pcb_mtx);
1688 		error = ENOTCONN;
1689 		goto drop;
1690 	}
1691 
1692 	/* Check route */
1693 	if (pcb->rt == NULL ||
1694 	    pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook)) {
1695 		mtx_unlock(&pcb->pcb_mtx);
1696 		error = ENETDOWN;
1697 		goto drop;
1698 	}
1699 
1700 	/* Check packet size */
1701 	if (m->m_pkthdr.len > pcb->rt->pkt_size) {
1702 		NG_BTSOCKET_SCO_ERR(
1703 "%s: Packet too big, len=%d, pkt_size=%d\n",
1704 			__func__, m->m_pkthdr.len, pcb->rt->pkt_size);
1705 
1706 		mtx_unlock(&pcb->pcb_mtx);
1707 		error = EMSGSIZE;
1708 		goto drop;
1709 	}
1710 
1711 	/*
1712 	 * First put packet on socket send queue. Then check if we have
1713 	 * pending timeout. If we do not have timeout then we must send
1714 	 * packet and schedule timeout. Otherwise do nothing and wait for
1715 	 * NGM_HCI_SYNC_CON_QUEUE message.
1716 	 */
1717 
1718 	sbappendrecord(&pcb->so->so_snd, m);
1719 	m = NULL;
1720 
1721 	if (!(pcb->flags & NG_BTSOCKET_SCO_TIMO)) {
1722 		error = ng_btsocket_sco_send2(pcb);
1723 		if (error == 0)
1724 			ng_btsocket_sco_timeout(pcb);
1725 		else
1726 			sbdroprecord(&pcb->so->so_snd); /* XXX */
1727 	}
1728 
1729 	mtx_unlock(&pcb->pcb_mtx);
1730 drop:
1731 	NG_FREE_M(m); /* checks for != NULL */
1732 	NG_FREE_M(control);
1733 
1734 	return (error);
1735 } /* ng_btsocket_sco_send */
1736 
1737 /*
1738  * Send first packet in the socket queue to the SCO layer
1739  */
1740 
1741 static int
1742 ng_btsocket_sco_send2(ng_btsocket_sco_pcb_p pcb)
1743 {
1744 	struct  mbuf		*m = NULL;
1745 	ng_hci_scodata_pkt_t	*hdr = NULL;
1746 	int			 error = 0;
1747 
1748 	mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1749 
1750 	while (pcb->rt->pending < pcb->rt->num_pkts &&
1751 	       sbavail(&pcb->so->so_snd) > 0) {
1752 		/* Get a copy of the first packet on send queue */
1753 		m = m_dup(pcb->so->so_snd.sb_mb, M_NOWAIT);
1754 		if (m == NULL) {
1755 			error = ENOBUFS;
1756 			break;
1757 		}
1758 
1759 		/* Create SCO packet header */
1760 		M_PREPEND(m, sizeof(*hdr), M_NOWAIT);
1761 		if (m != NULL)
1762 			if (m->m_len < sizeof(*hdr))
1763 				m = m_pullup(m, sizeof(*hdr));
1764 
1765 		if (m == NULL) {
1766 			error = ENOBUFS;
1767 			break;
1768 		}
1769 
1770 		/* Fill in the header */
1771 		hdr = mtod(m, ng_hci_scodata_pkt_t *);
1772 		hdr->type = NG_HCI_SCO_DATA_PKT;
1773 		hdr->con_handle = htole16(NG_HCI_MK_CON_HANDLE(pcb->con_handle, 0, 0));
1774 		hdr->length = m->m_pkthdr.len - sizeof(*hdr);
1775 
1776 		/* Send packet */
1777 		NG_SEND_DATA_ONLY(error, pcb->rt->hook, m);
1778 		if (error != 0)
1779 			break;
1780 
1781 		pcb->rt->pending ++;
1782 	}
1783 
1784 	return ((pcb->rt->pending > 0)? 0 : error);
1785 } /* ng_btsocket_sco_send2 */
1786 
1787 /*
1788  * Get socket address
1789  */
1790 
1791 int
1792 ng_btsocket_sco_sockaddr(struct socket *so, struct sockaddr **nam)
1793 {
1794 	ng_btsocket_sco_pcb_p	pcb = so2sco_pcb(so);
1795 	struct sockaddr_sco	sa;
1796 
1797 	if (pcb == NULL)
1798 		return (EINVAL);
1799 	if (ng_btsocket_sco_node == NULL)
1800 		return (EINVAL);
1801 
1802 	mtx_lock(&pcb->pcb_mtx);
1803 	bcopy(&pcb->src, &sa.sco_bdaddr, sizeof(sa.sco_bdaddr));
1804 	mtx_unlock(&pcb->pcb_mtx);
1805 
1806 	sa.sco_len = sizeof(sa);
1807 	sa.sco_family = AF_BLUETOOTH;
1808 
1809 	*nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT);
1810 
1811 	return ((*nam == NULL)? ENOMEM : 0);
1812 } /* ng_btsocket_sco_sockaddr */
1813 
1814 /*****************************************************************************
1815  *****************************************************************************
1816  **                              Misc. functions
1817  *****************************************************************************
1818  *****************************************************************************/
1819 
1820 /*
1821  * Look for the socket that listens on given bdaddr.
1822  * Returns exact or close match (if any).
1823  * Caller must hold ng_btsocket_sco_sockets_mtx.
1824  * Returns with locked pcb.
1825  */
1826 
1827 static ng_btsocket_sco_pcb_p
1828 ng_btsocket_sco_pcb_by_addr(bdaddr_p bdaddr)
1829 {
1830 	ng_btsocket_sco_pcb_p	p = NULL, p1 = NULL;
1831 
1832 	mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED);
1833 
1834 	LIST_FOREACH(p, &ng_btsocket_sco_sockets, next) {
1835 		mtx_lock(&p->pcb_mtx);
1836 
1837 		if (p->so == NULL || !(p->so->so_options & SO_ACCEPTCONN)) {
1838 			mtx_unlock(&p->pcb_mtx);
1839 			continue;
1840 		}
1841 
1842 		if (bcmp(&p->src, bdaddr, sizeof(p->src)) == 0)
1843 			return (p); /* return with locked pcb */
1844 
1845 		if (bcmp(&p->src, NG_HCI_BDADDR_ANY, sizeof(p->src)) == 0)
1846 			p1 = p;
1847 
1848 		mtx_unlock(&p->pcb_mtx);
1849 	}
1850 
1851 	if (p1 != NULL)
1852 		mtx_lock(&p1->pcb_mtx);
1853 
1854 	return (p1);
1855 } /* ng_btsocket_sco_pcb_by_addr */
1856 
1857 /*
1858  * Look for the socket that assigned to given source address and handle.
1859  * Caller must hold ng_btsocket_sco_sockets_mtx.
1860  * Returns with locked pcb.
1861  */
1862 
1863 static ng_btsocket_sco_pcb_p
1864 ng_btsocket_sco_pcb_by_handle(bdaddr_p src, int con_handle)
1865 {
1866 	ng_btsocket_sco_pcb_p	p = NULL;
1867 
1868 	mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED);
1869 
1870 	LIST_FOREACH(p, &ng_btsocket_sco_sockets, next) {
1871 		mtx_lock(&p->pcb_mtx);
1872 
1873 		if (p->con_handle == con_handle &&
1874 		    bcmp(src, &p->src, sizeof(p->src)) == 0)
1875 			return (p); /* return with locked pcb */
1876 
1877 		mtx_unlock(&p->pcb_mtx);
1878 	}
1879 
1880 	return (NULL);
1881 } /* ng_btsocket_sco_pcb_by_handle */
1882 
1883 /*
1884  * Look for the socket in CONNECTING state with given source and destination
1885  * addresses. Caller must hold ng_btsocket_sco_sockets_mtx.
1886  * Returns with locked pcb.
1887  */
1888 
1889 static ng_btsocket_sco_pcb_p
1890 ng_btsocket_sco_pcb_by_addrs(bdaddr_p src, bdaddr_p dst)
1891 {
1892 	ng_btsocket_sco_pcb_p	p = NULL;
1893 
1894 	mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED);
1895 
1896 	LIST_FOREACH(p, &ng_btsocket_sco_sockets, next) {
1897 		mtx_lock(&p->pcb_mtx);
1898 
1899 		if (p->state == NG_BTSOCKET_SCO_CONNECTING &&
1900 		    bcmp(src, &p->src, sizeof(p->src)) == 0 &&
1901 		    bcmp(dst, &p->dst, sizeof(p->dst)) == 0)
1902 			return (p); /* return with locked pcb */
1903 
1904 		mtx_unlock(&p->pcb_mtx);
1905 	}
1906 
1907 	return (NULL);
1908 } /* ng_btsocket_sco_pcb_by_addrs */
1909 
1910 /*
1911  * Set timeout on socket
1912  */
1913 
1914 static void
1915 ng_btsocket_sco_timeout(ng_btsocket_sco_pcb_p pcb)
1916 {
1917 	mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1918 
1919 	if (!(pcb->flags & NG_BTSOCKET_SCO_TIMO)) {
1920 		pcb->flags |= NG_BTSOCKET_SCO_TIMO;
1921 		callout_reset(&pcb->timo, bluetooth_sco_rtx_timeout(),
1922 					ng_btsocket_sco_process_timeout, pcb);
1923 	} else
1924 		KASSERT(0,
1925 ("%s: Duplicated socket timeout?!\n", __func__));
1926 } /* ng_btsocket_sco_timeout */
1927 
1928 /*
1929  * Unset timeout on socket
1930  */
1931 
1932 static void
1933 ng_btsocket_sco_untimeout(ng_btsocket_sco_pcb_p pcb)
1934 {
1935 	mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1936 
1937 	if (pcb->flags & NG_BTSOCKET_SCO_TIMO) {
1938 		callout_stop(&pcb->timo);
1939 		pcb->flags &= ~NG_BTSOCKET_SCO_TIMO;
1940 	} else
1941 		KASSERT(0,
1942 ("%s: No socket timeout?!\n", __func__));
1943 } /* ng_btsocket_sco_untimeout */
1944 
1945 /*
1946  * Process timeout on socket
1947  */
1948 
1949 static void
1950 ng_btsocket_sco_process_timeout(void *xpcb)
1951 {
1952 	ng_btsocket_sco_pcb_p	 pcb = (ng_btsocket_sco_pcb_p) xpcb;
1953 
1954 	mtx_lock(&pcb->pcb_mtx);
1955 
1956 	pcb->flags &= ~NG_BTSOCKET_SCO_TIMO;
1957 	pcb->so->so_error = ETIMEDOUT;
1958 
1959 	switch (pcb->state) {
1960 	case NG_BTSOCKET_SCO_CONNECTING:
1961 		/* Connect timeout - close the socket */
1962 		pcb->state = NG_BTSOCKET_SCO_CLOSED;
1963 		soisdisconnected(pcb->so);
1964 		break;
1965 
1966 	case NG_BTSOCKET_SCO_OPEN:
1967 		/* Send timeout - did not get NGM_HCI_SYNC_CON_QUEUE */
1968 		sbdroprecord(&pcb->so->so_snd);
1969 		sowwakeup(pcb->so);
1970 		/* XXX FIXME what to do with pcb->rt->pending??? */
1971 		break;
1972 
1973 	case NG_BTSOCKET_SCO_DISCONNECTING:
1974 		/* Disconnect timeout - disconnect the socket anyway */
1975 		pcb->state = NG_BTSOCKET_SCO_CLOSED;
1976 		soisdisconnected(pcb->so);
1977 		break;
1978 
1979 	default:
1980 		NG_BTSOCKET_SCO_ERR(
1981 "%s: Invalid socket state=%d\n", __func__, pcb->state);
1982 		break;
1983 	}
1984 
1985 	mtx_unlock(&pcb->pcb_mtx);
1986 } /* ng_btsocket_sco_process_timeout */
1987 
1988