/* * Copyright 2019 The Android Open Source Project * * 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 "hci/controller.h" #include #include #include #include #include #include "common/bind.h" #include "common/callback.h" #include "common/init_flags.h" #include "hci/address.h" #include "hci/hci_layer.h" #include "os/thread.h" #include "packet/raw_builder.h" namespace bluetooth { namespace hci { namespace { using common::BidiQueue; using common::BidiQueueEnd; using packet::kLittleEndian; using packet::PacketView; using packet::RawBuilder; constexpr uint16_t kHandle1 = 0x123; constexpr uint16_t kCredits1 = 0x78; constexpr uint16_t kHandle2 = 0x456; constexpr uint16_t kCredits2 = 0x9a; uint16_t feature_spec_version = 55; PacketView GetPacketView(std::unique_ptr packet) { auto bytes = std::make_shared>(); BitInserter i(*bytes); bytes->reserve(packet->size()); packet->Serialize(i); return packet::PacketView(bytes); } class TestHciLayer : public HciLayer { public: void EnqueueCommand( std::unique_ptr command, common::ContextualOnceCallback on_complete) override { GetHandler()->Post(common::BindOnce(&TestHciLayer::HandleCommand, common::Unretained(this), std::move(command), std::move(on_complete))); } void EnqueueCommand( std::unique_ptr command, common::ContextualOnceCallback on_status) override { EXPECT_TRUE(false) << "Controller properties should not generate Command Status"; } void HandleCommand( std::unique_ptr command_builder, common::ContextualOnceCallback on_complete) { auto packet_view = GetPacketView(std::move(command_builder)); CommandView command = CommandView::Create(packet_view); ASSERT_TRUE(command.IsValid()); uint8_t num_packets = 1; std::unique_ptr event_builder; switch (command.GetOpCode()) { case (OpCode::READ_LOCAL_NAME): { std::array local_name = {'D', 'U', 'T', '\0'}; event_builder = ReadLocalNameCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, local_name); } break; case (OpCode::READ_LOCAL_VERSION_INFORMATION): { LocalVersionInformation local_version_information; local_version_information.hci_version_ = HciVersion::V_5_0; local_version_information.hci_revision_ = 0x1234; local_version_information.lmp_version_ = LmpVersion::V_4_2; local_version_information.manufacturer_name_ = 0xBAD; local_version_information.lmp_subversion_ = 0x5678; event_builder = ReadLocalVersionInformationCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, local_version_information); } break; case (OpCode::READ_LOCAL_SUPPORTED_COMMANDS): { std::array supported_commands; for (int i = 0; i < 37; i++) { supported_commands[i] = 0xff; } for (int i = 37; i < 64; i++) { supported_commands[i] = 0x00; } event_builder = ReadLocalSupportedCommandsCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, supported_commands); } break; case (OpCode::READ_LOCAL_EXTENDED_FEATURES): { ReadLocalExtendedFeaturesView read_command = ReadLocalExtendedFeaturesView::Create(command); ASSERT_TRUE(read_command.IsValid()); uint8_t page_bumber = read_command.GetPageNumber(); uint64_t lmp_features = 0x012345678abcdef; lmp_features += page_bumber; event_builder = ReadLocalExtendedFeaturesCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, page_bumber, 0x02, lmp_features); } break; case (OpCode::READ_BUFFER_SIZE): { event_builder = ReadBufferSizeCompleteBuilder::Create( num_packets, ErrorCode::SUCCESS, acl_data_packet_length, synchronous_data_packet_length, total_num_acl_data_packets, total_num_synchronous_data_packets); } break; case (OpCode::READ_BD_ADDR): { event_builder = ReadBdAddrCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, Address::kAny); } break; case (OpCode::LE_READ_BUFFER_SIZE_V1): { LeBufferSize le_buffer_size; le_buffer_size.le_data_packet_length_ = 0x16; le_buffer_size.total_num_le_packets_ = 0x08; event_builder = LeReadBufferSizeV1CompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, le_buffer_size); } break; case (OpCode::LE_READ_LOCAL_SUPPORTED_FEATURES): { event_builder = LeReadLocalSupportedFeaturesCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, 0x001f123456789abc); } break; case (OpCode::LE_READ_SUPPORTED_STATES): { event_builder = LeReadSupportedStatesCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, 0x001f123456789abe); } break; case (OpCode::LE_READ_MAXIMUM_DATA_LENGTH): { LeMaximumDataLength le_maximum_data_length; le_maximum_data_length.supported_max_tx_octets_ = 0x12; le_maximum_data_length.supported_max_tx_time_ = 0x34; le_maximum_data_length.supported_max_rx_octets_ = 0x56; le_maximum_data_length.supported_max_rx_time_ = 0x78; event_builder = LeReadMaximumDataLengthCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, le_maximum_data_length); } break; case (OpCode::LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH): { event_builder = LeReadMaximumAdvertisingDataLengthCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, 0x0672); } break; case (OpCode::LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS): { event_builder = LeReadNumberOfSupportedAdvertisingSetsCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, 0xF0); } break; case (OpCode::LE_GET_VENDOR_CAPABILITIES): { BaseVendorCapabilities base_vendor_capabilities; base_vendor_capabilities.max_advt_instances_ = 0x10; base_vendor_capabilities.offloaded_resolution_of_private_address_ = 0x01; base_vendor_capabilities.total_scan_results_storage_ = 0x2800; base_vendor_capabilities.max_irk_list_sz_ = 0x20; base_vendor_capabilities.filtering_support_ = 0x01; base_vendor_capabilities.max_filter_ = 0x10; base_vendor_capabilities.activity_energy_info_support_ = 0x01; auto payload = std::make_unique(); if (feature_spec_version > 55) { std::vector payload_bytes = {0x20, 0x00, 0x01, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00}; payload->AddOctets2(feature_spec_version); payload->AddOctets(payload_bytes); } event_builder = LeGetVendorCapabilitiesCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, base_vendor_capabilities, std::move(payload)); } break; case (OpCode::SET_EVENT_MASK): { auto view = SetEventMaskView::Create(command); ASSERT_TRUE(view.IsValid()); event_mask = view.GetEventMask(); event_builder = SetEventMaskCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS); } break; case (OpCode::LE_SET_EVENT_MASK): { auto view = LeSetEventMaskView::Create(command); ASSERT_TRUE(view.IsValid()); le_event_mask = view.GetLeEventMask(); event_builder = LeSetEventMaskCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS); } break; case (OpCode::RESET): case (OpCode::SET_EVENT_FILTER): case (OpCode::HOST_BUFFER_SIZE): command_queue_.push(command); not_empty_.notify_all(); return; default: LOG_INFO("Dropping unhandled packet"); return; } auto packet = GetPacketView(std::move(event_builder)); EventView event = EventView::Create(packet); ASSERT_TRUE(event.IsValid()); CommandCompleteView command_complete = CommandCompleteView::Create(event); ASSERT_TRUE(command_complete.IsValid()); on_complete.Invoke(std::move(command_complete)); } void RegisterEventHandler(EventCode event_code, common::ContextualCallback event_handler) override { EXPECT_EQ(event_code, EventCode::NUMBER_OF_COMPLETED_PACKETS) << "Only NUMBER_OF_COMPLETED_PACKETS is needed"; number_of_completed_packets_callback_ = event_handler; } void UnregisterEventHandler(EventCode event_code) override { EXPECT_EQ(event_code, EventCode::NUMBER_OF_COMPLETED_PACKETS) << "Only NUMBER_OF_COMPLETED_PACKETS is needed"; number_of_completed_packets_callback_ = {}; } void IncomingCredit() { std::vector completed_packets; CompletedPackets cp; cp.host_num_of_completed_packets_ = kCredits1; cp.connection_handle_ = kHandle1; completed_packets.push_back(cp); cp.host_num_of_completed_packets_ = kCredits2; cp.connection_handle_ = kHandle2; completed_packets.push_back(cp); auto event_builder = NumberOfCompletedPacketsBuilder::Create(completed_packets); auto packet = GetPacketView(std::move(event_builder)); EventView event = EventView::Create(packet); ASSERT_TRUE(event.IsValid()); number_of_completed_packets_callback_.Invoke(event); } CommandView GetCommand(OpCode op_code) { std::unique_lock lock(mutex_); std::chrono::milliseconds time = std::chrono::milliseconds(3000); // wait for command while (command_queue_.size() == 0) { if (not_empty_.wait_for(lock, time) == std::cv_status::timeout) { break; } } EXPECT_TRUE(command_queue_.size() > 0); if (command_queue_.empty()) { return CommandView::Create(PacketView(std::make_shared>())); } CommandView command = command_queue_.front(); EXPECT_EQ(command.GetOpCode(), op_code); command_queue_.pop(); return command; } void ListDependencies(ModuleList* list) override {} void Start() override {} void Stop() override {} constexpr static uint16_t acl_data_packet_length = 1024; constexpr static uint8_t synchronous_data_packet_length = 60; constexpr static uint16_t total_num_acl_data_packets = 10; constexpr static uint16_t total_num_synchronous_data_packets = 12; uint64_t event_mask = 0; uint64_t le_event_mask = 0; private: common::ContextualCallback number_of_completed_packets_callback_; std::queue command_queue_; mutable std::mutex mutex_; std::condition_variable not_empty_; }; class ControllerTest : public ::testing::Test { protected: void SetUp() override { bluetooth::common::InitFlags::SetAllForTesting(); test_hci_layer_ = new TestHciLayer; fake_registry_.InjectTestModule(&HciLayer::Factory, test_hci_layer_); client_handler_ = fake_registry_.GetTestModuleHandler(&HciLayer::Factory); fake_registry_.Start(&thread_); controller_ = static_cast(fake_registry_.GetModuleUnderTest(&Controller::Factory)); } void TearDown() override { fake_registry_.StopAll(); } TestModuleRegistry fake_registry_; TestHciLayer* test_hci_layer_ = nullptr; os::Thread& thread_ = fake_registry_.GetTestThread(); Controller* controller_ = nullptr; os::Handler* client_handler_ = nullptr; }; TEST_F(ControllerTest, startup_teardown) {} TEST_F(ControllerTest, read_controller_info) { ASSERT_EQ(controller_->GetAclPacketLength(), test_hci_layer_->acl_data_packet_length); ASSERT_EQ(controller_->GetNumAclPacketBuffers(), test_hci_layer_->total_num_acl_data_packets); ASSERT_EQ(controller_->GetScoPacketLength(), test_hci_layer_->synchronous_data_packet_length); ASSERT_EQ(controller_->GetNumScoPacketBuffers(), test_hci_layer_->total_num_synchronous_data_packets); ASSERT_EQ(controller_->GetMacAddress(), Address::kAny); LocalVersionInformation local_version_information = controller_->GetLocalVersionInformation(); ASSERT_EQ(local_version_information.hci_version_, HciVersion::V_5_0); ASSERT_EQ(local_version_information.hci_revision_, 0x1234); ASSERT_EQ(local_version_information.lmp_version_, LmpVersion::V_4_2); ASSERT_EQ(local_version_information.manufacturer_name_, 0xBAD); ASSERT_EQ(local_version_information.lmp_subversion_, 0x5678); ASSERT_EQ(controller_->GetLeBufferSize().le_data_packet_length_, 0x16); ASSERT_EQ(controller_->GetLeBufferSize().total_num_le_packets_, 0x08); ASSERT_EQ(controller_->GetLeSupportedStates(), 0x001f123456789abe); ASSERT_EQ(controller_->GetLeMaximumDataLength().supported_max_tx_octets_, 0x12); ASSERT_EQ(controller_->GetLeMaximumDataLength().supported_max_tx_time_, 0x34); ASSERT_EQ(controller_->GetLeMaximumDataLength().supported_max_rx_octets_, 0x56); ASSERT_EQ(controller_->GetLeMaximumDataLength().supported_max_rx_time_, 0x78); ASSERT_EQ(controller_->GetLeMaximumAdvertisingDataLength(), 0x0672); ASSERT_EQ(controller_->GetLeNumberOfSupportedAdverisingSets(), 0xF0); } TEST_F(ControllerTest, read_write_local_name) { ASSERT_EQ(controller_->GetLocalName(), "DUT"); controller_->WriteLocalName("New name"); ASSERT_EQ(controller_->GetLocalName(), "New name"); } TEST_F(ControllerTest, send_set_event_mask_command) { uint64_t new_event_mask = test_hci_layer_->event_mask - 1; controller_->SetEventMask(new_event_mask); // Send another command to make sure it was applied controller_->Reset(); auto packet = test_hci_layer_->GetCommand(OpCode::RESET); ASSERT_EQ(new_event_mask, test_hci_layer_->event_mask); } TEST_F(ControllerTest, send_reset_command) { controller_->Reset(); auto packet = test_hci_layer_->GetCommand(OpCode::RESET); auto command = ResetView::Create(packet); ASSERT_TRUE(command.IsValid()); } TEST_F(ControllerTest, send_set_event_filter_command) { controller_->SetEventFilterInquiryResultAllDevices(); auto packet = test_hci_layer_->GetCommand(OpCode::SET_EVENT_FILTER); auto set_event_filter_view1 = SetEventFilterView::Create(packet); auto set_event_filter_inquiry_result_view1 = SetEventFilterInquiryResultView::Create(set_event_filter_view1); auto command1 = SetEventFilterInquiryResultAllDevicesView::Create(set_event_filter_inquiry_result_view1); ASSERT_TRUE(command1.IsValid()); ClassOfDevice class_of_device({0xab, 0xcd, 0xef}); ClassOfDevice class_of_device_mask({0x12, 0x34, 0x56}); controller_->SetEventFilterInquiryResultClassOfDevice(class_of_device, class_of_device_mask); packet = test_hci_layer_->GetCommand(OpCode::SET_EVENT_FILTER); auto set_event_filter_view2 = SetEventFilterView::Create(packet); auto set_event_filter_inquiry_result_view2 = SetEventFilterInquiryResultView::Create(set_event_filter_view2); auto command2 = SetEventFilterInquiryResultClassOfDeviceView::Create(set_event_filter_inquiry_result_view2); ASSERT_TRUE(command2.IsValid()); ASSERT_EQ(command2.GetClassOfDevice(), class_of_device); Address bdaddr({0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc}); controller_->SetEventFilterConnectionSetupAddress(bdaddr, AutoAcceptFlag::AUTO_ACCEPT_ON_ROLE_SWITCH_ENABLED); packet = test_hci_layer_->GetCommand(OpCode::SET_EVENT_FILTER); auto set_event_filter_view3 = SetEventFilterView::Create(packet); auto set_event_filter_connection_setup_view = SetEventFilterConnectionSetupView::Create(set_event_filter_view3); auto command3 = SetEventFilterConnectionSetupAddressView::Create(set_event_filter_connection_setup_view); ASSERT_TRUE(command3.IsValid()); ASSERT_EQ(command3.GetAddress(), bdaddr); } TEST_F(ControllerTest, send_host_buffer_size_command) { controller_->HostBufferSize(0xFF00, 0xF1, 0xFF02, 0xFF03); auto packet = test_hci_layer_->GetCommand(OpCode::HOST_BUFFER_SIZE); auto command = HostBufferSizeView::Create(packet); ASSERT_TRUE(command.IsValid()); ASSERT_EQ(command.GetHostAclDataPacketLength(), 0xFF00); ASSERT_EQ(command.GetHostSynchronousDataPacketLength(), 0xF1); ASSERT_EQ(command.GetHostTotalNumAclDataPackets(), 0xFF02); ASSERT_EQ(command.GetHostTotalNumSynchronousDataPackets(), 0xFF03); } TEST_F(ControllerTest, send_le_set_event_mask_command) { uint64_t new_le_event_mask = test_hci_layer_->event_mask - 1; controller_->LeSetEventMask(new_le_event_mask); // Send another command to make sure it was applied controller_->Reset(); auto packet = test_hci_layer_->GetCommand(OpCode::RESET); ASSERT_EQ(new_le_event_mask, test_hci_layer_->le_event_mask); } TEST_F(ControllerTest, is_supported_test) { ASSERT_TRUE(controller_->IsSupported(OpCode::INQUIRY)); ASSERT_TRUE(controller_->IsSupported(OpCode::REJECT_CONNECTION_REQUEST)); ASSERT_TRUE(controller_->IsSupported(OpCode::ACCEPT_CONNECTION_REQUEST)); ASSERT_FALSE(controller_->IsSupported(OpCode::LE_REMOVE_ADVERTISING_SET)); ASSERT_FALSE(controller_->IsSupported(OpCode::LE_CLEAR_ADVERTISING_SETS)); ASSERT_FALSE(controller_->IsSupported(OpCode::LE_SET_PERIODIC_ADVERTISING_PARAM)); } TEST_F(ControllerTest, feature_spec_version_055_test) { EXPECT_EQ(controller_->GetVendorCapabilities().version_supported_, 55); EXPECT_TRUE(controller_->IsSupported(OpCode::LE_MULTI_ADVT)); EXPECT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_DEBUG_INFO)); EXPECT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_A2DP_OPCODE)); feature_spec_version = 95; } TEST_F(ControllerTest, feature_spec_version_095_test) { EXPECT_EQ(controller_->GetVendorCapabilities().version_supported_, 95); EXPECT_TRUE(controller_->IsSupported(OpCode::LE_MULTI_ADVT)); EXPECT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_DEBUG_INFO)); EXPECT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_A2DP_OPCODE)); feature_spec_version = 96; } TEST_F(ControllerTest, feature_spec_version_096_test) { EXPECT_EQ(controller_->GetVendorCapabilities().version_supported_, 96); EXPECT_TRUE(controller_->IsSupported(OpCode::LE_MULTI_ADVT)); EXPECT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_DEBUG_INFO)); EXPECT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_A2DP_OPCODE)); feature_spec_version = 98; } TEST_F(ControllerTest, feature_spec_version_098_test) { EXPECT_EQ(controller_->GetVendorCapabilities().version_supported_, 98); EXPECT_TRUE(controller_->IsSupported(OpCode::LE_MULTI_ADVT)); EXPECT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_DEBUG_INFO)); EXPECT_TRUE(controller_->IsSupported(OpCode::CONTROLLER_A2DP_OPCODE)); } std::promise credits1_set; std::promise credits2_set; void CheckReceivedCredits(uint16_t handle, uint16_t credits) { switch (handle) { case (kHandle1): ASSERT_EQ(kCredits1, credits); credits1_set.set_value(); break; case (kHandle2): ASSERT_EQ(kCredits2, credits); credits2_set.set_value(); break; default: ASSERT_LOG(false, "Unknown handle 0x%0hx with 0x%0hx credits", handle, credits); } } TEST_F(ControllerTest, aclCreditCallbacksTest) { controller_->RegisterCompletedAclPacketsCallback(client_handler_->Bind(&CheckReceivedCredits)); test_hci_layer_->IncomingCredit(); credits1_set.get_future().wait(); credits2_set.get_future().wait(); } TEST_F(ControllerTest, aclCreditCallbackListenerUnregistered) { os::Thread thread("test_thread", os::Thread::Priority::NORMAL); os::Handler handler(&thread); controller_->RegisterCompletedAclPacketsCallback(handler.Bind(&CheckReceivedCredits)); handler.Clear(); handler.WaitUntilStopped(std::chrono::milliseconds(100)); controller_->UnregisterCompletedAclPacketsCallback(); test_hci_layer_->IncomingCredit(); } } // namespace } // namespace hci } // namespace bluetooth