6 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
8 * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * $Id: ng_btsocket_sco.c,v 1.2 2005/10/31 18:08:51 max Exp $
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/bitstring.h>
39 #include <sys/domain.h>
40 #include <sys/endian.h>
41 #include <sys/errno.h>
42 #include <sys/filedesc.h>
43 #include <sys/ioccom.h>
44 #include <sys/kernel.h>
46 #include <sys/malloc.h>
48 #include <sys/mutex.h>
49 #include <sys/protosw.h>
50 #include <sys/queue.h>
51 #include <sys/socket.h>
52 #include <sys/socketvar.h>
53 #include <sys/sysctl.h>
54 #include <sys/taskqueue.h>
58 #include <netgraph/ng_message.h>
59 #include <netgraph/netgraph.h>
60 #include <netgraph/bluetooth/include/ng_bluetooth.h>
61 #include <netgraph/bluetooth/include/ng_hci.h>
62 #include <netgraph/bluetooth/include/ng_l2cap.h>
63 #include <netgraph/bluetooth/include/ng_btsocket.h>
64 #include <netgraph/bluetooth/include/ng_btsocket_sco.h>
67 #ifdef NG_SEPARATE_MALLOC
68 static MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_SCO, "netgraph_btsocks_sco",
69 "Netgraph Bluetooth SCO sockets");
71 #define M_NETGRAPH_BTSOCKET_SCO M_NETGRAPH
72 #endif /* NG_SEPARATE_MALLOC */
74 /* Netgraph node methods */
75 static ng_constructor_t ng_btsocket_sco_node_constructor;
76 static ng_rcvmsg_t ng_btsocket_sco_node_rcvmsg;
77 static ng_shutdown_t ng_btsocket_sco_node_shutdown;
78 static ng_newhook_t ng_btsocket_sco_node_newhook;
79 static ng_connect_t ng_btsocket_sco_node_connect;
80 static ng_rcvdata_t ng_btsocket_sco_node_rcvdata;
81 static ng_disconnect_t ng_btsocket_sco_node_disconnect;
83 static void ng_btsocket_sco_input (void *, int);
84 static void ng_btsocket_sco_rtclean (void *, int);
86 /* Netgraph type descriptor */
87 static struct ng_type typestruct = {
88 .version = NG_ABI_VERSION,
89 .name = NG_BTSOCKET_SCO_NODE_TYPE,
90 .constructor = ng_btsocket_sco_node_constructor,
91 .rcvmsg = ng_btsocket_sco_node_rcvmsg,
92 .shutdown = ng_btsocket_sco_node_shutdown,
93 .newhook = ng_btsocket_sco_node_newhook,
94 .connect = ng_btsocket_sco_node_connect,
95 .rcvdata = ng_btsocket_sco_node_rcvdata,
96 .disconnect = ng_btsocket_sco_node_disconnect,
100 static u_int32_t ng_btsocket_sco_debug_level;
101 static node_p ng_btsocket_sco_node;
102 static struct ng_bt_itemq ng_btsocket_sco_queue;
103 static struct mtx ng_btsocket_sco_queue_mtx;
104 static struct task ng_btsocket_sco_queue_task;
105 static struct mtx ng_btsocket_sco_sockets_mtx;
106 static LIST_HEAD(, ng_btsocket_sco_pcb) ng_btsocket_sco_sockets;
107 static LIST_HEAD(, ng_btsocket_sco_rtentry) ng_btsocket_sco_rt;
108 static struct mtx ng_btsocket_sco_rt_mtx;
109 static struct task ng_btsocket_sco_rt_task;
110 static struct timeval ng_btsocket_sco_lasttime;
111 static int ng_btsocket_sco_curpps;
114 SYSCTL_DECL(_net_bluetooth_sco_sockets);
115 static SYSCTL_NODE(_net_bluetooth_sco_sockets, OID_AUTO, seq,
116 CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
117 "Bluetooth SEQPACKET SCO sockets family");
118 SYSCTL_UINT(_net_bluetooth_sco_sockets_seq, OID_AUTO, debug_level,
120 &ng_btsocket_sco_debug_level, NG_BTSOCKET_WARN_LEVEL,
121 "Bluetooth SEQPACKET SCO sockets debug level");
122 SYSCTL_UINT(_net_bluetooth_sco_sockets_seq, OID_AUTO, queue_len,
124 &ng_btsocket_sco_queue.len, 0,
125 "Bluetooth SEQPACKET SCO sockets input queue length");
126 SYSCTL_UINT(_net_bluetooth_sco_sockets_seq, OID_AUTO, queue_maxlen,
128 &ng_btsocket_sco_queue.maxlen, 0,
129 "Bluetooth SEQPACKET SCO sockets input queue max. length");
130 SYSCTL_UINT(_net_bluetooth_sco_sockets_seq, OID_AUTO, queue_drops,
132 &ng_btsocket_sco_queue.drops, 0,
133 "Bluetooth SEQPACKET SCO sockets input queue drops");
136 #define NG_BTSOCKET_SCO_INFO \
137 if (ng_btsocket_sco_debug_level >= NG_BTSOCKET_INFO_LEVEL && \
138 ppsratecheck(&ng_btsocket_sco_lasttime, &ng_btsocket_sco_curpps, 1)) \
141 #define NG_BTSOCKET_SCO_WARN \
142 if (ng_btsocket_sco_debug_level >= NG_BTSOCKET_WARN_LEVEL && \
143 ppsratecheck(&ng_btsocket_sco_lasttime, &ng_btsocket_sco_curpps, 1)) \
146 #define NG_BTSOCKET_SCO_ERR \
147 if (ng_btsocket_sco_debug_level >= NG_BTSOCKET_ERR_LEVEL && \
148 ppsratecheck(&ng_btsocket_sco_lasttime, &ng_btsocket_sco_curpps, 1)) \
151 #define NG_BTSOCKET_SCO_ALERT \
152 if (ng_btsocket_sco_debug_level >= NG_BTSOCKET_ALERT_LEVEL && \
153 ppsratecheck(&ng_btsocket_sco_lasttime, &ng_btsocket_sco_curpps, 1)) \
157 * Netgraph message processing routines
160 static int ng_btsocket_sco_process_lp_con_cfm
161 (struct ng_mesg *, ng_btsocket_sco_rtentry_p);
162 static int ng_btsocket_sco_process_lp_con_ind
163 (struct ng_mesg *, ng_btsocket_sco_rtentry_p);
164 static int ng_btsocket_sco_process_lp_discon_ind
165 (struct ng_mesg *, ng_btsocket_sco_rtentry_p);
168 * Send LP messages to the lower layer
171 static int ng_btsocket_sco_send_lp_con_req
172 (ng_btsocket_sco_pcb_p);
173 static int ng_btsocket_sco_send_lp_con_rsp
174 (ng_btsocket_sco_rtentry_p, bdaddr_p, int);
175 static int ng_btsocket_sco_send_lp_discon_req
176 (ng_btsocket_sco_pcb_p);
178 static int ng_btsocket_sco_send2
179 (ng_btsocket_sco_pcb_p);
182 * Timeout processing routines
185 static void ng_btsocket_sco_timeout (ng_btsocket_sco_pcb_p);
186 static void ng_btsocket_sco_untimeout (ng_btsocket_sco_pcb_p);
187 static void ng_btsocket_sco_process_timeout (void *);
193 static ng_btsocket_sco_pcb_p ng_btsocket_sco_pcb_by_addr(bdaddr_p);
194 static ng_btsocket_sco_pcb_p ng_btsocket_sco_pcb_by_handle(bdaddr_p, int);
195 static ng_btsocket_sco_pcb_p ng_btsocket_sco_pcb_by_addrs(bdaddr_p, bdaddr_p);
197 #define ng_btsocket_sco_wakeup_input_task() \
198 taskqueue_enqueue(taskqueue_swi, &ng_btsocket_sco_queue_task)
200 #define ng_btsocket_sco_wakeup_route_task() \
201 taskqueue_enqueue(taskqueue_swi, &ng_btsocket_sco_rt_task)
203 /*****************************************************************************
204 *****************************************************************************
205 ** Netgraph node interface
206 *****************************************************************************
207 *****************************************************************************/
210 * Netgraph node constructor. Do not allow to create node of this type.
214 ng_btsocket_sco_node_constructor(node_p node)
217 } /* ng_btsocket_sco_node_constructor */
220 * Do local shutdown processing. Let old node go and create new fresh one.
224 ng_btsocket_sco_node_shutdown(node_p node)
230 /* Create new node */
231 error = ng_make_node_common(&typestruct, &ng_btsocket_sco_node);
233 NG_BTSOCKET_SCO_ALERT(
234 "%s: Could not create Netgraph node, error=%d\n", __func__, error);
236 ng_btsocket_sco_node = NULL;
241 error = ng_name_node(ng_btsocket_sco_node,
242 NG_BTSOCKET_SCO_NODE_TYPE);
244 NG_BTSOCKET_SCO_ALERT(
245 "%s: Could not name Netgraph node, error=%d\n", __func__, error);
247 NG_NODE_UNREF(ng_btsocket_sco_node);
248 ng_btsocket_sco_node = NULL;
254 } /* ng_btsocket_sco_node_shutdown */
257 * We allow any hook to be connected to the node.
261 ng_btsocket_sco_node_newhook(node_p node, hook_p hook, char const *name)
264 } /* ng_btsocket_sco_node_newhook */
267 * Just say "YEP, that's OK by me!"
271 ng_btsocket_sco_node_connect(hook_p hook)
273 NG_HOOK_SET_PRIVATE(hook, NULL);
274 NG_HOOK_REF(hook); /* Keep extra reference to the hook */
277 NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
278 NG_HOOK_FORCE_QUEUE(hook);
282 } /* ng_btsocket_sco_node_connect */
285 * Hook disconnection. Schedule route cleanup task
289 ng_btsocket_sco_node_disconnect(hook_p hook)
292 * If hook has private information than we must have this hook in
293 * the routing table and must schedule cleaning for the routing table.
294 * Otherwise hook was connected but we never got "hook_info" message,
295 * so we have never added this hook to the routing table and it save
299 if (NG_HOOK_PRIVATE(hook) != NULL)
300 return (ng_btsocket_sco_wakeup_route_task());
302 NG_HOOK_UNREF(hook); /* Remove extra reference */
305 } /* ng_btsocket_sco_node_disconnect */
308 * Process incoming messages
312 ng_btsocket_sco_node_rcvmsg(node_p node, item_p item, hook_p hook)
314 struct ng_mesg *msg = NGI_MSG(item); /* item still has message */
317 if (msg != NULL && msg->header.typecookie == NGM_HCI_COOKIE) {
318 mtx_lock(&ng_btsocket_sco_queue_mtx);
319 if (NG_BT_ITEMQ_FULL(&ng_btsocket_sco_queue)) {
321 "%s: Input queue is full (msg)\n", __func__);
323 NG_BT_ITEMQ_DROP(&ng_btsocket_sco_queue);
329 NGI_SET_HOOK(item, hook);
332 NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_sco_queue, item);
333 error = ng_btsocket_sco_wakeup_input_task();
335 mtx_unlock(&ng_btsocket_sco_queue_mtx);
342 } /* ng_btsocket_sco_node_rcvmsg */
345 * Receive data on a hook
349 ng_btsocket_sco_node_rcvdata(hook_p hook, item_p item)
353 mtx_lock(&ng_btsocket_sco_queue_mtx);
354 if (NG_BT_ITEMQ_FULL(&ng_btsocket_sco_queue)) {
356 "%s: Input queue is full (data)\n", __func__);
358 NG_BT_ITEMQ_DROP(&ng_btsocket_sco_queue);
363 NGI_SET_HOOK(item, hook);
365 NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_sco_queue, item);
366 error = ng_btsocket_sco_wakeup_input_task();
368 mtx_unlock(&ng_btsocket_sco_queue_mtx);
371 } /* ng_btsocket_sco_node_rcvdata */
374 * Process LP_ConnectCfm event from the lower layer protocol
378 ng_btsocket_sco_process_lp_con_cfm(struct ng_mesg *msg,
379 ng_btsocket_sco_rtentry_p rt)
381 ng_hci_lp_con_cfm_ep *ep = NULL;
382 ng_btsocket_sco_pcb_t *pcb = NULL;
385 if (msg->header.arglen != sizeof(*ep))
388 ep = (ng_hci_lp_con_cfm_ep *)(msg->data);
390 mtx_lock(&ng_btsocket_sco_sockets_mtx);
392 /* Look for the socket with the token */
393 pcb = ng_btsocket_sco_pcb_by_addrs(&rt->src, &ep->bdaddr);
395 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
401 NG_BTSOCKET_SCO_INFO(
402 "%s: Got LP_ConnectCfm response, src bdaddr=%x:%x:%x:%x:%x:%x, " \
403 "dst bdaddr=%x:%x:%x:%x:%x:%x, status=%d, handle=%d, state=%d\n",
405 pcb->src.b[5], pcb->src.b[4], pcb->src.b[3],
406 pcb->src.b[2], pcb->src.b[1], pcb->src.b[0],
407 pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3],
408 pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0],
409 ep->status, ep->con_handle, pcb->state);
411 if (pcb->state != NG_BTSOCKET_SCO_CONNECTING) {
412 mtx_unlock(&pcb->pcb_mtx);
413 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
418 ng_btsocket_sco_untimeout(pcb);
420 if (ep->status == 0) {
422 * Connection is open. Update connection handle and
426 pcb->con_handle = ep->con_handle;
427 pcb->state = NG_BTSOCKET_SCO_OPEN;
428 soisconnected(pcb->so);
431 * We have failed to open connection, so disconnect the socket
434 pcb->so->so_error = ECONNREFUSED; /* XXX convert status ??? */
435 pcb->state = NG_BTSOCKET_SCO_CLOSED;
436 soisdisconnected(pcb->so);
439 mtx_unlock(&pcb->pcb_mtx);
440 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
443 } /* ng_btsocket_sco_process_lp_con_cfm */
446 * Process LP_ConnectInd indicator. Find socket that listens on address.
447 * Find exact or closest match.
451 ng_btsocket_sco_process_lp_con_ind(struct ng_mesg *msg,
452 ng_btsocket_sco_rtentry_p rt)
454 ng_hci_lp_con_ind_ep *ep = NULL;
455 ng_btsocket_sco_pcb_t *pcb = NULL, *pcb1 = NULL;
457 u_int16_t status = 0;
459 if (msg->header.arglen != sizeof(*ep))
462 ep = (ng_hci_lp_con_ind_ep *)(msg->data);
464 NG_BTSOCKET_SCO_INFO(
465 "%s: Got LP_ConnectInd indicator, src bdaddr=%x:%x:%x:%x:%x:%x, " \
466 "dst bdaddr=%x:%x:%x:%x:%x:%x\n",
468 rt->src.b[5], rt->src.b[4], rt->src.b[3],
469 rt->src.b[2], rt->src.b[1], rt->src.b[0],
470 ep->bdaddr.b[5], ep->bdaddr.b[4], ep->bdaddr.b[3],
471 ep->bdaddr.b[2], ep->bdaddr.b[1], ep->bdaddr.b[0]);
473 mtx_lock(&ng_btsocket_sco_sockets_mtx);
475 pcb = ng_btsocket_sco_pcb_by_addr(&rt->src);
481 CURVNET_SET(pcb->so->so_vnet);
482 so1 = sonewconn(pcb->so, 0);
486 status = 0x0d; /* Rejected due to limited resources */
491 * If we got here than we have created new socket. So complete
492 * connection. If we we listening on specific address then copy
493 * source address from listening socket, otherwise copy source
494 * address from hook's routing information.
497 pcb1 = so2sco_pcb(so1);
498 KASSERT((pcb1 != NULL),
499 ("%s: pcb1 == NULL\n", __func__));
501 mtx_lock(&pcb1->pcb_mtx);
503 if (bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(pcb->src)) != 0)
504 bcopy(&pcb->src, &pcb1->src, sizeof(pcb1->src));
506 bcopy(&rt->src, &pcb1->src, sizeof(pcb1->src));
508 pcb1->flags &= ~NG_BTSOCKET_SCO_CLIENT;
510 bcopy(&ep->bdaddr, &pcb1->dst, sizeof(pcb1->dst));
513 /* Nobody listens on requested BDADDR */
514 status = 0x1f; /* Unspecified Error */
517 error = ng_btsocket_sco_send_lp_con_rsp(rt, &ep->bdaddr, status);
520 pcb1->so->so_error = error;
521 pcb1->state = NG_BTSOCKET_SCO_CLOSED;
522 soisdisconnected(pcb1->so);
524 pcb1->state = NG_BTSOCKET_SCO_CONNECTING;
525 soisconnecting(pcb1->so);
527 ng_btsocket_sco_timeout(pcb1);
530 mtx_unlock(&pcb1->pcb_mtx);
534 mtx_unlock(&pcb->pcb_mtx);
536 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
539 } /* ng_btsocket_sco_process_lp_con_ind */
542 * Process LP_DisconnectInd indicator
546 ng_btsocket_sco_process_lp_discon_ind(struct ng_mesg *msg,
547 ng_btsocket_sco_rtentry_p rt)
549 ng_hci_lp_discon_ind_ep *ep = NULL;
550 ng_btsocket_sco_pcb_t *pcb = NULL;
553 if (msg->header.arglen != sizeof(*ep))
556 ep = (ng_hci_lp_discon_ind_ep *)(msg->data);
558 mtx_lock(&ng_btsocket_sco_sockets_mtx);
560 /* Look for the socket with given channel ID */
561 pcb = ng_btsocket_sco_pcb_by_handle(&rt->src, ep->con_handle);
563 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
568 * Disconnect the socket. If there was any pending request we can
569 * not do anything here anyway.
574 NG_BTSOCKET_SCO_INFO(
575 "%s: Got LP_DisconnectInd indicator, src bdaddr=%x:%x:%x:%x:%x:%x, " \
576 "dst bdaddr=%x:%x:%x:%x:%x:%x, handle=%d, state=%d\n",
578 pcb->src.b[5], pcb->src.b[4], pcb->src.b[3],
579 pcb->src.b[2], pcb->src.b[1], pcb->src.b[0],
580 pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3],
581 pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0],
582 pcb->con_handle, pcb->state);
584 if (pcb->flags & NG_BTSOCKET_SCO_TIMO)
585 ng_btsocket_sco_untimeout(pcb);
587 pcb->state = NG_BTSOCKET_SCO_CLOSED;
588 soisdisconnected(pcb->so);
590 mtx_unlock(&pcb->pcb_mtx);
591 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
594 } /* ng_btsocket_sco_process_lp_discon_ind */
597 * Send LP_ConnectReq request
601 ng_btsocket_sco_send_lp_con_req(ng_btsocket_sco_pcb_p pcb)
603 struct ng_mesg *msg = NULL;
604 ng_hci_lp_con_req_ep *ep = NULL;
607 mtx_assert(&pcb->pcb_mtx, MA_OWNED);
609 if (pcb->rt == NULL ||
610 pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook))
613 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_REQ,
614 sizeof(*ep), M_NOWAIT);
618 ep = (ng_hci_lp_con_req_ep *)(msg->data);
619 ep->link_type = NG_HCI_LINK_SCO;
620 bcopy(&pcb->dst, &ep->bdaddr, sizeof(ep->bdaddr));
622 NG_SEND_MSG_HOOK(error, ng_btsocket_sco_node, msg, pcb->rt->hook, 0);
625 } /* ng_btsocket_sco_send_lp_con_req */
628 * Send LP_ConnectRsp response
632 ng_btsocket_sco_send_lp_con_rsp(ng_btsocket_sco_rtentry_p rt, bdaddr_p dst, int status)
634 struct ng_mesg *msg = NULL;
635 ng_hci_lp_con_rsp_ep *ep = NULL;
638 if (rt == NULL || rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
641 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_RSP,
642 sizeof(*ep), M_NOWAIT);
646 ep = (ng_hci_lp_con_rsp_ep *)(msg->data);
648 ep->link_type = NG_HCI_LINK_SCO;
649 bcopy(dst, &ep->bdaddr, sizeof(ep->bdaddr));
651 NG_SEND_MSG_HOOK(error, ng_btsocket_sco_node, msg, rt->hook, 0);
654 } /* ng_btsocket_sco_send_lp_con_rsp */
657 * Send LP_DisconReq request
661 ng_btsocket_sco_send_lp_discon_req(ng_btsocket_sco_pcb_p pcb)
663 struct ng_mesg *msg = NULL;
664 ng_hci_lp_discon_req_ep *ep = NULL;
667 mtx_assert(&pcb->pcb_mtx, MA_OWNED);
669 if (pcb->rt == NULL ||
670 pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook))
673 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_DISCON_REQ,
674 sizeof(*ep), M_NOWAIT);
678 ep = (ng_hci_lp_discon_req_ep *)(msg->data);
679 ep->con_handle = pcb->con_handle;
680 ep->reason = 0x13; /* User Ended Connection */
682 NG_SEND_MSG_HOOK(error, ng_btsocket_sco_node, msg, pcb->rt->hook, 0);
685 } /* ng_btsocket_sco_send_lp_discon_req */
687 /*****************************************************************************
688 *****************************************************************************
690 *****************************************************************************
691 *****************************************************************************/
694 * SCO sockets data input routine
698 ng_btsocket_sco_data_input(struct mbuf *m, hook_p hook)
700 ng_hci_scodata_pkt_t *hdr = NULL;
701 ng_btsocket_sco_pcb_t *pcb = NULL;
702 ng_btsocket_sco_rtentry_t *rt = NULL;
703 u_int16_t con_handle;
706 NG_BTSOCKET_SCO_ALERT(
707 "%s: Invalid source hook for SCO data packet\n", __func__);
711 rt = (ng_btsocket_sco_rtentry_t *) NG_HOOK_PRIVATE(hook);
713 NG_BTSOCKET_SCO_ALERT(
714 "%s: Could not find out source bdaddr for SCO data packet\n", __func__);
718 /* Make sure we can access header */
719 if (m->m_pkthdr.len < sizeof(*hdr)) {
721 "%s: SCO data packet too small, len=%d\n", __func__, m->m_pkthdr.len);
725 if (m->m_len < sizeof(*hdr)) {
726 m = m_pullup(m, sizeof(*hdr));
731 /* Strip SCO packet header and verify packet length */
732 hdr = mtod(m, ng_hci_scodata_pkt_t *);
733 m_adj(m, sizeof(*hdr));
735 if (hdr->length != m->m_pkthdr.len) {
737 "%s: Bad SCO data packet length, len=%d, length=%d\n",
738 __func__, m->m_pkthdr.len, hdr->length);
746 con_handle = NG_HCI_CON_HANDLE(le16toh(hdr->con_handle));
748 NG_BTSOCKET_SCO_INFO(
749 "%s: Received SCO data packet: src bdaddr=%x:%x:%x:%x:%x:%x, handle=%d, " \
750 "length=%d\n", __func__,
751 rt->src.b[5], rt->src.b[4], rt->src.b[3],
752 rt->src.b[2], rt->src.b[1], rt->src.b[0],
753 con_handle, hdr->length);
755 mtx_lock(&ng_btsocket_sco_sockets_mtx);
758 pcb = ng_btsocket_sco_pcb_by_handle(&rt->src, con_handle);
760 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
766 if (pcb->state != NG_BTSOCKET_SCO_OPEN) {
768 "%s: No connected socket found, src bdaddr=%x:%x:%x:%x:%x:%x, state=%d\n",
770 rt->src.b[5], rt->src.b[4], rt->src.b[3],
771 rt->src.b[2], rt->src.b[1], rt->src.b[0],
774 mtx_unlock(&pcb->pcb_mtx);
775 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
779 /* Check if we have enough space in socket receive queue */
780 if (m->m_pkthdr.len > sbspace(&pcb->so->so_rcv)) {
782 "%s: Not enough space in socket receive queue. Dropping SCO data packet, " \
783 "src bdaddr=%x:%x:%x:%x:%x:%x, len=%d, space=%ld\n",
785 rt->src.b[5], rt->src.b[4], rt->src.b[3],
786 rt->src.b[2], rt->src.b[1], rt->src.b[0],
788 sbspace(&pcb->so->so_rcv));
790 mtx_unlock(&pcb->pcb_mtx);
791 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
795 /* Append packet to the socket receive queue and wakeup */
796 sbappendrecord(&pcb->so->so_rcv, m);
801 mtx_unlock(&pcb->pcb_mtx);
802 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
804 NG_FREE_M(m); /* checks for m != NULL */
805 } /* ng_btsocket_sco_data_input */
808 * SCO sockets default message input routine
812 ng_btsocket_sco_default_msg_input(struct ng_mesg *msg, hook_p hook)
814 ng_btsocket_sco_rtentry_t *rt = NULL;
816 if (hook == NULL || NG_HOOK_NOT_VALID(hook))
819 rt = (ng_btsocket_sco_rtentry_t *) NG_HOOK_PRIVATE(hook);
821 switch (msg->header.cmd) {
822 case NGM_HCI_NODE_UP: {
823 ng_hci_node_up_ep *ep = NULL;
825 if (msg->header.arglen != sizeof(*ep))
828 ep = (ng_hci_node_up_ep *)(msg->data);
829 if (bcmp(&ep->bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
833 rt = malloc(sizeof(*rt),
834 M_NETGRAPH_BTSOCKET_SCO, M_NOWAIT|M_ZERO);
838 NG_HOOK_SET_PRIVATE(hook, rt);
840 mtx_lock(&ng_btsocket_sco_rt_mtx);
842 LIST_INSERT_HEAD(&ng_btsocket_sco_rt, rt, next);
844 mtx_lock(&ng_btsocket_sco_rt_mtx);
846 bcopy(&ep->bdaddr, &rt->src, sizeof(rt->src));
847 rt->pkt_size = (ep->pkt_size == 0)? 60 : ep->pkt_size;
848 rt->num_pkts = ep->num_pkts;
851 mtx_unlock(&ng_btsocket_sco_rt_mtx);
853 NG_BTSOCKET_SCO_INFO(
854 "%s: Updating hook \"%s\", src bdaddr=%x:%x:%x:%x:%x:%x, pkt_size=%d, " \
855 "num_pkts=%d\n", __func__, NG_HOOK_NAME(hook),
856 rt->src.b[5], rt->src.b[4], rt->src.b[3],
857 rt->src.b[2], rt->src.b[1], rt->src.b[0],
858 rt->pkt_size, rt->num_pkts);
861 case NGM_HCI_SYNC_CON_QUEUE: {
862 ng_hci_sync_con_queue_ep *ep = NULL;
863 ng_btsocket_sco_pcb_t *pcb = NULL;
865 if (rt == NULL || msg->header.arglen != sizeof(*ep))
868 ep = (ng_hci_sync_con_queue_ep *)(msg->data);
870 rt->pending -= ep->completed;
871 if (rt->pending < 0) {
872 NG_BTSOCKET_SCO_WARN(
873 "%s: Pending packet counter is out of sync! bdaddr=%x:%x:%x:%x:%x:%x, " \
874 "handle=%d, pending=%d, completed=%d\n",
876 rt->src.b[5], rt->src.b[4], rt->src.b[3],
877 rt->src.b[2], rt->src.b[1], rt->src.b[0],
878 ep->con_handle, rt->pending,
884 mtx_lock(&ng_btsocket_sco_sockets_mtx);
887 pcb = ng_btsocket_sco_pcb_by_handle(&rt->src, ep->con_handle);
889 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
896 if (pcb->state == NG_BTSOCKET_SCO_OPEN) {
898 ng_btsocket_sco_untimeout(pcb);
900 /* Drop completed packets from the send queue */
901 for (; ep->completed > 0; ep->completed --)
902 sbdroprecord(&pcb->so->so_snd);
904 /* Send more if we have any */
905 if (sbavail(&pcb->so->so_snd) > 0)
906 if (ng_btsocket_sco_send2(pcb) == 0)
907 ng_btsocket_sco_timeout(pcb);
909 /* Wake up writers */
913 mtx_unlock(&pcb->pcb_mtx);
914 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
918 NG_BTSOCKET_SCO_WARN(
919 "%s: Unknown message, cmd=%d\n", __func__, msg->header.cmd);
923 NG_FREE_MSG(msg); /* Checks for msg != NULL */
924 } /* ng_btsocket_sco_default_msg_input */
927 * SCO sockets LP message input routine
931 ng_btsocket_sco_lp_msg_input(struct ng_mesg *msg, hook_p hook)
933 ng_btsocket_sco_rtentry_p rt = NULL;
936 NG_BTSOCKET_SCO_ALERT(
937 "%s: Invalid source hook for LP message\n", __func__);
941 rt = (ng_btsocket_sco_rtentry_p) NG_HOOK_PRIVATE(hook);
943 NG_BTSOCKET_SCO_ALERT(
944 "%s: Could not find out source bdaddr for LP message\n", __func__);
948 switch (msg->header.cmd) {
949 case NGM_HCI_LP_CON_CFM: /* Connection Confirmation Event */
950 ng_btsocket_sco_process_lp_con_cfm(msg, rt);
953 case NGM_HCI_LP_CON_IND: /* Connection Indication Event */
954 ng_btsocket_sco_process_lp_con_ind(msg, rt);
957 case NGM_HCI_LP_DISCON_IND: /* Disconnection Indication Event */
958 ng_btsocket_sco_process_lp_discon_ind(msg, rt);
961 /* XXX FIXME add other LP messages */
964 NG_BTSOCKET_SCO_WARN(
965 "%s: Unknown LP message, cmd=%d\n", __func__, msg->header.cmd);
970 } /* ng_btsocket_sco_lp_msg_input */
973 * SCO sockets input routine
977 ng_btsocket_sco_input(void *context, int pending)
983 mtx_lock(&ng_btsocket_sco_queue_mtx);
984 NG_BT_ITEMQ_DEQUEUE(&ng_btsocket_sco_queue, item);
985 mtx_unlock(&ng_btsocket_sco_queue_mtx);
990 NGI_GET_HOOK(item, hook);
991 if (hook != NULL && NG_HOOK_NOT_VALID(hook))
994 switch(item->el_flags & NGQF_TYPE) {
996 struct mbuf *m = NULL;
999 ng_btsocket_sco_data_input(m, hook);
1003 struct ng_mesg *msg = NULL;
1005 NGI_GET_MSG(item, msg);
1007 switch (msg->header.cmd) {
1008 case NGM_HCI_LP_CON_CFM:
1009 case NGM_HCI_LP_CON_IND:
1010 case NGM_HCI_LP_DISCON_IND:
1011 /* XXX FIXME add other LP messages */
1012 ng_btsocket_sco_lp_msg_input(msg, hook);
1016 ng_btsocket_sco_default_msg_input(msg, hook);
1023 ("%s: invalid item type=%ld\n", __func__, (item->el_flags & NGQF_TYPE)));
1028 NG_HOOK_UNREF(hook);
1032 } /* ng_btsocket_sco_input */
1035 * Route cleanup task. Gets scheduled when hook is disconnected. Here we
1036 * will find all sockets that use "invalid" hook and disconnect them.
1040 ng_btsocket_sco_rtclean(void *context, int pending)
1042 ng_btsocket_sco_pcb_p pcb = NULL, pcb_next = NULL;
1043 ng_btsocket_sco_rtentry_p rt = NULL;
1046 * First disconnect all sockets that use "invalid" hook
1049 mtx_lock(&ng_btsocket_sco_sockets_mtx);
1051 for(pcb = LIST_FIRST(&ng_btsocket_sco_sockets); pcb != NULL; ) {
1052 mtx_lock(&pcb->pcb_mtx);
1053 pcb_next = LIST_NEXT(pcb, next);
1055 if (pcb->rt != NULL &&
1056 pcb->rt->hook != NULL && NG_HOOK_NOT_VALID(pcb->rt->hook)) {
1057 if (pcb->flags & NG_BTSOCKET_SCO_TIMO)
1058 ng_btsocket_sco_untimeout(pcb);
1061 pcb->so->so_error = ENETDOWN;
1062 pcb->state = NG_BTSOCKET_SCO_CLOSED;
1063 soisdisconnected(pcb->so);
1066 mtx_unlock(&pcb->pcb_mtx);
1070 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1073 * Now cleanup routing table
1076 mtx_lock(&ng_btsocket_sco_rt_mtx);
1078 for (rt = LIST_FIRST(&ng_btsocket_sco_rt); rt != NULL; ) {
1079 ng_btsocket_sco_rtentry_p rt_next = LIST_NEXT(rt, next);
1081 if (rt->hook != NULL && NG_HOOK_NOT_VALID(rt->hook)) {
1082 LIST_REMOVE(rt, next);
1084 NG_HOOK_SET_PRIVATE(rt->hook, NULL);
1085 NG_HOOK_UNREF(rt->hook); /* Remove extra reference */
1087 bzero(rt, sizeof(*rt));
1088 free(rt, M_NETGRAPH_BTSOCKET_SCO);
1094 mtx_unlock(&ng_btsocket_sco_rt_mtx);
1095 } /* ng_btsocket_sco_rtclean */
1098 * Initialize everything
1102 ng_btsocket_sco_init(void)
1106 /* Skip initialization of globals for non-default instances. */
1107 if (!IS_DEFAULT_VNET(curvnet))
1110 ng_btsocket_sco_node = NULL;
1111 ng_btsocket_sco_debug_level = NG_BTSOCKET_WARN_LEVEL;
1113 /* Register Netgraph node type */
1114 error = ng_newtype(&typestruct);
1116 NG_BTSOCKET_SCO_ALERT(
1117 "%s: Could not register Netgraph node type, error=%d\n", __func__, error);
1122 /* Create Netgrapg node */
1123 error = ng_make_node_common(&typestruct, &ng_btsocket_sco_node);
1125 NG_BTSOCKET_SCO_ALERT(
1126 "%s: Could not create Netgraph node, error=%d\n", __func__, error);
1128 ng_btsocket_sco_node = NULL;
1133 error = ng_name_node(ng_btsocket_sco_node, NG_BTSOCKET_SCO_NODE_TYPE);
1135 NG_BTSOCKET_SCO_ALERT(
1136 "%s: Could not name Netgraph node, error=%d\n", __func__, error);
1138 NG_NODE_UNREF(ng_btsocket_sco_node);
1139 ng_btsocket_sco_node = NULL;
1144 /* Create input queue */
1145 NG_BT_ITEMQ_INIT(&ng_btsocket_sco_queue, 300);
1146 mtx_init(&ng_btsocket_sco_queue_mtx,
1147 "btsocks_sco_queue_mtx", NULL, MTX_DEF);
1148 TASK_INIT(&ng_btsocket_sco_queue_task, 0,
1149 ng_btsocket_sco_input, NULL);
1151 /* Create list of sockets */
1152 LIST_INIT(&ng_btsocket_sco_sockets);
1153 mtx_init(&ng_btsocket_sco_sockets_mtx,
1154 "btsocks_sco_sockets_mtx", NULL, MTX_DEF);
1157 LIST_INIT(&ng_btsocket_sco_rt);
1158 mtx_init(&ng_btsocket_sco_rt_mtx,
1159 "btsocks_sco_rt_mtx", NULL, MTX_DEF);
1160 TASK_INIT(&ng_btsocket_sco_rt_task, 0,
1161 ng_btsocket_sco_rtclean, NULL);
1162 } /* ng_btsocket_sco_init */
1165 * Abort connection on socket
1169 ng_btsocket_sco_abort(struct socket *so)
1171 so->so_error = ECONNABORTED;
1173 (void) ng_btsocket_sco_disconnect(so);
1174 } /* ng_btsocket_sco_abort */
1177 ng_btsocket_sco_close(struct socket *so)
1179 (void) ng_btsocket_sco_disconnect(so);
1180 } /* ng_btsocket_sco_close */
1183 * Accept connection on socket. Nothing to do here, socket must be connected
1184 * and ready, so just return peer address and be done with it.
1188 ng_btsocket_sco_accept(struct socket *so, struct sockaddr **nam)
1190 if (ng_btsocket_sco_node == NULL)
1193 return (ng_btsocket_sco_peeraddr(so, nam));
1194 } /* ng_btsocket_sco_accept */
1197 * Create and attach new socket
1201 ng_btsocket_sco_attach(struct socket *so, int proto, struct thread *td)
1203 ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so);
1206 /* Check socket and protocol */
1207 if (ng_btsocket_sco_node == NULL)
1208 return (EPROTONOSUPPORT);
1209 if (so->so_type != SOCK_SEQPACKET)
1210 return (ESOCKTNOSUPPORT);
1212 #if 0 /* XXX sonewconn() calls "pru_attach" with proto == 0 */
1214 if (proto != BLUETOOTH_PROTO_SCO)
1215 return (EPROTONOSUPPORT);
1221 /* Reserve send and receive space if it is not reserved yet */
1222 if ((so->so_snd.sb_hiwat == 0) || (so->so_rcv.sb_hiwat == 0)) {
1223 error = soreserve(so, NG_BTSOCKET_SCO_SENDSPACE,
1224 NG_BTSOCKET_SCO_RECVSPACE);
1229 /* Allocate the PCB */
1230 pcb = malloc(sizeof(*pcb),
1231 M_NETGRAPH_BTSOCKET_SCO, M_NOWAIT | M_ZERO);
1235 /* Link the PCB and the socket */
1236 so->so_pcb = (caddr_t) pcb;
1238 pcb->state = NG_BTSOCKET_SCO_CLOSED;
1240 callout_init(&pcb->timo, 1);
1243 * Mark PCB mutex as DUPOK to prevent "duplicated lock of
1244 * the same type" message. When accepting new SCO connection
1245 * ng_btsocket_sco_process_lp_con_ind() holds both PCB mutexes
1246 * for "old" (accepting) PCB and "new" (created) PCB.
1249 mtx_init(&pcb->pcb_mtx, "btsocks_sco_pcb_mtx", NULL,
1253 * Add the PCB to the list
1255 * XXX FIXME VERY IMPORTANT!
1257 * This is totally FUBAR. We could get here in two cases:
1259 * 1) When user calls socket()
1260 * 2) When we need to accept new incoming connection and call
1263 * In the first case we must acquire ng_btsocket_sco_sockets_mtx.
1264 * In the second case we hold ng_btsocket_sco_sockets_mtx already.
1265 * So we now need to distinguish between these cases. From reading
1266 * /sys/kern/uipc_socket2.c we can find out that sonewconn() calls
1267 * pru_attach with proto == 0 and td == NULL. For now use this fact
1268 * to figure out if we were called from socket() or from sonewconn().
1272 mtx_lock(&ng_btsocket_sco_sockets_mtx);
1274 mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED);
1276 LIST_INSERT_HEAD(&ng_btsocket_sco_sockets, pcb, next);
1279 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1282 } /* ng_btsocket_sco_attach */
1289 ng_btsocket_sco_bind(struct socket *so, struct sockaddr *nam,
1292 ng_btsocket_sco_pcb_t *pcb = NULL;
1293 struct sockaddr_sco *sa = (struct sockaddr_sco *) nam;
1295 if (ng_btsocket_sco_node == NULL)
1298 /* Verify address */
1301 if (sa->sco_family != AF_BLUETOOTH)
1302 return (EAFNOSUPPORT);
1303 if (sa->sco_len != sizeof(*sa))
1306 mtx_lock(&ng_btsocket_sco_sockets_mtx);
1309 * Check if other socket has this address already (look for exact
1310 * match in bdaddr) and assign socket address if it's available.
1313 if (bcmp(&sa->sco_bdaddr, NG_HCI_BDADDR_ANY, sizeof(sa->sco_bdaddr)) != 0) {
1314 LIST_FOREACH(pcb, &ng_btsocket_sco_sockets, next) {
1315 mtx_lock(&pcb->pcb_mtx);
1317 if (bcmp(&pcb->src, &sa->sco_bdaddr, sizeof(bdaddr_t)) == 0) {
1318 mtx_unlock(&pcb->pcb_mtx);
1319 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1321 return (EADDRINUSE);
1324 mtx_unlock(&pcb->pcb_mtx);
1328 pcb = so2sco_pcb(so);
1330 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1334 mtx_lock(&pcb->pcb_mtx);
1335 bcopy(&sa->sco_bdaddr, &pcb->src, sizeof(pcb->src));
1336 mtx_unlock(&pcb->pcb_mtx);
1338 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1341 } /* ng_btsocket_sco_bind */
1348 ng_btsocket_sco_connect(struct socket *so, struct sockaddr *nam,
1351 ng_btsocket_sco_pcb_t *pcb = so2sco_pcb(so);
1352 struct sockaddr_sco *sa = (struct sockaddr_sco *) nam;
1353 ng_btsocket_sco_rtentry_t *rt = NULL;
1354 int have_src, error = 0;
1359 if (ng_btsocket_sco_node == NULL)
1362 /* Verify address */
1365 if (sa->sco_family != AF_BLUETOOTH)
1366 return (EAFNOSUPPORT);
1367 if (sa->sco_len != sizeof(*sa))
1369 if (bcmp(&sa->sco_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
1370 return (EDESTADDRREQ);
1373 * Routing. Socket should be bound to some source address. The source
1374 * address can be ANY. Destination address must be set and it must not
1375 * be ANY. If source address is ANY then find first rtentry that has
1379 mtx_lock(&ng_btsocket_sco_rt_mtx);
1380 mtx_lock(&pcb->pcb_mtx);
1382 if (pcb->state == NG_BTSOCKET_SCO_CONNECTING) {
1383 mtx_unlock(&pcb->pcb_mtx);
1384 mtx_unlock(&ng_btsocket_sco_rt_mtx);
1386 return (EINPROGRESS);
1389 if (bcmp(&sa->sco_bdaddr, &pcb->src, sizeof(pcb->src)) == 0) {
1390 mtx_unlock(&pcb->pcb_mtx);
1391 mtx_unlock(&ng_btsocket_sco_rt_mtx);
1396 /* Send destination address and PSM */
1397 bcopy(&sa->sco_bdaddr, &pcb->dst, sizeof(pcb->dst));
1400 have_src = bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(pcb->src));
1402 LIST_FOREACH(rt, &ng_btsocket_sco_rt, next) {
1403 if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
1406 /* Match src and dst */
1408 if (bcmp(&pcb->src, &rt->src, sizeof(rt->src)) == 0)
1411 if (bcmp(&pcb->dst, &rt->src, sizeof(rt->src)) != 0)
1420 bcopy(&rt->src, &pcb->src, sizeof(pcb->src));
1422 error = EHOSTUNREACH;
1425 * Send LP_Connect request
1429 error = ng_btsocket_sco_send_lp_con_req(pcb);
1431 pcb->flags |= NG_BTSOCKET_SCO_CLIENT;
1432 pcb->state = NG_BTSOCKET_SCO_CONNECTING;
1433 soisconnecting(pcb->so);
1435 ng_btsocket_sco_timeout(pcb);
1439 mtx_unlock(&pcb->pcb_mtx);
1440 mtx_unlock(&ng_btsocket_sco_rt_mtx);
1443 } /* ng_btsocket_sco_connect */
1446 * Process ioctl's calls on socket
1450 ng_btsocket_sco_control(struct socket *so, u_long cmd, caddr_t data,
1451 struct ifnet *ifp, struct thread *td)
1454 } /* ng_btsocket_sco_control */
1457 * Process getsockopt/setsockopt system calls
1461 ng_btsocket_sco_ctloutput(struct socket *so, struct sockopt *sopt)
1463 ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so);
1466 if (ng_btsocket_sco_node == NULL)
1471 if (sopt->sopt_level != SOL_SCO)
1474 mtx_lock(&pcb->pcb_mtx);
1476 switch (sopt->sopt_dir) {
1478 if (pcb->state != NG_BTSOCKET_SCO_OPEN) {
1483 switch (sopt->sopt_name) {
1485 tmp = pcb->rt->pkt_size;
1486 error = sooptcopyout(sopt, &tmp, sizeof(tmp));
1489 case SO_SCO_CONNINFO:
1490 tmp = pcb->con_handle;
1491 error = sooptcopyout(sopt, &tmp, sizeof(tmp));
1501 error = ENOPROTOOPT;
1509 mtx_unlock(&pcb->pcb_mtx);
1512 } /* ng_btsocket_sco_ctloutput */
1515 * Detach and destroy socket
1519 ng_btsocket_sco_detach(struct socket *so)
1521 ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so);
1523 KASSERT(pcb != NULL, ("ng_btsocket_sco_detach: pcb == NULL"));
1525 if (ng_btsocket_sco_node == NULL)
1528 mtx_lock(&ng_btsocket_sco_sockets_mtx);
1529 mtx_lock(&pcb->pcb_mtx);
1531 if (pcb->flags & NG_BTSOCKET_SCO_TIMO)
1532 ng_btsocket_sco_untimeout(pcb);
1534 if (pcb->state == NG_BTSOCKET_SCO_OPEN)
1535 ng_btsocket_sco_send_lp_discon_req(pcb);
1537 pcb->state = NG_BTSOCKET_SCO_CLOSED;
1539 LIST_REMOVE(pcb, next);
1541 mtx_unlock(&pcb->pcb_mtx);
1542 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1544 mtx_destroy(&pcb->pcb_mtx);
1545 bzero(pcb, sizeof(*pcb));
1546 free(pcb, M_NETGRAPH_BTSOCKET_SCO);
1548 soisdisconnected(so);
1550 } /* ng_btsocket_sco_detach */
1557 ng_btsocket_sco_disconnect(struct socket *so)
1559 ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so);
1563 if (ng_btsocket_sco_node == NULL)
1566 mtx_lock(&pcb->pcb_mtx);
1568 if (pcb->state == NG_BTSOCKET_SCO_DISCONNECTING) {
1569 mtx_unlock(&pcb->pcb_mtx);
1571 return (EINPROGRESS);
1574 if (pcb->flags & NG_BTSOCKET_SCO_TIMO)
1575 ng_btsocket_sco_untimeout(pcb);
1577 if (pcb->state == NG_BTSOCKET_SCO_OPEN) {
1578 ng_btsocket_sco_send_lp_discon_req(pcb);
1580 pcb->state = NG_BTSOCKET_SCO_DISCONNECTING;
1581 soisdisconnecting(so);
1583 ng_btsocket_sco_timeout(pcb);
1585 pcb->state = NG_BTSOCKET_SCO_CLOSED;
1586 soisdisconnected(so);
1589 mtx_unlock(&pcb->pcb_mtx);
1592 } /* ng_btsocket_sco_disconnect */
1599 ng_btsocket_sco_listen(struct socket *so, int backlog, struct thread *td)
1601 ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so);
1606 if (ng_btsocket_sco_node == NULL)
1610 mtx_lock(&pcb->pcb_mtx);
1612 error = solisten_proto_check(so);
1616 if (bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0) {
1617 error = EDESTADDRREQ;
1621 solisten_proto(so, backlog);
1623 mtx_unlock(&pcb->pcb_mtx);
1627 } /* ng_btsocket_listen */
1634 ng_btsocket_sco_peeraddr(struct socket *so, struct sockaddr **nam)
1636 ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so);
1637 struct sockaddr_sco sa;
1641 if (ng_btsocket_sco_node == NULL)
1644 mtx_lock(&pcb->pcb_mtx);
1645 bcopy(&pcb->dst, &sa.sco_bdaddr, sizeof(sa.sco_bdaddr));
1646 mtx_unlock(&pcb->pcb_mtx);
1648 sa.sco_len = sizeof(sa);
1649 sa.sco_family = AF_BLUETOOTH;
1651 *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT);
1653 return ((*nam == NULL)? ENOMEM : 0);
1654 } /* ng_btsocket_sco_peeraddr */
1657 * Send data to socket
1661 ng_btsocket_sco_send(struct socket *so, int flags, struct mbuf *m,
1662 struct sockaddr *nam, struct mbuf *control, struct thread *td)
1664 ng_btsocket_sco_pcb_t *pcb = so2sco_pcb(so);
1667 if (ng_btsocket_sco_node == NULL) {
1672 /* Check socket and input */
1673 if (pcb == NULL || m == NULL || control != NULL) {
1678 mtx_lock(&pcb->pcb_mtx);
1680 /* Make sure socket is connected */
1681 if (pcb->state != NG_BTSOCKET_SCO_OPEN) {
1682 mtx_unlock(&pcb->pcb_mtx);
1688 if (pcb->rt == NULL ||
1689 pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook)) {
1690 mtx_unlock(&pcb->pcb_mtx);
1695 /* Check packet size */
1696 if (m->m_pkthdr.len > pcb->rt->pkt_size) {
1697 NG_BTSOCKET_SCO_ERR(
1698 "%s: Packet too big, len=%d, pkt_size=%d\n",
1699 __func__, m->m_pkthdr.len, pcb->rt->pkt_size);
1701 mtx_unlock(&pcb->pcb_mtx);
1707 * First put packet on socket send queue. Then check if we have
1708 * pending timeout. If we do not have timeout then we must send
1709 * packet and schedule timeout. Otherwise do nothing and wait for
1710 * NGM_HCI_SYNC_CON_QUEUE message.
1713 sbappendrecord(&pcb->so->so_snd, m);
1716 if (!(pcb->flags & NG_BTSOCKET_SCO_TIMO)) {
1717 error = ng_btsocket_sco_send2(pcb);
1719 ng_btsocket_sco_timeout(pcb);
1721 sbdroprecord(&pcb->so->so_snd); /* XXX */
1724 mtx_unlock(&pcb->pcb_mtx);
1726 NG_FREE_M(m); /* checks for != NULL */
1730 } /* ng_btsocket_sco_send */
1733 * Send first packet in the socket queue to the SCO layer
1737 ng_btsocket_sco_send2(ng_btsocket_sco_pcb_p pcb)
1739 struct mbuf *m = NULL;
1740 ng_hci_scodata_pkt_t *hdr = NULL;
1743 mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1745 while (pcb->rt->pending < pcb->rt->num_pkts &&
1746 sbavail(&pcb->so->so_snd) > 0) {
1747 /* Get a copy of the first packet on send queue */
1748 m = m_dup(pcb->so->so_snd.sb_mb, M_NOWAIT);
1754 /* Create SCO packet header */
1755 M_PREPEND(m, sizeof(*hdr), M_NOWAIT);
1757 if (m->m_len < sizeof(*hdr))
1758 m = m_pullup(m, sizeof(*hdr));
1765 /* Fill in the header */
1766 hdr = mtod(m, ng_hci_scodata_pkt_t *);
1767 hdr->type = NG_HCI_SCO_DATA_PKT;
1768 hdr->con_handle = htole16(NG_HCI_MK_CON_HANDLE(pcb->con_handle, 0, 0));
1769 hdr->length = m->m_pkthdr.len - sizeof(*hdr);
1772 NG_SEND_DATA_ONLY(error, pcb->rt->hook, m);
1776 pcb->rt->pending ++;
1779 return ((pcb->rt->pending > 0)? 0 : error);
1780 } /* ng_btsocket_sco_send2 */
1783 * Get socket address
1787 ng_btsocket_sco_sockaddr(struct socket *so, struct sockaddr **nam)
1789 ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so);
1790 struct sockaddr_sco sa;
1794 if (ng_btsocket_sco_node == NULL)
1797 mtx_lock(&pcb->pcb_mtx);
1798 bcopy(&pcb->src, &sa.sco_bdaddr, sizeof(sa.sco_bdaddr));
1799 mtx_unlock(&pcb->pcb_mtx);
1801 sa.sco_len = sizeof(sa);
1802 sa.sco_family = AF_BLUETOOTH;
1804 *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT);
1806 return ((*nam == NULL)? ENOMEM : 0);
1807 } /* ng_btsocket_sco_sockaddr */
1809 /*****************************************************************************
1810 *****************************************************************************
1812 *****************************************************************************
1813 *****************************************************************************/
1816 * Look for the socket that listens on given bdaddr.
1817 * Returns exact or close match (if any).
1818 * Caller must hold ng_btsocket_sco_sockets_mtx.
1819 * Returns with locked pcb.
1822 static ng_btsocket_sco_pcb_p
1823 ng_btsocket_sco_pcb_by_addr(bdaddr_p bdaddr)
1825 ng_btsocket_sco_pcb_p p = NULL, p1 = NULL;
1827 mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED);
1829 LIST_FOREACH(p, &ng_btsocket_sco_sockets, next) {
1830 mtx_lock(&p->pcb_mtx);
1832 if (p->so == NULL || !SOLISTENING(p->so)) {
1833 mtx_unlock(&p->pcb_mtx);
1837 if (bcmp(&p->src, bdaddr, sizeof(p->src)) == 0)
1838 return (p); /* return with locked pcb */
1840 if (bcmp(&p->src, NG_HCI_BDADDR_ANY, sizeof(p->src)) == 0)
1843 mtx_unlock(&p->pcb_mtx);
1847 mtx_lock(&p1->pcb_mtx);
1850 } /* ng_btsocket_sco_pcb_by_addr */
1853 * Look for the socket that assigned to given source address and handle.
1854 * Caller must hold ng_btsocket_sco_sockets_mtx.
1855 * Returns with locked pcb.
1858 static ng_btsocket_sco_pcb_p
1859 ng_btsocket_sco_pcb_by_handle(bdaddr_p src, int con_handle)
1861 ng_btsocket_sco_pcb_p p = NULL;
1863 mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED);
1865 LIST_FOREACH(p, &ng_btsocket_sco_sockets, next) {
1866 mtx_lock(&p->pcb_mtx);
1868 if (p->con_handle == con_handle &&
1869 bcmp(src, &p->src, sizeof(p->src)) == 0)
1870 return (p); /* return with locked pcb */
1872 mtx_unlock(&p->pcb_mtx);
1876 } /* ng_btsocket_sco_pcb_by_handle */
1879 * Look for the socket in CONNECTING state with given source and destination
1880 * addresses. Caller must hold ng_btsocket_sco_sockets_mtx.
1881 * Returns with locked pcb.
1884 static ng_btsocket_sco_pcb_p
1885 ng_btsocket_sco_pcb_by_addrs(bdaddr_p src, bdaddr_p dst)
1887 ng_btsocket_sco_pcb_p p = NULL;
1889 mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED);
1891 LIST_FOREACH(p, &ng_btsocket_sco_sockets, next) {
1892 mtx_lock(&p->pcb_mtx);
1894 if (p->state == NG_BTSOCKET_SCO_CONNECTING &&
1895 bcmp(src, &p->src, sizeof(p->src)) == 0 &&
1896 bcmp(dst, &p->dst, sizeof(p->dst)) == 0)
1897 return (p); /* return with locked pcb */
1899 mtx_unlock(&p->pcb_mtx);
1903 } /* ng_btsocket_sco_pcb_by_addrs */
1906 * Set timeout on socket
1910 ng_btsocket_sco_timeout(ng_btsocket_sco_pcb_p pcb)
1912 mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1914 if (!(pcb->flags & NG_BTSOCKET_SCO_TIMO)) {
1915 pcb->flags |= NG_BTSOCKET_SCO_TIMO;
1916 callout_reset(&pcb->timo, bluetooth_sco_rtx_timeout(),
1917 ng_btsocket_sco_process_timeout, pcb);
1920 ("%s: Duplicated socket timeout?!\n", __func__));
1921 } /* ng_btsocket_sco_timeout */
1924 * Unset timeout on socket
1928 ng_btsocket_sco_untimeout(ng_btsocket_sco_pcb_p pcb)
1930 mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1932 if (pcb->flags & NG_BTSOCKET_SCO_TIMO) {
1933 callout_stop(&pcb->timo);
1934 pcb->flags &= ~NG_BTSOCKET_SCO_TIMO;
1937 ("%s: No socket timeout?!\n", __func__));
1938 } /* ng_btsocket_sco_untimeout */
1941 * Process timeout on socket
1945 ng_btsocket_sco_process_timeout(void *xpcb)
1947 ng_btsocket_sco_pcb_p pcb = (ng_btsocket_sco_pcb_p) xpcb;
1949 mtx_lock(&pcb->pcb_mtx);
1951 pcb->flags &= ~NG_BTSOCKET_SCO_TIMO;
1952 pcb->so->so_error = ETIMEDOUT;
1954 switch (pcb->state) {
1955 case NG_BTSOCKET_SCO_CONNECTING:
1956 /* Connect timeout - close the socket */
1957 pcb->state = NG_BTSOCKET_SCO_CLOSED;
1958 soisdisconnected(pcb->so);
1961 case NG_BTSOCKET_SCO_OPEN:
1962 /* Send timeout - did not get NGM_HCI_SYNC_CON_QUEUE */
1963 sbdroprecord(&pcb->so->so_snd);
1965 /* XXX FIXME what to do with pcb->rt->pending??? */
1968 case NG_BTSOCKET_SCO_DISCONNECTING:
1969 /* Disconnect timeout - disconnect the socket anyway */
1970 pcb->state = NG_BTSOCKET_SCO_CLOSED;
1971 soisdisconnected(pcb->so);
1975 NG_BTSOCKET_SCO_ERR(
1976 "%s: Invalid socket state=%d\n", __func__, pcb->state);
1980 mtx_unlock(&pcb->pcb_mtx);
1981 } /* ng_btsocket_sco_process_timeout */