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.4 2006/11/16 01:33:45 christos 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.4 2006/11/16 01:33:45 christos 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/systm.h>
   42 
   43 #include <netbt/bluetooth.h>
   44 #include <netbt/hci.h>
   45 #include <netbt/sco.h>
   46 
   47 /****************************************************************************
   48  *
   49  *      SCO - Upper Protocol API
   50  */
   51 
   52 struct sco_pcb_list sco_pcb = LIST_HEAD_INITIALIZER(sco_pcb);
   53 
   54 /*
   55  * sco_attach(handle, proto, upper)
   56  *
   57  *      Attach a new instance of SCO pcb to handle
   58  */
   59 int
   60 sco_attach(struct sco_pcb **handle,
   61                 const struct btproto *proto, void *upper)
   62 {
   63         struct sco_pcb *pcb;
   64 
   65         KASSERT(handle);
   66         KASSERT(proto);
   67         KASSERT(upper);
   68 
   69         pcb = malloc(sizeof(struct sco_pcb), M_BLUETOOTH,
   70                         M_NOWAIT | M_ZERO);
   71         if (pcb == NULL)
   72                 return ENOMEM;
   73 
   74         pcb->sp_proto = proto;
   75         pcb->sp_upper = upper;
   76 
   77         LIST_INSERT_HEAD(&sco_pcb, pcb, sp_next);
   78 
   79         *handle = pcb;
   80         return 0;
   81 }
   82 
   83 /*
   84  * sco_bind(pcb, sockaddr)
   85  *
   86  *      Bind SCO pcb to local address
   87  */
   88 int
   89 sco_bind(struct sco_pcb *pcb, struct sockaddr_bt *addr)
   90 {
   91 
   92         bdaddr_copy(&pcb->sp_laddr, &addr->bt_bdaddr);
   93         return 0;
   94 }
   95 
   96 /*
   97  * sco_sockaddr(pcb, sockaddr)
   98  *
   99  *      Copy local address of PCB to sockaddr
  100  */
  101 int
  102 sco_sockaddr(struct sco_pcb *pcb, struct sockaddr_bt *addr)
  103 {
  104 
  105         memset(addr, 0, sizeof(struct sockaddr_bt));
  106         addr->bt_len = sizeof(struct sockaddr_bt);
  107         addr->bt_family = AF_BLUETOOTH;
  108         bdaddr_copy(&addr->bt_bdaddr, &pcb->sp_laddr);
  109         return 0;
  110 }
  111 
  112 /*
  113  * sco_connect(pcb, sockaddr)
  114  *
  115  *      Initiate a SCO connection to the destination address.
  116  */
  117 int
  118 sco_connect(struct sco_pcb *pcb, struct sockaddr_bt *dest)
  119 {
  120         hci_add_sco_con_cp cp;
  121         struct hci_unit *unit;
  122         struct hci_link *acl, *sco;
  123         int err;
  124 
  125         if (pcb->sp_flags & SP_LISTENING)
  126                 return EINVAL;
  127 
  128         bdaddr_copy(&pcb->sp_raddr, &dest->bt_bdaddr);
  129 
  130         if (bdaddr_any(&pcb->sp_raddr))
  131                 return EDESTADDRREQ;
  132 
  133         if (bdaddr_any(&pcb->sp_laddr)) {
  134                 err = hci_route_lookup(&pcb->sp_laddr, &pcb->sp_raddr);
  135                 if (err)
  136                         return err;
  137         }
  138 
  139         unit = hci_unit_lookup(&pcb->sp_laddr);
  140         if (unit == NULL)
  141                 return ENETDOWN;
  142 
  143         /*
  144          * We must have an already open ACL connection before we open the SCO
  145          * connection, and since SCO connections dont happen on their own we
  146          * will not open one, the application wanting this should have opened
  147          * it previously.
  148          */
  149         acl = hci_link_lookup_bdaddr(unit, &pcb->sp_raddr, HCI_LINK_ACL);
  150         if (acl == NULL || acl->hl_state != HCI_LINK_OPEN)
  151                 return EHOSTUNREACH;
  152 
  153         sco = hci_link_alloc(unit);
  154         if (sco == NULL)
  155                 return ENOMEM;
  156 
  157         sco->hl_type = HCI_LINK_SCO;
  158         bdaddr_copy(&sco->hl_bdaddr, &pcb->sp_raddr);
  159 
  160         sco->hl_link = hci_acl_open(unit, &pcb->sp_raddr);
  161         KASSERT(sco->hl_link == acl);
  162 
  163         cp.con_handle = htole16(acl->hl_handle);
  164         cp.pkt_type = htole16(0x00e0);          /* HV1, HV2, HV3 */
  165         err = hci_send_cmd(unit, HCI_CMD_ADD_SCO_CON, &cp, sizeof(cp));
  166         if (err) {
  167                 hci_link_free(sco, err);
  168                 return err;
  169         }
  170 
  171         sco->hl_sco = pcb;
  172         pcb->sp_link = sco;
  173 
  174         pcb->sp_mtu = unit->hci_max_sco_size;
  175         return 0;
  176 }
  177 
  178 /*
  179  * sco_peeraddr(pcb, sockaddr)
  180  *
  181  *      Copy remote address of SCO pcb to sockaddr
  182  */
  183 int
  184 sco_peeraddr(struct sco_pcb *pcb, struct sockaddr_bt *addr)
  185 {
  186 
  187         memset(addr, 0, sizeof(struct sockaddr_bt));
  188         addr->bt_len = sizeof(struct sockaddr_bt);
  189         addr->bt_family = AF_BLUETOOTH;
  190         bdaddr_copy(&addr->bt_bdaddr, &pcb->sp_raddr);
  191         return 0;
  192 }
  193 
  194 /*
  195  * sco_disconnect(pcb, linger)
  196  *
  197  *      Initiate disconnection of connected SCO pcb
  198  */
  199 int
  200 sco_disconnect(struct sco_pcb *pcb, int linger)
  201 {
  202         hci_discon_cp cp;
  203         struct hci_link *sco;
  204         int err;
  205 
  206         sco = pcb->sp_link;
  207         if (sco == NULL)
  208                 return EINVAL;
  209 
  210         cp.con_handle = htole16(sco->hl_handle);
  211         cp.reason = 0x13;       /* "Remote User Terminated Connection" */
  212 
  213         err = hci_send_cmd(sco->hl_unit, HCI_CMD_DISCONNECT, &cp, sizeof(cp));
  214         if (err || linger == 0) {
  215                 sco->hl_sco = NULL;
  216                 pcb->sp_link = NULL;
  217                 hci_link_free(sco, err);
  218         }
  219 
  220         return err;
  221 }
  222 
  223 /*
  224  * sco_detach(handle)
  225  *
  226  *      Detach SCO pcb from handle and clear up
  227  */
  228 int
  229 sco_detach(struct sco_pcb **handle)
  230 {
  231         struct sco_pcb *pcb;
  232 
  233         KASSERT(handle);
  234         pcb = *handle;
  235         *handle = NULL;
  236 
  237         if (pcb == NULL)
  238                 return EINVAL;
  239 
  240         if (pcb->sp_link != NULL) {
  241                 sco_disconnect(pcb, 0);
  242                 pcb->sp_link = NULL;
  243         }
  244 
  245         LIST_REMOVE(pcb, sp_next);
  246         free(pcb, M_BLUETOOTH);
  247         return 0;
  248 }
  249 
  250 /*
  251  * sco_listen(pcb)
  252  *
  253  *      Mark pcb as a listener.
  254  */
  255 int
  256 sco_listen(struct sco_pcb *pcb)
  257 {
  258 
  259         if (pcb->sp_link != NULL)
  260                 return EINVAL;
  261 
  262         pcb->sp_flags |= SP_LISTENING;
  263         return 0;
  264 }
  265 
  266 /*
  267  * sco_send(pcb, mbuf)
  268  *
  269  *      Send data on SCO pcb.
  270  *
  271  * Gross hackage, we just output the packet directly onto the unit queue.
  272  * This will work fine for one channel per unit, but for more channels it
  273  * really needs fixing. We set the context so that when the packet is sent,
  274  * we can drop a record from the socket buffer.
  275  */
  276 int
  277 sco_send(struct sco_pcb *pcb, struct mbuf *m)
  278 {
  279         hci_scodata_hdr_t *hdr;
  280         int plen;
  281 
  282         if (pcb->sp_link == NULL) {
  283                 m_freem(m);
  284                 return EINVAL;
  285         }
  286 
  287         plen = m->m_pkthdr.len;
  288         DPRINTFN(10, "%d bytes\n", plen);
  289 
  290         /*
  291          * This is a temporary limitation, as USB devices cannot
  292          * handle SCO packet sizes that are not an integer number
  293          * of Isochronous frames. See ubt(4)
  294          */
  295         if (plen != pcb->sp_mtu) {
  296                 m_freem(m);
  297                 return EMSGSIZE;
  298         }
  299 
  300         M_PREPEND(m, sizeof(hci_scodata_hdr_t), M_DONTWAIT);
  301         if (m == NULL)
  302                 return ENOMEM;
  303 
  304         hdr = mtod(m, hci_scodata_hdr_t *);
  305         hdr->type = HCI_SCO_DATA_PKT;
  306         hdr->con_handle = htole16(pcb->sp_link->hl_handle);
  307         hdr->length = plen;
  308 
  309         pcb->sp_pending++;
  310         M_SETCTX(m, pcb->sp_link);
  311         hci_output_sco(pcb->sp_link->hl_unit, m);
  312 
  313         return 0;
  314 }
  315 
  316 /*
  317  * sco_setopt(pcb, option, addr)
  318  *
  319  *      Set SCO pcb options
  320  */
  321 int
  322 sco_setopt(struct sco_pcb *pcb, int opt, void *addr)
  323 {
  324         int err = 0;
  325 
  326         switch (opt) {
  327         default:
  328                 break;
  329         }
  330 
  331         return err;
  332 }
  333 
  334 /*
  335  * sco_getopt(pcb, option, addr)
  336  *
  337  *      Get SCO pcb options
  338  */
  339 int
  340 sco_getopt(struct sco_pcb *pcb, int opt, void *addr)
  341 {
  342 
  343         switch (opt) {
  344         case SO_SCO_MTU:
  345                 *(uint16_t *)addr = pcb->sp_mtu;
  346                 return sizeof(uint16_t);
  347 
  348         case SO_SCO_HANDLE:
  349                 if (pcb->sp_link) {
  350                         *(uint16_t *)addr = pcb->sp_link->hl_handle;
  351                         return sizeof(uint16_t);
  352                 }
  353                 break;
  354 
  355         default:
  356                 break;
  357         }
  358         return 0;
  359 }

Cache object: d60783070a248463bc475e32ac3e70b2


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