1/*
2 * Copyright 2008 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
5
6#include <KernelExport.h>
7#include <string.h>
8
9#include <NetBufferUtilities.h>
10#include <net_protocol.h>
11
12#include <bluetooth/HCI/btHCI_acl.h>
13#include <bluetooth/HCI/btHCI_transport.h>
14#include <bluetooth/HCI/btHCI_event.h>
15#include <bluetooth/bdaddrUtils.h>
16
17#include <btDebug.h>
18#include <btCoreData.h>
19#include <btModules.h>
20#include <l2cap.h>
21
22#include "acl.h"
23
24extern struct bluetooth_core_data_module_info* btCoreData;
25
26struct net_protocol_module_info* L2cap = NULL;
27
28extern void RegisterConnection(hci_id hid, uint16 handle);
29extern void unRegisterConnection(hci_id hid, uint16 handle);
30
31status_t PostToUpper(HciConnection* conn, net_buffer* buf);
32
33status_t
34AclAssembly(net_buffer* nbuf, hci_id hid)
35{
36	status_t	error = B_OK;
37
38	// Check ACL data packet. Driver should ensure report complete ACL packets
39	if (nbuf->size < sizeof(struct hci_acl_header)) {
40		ERROR("%s: Invalid ACL data packet, small length=%" B_PRIu32 "\n",
41			__func__, nbuf->size);
42		gBufferModule->free(nbuf);
43		return (EMSGSIZE);
44	}
45
46	// Strip ACL data packet header
47	NetBufferHeaderReader<struct hci_acl_header> aclHeader(nbuf);
48	status_t status = aclHeader.Status();
49	if (status < B_OK) {
50		gBufferModule->free(nbuf);
51		return ENOBUFS;
52	}
53
54	// Get ACL connection handle, PB flag and payload length
55	aclHeader->handle = B_LENDIAN_TO_HOST_INT16(aclHeader->handle);
56
57	uint16 con_handle = get_acl_handle(aclHeader->handle);
58	uint16 pb = get_acl_pb_flag(aclHeader->handle);
59	uint16 length = B_LENDIAN_TO_HOST_INT16(aclHeader->alen);
60
61	aclHeader.Remove();
62
63	TRACE("%s: ACL data packet, handle=%#x, PB=%#x, length=%d\n", __func__,
64		con_handle, pb, length);
65
66	// a) Ensure there is HCI connection
67	// b) Get connection descriptor
68	// c) veryfy the status of the connection
69
70	HciConnection* conn = btCoreData->ConnectionByHandle(con_handle, hid);
71	if (conn == NULL) {
72		ERROR("%s: expected handle=%#x does not exist!\n", __func__,
73			con_handle);
74		conn = btCoreData->AddConnection(con_handle, BT_ACL, BDADDR_NULL, hid);
75	}
76
77	// Verify connection state
78	if (conn->status!= HCI_CONN_OPEN) {
79		ERROR("%s: unexpected ACL data packet. Connection not open\n",
80			__func__);
81		gBufferModule->free(nbuf);
82		return EHOSTDOWN;
83	}
84
85
86	// Process packet
87	if (pb == HCI_ACL_PACKET_START) {
88		if (conn->currentRxPacket != NULL) {
89			TRACE("%s: Dropping incomplete L2CAP packet, got %" B_PRIu32
90				" want %d \n", __func__, conn->currentRxPacket->size, length );
91			gBufferModule->free(conn->currentRxPacket);
92			conn->currentRxPacket = NULL;
93			conn->currentRxExpectedLength = 0;
94		}
95
96		// Get L2CAP header, ACL header was dimissed
97		if (nbuf->size < sizeof(l2cap_basic_header)) {
98			TRACE("%s: Invalid L2CAP start fragment, small, length=%" B_PRIu32
99				"\n", __func__, nbuf->size);
100			gBufferModule->free(nbuf);
101			return (EMSGSIZE);
102		}
103
104		NetBufferHeaderReader<l2cap_basic_header> l2capHeader(nbuf);
105		if (l2capHeader.Status() != B_OK) {
106			gBufferModule->free(nbuf);
107			return ENOBUFS;
108		}
109
110		TRACE("%s: New L2CAP, handle=%#x length=%d\n", __func__, con_handle,
111			le16toh(l2capHeader->length));
112
113		// Start new L2CAP packet
114		conn->currentRxPacket = nbuf;
115		conn->currentRxExpectedLength = B_LENDIAN_TO_HOST_INT16(l2capHeader->length)
116			+ sizeof(l2cap_basic_header);
117	} else if (pb == HCI_ACL_PACKET_FRAGMENT) {
118		if (conn->currentRxPacket == NULL) {
119			gBufferModule->free(nbuf);
120			return (EINVAL);
121		}
122
123		// Add fragment to the L2CAP packet
124		gBufferModule->merge(conn->currentRxPacket, nbuf, true);
125	} else {
126		ERROR("%s: invalid ACL data packet. Invalid PB flag=%#x\n", __func__,
127			pb);
128		gBufferModule->free(nbuf);
129		return (EINVAL);
130	}
131
132	// substract the length of content of the ACL packet
133	conn->currentRxExpectedLength -= length;
134
135	if (conn->currentRxExpectedLength < 0) {
136		TRACE("%s: Mismatch. Got %" B_PRIu32 ", expected %" B_PRIuSIZE "\n",
137			__func__, conn->currentRxPacket->size,
138			conn->currentRxExpectedLength);
139
140		gBufferModule->free(conn->currentRxPacket);
141		conn->currentRxPacket = NULL;
142		conn->currentRxExpectedLength = 0;
143
144	} else if (conn->currentRxExpectedLength == 0) {
145		// OK, we have got complete L2CAP packet, so process it
146		TRACE("%s: L2cap packet ready %" B_PRIu32 " bytes\n", __func__,
147			conn->currentRxPacket->size);
148
149		memcpy(conn->currentRxPacket->source, &conn->address_dest, sizeof(sockaddr_storage));
150		conn->currentRxPacket->interface_address = &conn->interface_address;
151
152		error = PostToUpper(conn, conn->currentRxPacket);
153		// clean
154		conn->currentRxPacket = NULL;
155		conn->currentRxExpectedLength = 0;
156	} else {
157		TRACE("%s: Expected %ld current adds %d\n", __func__,
158			conn->currentRxExpectedLength, length);
159	}
160
161	return error;
162}
163
164
165status_t
166PostToUpper(HciConnection* conn, net_buffer* buf)
167{
168	if (L2cap == NULL)
169
170	if (get_module(NET_BLUETOOTH_L2CAP_NAME, (module_info**)&L2cap) != B_OK) {
171		ERROR("%s: cannot get module \"%s\"\n", __func__,
172			NET_BLUETOOTH_L2CAP_NAME);
173		return B_ERROR;
174	} // TODO: someone put it
175
176	return L2cap->receive_data(buf);
177}
178