You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
396 lines
13 KiB
396 lines
13 KiB
/****************************************************************************** |
|
* |
|
* Copyright (C) 2014 Google, Inc. |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at: |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
* |
|
******************************************************************************/ |
|
|
|
#include <gtest/gtest.h> |
|
|
|
#include "AllocationTestHarness.h" |
|
|
|
#include <stdint.h> |
|
|
|
#include "device/include/controller.h" |
|
#include "hci_internals.h" |
|
#include "osi/include/allocator.h" |
|
#include "osi/include/osi.h" |
|
#include "packet_fragmenter.h" |
|
#include "test_stubs.h" |
|
|
|
DECLARE_TEST_MODES(init, set_data_sizes, no_fragmentation, fragmentation, |
|
ble_no_fragmentation, ble_fragmentation, |
|
non_acl_passthrough_fragmentation, no_reassembly, reassembly, |
|
non_acl_passthrough_reassembly); |
|
|
|
#define LOCAL_BLE_CONTROLLER_ID 1 |
|
|
|
static const char* sample_data = |
|
"At this point they came in sight of thirty forty windmills that there are " |
|
"on plain, and " |
|
"as soon as Don Quixote saw them he said to his squire, \"Fortune is " |
|
"arranging matters " |
|
"for us better than we could have shaped our desires ourselves, for look " |
|
"there, friend " |
|
"Sancho Panza, where thirty or more monstrous giants present themselves, " |
|
"all of whom I " |
|
"mean to engage in battle and slay, and with whose spoils we shall begin " |
|
"to make our " |
|
"fortunes; for this is righteous warfare, and it is God's good service to " |
|
"sweep so evil " |
|
"a breed from off the face of the earth.\""; |
|
|
|
static const char* small_sample_data = "\"What giants?\" said Sancho Panza."; |
|
static const uint16_t test_handle_start = (0x1992 & 0xCFFF) | 0x2000; |
|
static const uint16_t test_handle_continuation = (0x1992 & 0xCFFF) | 0x1000; |
|
static int packet_index; |
|
static unsigned int data_size_sum; |
|
|
|
static const packet_fragmenter_t* fragmenter; |
|
|
|
static BT_HDR* manufacture_packet_for_fragmentation(uint16_t event, |
|
const char* data) { |
|
uint16_t data_length = strlen(data); |
|
uint16_t size = data_length; |
|
if (event == MSG_STACK_TO_HC_HCI_ACL) { |
|
size += 4; // 2 for the handle, 2 for the length; |
|
} |
|
|
|
BT_HDR* packet = (BT_HDR*)osi_malloc(size + sizeof(BT_HDR)); |
|
packet->len = size; |
|
packet->offset = 0; |
|
packet->event = event; |
|
packet->layer_specific = 0; |
|
uint8_t* packet_data = packet->data; |
|
|
|
if (event == MSG_STACK_TO_HC_HCI_ACL) { |
|
UINT16_TO_STREAM(packet_data, test_handle_start); |
|
UINT16_TO_STREAM(packet_data, data_length); |
|
} |
|
|
|
memcpy(packet_data, data, data_length); |
|
return packet; |
|
} |
|
|
|
static void expect_packet_fragmented(uint16_t event, int max_acl_data_size, |
|
BT_HDR* packet, const char* expected_data, |
|
bool send_complete) { |
|
uint8_t* data = packet->data + packet->offset; |
|
int expected_data_offset; |
|
int length_to_check; |
|
|
|
if (event == MSG_STACK_TO_HC_HCI_ACL) { |
|
uint16_t handle; |
|
uint16_t length; |
|
STREAM_TO_UINT16(handle, data); |
|
STREAM_TO_UINT16(length, data); |
|
|
|
if (packet_index == 0) |
|
EXPECT_EQ(test_handle_start, handle); |
|
else |
|
EXPECT_EQ(test_handle_continuation, handle); |
|
|
|
int length_remaining = strlen(expected_data) - data_size_sum; |
|
int packet_data_length = packet->len - HCI_ACL_PREAMBLE_SIZE; |
|
EXPECT_EQ(packet_data_length, length); |
|
|
|
if (length_remaining > max_acl_data_size) |
|
EXPECT_EQ(max_acl_data_size, packet_data_length); |
|
|
|
length_to_check = packet_data_length; |
|
expected_data_offset = packet_index * max_acl_data_size; |
|
packet_index++; |
|
} else { |
|
length_to_check = strlen(expected_data); |
|
expected_data_offset = 0; |
|
} |
|
|
|
for (int i = 0; i < length_to_check; i++) { |
|
EXPECT_EQ(expected_data[expected_data_offset + i], data[i]); |
|
data_size_sum++; |
|
} |
|
|
|
if (event == MSG_STACK_TO_HC_HCI_ACL) |
|
EXPECT_TRUE(send_complete == (data_size_sum == strlen(expected_data))); |
|
|
|
if (send_complete) osi_free(packet); |
|
} |
|
|
|
static void manufacture_packet_and_then_reassemble(uint16_t event, |
|
uint16_t acl_size, |
|
const char* data) { |
|
uint16_t data_length = strlen(data); |
|
|
|
if (event == MSG_HC_TO_STACK_HCI_ACL) { |
|
uint16_t total_length = data_length + 2; // 2 for l2cap length; |
|
uint16_t length_sent = 0; |
|
uint16_t l2cap_length = data_length - 2; // l2cap length field, 2 for the |
|
// pretend channel id borrowed |
|
// from the data |
|
|
|
do { |
|
int length_to_send = (length_sent + (acl_size - 4) < total_length) |
|
? (acl_size - 4) |
|
: (total_length - length_sent); |
|
BT_HDR* packet = (BT_HDR*)osi_malloc(length_to_send + 4 + sizeof(BT_HDR)); |
|
packet->len = length_to_send + 4; |
|
packet->offset = 0; |
|
packet->event = event; |
|
packet->layer_specific = 0; |
|
|
|
uint8_t* packet_data = packet->data; |
|
if (length_sent == 0) { // first packet |
|
UINT16_TO_STREAM(packet_data, test_handle_start); |
|
UINT16_TO_STREAM(packet_data, length_to_send); |
|
UINT16_TO_STREAM(packet_data, l2cap_length); |
|
memcpy(packet_data, data, length_to_send - 2); |
|
} else { |
|
UINT16_TO_STREAM(packet_data, test_handle_continuation); |
|
UINT16_TO_STREAM(packet_data, length_to_send); |
|
memcpy(packet_data, data + length_sent - 2, length_to_send); |
|
} |
|
|
|
length_sent += length_to_send; |
|
fragmenter->reassemble_and_dispatch(packet); |
|
} while (length_sent < total_length); |
|
} else { |
|
BT_HDR* packet = (BT_HDR*)osi_malloc(data_length + sizeof(BT_HDR)); |
|
packet->len = data_length; |
|
packet->offset = 0; |
|
packet->event = event; |
|
packet->layer_specific = 0; |
|
memcpy(packet->data, data, data_length); |
|
|
|
fragmenter->reassemble_and_dispatch(packet); |
|
} |
|
} |
|
|
|
static void expect_packet_reassembled(uint16_t event, BT_HDR* packet, |
|
const char* expected_data) { |
|
uint16_t expected_data_length = strlen(expected_data); |
|
uint8_t* data = packet->data + packet->offset; |
|
|
|
if (event == MSG_HC_TO_STACK_HCI_ACL) { |
|
uint16_t handle; |
|
uint16_t length; |
|
uint16_t l2cap_length; |
|
STREAM_TO_UINT16(handle, data); |
|
STREAM_TO_UINT16(length, data); |
|
STREAM_TO_UINT16(l2cap_length, data); |
|
|
|
EXPECT_EQ(test_handle_start, handle); |
|
EXPECT_EQ(expected_data_length + 2, length); |
|
EXPECT_EQ(expected_data_length - 2, |
|
l2cap_length); // -2 for the pretend channel id |
|
} |
|
|
|
for (int i = 0; i < expected_data_length; i++) { |
|
EXPECT_EQ(expected_data[i], data[i]); |
|
data_size_sum++; |
|
} |
|
|
|
osi_free(packet); |
|
} |
|
|
|
STUB_FUNCTION(void, fragmented_callback, (BT_HDR * packet, bool send_complete)) |
|
DURING(no_fragmentation) AT_CALL(0) { |
|
expect_packet_fragmented(MSG_STACK_TO_HC_HCI_ACL, 42, packet, |
|
small_sample_data, send_complete); |
|
return; |
|
} |
|
|
|
DURING(fragmentation) { |
|
expect_packet_fragmented(MSG_STACK_TO_HC_HCI_ACL, 10, packet, sample_data, |
|
send_complete); |
|
return; |
|
} |
|
|
|
DURING(ble_no_fragmentation) AT_CALL(0) { |
|
expect_packet_fragmented(MSG_STACK_TO_HC_HCI_ACL, 42, packet, |
|
small_sample_data, send_complete); |
|
return; |
|
} |
|
|
|
DURING(ble_fragmentation) { |
|
expect_packet_fragmented(MSG_STACK_TO_HC_HCI_ACL, 10, packet, sample_data, |
|
send_complete); |
|
return; |
|
} |
|
|
|
DURING(non_acl_passthrough_fragmentation) AT_CALL(0) { |
|
expect_packet_fragmented(MSG_STACK_TO_HC_HCI_CMD, 10, packet, sample_data, |
|
send_complete); |
|
return; |
|
} |
|
|
|
UNEXPECTED_CALL; |
|
} |
|
|
|
STUB_FUNCTION(void, reassembled_callback, (BT_HDR * packet)) |
|
DURING(no_reassembly) AT_CALL(0) { |
|
expect_packet_reassembled(MSG_HC_TO_STACK_HCI_ACL, packet, small_sample_data); |
|
return; |
|
} |
|
|
|
DURING(reassembly) AT_CALL(0) { |
|
expect_packet_reassembled(MSG_HC_TO_STACK_HCI_ACL, packet, sample_data); |
|
return; |
|
} |
|
|
|
DURING(non_acl_passthrough_reassembly) AT_CALL(0) { |
|
expect_packet_reassembled(MSG_HC_TO_STACK_HCI_EVT, packet, sample_data); |
|
return; |
|
} |
|
|
|
UNEXPECTED_CALL; |
|
} |
|
|
|
STUB_FUNCTION(void, transmit_finished_callback, |
|
(UNUSED_ATTR BT_HDR * packet, |
|
UNUSED_ATTR bool sent_all_fragments)) |
|
UNEXPECTED_CALL; |
|
} |
|
|
|
STUB_FUNCTION(uint16_t, get_acl_data_size_classic, (void)) |
|
DURING(no_fragmentation, non_acl_passthrough_fragmentation, no_reassembly) |
|
return 42; |
|
DURING(fragmentation) return 10; |
|
DURING(no_reassembly) return 1337; |
|
|
|
UNEXPECTED_CALL; |
|
return 0; |
|
} |
|
|
|
STUB_FUNCTION(uint16_t, get_acl_data_size_ble, (void)) |
|
DURING(ble_no_fragmentation) return 42; |
|
DURING(ble_fragmentation) return 10; |
|
|
|
UNEXPECTED_CALL; |
|
return 0; |
|
} |
|
|
|
static void reset_for(TEST_MODES_T next) { |
|
RESET_CALL_COUNT(fragmented_callback); |
|
RESET_CALL_COUNT(reassembled_callback); |
|
RESET_CALL_COUNT(transmit_finished_callback); |
|
RESET_CALL_COUNT(get_acl_data_size_classic); |
|
RESET_CALL_COUNT(get_acl_data_size_ble); |
|
CURRENT_TEST_MODE = next; |
|
} |
|
|
|
class PacketFragmenterTest : public AllocationTestHarness { |
|
protected: |
|
virtual void SetUp() { |
|
AllocationTestHarness::SetUp(); |
|
fragmenter = |
|
packet_fragmenter_get_test_interface(&controller, &allocator_malloc); |
|
|
|
packet_index = 0; |
|
data_size_sum = 0; |
|
|
|
callbacks.fragmented = fragmented_callback; |
|
callbacks.reassembled = reassembled_callback; |
|
callbacks.transmit_finished = transmit_finished_callback; |
|
controller.get_acl_data_size_classic = get_acl_data_size_classic; |
|
controller.get_acl_data_size_ble = get_acl_data_size_ble; |
|
|
|
reset_for(init); |
|
fragmenter->init(&callbacks); |
|
} |
|
|
|
virtual void TearDown() { |
|
fragmenter->cleanup(); |
|
AllocationTestHarness::TearDown(); |
|
} |
|
|
|
controller_t controller; |
|
packet_fragmenter_callbacks_t callbacks; |
|
}; |
|
|
|
TEST_F(PacketFragmenterTest, test_no_fragment_necessary) { |
|
reset_for(no_fragmentation); |
|
BT_HDR* packet = manufacture_packet_for_fragmentation(MSG_STACK_TO_HC_HCI_ACL, |
|
small_sample_data); |
|
fragmenter->fragment_and_dispatch(packet); |
|
|
|
EXPECT_EQ(strlen(small_sample_data), data_size_sum); |
|
EXPECT_CALL_COUNT(fragmented_callback, 1); |
|
} |
|
|
|
TEST_F(PacketFragmenterTest, test_fragment_necessary) { |
|
reset_for(fragmentation); |
|
BT_HDR* packet = manufacture_packet_for_fragmentation(MSG_STACK_TO_HC_HCI_ACL, |
|
sample_data); |
|
fragmenter->fragment_and_dispatch(packet); |
|
|
|
EXPECT_EQ(strlen(sample_data), data_size_sum); |
|
} |
|
|
|
TEST_F(PacketFragmenterTest, test_ble_no_fragment_necessary) { |
|
reset_for(ble_no_fragmentation); |
|
BT_HDR* packet = manufacture_packet_for_fragmentation(MSG_STACK_TO_HC_HCI_ACL, |
|
small_sample_data); |
|
packet->event |= LOCAL_BLE_CONTROLLER_ID; |
|
fragmenter->fragment_and_dispatch(packet); |
|
|
|
EXPECT_EQ(strlen(small_sample_data), data_size_sum); |
|
EXPECT_CALL_COUNT(fragmented_callback, 1); |
|
} |
|
|
|
TEST_F(PacketFragmenterTest, test_ble_fragment_necessary) { |
|
reset_for(ble_fragmentation); |
|
BT_HDR* packet = manufacture_packet_for_fragmentation(MSG_STACK_TO_HC_HCI_ACL, |
|
sample_data); |
|
packet->event |= LOCAL_BLE_CONTROLLER_ID; |
|
fragmenter->fragment_and_dispatch(packet); |
|
|
|
EXPECT_EQ(strlen(sample_data), data_size_sum); |
|
} |
|
|
|
TEST_F(PacketFragmenterTest, test_non_acl_passthrough_fragmentation) { |
|
reset_for(non_acl_passthrough_fragmentation); |
|
BT_HDR* packet = manufacture_packet_for_fragmentation(MSG_STACK_TO_HC_HCI_CMD, |
|
sample_data); |
|
fragmenter->fragment_and_dispatch(packet); |
|
|
|
EXPECT_EQ(strlen(sample_data), data_size_sum); |
|
EXPECT_CALL_COUNT(fragmented_callback, 1); |
|
} |
|
|
|
TEST_F(PacketFragmenterTest, test_no_reassembly_necessary) { |
|
reset_for(no_reassembly); |
|
manufacture_packet_and_then_reassemble(MSG_HC_TO_STACK_HCI_ACL, 1337, |
|
small_sample_data); |
|
|
|
EXPECT_EQ(strlen(small_sample_data), data_size_sum); |
|
EXPECT_CALL_COUNT(reassembled_callback, 1); |
|
} |
|
|
|
TEST_F(PacketFragmenterTest, test_reassembly_necessary) { |
|
reset_for(reassembly); |
|
manufacture_packet_and_then_reassemble(MSG_HC_TO_STACK_HCI_ACL, 42, |
|
sample_data); |
|
|
|
EXPECT_EQ(strlen(sample_data), data_size_sum); |
|
EXPECT_CALL_COUNT(reassembled_callback, 1); |
|
} |
|
|
|
TEST_F(PacketFragmenterTest, test_non_acl_passthrough_reasseembly) { |
|
reset_for(non_acl_passthrough_reassembly); |
|
manufacture_packet_and_then_reassemble(MSG_HC_TO_STACK_HCI_EVT, 42, |
|
sample_data); |
|
|
|
EXPECT_EQ(strlen(sample_data), data_size_sum); |
|
EXPECT_CALL_COUNT(reassembled_callback, 1); |
|
}
|
|
|