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