[BACK]Return to l2cap_misc.c CVS log [TXT][DIR] Up to [local] / sys / netbt

Annotation of sys/netbt/l2cap_misc.c, Revision 1.1.1.1

1.1       nbrk        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: }

CVSweb