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/netbt/sco_upper.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 /*      $NetBSD: sco_upper.c,v 1.8 2008/08/06 15:01:24 plunky Exp $     */
    2 
    3 /*-
    4  * Copyright (c) 2006 Itronix Inc.
    5  * All rights reserved.
    6  *
    7  * Written by Iain Hibbert for Itronix Inc.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. The name of Itronix Inc. may not be used to endorse
   18  *    or promote products derived from this software without specific
   19  *    prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
   25  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   28  * ON ANY THEORY OF LIABILITY, WHETHER IN
   29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   31  * POSSIBILITY OF SUCH DAMAGE.
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __KERNEL_RCSID(0, "$NetBSD: sco_upper.c,v 1.8 2008/08/06 15:01:24 plunky Exp $");
   36 
   37 #include <sys/param.h>
   38 #include <sys/kernel.h>
   39 #include <sys/mbuf.h>
   40 #include <sys/proc.h>
   41 #include <sys/socketvar.h>
   42 #include <sys/systm.h>
   43 
   44 #include <netbt/bluetooth.h>
   45 #include <netbt/hci.h>
   46 #include <netbt/sco.h>
   47 
   48 /****************************************************************************
   49  *
   50  *      SCO - Upper Protocol API
   51  */
   52 
   53 struct sco_pcb_list sco_pcb = LIST_HEAD_INITIALIZER(sco_pcb);
   54 
   55 /*
   56  * sco_attach(handle, proto, upper)
   57  *
   58  *      Attach a new instance of SCO pcb to handle
   59  */
   60 int
   61 sco_attach(struct sco_pcb **handle,
   62                 const struct btproto *proto, void *upper)
   63 {
   64         struct sco_pcb *pcb;
   65 
   66         KASSERT(handle != NULL);
   67         KASSERT(proto != NULL);
   68         KASSERT(upper != NULL);
   69 
   70         pcb = malloc(sizeof(struct sco_pcb), M_BLUETOOTH,
   71                         M_NOWAIT | M_ZERO);
   72         if (pcb == NULL)
   73                 return ENOMEM;
   74 
   75         pcb->sp_proto = proto;
   76         pcb->sp_upper = upper;
   77 
   78         LIST_INSERT_HEAD(&sco_pcb, pcb, sp_next);
   79 
   80         *handle = pcb;
   81         return 0;
   82 }
   83 
   84 /*
   85  * sco_bind(pcb, sockaddr)
   86  *
   87  *      Bind SCO pcb to local address
   88  */
   89 int
   90 sco_bind(struct sco_pcb *pcb, struct sockaddr_bt *addr)
   91 {
   92 
   93         bdaddr_copy(&pcb->sp_laddr, &addr->bt_bdaddr);
   94         return 0;
   95 }
   96 
   97 /*
   98  * sco_sockaddr(pcb, sockaddr)
   99  *
  100  *      Copy local address of PCB to sockaddr
  101  */
  102 int
  103 sco_sockaddr(struct sco_pcb *pcb, struct sockaddr_bt *addr)
  104 {
  105 
  106         memset(addr, 0, sizeof(struct sockaddr_bt));
  107         addr->bt_len = sizeof(struct sockaddr_bt);
  108         addr->bt_family = AF_BLUETOOTH;
  109         bdaddr_copy(&addr->bt_bdaddr, &pcb->sp_laddr);
  110         return 0;
  111 }
  112 
  113 /*
  114  * sco_connect(pcb, sockaddr)
  115  *
  116  *      Initiate a SCO connection to the destination address.
  117  */
  118 int
  119 sco_connect(struct sco_pcb *pcb, struct sockaddr_bt *dest)
  120 {
  121         hci_add_sco_con_cp cp;
  122         struct hci_unit *unit;
  123         struct hci_link *acl, *sco;
  124         int err;
  125 
  126         if (pcb->sp_flags & SP_LISTENING)
  127                 return EINVAL;
  128 
  129         bdaddr_copy(&pcb->sp_raddr, &dest->bt_bdaddr);
  130 
  131         if (bdaddr_any(&pcb->sp_raddr))
  132                 return EDESTADDRREQ;
  133 
  134         if (bdaddr_any(&pcb->sp_laddr)) {
  135                 err = hci_route_lookup(&pcb->sp_laddr, &pcb->sp_raddr);
  136                 if (err)
  137                         return err;
  138         }
  139 
  140         unit = hci_unit_lookup(&pcb->sp_laddr);
  141         if (unit == NULL)
  142                 return ENETDOWN;
  143 
  144         /*
  145          * We must have an already open ACL connection before we open the SCO
  146          * connection, and since SCO connections dont happen on their own we
  147          * will not open one, the application wanting this should have opened
  148          * it previously.
  149          */
  150         acl = hci_link_lookup_bdaddr(unit, &pcb->sp_raddr, HCI_LINK_ACL);
  151         if (acl == NULL || acl->hl_state != HCI_LINK_OPEN)
  152                 return EHOSTUNREACH;
  153 
  154         sco = hci_link_alloc(unit, &pcb->sp_raddr, HCI_LINK_SCO);
  155         if (sco == NULL)
  156                 return ENOMEM;
  157 
  158         sco->hl_link = hci_acl_open(unit, &pcb->sp_raddr);
  159         KASSERT(sco->hl_link == acl);
  160 
  161         cp.con_handle = htole16(acl->hl_handle);
  162         cp.pkt_type = htole16(0x00e0);          /* HV1, HV2, HV3 */
  163         err = hci_send_cmd(unit, HCI_CMD_ADD_SCO_CON, &cp, sizeof(cp));
  164         if (err) {
  165                 hci_link_free(sco, err);
  166                 return err;
  167         }
  168 
  169         sco->hl_sco = pcb;
  170         pcb->sp_link = sco;
  171 
  172         pcb->sp_mtu = unit->hci_max_sco_size;
  173         return 0;
  174 }
  175 
  176 /*
  177  * sco_peeraddr(pcb, sockaddr)
  178  *
  179  *      Copy remote address of SCO pcb to sockaddr
  180  */
  181 int
  182 sco_peeraddr(struct sco_pcb *pcb, struct sockaddr_bt *addr)
  183 {
  184 
  185         memset(addr, 0, sizeof(struct sockaddr_bt));
  186         addr->bt_len = sizeof(struct sockaddr_bt);
  187         addr->bt_family = AF_BLUETOOTH;
  188         bdaddr_copy(&addr->bt_bdaddr, &pcb->sp_raddr);
  189         return 0;
  190 }
  191 
  192 /*
  193  * sco_disconnect(pcb, linger)
  194  *
  195  *      Initiate disconnection of connected SCO pcb
  196  */
  197 int
  198 sco_disconnect(struct sco_pcb *pcb, int linger)
  199 {
  200         hci_discon_cp cp;
  201         struct hci_link *sco;
  202         int err;
  203 
  204         sco = pcb->sp_link;
  205         if (sco == NULL)
  206                 return EINVAL;
  207 
  208         cp.con_handle = htole16(sco->hl_handle);
  209         cp.reason = 0x13;       /* "Remote User Terminated Connection" */
  210 
  211         err = hci_send_cmd(sco->hl_unit, HCI_CMD_DISCONNECT, &cp, sizeof(cp));
  212         if (err || linger == 0) {
  213                 sco->hl_sco = NULL;
  214                 pcb->sp_link = NULL;
  215                 hci_link_free(sco, err);
  216         }
  217 
  218         return err;
  219 }
  220 
  221 /*
  222  * sco_detach(handle)
  223  *
  224  *      Detach SCO pcb from handle and clear up
  225  */
  226 int
  227 sco_detach(struct sco_pcb **handle)
  228 {
  229         struct sco_pcb *pcb;
  230 
  231         KASSERT(handle != NULL);
  232         pcb = *handle;
  233         *handle = NULL;
  234 
  235         if (pcb == NULL)
  236                 return EINVAL;
  237 
  238         if (pcb->sp_link != NULL) {
  239                 sco_disconnect(pcb, 0);
  240                 pcb->sp_link = NULL;
  241         }
  242 
  243         LIST_REMOVE(pcb, sp_next);
  244         free(pcb, M_BLUETOOTH);
  245         return 0;
  246 }
  247 
  248 /*
  249  * sco_listen(pcb)
  250  *
  251  *      Mark pcb as a listener.
  252  */
  253 int
  254 sco_listen(struct sco_pcb *pcb)
  255 {
  256 
  257         if (pcb->sp_link != NULL)
  258                 return EINVAL;
  259 
  260         pcb->sp_flags |= SP_LISTENING;
  261         return 0;
  262 }
  263 
  264 /*
  265  * sco_send(pcb, mbuf)
  266  *
  267  *      Send data on SCO pcb.
  268  *
  269  * Gross hackage, we just output the packet directly onto the unit queue.
  270  * This will work fine for one channel per unit, but for more channels it
  271  * really needs fixing. We set the context so that when the packet is sent,
  272  * we can drop a record from the socket buffer.
  273  */
  274 int
  275 sco_send(struct sco_pcb *pcb, struct mbuf *m)
  276 {
  277         hci_scodata_hdr_t *hdr;
  278         int plen;
  279 
  280         if (pcb->sp_link == NULL) {
  281                 m_freem(m);
  282                 return EINVAL;
  283         }
  284 
  285         plen = m->m_pkthdr.len;
  286         DPRINTFN(10, "%d bytes\n", plen);
  287 
  288         /*
  289          * This is a temporary limitation, as USB devices cannot
  290          * handle SCO packet sizes that are not an integer number
  291          * of Isochronous frames. See ubt(4)
  292          */
  293         if (plen != pcb->sp_mtu) {
  294                 m_freem(m);
  295                 return EMSGSIZE;
  296         }
  297 
  298         M_PREPEND(m, sizeof(hci_scodata_hdr_t), M_DONTWAIT);
  299         if (m == NULL)
  300                 return ENOMEM;
  301 
  302         hdr = mtod(m, hci_scodata_hdr_t *);
  303         hdr->type = HCI_SCO_DATA_PKT;
  304         hdr->con_handle = htole16(pcb->sp_link->hl_handle);
  305         hdr->length = plen;
  306 
  307         pcb->sp_pending++;
  308         M_SETCTX(m, pcb->sp_link);
  309         hci_output_sco(pcb->sp_link->hl_unit, m);
  310 
  311         return 0;
  312 }
  313 
  314 /*
  315  * sco_setopt(pcb, sopt)
  316  *
  317  *      Set SCO pcb options
  318  */
  319 int
  320 sco_setopt(struct sco_pcb *pcb, const struct sockopt *sopt)
  321 {
  322         int err = 0;
  323 
  324         switch (sopt->sopt_name) {
  325         default:
  326                 err = ENOPROTOOPT;
  327                 break;
  328         }
  329 
  330         return err;
  331 }
  332 
  333 /*
  334  * sco_getopt(pcb, sopt)
  335  *
  336  *      Get SCO pcb options
  337  */
  338 int
  339 sco_getopt(struct sco_pcb *pcb, struct sockopt *sopt)
  340 {
  341 
  342         switch (sopt->sopt_name) {
  343         case SO_SCO_MTU:
  344                 return sockopt_set(sopt, &pcb->sp_mtu, sizeof(uint16_t));
  345 
  346         case SO_SCO_HANDLE:
  347                 if (pcb->sp_link)
  348                         return sockopt_set(sopt,
  349                             &pcb->sp_link->hl_handle, sizeof(uint16_t));
  350 
  351                 return ENOTCONN;
  352 
  353         default:
  354                 break;
  355         }
  356 
  357         return ENOPROTOOPT;
  358 }

Cache object: 84d748026f01b4038cb6966e4203ca06


[ 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.