xref: /haiku/src/add-ons/kernel/bluetooth/hci/acl.cpp (revision 21258e2674226d6aa732321b6f8494841895af5f)
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 
24 extern struct bluetooth_core_data_module_info* btCoreData;
25 
26 struct net_protocol_module_info* L2cap = NULL;
27 
28 extern void RegisterConnection(hci_id hid, uint16 handle);
29 extern void unRegisterConnection(hci_id hid, uint16 handle);
30 
31 status_t PostToUpper(HciConnection* conn, net_buffer* buf);
32 
33 status_t
34 AclAssembly(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 
55 	// Get ACL connection handle, PB flag and payload length
56 	aclHeader->handle = le16toh(aclHeader->handle);
57 
58 	uint16 con_handle = get_acl_handle(aclHeader->handle);
59 	uint16 pb = get_acl_pb_flag(aclHeader->handle);
60 	uint16 length = le16toh(aclHeader->alen);
61 
62 	aclHeader.Remove();
63 
64 	TRACE("%s: ACL data packet, handle=%#x, PB=%#x, length=%d\n", __func__,
65 		con_handle, pb, length);
66 
67 	// a) Ensure there is HCI connection
68 	// b) Get connection descriptor
69 	// c) veryfy the status of the connection
70 
71 	HciConnection* conn = btCoreData->ConnectionByHandle(con_handle, hid);
72 	if (conn == NULL) {
73 		ERROR("%s: expected handle=%#x does not exist!\n", __func__,
74 			con_handle);
75 		conn = btCoreData->AddConnection(con_handle, BT_ACL, BDADDR_NULL, hid);
76 	}
77 
78 	// Verify connection state
79 	if (conn->status!= HCI_CONN_OPEN) {
80 		ERROR("%s: unexpected ACL data packet. Connection not open\n",
81 			__func__);
82 		gBufferModule->free(nbuf);
83 		return EHOSTDOWN;
84 	}
85 
86 
87 	// Process packet
88 	if (pb == HCI_ACL_PACKET_START) {
89 		if (conn->currentRxPacket != NULL) {
90 			TRACE("%s: Dropping incomplete L2CAP packet, got %" B_PRIu32
91 				" want %d \n", __func__, conn->currentRxPacket->size, length );
92 			gBufferModule->free(conn->currentRxPacket);
93 			conn->currentRxPacket = NULL;
94 			conn->currentRxExpectedLength = 0;
95 		}
96 
97 		// Get L2CAP header, ACL header was dimissed
98 		if (nbuf->size < sizeof(l2cap_hdr_t)) {
99 			TRACE("%s: Invalid L2CAP start fragment, small, length=%" B_PRIu32
100 				"\n", __func__, nbuf->size);
101 			gBufferModule->free(nbuf);
102 			return (EMSGSIZE);
103 		}
104 
105 
106 		NetBufferHeaderReader<l2cap_hdr_t> l2capHeader(nbuf);
107 		status_t status = l2capHeader.Status();
108 		if (status < B_OK) {
109 			gBufferModule->free(nbuf);
110 			return ENOBUFS;
111 		}
112 
113 		l2capHeader->length = le16toh(l2capHeader->length);
114 		l2capHeader->dcid = le16toh(l2capHeader->dcid);
115 
116 		TRACE("%s: New L2CAP, handle=%#x length=%d\n", __func__, con_handle,
117 			le16toh(l2capHeader->length));
118 
119 		// Start new L2CAP packet
120 		conn->currentRxPacket = nbuf;
121 		conn->currentRxExpectedLength = l2capHeader->length + sizeof(l2cap_hdr_t);
122 
123 
124 	} else if (pb == HCI_ACL_PACKET_FRAGMENT) {
125 		if (conn->currentRxPacket == NULL) {
126 			gBufferModule->free(nbuf);
127 			return (EINVAL);
128 		}
129 
130 		// Add fragment to the L2CAP packet
131 		gBufferModule->merge(conn->currentRxPacket, nbuf, true);
132 
133 	} else {
134 		ERROR("%s: invalid ACL data packet. Invalid PB flag=%#x\n", __func__,
135 			pb);
136 		gBufferModule->free(nbuf);
137 		return (EINVAL);
138 	}
139 
140 	// substract the length of content of the ACL packet
141 	conn->currentRxExpectedLength -= length;
142 
143 	if (conn->currentRxExpectedLength < 0) {
144 		TRACE("%s: Mismatch. Got %" B_PRIu32 ", expected %" B_PRIuSIZE "\n",
145 			__func__, conn->currentRxPacket->size,
146 			conn->currentRxExpectedLength);
147 
148 		gBufferModule->free(conn->currentRxPacket);
149 		conn->currentRxPacket = NULL;
150 		conn->currentRxExpectedLength = 0;
151 
152 	} else if (conn->currentRxExpectedLength == 0) {
153 		// OK, we have got complete L2CAP packet, so process it
154 		TRACE("%s: L2cap packet ready %" B_PRIu32 " bytes\n", __func__,
155 			conn->currentRxPacket->size);
156 		error = PostToUpper(conn, conn->currentRxPacket);
157 		// clean
158 		conn->currentRxPacket = NULL;
159 		conn->currentRxExpectedLength = 0;
160 	} else {
161 		TRACE("%s: Expected %ld current adds %d\n", __func__,
162 			conn->currentRxExpectedLength, length);
163 	}
164 
165 	return error;
166 }
167 
168 
169 status_t
170 PostToUpper(HciConnection* conn, net_buffer* buf)
171 {
172 	if (L2cap == NULL)
173 
174 	if (get_module(NET_BLUETOOTH_L2CAP_NAME, (module_info**)&L2cap) != B_OK) {
175 		ERROR("%s: cannot get module \"%s\"\n", __func__,
176 			NET_BLUETOOTH_L2CAP_NAME);
177 		return B_ERROR;
178 	} // TODO: someone put it
179 
180 	return L2cap->receive_data((net_buffer*)conn);// XXX pass handle in type
181 
182 }
183