xref: /freebsd/sys/netgraph/bluetooth/socket/ng_btsocket_sco.c (revision 47606b869eb149ebb7135d6594c3b9b9f05b9aed)
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;
475 
476 		/* pcb is locked */
477 
478 		CURVNET_SET(pcb->so->so_vnet);
479 		so1 = sonewconn(pcb->so, 0);
480 		CURVNET_RESTORE();
481 
482 		if (so1 == NULL) {
483 			status = 0x0d; /* Rejected due to limited resources */
484 			goto respond;
485 		}
486 
487 		/*
488 		 * If we got here than we have created new socket. So complete
489 		 * connection. If we we listening on specific address then copy
490 		 * source address from listening socket, otherwise copy source
491 		 * address from hook's routing information.
492 		 */
493 
494 		pcb1 = so2sco_pcb(so1);
495 		KASSERT((pcb1 != NULL),
496 ("%s: pcb1 == NULL\n", __func__));
497 
498  		mtx_lock(&pcb1->pcb_mtx);
499 
500 		if (bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(pcb->src)) != 0)
501 			bcopy(&pcb->src, &pcb1->src, sizeof(pcb1->src));
502 		else
503 			bcopy(&rt->src, &pcb1->src, sizeof(pcb1->src));
504 
505 		pcb1->flags &= ~NG_BTSOCKET_SCO_CLIENT;
506 
507 		bcopy(&ep->bdaddr, &pcb1->dst, sizeof(pcb1->dst));
508 		pcb1->rt = rt;
509 	} else
510 		/* Nobody listens on requested BDADDR */
511 		status = 0x1f; /* Unspecified Error */
512 
513 respond:
514 	error = ng_btsocket_sco_send_lp_con_rsp(rt, &ep->bdaddr, status);
515 	if (pcb1 != NULL) {
516 		if (error != 0) {
517 			pcb1->so->so_error = error;
518 			pcb1->state = NG_BTSOCKET_SCO_CLOSED;
519 			soisdisconnected(pcb1->so);
520 		} else {
521 			pcb1->state = NG_BTSOCKET_SCO_CONNECTING;
522 			soisconnecting(pcb1->so);
523 
524 			ng_btsocket_sco_timeout(pcb1);
525 		}
526 
527 		mtx_unlock(&pcb1->pcb_mtx);
528 	}
529 
530 	if (pcb != NULL)
531 		mtx_unlock(&pcb->pcb_mtx);
532 
533 	mtx_unlock(&ng_btsocket_sco_sockets_mtx);
534 
535 	return (error);
536 } /* ng_btsocket_sco_process_lp_con_ind */
537 
538 /*
539  * Process LP_DisconnectInd indicator
540  */
541 
542 static int
543 ng_btsocket_sco_process_lp_discon_ind(struct ng_mesg *msg,
544 		ng_btsocket_sco_rtentry_p rt)
545 {
546 	ng_hci_lp_discon_ind_ep	*ep = NULL;
547 	ng_btsocket_sco_pcb_t	*pcb = NULL;
548 
549 	/* Check message */
550 	if (msg->header.arglen != sizeof(*ep))
551 		return (EMSGSIZE);
552 
553 	ep = (ng_hci_lp_discon_ind_ep *)(msg->data);
554 
555 	mtx_lock(&ng_btsocket_sco_sockets_mtx);
556 
557 	/* Look for the socket with given channel ID */
558 	pcb = ng_btsocket_sco_pcb_by_handle(&rt->src, ep->con_handle);
559 	if (pcb == NULL) {
560 		mtx_unlock(&ng_btsocket_sco_sockets_mtx);
561 		return (0);
562 	}
563 
564 	/*
565 	 * Disconnect the socket. If there was any pending request we can
566 	 * not do anything here anyway.
567 	 */
568 
569 	/* pcb is locked */
570 
571        	NG_BTSOCKET_SCO_INFO(
572 "%s: Got LP_DisconnectInd indicator, src bdaddr=%x:%x:%x:%x:%x:%x, " \
573 "dst bdaddr=%x:%x:%x:%x:%x:%x, handle=%d, state=%d\n",
574 		__func__,
575 		pcb->src.b[5], pcb->src.b[4], pcb->src.b[3],
576 		pcb->src.b[2], pcb->src.b[1], pcb->src.b[0],
577 		pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3],
578 		pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0],
579 		pcb->con_handle, pcb->state);
580 
581 	if (pcb->flags & NG_BTSOCKET_SCO_TIMO)
582 		ng_btsocket_sco_untimeout(pcb);
583 
584 	pcb->state = NG_BTSOCKET_SCO_CLOSED;
585 	soisdisconnected(pcb->so);
586 
587 	mtx_unlock(&pcb->pcb_mtx);
588 	mtx_unlock(&ng_btsocket_sco_sockets_mtx);
589 
590 	return (0);
591 } /* ng_btsocket_sco_process_lp_discon_ind */
592 
593 /*
594  * Send LP_ConnectReq request
595  */
596 
597 static int
598 ng_btsocket_sco_send_lp_con_req(ng_btsocket_sco_pcb_p pcb)
599 {
600 	struct ng_mesg		*msg = NULL;
601 	ng_hci_lp_con_req_ep	*ep = NULL;
602 	int			 error = 0;
603 
604 	mtx_assert(&pcb->pcb_mtx, MA_OWNED);
605 
606 	if (pcb->rt == NULL ||
607 	    pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook))
608 		return (ENETDOWN);
609 
610 	NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_REQ,
611 		sizeof(*ep), M_NOWAIT);
612 	if (msg == NULL)
613 		return (ENOMEM);
614 
615 	ep = (ng_hci_lp_con_req_ep *)(msg->data);
616 	ep->link_type = NG_HCI_LINK_SCO;
617 	bcopy(&pcb->dst, &ep->bdaddr, sizeof(ep->bdaddr));
618 
619 	NG_SEND_MSG_HOOK(error, ng_btsocket_sco_node, msg, pcb->rt->hook, 0);
620 
621 	return (error);
622 } /* ng_btsocket_sco_send_lp_con_req */
623 
624 /*
625  * Send LP_ConnectRsp response
626  */
627 
628 static int
629 ng_btsocket_sco_send_lp_con_rsp(ng_btsocket_sco_rtentry_p rt, bdaddr_p dst, int status)
630 {
631 	struct ng_mesg		*msg = NULL;
632 	ng_hci_lp_con_rsp_ep	*ep = NULL;
633 	int			 error = 0;
634 
635 	if (rt == NULL || rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
636 		return (ENETDOWN);
637 
638 	NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_RSP,
639 		sizeof(*ep), M_NOWAIT);
640 	if (msg == NULL)
641 		return (ENOMEM);
642 
643 	ep = (ng_hci_lp_con_rsp_ep *)(msg->data);
644 	ep->status = status;
645 	ep->link_type = NG_HCI_LINK_SCO;
646 	bcopy(dst, &ep->bdaddr, sizeof(ep->bdaddr));
647 
648 	NG_SEND_MSG_HOOK(error, ng_btsocket_sco_node, msg, rt->hook, 0);
649 
650 	return (error);
651 } /* ng_btsocket_sco_send_lp_con_rsp */
652 
653 /*
654  * Send LP_DisconReq request
655  */
656 
657 static int
658 ng_btsocket_sco_send_lp_discon_req(ng_btsocket_sco_pcb_p pcb)
659 {
660 	struct ng_mesg		*msg = NULL;
661 	ng_hci_lp_discon_req_ep	*ep = NULL;
662 	int			 error = 0;
663 
664 	mtx_assert(&pcb->pcb_mtx, MA_OWNED);
665 
666 	if (pcb->rt == NULL ||
667 	    pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook))
668 		return (ENETDOWN);
669 
670 	NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_DISCON_REQ,
671 		sizeof(*ep), M_NOWAIT);
672 	if (msg == NULL)
673 		return (ENOMEM);
674 
675 	ep = (ng_hci_lp_discon_req_ep *)(msg->data);
676 	ep->con_handle = pcb->con_handle;
677 	ep->reason = 0x13; /* User Ended Connection */
678 
679 	NG_SEND_MSG_HOOK(error, ng_btsocket_sco_node, msg, pcb->rt->hook, 0);
680 
681 	return (error);
682 } /* ng_btsocket_sco_send_lp_discon_req */
683 
684 /*****************************************************************************
685  *****************************************************************************
686  **                              Socket interface
687  *****************************************************************************
688  *****************************************************************************/
689 
690 /*
691  * SCO sockets data input routine
692  */
693 
694 static void
695 ng_btsocket_sco_data_input(struct mbuf *m, hook_p hook)
696 {
697 	ng_hci_scodata_pkt_t		*hdr = NULL;
698 	ng_btsocket_sco_pcb_t		*pcb = NULL;
699 	ng_btsocket_sco_rtentry_t	*rt = NULL;
700 	u_int16_t			 con_handle;
701 
702 	if (hook == NULL) {
703 		NG_BTSOCKET_SCO_ALERT(
704 "%s: Invalid source hook for SCO data packet\n", __func__);
705 		goto drop;
706 	}
707 
708 	rt = (ng_btsocket_sco_rtentry_t *) NG_HOOK_PRIVATE(hook);
709 	if (rt == NULL) {
710 		NG_BTSOCKET_SCO_ALERT(
711 "%s: Could not find out source bdaddr for SCO data packet\n", __func__);
712 		goto drop;
713 	}
714 
715 	/* Make sure we can access header */
716 	if (m->m_pkthdr.len < sizeof(*hdr)) {
717 		NG_BTSOCKET_SCO_ERR(
718 "%s: SCO data packet too small, len=%d\n", __func__, m->m_pkthdr.len);
719 		goto drop;
720 	}
721 
722 	if (m->m_len < sizeof(*hdr)) {
723 		m = m_pullup(m, sizeof(*hdr));
724 		if (m == NULL)
725 			goto drop;
726 	}
727 
728 	/* Strip SCO packet header and verify packet length */
729 	hdr = mtod(m, ng_hci_scodata_pkt_t *);
730 	m_adj(m, sizeof(*hdr));
731 
732 	if (hdr->length != m->m_pkthdr.len) {
733 		NG_BTSOCKET_SCO_ERR(
734 "%s: Bad SCO data packet length, len=%d, length=%d\n",
735 			__func__, m->m_pkthdr.len, hdr->length);
736 		goto drop;
737 	}
738 
739 	/*
740 	 * Now process packet
741 	 */
742 
743 	con_handle = NG_HCI_CON_HANDLE(le16toh(hdr->con_handle));
744 
745 	NG_BTSOCKET_SCO_INFO(
746 "%s: Received SCO data packet: src bdaddr=%x:%x:%x:%x:%x:%x, handle=%d, " \
747 "length=%d\n",	__func__,
748 		rt->src.b[5], rt->src.b[4], rt->src.b[3],
749 		rt->src.b[2], rt->src.b[1], rt->src.b[0],
750 		con_handle, hdr->length);
751 
752 	mtx_lock(&ng_btsocket_sco_sockets_mtx);
753 
754 	/* Find socket */
755 	pcb = ng_btsocket_sco_pcb_by_handle(&rt->src, con_handle);
756 	if (pcb == NULL) {
757 		mtx_unlock(&ng_btsocket_sco_sockets_mtx);
758 		goto drop;
759 	}
760 
761 	/* pcb is locked */
762 
763 	if (pcb->state != NG_BTSOCKET_SCO_OPEN) {
764 		NG_BTSOCKET_SCO_ERR(
765 "%s: No connected socket found, src bdaddr=%x:%x:%x:%x:%x:%x, state=%d\n",
766 			__func__,
767 			rt->src.b[5], rt->src.b[4], rt->src.b[3],
768 			rt->src.b[2], rt->src.b[1], rt->src.b[0],
769 			pcb->state);
770 
771 		mtx_unlock(&pcb->pcb_mtx);
772 		mtx_unlock(&ng_btsocket_sco_sockets_mtx);
773 		goto drop;
774 	}
775 
776 	/* Check if we have enough space in socket receive queue */
777 	if (m->m_pkthdr.len > sbspace(&pcb->so->so_rcv)) {
778 		NG_BTSOCKET_SCO_ERR(
779 "%s: Not enough space in socket receive queue. Dropping SCO data packet, " \
780 "src bdaddr=%x:%x:%x:%x:%x:%x, len=%d, space=%ld\n",
781 			__func__,
782 			rt->src.b[5], rt->src.b[4], rt->src.b[3],
783 			rt->src.b[2], rt->src.b[1], rt->src.b[0],
784 			m->m_pkthdr.len,
785 			sbspace(&pcb->so->so_rcv));
786 
787 		mtx_unlock(&pcb->pcb_mtx);
788 		mtx_unlock(&ng_btsocket_sco_sockets_mtx);
789 		goto drop;
790 	}
791 
792 	/* Append packet to the socket receive queue and wakeup */
793 	sbappendrecord(&pcb->so->so_rcv, m);
794 	m = NULL;
795 
796 	sorwakeup(pcb->so);
797 
798 	mtx_unlock(&pcb->pcb_mtx);
799 	mtx_unlock(&ng_btsocket_sco_sockets_mtx);
800 drop:
801 	NG_FREE_M(m); /* checks for m != NULL */
802 } /* ng_btsocket_sco_data_input */
803 
804 /*
805  * SCO sockets default message input routine
806  */
807 
808 static void
809 ng_btsocket_sco_default_msg_input(struct ng_mesg *msg, hook_p hook)
810 {
811 	ng_btsocket_sco_rtentry_t	*rt = NULL;
812 
813 	if (hook == NULL || NG_HOOK_NOT_VALID(hook))
814 		return;
815 
816 	rt = (ng_btsocket_sco_rtentry_t *) NG_HOOK_PRIVATE(hook);
817 
818 	switch (msg->header.cmd) {
819 	case NGM_HCI_NODE_UP: {
820 		ng_hci_node_up_ep	*ep = NULL;
821 
822 		if (msg->header.arglen != sizeof(*ep))
823 			break;
824 
825 		ep = (ng_hci_node_up_ep *)(msg->data);
826 		if (bcmp(&ep->bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
827 			break;
828 
829 		if (rt == NULL) {
830 			rt = malloc(sizeof(*rt),
831 				M_NETGRAPH_BTSOCKET_SCO, M_NOWAIT|M_ZERO);
832 			if (rt == NULL)
833 				break;
834 
835 			NG_HOOK_SET_PRIVATE(hook, rt);
836 
837 			mtx_lock(&ng_btsocket_sco_rt_mtx);
838 
839 			LIST_INSERT_HEAD(&ng_btsocket_sco_rt, rt, next);
840 		} else
841 			mtx_lock(&ng_btsocket_sco_rt_mtx);
842 
843 		bcopy(&ep->bdaddr, &rt->src, sizeof(rt->src));
844 		rt->pkt_size = (ep->pkt_size == 0)? 60 : ep->pkt_size;
845 		rt->num_pkts = ep->num_pkts;
846 		rt->hook = hook;
847 
848 		mtx_unlock(&ng_btsocket_sco_rt_mtx);
849 
850 		NG_BTSOCKET_SCO_INFO(
851 "%s: Updating hook \"%s\", src bdaddr=%x:%x:%x:%x:%x:%x, pkt_size=%d, " \
852 "num_pkts=%d\n",	__func__, NG_HOOK_NAME(hook),
853 			rt->src.b[5], rt->src.b[4], rt->src.b[3],
854 			rt->src.b[2], rt->src.b[1], rt->src.b[0],
855 			rt->pkt_size, rt->num_pkts);
856 		} break;
857 
858 	case NGM_HCI_SYNC_CON_QUEUE: {
859 		ng_hci_sync_con_queue_ep	*ep = NULL;
860 		ng_btsocket_sco_pcb_t		*pcb = NULL;
861 
862 		if (rt == NULL || msg->header.arglen != sizeof(*ep))
863 			break;
864 
865 		ep = (ng_hci_sync_con_queue_ep *)(msg->data);
866 
867 		rt->pending -= ep->completed;
868 		if (rt->pending < 0) {
869 			NG_BTSOCKET_SCO_WARN(
870 "%s: Pending packet counter is out of sync! bdaddr=%x:%x:%x:%x:%x:%x, " \
871 "handle=%d, pending=%d, completed=%d\n",
872 				__func__,
873 				rt->src.b[5], rt->src.b[4], rt->src.b[3],
874 				rt->src.b[2], rt->src.b[1], rt->src.b[0],
875 				ep->con_handle, rt->pending,
876 				ep->completed);
877 
878 			rt->pending = 0;
879 		}
880 
881 		mtx_lock(&ng_btsocket_sco_sockets_mtx);
882 
883 		/* Find socket */
884 		pcb = ng_btsocket_sco_pcb_by_handle(&rt->src, ep->con_handle);
885 		if (pcb == NULL) {
886 			mtx_unlock(&ng_btsocket_sco_sockets_mtx);
887 			break;
888 		}
889 
890 		/* pcb is locked */
891 
892 		/* Check state */
893 		if (pcb->state == NG_BTSOCKET_SCO_OPEN) {
894 			/* Remove timeout */
895 			ng_btsocket_sco_untimeout(pcb);
896 
897 			/* Drop completed packets from the send queue */
898 			for (; ep->completed > 0; ep->completed --)
899 				sbdroprecord(&pcb->so->so_snd);
900 
901 			/* Send more if we have any */
902 			if (sbavail(&pcb->so->so_snd) > 0)
903 				if (ng_btsocket_sco_send2(pcb) == 0)
904 					ng_btsocket_sco_timeout(pcb);
905 
906 			/* Wake up writers */
907 			sowwakeup(pcb->so);
908 		}
909 
910 		mtx_unlock(&pcb->pcb_mtx);
911 		mtx_unlock(&ng_btsocket_sco_sockets_mtx);
912 	} break;
913 
914 	default:
915 		NG_BTSOCKET_SCO_WARN(
916 "%s: Unknown message, cmd=%d\n", __func__, msg->header.cmd);
917 		break;
918 	}
919 
920 	NG_FREE_MSG(msg); /* Checks for msg != NULL */
921 } /* ng_btsocket_sco_default_msg_input */
922 
923 /*
924  * SCO sockets LP message input routine
925  */
926 
927 static void
928 ng_btsocket_sco_lp_msg_input(struct ng_mesg *msg, hook_p hook)
929 {
930 	ng_btsocket_sco_rtentry_p	 rt = NULL;
931 
932 	if (hook == NULL) {
933 		NG_BTSOCKET_SCO_ALERT(
934 "%s: Invalid source hook for LP message\n", __func__);
935 		goto drop;
936 	}
937 
938 	rt = (ng_btsocket_sco_rtentry_p) NG_HOOK_PRIVATE(hook);
939 	if (rt == NULL) {
940 		NG_BTSOCKET_SCO_ALERT(
941 "%s: Could not find out source bdaddr for LP message\n", __func__);
942 		goto drop;
943 	}
944 
945 	switch (msg->header.cmd) {
946 	case NGM_HCI_LP_CON_CFM: /* Connection Confirmation Event */
947 		ng_btsocket_sco_process_lp_con_cfm(msg, rt);
948 		break;
949 
950 	case NGM_HCI_LP_CON_IND: /* Connection Indication Event */
951 		ng_btsocket_sco_process_lp_con_ind(msg, rt);
952 		break;
953 
954 	case NGM_HCI_LP_DISCON_IND: /* Disconnection Indication Event */
955 		ng_btsocket_sco_process_lp_discon_ind(msg, rt);
956 		break;
957 
958 	/* XXX FIXME add other LP messages */
959 
960 	default:
961 		NG_BTSOCKET_SCO_WARN(
962 "%s: Unknown LP message, cmd=%d\n", __func__, msg->header.cmd);
963 		break;
964 	}
965 drop:
966 	NG_FREE_MSG(msg);
967 } /* ng_btsocket_sco_lp_msg_input */
968 
969 /*
970  * SCO sockets input routine
971  */
972 
973 static void
974 ng_btsocket_sco_input(void *context, int pending)
975 {
976 	item_p	item = NULL;
977 	hook_p	hook = NULL;
978 
979 	for (;;) {
980 		mtx_lock(&ng_btsocket_sco_queue_mtx);
981 		NG_BT_ITEMQ_DEQUEUE(&ng_btsocket_sco_queue, item);
982 		mtx_unlock(&ng_btsocket_sco_queue_mtx);
983 
984 		if (item == NULL)
985 			break;
986 
987 		NGI_GET_HOOK(item, hook);
988 		if (hook != NULL && NG_HOOK_NOT_VALID(hook))
989 			goto drop;
990 
991 		switch(item->el_flags & NGQF_TYPE) {
992 		case NGQF_DATA: {
993 			struct mbuf     *m = NULL;
994 
995 			NGI_GET_M(item, m);
996 			ng_btsocket_sco_data_input(m, hook);
997 			} break;
998 
999 		case NGQF_MESG: {
1000 			struct ng_mesg  *msg = NULL;
1001 
1002 			NGI_GET_MSG(item, msg);
1003 
1004 			switch (msg->header.cmd) {
1005 			case NGM_HCI_LP_CON_CFM:
1006 			case NGM_HCI_LP_CON_IND:
1007 			case NGM_HCI_LP_DISCON_IND:
1008 			/* XXX FIXME add other LP messages */
1009 				ng_btsocket_sco_lp_msg_input(msg, hook);
1010 				break;
1011 
1012 			default:
1013 				ng_btsocket_sco_default_msg_input(msg, hook);
1014 				break;
1015 			}
1016 			} break;
1017 
1018 		default:
1019 			KASSERT(0,
1020 ("%s: invalid item type=%ld\n", __func__, (item->el_flags & NGQF_TYPE)));
1021 			break;
1022 		}
1023 drop:
1024 		if (hook != NULL)
1025 			NG_HOOK_UNREF(hook);
1026 
1027 		NG_FREE_ITEM(item);
1028 	}
1029 } /* ng_btsocket_sco_input */
1030 
1031 /*
1032  * Route cleanup task. Gets scheduled when hook is disconnected. Here we
1033  * will find all sockets that use "invalid" hook and disconnect them.
1034  */
1035 
1036 static void
1037 ng_btsocket_sco_rtclean(void *context, int pending)
1038 {
1039 	ng_btsocket_sco_pcb_p		pcb = NULL, pcb_next = NULL;
1040 	ng_btsocket_sco_rtentry_p	rt = NULL;
1041 
1042 	/*
1043 	 * First disconnect all sockets that use "invalid" hook
1044 	 */
1045 
1046 	mtx_lock(&ng_btsocket_sco_sockets_mtx);
1047 
1048 	for(pcb = LIST_FIRST(&ng_btsocket_sco_sockets); pcb != NULL; ) {
1049 		mtx_lock(&pcb->pcb_mtx);
1050 		pcb_next = LIST_NEXT(pcb, next);
1051 
1052 		if (pcb->rt != NULL &&
1053 		    pcb->rt->hook != NULL && NG_HOOK_NOT_VALID(pcb->rt->hook)) {
1054 			if (pcb->flags & NG_BTSOCKET_SCO_TIMO)
1055 				ng_btsocket_sco_untimeout(pcb);
1056 
1057 			pcb->rt = NULL;
1058 			pcb->so->so_error = ENETDOWN;
1059 			pcb->state = NG_BTSOCKET_SCO_CLOSED;
1060 			soisdisconnected(pcb->so);
1061 		}
1062 
1063 		mtx_unlock(&pcb->pcb_mtx);
1064 		pcb = pcb_next;
1065 	}
1066 
1067 	mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1068 
1069 	/*
1070 	 * Now cleanup routing table
1071 	 */
1072 
1073 	mtx_lock(&ng_btsocket_sco_rt_mtx);
1074 
1075 	for (rt = LIST_FIRST(&ng_btsocket_sco_rt); rt != NULL; ) {
1076 		ng_btsocket_sco_rtentry_p	rt_next = LIST_NEXT(rt, next);
1077 
1078 		if (rt->hook != NULL && NG_HOOK_NOT_VALID(rt->hook)) {
1079 			LIST_REMOVE(rt, next);
1080 
1081 			NG_HOOK_SET_PRIVATE(rt->hook, NULL);
1082 			NG_HOOK_UNREF(rt->hook); /* Remove extra reference */
1083 
1084 			bzero(rt, sizeof(*rt));
1085 			free(rt, M_NETGRAPH_BTSOCKET_SCO);
1086 		}
1087 
1088 		rt = rt_next;
1089 	}
1090 
1091 	mtx_unlock(&ng_btsocket_sco_rt_mtx);
1092 } /* ng_btsocket_sco_rtclean */
1093 
1094 /*
1095  * Initialize everything
1096  */
1097 
1098 void
1099 ng_btsocket_sco_init(void)
1100 {
1101 	int	error = 0;
1102 
1103 	/* Skip initialization of globals for non-default instances. */
1104 	if (!IS_DEFAULT_VNET(curvnet))
1105 		return;
1106 
1107 	ng_btsocket_sco_node = NULL;
1108 	ng_btsocket_sco_debug_level = NG_BTSOCKET_WARN_LEVEL;
1109 
1110 	/* Register Netgraph node type */
1111 	error = ng_newtype(&typestruct);
1112 	if (error != 0) {
1113 		NG_BTSOCKET_SCO_ALERT(
1114 "%s: Could not register Netgraph node type, error=%d\n", __func__, error);
1115 
1116                 return;
1117 	}
1118 
1119 	/* Create Netgrapg node */
1120 	error = ng_make_node_common(&typestruct, &ng_btsocket_sco_node);
1121 	if (error != 0) {
1122 		NG_BTSOCKET_SCO_ALERT(
1123 "%s: Could not create Netgraph node, error=%d\n", __func__, error);
1124 
1125 		ng_btsocket_sco_node = NULL;
1126 
1127 		return;
1128 	}
1129 
1130 	error = ng_name_node(ng_btsocket_sco_node, NG_BTSOCKET_SCO_NODE_TYPE);
1131 	if (error != 0) {
1132 		NG_BTSOCKET_SCO_ALERT(
1133 "%s: Could not name Netgraph node, error=%d\n", __func__, error);
1134 
1135 		NG_NODE_UNREF(ng_btsocket_sco_node);
1136 		ng_btsocket_sco_node = NULL;
1137 
1138 		return;
1139 	}
1140 
1141 	/* Create input queue */
1142 	NG_BT_ITEMQ_INIT(&ng_btsocket_sco_queue, 300);
1143 	mtx_init(&ng_btsocket_sco_queue_mtx,
1144 		"btsocks_sco_queue_mtx", NULL, MTX_DEF);
1145 	TASK_INIT(&ng_btsocket_sco_queue_task, 0,
1146 		ng_btsocket_sco_input, NULL);
1147 
1148 	/* Create list of sockets */
1149 	LIST_INIT(&ng_btsocket_sco_sockets);
1150 	mtx_init(&ng_btsocket_sco_sockets_mtx,
1151 		"btsocks_sco_sockets_mtx", NULL, MTX_DEF);
1152 
1153 	/* Routing table */
1154 	LIST_INIT(&ng_btsocket_sco_rt);
1155 	mtx_init(&ng_btsocket_sco_rt_mtx,
1156 		"btsocks_sco_rt_mtx", NULL, MTX_DEF);
1157 	TASK_INIT(&ng_btsocket_sco_rt_task, 0,
1158 		ng_btsocket_sco_rtclean, NULL);
1159 } /* ng_btsocket_sco_init */
1160 
1161 /*
1162  * Abort connection on socket
1163  */
1164 
1165 void
1166 ng_btsocket_sco_abort(struct socket *so)
1167 {
1168 	so->so_error = ECONNABORTED;
1169 
1170 	(void) ng_btsocket_sco_disconnect(so);
1171 } /* ng_btsocket_sco_abort */
1172 
1173 void
1174 ng_btsocket_sco_close(struct socket *so)
1175 {
1176 	(void) ng_btsocket_sco_disconnect(so);
1177 } /* ng_btsocket_sco_close */
1178 
1179 /*
1180  * Accept connection on socket. Nothing to do here, socket must be connected
1181  * and ready, so just return peer address and be done with it.
1182  */
1183 
1184 int
1185 ng_btsocket_sco_accept(struct socket *so, struct sockaddr **nam)
1186 {
1187 	if (ng_btsocket_sco_node == NULL)
1188 		return (EINVAL);
1189 
1190 	return (ng_btsocket_sco_peeraddr(so, nam));
1191 } /* ng_btsocket_sco_accept */
1192 
1193 /*
1194  * Create and attach new socket
1195  */
1196 
1197 int
1198 ng_btsocket_sco_attach(struct socket *so, int proto, struct thread *td)
1199 {
1200 	ng_btsocket_sco_pcb_p	pcb = so2sco_pcb(so);
1201 	int			error;
1202 
1203 	/* Check socket and protocol */
1204 	if (ng_btsocket_sco_node == NULL)
1205 		return (EPROTONOSUPPORT);
1206 	if (so->so_type != SOCK_SEQPACKET)
1207 		return (ESOCKTNOSUPPORT);
1208 
1209 #if 0 /* XXX sonewconn() calls "pru_attach" with proto == 0 */
1210 	if (proto != 0)
1211 		if (proto != BLUETOOTH_PROTO_SCO)
1212 			return (EPROTONOSUPPORT);
1213 #endif /* XXX */
1214 
1215 	if (pcb != NULL)
1216 		return (EISCONN);
1217 
1218 	/* Reserve send and receive space if it is not reserved yet */
1219 	if ((so->so_snd.sb_hiwat == 0) || (so->so_rcv.sb_hiwat == 0)) {
1220 		error = soreserve(so, NG_BTSOCKET_SCO_SENDSPACE,
1221 					NG_BTSOCKET_SCO_RECVSPACE);
1222 		if (error != 0)
1223 			return (error);
1224 	}
1225 
1226 	/* Allocate the PCB */
1227         pcb = malloc(sizeof(*pcb),
1228 		M_NETGRAPH_BTSOCKET_SCO, M_NOWAIT | M_ZERO);
1229         if (pcb == NULL)
1230                 return (ENOMEM);
1231 
1232 	/* Link the PCB and the socket */
1233 	so->so_pcb = (caddr_t) pcb;
1234 	pcb->so = so;
1235 	pcb->state = NG_BTSOCKET_SCO_CLOSED;
1236 
1237 	callout_init(&pcb->timo, 1);
1238 
1239 	/*
1240 	 * Mark PCB mutex as DUPOK to prevent "duplicated lock of
1241 	 * the same type" message. When accepting new SCO connection
1242 	 * ng_btsocket_sco_process_lp_con_ind() holds both PCB mutexes
1243 	 * for "old" (accepting) PCB and "new" (created) PCB.
1244 	 */
1245 
1246 	mtx_init(&pcb->pcb_mtx, "btsocks_sco_pcb_mtx", NULL,
1247 		MTX_DEF|MTX_DUPOK);
1248 
1249 	/*
1250 	 * Add the PCB to the list
1251 	 *
1252 	 * XXX FIXME VERY IMPORTANT!
1253 	 *
1254 	 * This is totally FUBAR. We could get here in two cases:
1255 	 *
1256 	 * 1) When user calls socket()
1257 	 * 2) When we need to accept new incoming connection and call
1258 	 *    sonewconn()
1259 	 *
1260 	 * In the first case we must acquire ng_btsocket_sco_sockets_mtx.
1261 	 * In the second case we hold ng_btsocket_sco_sockets_mtx already.
1262 	 * So we now need to distinguish between these cases. From reading
1263 	 * /sys/kern/uipc_socket2.c we can find out that sonewconn() calls
1264 	 * pru_attach with proto == 0 and td == NULL. For now use this fact
1265 	 * to figure out if we were called from socket() or from sonewconn().
1266 	 */
1267 
1268 	if (td != NULL)
1269 		mtx_lock(&ng_btsocket_sco_sockets_mtx);
1270 	else
1271 		mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED);
1272 
1273 	LIST_INSERT_HEAD(&ng_btsocket_sco_sockets, pcb, next);
1274 
1275 	if (td != NULL)
1276 		mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1277 
1278         return (0);
1279 } /* ng_btsocket_sco_attach */
1280 
1281 /*
1282  * Bind socket
1283  */
1284 
1285 int
1286 ng_btsocket_sco_bind(struct socket *so, struct sockaddr *nam,
1287 		struct thread *td)
1288 {
1289 	ng_btsocket_sco_pcb_t	*pcb = NULL;
1290 	struct sockaddr_sco	*sa = (struct sockaddr_sco *) nam;
1291 
1292 	if (ng_btsocket_sco_node == NULL)
1293 		return (EINVAL);
1294 
1295 	/* Verify address */
1296 	if (sa == NULL)
1297 		return (EINVAL);
1298 	if (sa->sco_family != AF_BLUETOOTH)
1299 		return (EAFNOSUPPORT);
1300 	if (sa->sco_len != sizeof(*sa))
1301 		return (EINVAL);
1302 
1303 	mtx_lock(&ng_btsocket_sco_sockets_mtx);
1304 
1305 	/*
1306 	 * Check if other socket has this address already (look for exact
1307 	 * match in bdaddr) and assign socket address if it's available.
1308 	 */
1309 
1310 	if (bcmp(&sa->sco_bdaddr, NG_HCI_BDADDR_ANY, sizeof(sa->sco_bdaddr)) != 0) {
1311  		LIST_FOREACH(pcb, &ng_btsocket_sco_sockets, next) {
1312 			mtx_lock(&pcb->pcb_mtx);
1313 
1314 			if (bcmp(&pcb->src, &sa->sco_bdaddr, sizeof(bdaddr_t)) == 0) {
1315 				mtx_unlock(&pcb->pcb_mtx);
1316 				mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1317 
1318 				return (EADDRINUSE);
1319 			}
1320 
1321 			mtx_unlock(&pcb->pcb_mtx);
1322 		}
1323 
1324 	}
1325 
1326 	pcb = so2sco_pcb(so);
1327 	if (pcb == NULL) {
1328 		mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1329 		return (EINVAL);
1330 	}
1331 
1332 	mtx_lock(&pcb->pcb_mtx);
1333 	bcopy(&sa->sco_bdaddr, &pcb->src, sizeof(pcb->src));
1334 	mtx_unlock(&pcb->pcb_mtx);
1335 
1336 	mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1337 
1338 	return (0);
1339 } /* ng_btsocket_sco_bind */
1340 
1341 /*
1342  * Connect socket
1343  */
1344 
1345 int
1346 ng_btsocket_sco_connect(struct socket *so, struct sockaddr *nam,
1347 		struct thread *td)
1348 {
1349 	ng_btsocket_sco_pcb_t		*pcb = so2sco_pcb(so);
1350 	struct sockaddr_sco		*sa = (struct sockaddr_sco *) nam;
1351 	ng_btsocket_sco_rtentry_t	*rt = NULL;
1352 	int				 have_src, error = 0;
1353 
1354 	/* Check socket */
1355 	if (pcb == NULL)
1356 		return (EINVAL);
1357 	if (ng_btsocket_sco_node == NULL)
1358 		return (EINVAL);
1359 
1360 	/* Verify address */
1361 	if (sa == NULL)
1362 		return (EINVAL);
1363 	if (sa->sco_family != AF_BLUETOOTH)
1364 		return (EAFNOSUPPORT);
1365 	if (sa->sco_len != sizeof(*sa))
1366 		return (EINVAL);
1367 	if (bcmp(&sa->sco_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
1368 		return (EDESTADDRREQ);
1369 
1370 	/*
1371 	 * Routing. Socket should be bound to some source address. The source
1372 	 * address can be ANY. Destination address must be set and it must not
1373 	 * be ANY. If source address is ANY then find first rtentry that has
1374 	 * src != dst.
1375 	 */
1376 
1377 	mtx_lock(&ng_btsocket_sco_rt_mtx);
1378 	mtx_lock(&pcb->pcb_mtx);
1379 
1380 	if (pcb->state == NG_BTSOCKET_SCO_CONNECTING) {
1381 		mtx_unlock(&pcb->pcb_mtx);
1382 		mtx_unlock(&ng_btsocket_sco_rt_mtx);
1383 
1384 		return (EINPROGRESS);
1385 	}
1386 
1387 	if (bcmp(&sa->sco_bdaddr, &pcb->src, sizeof(pcb->src)) == 0) {
1388 		mtx_unlock(&pcb->pcb_mtx);
1389 		mtx_unlock(&ng_btsocket_sco_rt_mtx);
1390 
1391 		return (EINVAL);
1392 	}
1393 
1394 	/* Send destination address and PSM */
1395 	bcopy(&sa->sco_bdaddr, &pcb->dst, sizeof(pcb->dst));
1396 
1397 	pcb->rt = NULL;
1398 	have_src = bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(pcb->src));
1399 
1400 	LIST_FOREACH(rt, &ng_btsocket_sco_rt, next) {
1401 		if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
1402 			continue;
1403 
1404 		/* Match src and dst */
1405 		if (have_src) {
1406 			if (bcmp(&pcb->src, &rt->src, sizeof(rt->src)) == 0)
1407 				break;
1408 		} else {
1409 			if (bcmp(&pcb->dst, &rt->src, sizeof(rt->src)) != 0)
1410 				break;
1411 		}
1412 	}
1413 
1414 	if (rt != NULL) {
1415 		pcb->rt = rt;
1416 
1417 		if (!have_src)
1418 			bcopy(&rt->src, &pcb->src, sizeof(pcb->src));
1419 	} else
1420 		error = EHOSTUNREACH;
1421 
1422 	/*
1423 	 * Send LP_Connect request
1424 	 */
1425 
1426 	if (error == 0) {
1427 		error = ng_btsocket_sco_send_lp_con_req(pcb);
1428 		if (error == 0) {
1429 			pcb->flags |= NG_BTSOCKET_SCO_CLIENT;
1430 			pcb->state = NG_BTSOCKET_SCO_CONNECTING;
1431 			soisconnecting(pcb->so);
1432 
1433 			ng_btsocket_sco_timeout(pcb);
1434 		}
1435 	}
1436 
1437 	mtx_unlock(&pcb->pcb_mtx);
1438 	mtx_unlock(&ng_btsocket_sco_rt_mtx);
1439 
1440 	return (error);
1441 } /* ng_btsocket_sco_connect */
1442 
1443 /*
1444  * Process ioctl's calls on socket
1445  */
1446 
1447 int
1448 ng_btsocket_sco_control(struct socket *so, u_long cmd, caddr_t data,
1449 		struct ifnet *ifp, struct thread *td)
1450 {
1451 	return (EINVAL);
1452 } /* ng_btsocket_sco_control */
1453 
1454 /*
1455  * Process getsockopt/setsockopt system calls
1456  */
1457 
1458 int
1459 ng_btsocket_sco_ctloutput(struct socket *so, struct sockopt *sopt)
1460 {
1461 	ng_btsocket_sco_pcb_p	pcb = so2sco_pcb(so);
1462         int			error, tmp;
1463 
1464 	if (ng_btsocket_sco_node == NULL)
1465 		return (EINVAL);
1466 	if (pcb == NULL)
1467 		return (EINVAL);
1468 
1469 	if (sopt->sopt_level != SOL_SCO)
1470 		return (0);
1471 
1472 	mtx_lock(&pcb->pcb_mtx);
1473 
1474 	switch (sopt->sopt_dir) {
1475 	case SOPT_GET:
1476 		if (pcb->state != NG_BTSOCKET_SCO_OPEN) {
1477 			error = ENOTCONN;
1478 			break;
1479 		}
1480 
1481 		switch (sopt->sopt_name) {
1482 		case SO_SCO_MTU:
1483 			tmp = pcb->rt->pkt_size;
1484 			error = sooptcopyout(sopt, &tmp, sizeof(tmp));
1485 			break;
1486 
1487 		case SO_SCO_CONNINFO:
1488 			tmp = pcb->con_handle;
1489 			error = sooptcopyout(sopt, &tmp, sizeof(tmp));
1490 			break;
1491 
1492 		default:
1493 			error = EINVAL;
1494 			break;
1495 		}
1496 		break;
1497 
1498 	case SOPT_SET:
1499 		error = ENOPROTOOPT;
1500 		break;
1501 
1502 	default:
1503 		error = EINVAL;
1504 		break;
1505 	}
1506 
1507 	mtx_unlock(&pcb->pcb_mtx);
1508 
1509 	return (error);
1510 } /* ng_btsocket_sco_ctloutput */
1511 
1512 /*
1513  * Detach and destroy socket
1514  */
1515 
1516 void
1517 ng_btsocket_sco_detach(struct socket *so)
1518 {
1519 	ng_btsocket_sco_pcb_p	pcb = so2sco_pcb(so);
1520 
1521 	KASSERT(pcb != NULL, ("ng_btsocket_sco_detach: pcb == NULL"));
1522 
1523 	if (ng_btsocket_sco_node == NULL)
1524 		return;
1525 
1526 	mtx_lock(&ng_btsocket_sco_sockets_mtx);
1527 	mtx_lock(&pcb->pcb_mtx);
1528 
1529 	if (pcb->flags & NG_BTSOCKET_SCO_TIMO)
1530 		ng_btsocket_sco_untimeout(pcb);
1531 
1532 	if (pcb->state == NG_BTSOCKET_SCO_OPEN)
1533 		ng_btsocket_sco_send_lp_discon_req(pcb);
1534 
1535 	pcb->state = NG_BTSOCKET_SCO_CLOSED;
1536 
1537 	LIST_REMOVE(pcb, next);
1538 
1539 	mtx_unlock(&pcb->pcb_mtx);
1540 	mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1541 
1542 	mtx_destroy(&pcb->pcb_mtx);
1543 	bzero(pcb, sizeof(*pcb));
1544 	free(pcb, M_NETGRAPH_BTSOCKET_SCO);
1545 
1546 	soisdisconnected(so);
1547 	so->so_pcb = NULL;
1548 } /* ng_btsocket_sco_detach */
1549 
1550 /*
1551  * Disconnect socket
1552  */
1553 
1554 int
1555 ng_btsocket_sco_disconnect(struct socket *so)
1556 {
1557 	ng_btsocket_sco_pcb_p	pcb = so2sco_pcb(so);
1558 
1559 	if (pcb == NULL)
1560 		return (EINVAL);
1561 	if (ng_btsocket_sco_node == NULL)
1562 		return (EINVAL);
1563 
1564 	mtx_lock(&pcb->pcb_mtx);
1565 
1566 	if (pcb->state == NG_BTSOCKET_SCO_DISCONNECTING) {
1567 		mtx_unlock(&pcb->pcb_mtx);
1568 
1569 		return (EINPROGRESS);
1570 	}
1571 
1572 	if (pcb->flags & NG_BTSOCKET_SCO_TIMO)
1573 		ng_btsocket_sco_untimeout(pcb);
1574 
1575 	if (pcb->state == NG_BTSOCKET_SCO_OPEN) {
1576 		ng_btsocket_sco_send_lp_discon_req(pcb);
1577 
1578 		pcb->state = NG_BTSOCKET_SCO_DISCONNECTING;
1579 		soisdisconnecting(so);
1580 
1581 		ng_btsocket_sco_timeout(pcb);
1582 	} else {
1583 		pcb->state = NG_BTSOCKET_SCO_CLOSED;
1584 		soisdisconnected(so);
1585 	}
1586 
1587 	mtx_unlock(&pcb->pcb_mtx);
1588 
1589 	return (0);
1590 } /* ng_btsocket_sco_disconnect */
1591 
1592 /*
1593  * Listen on socket
1594  */
1595 
1596 int
1597 ng_btsocket_sco_listen(struct socket *so, int backlog, struct thread *td)
1598 {
1599 	ng_btsocket_sco_pcb_p	pcb = so2sco_pcb(so);
1600 	int			error;
1601 
1602 	if (pcb == NULL)
1603 		return (EINVAL);
1604 	if (ng_btsocket_sco_node == NULL)
1605 		return (EINVAL);
1606 
1607 	SOCK_LOCK(so);
1608 	mtx_lock(&pcb->pcb_mtx);
1609 
1610 	error = solisten_proto_check(so);
1611 	if (error != 0)
1612 		goto out;
1613 #if 0
1614 	if (bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0) {
1615 		error = EDESTADDRREQ;
1616 		goto out;
1617 	}
1618 #endif
1619 	solisten_proto(so, backlog);
1620 out:
1621 	mtx_unlock(&pcb->pcb_mtx);
1622 	SOCK_UNLOCK(so);
1623 
1624 	return (error);
1625 } /* ng_btsocket_listen */
1626 
1627 /*
1628  * Get peer address
1629  */
1630 
1631 int
1632 ng_btsocket_sco_peeraddr(struct socket *so, struct sockaddr **nam)
1633 {
1634 	ng_btsocket_sco_pcb_p	pcb = so2sco_pcb(so);
1635 	struct sockaddr_sco	sa;
1636 
1637 	if (pcb == NULL)
1638 		return (EINVAL);
1639 	if (ng_btsocket_sco_node == NULL)
1640 		return (EINVAL);
1641 
1642 	mtx_lock(&pcb->pcb_mtx);
1643 	bcopy(&pcb->dst, &sa.sco_bdaddr, sizeof(sa.sco_bdaddr));
1644 	mtx_unlock(&pcb->pcb_mtx);
1645 
1646 	sa.sco_len = sizeof(sa);
1647 	sa.sco_family = AF_BLUETOOTH;
1648 
1649 	*nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT);
1650 
1651 	return ((*nam == NULL)? ENOMEM : 0);
1652 } /* ng_btsocket_sco_peeraddr */
1653 
1654 /*
1655  * Send data to socket
1656  */
1657 
1658 int
1659 ng_btsocket_sco_send(struct socket *so, int flags, struct mbuf *m,
1660 		struct sockaddr *nam, struct mbuf *control, struct thread *td)
1661 {
1662 	ng_btsocket_sco_pcb_t	*pcb = so2sco_pcb(so);
1663 	int			 error = 0;
1664 
1665 	if (ng_btsocket_sco_node == NULL) {
1666 		error = ENETDOWN;
1667 		goto drop;
1668 	}
1669 
1670 	/* Check socket and input */
1671 	if (pcb == NULL || m == NULL || control != NULL) {
1672 		error = EINVAL;
1673 		goto drop;
1674 	}
1675 
1676 	mtx_lock(&pcb->pcb_mtx);
1677 
1678 	/* Make sure socket is connected */
1679 	if (pcb->state != NG_BTSOCKET_SCO_OPEN) {
1680 		mtx_unlock(&pcb->pcb_mtx);
1681 		error = ENOTCONN;
1682 		goto drop;
1683 	}
1684 
1685 	/* Check route */
1686 	if (pcb->rt == NULL ||
1687 	    pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook)) {
1688 		mtx_unlock(&pcb->pcb_mtx);
1689 		error = ENETDOWN;
1690 		goto drop;
1691 	}
1692 
1693 	/* Check packet size */
1694 	if (m->m_pkthdr.len > pcb->rt->pkt_size) {
1695 		NG_BTSOCKET_SCO_ERR(
1696 "%s: Packet too big, len=%d, pkt_size=%d\n",
1697 			__func__, m->m_pkthdr.len, pcb->rt->pkt_size);
1698 
1699 		mtx_unlock(&pcb->pcb_mtx);
1700 		error = EMSGSIZE;
1701 		goto drop;
1702 	}
1703 
1704 	/*
1705 	 * First put packet on socket send queue. Then check if we have
1706 	 * pending timeout. If we do not have timeout then we must send
1707 	 * packet and schedule timeout. Otherwise do nothing and wait for
1708 	 * NGM_HCI_SYNC_CON_QUEUE message.
1709 	 */
1710 
1711 	sbappendrecord(&pcb->so->so_snd, m);
1712 	m = NULL;
1713 
1714 	if (!(pcb->flags & NG_BTSOCKET_SCO_TIMO)) {
1715 		error = ng_btsocket_sco_send2(pcb);
1716 		if (error == 0)
1717 			ng_btsocket_sco_timeout(pcb);
1718 		else
1719 			sbdroprecord(&pcb->so->so_snd); /* XXX */
1720 	}
1721 
1722 	mtx_unlock(&pcb->pcb_mtx);
1723 drop:
1724 	NG_FREE_M(m); /* checks for != NULL */
1725 	NG_FREE_M(control);
1726 
1727 	return (error);
1728 } /* ng_btsocket_sco_send */
1729 
1730 /*
1731  * Send first packet in the socket queue to the SCO layer
1732  */
1733 
1734 static int
1735 ng_btsocket_sco_send2(ng_btsocket_sco_pcb_p pcb)
1736 {
1737 	struct  mbuf		*m = NULL;
1738 	ng_hci_scodata_pkt_t	*hdr = NULL;
1739 	int			 error = 0;
1740 
1741 	mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1742 
1743 	while (pcb->rt->pending < pcb->rt->num_pkts &&
1744 	       sbavail(&pcb->so->so_snd) > 0) {
1745 		/* Get a copy of the first packet on send queue */
1746 		m = m_dup(pcb->so->so_snd.sb_mb, M_NOWAIT);
1747 		if (m == NULL) {
1748 			error = ENOBUFS;
1749 			break;
1750 		}
1751 
1752 		/* Create SCO packet header */
1753 		M_PREPEND(m, sizeof(*hdr), M_NOWAIT);
1754 		if (m != NULL)
1755 			if (m->m_len < sizeof(*hdr))
1756 				m = m_pullup(m, sizeof(*hdr));
1757 
1758 		if (m == NULL) {
1759 			error = ENOBUFS;
1760 			break;
1761 		}
1762 
1763 		/* Fill in the header */
1764 		hdr = mtod(m, ng_hci_scodata_pkt_t *);
1765 		hdr->type = NG_HCI_SCO_DATA_PKT;
1766 		hdr->con_handle = htole16(NG_HCI_MK_CON_HANDLE(pcb->con_handle, 0, 0));
1767 		hdr->length = m->m_pkthdr.len - sizeof(*hdr);
1768 
1769 		/* Send packet */
1770 		NG_SEND_DATA_ONLY(error, pcb->rt->hook, m);
1771 		if (error != 0)
1772 			break;
1773 
1774 		pcb->rt->pending ++;
1775 	}
1776 
1777 	return ((pcb->rt->pending > 0)? 0 : error);
1778 } /* ng_btsocket_sco_send2 */
1779 
1780 /*
1781  * Get socket address
1782  */
1783 
1784 int
1785 ng_btsocket_sco_sockaddr(struct socket *so, struct sockaddr **nam)
1786 {
1787 	ng_btsocket_sco_pcb_p	pcb = so2sco_pcb(so);
1788 	struct sockaddr_sco	sa;
1789 
1790 	if (pcb == NULL)
1791 		return (EINVAL);
1792 	if (ng_btsocket_sco_node == NULL)
1793 		return (EINVAL);
1794 
1795 	mtx_lock(&pcb->pcb_mtx);
1796 	bcopy(&pcb->src, &sa.sco_bdaddr, sizeof(sa.sco_bdaddr));
1797 	mtx_unlock(&pcb->pcb_mtx);
1798 
1799 	sa.sco_len = sizeof(sa);
1800 	sa.sco_family = AF_BLUETOOTH;
1801 
1802 	*nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT);
1803 
1804 	return ((*nam == NULL)? ENOMEM : 0);
1805 } /* ng_btsocket_sco_sockaddr */
1806 
1807 /*****************************************************************************
1808  *****************************************************************************
1809  **                              Misc. functions
1810  *****************************************************************************
1811  *****************************************************************************/
1812 
1813 /*
1814  * Look for the socket that listens on given bdaddr.
1815  * Returns exact or close match (if any).
1816  * Caller must hold ng_btsocket_sco_sockets_mtx.
1817  * Returns with locked pcb.
1818  */
1819 
1820 static ng_btsocket_sco_pcb_p
1821 ng_btsocket_sco_pcb_by_addr(bdaddr_p bdaddr)
1822 {
1823 	ng_btsocket_sco_pcb_p	p = NULL, p1 = NULL;
1824 
1825 	mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED);
1826 
1827 	LIST_FOREACH(p, &ng_btsocket_sco_sockets, next) {
1828 		mtx_lock(&p->pcb_mtx);
1829 
1830 		if (p->so == NULL || !(p->so->so_options & SO_ACCEPTCONN)) {
1831 			mtx_unlock(&p->pcb_mtx);
1832 			continue;
1833 		}
1834 
1835 		if (bcmp(&p->src, bdaddr, sizeof(p->src)) == 0)
1836 			return (p); /* return with locked pcb */
1837 
1838 		if (bcmp(&p->src, NG_HCI_BDADDR_ANY, sizeof(p->src)) == 0)
1839 			p1 = p;
1840 
1841 		mtx_unlock(&p->pcb_mtx);
1842 	}
1843 
1844 	if (p1 != NULL)
1845 		mtx_lock(&p1->pcb_mtx);
1846 
1847 	return (p1);
1848 } /* ng_btsocket_sco_pcb_by_addr */
1849 
1850 /*
1851  * Look for the socket that assigned to given source address and handle.
1852  * Caller must hold ng_btsocket_sco_sockets_mtx.
1853  * Returns with locked pcb.
1854  */
1855 
1856 static ng_btsocket_sco_pcb_p
1857 ng_btsocket_sco_pcb_by_handle(bdaddr_p src, int con_handle)
1858 {
1859 	ng_btsocket_sco_pcb_p	p = NULL;
1860 
1861 	mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED);
1862 
1863 	LIST_FOREACH(p, &ng_btsocket_sco_sockets, next) {
1864 		mtx_lock(&p->pcb_mtx);
1865 
1866 		if (p->con_handle == con_handle &&
1867 		    bcmp(src, &p->src, sizeof(p->src)) == 0)
1868 			return (p); /* return with locked pcb */
1869 
1870 		mtx_unlock(&p->pcb_mtx);
1871 	}
1872 
1873 	return (NULL);
1874 } /* ng_btsocket_sco_pcb_by_handle */
1875 
1876 /*
1877  * Look for the socket in CONNECTING state with given source and destination
1878  * addresses. Caller must hold ng_btsocket_sco_sockets_mtx.
1879  * Returns with locked pcb.
1880  */
1881 
1882 static ng_btsocket_sco_pcb_p
1883 ng_btsocket_sco_pcb_by_addrs(bdaddr_p src, bdaddr_p dst)
1884 {
1885 	ng_btsocket_sco_pcb_p	p = NULL;
1886 
1887 	mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED);
1888 
1889 	LIST_FOREACH(p, &ng_btsocket_sco_sockets, next) {
1890 		mtx_lock(&p->pcb_mtx);
1891 
1892 		if (p->state == NG_BTSOCKET_SCO_CONNECTING &&
1893 		    bcmp(src, &p->src, sizeof(p->src)) == 0 &&
1894 		    bcmp(dst, &p->dst, sizeof(p->dst)) == 0)
1895 			return (p); /* return with locked pcb */
1896 
1897 		mtx_unlock(&p->pcb_mtx);
1898 	}
1899 
1900 	return (NULL);
1901 } /* ng_btsocket_sco_pcb_by_addrs */
1902 
1903 /*
1904  * Set timeout on socket
1905  */
1906 
1907 static void
1908 ng_btsocket_sco_timeout(ng_btsocket_sco_pcb_p pcb)
1909 {
1910 	mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1911 
1912 	if (!(pcb->flags & NG_BTSOCKET_SCO_TIMO)) {
1913 		pcb->flags |= NG_BTSOCKET_SCO_TIMO;
1914 		callout_reset(&pcb->timo, bluetooth_sco_rtx_timeout(),
1915 					ng_btsocket_sco_process_timeout, pcb);
1916 	} else
1917 		KASSERT(0,
1918 ("%s: Duplicated socket timeout?!\n", __func__));
1919 } /* ng_btsocket_sco_timeout */
1920 
1921 /*
1922  * Unset timeout on socket
1923  */
1924 
1925 static void
1926 ng_btsocket_sco_untimeout(ng_btsocket_sco_pcb_p pcb)
1927 {
1928 	mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1929 
1930 	if (pcb->flags & NG_BTSOCKET_SCO_TIMO) {
1931 		callout_stop(&pcb->timo);
1932 		pcb->flags &= ~NG_BTSOCKET_SCO_TIMO;
1933 	} else
1934 		KASSERT(0,
1935 ("%s: No socket timeout?!\n", __func__));
1936 } /* ng_btsocket_sco_untimeout */
1937 
1938 /*
1939  * Process timeout on socket
1940  */
1941 
1942 static void
1943 ng_btsocket_sco_process_timeout(void *xpcb)
1944 {
1945 	ng_btsocket_sco_pcb_p	 pcb = (ng_btsocket_sco_pcb_p) xpcb;
1946 
1947 	mtx_lock(&pcb->pcb_mtx);
1948 
1949 	pcb->flags &= ~NG_BTSOCKET_SCO_TIMO;
1950 	pcb->so->so_error = ETIMEDOUT;
1951 
1952 	switch (pcb->state) {
1953 	case NG_BTSOCKET_SCO_CONNECTING:
1954 		/* Connect timeout - close the socket */
1955 		pcb->state = NG_BTSOCKET_SCO_CLOSED;
1956 		soisdisconnected(pcb->so);
1957 		break;
1958 
1959 	case NG_BTSOCKET_SCO_OPEN:
1960 		/* Send timeout - did not get NGM_HCI_SYNC_CON_QUEUE */
1961 		sbdroprecord(&pcb->so->so_snd);
1962 		sowwakeup(pcb->so);
1963 		/* XXX FIXME what to do with pcb->rt->pending??? */
1964 		break;
1965 
1966 	case NG_BTSOCKET_SCO_DISCONNECTING:
1967 		/* Disconnect timeout - disconnect the socket anyway */
1968 		pcb->state = NG_BTSOCKET_SCO_CLOSED;
1969 		soisdisconnected(pcb->so);
1970 		break;
1971 
1972 	default:
1973 		NG_BTSOCKET_SCO_ERR(
1974 "%s: Invalid socket state=%d\n", __func__, pcb->state);
1975 		break;
1976 	}
1977 
1978 	mtx_unlock(&pcb->pcb_mtx);
1979 } /* ng_btsocket_sco_process_timeout */
1980 
1981