| /* |
| * 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. |
| */ |
| |
| #define LOG_TAG "bt_shim_hci" |
| |
| #include "hci/hci_layer.h" |
| |
| #include <base/bind.h> |
| |
| #include <algorithm> |
| #include <cstdint> |
| |
| #include "callbacks/callbacks.h" |
| #include "gd/common/init_flags.h" |
| #include "hci/hci_packets.h" |
| #include "hci/include/packet_fragmenter.h" |
| #include "hci/le_acl_connection_interface.h" |
| #include "hci/vendor_specific_event_manager.h" |
| #include "main/shim/hci_layer.h" |
| #include "main/shim/shim.h" |
| #include "main/shim/stack.h" |
| #include "osi/include/allocator.h" |
| #include "osi/include/future.h" |
| #include "packet/raw_builder.h" |
| #include "src/bridge.rs.h" |
| #include "stack/include/bt_types.h" |
| |
| /** |
| * Callback data wrapped as opaque token bundled with the command |
| * transmit request to the Gd layer. |
| * |
| * Upon completion a token for a corresponding command transmit. |
| * request is returned from the Gd layer. |
| */ |
| using CommandCallbackData = struct { void* context; }; |
| |
| constexpr size_t kBtHdrSize = sizeof(BT_HDR); |
| constexpr size_t kCommandLengthSize = sizeof(uint8_t); |
| constexpr size_t kCommandOpcodeSize = sizeof(uint16_t); |
| |
| static base::Callback<void(const base::Location&, BT_HDR*)> send_data_upwards; |
| static const packet_fragmenter_t* packet_fragmenter; |
| |
| namespace { |
| bool is_valid_event_code(bluetooth::hci::EventCode event_code) { |
| switch (event_code) { |
| case bluetooth::hci::EventCode::INQUIRY_COMPLETE: |
| case bluetooth::hci::EventCode::INQUIRY_RESULT: |
| case bluetooth::hci::EventCode::CONNECTION_COMPLETE: |
| case bluetooth::hci::EventCode::CONNECTION_REQUEST: |
| case bluetooth::hci::EventCode::DISCONNECTION_COMPLETE: |
| case bluetooth::hci::EventCode::AUTHENTICATION_COMPLETE: |
| case bluetooth::hci::EventCode::REMOTE_NAME_REQUEST_COMPLETE: |
| case bluetooth::hci::EventCode::ENCRYPTION_CHANGE: |
| case bluetooth::hci::EventCode::CHANGE_CONNECTION_LINK_KEY_COMPLETE: |
| case bluetooth::hci::EventCode::CENTRAL_LINK_KEY_COMPLETE: |
| case bluetooth::hci::EventCode::READ_REMOTE_SUPPORTED_FEATURES_COMPLETE: |
| case bluetooth::hci::EventCode::READ_REMOTE_VERSION_INFORMATION_COMPLETE: |
| case bluetooth::hci::EventCode::QOS_SETUP_COMPLETE: |
| case bluetooth::hci::EventCode::COMMAND_COMPLETE: |
| case bluetooth::hci::EventCode::COMMAND_STATUS: |
| case bluetooth::hci::EventCode::HARDWARE_ERROR: |
| case bluetooth::hci::EventCode::FLUSH_OCCURRED: |
| case bluetooth::hci::EventCode::ROLE_CHANGE: |
| case bluetooth::hci::EventCode::NUMBER_OF_COMPLETED_PACKETS: |
| case bluetooth::hci::EventCode::MODE_CHANGE: |
| case bluetooth::hci::EventCode::RETURN_LINK_KEYS: |
| case bluetooth::hci::EventCode::PIN_CODE_REQUEST: |
| case bluetooth::hci::EventCode::LINK_KEY_REQUEST: |
| case bluetooth::hci::EventCode::LINK_KEY_NOTIFICATION: |
| case bluetooth::hci::EventCode::LOOPBACK_COMMAND: |
| case bluetooth::hci::EventCode::DATA_BUFFER_OVERFLOW: |
| case bluetooth::hci::EventCode::MAX_SLOTS_CHANGE: |
| case bluetooth::hci::EventCode::READ_CLOCK_OFFSET_COMPLETE: |
| case bluetooth::hci::EventCode::CONNECTION_PACKET_TYPE_CHANGED: |
| case bluetooth::hci::EventCode::QOS_VIOLATION: |
| case bluetooth::hci::EventCode::PAGE_SCAN_REPETITION_MODE_CHANGE: |
| case bluetooth::hci::EventCode::FLOW_SPECIFICATION_COMPLETE: |
| case bluetooth::hci::EventCode::INQUIRY_RESULT_WITH_RSSI: |
| case bluetooth::hci::EventCode::READ_REMOTE_EXTENDED_FEATURES_COMPLETE: |
| case bluetooth::hci::EventCode::SYNCHRONOUS_CONNECTION_COMPLETE: |
| case bluetooth::hci::EventCode::SYNCHRONOUS_CONNECTION_CHANGED: |
| case bluetooth::hci::EventCode::SNIFF_SUBRATING: |
| case bluetooth::hci::EventCode::EXTENDED_INQUIRY_RESULT: |
| case bluetooth::hci::EventCode::ENCRYPTION_KEY_REFRESH_COMPLETE: |
| case bluetooth::hci::EventCode::IO_CAPABILITY_REQUEST: |
| case bluetooth::hci::EventCode::IO_CAPABILITY_RESPONSE: |
| case bluetooth::hci::EventCode::USER_CONFIRMATION_REQUEST: |
| case bluetooth::hci::EventCode::USER_PASSKEY_REQUEST: |
| case bluetooth::hci::EventCode::REMOTE_OOB_DATA_REQUEST: |
| case bluetooth::hci::EventCode::SIMPLE_PAIRING_COMPLETE: |
| case bluetooth::hci::EventCode::LINK_SUPERVISION_TIMEOUT_CHANGED: |
| case bluetooth::hci::EventCode::ENHANCED_FLUSH_COMPLETE: |
| case bluetooth::hci::EventCode::USER_PASSKEY_NOTIFICATION: |
| case bluetooth::hci::EventCode::KEYPRESS_NOTIFICATION: |
| case bluetooth::hci::EventCode::REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION: |
| case bluetooth::hci::EventCode::NUMBER_OF_COMPLETED_DATA_BLOCKS: |
| return true; |
| case bluetooth::hci::EventCode::VENDOR_SPECIFIC: |
| case bluetooth::hci::EventCode::LE_META_EVENT: // Private to hci |
| return false; |
| } |
| return false; |
| }; |
| |
| bool is_valid_subevent_code(bluetooth::hci::SubeventCode subevent_code) { |
| switch (subevent_code) { |
| case bluetooth::hci::SubeventCode::CONNECTION_COMPLETE: |
| case bluetooth::hci::SubeventCode::CONNECTION_UPDATE_COMPLETE: |
| case bluetooth::hci::SubeventCode::DATA_LENGTH_CHANGE: |
| case bluetooth::hci::SubeventCode::ENHANCED_CONNECTION_COMPLETE: |
| case bluetooth::hci::SubeventCode::PHY_UPDATE_COMPLETE: |
| case bluetooth::hci::SubeventCode::READ_REMOTE_FEATURES_COMPLETE: |
| case bluetooth::hci::SubeventCode::REMOTE_CONNECTION_PARAMETER_REQUEST: |
| case bluetooth::hci::SubeventCode::READ_LOCAL_P256_PUBLIC_KEY_COMPLETE: |
| case bluetooth::hci::SubeventCode::GENERATE_DHKEY_COMPLETE: |
| case bluetooth::hci::SubeventCode::DIRECTED_ADVERTISING_REPORT: |
| case bluetooth::hci::SubeventCode::EXTENDED_ADVERTISING_REPORT: |
| case bluetooth::hci::SubeventCode::PERIODIC_ADVERTISING_SYNC_ESTABLISHED: |
| case bluetooth::hci::SubeventCode::PERIODIC_ADVERTISING_REPORT: |
| case bluetooth::hci::SubeventCode::PERIODIC_ADVERTISING_SYNC_LOST: |
| case bluetooth::hci::SubeventCode::SCAN_TIMEOUT: |
| case bluetooth::hci::SubeventCode::ADVERTISING_SET_TERMINATED: |
| case bluetooth::hci::SubeventCode::SCAN_REQUEST_RECEIVED: |
| case bluetooth::hci::SubeventCode::CHANNEL_SELECTION_ALGORITHM: |
| case bluetooth::hci::SubeventCode::CONNECTIONLESS_IQ_REPORT: |
| case bluetooth::hci::SubeventCode::CONNECTION_IQ_REPORT: |
| case bluetooth::hci::SubeventCode::CTE_REQUEST_FAILED: |
| case bluetooth::hci::SubeventCode:: |
| PERIODIC_ADVERTISING_SYNC_TRANSFER_RECEIVED: |
| case bluetooth::hci::SubeventCode::CIS_ESTABLISHED: |
| case bluetooth::hci::SubeventCode::CIS_REQUEST: |
| case bluetooth::hci::SubeventCode::CREATE_BIG_COMPLETE: |
| case bluetooth::hci::SubeventCode::TERMINATE_BIG_COMPLETE: |
| case bluetooth::hci::SubeventCode::BIG_SYNC_ESTABLISHED: |
| case bluetooth::hci::SubeventCode::BIG_SYNC_LOST: |
| case bluetooth::hci::SubeventCode::REQUEST_PEER_SCA_COMPLETE: |
| case bluetooth::hci::SubeventCode::PATH_LOSS_THRESHOLD: |
| case bluetooth::hci::SubeventCode::TRANSMIT_POWER_REPORTING: |
| case bluetooth::hci::SubeventCode::BIG_INFO_ADVERTISING_REPORT: |
| case bluetooth::hci::SubeventCode::ADVERTISING_REPORT: |
| case bluetooth::hci::SubeventCode::LONG_TERM_KEY_REQUEST: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| static bool event_already_registered_in_hci_layer( |
| bluetooth::hci::EventCode event_code) { |
| switch (event_code) { |
| case bluetooth::hci::EventCode::COMMAND_COMPLETE: |
| case bluetooth::hci::EventCode::COMMAND_STATUS: |
| case bluetooth::hci::EventCode::PAGE_SCAN_REPETITION_MODE_CHANGE: |
| case bluetooth::hci::EventCode::MAX_SLOTS_CHANGE: |
| case bluetooth::hci::EventCode::LE_META_EVENT: |
| return bluetooth::shim::is_gd_hci_enabled() || |
| bluetooth::shim::is_gd_acl_enabled() || |
| bluetooth::shim::is_gd_l2cap_enabled(); |
| case bluetooth::hci::EventCode::DISCONNECTION_COMPLETE: |
| case bluetooth::hci::EventCode::READ_REMOTE_VERSION_INFORMATION_COMPLETE: |
| return bluetooth::shim::is_gd_acl_enabled() || |
| bluetooth::shim::is_gd_l2cap_enabled(); |
| default: |
| return false; |
| } |
| } |
| |
| static bool event_already_registered_in_controller_layer( |
| bluetooth::hci::EventCode event_code) { |
| switch (event_code) { |
| case bluetooth::hci::EventCode::NUMBER_OF_COMPLETED_PACKETS: |
| return bluetooth::shim::is_gd_acl_enabled() || |
| bluetooth::shim::is_gd_l2cap_enabled(); |
| default: |
| return false; |
| } |
| } |
| |
| static bool event_already_registered_in_acl_layer( |
| bluetooth::hci::EventCode event_code) { |
| for (auto event : bluetooth::hci::AclConnectionEvents) { |
| if (event == event_code) { |
| return bluetooth::shim::is_gd_acl_enabled() || |
| bluetooth::shim::is_gd_l2cap_enabled(); |
| } |
| } |
| return false; |
| } |
| |
| static bool subevent_already_registered_in_le_hci_layer( |
| bluetooth::hci::SubeventCode subevent_code) { |
| switch (subevent_code) { |
| case bluetooth::hci::SubeventCode::CONNECTION_COMPLETE: |
| case bluetooth::hci::SubeventCode::CONNECTION_UPDATE_COMPLETE: |
| case bluetooth::hci::SubeventCode::DATA_LENGTH_CHANGE: |
| case bluetooth::hci::SubeventCode::ENHANCED_CONNECTION_COMPLETE: |
| case bluetooth::hci::SubeventCode::PHY_UPDATE_COMPLETE: |
| case bluetooth::hci::SubeventCode::REMOTE_CONNECTION_PARAMETER_REQUEST: |
| return bluetooth::shim::is_gd_acl_enabled() || |
| bluetooth::shim::is_gd_l2cap_enabled() || |
| bluetooth::shim::is_gd_advertising_enabled() || |
| bluetooth::shim::is_gd_scanning_enabled(); |
| case bluetooth::hci::SubeventCode::ADVERTISING_SET_TERMINATED: |
| case bluetooth::hci::SubeventCode::SCAN_REQUEST_RECEIVED: |
| return bluetooth::shim::is_gd_acl_enabled() || |
| bluetooth::shim::is_gd_l2cap_enabled() || |
| bluetooth::shim::is_gd_advertising_enabled(); |
| case bluetooth::hci::SubeventCode::SCAN_TIMEOUT: |
| case bluetooth::hci::SubeventCode::ADVERTISING_REPORT: |
| case bluetooth::hci::SubeventCode::DIRECTED_ADVERTISING_REPORT: |
| case bluetooth::hci::SubeventCode::EXTENDED_ADVERTISING_REPORT: |
| case bluetooth::hci::SubeventCode::PERIODIC_ADVERTISING_REPORT: |
| case bluetooth::hci::SubeventCode::PERIODIC_ADVERTISING_SYNC_ESTABLISHED: |
| case bluetooth::hci::SubeventCode::PERIODIC_ADVERTISING_SYNC_LOST: |
| return bluetooth::shim::is_gd_scanning_enabled(); |
| case bluetooth::hci::SubeventCode::READ_REMOTE_FEATURES_COMPLETE: |
| case bluetooth::hci::SubeventCode::READ_LOCAL_P256_PUBLIC_KEY_COMPLETE: |
| case bluetooth::hci::SubeventCode::GENERATE_DHKEY_COMPLETE: |
| case bluetooth::hci::SubeventCode::CHANNEL_SELECTION_ALGORITHM: |
| case bluetooth::hci::SubeventCode::CONNECTIONLESS_IQ_REPORT: |
| case bluetooth::hci::SubeventCode::CONNECTION_IQ_REPORT: |
| case bluetooth::hci::SubeventCode::CTE_REQUEST_FAILED: |
| case bluetooth::hci::SubeventCode:: |
| PERIODIC_ADVERTISING_SYNC_TRANSFER_RECEIVED: |
| case bluetooth::hci::SubeventCode::CIS_ESTABLISHED: |
| case bluetooth::hci::SubeventCode::CIS_REQUEST: |
| case bluetooth::hci::SubeventCode::CREATE_BIG_COMPLETE: |
| case bluetooth::hci::SubeventCode::TERMINATE_BIG_COMPLETE: |
| case bluetooth::hci::SubeventCode::BIG_SYNC_ESTABLISHED: |
| case bluetooth::hci::SubeventCode::BIG_SYNC_LOST: |
| case bluetooth::hci::SubeventCode::REQUEST_PEER_SCA_COMPLETE: |
| case bluetooth::hci::SubeventCode::PATH_LOSS_THRESHOLD: |
| case bluetooth::hci::SubeventCode::TRANSMIT_POWER_REPORTING: |
| case bluetooth::hci::SubeventCode::BIG_INFO_ADVERTISING_REPORT: |
| case bluetooth::hci::SubeventCode::LONG_TERM_KEY_REQUEST: |
| default: |
| return false; |
| } |
| } |
| |
| static bool event_already_registered_in_le_advertising_manager( |
| bluetooth::hci::EventCode event_code) { |
| for (auto event : bluetooth::hci::AclConnectionEvents) { |
| if (event == event_code) { |
| return bluetooth::shim::is_gd_advertising_enabled(); |
| } |
| } |
| return false; |
| } |
| |
| static bool event_already_registered_in_le_scanning_manager( |
| bluetooth::hci::EventCode event_code) { |
| for (auto event : bluetooth::hci::AclConnectionEvents) { |
| if (event == event_code) { |
| return bluetooth::shim::is_gd_scanning_enabled(); |
| } |
| } |
| return false; |
| } |
| |
| class OsiObject { |
| public: |
| OsiObject(void* ptr) : ptr_(ptr) {} |
| ~OsiObject() { |
| if (ptr_ != nullptr) { |
| osi_free(ptr_); |
| } |
| } |
| void* Release() { |
| void* ptr = ptr_; |
| ptr_ = nullptr; |
| return ptr; |
| } |
| |
| private: |
| void* ptr_; |
| }; |
| |
| } // namespace |
| |
| namespace cpp { |
| bluetooth::common::BidiQueueEnd<bluetooth::hci::AclBuilder, |
| bluetooth::hci::AclView>* hci_queue_end = |
| nullptr; |
| static bluetooth::os::EnqueueBuffer<bluetooth::hci::AclBuilder>* pending_data = |
| nullptr; |
| |
| static std::unique_ptr<bluetooth::packet::RawBuilder> MakeUniquePacket( |
| const uint8_t* data, size_t len) { |
| bluetooth::packet::RawBuilder builder; |
| std::vector<uint8_t> bytes(data, data + len); |
| |
| auto payload = std::make_unique<bluetooth::packet::RawBuilder>(); |
| payload->AddOctets(bytes); |
| |
| return payload; |
| } |
| |
| static BT_HDR* WrapPacketAndCopy( |
| uint16_t event, |
| bluetooth::hci::PacketView<bluetooth::hci::kLittleEndian>* data) { |
| size_t packet_size = data->size() + kBtHdrSize; |
| BT_HDR* packet = reinterpret_cast<BT_HDR*>(osi_malloc(packet_size)); |
| packet->offset = 0; |
| packet->len = data->size(); |
| packet->layer_specific = 0; |
| packet->event = event; |
| std::copy(data->begin(), data->end(), packet->data); |
| return packet; |
| } |
| |
| static void event_callback(bluetooth::hci::EventView event_packet_view) { |
| if (!send_data_upwards) { |
| return; |
| } |
| send_data_upwards.Run(FROM_HERE, WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_EVT, |
| &event_packet_view)); |
| } |
| |
| static void subevent_callback( |
| bluetooth::hci::LeMetaEventView le_meta_event_view) { |
| if (!send_data_upwards) { |
| return; |
| } |
| send_data_upwards.Run(FROM_HERE, WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_EVT, |
| &le_meta_event_view)); |
| } |
| |
| static void vendor_specific_event_callback( |
| bluetooth::hci::VendorSpecificEventView vendor_specific_event_view) { |
| if (!send_data_upwards) { |
| return; |
| } |
| send_data_upwards.Run( |
| FROM_HERE, |
| WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_EVT, &vendor_specific_event_view)); |
| } |
| |
| void OnTransmitPacketCommandComplete(command_complete_cb complete_callback, |
| void* context, |
| bluetooth::hci::CommandCompleteView view) { |
| LOG_DEBUG("Received cmd complete for %s", |
| bluetooth::hci::OpCodeText(view.GetCommandOpCode()).c_str()); |
| std::vector<uint8_t> data(view.begin(), view.end()); |
| BT_HDR* response = WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_EVT, &view); |
| complete_callback(response, context); |
| } |
| |
| void OnTransmitPacketStatus(command_status_cb status_callback, void* context, |
| std::unique_ptr<OsiObject> command, |
| bluetooth::hci::CommandStatusView view) { |
| LOG_DEBUG("Received cmd status %s for %s", |
| bluetooth::hci::ErrorCodeText(view.GetStatus()).c_str(), |
| bluetooth::hci::OpCodeText(view.GetCommandOpCode()).c_str()); |
| uint8_t status = static_cast<uint8_t>(view.GetStatus()); |
| status_callback(status, static_cast<BT_HDR*>(command->Release()), context); |
| } |
| |
| static void transmit_command(BT_HDR* command, |
| command_complete_cb complete_callback, |
| command_status_cb status_callback, void* context) { |
| CHECK(command != nullptr); |
| uint8_t* data = command->data + command->offset; |
| size_t len = command->len; |
| CHECK(len >= (kCommandOpcodeSize + kCommandLengthSize)); |
| |
| // little endian command opcode |
| uint16_t command_op_code = (data[1] << 8 | data[0]); |
| // Gd stack API requires opcode specification and calculates length, so |
| // no need to provide opcode or length here. |
| data += (kCommandOpcodeSize + kCommandLengthSize); |
| len -= (kCommandOpcodeSize + kCommandLengthSize); |
| |
| auto op_code = static_cast<const bluetooth::hci::OpCode>(command_op_code); |
| |
| auto payload = MakeUniquePacket(data, len); |
| auto packet = |
| bluetooth::hci::CommandBuilder::Create(op_code, std::move(payload)); |
| |
| LOG_DEBUG("Sending command %s", bluetooth::hci::OpCodeText(op_code).c_str()); |
| |
| if (bluetooth::hci::Checker::IsCommandStatusOpcode(op_code)) { |
| auto command_unique = std::make_unique<OsiObject>(command); |
| bluetooth::shim::GetHciLayer()->EnqueueCommand( |
| std::move(packet), bluetooth::shim::GetGdShimHandler()->BindOnce( |
| OnTransmitPacketStatus, status_callback, context, |
| std::move(command_unique))); |
| } else { |
| bluetooth::shim::GetHciLayer()->EnqueueCommand( |
| std::move(packet), |
| bluetooth::shim::GetGdShimHandler()->BindOnce( |
| OnTransmitPacketCommandComplete, complete_callback, context)); |
| osi_free(command); |
| } |
| } |
| |
| static void transmit_fragment(const uint8_t* stream, size_t length) { |
| uint16_t handle_with_flags; |
| STREAM_TO_UINT16(handle_with_flags, stream); |
| auto pb_flag = static_cast<bluetooth::hci::PacketBoundaryFlag>( |
| handle_with_flags >> 12 & 0b11); |
| auto bc_flag = |
| static_cast<bluetooth::hci::BroadcastFlag>(handle_with_flags >> 14); |
| uint16_t handle = handle_with_flags & 0xEFF; |
| length -= 2; |
| // skip data total length |
| stream += 2; |
| length -= 2; |
| auto payload = MakeUniquePacket(stream, length); |
| auto acl_packet = bluetooth::hci::AclBuilder::Create(handle, pb_flag, bc_flag, |
| std::move(payload)); |
| pending_data->Enqueue(std::move(acl_packet), |
| bluetooth::shim::GetGdShimHandler()); |
| } |
| |
| static void register_event(bluetooth::hci::EventCode event_code) { |
| auto handler = bluetooth::shim::GetGdShimHandler(); |
| bluetooth::shim::GetHciLayer()->RegisterEventHandler( |
| event_code, handler->Bind(event_callback)); |
| } |
| |
| static void register_le_event(bluetooth::hci::SubeventCode subevent_code) { |
| auto handler = bluetooth::shim::GetGdShimHandler(); |
| bluetooth::shim::GetHciLayer()->RegisterLeEventHandler( |
| subevent_code, handler->Bind(subevent_callback)); |
| } |
| |
| static void acl_data_callback() { |
| if (hci_queue_end == nullptr) { |
| return; |
| } |
| auto packet = hci_queue_end->TryDequeue(); |
| ASSERT(packet != nullptr); |
| if (!packet->IsValid()) { |
| LOG_INFO("Dropping invalid packet of size %zu", packet->size()); |
| return; |
| } |
| if (!send_data_upwards) { |
| return; |
| } |
| auto data = WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_ACL, packet.get()); |
| packet_fragmenter->reassemble_and_dispatch(data); |
| } |
| |
| static void register_for_acl() { |
| hci_queue_end = bluetooth::shim::GetHciLayer()->GetAclQueueEnd(); |
| |
| // if gd advertising/scanning enabled, hci_queue_end will be register in |
| // AclManager::impl::Start |
| if (!bluetooth::shim::is_gd_advertising_enabled() && |
| !bluetooth::shim::is_gd_scanning_enabled() && |
| !bluetooth::shim::is_gd_l2cap_enabled()) { |
| hci_queue_end->RegisterDequeue(bluetooth::shim::GetGdShimHandler(), |
| bluetooth::common::Bind(acl_data_callback)); |
| } |
| |
| pending_data = new bluetooth::os::EnqueueBuffer<bluetooth::hci::AclBuilder>( |
| hci_queue_end); |
| } |
| |
| static void on_shutting_down() { |
| if (pending_data != nullptr) { |
| pending_data->Clear(); |
| delete pending_data; |
| pending_data = nullptr; |
| } |
| if (hci_queue_end != nullptr) { |
| if (!bluetooth::shim::is_gd_advertising_enabled() && |
| !bluetooth::shim::is_gd_l2cap_enabled()) { |
| hci_queue_end->UnregisterDequeue(); |
| } |
| for (uint16_t event_code_raw = 0; event_code_raw < 0x100; |
| event_code_raw++) { |
| auto event_code = static_cast<bluetooth::hci::EventCode>(event_code_raw); |
| if (!is_valid_event_code(event_code)) { |
| continue; |
| } |
| if (event_already_registered_in_hci_layer(event_code)) { |
| continue; |
| } else if (event_already_registered_in_le_advertising_manager( |
| event_code)) { |
| continue; |
| } else if (event_already_registered_in_le_scanning_manager(event_code)) { |
| continue; |
| } |
| bluetooth::shim::GetHciLayer()->UnregisterEventHandler(event_code); |
| } |
| hci_queue_end = nullptr; |
| } |
| } |
| |
| } // namespace cpp |
| |
| using bluetooth::common::Bind; |
| using bluetooth::common::BindOnce; |
| using bluetooth::common::Unretained; |
| |
| namespace rust { |
| |
| using bluetooth::shim::rust::u8SliceCallback; |
| using bluetooth::shim::rust::u8SliceOnceCallback; |
| |
| static BT_HDR* WrapRustPacketAndCopy(uint16_t event, |
| ::rust::Slice<const uint8_t>* data) { |
| size_t packet_size = data->length() + kBtHdrSize; |
| BT_HDR* packet = reinterpret_cast<BT_HDR*>(osi_malloc(packet_size)); |
| packet->offset = 0; |
| packet->len = data->length(); |
| packet->layer_specific = 0; |
| packet->event = event; |
| std::copy(data->data(), data->data() + data->length(), packet->data); |
| return packet; |
| } |
| |
| static void on_acl(::rust::Slice<const uint8_t> data) { |
| if (!send_data_upwards) { |
| return; |
| } |
| auto legacy_data = WrapRustPacketAndCopy(MSG_HC_TO_STACK_HCI_ACL, &data); |
| packet_fragmenter->reassemble_and_dispatch(legacy_data); |
| } |
| |
| static void on_event(::rust::Slice<const uint8_t> data) { |
| if (!send_data_upwards) { |
| return; |
| } |
| send_data_upwards.Run(FROM_HERE, |
| WrapRustPacketAndCopy(MSG_HC_TO_STACK_HCI_EVT, &data)); |
| } |
| |
| void OnRustTransmitPacketCommandComplete(command_complete_cb complete_callback, |
| void* context, |
| ::rust::Slice<const uint8_t> data) { |
| BT_HDR* response = WrapRustPacketAndCopy(MSG_HC_TO_STACK_HCI_EVT, &data); |
| complete_callback(response, context); |
| } |
| |
| void OnRustTransmitPacketStatus(command_status_cb status_callback, |
| void* context, |
| std::unique_ptr<OsiObject> command, |
| ::rust::Slice<const uint8_t> data) { |
| ASSERT(data.length() >= 3); |
| uint8_t status = data.data()[2]; |
| status_callback(status, static_cast<BT_HDR*>(command->Release()), context); |
| } |
| |
| static void transmit_command(BT_HDR* command, |
| command_complete_cb complete_callback, |
| command_status_cb status_callback, void* context) { |
| CHECK(command != nullptr); |
| const uint8_t* data = command->data + command->offset; |
| size_t len = command->len; |
| CHECK(len >= (kCommandOpcodeSize + kCommandLengthSize)); |
| |
| // little endian command opcode |
| uint16_t command_op_code = (data[1] << 8 | data[0]); |
| auto op_code = static_cast<const bluetooth::hci::OpCode>(command_op_code); |
| |
| LOG_DEBUG("Sending command %s", bluetooth::hci::OpCodeText(op_code).c_str()); |
| |
| if (bluetooth::hci::Checker::IsCommandStatusOpcode(op_code)) { |
| auto command_unique = std::make_unique<OsiObject>(command); |
| bluetooth::shim::rust::hci_send_command( |
| **bluetooth::shim::Stack::Stack::GetInstance()->GetRustHci(), |
| ::rust::Slice(data, len), |
| std::make_unique<u8SliceOnceCallback>( |
| BindOnce(OnRustTransmitPacketStatus, status_callback, context, |
| std::move(command_unique)))); |
| } else { |
| bluetooth::shim::rust::hci_send_command( |
| **bluetooth::shim::Stack::Stack::GetInstance()->GetRustHci(), |
| ::rust::Slice(data, len), |
| std::make_unique<u8SliceOnceCallback>(BindOnce( |
| OnRustTransmitPacketCommandComplete, complete_callback, context))); |
| osi_free(command); |
| } |
| } |
| |
| static void transmit_fragment(const uint8_t* stream, size_t length) { |
| bluetooth::shim::rust::hci_send_acl( |
| **bluetooth::shim::Stack::Stack::GetInstance()->GetRustHci(), |
| ::rust::Slice(stream, length)); |
| } |
| |
| static void register_event(bluetooth::hci::EventCode event_code) { |
| bluetooth::shim::rust::hci_register_event( |
| **bluetooth::shim::Stack::GetInstance()->GetRustHci(), |
| static_cast<uint8_t>(event_code)); |
| } |
| |
| static void register_le_event(bluetooth::hci::SubeventCode subevent_code) { |
| bluetooth::shim::rust::hci_register_le_event( |
| **bluetooth::shim::Stack::Stack::GetInstance()->GetRustHci(), |
| static_cast<uint8_t>(subevent_code)); |
| } |
| |
| static void hci_on_reset_complete() { |
| bluetooth::shim::rust::hci_set_evt_callback( |
| **bluetooth::shim::Stack::GetInstance()->GetRustHci(), |
| std::make_unique<u8SliceCallback>(Bind(rust::on_event))); |
| bluetooth::shim::rust::hci_set_le_evt_callback( |
| **bluetooth::shim::Stack::GetInstance()->GetRustHci(), |
| std::make_unique<u8SliceCallback>(Bind(rust::on_event))); |
| } |
| |
| static void register_for_acl() { |
| bluetooth::shim::rust::hci_set_acl_callback( |
| **bluetooth::shim::Stack::GetInstance()->GetRustHci(), |
| std::make_unique<u8SliceCallback>(Bind(rust::on_acl))); |
| } |
| |
| static void on_shutting_down() {} |
| |
| } // namespace rust |
| |
| static void set_data_cb( |
| base::Callback<void(const base::Location&, BT_HDR*)> send_data_cb) { |
| send_data_upwards = std::move(send_data_cb); |
| } |
| |
| static void transmit_command(BT_HDR* command, |
| command_complete_cb complete_callback, |
| command_status_cb status_callback, void* context) { |
| if (bluetooth::common::init_flags::gd_rust_is_enabled()) { |
| rust::transmit_command(command, complete_callback, status_callback, |
| context); |
| } else { |
| cpp::transmit_command(command, complete_callback, status_callback, context); |
| } |
| } |
| |
| static void command_complete_callback(BT_HDR* response, void* context) { |
| auto future = static_cast<future_t*>(context); |
| future_ready(future, response); |
| } |
| |
| static void command_status_callback(uint8_t status, BT_HDR* command, |
| void* context) { |
| LOG_ALWAYS_FATAL( |
| "transmit_command_futured should only send command complete opcode"); |
| } |
| |
| static future_t* transmit_command_futured(BT_HDR* command) { |
| future_t* future = future_new(); |
| transmit_command(command, command_complete_callback, command_status_callback, |
| future); |
| return future; |
| } |
| |
| static void transmit_fragment(BT_HDR* packet, bool send_transmit_finished) { |
| // HCI command packets are freed on a different thread when the matching |
| // event is received. Check packet->event before sending to avoid a race. |
| bool free_after_transmit = |
| (packet->event & MSG_EVT_MASK) != MSG_STACK_TO_HC_HCI_CMD && |
| send_transmit_finished; |
| |
| const uint8_t* stream = packet->data + packet->offset; |
| size_t length = packet->len; |
| if (bluetooth::common::init_flags::gd_rust_is_enabled()) { |
| rust::transmit_fragment(stream, length); |
| } else { |
| cpp::transmit_fragment(stream, length); |
| } |
| if (free_after_transmit) { |
| osi_free(packet); |
| } |
| } |
| static void dispatch_reassembled(BT_HDR* packet) { |
| // Events should already have been dispatched before this point |
| CHECK((packet->event & MSG_EVT_MASK) != MSG_HC_TO_STACK_HCI_EVT); |
| CHECK(!send_data_upwards.is_null()); |
| send_data_upwards.Run(FROM_HERE, packet); |
| } |
| static void fragmenter_transmit_finished(BT_HDR* packet, |
| bool all_fragments_sent) { |
| if (all_fragments_sent) { |
| osi_free(packet); |
| } else { |
| // This is kind of a weird case, since we're dispatching a partially sent |
| // packet up to a higher layer. |
| // TODO(zachoverflow): rework upper layer so this isn't necessary. |
| send_data_upwards.Run(FROM_HERE, packet); |
| } |
| } |
| |
| static const packet_fragmenter_callbacks_t packet_fragmenter_callbacks = { |
| transmit_fragment, dispatch_reassembled, fragmenter_transmit_finished}; |
| |
| static void transmit_downward(uint16_t type, void* raw_data) { |
| if (bluetooth::common::init_flags::gd_rust_is_enabled()) { |
| packet_fragmenter->fragment_and_dispatch(static_cast<BT_HDR*>(raw_data)); |
| } else { |
| bluetooth::shim::GetGdShimHandler()->Call( |
| packet_fragmenter->fragment_and_dispatch, |
| static_cast<BT_HDR*>(raw_data)); |
| } |
| } |
| |
| static hci_t interface = {.set_data_cb = set_data_cb, |
| .transmit_command = transmit_command, |
| .transmit_command_futured = transmit_command_futured, |
| .transmit_downward = transmit_downward}; |
| |
| const hci_t* bluetooth::shim::hci_layer_get_interface() { |
| packet_fragmenter = packet_fragmenter_get_interface(); |
| packet_fragmenter->init(&packet_fragmenter_callbacks); |
| return &interface; |
| } |
| |
| void bluetooth::shim::hci_on_reset_complete() { |
| ASSERT(send_data_upwards); |
| if (bluetooth::common::init_flags::gd_rust_is_enabled()) { |
| ::rust::hci_on_reset_complete(); |
| } |
| |
| for (uint16_t event_code_raw = 0; event_code_raw < 0x100; event_code_raw++) { |
| auto event_code = static_cast<bluetooth::hci::EventCode>(event_code_raw); |
| if (!is_valid_event_code(event_code)) { |
| continue; |
| } |
| if (event_already_registered_in_acl_layer(event_code)) { |
| continue; |
| } else if (event_already_registered_in_controller_layer(event_code)) { |
| continue; |
| } else if (event_already_registered_in_hci_layer(event_code)) { |
| continue; |
| } else if (event_already_registered_in_le_advertising_manager(event_code)) { |
| continue; |
| } else if (event_already_registered_in_le_scanning_manager(event_code)) { |
| continue; |
| } |
| |
| if (bluetooth::common::init_flags::gd_rust_is_enabled()) { |
| ::rust::register_event(event_code); |
| } else { |
| cpp::register_event(event_code); |
| } |
| } |
| |
| for (uint16_t subevent_code_raw = 0; subevent_code_raw < 0x100; |
| subevent_code_raw++) { |
| auto subevent_code = |
| static_cast<bluetooth::hci::SubeventCode>(subevent_code_raw); |
| if (!is_valid_subevent_code(subevent_code)) { |
| continue; |
| } |
| if (subevent_already_registered_in_le_hci_layer(subevent_code)) { |
| continue; |
| } |
| |
| if (bluetooth::common::init_flags::gd_rust_is_enabled()) { |
| ::rust::register_le_event(subevent_code); |
| } else { |
| cpp::register_le_event(subevent_code); |
| } |
| } |
| |
| // TODO handle BQR event in GD |
| auto handler = bluetooth::shim::GetGdShimHandler(); |
| bluetooth::shim::GetVendorSpecificEventManager()->RegisterEventHandler( |
| bluetooth::hci::VseSubeventCode::BQR_EVENT, |
| handler->Bind(cpp::vendor_specific_event_callback)); |
| |
| if (bluetooth::shim::is_gd_acl_enabled()) { |
| return; |
| } |
| |
| if (bluetooth::common::init_flags::gd_rust_is_enabled()) { |
| ::rust::register_for_acl(); |
| } else { |
| cpp::register_for_acl(); |
| } |
| } |
| |
| void bluetooth::shim::hci_on_shutting_down() { |
| if (bluetooth::common::init_flags::gd_rust_is_enabled()) { |
| ::rust::on_shutting_down(); |
| } else { |
| cpp::on_shutting_down(); |
| } |
| } |