xref: /haiku/src/add-ons/kernel/bluetooth/hci/acl.cpp (revision 47c05920fde47c2618efccd24bd82f1e79cdf05a)
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 	// 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 
165 status_t
166 PostToUpper(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