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/l2cap_misc.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: l2cap_misc.c,v 1.1.18.1 2007/07/19 16:04:19 liamjfoy Exp $     */
    2 
    3 /*-
    4  * Copyright (c) 2005 Iain Hibbert.
    5  * Copyright (c) 2006 Itronix Inc.
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. The name of Itronix Inc. may not be used to endorse
   17  *    or promote products derived from this software without specific
   18  *    prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
   24  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   27  * ON ANY THEORY OF LIABILITY, WHETHER IN
   28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   30  * POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __KERNEL_RCSID(0, "$NetBSD: l2cap_misc.c,v 1.1.18.1 2007/07/19 16:04:19 liamjfoy Exp $");
   35 
   36 #include <sys/param.h>
   37 #include <sys/kernel.h>
   38 #include <sys/mbuf.h>
   39 #include <sys/proc.h>
   40 #include <sys/queue.h>
   41 #include <sys/systm.h>
   42 
   43 #include <netbt/bluetooth.h>
   44 #include <netbt/hci.h>
   45 #include <netbt/l2cap.h>
   46 
   47 struct l2cap_channel_list
   48         l2cap_active_list = LIST_HEAD_INITIALIZER(l2cap_active_list);
   49 struct l2cap_channel_list
   50         l2cap_listen_list = LIST_HEAD_INITIALIZER(l2cap_listen_list);
   51 
   52 POOL_INIT(l2cap_req_pool, sizeof(struct l2cap_req), 0, 0, 0, "l2cap_req", NULL);
   53 POOL_INIT(l2cap_pdu_pool, sizeof(struct l2cap_pdu), 0, 0, 0, "l2cap_pdu", NULL);
   54 
   55 const l2cap_qos_t l2cap_default_qos = {
   56         0,                      /* flags */
   57         L2CAP_QOS_BEST_EFFORT,  /* service type */
   58         0x00000000,             /* token rate */
   59         0x00000000,             /* token bucket size */
   60         0x00000000,             /* peak bandwidth */
   61         0xffffffff,             /* latency */
   62         0xffffffff              /* delay variation */
   63 };
   64 
   65 /*
   66  * L2CAP request timeouts
   67  */
   68 int l2cap_response_timeout = 30;                /* seconds */
   69 int l2cap_response_extended_timeout = 180;      /* seconds */
   70 
   71 /*
   72  * Set Link Mode on channel
   73  */
   74 int
   75 l2cap_setmode(struct l2cap_channel *chan)
   76 {
   77 
   78         KASSERT(chan != NULL);
   79         KASSERT(chan->lc_link != NULL);
   80 
   81         DPRINTF("CID #%d, auth %s, encrypt %s, secure %s\n", chan->lc_lcid,
   82                 (chan->lc_mode & L2CAP_LM_AUTH ? "yes" : "no"),
   83                 (chan->lc_mode & L2CAP_LM_ENCRYPT ? "yes" : "no"),
   84                 (chan->lc_mode & L2CAP_LM_SECURE ? "yes" : "no"));
   85 
   86         if (chan->lc_mode & L2CAP_LM_AUTH)
   87                 chan->lc_link->hl_flags |= HCI_LINK_AUTH_REQ;
   88 
   89         if (chan->lc_mode & L2CAP_LM_ENCRYPT)
   90                 chan->lc_link->hl_flags |= HCI_LINK_ENCRYPT_REQ;
   91 
   92         if (chan->lc_mode & L2CAP_LM_SECURE)
   93                 chan->lc_link->hl_flags |= HCI_LINK_SECURE_REQ;
   94 
   95         return hci_acl_setmode(chan->lc_link);
   96 }
   97 
   98 /*
   99  * Allocate a new Request structure & ID and set the timer going
  100  */
  101 int
  102 l2cap_request_alloc(struct l2cap_channel *chan, uint8_t code)
  103 {
  104         struct hci_link *link = chan->lc_link;
  105         struct l2cap_req *req;
  106         int next_id;
  107 
  108         if (link == NULL)
  109                 return ENETDOWN;
  110 
  111         /* find next ID (0 is not allowed) */
  112         next_id = link->hl_lastid + 1;
  113         if (next_id > 0xff)
  114                 next_id = 1;
  115 
  116         /* Ouroboros check */
  117         req = TAILQ_FIRST(&link->hl_reqs);
  118         if (req && req->lr_id == next_id)
  119                 return ENFILE;
  120 
  121         req = pool_get(&l2cap_req_pool, PR_NOWAIT);
  122         if (req == NULL)
  123                 return ENOMEM;
  124 
  125         req->lr_id = link->hl_lastid = next_id;
  126 
  127         req->lr_code = code;
  128         req->lr_chan = chan;
  129         req->lr_link = link;
  130 
  131         callout_init(&req->lr_rtx);
  132         callout_reset(&req->lr_rtx, l2cap_response_timeout*hz, l2cap_rtx, req);
  133 
  134         TAILQ_INSERT_TAIL(&link->hl_reqs, req, lr_next);
  135 
  136         return 0;
  137 }
  138 
  139 /*
  140  * Find a running request for this link
  141  */
  142 struct l2cap_req *
  143 l2cap_request_lookup(struct hci_link *link, uint8_t id)
  144 {
  145         struct l2cap_req *req;
  146 
  147         TAILQ_FOREACH(req, &link->hl_reqs, lr_next) {
  148                 if (req->lr_id == id)
  149                         return req;
  150         }
  151 
  152         return NULL;
  153 }
  154 
  155 /*
  156  * Halt and free a request
  157  */
  158 void
  159 l2cap_request_free(struct l2cap_req *req)
  160 {
  161         struct hci_link *link = req->lr_link;
  162 
  163         callout_stop(&req->lr_rtx);
  164         if (callout_invoking(&req->lr_rtx))
  165                 return;
  166 
  167         TAILQ_REMOVE(&link->hl_reqs, req, lr_next);
  168         pool_put(&l2cap_req_pool, req);
  169 }
  170 
  171 /*
  172  * Response Timeout eXpired
  173  *
  174  * No response to our request, so deal with it as best we can.
  175  *
  176  * XXX should try again at least with ertx?
  177  */
  178 void
  179 l2cap_rtx(void *arg)
  180 {
  181         struct l2cap_req *req = arg;
  182         struct l2cap_channel *chan;
  183         int s;
  184 
  185         s = splsoftnet();
  186         callout_ack(&req->lr_rtx);
  187 
  188         chan = req->lr_chan;
  189         l2cap_request_free(req);
  190 
  191         DPRINTF("cid %d, ident %d\n", (chan ? chan->lc_lcid : 0), req->lr_id);
  192 
  193         if (chan && chan->lc_state != L2CAP_CLOSED)
  194                 l2cap_close(chan, ETIMEDOUT);
  195 
  196         splx(s);
  197 }
  198 
  199 /*
  200  * Allocate next available CID to channel. We keep a single
  201  * ordered list of channels, so find the first gap.
  202  *
  203  * If this turns out to be not enough (!), could use a
  204  * list per HCI unit..
  205  */
  206 int
  207 l2cap_cid_alloc(struct l2cap_channel *chan)
  208 {
  209         struct l2cap_channel *used, *prev = NULL;
  210         uint16_t cid = L2CAP_FIRST_CID;
  211 
  212         if (chan->lc_lcid != L2CAP_NULL_CID || chan->lc_state != L2CAP_CLOSED)
  213                 return EISCONN;
  214 
  215         LIST_FOREACH(used, &l2cap_active_list, lc_ncid) {
  216                 if (used->lc_lcid > cid)
  217                         break;  /* found our gap */
  218 
  219                 KASSERT(used->lc_lcid == cid);
  220                 cid++;
  221 
  222                 if (cid == L2CAP_LAST_CID)
  223                         return ENFILE;
  224 
  225                 prev = used;    /* for insert after */
  226         }
  227 
  228         chan->lc_lcid = cid;
  229 
  230         if (prev)
  231                 LIST_INSERT_AFTER(prev, chan, lc_ncid);
  232         else
  233                 LIST_INSERT_HEAD(&l2cap_active_list, chan, lc_ncid);
  234 
  235         return 0;
  236 }
  237 
  238 /*
  239  * Find channel with CID
  240  */
  241 struct l2cap_channel *
  242 l2cap_cid_lookup(uint16_t cid)
  243 {
  244         struct l2cap_channel *chan;
  245 
  246         LIST_FOREACH(chan, &l2cap_active_list, lc_ncid) {
  247                 if (chan->lc_lcid == cid)
  248                         return chan;
  249 
  250                 if (chan->lc_lcid > cid)
  251                         return NULL;
  252         }
  253 
  254         return NULL;
  255 }

Cache object: 3628e2a9bdce4ec92c7b5a9911e997e3


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