vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / bluetooth / hci / acl.cpp
blob230ba65db5942ff83fe7997eda51239857814d00
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 */
6 #include <KernelExport.h>
7 #include <string.h>
9 #include <NetBufferUtilities.h>
10 #include <net_protocol.h>
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>
17 #include <btDebug.h>
18 #include <btCoreData.h>
19 #include <btModules.h>
20 #include <l2cap.h>
22 #include "acl.h"
24 extern struct bluetooth_core_data_module_info* btCoreData;
26 struct net_protocol_module_info* L2cap = NULL;
28 extern void RegisterConnection(hci_id hid, uint16 handle);
29 extern void unRegisterConnection(hci_id hid, uint16 handle);
31 status_t PostToUpper(HciConnection* conn, net_buffer* buf);
33 status_t
34 AclAssembly(net_buffer* nbuf, hci_id hid)
36 status_t error = B_OK;
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);
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;
55 // Get ACL connection handle, PB flag and payload length
56 aclHeader->handle = le16toh(aclHeader->handle);
58 uint16 con_handle = get_acl_handle(aclHeader->handle);
59 uint16 pb = get_acl_pb_flag(aclHeader->handle);
60 uint16 length = le16toh(aclHeader->alen);
62 aclHeader.Remove();
64 TRACE("%s: ACL data packet, handle=%#x, PB=%#x, length=%d\n", __func__,
65 con_handle, pb, length);
67 // a) Ensure there is HCI connection
68 // b) Get connection descriptor
69 // c) veryfy the status of the connection
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);
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;
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;
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);
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;
113 l2capHeader->length = le16toh(l2capHeader->length);
114 l2capHeader->dcid = le16toh(l2capHeader->dcid);
116 TRACE("%s: New L2CAP, handle=%#x length=%d\n", __func__, con_handle,
117 le16toh(l2capHeader->length));
119 // Start new L2CAP packet
120 conn->currentRxPacket = nbuf;
121 conn->currentRxExpectedLength = l2capHeader->length + sizeof(l2cap_hdr_t);
124 } else if (pb == HCI_ACL_PACKET_FRAGMENT) {
125 if (conn->currentRxPacket == NULL) {
126 gBufferModule->free(nbuf);
127 return (EINVAL);
130 // Add fragment to the L2CAP packet
131 gBufferModule->merge(conn->currentRxPacket, nbuf, true);
133 } else {
134 ERROR("%s: invalid ACL data packet. Invalid PB flag=%#x\n", __func__,
135 pb);
136 gBufferModule->free(nbuf);
137 return (EINVAL);
140 // substract the length of content of the ACL packet
141 conn->currentRxExpectedLength -= length;
143 if (conn->currentRxExpectedLength < 0) {
144 TRACE("%s: Mismatch. Got %" B_PRIu32 ", expected %" B_PRIuSIZE "\n",
145 __func__, conn->currentRxPacket->size,
146 conn->currentRxExpectedLength);
148 gBufferModule->free(conn->currentRxPacket);
149 conn->currentRxPacket = NULL;
150 conn->currentRxExpectedLength = 0;
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);
165 return error;
169 status_t
170 PostToUpper(HciConnection* conn, net_buffer* buf)
172 if (L2cap == NULL)
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
180 return L2cap->receive_data((net_buffer*)conn);// XXX pass handle in type