root/netbt/sco_upper.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sco_attach
  2. sco_bind
  3. sco_sockaddr
  4. sco_connect
  5. sco_peeraddr
  6. sco_disconnect
  7. sco_detach
  8. sco_listen
  9. sco_send
  10. sco_setopt
  11. sco_getopt

    1 /*      $OpenBSD: sco_upper.c,v 1.1 2007/06/01 02:46:12 uwe Exp $       */
    2 /*      $NetBSD: sco_upper.c,v 1.6 2007/03/30 20:47:03 plunky Exp $     */
    3 
    4 /*-
    5  * Copyright (c) 2006 Itronix Inc.
    6  * All rights reserved.
    7  *
    8  * Written by Iain Hibbert for Itronix Inc.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. The name of Itronix Inc. may not be used to endorse
   19  *    or promote products derived from this software without specific
   20  *    prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   25  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
   26  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   27  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   29  * ON ANY THEORY OF LIABILITY, WHETHER IN
   30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   32  * POSSIBILITY OF SUCH DAMAGE.
   33  */
   34 
   35 #include <sys/cdefs.h>
   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 != NULL);
   66         KASSERT(proto != NULL);
   67         KASSERT(upper != NULL);
   68 
   69         pcb = malloc(sizeof(struct sco_pcb), M_BLUETOOTH, M_NOWAIT);
   70         if (pcb == NULL)
   71                 return ENOMEM;
   72         bzero(pcb, sizeof *pcb);
   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 != NULL);
  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                 err = ENOPROTOOPT;
  329                 break;
  330         }
  331 
  332         return err;
  333 }
  334 
  335 /*
  336  * sco_getopt(pcb, option, addr)
  337  *
  338  *      Get SCO pcb options
  339  */
  340 int
  341 sco_getopt(struct sco_pcb *pcb, int opt, void *addr)
  342 {
  343 
  344         switch (opt) {
  345         case SO_SCO_MTU:
  346                 *(uint16_t *)addr = pcb->sp_mtu;
  347                 return sizeof(uint16_t);
  348 
  349         case SO_SCO_HANDLE:
  350                 if (pcb->sp_link) {
  351                         *(uint16_t *)addr = pcb->sp_link->hl_handle;
  352                         return sizeof(uint16_t);
  353                 }
  354                 break;
  355 
  356         default:
  357                 break;
  358         }
  359         return 0;
  360 }

/* [<][>][^][v][top][bottom][index][help] */