xref: /dflybsd-src/sys/netbt/l2cap_misc.c (revision 3598cc148acd8b5b528ae01060c3f974e6692bfc)
1*83aacedeSHasso Tepper /* $OpenBSD: src/sys/netbt/l2cap_misc.c,v 1.3 2008/02/24 21:34:48 uwe Exp $ */
2*83aacedeSHasso Tepper /* $NetBSD: l2cap_misc.c,v 1.5 2007/11/03 17:20:17 plunky Exp $ */
30a9108ebSHasso Tepper 
40a9108ebSHasso Tepper /*-
50a9108ebSHasso Tepper  * Copyright (c) 2005 Iain Hibbert.
60a9108ebSHasso Tepper  * Copyright (c) 2006 Itronix Inc.
70a9108ebSHasso Tepper  * All rights reserved.
80a9108ebSHasso Tepper  *
90a9108ebSHasso Tepper  * Redistribution and use in source and binary forms, with or without
100a9108ebSHasso Tepper  * modification, are permitted provided that the following conditions
110a9108ebSHasso Tepper  * are met:
120a9108ebSHasso Tepper  * 1. Redistributions of source code must retain the above copyright
130a9108ebSHasso Tepper  *    notice, this list of conditions and the following disclaimer.
140a9108ebSHasso Tepper  * 2. Redistributions in binary form must reproduce the above copyright
150a9108ebSHasso Tepper  *    notice, this list of conditions and the following disclaimer in the
160a9108ebSHasso Tepper  *    documentation and/or other materials provided with the distribution.
170a9108ebSHasso Tepper  * 3. The name of Itronix Inc. may not be used to endorse
180a9108ebSHasso Tepper  *    or promote products derived from this software without specific
190a9108ebSHasso Tepper  *    prior written permission.
200a9108ebSHasso Tepper  *
210a9108ebSHasso Tepper  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
220a9108ebSHasso Tepper  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
230a9108ebSHasso Tepper  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
240a9108ebSHasso Tepper  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
250a9108ebSHasso Tepper  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
260a9108ebSHasso Tepper  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
270a9108ebSHasso Tepper  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
280a9108ebSHasso Tepper  * ON ANY THEORY OF LIABILITY, WHETHER IN
290a9108ebSHasso Tepper  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
300a9108ebSHasso Tepper  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
310a9108ebSHasso Tepper  * POSSIBILITY OF SUCH DAMAGE.
320a9108ebSHasso Tepper  */
330a9108ebSHasso Tepper 
340a9108ebSHasso Tepper #include <sys/param.h>
350a9108ebSHasso Tepper #include <sys/kernel.h>
360a9108ebSHasso Tepper #include <sys/mbuf.h>
370a9108ebSHasso Tepper #include <sys/proc.h>
380a9108ebSHasso Tepper #include <sys/queue.h>
390a9108ebSHasso Tepper #include <sys/systm.h>
400a9108ebSHasso Tepper #include <net/if.h>
410a9108ebSHasso Tepper 
420a9108ebSHasso Tepper #include <netbt/bluetooth.h>
430a9108ebSHasso Tepper #include <netbt/hci.h>
440a9108ebSHasso Tepper #include <netbt/l2cap.h>
450a9108ebSHasso Tepper 
460a9108ebSHasso Tepper struct l2cap_channel_list
470a9108ebSHasso Tepper 	l2cap_active_list = LIST_HEAD_INITIALIZER(l2cap_active_list);
480a9108ebSHasso Tepper struct l2cap_channel_list
490a9108ebSHasso Tepper 	l2cap_listen_list = LIST_HEAD_INITIALIZER(l2cap_listen_list);
500a9108ebSHasso Tepper 
510a9108ebSHasso Tepper vm_zone_t l2cap_req_pool;
520a9108ebSHasso Tepper vm_zone_t l2cap_pdu_pool;
530a9108ebSHasso Tepper 
540a9108ebSHasso Tepper const l2cap_qos_t l2cap_default_qos = {
550a9108ebSHasso Tepper 	0,			/* flags */
560a9108ebSHasso Tepper 	L2CAP_QOS_BEST_EFFORT,	/* service type */
570a9108ebSHasso Tepper 	0x00000000,		/* token rate */
580a9108ebSHasso Tepper 	0x00000000,		/* token bucket size */
590a9108ebSHasso Tepper 	0x00000000,		/* peak bandwidth */
600a9108ebSHasso Tepper 	0xffffffff,		/* latency */
610a9108ebSHasso Tepper 	0xffffffff		/* delay variation */
620a9108ebSHasso Tepper };
630a9108ebSHasso Tepper 
640a9108ebSHasso Tepper /*
650a9108ebSHasso Tepper  * L2CAP request timeouts
660a9108ebSHasso Tepper  */
670a9108ebSHasso Tepper int l2cap_response_timeout = 30;		/* seconds */
680a9108ebSHasso Tepper int l2cap_response_extended_timeout = 180;	/* seconds */
690a9108ebSHasso Tepper 
700a9108ebSHasso Tepper void
l2cap_init(void)710a9108ebSHasso Tepper l2cap_init(void)
720a9108ebSHasso Tepper {
730a9108ebSHasso Tepper }
740a9108ebSHasso Tepper 
750a9108ebSHasso Tepper /*
760a9108ebSHasso Tepper  * Set Link Mode on channel
770a9108ebSHasso Tepper  */
780a9108ebSHasso Tepper int
l2cap_setmode(struct l2cap_channel * chan)790a9108ebSHasso Tepper l2cap_setmode(struct l2cap_channel *chan)
800a9108ebSHasso Tepper {
810a9108ebSHasso Tepper 	KKASSERT(chan != NULL);
820a9108ebSHasso Tepper 	KKASSERT(chan->lc_link != NULL);
830a9108ebSHasso Tepper 
84*83aacedeSHasso Tepper 	DPRINTF("(%s) CID #%d, auth %s, encrypt %s, secure %s\n",
85*83aacedeSHasso Tepper 	    device_get_nameunit(chan->lc_link->hl_unit->hci_dev), chan->lc_lcid,
860a9108ebSHasso Tepper 	    (chan->lc_mode & L2CAP_LM_AUTH ? "yes" : "no"),
870a9108ebSHasso Tepper 	    (chan->lc_mode & L2CAP_LM_ENCRYPT ? "yes" : "no"),
880a9108ebSHasso Tepper 	    (chan->lc_mode & L2CAP_LM_SECURE ? "yes" : "no"));
890a9108ebSHasso Tepper 
900a9108ebSHasso Tepper 	if (chan->lc_mode & L2CAP_LM_AUTH)
910a9108ebSHasso Tepper 		chan->lc_link->hl_flags |= HCI_LINK_AUTH_REQ;
920a9108ebSHasso Tepper 
930a9108ebSHasso Tepper 	if (chan->lc_mode & L2CAP_LM_ENCRYPT)
940a9108ebSHasso Tepper 		chan->lc_link->hl_flags |= HCI_LINK_ENCRYPT_REQ;
950a9108ebSHasso Tepper 
960a9108ebSHasso Tepper 	if (chan->lc_mode & L2CAP_LM_SECURE)
970a9108ebSHasso Tepper 		chan->lc_link->hl_flags |= HCI_LINK_SECURE_REQ;
980a9108ebSHasso Tepper 
990a9108ebSHasso Tepper 	return hci_acl_setmode(chan->lc_link);
1000a9108ebSHasso Tepper }
1010a9108ebSHasso Tepper 
1020a9108ebSHasso Tepper /*
1030a9108ebSHasso Tepper  * Allocate a new Request structure & ID and set the timer going
1040a9108ebSHasso Tepper  */
1050a9108ebSHasso Tepper int
l2cap_request_alloc(struct l2cap_channel * chan,uint8_t code)1060a9108ebSHasso Tepper l2cap_request_alloc(struct l2cap_channel *chan, uint8_t code)
1070a9108ebSHasso Tepper {
1080a9108ebSHasso Tepper 	struct hci_link *link = chan->lc_link;
1090a9108ebSHasso Tepper 	struct l2cap_req *req;
1100a9108ebSHasso Tepper 	int next_id;
1110a9108ebSHasso Tepper 
1120a9108ebSHasso Tepper 	if (link == NULL)
1130a9108ebSHasso Tepper 		return ENETDOWN;
1140a9108ebSHasso Tepper 
1150a9108ebSHasso Tepper 	/* find next ID (0 is not allowed) */
1160a9108ebSHasso Tepper 	next_id = link->hl_lastid + 1;
1170a9108ebSHasso Tepper 	if (next_id > 0xff)
1180a9108ebSHasso Tepper 		next_id = 1;
1190a9108ebSHasso Tepper 
1200a9108ebSHasso Tepper 	/* Ouroboros check */
1210a9108ebSHasso Tepper 	req = TAILQ_FIRST(&link->hl_reqs);
1220a9108ebSHasso Tepper 	if (req && req->lr_id == next_id)
1230a9108ebSHasso Tepper 		return ENFILE;
1240a9108ebSHasso Tepper 
1255179415aSSascha Wildner 	req = zalloc(l2cap_req_pool);
1260a9108ebSHasso Tepper 	if (req == NULL)
1270a9108ebSHasso Tepper 		return ENOMEM;
1280a9108ebSHasso Tepper 
1290a9108ebSHasso Tepper 	req->lr_id = link->hl_lastid = next_id;
1300a9108ebSHasso Tepper 
1310a9108ebSHasso Tepper 	req->lr_code = code;
1320a9108ebSHasso Tepper 	req->lr_chan = chan;
1330a9108ebSHasso Tepper 	req->lr_link = link;
1340a9108ebSHasso Tepper 
1350a9108ebSHasso Tepper 	callout_init(&req->lr_rtx);
1360a9108ebSHasso Tepper 	callout_reset(&req->lr_rtx, l2cap_response_timeout * hz,
1370a9108ebSHasso Tepper 	    l2cap_rtx, req);
1380a9108ebSHasso Tepper 
1390a9108ebSHasso Tepper 	TAILQ_INSERT_TAIL(&link->hl_reqs, req, lr_next);
1400a9108ebSHasso Tepper 
1410a9108ebSHasso Tepper 	return 0;
1420a9108ebSHasso Tepper }
1430a9108ebSHasso Tepper 
1440a9108ebSHasso Tepper /*
1450a9108ebSHasso Tepper  * Find a running request for this link
1460a9108ebSHasso Tepper  */
1470a9108ebSHasso Tepper struct l2cap_req *
l2cap_request_lookup(struct hci_link * link,uint8_t id)1480a9108ebSHasso Tepper l2cap_request_lookup(struct hci_link *link, uint8_t id)
1490a9108ebSHasso Tepper {
1500a9108ebSHasso Tepper 	struct l2cap_req *req;
1510a9108ebSHasso Tepper 
1520a9108ebSHasso Tepper 	TAILQ_FOREACH(req, &link->hl_reqs, lr_next) {
1530a9108ebSHasso Tepper 		if (req->lr_id == id)
1540a9108ebSHasso Tepper 			return req;
1550a9108ebSHasso Tepper 	}
1560a9108ebSHasso Tepper 
1570a9108ebSHasso Tepper 	return NULL;
1580a9108ebSHasso Tepper }
1590a9108ebSHasso Tepper 
1600a9108ebSHasso Tepper /*
1610a9108ebSHasso Tepper  * Halt and free a request
1620a9108ebSHasso Tepper  */
1630a9108ebSHasso Tepper void
l2cap_request_free(struct l2cap_req * req)1640a9108ebSHasso Tepper l2cap_request_free(struct l2cap_req *req)
1650a9108ebSHasso Tepper {
1660a9108ebSHasso Tepper 	struct hci_link *link = req->lr_link;
1670a9108ebSHasso Tepper 
1680a9108ebSHasso Tepper 	callout_stop(&req->lr_rtx);
1690a9108ebSHasso Tepper 	if (callout_active(&req->lr_rtx))
1700a9108ebSHasso Tepper 		return;
1710a9108ebSHasso Tepper 
1720a9108ebSHasso Tepper 	TAILQ_REMOVE(&link->hl_reqs, req, lr_next);
1735179415aSSascha Wildner 	zfree(l2cap_req_pool, req);
1740a9108ebSHasso Tepper }
1750a9108ebSHasso Tepper 
1760a9108ebSHasso Tepper /*
1770a9108ebSHasso Tepper  * Response Timeout eXpired
1780a9108ebSHasso Tepper  *
1790a9108ebSHasso Tepper  * No response to our request, so deal with it as best we can.
1800a9108ebSHasso Tepper  *
1810a9108ebSHasso Tepper  * XXX should try again at least with ertx?
1820a9108ebSHasso Tepper  */
1830a9108ebSHasso Tepper void
l2cap_rtx(void * arg)1840a9108ebSHasso Tepper l2cap_rtx(void *arg)
1850a9108ebSHasso Tepper {
1860a9108ebSHasso Tepper 	struct l2cap_req *req = arg;
1870a9108ebSHasso Tepper 	struct l2cap_channel *chan;
1880a9108ebSHasso Tepper 
1890a9108ebSHasso Tepper 	chan = req->lr_chan;
1900a9108ebSHasso Tepper 	l2cap_request_free(req);
1910a9108ebSHasso Tepper 
1920a9108ebSHasso Tepper 	DPRINTF("cid %d, ident %d\n", (chan ? chan->lc_lcid : 0), req->lr_id);
1930a9108ebSHasso Tepper 
1940a9108ebSHasso Tepper 	if (chan && chan->lc_state != L2CAP_CLOSED)
1950a9108ebSHasso Tepper 		l2cap_close(chan, ETIMEDOUT);
1960a9108ebSHasso Tepper 
1970a9108ebSHasso Tepper }
1980a9108ebSHasso Tepper 
1990a9108ebSHasso Tepper /*
2000a9108ebSHasso Tepper  * Allocate next available CID to channel. We keep a single
2010a9108ebSHasso Tepper  * ordered list of channels, so find the first gap.
2020a9108ebSHasso Tepper  *
2030a9108ebSHasso Tepper  * If this turns out to be not enough (!), could use a
2040a9108ebSHasso Tepper  * list per HCI unit..
2050a9108ebSHasso Tepper  */
2060a9108ebSHasso Tepper int
l2cap_cid_alloc(struct l2cap_channel * chan)2070a9108ebSHasso Tepper l2cap_cid_alloc(struct l2cap_channel *chan)
2080a9108ebSHasso Tepper {
2090a9108ebSHasso Tepper 	struct l2cap_channel *used, *prev = NULL;
2100a9108ebSHasso Tepper 	uint16_t cid = L2CAP_FIRST_CID;
2110a9108ebSHasso Tepper 
2120a9108ebSHasso Tepper 	if (chan->lc_lcid != L2CAP_NULL_CID || chan->lc_state != L2CAP_CLOSED)
2130a9108ebSHasso Tepper 		return EISCONN;
2140a9108ebSHasso Tepper 
2150a9108ebSHasso Tepper 	LIST_FOREACH(used, &l2cap_active_list, lc_ncid) {
2160a9108ebSHasso Tepper 		if (used->lc_lcid > cid)
2170a9108ebSHasso Tepper 			break;	/* found our gap */
2180a9108ebSHasso Tepper 
2190a9108ebSHasso Tepper 		KKASSERT(used->lc_lcid == cid);
2200a9108ebSHasso Tepper 		cid++;
2210a9108ebSHasso Tepper 
2220a9108ebSHasso Tepper 		if (cid == L2CAP_LAST_CID)
2230a9108ebSHasso Tepper 			return ENFILE;
2240a9108ebSHasso Tepper 
2250a9108ebSHasso Tepper 		prev = used;	/* for insert after */
2260a9108ebSHasso Tepper 	}
2270a9108ebSHasso Tepper 
2280a9108ebSHasso Tepper 	chan->lc_lcid = cid;
2290a9108ebSHasso Tepper 
2300a9108ebSHasso Tepper 	if (prev)
2310a9108ebSHasso Tepper 		LIST_INSERT_AFTER(prev, chan, lc_ncid);
2320a9108ebSHasso Tepper 	else
2330a9108ebSHasso Tepper 		LIST_INSERT_HEAD(&l2cap_active_list, chan, lc_ncid);
2340a9108ebSHasso Tepper 
2350a9108ebSHasso Tepper 	return 0;
2360a9108ebSHasso Tepper }
2370a9108ebSHasso Tepper 
2380a9108ebSHasso Tepper /*
2390a9108ebSHasso Tepper  * Find channel with CID
2400a9108ebSHasso Tepper  */
2410a9108ebSHasso Tepper struct l2cap_channel *
l2cap_cid_lookup(uint16_t cid)2420a9108ebSHasso Tepper l2cap_cid_lookup(uint16_t cid)
2430a9108ebSHasso Tepper {
2440a9108ebSHasso Tepper 	struct l2cap_channel *chan;
2450a9108ebSHasso Tepper 
2460a9108ebSHasso Tepper 	LIST_FOREACH(chan, &l2cap_active_list, lc_ncid) {
2470a9108ebSHasso Tepper 		if (chan->lc_lcid == cid)
2480a9108ebSHasso Tepper 			return chan;
2490a9108ebSHasso Tepper 
2500a9108ebSHasso Tepper 		if (chan->lc_lcid > cid)
2510a9108ebSHasso Tepper 			return NULL;
2520a9108ebSHasso Tepper 	}
2530a9108ebSHasso Tepper 
2540a9108ebSHasso Tepper 	return NULL;
2550a9108ebSHasso Tepper }
256