1 /******************************************************************************
2 *
3 * Copyright (C) 2014 Google, Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 #define LOG_TAG "bt_hci_packet_fragmenter"
20
21 #include <assert.h>
22 #include <string.h>
23
24 #include "buffer_allocator.h"
25 #include "device/include/controller.h"
26 #include "osi/include/hash_map.h"
27 #include "hci_internals.h"
28 #include "hci_layer.h"
29 #include "packet_fragmenter.h"
30 #include "osi/include/osi.h"
31 #include "osi/include/hash_functions.h"
32 #include "osi/include/log.h"
33
34 #define APPLY_CONTINUATION_FLAG(handle) (((handle) & 0xCFFF) | 0x1000)
35 #define APPLY_START_FLAG(handle) (((handle) & 0xCFFF) | 0x2000)
36 #define SUB_EVENT(event) ((event) & MSG_SUB_EVT_MASK)
37 #define GET_BOUNDARY_FLAG(handle) (((handle) >> 12) & 0x0003)
38
39 #define HANDLE_MASK 0x0FFF
40 #define START_PACKET_BOUNDARY 2
41 #define CONTINUATION_PACKET_BOUNDARY 1
42 #define L2CAP_HEADER_SIZE 4
43
44 // TODO(zachoverflow): find good value for this
45 #define NUMBER_OF_BUCKETS 42
46
47 // Our interface and callbacks
48 static const packet_fragmenter_t interface;
49 static const allocator_t *buffer_allocator;
50 static const controller_t *controller;
51 static const packet_fragmenter_callbacks_t *callbacks;
52
53 static hash_map_t *partial_packets;
54
init(const packet_fragmenter_callbacks_t * result_callbacks)55 static void init(const packet_fragmenter_callbacks_t *result_callbacks) {
56 callbacks = result_callbacks;
57 partial_packets = hash_map_new(NUMBER_OF_BUCKETS, hash_function_naive, NULL, NULL, NULL);
58 }
59
cleanup()60 static void cleanup() {
61 if (partial_packets)
62 hash_map_free(partial_packets);
63 }
64
fragment_and_dispatch(BT_HDR * packet)65 static void fragment_and_dispatch(BT_HDR *packet) {
66 assert(packet != NULL);
67
68 uint16_t event = packet->event & MSG_EVT_MASK;
69 uint8_t *stream = packet->data + packet->offset;
70
71 // We only fragment ACL packets
72 if (event != MSG_STACK_TO_HC_HCI_ACL) {
73 callbacks->fragmented(packet, true);
74 return;
75 }
76
77 uint16_t max_data_size =
78 SUB_EVENT(packet->event) == LOCAL_BR_EDR_CONTROLLER_ID ?
79 controller->get_acl_data_size_classic() :
80 controller->get_acl_data_size_ble();
81
82 uint16_t max_packet_size = max_data_size + HCI_ACL_PREAMBLE_SIZE;
83 uint16_t remaining_length = packet->len;
84
85 uint16_t continuation_handle;
86 STREAM_TO_UINT16(continuation_handle, stream);
87 continuation_handle = APPLY_CONTINUATION_FLAG(continuation_handle);
88
89 while (remaining_length > max_packet_size) {
90 // Make sure we use the right ACL packet size
91 stream = packet->data + packet->offset;
92 STREAM_SKIP_UINT16(stream);
93 UINT16_TO_STREAM(stream, max_data_size);
94
95 packet->len = max_packet_size;
96 callbacks->fragmented(packet, false);
97
98 packet->offset += max_data_size;
99 remaining_length -= max_data_size;
100 packet->len = remaining_length;
101
102 // Write the ACL header for the next fragment
103 stream = packet->data + packet->offset;
104 UINT16_TO_STREAM(stream, continuation_handle);
105 UINT16_TO_STREAM(stream, remaining_length - HCI_ACL_PREAMBLE_SIZE);
106
107 // Apparently L2CAP can set layer_specific to a max number of segments to transmit
108 if (packet->layer_specific) {
109 packet->layer_specific--;
110
111 if (packet->layer_specific == 0) {
112 packet->event = MSG_HC_TO_STACK_L2C_SEG_XMIT;
113 callbacks->transmit_finished(packet, false);
114 return;
115 }
116 }
117 }
118
119 callbacks->fragmented(packet, true);
120 }
121
reassemble_and_dispatch(UNUSED_ATTR BT_HDR * packet)122 static void reassemble_and_dispatch(UNUSED_ATTR BT_HDR *packet) {
123 if ((packet->event & MSG_EVT_MASK) == MSG_HC_TO_STACK_HCI_ACL) {
124 uint8_t *stream = packet->data;
125 uint16_t handle;
126 uint16_t l2cap_length;
127 uint16_t acl_length;
128
129 STREAM_TO_UINT16(handle, stream);
130 STREAM_TO_UINT16(acl_length, stream);
131 STREAM_TO_UINT16(l2cap_length, stream);
132
133 assert(acl_length == packet->len - HCI_ACL_PREAMBLE_SIZE);
134
135 uint8_t boundary_flag = GET_BOUNDARY_FLAG(handle);
136 handle = handle & HANDLE_MASK;
137
138 BT_HDR *partial_packet = (BT_HDR *)hash_map_get(partial_packets, (void *)(uintptr_t)handle);
139
140 if (boundary_flag == START_PACKET_BOUNDARY) {
141 if (partial_packet) {
142 LOG_WARN("%s found unfinished packet for handle with start packet. Dropping old.", __func__);
143
144 hash_map_erase(partial_packets, (void *)(uintptr_t)handle);
145 buffer_allocator->free(partial_packet);
146 }
147
148 uint16_t full_length = l2cap_length + L2CAP_HEADER_SIZE + HCI_ACL_PREAMBLE_SIZE;
149 if (full_length <= packet->len) {
150 if (full_length < packet->len)
151 LOG_WARN("%s found l2cap full length %d less than the hci length %d.", __func__, l2cap_length, packet->len);
152
153 callbacks->reassembled(packet);
154 return;
155 }
156
157 partial_packet = (BT_HDR *)buffer_allocator->alloc(full_length + sizeof(BT_HDR));
158 partial_packet->event = packet->event;
159 partial_packet->len = full_length;
160 partial_packet->offset = packet->len;
161
162 memcpy(partial_packet->data, packet->data, packet->len);
163
164 // Update the ACL data size to indicate the full expected length
165 stream = partial_packet->data;
166 STREAM_SKIP_UINT16(stream); // skip the handle
167 UINT16_TO_STREAM(stream, full_length - HCI_ACL_PREAMBLE_SIZE);
168
169 hash_map_set(partial_packets, (void *)(uintptr_t)handle, partial_packet);
170 // Free the old packet buffer, since we don't need it anymore
171 buffer_allocator->free(packet);
172 } else {
173 if (!partial_packet) {
174 LOG_WARN("%s got continuation for unknown packet. Dropping it.", __func__);
175 buffer_allocator->free(packet);
176 return;
177 }
178
179 packet->offset = HCI_ACL_PREAMBLE_SIZE;
180 uint16_t projected_offset = partial_packet->offset + (packet->len - HCI_ACL_PREAMBLE_SIZE);
181 if (projected_offset > partial_packet->len) { // len stores the expected length
182 LOG_WARN("%s got packet which would exceed expected length of %d. Truncating.", __func__, partial_packet->len);
183 packet->len = partial_packet->len - partial_packet->offset;
184 projected_offset = partial_packet->len;
185 }
186
187 memcpy(
188 partial_packet->data + partial_packet->offset,
189 packet->data + packet->offset,
190 packet->len - packet->offset
191 );
192
193 // Free the old packet buffer, since we don't need it anymore
194 buffer_allocator->free(packet);
195 partial_packet->offset = projected_offset;
196
197 if (partial_packet->offset == partial_packet->len) {
198 hash_map_erase(partial_packets, (void *)(uintptr_t)handle);
199 partial_packet->offset = 0;
200 callbacks->reassembled(partial_packet);
201 }
202 }
203 } else {
204 callbacks->reassembled(packet);
205 }
206 }
207
208 static const packet_fragmenter_t interface = {
209 init,
210 cleanup,
211
212 fragment_and_dispatch,
213 reassemble_and_dispatch
214 };
215
packet_fragmenter_get_interface()216 const packet_fragmenter_t *packet_fragmenter_get_interface() {
217 controller = controller_get_interface();
218 buffer_allocator = buffer_allocator_get_interface();
219 return &interface;
220 }
221
packet_fragmenter_get_test_interface(const controller_t * controller_interface,const allocator_t * buffer_allocator_interface)222 const packet_fragmenter_t *packet_fragmenter_get_test_interface(
223 const controller_t *controller_interface,
224 const allocator_t *buffer_allocator_interface) {
225 controller = controller_interface;
226 buffer_allocator = buffer_allocator_interface;
227 return &interface;
228 }
229