The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netgraph/bluetooth/socket/ng_btsocket_sco.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 2fb1cc64f5e37caad40a35cfc789854d


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.