xref: /dragonfly/sys/netbt/l2cap_lower.c (revision 05d02a38)
183aacedeSHasso Tepper /* $DragonFly: src/sys/netbt/l2cap_lower.c,v 1.2 2008/03/18 13:41:42 hasso Exp $ */
283aacedeSHasso Tepper /* $OpenBSD: src/sys/netbt/l2cap_lower.c,v 1.2 2008/02/24 21:34:48 uwe Exp $ */
383aacedeSHasso Tepper /* $NetBSD: l2cap_lower.c,v 1.7 2007/11/10 23:12:23 plunky Exp $ */
40a9108ebSHasso Tepper 
50a9108ebSHasso Tepper /*-
60a9108ebSHasso Tepper  * Copyright (c) 2005 Iain Hibbert.
70a9108ebSHasso Tepper  * Copyright (c) 2006 Itronix Inc.
80a9108ebSHasso Tepper  * All rights reserved.
90a9108ebSHasso Tepper  *
100a9108ebSHasso Tepper  * Redistribution and use in source and binary forms, with or without
110a9108ebSHasso Tepper  * modification, are permitted provided that the following conditions
120a9108ebSHasso Tepper  * are met:
130a9108ebSHasso Tepper  * 1. Redistributions of source code must retain the above copyright
140a9108ebSHasso Tepper  *    notice, this list of conditions and the following disclaimer.
150a9108ebSHasso Tepper  * 2. Redistributions in binary form must reproduce the above copyright
160a9108ebSHasso Tepper  *    notice, this list of conditions and the following disclaimer in the
170a9108ebSHasso Tepper  *    documentation and/or other materials provided with the distribution.
180a9108ebSHasso Tepper  * 3. The name of Itronix Inc. may not be used to endorse
190a9108ebSHasso Tepper  *    or promote products derived from this software without specific
200a9108ebSHasso Tepper  *    prior written permission.
210a9108ebSHasso Tepper  *
220a9108ebSHasso Tepper  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
230a9108ebSHasso Tepper  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
240a9108ebSHasso Tepper  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
250a9108ebSHasso Tepper  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
260a9108ebSHasso Tepper  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
270a9108ebSHasso Tepper  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
280a9108ebSHasso Tepper  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
290a9108ebSHasso Tepper  * ON ANY THEORY OF LIABILITY, WHETHER IN
300a9108ebSHasso Tepper  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
310a9108ebSHasso Tepper  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
320a9108ebSHasso Tepper  * POSSIBILITY OF SUCH DAMAGE.
330a9108ebSHasso Tepper  */
340a9108ebSHasso Tepper 
350a9108ebSHasso Tepper #include <sys/param.h>
360a9108ebSHasso Tepper #include <sys/kernel.h>
370a9108ebSHasso Tepper #include <sys/malloc.h>
380a9108ebSHasso Tepper #include <sys/mbuf.h>
390a9108ebSHasso Tepper #include <sys/proc.h>
400a9108ebSHasso Tepper #include <sys/queue.h>
410a9108ebSHasso Tepper #include <sys/systm.h>
420a9108ebSHasso Tepper #include <sys/endian.h>
430a9108ebSHasso Tepper 
440a9108ebSHasso Tepper #include <netbt/bluetooth.h>
450a9108ebSHasso Tepper #include <netbt/hci.h>
460a9108ebSHasso Tepper #include <netbt/l2cap.h>
470a9108ebSHasso Tepper 
480a9108ebSHasso Tepper /****************************************************************************
490a9108ebSHasso Tepper  *
500a9108ebSHasso Tepper  *	L2CAP Channel Lower Layer interface
510a9108ebSHasso Tepper  */
520a9108ebSHasso Tepper 
530a9108ebSHasso Tepper /*
540a9108ebSHasso Tepper  * L2CAP channel is disconnected, could be:
550a9108ebSHasso Tepper  *
560a9108ebSHasso Tepper  * HCI layer received "Disconnect Complete" event for ACL link
570a9108ebSHasso Tepper  * some Request timed out
580a9108ebSHasso Tepper  * Config failed
590a9108ebSHasso Tepper  * Other end reported invalid CID
600a9108ebSHasso Tepper  * Normal disconnection
610a9108ebSHasso Tepper  * Change link mode failed
620a9108ebSHasso Tepper  */
630a9108ebSHasso Tepper void
l2cap_close(struct l2cap_channel * chan,int err)640a9108ebSHasso Tepper l2cap_close(struct l2cap_channel *chan, int err)
650a9108ebSHasso Tepper {
660a9108ebSHasso Tepper 	struct l2cap_pdu *pdu;
670a9108ebSHasso Tepper 	struct l2cap_req *req, *n;
680a9108ebSHasso Tepper 
690a9108ebSHasso Tepper 	if (chan->lc_state == L2CAP_CLOSED)
700a9108ebSHasso Tepper 		return;
710a9108ebSHasso Tepper 
720a9108ebSHasso Tepper 	/*
730a9108ebSHasso Tepper 	 * Since any potential PDU could be half sent we just let it go,
740a9108ebSHasso Tepper 	 * but disassociate ourselves from it as links deal with ownerless
750a9108ebSHasso Tepper 	 * PDU's in any case.  We could try harder to flush unsent packets
760a9108ebSHasso Tepper 	 * but maybe its better to leave them in the queue?
770a9108ebSHasso Tepper 	 */
780a9108ebSHasso Tepper 	TAILQ_FOREACH(pdu, &chan->lc_link->hl_txq, lp_next) {
790a9108ebSHasso Tepper 		if (pdu->lp_chan == chan)
800a9108ebSHasso Tepper 			pdu->lp_chan = NULL;
810a9108ebSHasso Tepper 	}
820a9108ebSHasso Tepper 
830a9108ebSHasso Tepper 	/*
840a9108ebSHasso Tepper 	 * and clear any outstanding requests..
850a9108ebSHasso Tepper 	 */
860a9108ebSHasso Tepper 	req = TAILQ_FIRST(&chan->lc_link->hl_reqs);
870a9108ebSHasso Tepper 	while (req != NULL) {
880a9108ebSHasso Tepper 		n = TAILQ_NEXT(req, lr_next);
890a9108ebSHasso Tepper 		if (req->lr_chan == chan)
900a9108ebSHasso Tepper 			l2cap_request_free(req);
910a9108ebSHasso Tepper 
920a9108ebSHasso Tepper 		req = n;
930a9108ebSHasso Tepper 	}
940a9108ebSHasso Tepper 
950a9108ebSHasso Tepper 	chan->lc_pending = 0;
960a9108ebSHasso Tepper 	chan->lc_state = L2CAP_CLOSED;
970a9108ebSHasso Tepper 	hci_acl_close(chan->lc_link, err);
980a9108ebSHasso Tepper 	chan->lc_link = NULL;
990a9108ebSHasso Tepper 
1000a9108ebSHasso Tepper 	(*chan->lc_proto->disconnected)(chan->lc_upper, err);
1010a9108ebSHasso Tepper }
1020a9108ebSHasso Tepper 
1030a9108ebSHasso Tepper /*
1040a9108ebSHasso Tepper  * Process incoming L2CAP frame from ACL link. We take off the B-Frame
1050a9108ebSHasso Tepper  * header (which is present in all packets), verify the data length
1060a9108ebSHasso Tepper  * and distribute the rest of the frame to the relevant channel
1070a9108ebSHasso Tepper  * handler.
1080a9108ebSHasso Tepper  */
1090a9108ebSHasso Tepper void
l2cap_recv_frame(struct mbuf * m,struct hci_link * link)1100a9108ebSHasso Tepper l2cap_recv_frame(struct mbuf *m, struct hci_link *link)
1110a9108ebSHasso Tepper {
1120a9108ebSHasso Tepper 	struct l2cap_channel *chan;
1130a9108ebSHasso Tepper 	l2cap_hdr_t hdr;
1140a9108ebSHasso Tepper 
115*05d02a38SAaron LI 	m_copydata(m, 0, sizeof(hdr), &hdr);
1160a9108ebSHasso Tepper 	m_adj(m, sizeof(hdr));
1170a9108ebSHasso Tepper 
1180a9108ebSHasso Tepper 	hdr.length = letoh16(hdr.length);
1190a9108ebSHasso Tepper 	hdr.dcid = letoh16(hdr.dcid);
1200a9108ebSHasso Tepper 
1210a9108ebSHasso Tepper 	DPRINTFN(5, "(%s) received packet (%d bytes)\n",
12283aacedeSHasso Tepper 		    device_get_nameunit(link->hl_unit->hci_dev), hdr.length);
1230a9108ebSHasso Tepper 
1240a9108ebSHasso Tepper 	if (hdr.length != m->m_pkthdr.len)
1250a9108ebSHasso Tepper 		goto failed;
1260a9108ebSHasso Tepper 
1270a9108ebSHasso Tepper 	if (hdr.dcid == L2CAP_SIGNAL_CID) {
1280a9108ebSHasso Tepper 		l2cap_recv_signal(m, link);
1290a9108ebSHasso Tepper 		return;
1300a9108ebSHasso Tepper 	}
1310a9108ebSHasso Tepper 
1320a9108ebSHasso Tepper 	if (hdr.dcid == L2CAP_CLT_CID) {
1330a9108ebSHasso Tepper 		m_freem(m);	/* TODO */
1340a9108ebSHasso Tepper 		return;
1350a9108ebSHasso Tepper 	}
1360a9108ebSHasso Tepper 
1370a9108ebSHasso Tepper 	chan = l2cap_cid_lookup(hdr.dcid);
1380a9108ebSHasso Tepper 	if (chan != NULL && chan->lc_link == link
1390a9108ebSHasso Tepper 	    && chan->lc_state == L2CAP_OPEN) {
1400a9108ebSHasso Tepper 		(*chan->lc_proto->input)(chan->lc_upper, m);
1410a9108ebSHasso Tepper 		return;
1420a9108ebSHasso Tepper 	}
1430a9108ebSHasso Tepper 
1440a9108ebSHasso Tepper 	DPRINTF("(%s) dropping %d L2CAP data bytes for unknown CID #%d\n",
14583aacedeSHasso Tepper 		device_get_nameunit(link->hl_unit->hci_dev), hdr.length,
14683aacedeSHasso Tepper 		hdr.dcid);
1470a9108ebSHasso Tepper 
1480a9108ebSHasso Tepper failed:
1490a9108ebSHasso Tepper 	m_freem(m);
1500a9108ebSHasso Tepper }
1510a9108ebSHasso Tepper 
1520a9108ebSHasso Tepper /*
1530a9108ebSHasso Tepper  * Start another L2CAP packet on its way. This is called from l2cap_send
1540a9108ebSHasso Tepper  * (when no PDU is pending) and hci_acl_start (when PDU has been placed on
1550a9108ebSHasso Tepper  * device queue). Thus we can have more than one PDU waiting at the device
1560a9108ebSHasso Tepper  * if space is available but no single channel will hog the link.
1570a9108ebSHasso Tepper  */
1580a9108ebSHasso Tepper int
l2cap_start(struct l2cap_channel * chan)1590a9108ebSHasso Tepper l2cap_start(struct l2cap_channel *chan)
1600a9108ebSHasso Tepper {
1610a9108ebSHasso Tepper 	struct mbuf *m;
1620a9108ebSHasso Tepper 	int err = 0;
1630a9108ebSHasso Tepper 
1640a9108ebSHasso Tepper 	if (chan->lc_state != L2CAP_OPEN)
1650a9108ebSHasso Tepper 		return 0;
1660a9108ebSHasso Tepper 
1670a9108ebSHasso Tepper 	if (IF_QEMPTY(&chan->lc_txq)) {
1680a9108ebSHasso Tepper 		DPRINTFN(5, "no data, pending = %d\n", chan->lc_pending);
1690a9108ebSHasso Tepper 		/*
1700a9108ebSHasso Tepper 		 * If we are just waiting for the queue to flush
1710a9108ebSHasso Tepper 		 * and it has, we may disconnect..
1720a9108ebSHasso Tepper 		 */
1730a9108ebSHasso Tepper 		if (chan->lc_flags & L2CAP_SHUTDOWN
1740a9108ebSHasso Tepper 		    && chan->lc_pending == 0) {
1750a9108ebSHasso Tepper 			chan->lc_state = L2CAP_WAIT_DISCONNECT;
1760a9108ebSHasso Tepper 			err = l2cap_send_disconnect_req(chan);
1770a9108ebSHasso Tepper 			if (err)
1780a9108ebSHasso Tepper 				l2cap_close(chan, err);
1790a9108ebSHasso Tepper 		}
1800a9108ebSHasso Tepper 
1810a9108ebSHasso Tepper 		return err;
1820a9108ebSHasso Tepper 	}
1830a9108ebSHasso Tepper 
1840a9108ebSHasso Tepper 	/*
1850a9108ebSHasso Tepper 	 * We could check QoS/RFC mode here and optionally not send
1860a9108ebSHasso Tepper 	 * the packet if we are not ready for any reason
1870a9108ebSHasso Tepper 	 *
1880a9108ebSHasso Tepper 	 * Also to support flush timeout then we might want to start
1890a9108ebSHasso Tepper 	 * the timer going? (would need to keep some kind of record
1900a9108ebSHasso Tepper 	 * of packets sent, possibly change it so that we allocate
1910a9108ebSHasso Tepper 	 * the l2cap_pdu and fragment the packet, then hand it down
1920a9108ebSHasso Tepper 	 * and get it back when its completed). Hm.
1930a9108ebSHasso Tepper 	 */
1940a9108ebSHasso Tepper 
1950a9108ebSHasso Tepper 	IF_DEQUEUE(&chan->lc_txq, m);
1960a9108ebSHasso Tepper 
1970a9108ebSHasso Tepper 	KKASSERT(chan->lc_link != NULL);
1980a9108ebSHasso Tepper 	KKASSERT(m != NULL);
1990a9108ebSHasso Tepper 
2000a9108ebSHasso Tepper 	DPRINTFN(5, "CID #%d sending packet (%d bytes)\n",
2010a9108ebSHasso Tepper 		chan->lc_lcid, m->m_pkthdr.len);
2020a9108ebSHasso Tepper 
2030a9108ebSHasso Tepper 	chan->lc_pending++;
2040a9108ebSHasso Tepper 	return hci_acl_send(m, chan->lc_link, chan);
2050a9108ebSHasso Tepper }
206