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