/****************************************************************************** * * 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 #include "AlarmTestHarness.h" extern "C" { #include #include "device/include/controller.h" #include "osi/include/allocation_tracker.h" #include "osi/include/allocator.h" #include "osi/include/osi.h" #include "osi/include/semaphore.h" #include "btsnoop.h" #include "hcimsgs.h" #include "hci_hal.h" #include "hci_inject.h" #include "hci_layer.h" #include "low_power_manager.h" #include "module.h" #include "packet_fragmenter.h" #include "test_stubs.h" #include "vendor.h" extern const module_t hci_module; } DECLARE_TEST_MODES( start_up_async, shut_down, postload, transmit_simple, receive_simple, transmit_command_no_callbacks, transmit_command_command_status, transmit_command_command_complete, ignoring_packets_ignored_packet, ignoring_packets_following_packet ); static const char *small_sample_data = "\"It is easy to see,\" replied Don Quixote"; static const char *command_sample_data = "that thou art not used to this business of adventures; those are giants"; static const char *ignored_data = "and if thou art afraid, away with thee out of this and betake thyself to prayer"; static const char *unignored_data = "while I engage them in fierce and unequal combat"; static const hci_t *hci; static const hci_hal_callbacks_t *hal_callbacks; static thread_t *internal_thread; static vendor_cb firmware_config_callback; static vendor_cb sco_config_callback; static vendor_cb epilog_callback; static semaphore_t *done; static const uint16_t test_handle = (0x1992 & 0xCFFF); static const uint16_t test_handle_continuation = (0x1992 & 0xCFFF) | 0x1000; static int packet_index; static unsigned int data_size_sum; static BT_HDR *data_to_receive; static void signal_work_item(UNUSED_ATTR void *context) { semaphore_post(done); } static void flush_thread(thread_t *thread) { // Double flush to ensure we get the next reactor cycle thread_post(thread, signal_work_item, NULL); semaphore_wait(done); thread_post(thread, signal_work_item, NULL); semaphore_wait(done); } // TODO move this to a common packet testing helper static BT_HDR *manufacture_packet(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->layer_specific = 0; // The command transmit interface adds the event type automatically. // Make sure it works but omitting it here. if (event != MSG_STACK_TO_HC_HCI_CMD) packet->event = event; uint8_t *packet_data = packet->data; if (event == MSG_STACK_TO_HC_HCI_ACL) { UINT16_TO_STREAM(packet_data, test_handle); UINT16_TO_STREAM(packet_data, data_length); } for (int i = 0; i < data_length; i++) { packet_data[i] = data[i]; } if (event == MSG_STACK_TO_HC_HCI_CMD) { STREAM_SKIP_UINT16(packet_data); UINT8_TO_STREAM(packet_data, data_length - 3); } else if (event == MSG_HC_TO_STACK_HCI_EVT) { STREAM_SKIP_UINT8(packet_data); UINT8_TO_STREAM(packet_data, data_length - 2); } return packet; } static void expect_packet(uint16_t event, int max_acl_data_size, const uint8_t *data, uint16_t data_length, const char *expected_data) { 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, handle); else EXPECT_EQ(test_handle_continuation, handle); int length_remaining = strlen(expected_data) - data_size_sum; int packet_data_length = data_length - HCI_ACL_PREAMBLE_SIZE; EXPECT_EQ(length_remaining, length); if (length_remaining < max_acl_data_size) EXPECT_EQ(length, packet_data_length); else 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++) { if (event == MSG_STACK_TO_HC_HCI_CMD && (i == 2)) EXPECT_EQ(data_length - 3, data[i]); else EXPECT_EQ(expected_data[expected_data_offset + i], data[i]); data_size_sum++; } } STUB_FUNCTION(bool, hal_init, (const hci_hal_callbacks_t *callbacks, thread_t *working_thread)) DURING(start_up_async) AT_CALL(0) { hal_callbacks = callbacks; internal_thread = working_thread; return true; } UNEXPECTED_CALL; return false; } STUB_FUNCTION(bool, hal_open, ()) DURING(start_up_async) AT_CALL(0) return true; UNEXPECTED_CALL; return false; } STUB_FUNCTION(void, hal_close, ()) DURING(shut_down) AT_CALL(0) return; UNEXPECTED_CALL; } STUB_FUNCTION(uint16_t, hal_transmit_data, (serial_data_type_t type, uint8_t *data, uint16_t length)) DURING(transmit_simple) AT_CALL(0) { EXPECT_EQ(DATA_TYPE_ACL, type); expect_packet(MSG_STACK_TO_HC_HCI_ACL, 1021, data, length, small_sample_data); return length; } DURING( transmit_command_no_callbacks, transmit_command_command_status, transmit_command_command_complete ) AT_CALL(0) { EXPECT_EQ(DATA_TYPE_COMMAND, type); expect_packet(MSG_STACK_TO_HC_HCI_CMD, 1021, data, length, command_sample_data); return length; } UNEXPECTED_CALL; return 0; } static size_t replay_data_to_receive(size_t max_size, uint8_t *buffer) { for (size_t i = 0; i < max_size; i++) { if (data_to_receive->offset >= data_to_receive->len) break; buffer[i] = data_to_receive->data[data_to_receive->offset++]; if (i == (max_size - 1)) return i + 1; // We return the length, not the index; } return 0; } STUB_FUNCTION(size_t, hal_read_data, (serial_data_type_t type, uint8_t *buffer, size_t max_size)) DURING(receive_simple, ignoring_packets_following_packet) { EXPECT_EQ(DATA_TYPE_ACL, type); return replay_data_to_receive(max_size, buffer); } DURING(ignoring_packets_ignored_packet) { EXPECT_EQ(DATA_TYPE_EVENT, type); return replay_data_to_receive(max_size, buffer); } DURING( transmit_command_no_callbacks, transmit_command_command_status, transmit_command_command_complete) { EXPECT_EQ(DATA_TYPE_EVENT, type); return replay_data_to_receive(max_size, buffer); } UNEXPECTED_CALL; return 0; } STUB_FUNCTION(void, hal_packet_finished, (serial_data_type_t type)) DURING(receive_simple, ignoring_packets_following_packet) AT_CALL(0) { EXPECT_EQ(DATA_TYPE_ACL, type); return; } DURING(ignoring_packets_ignored_packet) AT_CALL(0) { EXPECT_EQ(DATA_TYPE_EVENT, type); return; } DURING( transmit_command_no_callbacks, transmit_command_command_status, transmit_command_command_complete ) AT_CALL(0) { EXPECT_EQ(DATA_TYPE_EVENT, type); return; } UNEXPECTED_CALL; } STUB_FUNCTION(bool, hci_inject_open, ( UNUSED_ATTR const hci_t *hci_interface)) DURING(start_up_async) AT_CALL(0) return true; UNEXPECTED_CALL; return false; } STUB_FUNCTION(void, hci_inject_close, ()) DURING(shut_down) AT_CALL(0) return; UNEXPECTED_CALL; } STUB_FUNCTION(void, btsnoop_capture, (const BT_HDR *buffer, bool is_received)) DURING(transmit_simple) AT_CALL(0) { EXPECT_FALSE(is_received); expect_packet(MSG_STACK_TO_HC_HCI_ACL, 1021, buffer->data + buffer->offset, buffer->len, small_sample_data); packet_index = 0; data_size_sum = 0; return; } DURING( transmit_command_no_callbacks, transmit_command_command_status, transmit_command_command_complete) { AT_CALL(0) { EXPECT_FALSE(is_received); expect_packet(MSG_STACK_TO_HC_HCI_CMD, 1021, buffer->data + buffer->offset, buffer->len, command_sample_data); packet_index = 0; data_size_sum = 0; return; } AT_CALL(1) { EXPECT_TRUE(is_received); // not super important to verify the contents right now return; } } DURING( receive_simple, ignoring_packets_following_packet ) AT_CALL(0) { EXPECT_TRUE(is_received); EXPECT_TRUE(buffer->len == data_to_receive->len); const uint8_t *buffer_base = buffer->data + buffer->offset; const uint8_t *expected_base = data_to_receive->data; for (int i = 0; i < buffer->len; i++) { EXPECT_EQ(expected_base[i], buffer_base[i]); } return; } UNEXPECTED_CALL; } STUB_FUNCTION(void, low_power_init, (UNUSED_ATTR thread_t *thread)) DURING(start_up_async) AT_CALL(0) return; UNEXPECTED_CALL; } STUB_FUNCTION(void, low_power_cleanup, ()) DURING(shut_down) AT_CALL(0) return; UNEXPECTED_CALL; } STUB_FUNCTION(void, low_power_wake_assert, ()) DURING( transmit_simple, transmit_command_no_callbacks, transmit_command_command_status, transmit_command_command_complete) { AT_CALL(0) return; } UNEXPECTED_CALL; } STUB_FUNCTION(void, low_power_transmit_done, ()) DURING( transmit_simple, transmit_command_no_callbacks, transmit_command_command_status, transmit_command_command_complete) { AT_CALL(0) return; } UNEXPECTED_CALL; } STUB_FUNCTION(bool, vendor_open, (UNUSED_ATTR const uint8_t *addr, const hci_t *hci_interface)) DURING(start_up_async) AT_CALL(0) { // TODO(zachoverflow): check address value when it gets put into a module EXPECT_EQ(hci, hci_interface); return true; } UNEXPECTED_CALL; return true; } STUB_FUNCTION(void, vendor_close, ()) DURING(shut_down) AT_CALL(0) return; UNEXPECTED_CALL; } STUB_FUNCTION(void, vendor_set_callback, (vendor_async_opcode_t opcode, UNUSED_ATTR vendor_cb callback)) DURING(start_up_async) { AT_CALL(0) { EXPECT_EQ(VENDOR_CONFIGURE_FIRMWARE, opcode); firmware_config_callback = callback; return; } AT_CALL(1) { EXPECT_EQ(VENDOR_CONFIGURE_SCO, opcode); sco_config_callback = callback; return; } AT_CALL(2) { EXPECT_EQ(VENDOR_DO_EPILOG, opcode); epilog_callback = callback; return; } } UNEXPECTED_CALL; } STUB_FUNCTION(int, vendor_send_command, (vendor_opcode_t opcode, void *param)) DURING(start_up_async) { #if (defined (BT_CLEAN_TURN_ON_DISABLED) && BT_CLEAN_TURN_ON_DISABLED == TRUE) AT_CALL(0) { EXPECT_EQ(VENDOR_CHIP_POWER_CONTROL, opcode); EXPECT_EQ(BT_VND_PWR_ON, *(int *)param); return 0; } #else AT_CALL(0) { EXPECT_EQ(VENDOR_CHIP_POWER_CONTROL, opcode); EXPECT_EQ(BT_VND_PWR_OFF, *(int *)param); return 0; } AT_CALL(1) { EXPECT_EQ(VENDOR_CHIP_POWER_CONTROL, opcode); EXPECT_EQ(BT_VND_PWR_ON, *(int *)param); return 0; } #endif } DURING(shut_down) AT_CALL(0) { EXPECT_EQ(VENDOR_CHIP_POWER_CONTROL, opcode); EXPECT_EQ(BT_VND_PWR_OFF, *(int *)param); return 0; } UNEXPECTED_CALL; return 0; } STUB_FUNCTION(int, vendor_send_async_command, (UNUSED_ATTR vendor_async_opcode_t opcode, UNUSED_ATTR void *param)) DURING(start_up_async) AT_CALL(0) { EXPECT_EQ(VENDOR_CONFIGURE_FIRMWARE, opcode); firmware_config_callback(true); return 0; } DURING(postload) AT_CALL(0) { EXPECT_EQ(VENDOR_CONFIGURE_SCO, opcode); sco_config_callback(true); return 0; } DURING(shut_down) AT_CALL(0) { EXPECT_EQ(VENDOR_DO_EPILOG, opcode); epilog_callback(true); return 0; } UNEXPECTED_CALL; return 0; } STUB_FUNCTION(void, command_complete_callback, (BT_HDR *response, UNUSED_ATTR void *context)) DURING(transmit_command_command_complete) AT_CALL(0) { osi_free(response); return; } UNEXPECTED_CALL; } STUB_FUNCTION(void, command_status_callback, (UNUSED_ATTR uint8_t status, BT_HDR *command, UNUSED_ATTR void *context)) DURING(transmit_command_command_status) AT_CALL(0) { osi_free(command); return; } UNEXPECTED_CALL; } STUB_FUNCTION(uint16_t, controller_get_acl_data_size_classic, (void)) return 2048; } STUB_FUNCTION(uint16_t, controller_get_acl_data_size_ble, (void)) return 2048; } STUB_FUNCTION(void *, buffer_allocator_alloc, (size_t size)) DURING(ignoring_packets_ignored_packet) { AT_CALL(0) return NULL; UNEXPECTED_CALL; } return allocator_malloc.alloc(size); } STUB_FUNCTION(void, buffer_allocator_free, (void *ptr)) allocator_malloc.free(ptr); } static void reset_for(TEST_MODES_T next) { RESET_CALL_COUNT(vendor_open); RESET_CALL_COUNT(vendor_close); RESET_CALL_COUNT(vendor_set_callback); RESET_CALL_COUNT(vendor_send_command); RESET_CALL_COUNT(vendor_send_async_command); RESET_CALL_COUNT(hal_init); RESET_CALL_COUNT(hal_open); RESET_CALL_COUNT(hal_close); RESET_CALL_COUNT(hal_read_data); RESET_CALL_COUNT(hal_packet_finished); RESET_CALL_COUNT(hal_transmit_data); RESET_CALL_COUNT(btsnoop_capture); RESET_CALL_COUNT(hci_inject_open); RESET_CALL_COUNT(hci_inject_close); RESET_CALL_COUNT(low_power_init); RESET_CALL_COUNT(low_power_cleanup); RESET_CALL_COUNT(low_power_wake_assert); RESET_CALL_COUNT(low_power_transmit_done); RESET_CALL_COUNT(command_complete_callback); RESET_CALL_COUNT(command_status_callback); RESET_CALL_COUNT(controller_get_acl_data_size_classic); RESET_CALL_COUNT(controller_get_acl_data_size_ble); RESET_CALL_COUNT(buffer_allocator_alloc); RESET_CALL_COUNT(buffer_allocator_free); CURRENT_TEST_MODE = next; } class HciLayerTest : public AlarmTestHarness { protected: virtual void SetUp() { AlarmTestHarness::SetUp(); module_management_start(); hci = hci_layer_get_test_interface( &buffer_allocator, &hal, &btsnoop, &hci_inject, packet_fragmenter_get_test_interface(&controller, &allocator_malloc), &vendor, &low_power_manager ); packet_index = 0; data_size_sum = 0; vendor.open = vendor_open; vendor.close = vendor_close; vendor.set_callback = vendor_set_callback; vendor.send_command = vendor_send_command; vendor.send_async_command = vendor_send_async_command; hal.init = hal_init; hal.open = hal_open; hal.close = hal_close; hal.read_data = hal_read_data; hal.packet_finished = hal_packet_finished; hal.transmit_data = hal_transmit_data; btsnoop.capture = btsnoop_capture; hci_inject.open = hci_inject_open; hci_inject.close = hci_inject_close; low_power_manager.init = low_power_init; low_power_manager.cleanup = low_power_cleanup; low_power_manager.wake_assert = low_power_wake_assert; low_power_manager.transmit_done = low_power_transmit_done; controller.get_acl_data_size_classic = controller_get_acl_data_size_classic; controller.get_acl_data_size_ble = controller_get_acl_data_size_ble; buffer_allocator.alloc = buffer_allocator_alloc; buffer_allocator.free = buffer_allocator_free; done = semaphore_new(0); reset_for(start_up_async); EXPECT_TRUE(module_start_up(&hci_module)); EXPECT_CALL_COUNT(vendor_open, 1); EXPECT_CALL_COUNT(hal_init, 1); EXPECT_CALL_COUNT(low_power_init, 1); EXPECT_CALL_COUNT(vendor_set_callback, 3); EXPECT_CALL_COUNT(hal_open, 1); EXPECT_CALL_COUNT(vendor_send_async_command, 1); } virtual void TearDown() { reset_for(shut_down); module_shut_down(&hci_module); EXPECT_CALL_COUNT(low_power_cleanup, 1); EXPECT_CALL_COUNT(hal_close, 1); EXPECT_CALL_COUNT(vendor_send_command, 1); EXPECT_CALL_COUNT(vendor_close, 1); semaphore_free(done); hci_layer_cleanup_interface(); module_management_stop(); AlarmTestHarness::TearDown(); } hci_hal_t hal; btsnoop_t btsnoop; controller_t controller; hci_inject_t hci_inject; vendor_t vendor; low_power_manager_t low_power_manager; allocator_t buffer_allocator; }; TEST_F(HciLayerTest, test_postload) { reset_for(postload); hci->do_postload(); flush_thread(internal_thread); EXPECT_CALL_COUNT(vendor_send_async_command, 1); } TEST_F(HciLayerTest, test_transmit_simple) { reset_for(transmit_simple); BT_HDR *packet = manufacture_packet(MSG_STACK_TO_HC_HCI_ACL, small_sample_data); hci->transmit_downward(MSG_STACK_TO_HC_HCI_ACL, packet); flush_thread(internal_thread); EXPECT_CALL_COUNT(hal_transmit_data, 1); EXPECT_CALL_COUNT(btsnoop_capture, 1); EXPECT_CALL_COUNT(low_power_transmit_done, 1); EXPECT_CALL_COUNT(low_power_wake_assert, 1); } TEST_F(HciLayerTest, test_receive_simple) { reset_for(receive_simple); data_to_receive = manufacture_packet(MSG_STACK_TO_HC_HCI_ACL, small_sample_data); // Not running on the internal thread, unlike the real hal hal_callbacks->data_ready(DATA_TYPE_ACL); EXPECT_CALL_COUNT(hal_packet_finished, 1); EXPECT_CALL_COUNT(btsnoop_capture, 1); osi_free(data_to_receive); } static BT_HDR *manufacture_command_complete(command_opcode_t opcode) { BT_HDR *ret = (BT_HDR *)osi_calloc(sizeof(BT_HDR) + 5); uint8_t *stream = ret->data; UINT8_TO_STREAM(stream, HCI_COMMAND_COMPLETE_EVT); UINT8_TO_STREAM(stream, 3); // length of the event parameters UINT8_TO_STREAM(stream, 1); // the number of commands that can be sent UINT16_TO_STREAM(stream, opcode); ret->len = 5; return ret; } static BT_HDR *manufacture_command_status(command_opcode_t opcode) { BT_HDR *ret = (BT_HDR *)osi_calloc(sizeof(BT_HDR) + 6); uint8_t *stream = ret->data; UINT8_TO_STREAM(stream, HCI_COMMAND_STATUS_EVT); UINT8_TO_STREAM(stream, 4); // length of the event parameters UINT8_TO_STREAM(stream, HCI_PENDING); // status UINT8_TO_STREAM(stream, 1); // the number of commands that can be sent UINT16_TO_STREAM(stream, opcode); ret->len = 6; return ret; } TEST_F(HciLayerTest, test_transmit_command_no_callbacks) { // Send a test command reset_for(transmit_command_no_callbacks); data_to_receive = manufacture_packet(MSG_STACK_TO_HC_HCI_CMD, command_sample_data); hci->transmit_command(data_to_receive, NULL, NULL, NULL); flush_thread(internal_thread); EXPECT_CALL_COUNT(hal_transmit_data, 1); EXPECT_CALL_COUNT(btsnoop_capture, 1); EXPECT_CALL_COUNT(low_power_transmit_done, 1); EXPECT_CALL_COUNT(low_power_wake_assert, 1); // Send a response command_opcode_t opcode = *((uint16_t *)command_sample_data); data_to_receive = manufacture_command_complete(opcode); hal_callbacks->data_ready(DATA_TYPE_EVENT); EXPECT_CALL_COUNT(hal_packet_finished, 1); EXPECT_CALL_COUNT(btsnoop_capture, 2); osi_free(data_to_receive); } TEST_F(HciLayerTest, test_transmit_command_command_status) { // Send a test command reset_for(transmit_command_command_status); data_to_receive = manufacture_packet(MSG_STACK_TO_HC_HCI_CMD, command_sample_data); hci->transmit_command(data_to_receive, command_complete_callback, command_status_callback, NULL); flush_thread(internal_thread); EXPECT_CALL_COUNT(hal_transmit_data, 1); EXPECT_CALL_COUNT(btsnoop_capture, 1); EXPECT_CALL_COUNT(low_power_transmit_done, 1); EXPECT_CALL_COUNT(low_power_wake_assert, 1); command_opcode_t opcode = *((uint16_t *)command_sample_data); // Send status event response data_to_receive = manufacture_command_status(opcode); hal_callbacks->data_ready(DATA_TYPE_EVENT); EXPECT_CALL_COUNT(hal_packet_finished, 1); EXPECT_CALL_COUNT(btsnoop_capture, 2); EXPECT_CALL_COUNT(command_status_callback, 1); osi_free(data_to_receive); } TEST_F(HciLayerTest, test_transmit_command_command_complete) { // Send a test command reset_for(transmit_command_command_complete); data_to_receive = manufacture_packet(MSG_STACK_TO_HC_HCI_CMD, command_sample_data); hci->transmit_command(data_to_receive, command_complete_callback, command_status_callback, NULL); flush_thread(internal_thread); EXPECT_CALL_COUNT(hal_transmit_data, 1); EXPECT_CALL_COUNT(btsnoop_capture, 1); EXPECT_CALL_COUNT(low_power_transmit_done, 1); EXPECT_CALL_COUNT(low_power_wake_assert, 1); command_opcode_t opcode = *((uint16_t *)command_sample_data); // Send complete event response data_to_receive = manufacture_command_complete(opcode); hal_callbacks->data_ready(DATA_TYPE_EVENT); EXPECT_CALL_COUNT(hal_packet_finished, 1); EXPECT_CALL_COUNT(btsnoop_capture, 2); EXPECT_CALL_COUNT(command_complete_callback, 1); osi_free(data_to_receive); } TEST_F(HciLayerTest, test_ignoring_packets) { reset_for(ignoring_packets_ignored_packet); data_to_receive = manufacture_packet(MSG_HC_TO_STACK_HCI_EVT, unignored_data); hal_callbacks->data_ready(DATA_TYPE_EVENT); EXPECT_CALL_COUNT(buffer_allocator_alloc, 1); EXPECT_CALL_COUNT(hal_packet_finished, 1); EXPECT_CALL_COUNT(btsnoop_capture, 0); osi_free(data_to_receive); reset_for(ignoring_packets_following_packet); data_to_receive = manufacture_packet(MSG_STACK_TO_HC_HCI_ACL, ignored_data); hal_callbacks->data_ready(DATA_TYPE_ACL); EXPECT_CALL_COUNT(buffer_allocator_alloc, 1); EXPECT_CALL_COUNT(hal_packet_finished, 1); EXPECT_CALL_COUNT(btsnoop_capture, 1); osi_free(data_to_receive); } // TODO(zachoverflow): test post-reassembly better, stub out fragmenter instead of using it