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.6 2008/04/24 11:38:37 ad 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.6 2008/04/24 11:38:37 ad 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     IPL_SOFTNET);
   54 POOL_INIT(l2cap_pdu_pool, sizeof(struct l2cap_pdu), 0, 0, 0, "l2cap_pdu", NULL,
   55     IPL_SOFTNET);
   56 
   57 const l2cap_qos_t l2cap_default_qos = {
   58         0,                      /* flags */
   59         L2CAP_QOS_BEST_EFFORT,  /* service type */
   60         0x00000000,             /* token rate */
   61         0x00000000,             /* token bucket size */
   62         0x00000000,             /* peak bandwidth */
   63         0xffffffff,             /* latency */
   64         0xffffffff              /* delay variation */
   65 };
   66 
   67 /*
   68  * L2CAP request timeouts
   69  */
   70 int l2cap_response_timeout = 30;                /* seconds */
   71 int l2cap_response_extended_timeout = 180;      /* seconds */
   72 
   73 /*
   74  * Set Link Mode on channel
   75  */
   76 int
   77 l2cap_setmode(struct l2cap_channel *chan)
   78 {
   79 
   80         KASSERT(chan != NULL);
   81         KASSERT(chan->lc_link != NULL);
   82 
   83         DPRINTF("CID #%d, auth %s, encrypt %s, secure %s\n", chan->lc_lcid,
   84                 (chan->lc_mode & L2CAP_LM_AUTH ? "yes" : "no"),
   85                 (chan->lc_mode & L2CAP_LM_ENCRYPT ? "yes" : "no"),
   86                 (chan->lc_mode & L2CAP_LM_SECURE ? "yes" : "no"));
   87 
   88         if (chan->lc_mode & L2CAP_LM_AUTH)
   89                 chan->lc_link->hl_flags |= HCI_LINK_AUTH_REQ;
   90 
   91         if (chan->lc_mode & L2CAP_LM_ENCRYPT)
   92                 chan->lc_link->hl_flags |= HCI_LINK_ENCRYPT_REQ;
   93 
   94         if (chan->lc_mode & L2CAP_LM_SECURE)
   95                 chan->lc_link->hl_flags |= HCI_LINK_SECURE_REQ;
   96 
   97         return hci_acl_setmode(chan->lc_link);
   98 }
   99 
  100 /*
  101  * Allocate a new Request structure & ID and set the timer going
  102  */
  103 int
  104 l2cap_request_alloc(struct l2cap_channel *chan, uint8_t code)
  105 {
  106         struct hci_link *link = chan->lc_link;
  107         struct l2cap_req *req;
  108         int next_id;
  109 
  110         if (link == NULL)
  111                 return ENETDOWN;
  112 
  113         /* find next ID (0 is not allowed) */
  114         next_id = link->hl_lastid + 1;
  115         if (next_id > 0xff)
  116                 next_id = 1;
  117 
  118         /* Ouroboros check */
  119         req = TAILQ_FIRST(&link->hl_reqs);
  120         if (req && req->lr_id == next_id)
  121                 return ENFILE;
  122 
  123         req = pool_get(&l2cap_req_pool, PR_NOWAIT);
  124         if (req == NULL)
  125                 return ENOMEM;
  126 
  127         req->lr_id = link->hl_lastid = next_id;
  128 
  129         req->lr_code = code;
  130         req->lr_chan = chan;
  131         req->lr_link = link;
  132 
  133         callout_init(&req->lr_rtx, 0);
  134         callout_setfunc(&req->lr_rtx, l2cap_rtx, req);
  135         callout_schedule(&req->lr_rtx, l2cap_response_timeout * hz);
  136 
  137         TAILQ_INSERT_TAIL(&link->hl_reqs, req, lr_next);
  138 
  139         return 0;
  140 }
  141 
  142 /*
  143  * Find a running request for this link
  144  */
  145 struct l2cap_req *
  146 l2cap_request_lookup(struct hci_link *link, uint8_t id)
  147 {
  148         struct l2cap_req *req;
  149 
  150         TAILQ_FOREACH(req, &link->hl_reqs, lr_next) {
  151                 if (req->lr_id == id)
  152                         return req;
  153         }
  154 
  155         return NULL;
  156 }
  157 
  158 /*
  159  * Halt and free a request
  160  */
  161 void
  162 l2cap_request_free(struct l2cap_req *req)
  163 {
  164         struct hci_link *link = req->lr_link;
  165 
  166         callout_stop(&req->lr_rtx);
  167         if (callout_invoking(&req->lr_rtx))
  168                 return;
  169 
  170         callout_destroy(&req->lr_rtx);
  171 
  172         TAILQ_REMOVE(&link->hl_reqs, req, lr_next);
  173         pool_put(&l2cap_req_pool, req);
  174 }
  175 
  176 /*
  177  * Response Timeout eXpired
  178  *
  179  * No response to our request, so deal with it as best we can.
  180  *
  181  * XXX should try again at least with ertx?
  182  */
  183 void
  184 l2cap_rtx(void *arg)
  185 {
  186         struct l2cap_req *req = arg;
  187         struct l2cap_channel *chan;
  188 
  189         mutex_enter(bt_lock);
  190         callout_ack(&req->lr_rtx);
  191 
  192         chan = req->lr_chan;
  193         l2cap_request_free(req);
  194 
  195         DPRINTF("cid %d, ident %d\n", (chan ? chan->lc_lcid : 0), req->lr_id);
  196 
  197         if (chan && chan->lc_state != L2CAP_CLOSED)
  198                 l2cap_close(chan, ETIMEDOUT);
  199 
  200         mutex_exit(bt_lock);
  201 }
  202 
  203 /*
  204  * Allocate next available CID to channel. We keep a single
  205  * ordered list of channels, so find the first gap.
  206  *
  207  * If this turns out to be not enough (!), could use a
  208  * list per HCI unit..
  209  */
  210 int
  211 l2cap_cid_alloc(struct l2cap_channel *chan)
  212 {
  213         struct l2cap_channel *used, *prev = NULL;
  214         uint16_t cid = L2CAP_FIRST_CID;
  215 
  216         if (chan->lc_lcid != L2CAP_NULL_CID || chan->lc_state != L2CAP_CLOSED)
  217                 return EISCONN;
  218 
  219         LIST_FOREACH(used, &l2cap_active_list, lc_ncid) {
  220                 if (used->lc_lcid > cid)
  221                         break;  /* found our gap */
  222 
  223                 KASSERT(used->lc_lcid == cid);
  224                 cid++;
  225 
  226                 if (cid == L2CAP_LAST_CID)
  227                         return ENFILE;
  228 
  229                 prev = used;    /* for insert after */
  230         }
  231 
  232         chan->lc_lcid = cid;
  233 
  234         if (prev)
  235                 LIST_INSERT_AFTER(prev, chan, lc_ncid);
  236         else
  237                 LIST_INSERT_HEAD(&l2cap_active_list, chan, lc_ncid);
  238 
  239         return 0;
  240 }
  241 
  242 /*
  243  * Find channel with CID
  244  */
  245 struct l2cap_channel *
  246 l2cap_cid_lookup(uint16_t cid)
  247 {
  248         struct l2cap_channel *chan;
  249 
  250         LIST_FOREACH(chan, &l2cap_active_list, lc_ncid) {
  251                 if (chan->lc_lcid == cid)
  252                         return chan;
  253 
  254                 if (chan->lc_lcid > cid)
  255                         return NULL;
  256         }
  257 
  258         return NULL;
  259 }

Cache object: aab7c24996607c0629935dbd750cac27


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