/******************************************************************************
*
* Copyright 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);
}