root/netbt/l2cap_misc.c

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

DEFINITIONS

This source file includes following definitions.
  1. l2cap_init
  2. l2cap_setmode
  3. l2cap_request_alloc
  4. l2cap_request_lookup
  5. l2cap_request_free
  6. l2cap_rtx
  7. l2cap_cid_alloc
  8. l2cap_cid_lookup

    1 /*      $OpenBSD: l2cap_misc.c,v 1.2 2007/06/01 02:46:11 uwe Exp $      */
    2 /*      $NetBSD: l2cap_misc.c,v 1.3 2007/04/21 06:15:23 plunky Exp $    */
    3 
    4 /*-
    5  * Copyright (c) 2005 Iain Hibbert.
    6  * Copyright (c) 2006 Itronix Inc.
    7  * All rights reserved.
    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 
   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 struct pool l2cap_req_pool;
   53 struct pool l2cap_pdu_pool;
   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 void
   72 l2cap_init(void)
   73 {
   74         pool_init(&l2cap_req_pool, sizeof(struct l2cap_req), 0, 0, 0,
   75             "l2cap_req", NULL);
   76         pool_init(&l2cap_pdu_pool, sizeof(struct l2cap_pdu), 0, 0, 0,
   77             "l2cap_pdu", NULL);
   78 }
   79 
   80 /*
   81  * Set Link Mode on channel
   82  */
   83 int
   84 l2cap_setmode(struct l2cap_channel *chan)
   85 {
   86 
   87         KASSERT(chan != NULL);
   88         KASSERT(chan->lc_link != NULL);
   89 
   90         DPRINTF("CID #%d, auth %s, encrypt %s, secure %s\n", chan->lc_lcid,
   91                 (chan->lc_mode & L2CAP_LM_AUTH ? "yes" : "no"),
   92                 (chan->lc_mode & L2CAP_LM_ENCRYPT ? "yes" : "no"),
   93                 (chan->lc_mode & L2CAP_LM_SECURE ? "yes" : "no"));
   94 
   95         if (chan->lc_mode & L2CAP_LM_AUTH)
   96                 chan->lc_link->hl_flags |= HCI_LINK_AUTH_REQ;
   97 
   98         if (chan->lc_mode & L2CAP_LM_ENCRYPT)
   99                 chan->lc_link->hl_flags |= HCI_LINK_ENCRYPT_REQ;
  100 
  101         if (chan->lc_mode & L2CAP_LM_SECURE)
  102                 chan->lc_link->hl_flags |= HCI_LINK_SECURE_REQ;
  103 
  104         return hci_acl_setmode(chan->lc_link);
  105 }
  106 
  107 /*
  108  * Allocate a new Request structure & ID and set the timer going
  109  */
  110 int
  111 l2cap_request_alloc(struct l2cap_channel *chan, uint8_t code)
  112 {
  113         struct hci_link *link = chan->lc_link;
  114         struct l2cap_req *req;
  115         int next_id;
  116 
  117         if (link == NULL)
  118                 return ENETDOWN;
  119 
  120         /* find next ID (0 is not allowed) */
  121         next_id = link->hl_lastid + 1;
  122         if (next_id > 0xff)
  123                 next_id = 1;
  124 
  125         /* Ouroboros check */
  126         req = TAILQ_FIRST(&link->hl_reqs);
  127         if (req && req->lr_id == next_id)
  128                 return ENFILE;
  129 
  130         req = pool_get(&l2cap_req_pool, PR_NOWAIT);
  131         if (req == NULL)
  132                 return ENOMEM;
  133 
  134         req->lr_id = link->hl_lastid = next_id;
  135 
  136         req->lr_code = code;
  137         req->lr_chan = chan;
  138         req->lr_link = link;
  139 
  140         timeout_set(&req->lr_rtx, l2cap_rtx, req);
  141         timeout_add(&req->lr_rtx, l2cap_response_timeout*hz);
  142 
  143         TAILQ_INSERT_TAIL(&link->hl_reqs, req, lr_next);
  144 
  145         return 0;
  146 }
  147 
  148 /*
  149  * Find a running request for this link
  150  */
  151 struct l2cap_req *
  152 l2cap_request_lookup(struct hci_link *link, uint8_t id)
  153 {
  154         struct l2cap_req *req;
  155 
  156         TAILQ_FOREACH(req, &link->hl_reqs, lr_next) {
  157                 if (req->lr_id == id)
  158                         return req;
  159         }
  160 
  161         return NULL;
  162 }
  163 
  164 /*
  165  * Halt and free a request
  166  */
  167 void
  168 l2cap_request_free(struct l2cap_req *req)
  169 {
  170         struct hci_link *link = req->lr_link;
  171 
  172         timeout_del(&req->lr_rtx);
  173         if (timeout_triggered(&req->lr_rtx))
  174                 return;
  175 
  176         TAILQ_REMOVE(&link->hl_reqs, req, lr_next);
  177         pool_put(&l2cap_req_pool, req);
  178 }
  179 
  180 /*
  181  * Response Timeout eXpired
  182  *
  183  * No response to our request, so deal with it as best we can.
  184  *
  185  * XXX should try again at least with ertx?
  186  */
  187 void
  188 l2cap_rtx(void *arg)
  189 {
  190         struct l2cap_req *req = arg;
  191         struct l2cap_channel *chan;
  192         int s;
  193 
  194         s = splsoftnet();
  195 
  196         chan = req->lr_chan;
  197         l2cap_request_free(req);
  198 
  199         DPRINTF("cid %d, ident %d\n", (chan ? chan->lc_lcid : 0), req->lr_id);
  200 
  201         if (chan && chan->lc_state != L2CAP_CLOSED)
  202                 l2cap_close(chan, ETIMEDOUT);
  203 
  204         splx(s);
  205 }
  206 
  207 /*
  208  * Allocate next available CID to channel. We keep a single
  209  * ordered list of channels, so find the first gap.
  210  *
  211  * If this turns out to be not enough (!), could use a
  212  * list per HCI unit..
  213  */
  214 int
  215 l2cap_cid_alloc(struct l2cap_channel *chan)
  216 {
  217         struct l2cap_channel *used, *prev = NULL;
  218         uint16_t cid = L2CAP_FIRST_CID;
  219 
  220         if (chan->lc_lcid != L2CAP_NULL_CID || chan->lc_state != L2CAP_CLOSED)
  221                 return EISCONN;
  222 
  223         LIST_FOREACH(used, &l2cap_active_list, lc_ncid) {
  224                 if (used->lc_lcid > cid)
  225                         break;  /* found our gap */
  226 
  227                 KASSERT(used->lc_lcid == cid);
  228                 cid++;
  229 
  230                 if (cid == L2CAP_LAST_CID)
  231                         return ENFILE;
  232 
  233                 prev = used;    /* for insert after */
  234         }
  235 
  236         chan->lc_lcid = cid;
  237 
  238         if (prev)
  239                 LIST_INSERT_AFTER(prev, chan, lc_ncid);
  240         else
  241                 LIST_INSERT_HEAD(&l2cap_active_list, chan, lc_ncid);
  242 
  243         return 0;
  244 }
  245 
  246 /*
  247  * Find channel with CID
  248  */
  249 struct l2cap_channel *
  250 l2cap_cid_lookup(uint16_t cid)
  251 {
  252         struct l2cap_channel *chan;
  253 
  254         LIST_FOREACH(chan, &l2cap_active_list, lc_ncid) {
  255                 if (chan->lc_lcid == cid)
  256                         return chan;
  257 
  258                 if (chan->lc_lcid > cid)
  259                         return NULL;
  260         }
  261 
  262         return NULL;
  263 }

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