Home | History | Annotate | Line # | Download | only in netbt
l2cap_misc.c revision 1.1.26.1
      1  1.1.26.1  wrstuden /*	$NetBSD: l2cap_misc.c,v 1.1.26.1 2007/09/03 07:05:10 wrstuden Exp $	*/
      2       1.1   gdamore 
      3       1.1   gdamore /*-
      4       1.1   gdamore  * Copyright (c) 2005 Iain Hibbert.
      5       1.1   gdamore  * Copyright (c) 2006 Itronix Inc.
      6       1.1   gdamore  * All rights reserved.
      7       1.1   gdamore  *
      8       1.1   gdamore  * Redistribution and use in source and binary forms, with or without
      9       1.1   gdamore  * modification, are permitted provided that the following conditions
     10       1.1   gdamore  * are met:
     11       1.1   gdamore  * 1. Redistributions of source code must retain the above copyright
     12       1.1   gdamore  *    notice, this list of conditions and the following disclaimer.
     13       1.1   gdamore  * 2. Redistributions in binary form must reproduce the above copyright
     14       1.1   gdamore  *    notice, this list of conditions and the following disclaimer in the
     15       1.1   gdamore  *    documentation and/or other materials provided with the distribution.
     16       1.1   gdamore  * 3. The name of Itronix Inc. may not be used to endorse
     17       1.1   gdamore  *    or promote products derived from this software without specific
     18       1.1   gdamore  *    prior written permission.
     19       1.1   gdamore  *
     20       1.1   gdamore  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
     21       1.1   gdamore  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22       1.1   gdamore  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23       1.1   gdamore  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
     24       1.1   gdamore  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     25       1.1   gdamore  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     26       1.1   gdamore  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     27       1.1   gdamore  * ON ANY THEORY OF LIABILITY, WHETHER IN
     28       1.1   gdamore  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29       1.1   gdamore  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30       1.1   gdamore  * POSSIBILITY OF SUCH DAMAGE.
     31       1.1   gdamore  */
     32       1.1   gdamore 
     33       1.1   gdamore #include <sys/cdefs.h>
     34  1.1.26.1  wrstuden __KERNEL_RCSID(0, "$NetBSD: l2cap_misc.c,v 1.1.26.1 2007/09/03 07:05:10 wrstuden Exp $");
     35       1.1   gdamore 
     36       1.1   gdamore #include <sys/param.h>
     37       1.1   gdamore #include <sys/kernel.h>
     38       1.1   gdamore #include <sys/mbuf.h>
     39       1.1   gdamore #include <sys/proc.h>
     40       1.1   gdamore #include <sys/queue.h>
     41       1.1   gdamore #include <sys/systm.h>
     42       1.1   gdamore 
     43       1.1   gdamore #include <netbt/bluetooth.h>
     44       1.1   gdamore #include <netbt/hci.h>
     45       1.1   gdamore #include <netbt/l2cap.h>
     46       1.1   gdamore 
     47       1.1   gdamore struct l2cap_channel_list
     48       1.1   gdamore 	l2cap_active_list = LIST_HEAD_INITIALIZER(l2cap_active_list);
     49       1.1   gdamore struct l2cap_channel_list
     50       1.1   gdamore 	l2cap_listen_list = LIST_HEAD_INITIALIZER(l2cap_listen_list);
     51       1.1   gdamore 
     52       1.1   gdamore POOL_INIT(l2cap_req_pool, sizeof(struct l2cap_req), 0, 0, 0, "l2cap_req", NULL);
     53       1.1   gdamore POOL_INIT(l2cap_pdu_pool, sizeof(struct l2cap_pdu), 0, 0, 0, "l2cap_pdu", NULL);
     54       1.1   gdamore 
     55       1.1   gdamore const l2cap_qos_t l2cap_default_qos = {
     56       1.1   gdamore 	0,			/* flags */
     57       1.1   gdamore 	L2CAP_QOS_BEST_EFFORT,	/* service type */
     58       1.1   gdamore 	0x00000000,		/* token rate */
     59       1.1   gdamore 	0x00000000,		/* token bucket size */
     60       1.1   gdamore 	0x00000000,		/* peak bandwidth */
     61       1.1   gdamore 	0xffffffff,		/* latency */
     62       1.1   gdamore 	0xffffffff		/* delay variation */
     63       1.1   gdamore };
     64       1.1   gdamore 
     65       1.1   gdamore /*
     66       1.1   gdamore  * L2CAP request timeouts
     67       1.1   gdamore  */
     68       1.1   gdamore int l2cap_response_timeout = 30;		/* seconds */
     69       1.1   gdamore int l2cap_response_extended_timeout = 180;	/* seconds */
     70       1.1   gdamore 
     71       1.1   gdamore /*
     72  1.1.26.1  wrstuden  * Set Link Mode on channel
     73  1.1.26.1  wrstuden  */
     74  1.1.26.1  wrstuden int
     75  1.1.26.1  wrstuden l2cap_setmode(struct l2cap_channel *chan)
     76  1.1.26.1  wrstuden {
     77  1.1.26.1  wrstuden 
     78  1.1.26.1  wrstuden 	KASSERT(chan != NULL);
     79  1.1.26.1  wrstuden 	KASSERT(chan->lc_link != NULL);
     80  1.1.26.1  wrstuden 
     81  1.1.26.1  wrstuden 	DPRINTF("CID #%d, auth %s, encrypt %s, secure %s\n", chan->lc_lcid,
     82  1.1.26.1  wrstuden 		(chan->lc_mode & L2CAP_LM_AUTH ? "yes" : "no"),
     83  1.1.26.1  wrstuden 		(chan->lc_mode & L2CAP_LM_ENCRYPT ? "yes" : "no"),
     84  1.1.26.1  wrstuden 		(chan->lc_mode & L2CAP_LM_SECURE ? "yes" : "no"));
     85  1.1.26.1  wrstuden 
     86  1.1.26.1  wrstuden 	if (chan->lc_mode & L2CAP_LM_AUTH)
     87  1.1.26.1  wrstuden 		chan->lc_link->hl_flags |= HCI_LINK_AUTH_REQ;
     88  1.1.26.1  wrstuden 
     89  1.1.26.1  wrstuden 	if (chan->lc_mode & L2CAP_LM_ENCRYPT)
     90  1.1.26.1  wrstuden 		chan->lc_link->hl_flags |= HCI_LINK_ENCRYPT_REQ;
     91  1.1.26.1  wrstuden 
     92  1.1.26.1  wrstuden 	if (chan->lc_mode & L2CAP_LM_SECURE)
     93  1.1.26.1  wrstuden 		chan->lc_link->hl_flags |= HCI_LINK_SECURE_REQ;
     94  1.1.26.1  wrstuden 
     95  1.1.26.1  wrstuden 	return hci_acl_setmode(chan->lc_link);
     96  1.1.26.1  wrstuden }
     97  1.1.26.1  wrstuden 
     98  1.1.26.1  wrstuden /*
     99       1.1   gdamore  * Allocate a new Request structure & ID and set the timer going
    100       1.1   gdamore  */
    101       1.1   gdamore int
    102       1.1   gdamore l2cap_request_alloc(struct l2cap_channel *chan, uint8_t code)
    103       1.1   gdamore {
    104       1.1   gdamore 	struct hci_link *link = chan->lc_link;
    105       1.1   gdamore 	struct l2cap_req *req;
    106       1.1   gdamore 	int next_id;
    107       1.1   gdamore 
    108       1.1   gdamore 	if (link == NULL)
    109       1.1   gdamore 		return ENETDOWN;
    110       1.1   gdamore 
    111       1.1   gdamore 	/* find next ID (0 is not allowed) */
    112       1.1   gdamore 	next_id = link->hl_lastid + 1;
    113       1.1   gdamore 	if (next_id > 0xff)
    114       1.1   gdamore 		next_id = 1;
    115       1.1   gdamore 
    116       1.1   gdamore 	/* Ouroboros check */
    117       1.1   gdamore 	req = TAILQ_FIRST(&link->hl_reqs);
    118       1.1   gdamore 	if (req && req->lr_id == next_id)
    119       1.1   gdamore 		return ENFILE;
    120       1.1   gdamore 
    121       1.1   gdamore 	req = pool_get(&l2cap_req_pool, PR_NOWAIT);
    122       1.1   gdamore 	if (req == NULL)
    123       1.1   gdamore 		return ENOMEM;
    124       1.1   gdamore 
    125       1.1   gdamore 	req->lr_id = link->hl_lastid = next_id;
    126       1.1   gdamore 
    127       1.1   gdamore 	req->lr_code = code;
    128       1.1   gdamore 	req->lr_chan = chan;
    129       1.1   gdamore 	req->lr_link = link;
    130       1.1   gdamore 
    131       1.1   gdamore 	callout_init(&req->lr_rtx);
    132       1.1   gdamore 	callout_reset(&req->lr_rtx, l2cap_response_timeout*hz, l2cap_rtx, req);
    133       1.1   gdamore 
    134       1.1   gdamore 	TAILQ_INSERT_TAIL(&link->hl_reqs, req, lr_next);
    135       1.1   gdamore 
    136       1.1   gdamore 	return 0;
    137       1.1   gdamore }
    138       1.1   gdamore 
    139       1.1   gdamore /*
    140       1.1   gdamore  * Find a running request for this link
    141       1.1   gdamore  */
    142       1.1   gdamore struct l2cap_req *
    143       1.1   gdamore l2cap_request_lookup(struct hci_link *link, uint8_t id)
    144       1.1   gdamore {
    145       1.1   gdamore 	struct l2cap_req *req;
    146       1.1   gdamore 
    147       1.1   gdamore 	TAILQ_FOREACH(req, &link->hl_reqs, lr_next) {
    148       1.1   gdamore 		if (req->lr_id == id)
    149       1.1   gdamore 			return req;
    150       1.1   gdamore 	}
    151       1.1   gdamore 
    152       1.1   gdamore 	return NULL;
    153       1.1   gdamore }
    154       1.1   gdamore 
    155       1.1   gdamore /*
    156       1.1   gdamore  * Halt and free a request
    157       1.1   gdamore  */
    158       1.1   gdamore void
    159       1.1   gdamore l2cap_request_free(struct l2cap_req *req)
    160       1.1   gdamore {
    161       1.1   gdamore 	struct hci_link *link = req->lr_link;
    162       1.1   gdamore 
    163       1.1   gdamore 	callout_stop(&req->lr_rtx);
    164       1.1   gdamore 	if (callout_invoking(&req->lr_rtx))
    165       1.1   gdamore 		return;
    166       1.1   gdamore 
    167       1.1   gdamore 	TAILQ_REMOVE(&link->hl_reqs, req, lr_next);
    168       1.1   gdamore 	pool_put(&l2cap_req_pool, req);
    169       1.1   gdamore }
    170       1.1   gdamore 
    171       1.1   gdamore /*
    172       1.1   gdamore  * Response Timeout eXpired
    173       1.1   gdamore  *
    174       1.1   gdamore  * No response to our request, so deal with it as best we can.
    175       1.1   gdamore  *
    176       1.1   gdamore  * XXX should try again at least with ertx?
    177       1.1   gdamore  */
    178       1.1   gdamore void
    179       1.1   gdamore l2cap_rtx(void *arg)
    180       1.1   gdamore {
    181       1.1   gdamore 	struct l2cap_req *req = arg;
    182       1.1   gdamore 	struct l2cap_channel *chan;
    183       1.1   gdamore 	int s;
    184       1.1   gdamore 
    185       1.1   gdamore 	s = splsoftnet();
    186       1.1   gdamore 	callout_ack(&req->lr_rtx);
    187       1.1   gdamore 
    188       1.1   gdamore 	chan = req->lr_chan;
    189       1.1   gdamore 	l2cap_request_free(req);
    190       1.1   gdamore 
    191       1.1   gdamore 	DPRINTF("cid %d, ident %d\n", (chan ? chan->lc_lcid : 0), req->lr_id);
    192       1.1   gdamore 
    193       1.1   gdamore 	if (chan && chan->lc_state != L2CAP_CLOSED)
    194       1.1   gdamore 		l2cap_close(chan, ETIMEDOUT);
    195       1.1   gdamore 
    196       1.1   gdamore 	splx(s);
    197       1.1   gdamore }
    198       1.1   gdamore 
    199       1.1   gdamore /*
    200       1.1   gdamore  * Allocate next available CID to channel. We keep a single
    201       1.1   gdamore  * ordered list of channels, so find the first gap.
    202       1.1   gdamore  *
    203       1.1   gdamore  * If this turns out to be not enough (!), could use a
    204       1.1   gdamore  * list per HCI unit..
    205       1.1   gdamore  */
    206       1.1   gdamore int
    207       1.1   gdamore l2cap_cid_alloc(struct l2cap_channel *chan)
    208       1.1   gdamore {
    209       1.1   gdamore 	struct l2cap_channel *used, *prev = NULL;
    210       1.1   gdamore 	uint16_t cid = L2CAP_FIRST_CID;
    211       1.1   gdamore 
    212       1.1   gdamore 	if (chan->lc_lcid != L2CAP_NULL_CID || chan->lc_state != L2CAP_CLOSED)
    213       1.1   gdamore 		return EISCONN;
    214       1.1   gdamore 
    215       1.1   gdamore 	LIST_FOREACH(used, &l2cap_active_list, lc_ncid) {
    216       1.1   gdamore 		if (used->lc_lcid > cid)
    217       1.1   gdamore 			break;	/* found our gap */
    218       1.1   gdamore 
    219       1.1   gdamore 		KASSERT(used->lc_lcid == cid);
    220       1.1   gdamore 		cid++;
    221       1.1   gdamore 
    222       1.1   gdamore 		if (cid == L2CAP_LAST_CID)
    223       1.1   gdamore 			return ENFILE;
    224       1.1   gdamore 
    225       1.1   gdamore 		prev = used;	/* for insert after */
    226       1.1   gdamore 	}
    227       1.1   gdamore 
    228       1.1   gdamore 	chan->lc_lcid = cid;
    229       1.1   gdamore 
    230       1.1   gdamore 	if (prev)
    231       1.1   gdamore 		LIST_INSERT_AFTER(prev, chan, lc_ncid);
    232       1.1   gdamore 	else
    233       1.1   gdamore 		LIST_INSERT_HEAD(&l2cap_active_list, chan, lc_ncid);
    234       1.1   gdamore 
    235       1.1   gdamore 	return 0;
    236       1.1   gdamore }
    237       1.1   gdamore 
    238       1.1   gdamore /*
    239       1.1   gdamore  * Find channel with CID
    240       1.1   gdamore  */
    241       1.1   gdamore struct l2cap_channel *
    242       1.1   gdamore l2cap_cid_lookup(uint16_t cid)
    243       1.1   gdamore {
    244       1.1   gdamore 	struct l2cap_channel *chan;
    245       1.1   gdamore 
    246       1.1   gdamore 	LIST_FOREACH(chan, &l2cap_active_list, lc_ncid) {
    247       1.1   gdamore 		if (chan->lc_lcid == cid)
    248       1.1   gdamore 			return chan;
    249       1.1   gdamore 
    250       1.1   gdamore 		if (chan->lc_lcid > cid)
    251       1.1   gdamore 			return NULL;
    252       1.1   gdamore 	}
    253       1.1   gdamore 
    254       1.1   gdamore 	return NULL;
    255       1.1   gdamore }
    256