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