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