xref: /haiku/src/add-ons/kernel/bluetooth/hci/acl.cpp (revision 579f1dbca962a2a03df54f69fdc6e9423f91f20e)
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 //#define BT_DEBUG_THIS_MODULE
18 #define SUBMODULE_NAME "ACL"
19 #define SUBMODULE_COLOR 34
20 #include <btDebug.h>
21 #include <btCoreData.h>
22 #include <btModules.h>
23 #include <l2cap.h>
24 
25 #include "acl.h"
26 
27 extern struct bluetooth_core_data_module_info* btCoreData;
28 
29 struct net_protocol_module_info* L2cap = NULL;
30 
31 extern void RegisterConnection(hci_id hid, uint16 handle);
32 extern void unRegisterConnection(hci_id hid, uint16 handle);
33 
34 status_t PostToUpper(HciConnection* conn, net_buffer* buf);
35 
36 status_t
37 AclAssembly(net_buffer* nbuf, hci_id hid)
38 {
39 	status_t	error = B_OK;
40 
41 	// Check ACL data packet. Driver should ensure report complete ACL packets
42 	if (nbuf->size < sizeof(struct hci_acl_header)) {
43 		debugf("Invalid ACL data packet, small length=%ld\n", nbuf->size);
44 		gBufferModule->free(nbuf);
45 		return (EMSGSIZE);
46 	}
47 
48 	// Strip ACL data packet header
49 	NetBufferHeaderReader<struct hci_acl_header> aclHeader(nbuf);
50 	status_t status = aclHeader.Status();
51 	if (status < B_OK) {
52 		gBufferModule->free(nbuf);
53 		return ENOBUFS;
54 	}
55 
56 
57 	// Get ACL connection handle, PB flag and payload length
58 	aclHeader->handle = le16toh(aclHeader->handle);
59 
60 	uint16 con_handle = get_acl_handle(aclHeader->handle);
61 	uint16 pb = get_acl_pb_flag(aclHeader->handle);
62 	uint16 length = le16toh(aclHeader->alen);
63 
64 	aclHeader.Remove();
65 
66 	debugf("ACL data packet, handle=%#x, PB=%#x, length=%d\n",
67 		con_handle, pb, length);
68 
69 	// a) Ensure there is HCI connection
70 	// b) Get connection descriptor
71 	// c) veryfy the status of the connection
72 
73 	HciConnection* conn = btCoreData->ConnectionByHandle(con_handle, hid);
74 	if (conn == NULL) {
75 		debugf("Uexpected handle=%#x does not exist!\n", con_handle);
76 		conn = btCoreData->AddConnection(con_handle, BT_ACL, BDADDR_NULL, hid);
77 	}
78 
79 	// Verify connection state
80 	if (conn->status!= HCI_CONN_OPEN) {
81 		flowf("unexpected ACL data packet. Connection not open\n");
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 			debugf("Dropping incomplete L2CAP packet, got %ld want %d \n",
91 				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 			debugf("Invalid L2CAP start fragment, small, length=%ld\n",
100 				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 		debugf("New L2CAP, handle=%#x length=%d\n", 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 		debugf("invalid ACL data packet. Invalid PB flag=%#x\n", pb);
135 		gBufferModule->free(nbuf);
136 		return (EINVAL);
137 	}
138 
139 	// substract the length of content of the ACL packet
140 	conn->currentRxExpectedLength -= length;
141 
142 	if (conn->currentRxExpectedLength < 0) {
143 
144 		debugf("Mismatch. Got %ld, expected %ld\n",
145 			conn->currentRxPacket->size, conn->currentRxExpectedLength);
146 
147 		gBufferModule->free(conn->currentRxPacket);
148 		conn->currentRxPacket = NULL;
149 		conn->currentRxExpectedLength = 0;
150 
151 	} else if (conn->currentRxExpectedLength == 0) {
152 		// OK, we have got complete L2CAP packet, so process it
153 		debugf("L2cap packet ready %ld bytes\n", conn->currentRxPacket->size);
154 		error = PostToUpper(conn, conn->currentRxPacket);
155 		// clean
156 		conn->currentRxPacket = NULL;
157 		conn->currentRxExpectedLength = 0;
158 	} else {
159 		debugf("Expected %ld current adds %d\n",
160 			conn->currentRxExpectedLength, length);
161 	}
162 
163 	return error;
164 }
165 
166 
167 status_t
168 PostToUpper(HciConnection* conn, net_buffer* buf)
169 {
170 	if (L2cap == NULL)
171 
172 	if (get_module(NET_BLUETOOTH_L2CAP_NAME,(module_info**)&L2cap) != B_OK) {
173 		debugf("cannot get module \"%s\"\n", NET_BLUETOOTH_L2CAP_NAME);
174 		return B_ERROR;
175 	} // TODO: someone put it
176 
177 	return L2cap->receive_data((net_buffer*)conn);// XXX pass handle in type
178 
179 }
180