1fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson/******************************************************************************
2fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson *
3fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson *  Copyright (C) 2014 Google, Inc.
4fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson *
5fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson *  Licensed under the Apache License, Version 2.0 (the "License");
6fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson *  you may not use this file except in compliance with the License.
7fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson *  You may obtain a copy of the License at:
8fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson *
9fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson *  http://www.apache.org/licenses/LICENSE-2.0
10fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson *
11fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson *  Unless required by applicable law or agreed to in writing, software
12fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson *  distributed under the License is distributed on an "AS IS" BASIS,
13fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson *  See the License for the specific language governing permissions and
15fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson *  limitations under the License.
16fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson *
17fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson ******************************************************************************/
18fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
194a04780fd423d3c6673e9355af90ab60f31d9533Zach Johnson#define LOG_TAG "bt_hci_packet_fragmenter"
20fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
21fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson#include <assert.h>
223e59b5b6f2ce1295e3e2711afcd2cdf0dd7e22b6Etan Cohen#include <string.h>
23fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
24bf8193bc81cc077e3acd245cacbe8e3789c4b9ffZach Johnson#include "buffer_allocator.h"
2579ecab5d0418fde77e9afcdd451bd713af73e180Chris Manton#include "device/include/controller.h"
260f9b91e150e153229235c163861198e23600e636Sharvil Nanavati#include "osi/include/hash_map.h"
27fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson#include "hci_internals.h"
28fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson#include "hci_layer.h"
29fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson#include "packet_fragmenter.h"
300f9b91e150e153229235c163861198e23600e636Sharvil Nanavati#include "osi/include/osi.h"
3105d0366413bedc16b4189b9e74395fe4b11ba41aZach Johnson#include "osi/include/hash_functions.h"
3244802768c447ab480d4227b3a852a97d923b816dSharvil Nanavati#include "osi/include/log.h"
33fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
34fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson#define APPLY_CONTINUATION_FLAG(handle) (((handle) & 0xCFFF) | 0x1000)
35fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson#define APPLY_START_FLAG(handle) (((handle) & 0xCFFF) | 0x2000)
36fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson#define SUB_EVENT(event) ((event) & MSG_SUB_EVT_MASK)
37fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson#define GET_BOUNDARY_FLAG(handle) (((handle) >> 12) & 0x0003)
38fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
39fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson#define HANDLE_MASK 0x0FFF
40fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson#define START_PACKET_BOUNDARY 2
41fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson#define CONTINUATION_PACKET_BOUNDARY 1
42fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson#define L2CAP_HEADER_SIZE       4
43fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
44fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson// TODO(zachoverflow): find good value for this
45fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson#define NUMBER_OF_BUCKETS 42
46fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
47fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson// Our interface and callbacks
48bf8193bc81cc077e3acd245cacbe8e3789c4b9ffZach Johnsonstatic const packet_fragmenter_t interface;
49bf8193bc81cc077e3acd245cacbe8e3789c4b9ffZach Johnsonstatic const allocator_t *buffer_allocator;
50bf8193bc81cc077e3acd245cacbe8e3789c4b9ffZach Johnsonstatic const controller_t *controller;
51fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnsonstatic const packet_fragmenter_callbacks_t *callbacks;
52fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
53fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnsonstatic hash_map_t *partial_packets;
54fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
55bf8193bc81cc077e3acd245cacbe8e3789c4b9ffZach Johnsonstatic void init(const packet_fragmenter_callbacks_t *result_callbacks) {
56fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson  callbacks = result_callbacks;
57aa3a0114b6f018d0dd296d5bdb113d2f881cbc51Zach Johnson  partial_packets = hash_map_new(NUMBER_OF_BUCKETS, hash_function_naive, NULL, NULL, NULL);
581e0ede7f5522a853fc39d4f183e508ed38f01636Zach Johnson}
591e0ede7f5522a853fc39d4f183e508ed38f01636Zach Johnson
601e0ede7f5522a853fc39d4f183e508ed38f01636Zach Johnsonstatic void cleanup() {
61fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson  if (partial_packets)
62fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson    hash_map_free(partial_packets);
63fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson}
64fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
65fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnsonstatic void fragment_and_dispatch(BT_HDR *packet) {
66fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson  assert(packet != NULL);
67fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
68fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson  uint16_t event = packet->event & MSG_EVT_MASK;
6943b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson  uint8_t *stream = packet->data + packet->offset;
7043b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson
7143b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson  // We only fragment ACL packets
7243b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson  if (event != MSG_STACK_TO_HC_HCI_ACL) {
7343b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson    callbacks->fragmented(packet, true);
7443b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson    return;
7543b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson  }
7643b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson
77bf8193bc81cc077e3acd245cacbe8e3789c4b9ffZach Johnson  uint16_t max_data_size =
78bf8193bc81cc077e3acd245cacbe8e3789c4b9ffZach Johnson    SUB_EVENT(packet->event) == LOCAL_BR_EDR_CONTROLLER_ID ?
7930e58068c1adaac7c5ccb3aa9cfb045d41d2a10eZach Johnson      controller->get_acl_data_size_classic() :
8030e58068c1adaac7c5ccb3aa9cfb045d41d2a10eZach Johnson      controller->get_acl_data_size_ble();
8143b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson
82fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson  uint16_t max_packet_size = max_data_size + HCI_ACL_PREAMBLE_SIZE;
8343b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson  uint16_t remaining_length = packet->len;
84fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
8543b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson  uint16_t continuation_handle;
8643b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson  STREAM_TO_UINT16(continuation_handle, stream);
8743b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson  continuation_handle = APPLY_CONTINUATION_FLAG(continuation_handle);
8843b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson
8943b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson  while (remaining_length > max_packet_size) {
9043b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson    // Make sure we use the right ACL packet size
9143b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson    stream = packet->data + packet->offset;
9243b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson    STREAM_SKIP_UINT16(stream);
9343b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson    UINT16_TO_STREAM(stream, max_data_size);
9443b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson
9543b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson    packet->len = max_packet_size;
9643b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson    callbacks->fragmented(packet, false);
9743b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson
9843b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson    packet->offset += max_data_size;
9943b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson    remaining_length -= max_data_size;
10043b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson    packet->len = remaining_length;
10143b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson
10243b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson    // Write the ACL header for the next fragment
10343b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson    stream = packet->data + packet->offset;
10443b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson    UINT16_TO_STREAM(stream, continuation_handle);
10543b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson    UINT16_TO_STREAM(stream, remaining_length - HCI_ACL_PREAMBLE_SIZE);
10643b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson
10743b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson    // Apparently L2CAP can set layer_specific to a max number of segments to transmit
10843b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson    if (packet->layer_specific) {
10943b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson      packet->layer_specific--;
110fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
11143b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson      if (packet->layer_specific == 0) {
11243b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson        packet->event = MSG_HC_TO_STACK_L2C_SEG_XMIT;
11343b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson        callbacks->transmit_finished(packet, false);
11443b9ddb63f2efac8b3113df975e479663301a5b7Zach Johnson        return;
115fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson      }
116fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson    }
117fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson  }
118fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
119fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson  callbacks->fragmented(packet, true);
120fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson}
121fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
122fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnsonstatic void reassemble_and_dispatch(UNUSED_ATTR BT_HDR *packet) {
123fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson  if ((packet->event & MSG_EVT_MASK) == MSG_HC_TO_STACK_HCI_ACL) {
124fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson    uint8_t *stream = packet->data;
125fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson    uint16_t handle;
126fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson    uint16_t l2cap_length;
127fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson    uint16_t acl_length;
128fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
129fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson    STREAM_TO_UINT16(handle, stream);
130fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson    STREAM_TO_UINT16(acl_length, stream);
131fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson    STREAM_TO_UINT16(l2cap_length, stream);
132fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
133fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson    assert(acl_length == packet->len - HCI_ACL_PREAMBLE_SIZE);
134fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
135fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson    uint8_t boundary_flag = GET_BOUNDARY_FLAG(handle);
136fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson    handle = handle & HANDLE_MASK;
137fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
138fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson    BT_HDR *partial_packet = (BT_HDR *)hash_map_get(partial_packets, (void *)(uintptr_t)handle);
139fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
140fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson    if (boundary_flag == START_PACKET_BOUNDARY) {
141fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson      if (partial_packet) {
14244802768c447ab480d4227b3a852a97d923b816dSharvil Nanavati        LOG_WARN("%s found unfinished packet for handle with start packet. Dropping old.", __func__);
143fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
144fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson        hash_map_erase(partial_packets, (void *)(uintptr_t)handle);
145bf8193bc81cc077e3acd245cacbe8e3789c4b9ffZach Johnson        buffer_allocator->free(partial_packet);
146fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson      }
147fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
148fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson      uint16_t full_length = l2cap_length + L2CAP_HEADER_SIZE + HCI_ACL_PREAMBLE_SIZE;
149fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson      if (full_length <= packet->len) {
150fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson        if (full_length < packet->len)
15144802768c447ab480d4227b3a852a97d923b816dSharvil Nanavati          LOG_WARN("%s found l2cap full length %d less than the hci length %d.", __func__, l2cap_length, packet->len);
152fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
153fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson        callbacks->reassembled(packet);
154fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson        return;
155fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson      }
156fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
157bf8193bc81cc077e3acd245cacbe8e3789c4b9ffZach Johnson      partial_packet = (BT_HDR *)buffer_allocator->alloc(full_length + sizeof(BT_HDR));
158fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson      partial_packet->event = packet->event;
159fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson      partial_packet->len = full_length;
160fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson      partial_packet->offset = packet->len;
161fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
162fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson      memcpy(partial_packet->data, packet->data, packet->len);
163fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
164fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson      // Update the ACL data size to indicate the full expected length
165fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson      stream = partial_packet->data;
166fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson      STREAM_SKIP_UINT16(stream); // skip the handle
167fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson      UINT16_TO_STREAM(stream, full_length - HCI_ACL_PREAMBLE_SIZE);
168fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
169fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson      hash_map_set(partial_packets, (void *)(uintptr_t)handle, partial_packet);
170fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson      // Free the old packet buffer, since we don't need it anymore
171bf8193bc81cc077e3acd245cacbe8e3789c4b9ffZach Johnson      buffer_allocator->free(packet);
172fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson    } else {
173fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson      if (!partial_packet) {
17444802768c447ab480d4227b3a852a97d923b816dSharvil Nanavati        LOG_WARN("%s got continuation for unknown packet. Dropping it.", __func__);
175bf8193bc81cc077e3acd245cacbe8e3789c4b9ffZach Johnson        buffer_allocator->free(packet);
176fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson        return;
177fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson      }
178fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
179fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson      packet->offset = HCI_ACL_PREAMBLE_SIZE;
180fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson      uint16_t projected_offset = partial_packet->offset + (packet->len - HCI_ACL_PREAMBLE_SIZE);
181fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson      if (projected_offset > partial_packet->len) { // len stores the expected length
18244802768c447ab480d4227b3a852a97d923b816dSharvil Nanavati        LOG_WARN("%s got packet which would exceed expected length of %d. Truncating.", __func__, partial_packet->len);
183fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson        packet->len = partial_packet->len - partial_packet->offset;
184fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson        projected_offset = partial_packet->len;
185fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson      }
186fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
187fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson      memcpy(
188fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson        partial_packet->data + partial_packet->offset,
189fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson        packet->data + packet->offset,
190fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson        packet->len - packet->offset
191fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson      );
192fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
193fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson      // Free the old packet buffer, since we don't need it anymore
194bf8193bc81cc077e3acd245cacbe8e3789c4b9ffZach Johnson      buffer_allocator->free(packet);
195fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson      partial_packet->offset = projected_offset;
196fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
197fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson      if (partial_packet->offset == partial_packet->len) {
198fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson        hash_map_erase(partial_packets, (void *)(uintptr_t)handle);
199fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson        partial_packet->offset = 0;
200fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson        callbacks->reassembled(partial_packet);
201fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson      }
202fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson    }
203fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson  } else {
204fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson    callbacks->reassembled(packet);
205fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson  }
206fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson}
207fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
208bf8193bc81cc077e3acd245cacbe8e3789c4b9ffZach Johnsonstatic const packet_fragmenter_t interface = {
209fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson  init,
2101e0ede7f5522a853fc39d4f183e508ed38f01636Zach Johnson  cleanup,
211fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
212fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson  fragment_and_dispatch,
213fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson  reassemble_and_dispatch
214fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson};
215fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson
216bf8193bc81cc077e3acd245cacbe8e3789c4b9ffZach Johnsonconst packet_fragmenter_t *packet_fragmenter_get_interface() {
217bf8193bc81cc077e3acd245cacbe8e3789c4b9ffZach Johnson  controller = controller_get_interface();
218bf8193bc81cc077e3acd245cacbe8e3789c4b9ffZach Johnson  buffer_allocator = buffer_allocator_get_interface();
219bf8193bc81cc077e3acd245cacbe8e3789c4b9ffZach Johnson  return &interface;
220bf8193bc81cc077e3acd245cacbe8e3789c4b9ffZach Johnson}
221bf8193bc81cc077e3acd245cacbe8e3789c4b9ffZach Johnson
222bf8193bc81cc077e3acd245cacbe8e3789c4b9ffZach Johnsonconst packet_fragmenter_t *packet_fragmenter_get_test_interface(
223bf8193bc81cc077e3acd245cacbe8e3789c4b9ffZach Johnson    const controller_t *controller_interface,
224bf8193bc81cc077e3acd245cacbe8e3789c4b9ffZach Johnson    const allocator_t *buffer_allocator_interface) {
225bf8193bc81cc077e3acd245cacbe8e3789c4b9ffZach Johnson  controller = controller_interface;
226bf8193bc81cc077e3acd245cacbe8e3789c4b9ffZach Johnson  buffer_allocator = buffer_allocator_interface;
227fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson  return &interface;
228fbbd42b1fc1aae7a106f46275ab1fd86452cce78Zach Johnson}
229