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