6 * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
30 * $Id: ng_btsocket_sco.c,v 1.2 2005/10/31 18:08:51 max Exp $
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>
44 #include <sys/malloc.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>
62 #ifdef NG_SEPARATE_MALLOC
63 MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_SCO, "netgraph_btsocks_sco",
64 "Netgraph Bluetooth SCO sockets");
66 #define M_NETGRAPH_BTSOCKET_SCO M_NETGRAPH
67 #endif /* NG_SEPARATE_MALLOC */
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;
78 static void ng_btsocket_sco_input (void *, int);
79 static void ng_btsocket_sco_rtclean (void *, int);
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,
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 static struct timeval ng_btsocket_sco_lasttime;
106 static int ng_btsocket_sco_curpps;
109 SYSCTL_DECL(_net_bluetooth_sco_sockets);
110 SYSCTL_NODE(_net_bluetooth_sco_sockets, OID_AUTO, seq, CTLFLAG_RW,
111 0, "Bluetooth SEQPACKET SCO sockets family");
112 SYSCTL_INT(_net_bluetooth_sco_sockets_seq, OID_AUTO, debug_level,
114 &ng_btsocket_sco_debug_level, NG_BTSOCKET_WARN_LEVEL,
115 "Bluetooth SEQPACKET SCO sockets debug level");
116 SYSCTL_INT(_net_bluetooth_sco_sockets_seq, OID_AUTO, queue_len,
118 &ng_btsocket_sco_queue.len, 0,
119 "Bluetooth SEQPACKET SCO sockets input queue length");
120 SYSCTL_INT(_net_bluetooth_sco_sockets_seq, OID_AUTO, queue_maxlen,
122 &ng_btsocket_sco_queue.maxlen, 0,
123 "Bluetooth SEQPACKET SCO sockets input queue max. length");
124 SYSCTL_INT(_net_bluetooth_sco_sockets_seq, OID_AUTO, queue_drops,
126 &ng_btsocket_sco_queue.drops, 0,
127 "Bluetooth SEQPACKET SCO sockets input queue drops");
130 #define NG_BTSOCKET_SCO_INFO \
131 if (ng_btsocket_sco_debug_level >= NG_BTSOCKET_INFO_LEVEL && \
132 ppsratecheck(&ng_btsocket_sco_lasttime, &ng_btsocket_sco_curpps, 1)) \
135 #define NG_BTSOCKET_SCO_WARN \
136 if (ng_btsocket_sco_debug_level >= NG_BTSOCKET_WARN_LEVEL && \
137 ppsratecheck(&ng_btsocket_sco_lasttime, &ng_btsocket_sco_curpps, 1)) \
140 #define NG_BTSOCKET_SCO_ERR \
141 if (ng_btsocket_sco_debug_level >= NG_BTSOCKET_ERR_LEVEL && \
142 ppsratecheck(&ng_btsocket_sco_lasttime, &ng_btsocket_sco_curpps, 1)) \
145 #define NG_BTSOCKET_SCO_ALERT \
146 if (ng_btsocket_sco_debug_level >= NG_BTSOCKET_ALERT_LEVEL && \
147 ppsratecheck(&ng_btsocket_sco_lasttime, &ng_btsocket_sco_curpps, 1)) \
151 * Netgraph message processing routines
154 static int ng_btsocket_sco_process_lp_con_cfm
155 (struct ng_mesg *, ng_btsocket_sco_rtentry_p);
156 static int ng_btsocket_sco_process_lp_con_ind
157 (struct ng_mesg *, ng_btsocket_sco_rtentry_p);
158 static int ng_btsocket_sco_process_lp_discon_ind
159 (struct ng_mesg *, ng_btsocket_sco_rtentry_p);
162 * Send LP messages to the lower layer
165 static int ng_btsocket_sco_send_lp_con_req
166 (ng_btsocket_sco_pcb_p);
167 static int ng_btsocket_sco_send_lp_con_rsp
168 (ng_btsocket_sco_rtentry_p, bdaddr_p, int);
169 static int ng_btsocket_sco_send_lp_discon_req
170 (ng_btsocket_sco_pcb_p);
172 static int ng_btsocket_sco_send2
173 (ng_btsocket_sco_pcb_p);
176 * Timeout processing routines
179 static void ng_btsocket_sco_timeout (ng_btsocket_sco_pcb_p);
180 static void ng_btsocket_sco_untimeout (ng_btsocket_sco_pcb_p);
181 static void ng_btsocket_sco_process_timeout (void *);
187 static ng_btsocket_sco_pcb_p ng_btsocket_sco_pcb_by_addr(bdaddr_p);
188 static ng_btsocket_sco_pcb_p ng_btsocket_sco_pcb_by_handle(bdaddr_p, int);
189 static ng_btsocket_sco_pcb_p ng_btsocket_sco_pcb_by_addrs(bdaddr_p, bdaddr_p);
191 #define ng_btsocket_sco_wakeup_input_task() \
192 taskqueue_enqueue(taskqueue_swi, &ng_btsocket_sco_queue_task)
194 #define ng_btsocket_sco_wakeup_route_task() \
195 taskqueue_enqueue(taskqueue_swi, &ng_btsocket_sco_rt_task)
197 /*****************************************************************************
198 *****************************************************************************
199 ** Netgraph node interface
200 *****************************************************************************
201 *****************************************************************************/
204 * Netgraph node constructor. Do not allow to create node of this type.
208 ng_btsocket_sco_node_constructor(node_p node)
211 } /* ng_btsocket_sco_node_constructor */
214 * Do local shutdown processing. Let old node go and create new fresh one.
218 ng_btsocket_sco_node_shutdown(node_p node)
224 /* Create new node */
225 error = ng_make_node_common(&typestruct, &ng_btsocket_sco_node);
227 NG_BTSOCKET_SCO_ALERT(
228 "%s: Could not create Netgraph node, error=%d\n", __func__, error);
230 ng_btsocket_sco_node = NULL;
235 error = ng_name_node(ng_btsocket_sco_node,
236 NG_BTSOCKET_SCO_NODE_TYPE);
238 NG_BTSOCKET_SCO_ALERT(
239 "%s: Could not name Netgraph node, error=%d\n", __func__, error);
241 NG_NODE_UNREF(ng_btsocket_sco_node);
242 ng_btsocket_sco_node = NULL;
248 } /* ng_btsocket_sco_node_shutdown */
251 * We allow any hook to be connected to the node.
255 ng_btsocket_sco_node_newhook(node_p node, hook_p hook, char const *name)
258 } /* ng_btsocket_sco_node_newhook */
261 * Just say "YEP, that's OK by me!"
265 ng_btsocket_sco_node_connect(hook_p hook)
267 NG_HOOK_SET_PRIVATE(hook, NULL);
268 NG_HOOK_REF(hook); /* Keep extra reference to the hook */
271 NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
272 NG_HOOK_FORCE_QUEUE(hook);
276 } /* ng_btsocket_sco_node_connect */
279 * Hook disconnection. Schedule route cleanup task
283 ng_btsocket_sco_node_disconnect(hook_p hook)
286 * If hook has private information than we must have this hook in
287 * the routing table and must schedule cleaning for the routing table.
288 * Otherwise hook was connected but we never got "hook_info" message,
289 * so we have never added this hook to the routing table and it save
293 if (NG_HOOK_PRIVATE(hook) != NULL)
294 return (ng_btsocket_sco_wakeup_route_task());
296 NG_HOOK_UNREF(hook); /* Remove extra reference */
299 } /* ng_btsocket_sco_node_disconnect */
302 * Process incoming messages
306 ng_btsocket_sco_node_rcvmsg(node_p node, item_p item, hook_p hook)
308 struct ng_mesg *msg = NGI_MSG(item); /* item still has message */
311 if (msg != NULL && msg->header.typecookie == NGM_HCI_COOKIE) {
312 mtx_lock(&ng_btsocket_sco_queue_mtx);
313 if (NG_BT_ITEMQ_FULL(&ng_btsocket_sco_queue)) {
315 "%s: Input queue is full (msg)\n", __func__);
317 NG_BT_ITEMQ_DROP(&ng_btsocket_sco_queue);
323 NGI_SET_HOOK(item, hook);
326 NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_sco_queue, item);
327 error = ng_btsocket_sco_wakeup_input_task();
329 mtx_unlock(&ng_btsocket_sco_queue_mtx);
336 } /* ng_btsocket_sco_node_rcvmsg */
339 * Receive data on a hook
343 ng_btsocket_sco_node_rcvdata(hook_p hook, item_p item)
347 mtx_lock(&ng_btsocket_sco_queue_mtx);
348 if (NG_BT_ITEMQ_FULL(&ng_btsocket_sco_queue)) {
350 "%s: Input queue is full (data)\n", __func__);
352 NG_BT_ITEMQ_DROP(&ng_btsocket_sco_queue);
357 NGI_SET_HOOK(item, hook);
359 NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_sco_queue, item);
360 error = ng_btsocket_sco_wakeup_input_task();
362 mtx_unlock(&ng_btsocket_sco_queue_mtx);
365 } /* ng_btsocket_sco_node_rcvdata */
368 * Process LP_ConnectCfm event from the lower layer protocol
372 ng_btsocket_sco_process_lp_con_cfm(struct ng_mesg *msg,
373 ng_btsocket_sco_rtentry_p rt)
375 ng_hci_lp_con_cfm_ep *ep = NULL;
376 ng_btsocket_sco_pcb_t *pcb = NULL;
379 if (msg->header.arglen != sizeof(*ep))
382 ep = (ng_hci_lp_con_cfm_ep *)(msg->data);
384 mtx_lock(&ng_btsocket_sco_sockets_mtx);
386 /* Look for the socket with the token */
387 pcb = ng_btsocket_sco_pcb_by_addrs(&rt->src, &ep->bdaddr);
389 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
395 NG_BTSOCKET_SCO_INFO(
396 "%s: Got LP_ConnectCfm response, src bdaddr=%x:%x:%x:%x:%x:%x, " \
397 "dst bdaddr=%x:%x:%x:%x:%x:%x, status=%d, handle=%d, state=%d\n",
399 pcb->src.b[5], pcb->src.b[4], pcb->src.b[3],
400 pcb->src.b[2], pcb->src.b[1], pcb->src.b[0],
401 pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3],
402 pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0],
403 ep->status, ep->con_handle, pcb->state);
405 if (pcb->state != NG_BTSOCKET_SCO_CONNECTING) {
406 mtx_unlock(&pcb->pcb_mtx);
407 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
412 ng_btsocket_sco_untimeout(pcb);
414 if (ep->status == 0) {
416 * Connection is open. Update connection handle and
420 pcb->con_handle = ep->con_handle;
421 pcb->state = NG_BTSOCKET_SCO_OPEN;
422 soisconnected(pcb->so);
425 * We have failed to open connection, so disconnect the socket
428 pcb->so->so_error = ECONNREFUSED; /* XXX convert status ??? */
429 pcb->state = NG_BTSOCKET_SCO_CLOSED;
430 soisdisconnected(pcb->so);
433 mtx_unlock(&pcb->pcb_mtx);
434 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
437 } /* ng_btsocket_sco_process_lp_con_cfm */
440 * Process LP_ConnectInd indicator. Find socket that listens on address.
441 * Find exact or closest match.
445 ng_btsocket_sco_process_lp_con_ind(struct ng_mesg *msg,
446 ng_btsocket_sco_rtentry_p rt)
448 ng_hci_lp_con_ind_ep *ep = NULL;
449 ng_btsocket_sco_pcb_t *pcb = NULL, *pcb1 = NULL;
451 u_int16_t status = 0;
453 if (msg->header.arglen != sizeof(*ep))
456 ep = (ng_hci_lp_con_ind_ep *)(msg->data);
458 NG_BTSOCKET_SCO_INFO(
459 "%s: Got LP_ConnectInd indicator, src bdaddr=%x:%x:%x:%x:%x:%x, " \
460 "dst bdaddr=%x:%x:%x:%x:%x:%x\n",
462 rt->src.b[5], rt->src.b[4], rt->src.b[3],
463 rt->src.b[2], rt->src.b[1], rt->src.b[0],
464 ep->bdaddr.b[5], ep->bdaddr.b[4], ep->bdaddr.b[3],
465 ep->bdaddr.b[2], ep->bdaddr.b[1], ep->bdaddr.b[0]);
467 mtx_lock(&ng_btsocket_sco_sockets_mtx);
469 pcb = ng_btsocket_sco_pcb_by_addr(&rt->src);
471 struct socket *so1 = NULL;
476 * First check the pending connections queue and if we have
477 * space then create new socket and set proper source address.
480 if (pcb->so->so_qlen <= pcb->so->so_qlimit)
481 so1 = sonewconn(pcb->so, 0);
484 status = 0x0d; /* Rejected due to limited resources */
489 * If we got here than we have created new socket. So complete
490 * connection. If we we listening on specific address then copy
491 * source address from listening socket, otherwise copy source
492 * address from hook's routing information.
495 pcb1 = so2sco_pcb(so1);
496 KASSERT((pcb1 != NULL),
497 ("%s: pcb1 == NULL\n", __func__));
499 mtx_lock(&pcb1->pcb_mtx);
501 if (bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(pcb->src)) != 0)
502 bcopy(&pcb->src, &pcb1->src, sizeof(pcb1->src));
504 bcopy(&rt->src, &pcb1->src, sizeof(pcb1->src));
506 pcb1->flags &= ~NG_BTSOCKET_SCO_CLIENT;
508 bcopy(&ep->bdaddr, &pcb1->dst, sizeof(pcb1->dst));
511 /* Nobody listens on requested BDADDR */
512 status = 0x1f; /* Unspecified Error */
515 error = ng_btsocket_sco_send_lp_con_rsp(rt, &ep->bdaddr, status);
518 pcb1->so->so_error = error;
519 pcb1->state = NG_BTSOCKET_SCO_CLOSED;
520 soisdisconnected(pcb1->so);
522 pcb1->state = NG_BTSOCKET_SCO_CONNECTING;
523 soisconnecting(pcb1->so);
525 ng_btsocket_sco_timeout(pcb1);
528 mtx_unlock(&pcb1->pcb_mtx);
532 mtx_unlock(&pcb->pcb_mtx);
534 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
537 } /* ng_btsocket_sco_process_lp_con_ind */
540 * Process LP_DisconnectInd indicator
544 ng_btsocket_sco_process_lp_discon_ind(struct ng_mesg *msg,
545 ng_btsocket_sco_rtentry_p rt)
547 ng_hci_lp_discon_ind_ep *ep = NULL;
548 ng_btsocket_sco_pcb_t *pcb = NULL;
551 if (msg->header.arglen != sizeof(*ep))
554 ep = (ng_hci_lp_discon_ind_ep *)(msg->data);
556 mtx_lock(&ng_btsocket_sco_sockets_mtx);
558 /* Look for the socket with given channel ID */
559 pcb = ng_btsocket_sco_pcb_by_handle(&rt->src, ep->con_handle);
561 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
566 * Disconnect the socket. If there was any pending request we can
567 * not do anything here anyway.
572 NG_BTSOCKET_SCO_INFO(
573 "%s: Got LP_DisconnectInd indicator, src bdaddr=%x:%x:%x:%x:%x:%x, " \
574 "dst bdaddr=%x:%x:%x:%x:%x:%x, handle=%d, state=%d\n",
576 pcb->src.b[5], pcb->src.b[4], pcb->src.b[3],
577 pcb->src.b[2], pcb->src.b[1], pcb->src.b[0],
578 pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3],
579 pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0],
580 pcb->con_handle, pcb->state);
582 if (pcb->flags & NG_BTSOCKET_SCO_TIMO)
583 ng_btsocket_sco_untimeout(pcb);
585 pcb->state = NG_BTSOCKET_SCO_CLOSED;
586 soisdisconnected(pcb->so);
588 mtx_unlock(&pcb->pcb_mtx);
589 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
592 } /* ng_btsocket_sco_process_lp_discon_ind */
595 * Send LP_ConnectReq request
599 ng_btsocket_sco_send_lp_con_req(ng_btsocket_sco_pcb_p pcb)
601 struct ng_mesg *msg = NULL;
602 ng_hci_lp_con_req_ep *ep = NULL;
605 mtx_assert(&pcb->pcb_mtx, MA_OWNED);
607 if (pcb->rt == NULL ||
608 pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook))
611 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_REQ,
612 sizeof(*ep), M_NOWAIT);
616 ep = (ng_hci_lp_con_req_ep *)(msg->data);
617 ep->link_type = NG_HCI_LINK_SCO;
618 bcopy(&pcb->dst, &ep->bdaddr, sizeof(ep->bdaddr));
620 NG_SEND_MSG_HOOK(error, ng_btsocket_sco_node, msg, pcb->rt->hook, 0);
623 } /* ng_btsocket_sco_send_lp_con_req */
626 * Send LP_ConnectRsp response
630 ng_btsocket_sco_send_lp_con_rsp(ng_btsocket_sco_rtentry_p rt, bdaddr_p dst, int status)
632 struct ng_mesg *msg = NULL;
633 ng_hci_lp_con_rsp_ep *ep = NULL;
636 if (rt == NULL || rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
639 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_RSP,
640 sizeof(*ep), M_NOWAIT);
644 ep = (ng_hci_lp_con_rsp_ep *)(msg->data);
646 ep->link_type = NG_HCI_LINK_SCO;
647 bcopy(dst, &ep->bdaddr, sizeof(ep->bdaddr));
649 NG_SEND_MSG_HOOK(error, ng_btsocket_sco_node, msg, rt->hook, 0);
652 } /* ng_btsocket_sco_send_lp_con_rsp */
655 * Send LP_DisconReq request
659 ng_btsocket_sco_send_lp_discon_req(ng_btsocket_sco_pcb_p pcb)
661 struct ng_mesg *msg = NULL;
662 ng_hci_lp_discon_req_ep *ep = NULL;
665 mtx_assert(&pcb->pcb_mtx, MA_OWNED);
667 if (pcb->rt == NULL ||
668 pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook))
671 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_DISCON_REQ,
672 sizeof(*ep), M_NOWAIT);
676 ep = (ng_hci_lp_discon_req_ep *)(msg->data);
677 ep->con_handle = pcb->con_handle;
678 ep->reason = 0x13; /* User Ended Connection */
680 NG_SEND_MSG_HOOK(error, ng_btsocket_sco_node, msg, pcb->rt->hook, 0);
683 } /* ng_btsocket_sco_send_lp_discon_req */
685 /*****************************************************************************
686 *****************************************************************************
688 *****************************************************************************
689 *****************************************************************************/
692 * SCO sockets data input routine
696 ng_btsocket_sco_data_input(struct mbuf *m, hook_p hook)
698 ng_hci_scodata_pkt_t *hdr = NULL;
699 ng_btsocket_sco_pcb_t *pcb = NULL;
700 ng_btsocket_sco_rtentry_t *rt = NULL;
701 u_int16_t con_handle;
704 NG_BTSOCKET_SCO_ALERT(
705 "%s: Invalid source hook for SCO data packet\n", __func__);
709 rt = (ng_btsocket_sco_rtentry_t *) NG_HOOK_PRIVATE(hook);
711 NG_BTSOCKET_SCO_ALERT(
712 "%s: Could not find out source bdaddr for SCO data packet\n", __func__);
716 /* Make sure we can access header */
717 if (m->m_pkthdr.len < sizeof(*hdr)) {
719 "%s: SCO data packet too small, len=%d\n", __func__, m->m_pkthdr.len);
723 if (m->m_len < sizeof(*hdr)) {
724 m = m_pullup(m, sizeof(*hdr));
729 /* Strip SCO packet header and verify packet length */
730 hdr = mtod(m, ng_hci_scodata_pkt_t *);
731 m_adj(m, sizeof(*hdr));
733 if (hdr->length != m->m_pkthdr.len) {
735 "%s: Bad SCO data packet length, len=%d, length=%d\n",
736 __func__, m->m_pkthdr.len, hdr->length);
744 con_handle = NG_HCI_CON_HANDLE(le16toh(hdr->con_handle));
746 NG_BTSOCKET_SCO_INFO(
747 "%s: Received SCO data packet: src bdaddr=%x:%x:%x:%x:%x:%x, handle=%d, " \
748 "length=%d\n", __func__,
749 rt->src.b[5], rt->src.b[4], rt->src.b[3],
750 rt->src.b[2], rt->src.b[1], rt->src.b[0],
751 con_handle, hdr->length);
753 mtx_lock(&ng_btsocket_sco_sockets_mtx);
756 pcb = ng_btsocket_sco_pcb_by_handle(&rt->src, con_handle);
758 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
764 if (pcb->state != NG_BTSOCKET_SCO_OPEN) {
766 "%s: No connected socket found, src bdaddr=%x:%x:%x:%x:%x:%x, state=%d\n",
768 rt->src.b[5], rt->src.b[4], rt->src.b[3],
769 rt->src.b[2], rt->src.b[1], rt->src.b[0],
772 mtx_unlock(&pcb->pcb_mtx);
773 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
777 /* Check if we have enough space in socket receive queue */
778 if (m->m_pkthdr.len > sbspace(&pcb->so->so_rcv)) {
780 "%s: Not enough space in socket receive queue. Dropping SCO data packet, " \
781 "src bdaddr=%x:%x:%x:%x:%x:%x, len=%d, space=%ld\n",
783 rt->src.b[5], rt->src.b[4], rt->src.b[3],
784 rt->src.b[2], rt->src.b[1], rt->src.b[0],
786 sbspace(&pcb->so->so_rcv));
788 mtx_unlock(&pcb->pcb_mtx);
789 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
793 /* Append packet to the socket receive queue and wakeup */
794 sbappendrecord(&pcb->so->so_rcv, m);
799 mtx_unlock(&pcb->pcb_mtx);
800 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
802 NG_FREE_M(m); /* checks for m != NULL */
803 } /* ng_btsocket_sco_data_input */
806 * SCO sockets default message input routine
810 ng_btsocket_sco_default_msg_input(struct ng_mesg *msg, hook_p hook)
812 ng_btsocket_sco_rtentry_t *rt = NULL;
814 if (hook == NULL || NG_HOOK_NOT_VALID(hook))
817 rt = (ng_btsocket_sco_rtentry_t *) NG_HOOK_PRIVATE(hook);
819 switch (msg->header.cmd) {
820 case NGM_HCI_NODE_UP: {
821 ng_hci_node_up_ep *ep = NULL;
823 if (msg->header.arglen != sizeof(*ep))
826 ep = (ng_hci_node_up_ep *)(msg->data);
827 if (bcmp(&ep->bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
831 rt = malloc(sizeof(*rt),
832 M_NETGRAPH_BTSOCKET_SCO, M_NOWAIT|M_ZERO);
836 NG_HOOK_SET_PRIVATE(hook, rt);
838 mtx_lock(&ng_btsocket_sco_rt_mtx);
840 LIST_INSERT_HEAD(&ng_btsocket_sco_rt, rt, next);
842 mtx_lock(&ng_btsocket_sco_rt_mtx);
844 bcopy(&ep->bdaddr, &rt->src, sizeof(rt->src));
845 rt->pkt_size = (ep->pkt_size == 0)? 60 : ep->pkt_size;
846 rt->num_pkts = ep->num_pkts;
849 mtx_unlock(&ng_btsocket_sco_rt_mtx);
851 NG_BTSOCKET_SCO_INFO(
852 "%s: Updating hook \"%s\", src bdaddr=%x:%x:%x:%x:%x:%x, pkt_size=%d, " \
853 "num_pkts=%d\n", __func__, NG_HOOK_NAME(hook),
854 rt->src.b[5], rt->src.b[4], rt->src.b[3],
855 rt->src.b[2], rt->src.b[1], rt->src.b[0],
856 rt->pkt_size, rt->num_pkts);
859 case NGM_HCI_SYNC_CON_QUEUE: {
860 ng_hci_sync_con_queue_ep *ep = NULL;
861 ng_btsocket_sco_pcb_t *pcb = NULL;
863 if (rt == NULL || msg->header.arglen != sizeof(*ep))
866 ep = (ng_hci_sync_con_queue_ep *)(msg->data);
868 rt->pending -= ep->completed;
869 if (rt->pending < 0) {
870 NG_BTSOCKET_SCO_WARN(
871 "%s: Pending packet counter is out of sync! bdaddr=%x:%x:%x:%x:%x:%x, " \
872 "handle=%d, pending=%d, completed=%d\n",
874 rt->src.b[5], rt->src.b[4], rt->src.b[3],
875 rt->src.b[2], rt->src.b[1], rt->src.b[0],
876 ep->con_handle, rt->pending,
882 mtx_lock(&ng_btsocket_sco_sockets_mtx);
885 pcb = ng_btsocket_sco_pcb_by_handle(&rt->src, ep->con_handle);
887 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
894 if (pcb->state == NG_BTSOCKET_SCO_OPEN) {
896 ng_btsocket_sco_untimeout(pcb);
898 /* Drop completed packets from the send queue */
899 for (; ep->completed > 0; ep->completed --)
900 sbdroprecord(&pcb->so->so_snd);
902 /* Send more if we have any */
903 if (pcb->so->so_snd.sb_cc > 0)
904 if (ng_btsocket_sco_send2(pcb) == 0)
905 ng_btsocket_sco_timeout(pcb);
907 /* Wake up writers */
911 mtx_unlock(&pcb->pcb_mtx);
912 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
916 NG_BTSOCKET_SCO_WARN(
917 "%s: Unknown message, cmd=%d\n", __func__, msg->header.cmd);
921 NG_FREE_MSG(msg); /* Checks for msg != NULL */
922 } /* ng_btsocket_sco_default_msg_input */
925 * SCO sockets LP message input routine
929 ng_btsocket_sco_lp_msg_input(struct ng_mesg *msg, hook_p hook)
931 ng_btsocket_sco_rtentry_p rt = NULL;
934 NG_BTSOCKET_SCO_ALERT(
935 "%s: Invalid source hook for LP message\n", __func__);
939 rt = (ng_btsocket_sco_rtentry_p) NG_HOOK_PRIVATE(hook);
941 NG_BTSOCKET_SCO_ALERT(
942 "%s: Could not find out source bdaddr for LP message\n", __func__);
946 switch (msg->header.cmd) {
947 case NGM_HCI_LP_CON_CFM: /* Connection Confirmation Event */
948 ng_btsocket_sco_process_lp_con_cfm(msg, rt);
951 case NGM_HCI_LP_CON_IND: /* Connection Indication Event */
952 ng_btsocket_sco_process_lp_con_ind(msg, rt);
955 case NGM_HCI_LP_DISCON_IND: /* Disconnection Indication Event */
956 ng_btsocket_sco_process_lp_discon_ind(msg, rt);
959 /* XXX FIXME add other LP messages */
962 NG_BTSOCKET_SCO_WARN(
963 "%s: Unknown LP message, cmd=%d\n", __func__, msg->header.cmd);
968 } /* ng_btsocket_sco_lp_msg_input */
971 * SCO sockets input routine
975 ng_btsocket_sco_input(void *context, int pending)
981 mtx_lock(&ng_btsocket_sco_queue_mtx);
982 NG_BT_ITEMQ_DEQUEUE(&ng_btsocket_sco_queue, item);
983 mtx_unlock(&ng_btsocket_sco_queue_mtx);
988 NGI_GET_HOOK(item, hook);
989 if (hook != NULL && NG_HOOK_NOT_VALID(hook))
992 switch(item->el_flags & NGQF_TYPE) {
994 struct mbuf *m = NULL;
997 ng_btsocket_sco_data_input(m, hook);
1001 struct ng_mesg *msg = NULL;
1003 NGI_GET_MSG(item, msg);
1005 switch (msg->header.cmd) {
1006 case NGM_HCI_LP_CON_CFM:
1007 case NGM_HCI_LP_CON_IND:
1008 case NGM_HCI_LP_DISCON_IND:
1009 /* XXX FIXME add other LP messages */
1010 ng_btsocket_sco_lp_msg_input(msg, hook);
1014 ng_btsocket_sco_default_msg_input(msg, hook);
1021 ("%s: invalid item type=%ld\n", __func__, (item->el_flags & NGQF_TYPE)));
1026 NG_HOOK_UNREF(hook);
1030 } /* ng_btsocket_sco_input */
1033 * Route cleanup task. Gets scheduled when hook is disconnected. Here we
1034 * will find all sockets that use "invalid" hook and disconnect them.
1038 ng_btsocket_sco_rtclean(void *context, int pending)
1040 ng_btsocket_sco_pcb_p pcb = NULL, pcb_next = NULL;
1041 ng_btsocket_sco_rtentry_p rt = NULL;
1044 * First disconnect all sockets that use "invalid" hook
1047 mtx_lock(&ng_btsocket_sco_sockets_mtx);
1049 for(pcb = LIST_FIRST(&ng_btsocket_sco_sockets); pcb != NULL; ) {
1050 mtx_lock(&pcb->pcb_mtx);
1051 pcb_next = LIST_NEXT(pcb, next);
1053 if (pcb->rt != NULL &&
1054 pcb->rt->hook != NULL && NG_HOOK_NOT_VALID(pcb->rt->hook)) {
1055 if (pcb->flags & NG_BTSOCKET_SCO_TIMO)
1056 ng_btsocket_sco_untimeout(pcb);
1059 pcb->so->so_error = ENETDOWN;
1060 pcb->state = NG_BTSOCKET_SCO_CLOSED;
1061 soisdisconnected(pcb->so);
1064 mtx_unlock(&pcb->pcb_mtx);
1068 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1071 * Now cleanup routing table
1074 mtx_lock(&ng_btsocket_sco_rt_mtx);
1076 for (rt = LIST_FIRST(&ng_btsocket_sco_rt); rt != NULL; ) {
1077 ng_btsocket_sco_rtentry_p rt_next = LIST_NEXT(rt, next);
1079 if (rt->hook != NULL && NG_HOOK_NOT_VALID(rt->hook)) {
1080 LIST_REMOVE(rt, next);
1082 NG_HOOK_SET_PRIVATE(rt->hook, NULL);
1083 NG_HOOK_UNREF(rt->hook); /* Remove extra reference */
1085 bzero(rt, sizeof(*rt));
1086 free(rt, M_NETGRAPH_BTSOCKET_SCO);
1092 mtx_unlock(&ng_btsocket_sco_rt_mtx);
1093 } /* ng_btsocket_sco_rtclean */
1096 * Initialize everything
1100 ng_btsocket_sco_init(void)
1104 ng_btsocket_sco_node = NULL;
1105 ng_btsocket_sco_debug_level = NG_BTSOCKET_WARN_LEVEL;
1107 /* Register Netgraph node type */
1108 error = ng_newtype(&typestruct);
1110 NG_BTSOCKET_SCO_ALERT(
1111 "%s: Could not register Netgraph node type, error=%d\n", __func__, error);
1116 /* Create Netgrapg node */
1117 error = ng_make_node_common(&typestruct, &ng_btsocket_sco_node);
1119 NG_BTSOCKET_SCO_ALERT(
1120 "%s: Could not create Netgraph node, error=%d\n", __func__, error);
1122 ng_btsocket_sco_node = NULL;
1127 error = ng_name_node(ng_btsocket_sco_node, NG_BTSOCKET_SCO_NODE_TYPE);
1129 NG_BTSOCKET_SCO_ALERT(
1130 "%s: Could not name Netgraph node, error=%d\n", __func__, error);
1132 NG_NODE_UNREF(ng_btsocket_sco_node);
1133 ng_btsocket_sco_node = NULL;
1138 /* Create input queue */
1139 NG_BT_ITEMQ_INIT(&ng_btsocket_sco_queue, 300);
1140 mtx_init(&ng_btsocket_sco_queue_mtx,
1141 "btsocks_sco_queue_mtx", NULL, MTX_DEF);
1142 TASK_INIT(&ng_btsocket_sco_queue_task, 0,
1143 ng_btsocket_sco_input, NULL);
1145 /* Create list of sockets */
1146 LIST_INIT(&ng_btsocket_sco_sockets);
1147 mtx_init(&ng_btsocket_sco_sockets_mtx,
1148 "btsocks_sco_sockets_mtx", NULL, MTX_DEF);
1151 LIST_INIT(&ng_btsocket_sco_rt);
1152 mtx_init(&ng_btsocket_sco_rt_mtx,
1153 "btsocks_sco_rt_mtx", NULL, MTX_DEF);
1154 TASK_INIT(&ng_btsocket_sco_rt_task, 0,
1155 ng_btsocket_sco_rtclean, NULL);
1156 } /* ng_btsocket_sco_init */
1159 * Abort connection on socket
1163 ng_btsocket_sco_abort(struct socket *so)
1165 so->so_error = ECONNABORTED;
1167 (void) ng_btsocket_sco_disconnect(so);
1168 } /* ng_btsocket_sco_abort */
1171 ng_btsocket_sco_close(struct socket *so)
1173 (void) ng_btsocket_sco_disconnect(so);
1174 } /* ng_btsocket_sco_close */
1177 * Accept connection on socket. Nothing to do here, socket must be connected
1178 * and ready, so just return peer address and be done with it.
1182 ng_btsocket_sco_accept(struct socket *so, struct sockaddr **nam)
1184 if (ng_btsocket_sco_node == NULL)
1187 return (ng_btsocket_sco_peeraddr(so, nam));
1188 } /* ng_btsocket_sco_accept */
1191 * Create and attach new socket
1195 ng_btsocket_sco_attach(struct socket *so, int proto, struct thread *td)
1197 ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so);
1200 /* Check socket and protocol */
1201 if (ng_btsocket_sco_node == NULL)
1202 return (EPROTONOSUPPORT);
1203 if (so->so_type != SOCK_SEQPACKET)
1204 return (ESOCKTNOSUPPORT);
1206 #if 0 /* XXX sonewconn() calls "pru_attach" with proto == 0 */
1208 if (proto != BLUETOOTH_PROTO_SCO)
1209 return (EPROTONOSUPPORT);
1215 /* Reserve send and receive space if it is not reserved yet */
1216 if ((so->so_snd.sb_hiwat == 0) || (so->so_rcv.sb_hiwat == 0)) {
1217 error = soreserve(so, NG_BTSOCKET_SCO_SENDSPACE,
1218 NG_BTSOCKET_SCO_RECVSPACE);
1223 /* Allocate the PCB */
1224 pcb = malloc(sizeof(*pcb),
1225 M_NETGRAPH_BTSOCKET_SCO, M_NOWAIT | M_ZERO);
1229 /* Link the PCB and the socket */
1230 so->so_pcb = (caddr_t) pcb;
1232 pcb->state = NG_BTSOCKET_SCO_CLOSED;
1234 callout_init(&pcb->timo, 1);
1237 * Mark PCB mutex as DUPOK to prevent "duplicated lock of
1238 * the same type" message. When accepting new SCO connection
1239 * ng_btsocket_sco_process_lp_con_ind() holds both PCB mutexes
1240 * for "old" (accepting) PCB and "new" (created) PCB.
1243 mtx_init(&pcb->pcb_mtx, "btsocks_sco_pcb_mtx", NULL,
1247 * Add the PCB to the list
1249 * XXX FIXME VERY IMPORTANT!
1251 * This is totally FUBAR. We could get here in two cases:
1253 * 1) When user calls socket()
1254 * 2) When we need to accept new incomming connection and call
1257 * In the first case we must aquire ng_btsocket_sco_sockets_mtx.
1258 * In the second case we hold ng_btsocket_sco_sockets_mtx already.
1259 * So we now need to distinguish between these cases. From reading
1260 * /sys/kern/uipc_socket2.c we can find out that sonewconn() calls
1261 * pru_attach with proto == 0 and td == NULL. For now use this fact
1262 * to figure out if we were called from socket() or from sonewconn().
1266 mtx_lock(&ng_btsocket_sco_sockets_mtx);
1268 mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED);
1270 LIST_INSERT_HEAD(&ng_btsocket_sco_sockets, pcb, next);
1273 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1276 } /* ng_btsocket_sco_attach */
1283 ng_btsocket_sco_bind(struct socket *so, struct sockaddr *nam,
1286 ng_btsocket_sco_pcb_t *pcb = NULL;
1287 struct sockaddr_sco *sa = (struct sockaddr_sco *) nam;
1289 if (ng_btsocket_sco_node == NULL)
1292 /* Verify address */
1295 if (sa->sco_family != AF_BLUETOOTH)
1296 return (EAFNOSUPPORT);
1297 if (sa->sco_len != sizeof(*sa))
1300 mtx_lock(&ng_btsocket_sco_sockets_mtx);
1303 * Check if other socket has this address already (look for exact
1304 * match in bdaddr) and assign socket address if it's available.
1307 if (bcmp(&sa->sco_bdaddr, NG_HCI_BDADDR_ANY, sizeof(sa->sco_bdaddr)) != 0) {
1308 LIST_FOREACH(pcb, &ng_btsocket_sco_sockets, next) {
1309 mtx_lock(&pcb->pcb_mtx);
1311 if (bcmp(&pcb->src, &sa->sco_bdaddr, sizeof(bdaddr_t)) == 0) {
1312 mtx_unlock(&pcb->pcb_mtx);
1313 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1315 return (EADDRINUSE);
1318 mtx_unlock(&pcb->pcb_mtx);
1323 pcb = so2sco_pcb(so);
1325 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1329 mtx_lock(&pcb->pcb_mtx);
1330 bcopy(&sa->sco_bdaddr, &pcb->src, sizeof(pcb->src));
1331 mtx_unlock(&pcb->pcb_mtx);
1333 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1336 } /* ng_btsocket_sco_bind */
1343 ng_btsocket_sco_connect(struct socket *so, struct sockaddr *nam,
1346 ng_btsocket_sco_pcb_t *pcb = so2sco_pcb(so);
1347 struct sockaddr_sco *sa = (struct sockaddr_sco *) nam;
1348 ng_btsocket_sco_rtentry_t *rt = NULL;
1349 int have_src, error = 0;
1354 if (ng_btsocket_sco_node == NULL)
1357 /* Verify address */
1360 if (sa->sco_family != AF_BLUETOOTH)
1361 return (EAFNOSUPPORT);
1362 if (sa->sco_len != sizeof(*sa))
1364 if (bcmp(&sa->sco_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
1365 return (EDESTADDRREQ);
1368 * Routing. Socket should be bound to some source address. The source
1369 * address can be ANY. Destination address must be set and it must not
1370 * be ANY. If source address is ANY then find first rtentry that has
1374 mtx_lock(&ng_btsocket_sco_rt_mtx);
1375 mtx_lock(&pcb->pcb_mtx);
1377 if (pcb->state == NG_BTSOCKET_SCO_CONNECTING) {
1378 mtx_unlock(&pcb->pcb_mtx);
1379 mtx_unlock(&ng_btsocket_sco_rt_mtx);
1381 return (EINPROGRESS);
1384 if (bcmp(&sa->sco_bdaddr, &pcb->src, sizeof(pcb->src)) == 0) {
1385 mtx_unlock(&pcb->pcb_mtx);
1386 mtx_unlock(&ng_btsocket_sco_rt_mtx);
1391 /* Send destination address and PSM */
1392 bcopy(&sa->sco_bdaddr, &pcb->dst, sizeof(pcb->dst));
1395 have_src = bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(pcb->src));
1397 LIST_FOREACH(rt, &ng_btsocket_sco_rt, next) {
1398 if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
1401 /* Match src and dst */
1403 if (bcmp(&pcb->src, &rt->src, sizeof(rt->src)) == 0)
1406 if (bcmp(&pcb->dst, &rt->src, sizeof(rt->src)) != 0)
1415 bcopy(&rt->src, &pcb->src, sizeof(pcb->src));
1417 error = EHOSTUNREACH;
1420 * Send LP_Connect request
1424 error = ng_btsocket_sco_send_lp_con_req(pcb);
1426 pcb->flags |= NG_BTSOCKET_SCO_CLIENT;
1427 pcb->state = NG_BTSOCKET_SCO_CONNECTING;
1428 soisconnecting(pcb->so);
1430 ng_btsocket_sco_timeout(pcb);
1434 mtx_unlock(&pcb->pcb_mtx);
1435 mtx_unlock(&ng_btsocket_sco_rt_mtx);
1438 } /* ng_btsocket_sco_connect */
1441 * Process ioctl's calls on socket
1445 ng_btsocket_sco_control(struct socket *so, u_long cmd, caddr_t data,
1446 struct ifnet *ifp, struct thread *td)
1449 } /* ng_btsocket_sco_control */
1452 * Process getsockopt/setsockopt system calls
1456 ng_btsocket_sco_ctloutput(struct socket *so, struct sockopt *sopt)
1458 ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so);
1461 if (ng_btsocket_sco_node == NULL)
1466 if (sopt->sopt_level != SOL_SCO)
1469 mtx_lock(&pcb->pcb_mtx);
1471 switch (sopt->sopt_dir) {
1473 if (pcb->state != NG_BTSOCKET_SCO_OPEN) {
1478 switch (sopt->sopt_name) {
1480 tmp = pcb->rt->pkt_size;
1481 error = sooptcopyout(sopt, &tmp, sizeof(tmp));
1484 case SO_SCO_CONNINFO:
1485 tmp = pcb->con_handle;
1486 error = sooptcopyout(sopt, &tmp, sizeof(tmp));
1496 error = ENOPROTOOPT;
1504 mtx_unlock(&pcb->pcb_mtx);
1507 } /* ng_btsocket_sco_ctloutput */
1510 * Detach and destroy socket
1514 ng_btsocket_sco_detach(struct socket *so)
1516 ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so);
1518 KASSERT(pcb != NULL, ("ng_btsocket_sco_detach: pcb == NULL"));
1520 if (ng_btsocket_sco_node == NULL)
1523 mtx_lock(&ng_btsocket_sco_sockets_mtx);
1524 mtx_lock(&pcb->pcb_mtx);
1526 if (pcb->flags & NG_BTSOCKET_SCO_TIMO)
1527 ng_btsocket_sco_untimeout(pcb);
1529 if (pcb->state == NG_BTSOCKET_SCO_OPEN)
1530 ng_btsocket_sco_send_lp_discon_req(pcb);
1532 pcb->state = NG_BTSOCKET_SCO_CLOSED;
1534 LIST_REMOVE(pcb, next);
1536 mtx_unlock(&pcb->pcb_mtx);
1537 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1539 mtx_destroy(&pcb->pcb_mtx);
1540 bzero(pcb, sizeof(*pcb));
1541 free(pcb, M_NETGRAPH_BTSOCKET_SCO);
1543 soisdisconnected(so);
1545 } /* ng_btsocket_sco_detach */
1552 ng_btsocket_sco_disconnect(struct socket *so)
1554 ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so);
1558 if (ng_btsocket_sco_node == NULL)
1561 mtx_lock(&pcb->pcb_mtx);
1563 if (pcb->state == NG_BTSOCKET_SCO_DISCONNECTING) {
1564 mtx_unlock(&pcb->pcb_mtx);
1566 return (EINPROGRESS);
1569 if (pcb->flags & NG_BTSOCKET_SCO_TIMO)
1570 ng_btsocket_sco_untimeout(pcb);
1572 if (pcb->state == NG_BTSOCKET_SCO_OPEN) {
1573 ng_btsocket_sco_send_lp_discon_req(pcb);
1575 pcb->state = NG_BTSOCKET_SCO_DISCONNECTING;
1576 soisdisconnecting(so);
1578 ng_btsocket_sco_timeout(pcb);
1580 pcb->state = NG_BTSOCKET_SCO_CLOSED;
1581 soisdisconnected(so);
1584 mtx_unlock(&pcb->pcb_mtx);
1587 } /* ng_btsocket_sco_disconnect */
1594 ng_btsocket_sco_listen(struct socket *so, int backlog, struct thread *td)
1596 ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so);
1601 if (ng_btsocket_sco_node == NULL)
1605 mtx_lock(&pcb->pcb_mtx);
1607 error = solisten_proto_check(so);
1611 if (bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0) {
1612 error = EDESTADDRREQ;
1616 solisten_proto(so, backlog);
1618 mtx_unlock(&pcb->pcb_mtx);
1622 } /* ng_btsocket_listen */
1629 ng_btsocket_sco_peeraddr(struct socket *so, struct sockaddr **nam)
1631 ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so);
1632 struct sockaddr_sco sa;
1636 if (ng_btsocket_sco_node == NULL)
1639 mtx_lock(&pcb->pcb_mtx);
1640 bcopy(&pcb->dst, &sa.sco_bdaddr, sizeof(sa.sco_bdaddr));
1641 mtx_unlock(&pcb->pcb_mtx);
1643 sa.sco_len = sizeof(sa);
1644 sa.sco_family = AF_BLUETOOTH;
1646 *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT);
1648 return ((*nam == NULL)? ENOMEM : 0);
1649 } /* ng_btsocket_sco_peeraddr */
1652 * Send data to socket
1656 ng_btsocket_sco_send(struct socket *so, int flags, struct mbuf *m,
1657 struct sockaddr *nam, struct mbuf *control, struct thread *td)
1659 ng_btsocket_sco_pcb_t *pcb = so2sco_pcb(so);
1662 if (ng_btsocket_sco_node == NULL) {
1667 /* Check socket and input */
1668 if (pcb == NULL || m == NULL || control != NULL) {
1673 mtx_lock(&pcb->pcb_mtx);
1675 /* Make sure socket is connected */
1676 if (pcb->state != NG_BTSOCKET_SCO_OPEN) {
1677 mtx_unlock(&pcb->pcb_mtx);
1683 if (pcb->rt == NULL ||
1684 pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook)) {
1685 mtx_unlock(&pcb->pcb_mtx);
1690 /* Check packet size */
1691 if (m->m_pkthdr.len > pcb->rt->pkt_size) {
1692 NG_BTSOCKET_SCO_ERR(
1693 "%s: Packet too big, len=%d, pkt_size=%d\n",
1694 __func__, m->m_pkthdr.len, pcb->rt->pkt_size);
1696 mtx_unlock(&pcb->pcb_mtx);
1702 * First put packet on socket send queue. Then check if we have
1703 * pending timeout. If we do not have timeout then we must send
1704 * packet and schedule timeout. Otherwise do nothing and wait for
1705 * NGM_HCI_SYNC_CON_QUEUE message.
1708 sbappendrecord(&pcb->so->so_snd, m);
1711 if (!(pcb->flags & NG_BTSOCKET_SCO_TIMO)) {
1712 error = ng_btsocket_sco_send2(pcb);
1714 ng_btsocket_sco_timeout(pcb);
1716 sbdroprecord(&pcb->so->so_snd); /* XXX */
1719 mtx_unlock(&pcb->pcb_mtx);
1721 NG_FREE_M(m); /* checks for != NULL */
1725 } /* ng_btsocket_sco_send */
1728 * Send first packet in the socket queue to the SCO layer
1732 ng_btsocket_sco_send2(ng_btsocket_sco_pcb_p pcb)
1734 struct mbuf *m = NULL;
1735 ng_hci_scodata_pkt_t *hdr = NULL;
1738 mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1740 while (pcb->rt->pending < pcb->rt->num_pkts &&
1741 pcb->so->so_snd.sb_cc > 0) {
1742 /* Get a copy of the first packet on send queue */
1743 m = m_dup(pcb->so->so_snd.sb_mb, M_DONTWAIT);
1749 /* Create SCO packet header */
1750 M_PREPEND(m, sizeof(*hdr), M_DONTWAIT);
1752 if (m->m_len < sizeof(*hdr))
1753 m = m_pullup(m, sizeof(*hdr));
1760 /* Fill in the header */
1761 hdr = mtod(m, ng_hci_scodata_pkt_t *);
1762 hdr->type = NG_HCI_SCO_DATA_PKT;
1763 hdr->con_handle = htole16(NG_HCI_MK_CON_HANDLE(pcb->con_handle, 0, 0));
1764 hdr->length = m->m_pkthdr.len - sizeof(*hdr);
1767 NG_SEND_DATA_ONLY(error, pcb->rt->hook, m);
1771 pcb->rt->pending ++;
1774 return ((pcb->rt->pending > 0)? 0 : error);
1775 } /* ng_btsocket_sco_send2 */
1778 * Get socket address
1782 ng_btsocket_sco_sockaddr(struct socket *so, struct sockaddr **nam)
1784 ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so);
1785 struct sockaddr_sco sa;
1789 if (ng_btsocket_sco_node == NULL)
1792 mtx_lock(&pcb->pcb_mtx);
1793 bcopy(&pcb->src, &sa.sco_bdaddr, sizeof(sa.sco_bdaddr));
1794 mtx_unlock(&pcb->pcb_mtx);
1796 sa.sco_len = sizeof(sa);
1797 sa.sco_family = AF_BLUETOOTH;
1799 *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT);
1801 return ((*nam == NULL)? ENOMEM : 0);
1802 } /* ng_btsocket_sco_sockaddr */
1804 /*****************************************************************************
1805 *****************************************************************************
1807 *****************************************************************************
1808 *****************************************************************************/
1811 * Look for the socket that listens on given bdaddr.
1812 * Returns exact or close match (if any).
1813 * Caller must hold ng_btsocket_sco_sockets_mtx.
1814 * Returns with locked pcb.
1817 static ng_btsocket_sco_pcb_p
1818 ng_btsocket_sco_pcb_by_addr(bdaddr_p bdaddr)
1820 ng_btsocket_sco_pcb_p p = NULL, p1 = NULL;
1822 mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED);
1824 LIST_FOREACH(p, &ng_btsocket_sco_sockets, next) {
1825 mtx_lock(&p->pcb_mtx);
1827 if (p->so == NULL || !(p->so->so_options & SO_ACCEPTCONN)) {
1828 mtx_unlock(&p->pcb_mtx);
1832 if (bcmp(&p->src, bdaddr, sizeof(p->src)) == 0)
1833 return (p); /* return with locked pcb */
1835 if (bcmp(&p->src, NG_HCI_BDADDR_ANY, sizeof(p->src)) == 0)
1838 mtx_unlock(&p->pcb_mtx);
1842 mtx_lock(&p1->pcb_mtx);
1845 } /* ng_btsocket_sco_pcb_by_addr */
1848 * Look for the socket that assigned to given source address and handle.
1849 * Caller must hold ng_btsocket_sco_sockets_mtx.
1850 * Returns with locked pcb.
1853 static ng_btsocket_sco_pcb_p
1854 ng_btsocket_sco_pcb_by_handle(bdaddr_p src, int con_handle)
1856 ng_btsocket_sco_pcb_p p = NULL;
1858 mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED);
1860 LIST_FOREACH(p, &ng_btsocket_sco_sockets, next) {
1861 mtx_lock(&p->pcb_mtx);
1863 if (p->con_handle == con_handle &&
1864 bcmp(src, &p->src, sizeof(p->src)) == 0)
1865 return (p); /* return with locked pcb */
1867 mtx_unlock(&p->pcb_mtx);
1871 } /* ng_btsocket_sco_pcb_by_handle */
1874 * Look for the socket in CONNECTING state with given source and destination
1875 * addresses. Caller must hold ng_btsocket_sco_sockets_mtx.
1876 * Returns with locked pcb.
1879 static ng_btsocket_sco_pcb_p
1880 ng_btsocket_sco_pcb_by_addrs(bdaddr_p src, bdaddr_p dst)
1882 ng_btsocket_sco_pcb_p p = NULL;
1884 mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED);
1886 LIST_FOREACH(p, &ng_btsocket_sco_sockets, next) {
1887 mtx_lock(&p->pcb_mtx);
1889 if (p->state == NG_BTSOCKET_SCO_CONNECTING &&
1890 bcmp(src, &p->src, sizeof(p->src)) == 0 &&
1891 bcmp(dst, &p->dst, sizeof(p->dst)) == 0)
1892 return (p); /* return with locked pcb */
1894 mtx_unlock(&p->pcb_mtx);
1898 } /* ng_btsocket_sco_pcb_by_addrs */
1901 * Set timeout on socket
1905 ng_btsocket_sco_timeout(ng_btsocket_sco_pcb_p pcb)
1907 mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1909 if (!(pcb->flags & NG_BTSOCKET_SCO_TIMO)) {
1910 pcb->flags |= NG_BTSOCKET_SCO_TIMO;
1911 callout_reset(&pcb->timo, bluetooth_sco_rtx_timeout(),
1912 ng_btsocket_sco_process_timeout, pcb);
1915 ("%s: Duplicated socket timeout?!\n", __func__));
1916 } /* ng_btsocket_sco_timeout */
1919 * Unset timeout on socket
1923 ng_btsocket_sco_untimeout(ng_btsocket_sco_pcb_p pcb)
1925 mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1927 if (pcb->flags & NG_BTSOCKET_SCO_TIMO) {
1928 callout_stop(&pcb->timo);
1929 pcb->flags &= ~NG_BTSOCKET_SCO_TIMO;
1932 ("%s: No socket timeout?!\n", __func__));
1933 } /* ng_btsocket_sco_untimeout */
1936 * Process timeout on socket
1940 ng_btsocket_sco_process_timeout(void *xpcb)
1942 ng_btsocket_sco_pcb_p pcb = (ng_btsocket_sco_pcb_p) xpcb;
1944 mtx_lock(&pcb->pcb_mtx);
1946 pcb->flags &= ~NG_BTSOCKET_SCO_TIMO;
1947 pcb->so->so_error = ETIMEDOUT;
1949 switch (pcb->state) {
1950 case NG_BTSOCKET_SCO_CONNECTING:
1951 /* Connect timeout - close the socket */
1952 pcb->state = NG_BTSOCKET_SCO_CLOSED;
1953 soisdisconnected(pcb->so);
1956 case NG_BTSOCKET_SCO_OPEN:
1957 /* Send timeout - did not get NGM_HCI_SYNC_CON_QUEUE */
1958 sbdroprecord(&pcb->so->so_snd);
1960 /* XXX FIXME what to do with pcb->rt->pending??? */
1963 case NG_BTSOCKET_SCO_DISCONNECTING:
1964 /* Disconnect timeout - disconnect the socket anyway */
1965 pcb->state = NG_BTSOCKET_SCO_CLOSED;
1966 soisdisconnected(pcb->so);
1970 NG_BTSOCKET_SCO_ERR(
1971 "%s: Invalid socket state=%d\n", __func__, pcb->state);
1975 mtx_unlock(&pcb->pcb_mtx);
1976 } /* ng_btsocket_sco_process_timeout */