/* * 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_l2cap" #include #include #include #include "bta/include/bta_dm_acl.h" #include "gd/l2cap/classic/l2cap_classic_module.h" #include "gd/l2cap/le/l2cap_le_module.h" #include "gd/os/log.h" #include "gd/os/queue.h" #include "main/shim/acl_api.h" #include "main/shim/btm.h" #include "main/shim/entry.h" #include "main/shim/helpers.h" #include "main/shim/l2c_api.h" #include "main/shim/stack.h" #include "osi/include/allocator.h" #include "stack/btm/btm_ble_int.h" #include "stack/btm/btm_sec.h" #include "stack/include/acl_hci_link_interface.h" #include "stack/include/ble_acl_interface.h" #include "stack/include/btm_api.h" #include "stack/include/btu.h" #include "stack/include/gatt_api.h" #include "stack/include/sco_hci_link_interface.h" extern void gatt_notify_conn_update(const RawAddress& remote, uint16_t interval, uint16_t latency, uint16_t timeout, tHCI_STATUS status); extern void gatt_notify_phy_updated(tGATT_STATUS status, uint16_t handle, uint8_t tx_phy, uint8_t rx_phy); void process_ssr_event(tHCI_STATUS status, uint16_t handle, uint16_t max_tx_lat, uint16_t max_rx_lat); namespace bluetooth { namespace shim { using bluetooth::hci::AddressWithType; using namespace bluetooth::l2cap; // Classic Dynamic Channel Shim Helper namespace { uint16_t classic_cid_token_counter_ = 0x41; constexpr uint64_t kBrEdrNotSupportedMask = 0x0000002000000000; // Bit 37 constexpr uint64_t kLeSupportedControllerMask = 0x0000004000000000; // Bit 38 constexpr uint64_t kLeSupportedHostMask = 0x0000000000000002; // Bit 1 std::unordered_map classic_cid_token_to_channel_map_; uint16_t add_classic_cid_token_entry(uint16_t psm) { uint16_t new_token = classic_cid_token_counter_; classic_cid_token_to_channel_map_[new_token] = psm; classic_cid_token_counter_++; if (classic_cid_token_counter_ == 0) classic_cid_token_counter_ = 0x41; return new_token; } void remove_classic_cid_token_entry(uint16_t cid_token) { classic_cid_token_to_channel_map_.erase(cid_token); } void remove_classic_dynamic_channel_helper(uint16_t psm); struct ClassicDynamicChannelHelper { ClassicDynamicChannelHelper(uint16_t psm, tL2CAP_APPL_INFO appl_info, classic::DynamicChannelConfigurationOption config, classic::SecurityPolicy policy) : psm_(psm), appl_info_(appl_info), config_(config), policy_(policy) {} uint16_t psm_; tL2CAP_APPL_INFO appl_info_; classic::DynamicChannelConfigurationOption config_; classic::SecurityPolicy policy_; void Register() { GetL2capClassicModule()->GetDynamicChannelManager()->RegisterService( psm_, config_, policy_, GetGdShimHandler()->BindOnceOn( this, &ClassicDynamicChannelHelper::on_registration_complete), GetGdShimHandler()->BindOn( this, &ClassicDynamicChannelHelper::on_channel_open, 0)); } void on_registration_complete( classic::DynamicChannelManager::RegistrationResult result, std::unique_ptr service) { if (result != classic::DynamicChannelManager::RegistrationResult::SUCCESS) { LOG(ERROR) << "Channel is not registered. psm=" << +psm_ << (int)result; return; } channel_service_ = std::move(service); } std::unique_ptr channel_service_ = nullptr; void Connect(uint16_t cid_token, bluetooth::hci::AddressWithType device) { if (channel_service_ == nullptr) { return; } initiated_by_us_[cid_token] = true; GetL2capClassicModule()->GetDynamicChannelManager()->ConnectChannel( device.GetAddress(), config_, psm_, GetGdShimHandler()->BindOn( this, &ClassicDynamicChannelHelper::on_channel_open, cid_token), GetGdShimHandler()->BindOnceOn( this, &ClassicDynamicChannelHelper::on_outgoing_connection_fail)); } void Disconnect(uint16_t cid_token) { if (channel_service_ == nullptr) { return; } if (channels_.count(cid_token) == 0) { return; } channels_[cid_token]->Close(); } void Unregister() { if (channel_service_ != nullptr) { channel_service_->Unregister(GetGdShimHandler()->BindOnceOn( this, &ClassicDynamicChannelHelper::on_unregistered)); channel_service_ = nullptr; } } void on_unregistered() { for (const auto& device : channels_) { device.second->Close(); } remove_classic_dynamic_channel_helper(psm_); } void on_channel_close(uint16_t cid_token, bluetooth::hci::ErrorCode error_code) { channel_enqueue_buffer_[cid_token] = nullptr; channel_enqueue_buffer_.erase(cid_token); channels_[cid_token]->GetQueueUpEnd()->UnregisterDequeue(); channels_.erase(cid_token); do_in_main_thread(FROM_HERE, base::Bind(appl_info_.pL2CA_DisconnectInd_Cb, cid_token, false)); remove_classic_cid_token_entry(cid_token); initiated_by_us_.erase(cid_token); if (channel_service_ == nullptr && channels_.empty()) { // Try again L2CA_Deregister(psm_); } } void on_channel_open(uint16_t cid_token, std::unique_ptr channel) { auto device = channel->GetDevice(); auto address = bluetooth::ToRawAddress(device.GetAddress()); bool initiator_local = (cid_token != 0); if (cid_token == 0) { cid_token = add_classic_cid_token_entry(psm_); } channel->RegisterOnCloseCallback(GetGdShimHandler()->BindOnceOn( this, &ClassicDynamicChannelHelper::on_channel_close, cid_token)); channel_enqueue_buffer_[cid_token] = std::make_unique< bluetooth::os::EnqueueBuffer>( channel->GetQueueUpEnd()); if (initiator_local) { do_in_main_thread( FROM_HERE, base::Bind(appl_info_.pL2CA_ConnectCfm_Cb, cid_token, 0)); tL2CAP_CFG_INFO cfg_info{}; do_in_main_thread(FROM_HERE, base::Bind(appl_info_.pL2CA_ConfigCfm_Cb, cid_token, L2CAP_INITIATOR_LOCAL, base::Unretained(&cfg_info))); } else { if (appl_info_.pL2CA_ConnectInd_Cb == nullptr) { Disconnect(cid_token); return; } do_in_main_thread(FROM_HERE, base::Bind(appl_info_.pL2CA_ConnectInd_Cb, address, cid_token, psm_, 0)); tL2CAP_CFG_INFO cfg_info{}; do_in_main_thread(FROM_HERE, base::Bind(appl_info_.pL2CA_ConfigCfm_Cb, cid_token, L2CAP_INITIATOR_LOCAL, base::Unretained(&cfg_info))); } channel->GetQueueUpEnd()->RegisterDequeue( GetGdShimHandler(), bluetooth::common::Bind(&ClassicDynamicChannelHelper::on_incoming_data, bluetooth::common::Unretained(this), cid_token)); channels_[cid_token] = std::move(channel); } void on_incoming_data(uint16_t cid_token) { auto channel = channels_.find(cid_token); if (channel == channels_.end()) { LOG_ERROR("Channel is not open"); return; } auto packet = channel->second->GetQueueUpEnd()->TryDequeue(); std::vector packet_vector(packet->begin(), packet->end()); BT_HDR* buffer = static_cast(osi_calloc(packet_vector.size() + sizeof(BT_HDR))); std::copy(packet_vector.begin(), packet_vector.end(), buffer->data); buffer->len = packet_vector.size(); if (do_in_main_thread(FROM_HERE, base::Bind(appl_info_.pL2CA_DataInd_Cb, cid_token, base::Unretained(buffer))) != BT_STATUS_SUCCESS) { osi_free(buffer); } } void on_outgoing_connection_fail( classic::DynamicChannelManager::ConnectionResult result) { LOG(ERROR) << "Outgoing connection failed: " << static_cast(result.connection_result_code); } bool send(uint16_t cid, std::unique_ptr packet) { auto buffer = channel_enqueue_buffer_.find(cid); if (buffer == channel_enqueue_buffer_.end() || buffer->second == nullptr) { LOG(ERROR) << "Channel is not open"; return false; } buffer->second->Enqueue(std::move(packet), GetGdShimHandler()); return true; } uint16_t GetRemoteCid(uint16_t cid) { auto channel = channels_.find(cid); if (channel == channels_.end()) { LOG_ERROR("Channel is not open"); return 0; } return channel->second->HACK_GetRemoteCid(); } bool SetChannelTxPriority(uint16_t cid, bool high_priority) { auto channel = channels_.find(cid); if (channel == channels_.end()) { LOG_ERROR("Channel is not open"); return false; } channel->second->HACK_SetChannelTxPriority(high_priority); return true; } void FlushChannel(uint16_t cid) { auto buffer = channel_enqueue_buffer_.find(cid); if (buffer == channel_enqueue_buffer_.end()) { LOG_ERROR("Channel is not open"); return; } buffer->second->Clear(); } uint16_t GetNumBufferedPackets(uint16_t cid) { auto buffer = channel_enqueue_buffer_.find(cid); if (buffer == channel_enqueue_buffer_.end()) { LOG_ERROR("Channel is not open"); return 0; } return buffer->second->Size(); } std::unordered_map> channels_; std::unordered_map>> channel_enqueue_buffer_; std::unordered_map initiated_by_us_; }; std::unordered_map> classic_dynamic_channel_helper_map_; void remove_classic_dynamic_channel_helper(uint16_t psm) { if (classic_dynamic_channel_helper_map_.count(psm) != 0 && classic_dynamic_channel_helper_map_[psm]->channels_.empty()) { classic_dynamic_channel_helper_map_.erase(psm); } } // Helper: L2cap security enforcement shim std::unordered_map> security_enforce_callback_map = {}; class ClassicSecurityEnforcementShim : public bluetooth::l2cap::classic::SecurityEnforcementInterface { public: static void security_enforce_result_callback(const RawAddress* bd_addr, tBT_TRANSPORT trasnport, void* p_ref_data, tBTM_STATUS result) { intptr_t counter = (intptr_t)p_ref_data; if (security_enforce_callback_map.count(counter) == 0) { LOG_ERROR("Received unexpected callback"); return; } auto& callback = security_enforce_callback_map[counter]; std::move(callback).Invoke(result == BTM_SUCCESS); security_enforce_callback_map.erase(counter); } void Enforce(bluetooth::hci::AddressWithType remote, bluetooth::l2cap::classic::SecurityPolicy policy, ResultCallback result_callback) override { uint16_t sec_mask = 0; switch (policy) { case bluetooth::l2cap::classic::SecurityPolicy:: _SDP_ONLY_NO_SECURITY_WHATSOEVER_PLAINTEXT_TRANSPORT_OK: result_callback.Invoke(true); return; case bluetooth::l2cap::classic::SecurityPolicy::ENCRYPTED_TRANSPORT: sec_mask = BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT; break; case bluetooth::l2cap::classic::SecurityPolicy::BEST: case bluetooth::l2cap::classic::SecurityPolicy:: AUTHENTICATED_ENCRYPTED_TRANSPORT: sec_mask = BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT | BTM_SEC_IN_MITM | BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT | BTM_SEC_OUT_MITM; break; } auto bd_addr = bluetooth::ToRawAddress(remote.GetAddress()); security_enforce_callback_map[security_enforce_callback_counter_] = std::move(result_callback); btm_sec_l2cap_access_req_by_requirement( bd_addr, sec_mask, true, security_enforce_result_callback, (void*)security_enforce_callback_counter_); security_enforce_callback_counter_++; } intptr_t security_enforce_callback_counter_ = 100; } security_enforcement_shim_; struct RemoteFeature { uint8_t lmp_version = 0; uint16_t manufacturer_name = 0; uint16_t sub_version = 0; uint8_t raw_remote_features[8]; bool version_info_received = false; bool role_switch_supported = false; bool br_edr_supported = false; bool le_supported_controller = false; bool le_supported_host = false; bool ssp_supported = false; bool sc_supported = false; bool received_page_0 = false; bool received_page_1 = false; }; std::unordered_map remote_feature_map_; struct LinkPropertyListenerShim : public bluetooth::l2cap::classic::LinkPropertyListener { std::unordered_map address_to_handle_; void OnLinkConnected(hci::Address remote, uint16_t handle) override { address_to_handle_[remote] = handle; } void OnLinkDisconnected(hci::Address remote) override { address_to_handle_.erase(remote); } void OnReadRemoteVersionInformation(hci::ErrorCode error_code, hci::Address remote, uint8_t lmp_version, uint16_t manufacturer_name, uint16_t sub_version) override { auto bda = bluetooth::ToRawAddress(remote); auto& entry = remote_feature_map_[bda]; entry.lmp_version = lmp_version; entry.manufacturer_name = manufacturer_name; entry.sub_version = sub_version; entry.version_info_received = true; } void OnReadRemoteExtendedFeatures(hci::Address remote, uint8_t page_number, uint8_t max_page_number, uint64_t features) override { auto bda = bluetooth::ToRawAddress(remote); auto& entry = remote_feature_map_[bda]; if (page_number == 0) { entry.received_page_0 = true; if (features & 0x20) entry.role_switch_supported = true; entry.br_edr_supported = !(features & kBrEdrNotSupportedMask); entry.le_supported_controller = features & kLeSupportedControllerMask; std::memcpy(entry.raw_remote_features, &features, 8); } if (page_number == 1) { entry.received_page_1 = true; if (features & 0x01) entry.ssp_supported = true; entry.le_supported_host = features & kLeSupportedHostMask; } if (entry.received_page_0 && entry.received_page_1) { const bool le_supported = entry.le_supported_controller && entry.le_supported_host; btm_sec_set_peer_sec_caps(address_to_handle_[remote], entry.ssp_supported, false, entry.role_switch_supported, entry.br_edr_supported, le_supported); } } void OnRoleChange(hci::ErrorCode error_code, hci::Address remote, hci::Role role) override { btm_rejectlist_role_change_device(ToRawAddress(remote), ToLegacyHciErrorCode(error_code)); btm_acl_role_changed(ToLegacyHciErrorCode(error_code), ToRawAddress(remote), ToLegacyRole(role)); } void OnReadClockOffset(hci::Address remote, uint16_t clock_offset) override { btm_sec_update_clock_offset(address_to_handle_[remote], clock_offset); } void OnModeChange(hci::ErrorCode error_code, hci::Address remote, hci::Mode mode, uint16_t interval) override { btm_sco_chk_pend_unpark(ToLegacyHciErrorCode(error_code), address_to_handle_[remote]); btm_pm_proc_mode_change(ToLegacyHciErrorCode(error_code), address_to_handle_[remote], ToLegacyHciMode(mode), interval); } void OnSniffSubrating(hci::ErrorCode error_code, hci::Address remote, uint16_t max_tx_lat, uint16_t max_rx_lat, uint16_t min_remote_timeout, uint16_t min_local_timeout) override { process_ssr_event(ToLegacyHciErrorCode(error_code), address_to_handle_[remote], max_tx_lat, max_rx_lat); } } link_property_listener_shim_; class SecurityListenerShim : public bluetooth::l2cap::classic::LinkSecurityInterfaceListener { public: void OnLinkConnected( std::unique_ptr interface) override { auto bda = bluetooth::ToRawAddress(interface->GetRemoteAddress()); uint16_t handle = interface->GetAclHandle(); address_to_handle_[bda] = handle; btm_sec_connected(bda, handle, HCI_SUCCESS, 0); BTM_PM_OnConnected(handle, bda); BTA_dm_acl_up(bda, BT_TRANSPORT_BR_EDR); address_to_interface_[bda] = std::move(interface); } void OnAuthenticationComplete(hci::ErrorCode hci_status, bluetooth::hci::Address remote) override { // Note: if gd security is not enabled, we should use btu_hcif.cc path auto bda = bluetooth::ToRawAddress(remote); uint16_t handle = address_to_handle_[bda]; btm_sec_auth_complete(handle, ToLegacyHciErrorCode(hci_status)); } void OnLinkDisconnected(bluetooth::hci::Address remote) override { auto bda = bluetooth::ToRawAddress(remote); uint16_t handle = address_to_handle_[bda]; address_to_handle_.erase(bda); address_to_interface_.erase(bda); btm_sec_disconnected(handle, HCI_ERR_PEER_USER); BTA_dm_acl_down(bda, BT_TRANSPORT_BR_EDR); BTM_PM_OnDisconnected(handle); } void OnEncryptionChange(bluetooth::hci::Address remote, bool encrypted) override { // Note: if gd security is not enabled, we should use btu_hcif.cc path auto bda = bluetooth::ToRawAddress(remote); uint16_t handle = address_to_handle_[bda]; btm_sec_encrypt_change(handle, HCI_SUCCESS, encrypted); } void UpdateLinkHoldForSecurity(RawAddress remote, bool is_bonding) { if (address_to_interface_.count(remote) == 0) { return; } if (is_bonding) { address_to_interface_[remote]->Hold(); } else { address_to_interface_[remote]->Release(); } } bool IsRoleCentral(RawAddress remote) { if (address_to_interface_.count(remote) == 0) { return false; } return address_to_interface_[remote]->GetRole() == bluetooth::hci::Role::CENTRAL; } void Disconnect(RawAddress remote) { if (address_to_interface_.count(remote) == 0) { return; } return address_to_interface_[remote]->Disconnect(); } uint16_t GetNumAclLinks() { return address_to_handle_.size(); } bool IsLinkUp(RawAddress remote) { return address_to_interface_.count(remote) != 0; } std::unordered_map address_to_handle_; std::unordered_map< RawAddress, std::unique_ptr> address_to_interface_; } security_listener_shim_; bluetooth::l2cap::classic::SecurityInterface* security_interface_ = nullptr; struct LeLinkPropertyListenerShim : public bluetooth::l2cap::le::LinkPropertyListener { struct ConnectionInfo { uint16_t handle; hci::Role role; AddressWithType address_with_type; }; std::unordered_map info_; void OnLinkConnected(AddressWithType remote, uint16_t handle, hci::Role role) override { info_[remote.GetAddress()] = {handle, role, remote}; btm_ble_connected(ToRawAddress(remote.GetAddress()), handle, HCI_ENCRYPT_MODE_DISABLED, static_cast(role), static_cast(remote.GetAddressType()), false); } void OnLinkDisconnected(hci::AddressWithType remote) override { info_.erase(remote.GetAddress()); } void OnReadRemoteVersionInformation(hci::ErrorCode hci_status, hci::AddressWithType remote, uint8_t lmp_version, uint16_t manufacturer_name, uint16_t sub_version) override { auto bda = bluetooth::ToRawAddress(remote.GetAddress()); auto& entry = remote_feature_map_[bda]; entry.lmp_version = lmp_version; entry.manufacturer_name = manufacturer_name; entry.sub_version = sub_version; entry.version_info_received = true; } void OnConnectionUpdate(hci::AddressWithType remote, uint16_t connection_interval, uint16_t connection_latency, uint16_t supervision_timeout) override { acl_ble_update_event_received( HCI_SUCCESS, info_[remote.GetAddress()].handle, connection_interval, connection_latency, supervision_timeout); } void OnPhyUpdate(hci::AddressWithType remote, uint8_t tx_phy, uint8_t rx_phy) override { gatt_notify_phy_updated(GATT_SUCCESS, info_[remote.GetAddress()].handle, tx_phy, rx_phy); } void OnDataLengthChange(hci::AddressWithType remote, uint16_t tx_octets, uint16_t tx_time, uint16_t rx_octets, uint16_t rx_time) override { // Used by L2cap internal only. } } le_link_property_listener_shim_; std::unordered_map> le_security_enforce_callback_map = {}; class LeSecurityEnforcementShim : public bluetooth::l2cap::le::SecurityEnforcementInterface { public: static void le_security_enforce_result_callback(const RawAddress* bd_addr, tBT_TRANSPORT trasnport, void* p_ref_data, tBTM_STATUS result) { intptr_t counter = (intptr_t)p_ref_data; if (le_security_enforce_callback_map.count(counter) == 0) { LOG_ERROR("Received unexpected callback"); return; } auto& callback = le_security_enforce_callback_map[counter]; std::move(callback).Invoke(result == BTM_SUCCESS); le_security_enforce_callback_map.erase(counter); } void Enforce(bluetooth::hci::AddressWithType remote, bluetooth::l2cap::le::SecurityPolicy policy, ResultCallback result_callback) override { tBTM_BLE_SEC_ACT sec_act = BTM_BLE_SEC_NONE; switch (policy) { case bluetooth::l2cap::le::SecurityPolicy:: NO_SECURITY_WHATSOEVER_PLAINTEXT_TRANSPORT_OK: result_callback.Invoke(true); return; case bluetooth::l2cap::le::SecurityPolicy::ENCRYPTED_TRANSPORT: sec_act = BTM_BLE_SEC_ENCRYPT; break; case bluetooth::l2cap::le::SecurityPolicy::BEST: case bluetooth::l2cap::le::SecurityPolicy:: AUTHENTICATED_ENCRYPTED_TRANSPORT: sec_act = BTM_BLE_SEC_ENCRYPT_MITM; break; default: result_callback.Invoke(false); } auto bd_addr = bluetooth::ToRawAddress(remote.GetAddress()); le_security_enforce_callback_map[security_enforce_callback_counter_] = std::move(result_callback); BTM_SetEncryption(bd_addr, BT_TRANSPORT_LE, le_security_enforce_result_callback, (void*)security_enforce_callback_counter_, sec_act); security_enforce_callback_counter_++; } intptr_t security_enforce_callback_counter_ = 100; } le_security_enforcement_shim_; } // namespace bool L2CA_ReadRemoteVersion(const RawAddress& addr, uint8_t* lmp_version, uint16_t* manufacturer, uint16_t* lmp_sub_version) { auto& entry = remote_feature_map_[addr]; if (!entry.version_info_received) { return false; } if (lmp_version != nullptr) *lmp_version = entry.lmp_version; if (manufacturer != nullptr) *manufacturer = entry.manufacturer_name; if (lmp_sub_version != nullptr) *lmp_sub_version = entry.sub_version; return true; } uint8_t* L2CA_ReadRemoteFeatures(const RawAddress& addr) { auto& entry = remote_feature_map_[addr]; if (!entry.received_page_0) { return nullptr; } return entry.raw_remote_features; } static void on_sco_disconnect(uint16_t handle, uint8_t reason) { GetGdShimHandler()->Post(base::BindOnce(base::IgnoreResult(&btm_sco_removed), handle, static_cast(reason))); } void L2CA_UseLegacySecurityModule() { LOG_INFO("GD L2cap is using legacy security module"); GetL2capClassicModule()->SetLinkPropertyListener( GetGdShimHandler(), &link_property_listener_shim_); GetL2capClassicModule()->InjectSecurityEnforcementInterface( &security_enforcement_shim_); security_interface_ = GetL2capClassicModule()->GetSecurityInterface( GetGdShimHandler(), &security_listener_shim_); GetL2capLeModule()->SetLinkPropertyListener(GetGdShimHandler(), &le_link_property_listener_shim_); GetL2capLeModule()->InjectSecurityEnforcementInterface( &le_security_enforcement_shim_); GetAclManager()->HACK_SetScoDisconnectCallback(on_sco_disconnect); } /** * Classic Service Registration APIs */ uint16_t L2CA_Register(uint16_t client_psm, const tL2CAP_APPL_INFO& callbacks, bool enable_snoop, tL2CAP_ERTM_INFO* p_ertm_info, uint16_t my_mtu, uint16_t required_remote_mtu, uint16_t sec_level) { if (classic_dynamic_channel_helper_map_.count(client_psm) != 0) { LOG(ERROR) << __func__ << "Already registered psm: " << client_psm; return 0; } classic::DynamicChannelConfigurationOption config; config.minimal_remote_mtu = std::max(required_remote_mtu, 48); config.incoming_mtu = my_mtu; config.channel_mode = (p_ertm_info != nullptr && p_ertm_info->preferred_mode == L2CAP_FCR_ERTM_MODE ? classic::DynamicChannelConfigurationOption:: RetransmissionAndFlowControlMode::ENHANCED_RETRANSMISSION : classic::DynamicChannelConfigurationOption:: RetransmissionAndFlowControlMode::L2CAP_BASIC); classic::SecurityPolicy policy = (client_psm == 1 ? classic::SecurityPolicy:: _SDP_ONLY_NO_SECURITY_WHATSOEVER_PLAINTEXT_TRANSPORT_OK : classic::SecurityPolicy::ENCRYPTED_TRANSPORT); if (sec_level & (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_OUT_AUTHENTICATE)) { policy = classic::SecurityPolicy::BEST; } classic_dynamic_channel_helper_map_[client_psm] = std::make_unique(client_psm, callbacks, config, policy); classic_dynamic_channel_helper_map_[client_psm]->Register(); return client_psm; } void L2CA_Deregister(uint16_t psm) { if (classic_dynamic_channel_helper_map_.count(psm) == 0) { LOG(ERROR) << __func__ << "Not registered psm: " << psm; return; } classic_dynamic_channel_helper_map_[psm]->Unregister(); } /** * Classic Connection Oriented Channel APIS */ uint16_t L2CA_ConnectReq(uint16_t psm, const RawAddress& raw_address) { if (classic_dynamic_channel_helper_map_.count(psm) == 0) { LOG(ERROR) << __func__ << "Not registered psm: " << psm; return 0; } uint16_t cid_token = add_classic_cid_token_entry(psm); classic_dynamic_channel_helper_map_[psm]->Connect( cid_token, ToAddressWithType(raw_address, BLE_ADDR_PUBLIC)); return cid_token; } bool L2CA_DisconnectReq(uint16_t cid) { auto psm = classic_cid_token_to_channel_map_[cid]; if (classic_dynamic_channel_helper_map_.count(psm) == 0) { LOG(ERROR) << __func__ << "Not registered psm: " << psm; return false; } classic_dynamic_channel_helper_map_[psm]->Disconnect(cid); return true; } uint8_t L2CA_DataWrite(uint16_t cid, BT_HDR* p_data) { if (classic_cid_token_to_channel_map_.count(cid) == 0) { LOG(ERROR) << __func__ << "Invalid cid: " << cid; osi_free(p_data); return 0; } auto psm = classic_cid_token_to_channel_map_[cid]; if (classic_dynamic_channel_helper_map_.count(psm) == 0) { LOG(ERROR) << __func__ << "Not registered psm: " << psm; osi_free(p_data); return 0; } auto len = p_data->len; auto* data = p_data->data + p_data->offset; uint8_t sent_length = classic_dynamic_channel_helper_map_[psm]->send( cid, MakeUniquePacket(data, len, IsPacketFlushable(p_data))) * len; osi_free(p_data); return sent_length; } bool L2CA_ReconfigCreditBasedConnsReq(const RawAddress& bd_addr, std::vector& lcids, tL2CAP_LE_CFG_INFO* p_cfg) { LOG_INFO("UNIMPLEMENTED %s addr: %s cfg:%p", __func__, bd_addr.ToString().c_str(), p_cfg); return false; } std::vector L2CA_ConnectCreditBasedReq(uint16_t psm, const RawAddress& p_bd_addr, tL2CAP_LE_CFG_INFO* p_cfg) { LOG_INFO("UNIMPLEMENTED %s addr:%s", __func__, p_bd_addr.ToString().c_str()); std::vector result; return result; } bool L2CA_ConnectCreditBasedRsp(const RawAddress& bd_addr, uint8_t id, std::vector& accepted_lcids, uint16_t result, tL2CAP_LE_CFG_INFO* p_cfg) { LOG_INFO("UNIMPLEMENTED %s addr:%s", __func__, bd_addr.ToString().c_str()); return false; } /** * Link APIs */ bool L2CA_SetIdleTimeoutByBdAddr(const RawAddress& bd_addr, uint16_t timeout, tBT_TRANSPORT transport) { if (transport == BT_TRANSPORT_BR_EDR) { LOG_INFO("UNIMPLEMENTED %s", __func__); return false; } if (timeout == 0 || timeout == GATT_LINK_IDLE_TIMEOUT_WHEN_NO_APP) { bluetooth::shim::L2CA_RemoveFixedChnl(kLeAttributeCid, bd_addr); return true; } else { LOG_INFO("UNIMPLEMENTED %s", __func__); return false; } } bool L2CA_SetAclPriority(uint16_t handle, bool high_priority) { GetAclManager()->HACK_SetAclTxPriority(handle, high_priority); return true; } bool L2CA_SetAclPriority(const RawAddress& bd_addr, tL2CAP_PRIORITY priority) { uint16_t handle = security_listener_shim_.address_to_handle_[bd_addr]; return L2CA_SetAclPriority(handle, priority == L2CAP_PRIORITY_HIGH); } bool L2CA_GetPeerFeatures(const RawAddress& bd_addr, uint32_t* p_ext_feat, uint8_t* p_chnl_mask) { LOG_INFO("UNIMPLEMENTED %s", __func__); return false; } static constexpr uint16_t kAttCid = 4; struct LeFixedChannelHelper { LeFixedChannelHelper(uint16_t cid) : cid_(cid) {} uint16_t cid_; void on_registration_complete( le::FixedChannelManager::RegistrationResult result, std::unique_ptr service) { if (result != le::FixedChannelManager::RegistrationResult::SUCCESS) { LOG(ERROR) << "Channel is not registered. cid=" << +cid_; return; } channel_service_ = std::move(service); } std::unique_ptr channel_service_ = nullptr; void on_channel_close(bluetooth::hci::Address device, bluetooth::hci::ErrorCode error_code) { auto address = bluetooth::ToRawAddress(device); channel_enqueue_buffer_[device] = nullptr; channels_[device]->GetQueueUpEnd()->UnregisterDequeue(); channels_[device] = nullptr; conn_parameters_.erase(device); uint8_t error = static_cast(error_code); (freg_.pL2CA_FixedConn_Cb)(cid_, address, false, error, BT_TRANSPORT_LE); } void on_channel_open(std::unique_ptr channel) { auto remote = channel->GetDevice(); auto device = remote.GetAddress(); channel->RegisterOnCloseCallback( GetGdShimHandler(), bluetooth::common::BindOnce( &LeFixedChannelHelper::on_channel_close, bluetooth::common::Unretained(this), device)); if (cid_ == kAttCid) { channel->Acquire(); } channel_enqueue_buffer_[device] = std::make_unique< bluetooth::os::EnqueueBuffer>( channel->GetQueueUpEnd()); channel->GetQueueUpEnd()->RegisterDequeue( GetGdShimHandler(), bluetooth::common::Bind(&LeFixedChannelHelper::on_incoming_data, bluetooth::common::Unretained(this), device)); channels_[device] = std::move(channel); conn_parameters_[device] = {}; auto address = bluetooth::ToRawAddress(device); (freg_.pL2CA_FixedConn_Cb)(cid_, address, true, 0, BT_TRANSPORT_LE); } void on_incoming_data(bluetooth::hci::Address device) { auto channel = channels_.find(device); if (channel == channels_.end()) { LOG_ERROR("Channel is not open"); return; } auto packet = channel->second->GetQueueUpEnd()->TryDequeue(); std::vector packet_vector(packet->begin(), packet->end()); BT_HDR* buffer = static_cast(osi_calloc(packet_vector.size() + sizeof(BT_HDR))); std::copy(packet_vector.begin(), packet_vector.end(), buffer->data); buffer->len = packet_vector.size(); auto address = bluetooth::ToRawAddress(device); freg_.pL2CA_FixedData_Cb(cid_, address, buffer); } void on_outgoing_connection_fail( RawAddress remote, le::FixedChannelManager::ConnectionResult result) { LOG(ERROR) << "Outgoing connection failed"; freg_.pL2CA_FixedConn_Cb(cid_, remote, true, 0, BT_TRANSPORT_LE); } bool send(hci::Address remote, std::unique_ptr packet) { auto buffer = channel_enqueue_buffer_.find(remote); if (buffer == channel_enqueue_buffer_.end() || buffer->second == nullptr) { LOG(ERROR) << "Channel is not open for cid " << cid_; return false; } buffer->second->Enqueue(std::move(packet), GetGdShimHandler()); return true; } std::unordered_map> channels_; std::unordered_map>> channel_enqueue_buffer_; struct ConnectionParameter { // Default values are from GD HCI_ACL le_impl. uint16_t min_int = 0x0018; uint16_t max_int = 0x0028; uint16_t latency = 0x0000; uint16_t timeout = 0x001f4; uint16_t min_ce_len = 0x0000; uint16_t max_ce_len = 0x0000; bool update_allowed = true; }; std::unordered_map conn_parameters_; tL2CAP_FIXED_CHNL_REG freg_; }; static LeFixedChannelHelper att_helper{4}; static LeFixedChannelHelper smp_helper{6}; static std::unordered_map le_fixed_channel_helper_{ {4, att_helper}, {6, smp_helper}, }; /** * Fixed Channel APIs. Note: Classic fixed channel (connectionless and BR SMP) * is not supported */ bool L2CA_RegisterFixedChannel(uint16_t cid, tL2CAP_FIXED_CHNL_REG* p_freg) { if (cid != kAttCid && cid != kSmpCid) { LOG(ERROR) << "Invalid cid: " << cid; return false; } auto* helper = &le_fixed_channel_helper_.find(cid)->second; if (helper == nullptr) { LOG(ERROR) << "Can't register cid " << cid; return false; } GetL2capLeModule()->GetFixedChannelManager()->RegisterService( cid, common::BindOnce(&LeFixedChannelHelper::on_registration_complete, common::Unretained(helper)), common::Bind(&LeFixedChannelHelper::on_channel_open, common::Unretained(helper)), GetGdShimHandler()); helper->freg_ = *p_freg; return true; } bool L2CA_ConnectFixedChnl(uint16_t cid, const RawAddress& rem_bda) { if (cid != kAttCid && cid != kSmpCid) { LOG(ERROR) << "Invalid cid " << cid; return false; } auto* helper = &le_fixed_channel_helper_.find(cid)->second; auto remote = Btm::GetAddressAndType(rem_bda); auto record = le_link_property_listener_shim_.info_.find(ToGdAddress(rem_bda)); if (record != le_link_property_listener_shim_.info_.end()) { remote = record->second.address_with_type; } LOG(ERROR) << __func__ << remote.ToString(); auto manager = GetL2capLeModule()->GetFixedChannelManager(); manager->ConnectServices( remote, common::BindOnce(&LeFixedChannelHelper::on_outgoing_connection_fail, common::Unretained(helper), rem_bda), GetGdShimHandler()); return true; } uint16_t L2CA_SendFixedChnlData(uint16_t cid, const RawAddress& rem_bda, BT_HDR* p_buf) { if (cid != kAttCid && cid != kSmpCid) { LOG(ERROR) << "Invalid cid " << cid; osi_free(p_buf); return L2CAP_DW_FAILED; } auto* helper = &le_fixed_channel_helper_.find(cid)->second; auto len = p_buf->len; auto* data = p_buf->data + p_buf->offset; bool sent = helper->send(ToGdAddress(rem_bda), MakeUniquePacket(data, len, IsPacketFlushable(p_buf))); osi_free(p_buf); return sent ? L2CAP_DW_SUCCESS : L2CAP_DW_FAILED; } bool L2CA_RemoveFixedChnl(uint16_t cid, const RawAddress& rem_bda) { if (cid != kAttCid && cid != kSmpCid) { LOG(ERROR) << "Invalid cid " << cid; return false; } auto* helper = &le_fixed_channel_helper_.find(cid)->second; auto channel = helper->channels_.find(ToGdAddress(rem_bda)); if (channel == helper->channels_.end() || channel->second == nullptr) { LOG(ERROR) << "Channel is not open"; return false; } channel->second->Release(); return true; } uint16_t L2CA_GetLeHandle(const RawAddress& rem_bda) { auto addr = ToGdAddress(rem_bda); if (le_link_property_listener_shim_.info_.count(addr) == 0) { return 0; } return le_link_property_listener_shim_.info_[addr].handle; } void L2CA_LeConnectionUpdate(const RawAddress& rem_bda, uint16_t min_int, uint16_t max_int, uint16_t latency, uint16_t timeout, uint16_t min_ce_len, uint16_t max_ce_len) { auto* helper = &le_fixed_channel_helper_.find(kAttCid)->second; auto channel = helper->channels_.find(ToGdAddress(rem_bda)); if (channel == helper->channels_.end() || channel->second == nullptr) { LOG(ERROR) << "Channel is not open"; return; } auto& parameter = helper->conn_parameters_[ToGdAddress(rem_bda)]; parameter.min_int = min_int; parameter.max_int = max_int; parameter.latency = latency; parameter.timeout = timeout; parameter.min_ce_len = min_ce_len; parameter.max_ce_len = max_ce_len; if (parameter.update_allowed) { channel->second->GetLinkOptions()->UpdateConnectionParameter( min_int, max_int, latency, timeout, min_ce_len, max_ce_len); } // If update not allowed, don't update; instead cache the value, and update // when update is allowed. } bool L2CA_EnableUpdateBleConnParams(const RawAddress& rem_bda, bool enable) { // When enable is false, we disallow remote connection update request, and // we use default parameters temporarily. auto* helper = &le_fixed_channel_helper_.find(kAttCid)->second; auto channel = helper->channels_.find(ToGdAddress(rem_bda)); if (channel == helper->channels_.end() || channel->second == nullptr) { LOG(ERROR) << "Channel is not open"; return false; } auto& parameter = helper->conn_parameters_[ToGdAddress(rem_bda)]; parameter.update_allowed = enable; // TODO(hsz): Notify HCI_ACL LE to allow/disallow remote request. if (parameter.update_allowed) { // Use cached values uint16_t min_int = parameter.min_int; uint16_t max_int = parameter.max_int; uint16_t latency = parameter.latency; uint16_t timeout = parameter.timeout; uint16_t min_ce_len = parameter.min_ce_len; uint16_t max_ce_len = parameter.max_ce_len; channel->second->GetLinkOptions()->UpdateConnectionParameter( min_int, max_int, latency, timeout, min_ce_len, max_ce_len); } else { // Use the value from legacy l2cble_start_conn_update uint16_t min_int = BTM_BLE_CONN_INT_MIN; uint16_t max_int = BTM_BLE_CONN_INT_MIN; L2CA_AdjustConnectionIntervals(&min_int, &max_int, BTM_BLE_CONN_INT_MIN); uint16_t latency = BTM_BLE_CONN_PERIPHERAL_LATENCY_DEF; uint16_t timeout = BTM_BLE_CONN_TIMEOUT_DEF; uint16_t min_ce_len = 0x0000; uint16_t max_ce_len = 0x0000; channel->second->GetLinkOptions()->UpdateConnectionParameter( min_int, max_int, latency, timeout, min_ce_len, max_ce_len); } return true; } /** * Channel hygiene APIs */ bool L2CA_GetRemoteCid(uint16_t lcid, uint16_t* rcid) { auto psm = classic_cid_token_to_channel_map_[lcid]; if (classic_dynamic_channel_helper_map_.count(psm) == 0) { LOG(ERROR) << __func__ << "Not registered psm: " << psm; return false; } *rcid = classic_dynamic_channel_helper_map_[psm]->GetRemoteCid(lcid); return *rcid != 0; } bool L2CA_SetTxPriority(uint16_t cid, tL2CAP_CHNL_PRIORITY priority) { auto psm = classic_cid_token_to_channel_map_[cid]; if (classic_dynamic_channel_helper_map_.count(psm) == 0) { LOG(ERROR) << __func__ << "Not registered psm: " << psm; return false; } bool high_priority = priority == L2CAP_CHNL_PRIORITY_HIGH; return classic_dynamic_channel_helper_map_[psm]->SetChannelTxPriority( cid, high_priority); } bool L2CA_SetLeGattTimeout(const RawAddress& rem_bda, uint16_t idle_tout) { if (idle_tout == 0xffff) { bluetooth::shim::L2CA_ConnectFixedChnl(kLeAttributeCid, rem_bda); } else { bluetooth::shim::L2CA_RemoveFixedChnl(kLeAttributeCid, rem_bda); } return true; } bool L2CA_SetChnlFlushability(uint16_t cid, bool is_flushable) { LOG_INFO("UNIMPLEMENTED %s", __func__); return false; } uint16_t L2CA_FlushChannel(uint16_t lcid, uint16_t num_to_flush) { auto psm = classic_cid_token_to_channel_map_[lcid]; if (classic_dynamic_channel_helper_map_.count(psm) == 0) { LOG(ERROR) << __func__ << "Not registered psm: " << psm; return 0; } if (num_to_flush == L2CAP_FLUSH_CHANS_GET) { return classic_dynamic_channel_helper_map_[psm]->GetNumBufferedPackets( lcid); } else { classic_dynamic_channel_helper_map_[psm]->FlushChannel(lcid); return 1; // Client doesn't care } // TODO: Implement LE part } bool L2CA_IsLinkEstablished(const RawAddress& bd_addr, tBT_TRANSPORT transport) { if (transport == BT_TRANSPORT_BR_EDR) { return security_listener_shim_.IsLinkUp(bd_addr); } else { return bluetooth::shim::L2CA_GetLeHandle(bd_addr) != 0; } } bool L2CA_IsLeLink(uint16_t acl_handle) { for (const auto& entry : le_link_property_listener_shim_.info_) { if (entry.second.handle == acl_handle) return true; } return false; } void L2CA_ReadConnectionAddr(const RawAddress& pseudo_addr, RawAddress& conn_addr, uint8_t* p_addr_type) { auto* helper = &le_fixed_channel_helper_.find(kSmpCid)->second; auto channel = helper->channels_.find(ToGdAddress(pseudo_addr)); if (channel == helper->channels_.end() || channel->second == nullptr) { LOG(ERROR) << "Channel is not open!"; return; } auto local = channel->second->GetLinkOptions()->GetLocalAddress(); conn_addr = ToRawAddress(local.GetAddress()); *p_addr_type = static_cast(local.GetAddressType()); } bool L2CA_ReadRemoteConnectionAddr(const RawAddress& pseudo_addr, RawAddress& conn_addr, uint8_t* p_addr_type) { auto remote = ToGdAddress(pseudo_addr); if (le_link_property_listener_shim_.info_.count(remote) == 0) { LOG(ERROR) << __func__ << ": Unknown address"; return false; } auto info = le_link_property_listener_shim_.info_[remote].address_with_type; conn_addr = ToRawAddress(info.GetAddress()); *p_addr_type = static_cast(info.GetAddressType()); return true; } hci_role_t L2CA_GetBleConnRole(const RawAddress& bd_addr) { auto remote = ToGdAddress(bd_addr); if (le_link_property_listener_shim_.info_.count(remote) == 0) { return HCI_ROLE_UNKNOWN; } return static_cast( le_link_property_listener_shim_.info_[remote].role); } void L2CA_ConnectForSecurity(const RawAddress& bd_addr) { security_interface_->InitiateConnectionForSecurity( bluetooth::ToGdAddress(bd_addr)); } void L2CA_SetBondingState(const RawAddress& bd_addr, bool is_bonding) { security_listener_shim_.UpdateLinkHoldForSecurity(bd_addr, is_bonding); } void L2CA_DisconnectLink(const RawAddress& remote) { security_listener_shim_.Disconnect(remote); } uint16_t L2CA_GetNumLinks() { return security_listener_shim_.GetNumAclLinks(); } // LE COC Shim Helper namespace { uint16_t le_cid_token_counter_ = 0x41; std::unordered_map le_cid_token_to_channel_map_; uint16_t add_le_cid_token_entry(uint16_t psm) { uint16_t new_token = le_cid_token_counter_; le_cid_token_to_channel_map_[new_token] = psm; le_cid_token_counter_++; if (le_cid_token_counter_ == 0) le_cid_token_counter_ = 0x41; return new_token; } void remove_le_cid_token_entry(uint16_t cid_token) { le_cid_token_to_channel_map_.erase(cid_token); } void remove_le_dynamic_channel_helper(uint16_t psm); struct LeDynamicChannelHelper { LeDynamicChannelHelper(uint16_t psm, tL2CAP_APPL_INFO appl_info, le::DynamicChannelConfigurationOption config, le::SecurityPolicy policy) : psm_(psm), appl_info_(appl_info), config_(config), policy_(policy) {} uint16_t psm_; tL2CAP_APPL_INFO appl_info_; le::DynamicChannelConfigurationOption config_; le::SecurityPolicy policy_; void Register() { std::promise promise; auto future = promise.get_future(); GetL2capLeModule()->GetDynamicChannelManager()->RegisterService( psm_, config_, policy_, base::BindOnce(&LeDynamicChannelHelper::on_registration_complete, base::Unretained(this), std::move(promise)), base::Bind(&LeDynamicChannelHelper::on_channel_open, base::Unretained(this), 0), GetGdShimHandler()); future.wait_for(std::chrono::milliseconds(300)); } void on_registration_complete( std::promise promise, le::DynamicChannelManager::RegistrationResult result, std::unique_ptr service) { if (result != le::DynamicChannelManager::RegistrationResult::SUCCESS) { LOG(ERROR) << "Channel is not registered. psm=" << +psm_ << (int)result; promise.set_value(); return; } channel_service_ = std::move(service); promise.set_value(); } std::unique_ptr channel_service_ = nullptr; void Connect(uint16_t cid_token, bluetooth::hci::AddressWithType device) { if (channel_service_ == nullptr) { LOG(ERROR) << __func__ << "Not registered"; return; } initiated_by_us_[cid_token] = true; GetL2capLeModule()->GetDynamicChannelManager()->ConnectChannel( device, config_, psm_, base::Bind(&LeDynamicChannelHelper::on_channel_open, base::Unretained(this), cid_token), base::BindOnce(&LeDynamicChannelHelper::on_outgoing_connection_fail, base::Unretained(this)), GetGdShimHandler()); } void Disconnect(uint16_t cid_token) { if (channel_service_ == nullptr) { return; } if (channels_.count(cid_token) == 0) { return; } channels_[cid_token]->Close(); } void Unregister() { if (channel_service_ != nullptr) { channel_service_->Unregister( base::BindOnce(&LeDynamicChannelHelper::on_unregistered, base::Unretained(this)), GetGdShimHandler()); channel_service_ = nullptr; } } void on_unregistered() { for (const auto& device : channels_) { device.second->Close(); } remove_le_dynamic_channel_helper(psm_); } void on_channel_close(uint16_t cid_token, bluetooth::hci::ErrorCode error_code) { channel_enqueue_buffer_[cid_token] = nullptr; channel_enqueue_buffer_.erase(cid_token); channels_[cid_token]->GetQueueUpEnd()->UnregisterDequeue(); channels_.erase(cid_token); do_in_main_thread(FROM_HERE, base::Bind(appl_info_.pL2CA_DisconnectInd_Cb, cid_token, false)); remove_le_cid_token_entry(cid_token); initiated_by_us_.erase(cid_token); if (channel_service_ == nullptr && channels_.empty()) { // Try again L2CA_Deregister(psm_); } } void on_channel_open(uint16_t cid_token, std::unique_ptr channel) { auto device = channel->GetDevice(); auto address = bluetooth::ToRawAddress(device.GetAddress()); bool initiator_local = (cid_token != 0); if (cid_token == 0) { cid_token = add_le_cid_token_entry(psm_); } channel->RegisterOnCloseCallback(GetGdShimHandler()->BindOnceOn( this, &LeDynamicChannelHelper::on_channel_close, cid_token)); channel->GetQueueUpEnd()->RegisterDequeue( GetGdShimHandler(), bluetooth::common::Bind(&LeDynamicChannelHelper::on_incoming_data, bluetooth::common::Unretained(this), cid_token)); channel_enqueue_buffer_[cid_token] = std::make_unique< bluetooth::os::EnqueueBuffer>( channel->GetQueueUpEnd()); channels_[cid_token] = std::move(channel); if (initiator_local) { do_in_main_thread( FROM_HERE, base::Bind(appl_info_.pL2CA_ConnectCfm_Cb, cid_token, 0)); } else { if (appl_info_.pL2CA_ConnectInd_Cb == nullptr) { Disconnect(cid_token); return; } do_in_main_thread(FROM_HERE, base::Bind(appl_info_.pL2CA_ConnectInd_Cb, address, cid_token, psm_, 0)); } } void on_incoming_data(uint16_t cid_token) { auto channel = channels_.find(cid_token); if (channel == channels_.end()) { LOG_ERROR("Channel is not open"); return; } auto packet = channel->second->GetQueueUpEnd()->TryDequeue(); std::vector packet_vector(packet->begin(), packet->end()); BT_HDR* buffer = static_cast(osi_calloc(packet_vector.size() + sizeof(BT_HDR))); std::copy(packet_vector.begin(), packet_vector.end(), buffer->data); buffer->len = packet_vector.size(); if (do_in_main_thread(FROM_HERE, base::Bind(appl_info_.pL2CA_DataInd_Cb, cid_token, base::Unretained(buffer))) != BT_STATUS_SUCCESS) { osi_free(buffer); } } void on_outgoing_connection_fail( le::DynamicChannelManager::ConnectionResult result) { LOG(ERROR) << "Outgoing connection failed"; } bool send(uint16_t cid, std::unique_ptr packet) { auto buffer = channel_enqueue_buffer_.find(cid); if (buffer == channel_enqueue_buffer_.end() || buffer->second == nullptr) { LOG(ERROR) << "Channel is not open"; return false; } buffer->second->Enqueue(std::move(packet), GetGdShimHandler()); return true; } uint16_t GetMtu(uint16_t cid_token) { if (channels_.count(cid_token) == 0) { return 0; } return static_cast(channels_[cid_token]->GetMtu()); } std::unordered_map> channels_; std::unordered_map>> channel_enqueue_buffer_; std::unordered_map initiated_by_us_; }; std::unordered_map> le_dynamic_channel_helper_map_; void remove_le_dynamic_channel_helper(uint16_t psm) { if (le_dynamic_channel_helper_map_.count(psm) != 0 && le_dynamic_channel_helper_map_[psm]->channels_.empty()) { le_dynamic_channel_helper_map_.erase(psm); } } std::unordered_set assigned_dynamic_le_psm_; uint16_t next_assigned_dynamic_le_psm_ = 0x80; } // namespace /** * Le Connection Oriented Channel APIs */ uint16_t L2CA_AllocateLePSM() { if (le_dynamic_channel_helper_map_.size() > 100) { LOG_ERROR("Why do we need more than 100 dynamic channel PSMs?"); return 0; } while (le_dynamic_channel_helper_map_.count(next_assigned_dynamic_le_psm_)) { next_assigned_dynamic_le_psm_++; if (next_assigned_dynamic_le_psm_ > 0xff) { next_assigned_dynamic_le_psm_ = 0x80; } } assigned_dynamic_le_psm_.emplace(next_assigned_dynamic_le_psm_); return next_assigned_dynamic_le_psm_; } void L2CA_FreeLePSM(uint16_t psm) { assigned_dynamic_le_psm_.erase(psm); } uint16_t L2CA_RegisterLECoc(uint16_t psm, const tL2CAP_APPL_INFO& callbacks, uint16_t sec_level, tL2CAP_LE_CFG_INFO cfg) { if (le_dynamic_channel_helper_map_.count(psm) != 0) { LOG(ERROR) << __func__ << "Already registered psm: " << psm; return 0; } le::DynamicChannelConfigurationOption config; config.mtu = cfg.mtu; le::SecurityPolicy policy = le::SecurityPolicy::NO_SECURITY_WHATSOEVER_PLAINTEXT_TRANSPORT_OK; if (sec_level & (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_OUT_AUTHENTICATE)) { policy = le::SecurityPolicy::AUTHENTICATED_ENCRYPTED_TRANSPORT; } le_dynamic_channel_helper_map_[psm] = std::make_unique(psm, callbacks, config, policy); le_dynamic_channel_helper_map_[psm]->Register(); return psm; } void L2CA_DeregisterLECoc(uint16_t psm) { if (le_dynamic_channel_helper_map_.count(psm) == 0) { LOG(ERROR) << __func__ << "Not registered psm: " << psm; return; } le_dynamic_channel_helper_map_[psm]->Unregister(); } uint16_t L2CA_ConnectLECocReq(uint16_t psm, const RawAddress& p_bd_addr, tL2CAP_LE_CFG_INFO* p_cfg) { if (le_dynamic_channel_helper_map_.count(psm) == 0) { LOG(ERROR) << __func__ << "Not registered psm: " << psm; return 0; } uint16_t cid_token = add_le_cid_token_entry(psm); auto remote = Btm::GetAddressAndType(p_bd_addr); auto record = le_link_property_listener_shim_.info_.find(ToGdAddress(p_bd_addr)); if (record != le_link_property_listener_shim_.info_.end()) { remote = record->second.address_with_type; } le_dynamic_channel_helper_map_[psm]->Connect(cid_token, remote); return cid_token; } bool L2CA_GetPeerLECocConfig(uint16_t cid, tL2CAP_LE_CFG_INFO* peer_cfg) { if (le_cid_token_to_channel_map_.count(cid) == 0) { LOG(ERROR) << __func__ << "Invalid cid: " << cid; return false; } auto psm = le_cid_token_to_channel_map_[cid]; if (le_dynamic_channel_helper_map_.count(psm) == 0) { LOG(ERROR) << __func__ << "Not registered psm: " << psm; return false; } auto mtu = le_dynamic_channel_helper_map_[psm]->GetMtu(cid); peer_cfg->mtu = mtu; return mtu; } bool L2CA_DisconnectLECocReq(uint16_t cid) { if (le_cid_token_to_channel_map_.count(cid) == 0) { LOG(ERROR) << __func__ << "Invalid cid: " << cid; return false; } auto psm = le_cid_token_to_channel_map_[cid]; if (le_dynamic_channel_helper_map_.count(psm) == 0) { LOG(ERROR) << __func__ << "Not registered psm: " << psm; return false; } le_dynamic_channel_helper_map_[psm]->Disconnect(cid); return true; } uint8_t L2CA_LECocDataWrite(uint16_t cid, BT_HDR* p_data) { if (le_cid_token_to_channel_map_.count(cid) == 0) { LOG(ERROR) << __func__ << "Invalid cid: " << cid; osi_free(p_data); return 0; } auto psm = le_cid_token_to_channel_map_[cid]; if (le_dynamic_channel_helper_map_.count(psm) == 0) { LOG(ERROR) << __func__ << "Not registered psm: " << psm; osi_free(p_data); return 0; } auto len = p_data->len; auto* data = p_data->data + p_data->offset; uint8_t sent_length = le_dynamic_channel_helper_map_[psm]->send( cid, MakeUniquePacket(data, len, IsPacketFlushable(p_data))) * len; osi_free(p_data); return sent_length; } void L2CA_SwitchRoleToCentral(const RawAddress& addr) { GetAclManager()->SwitchRole(ToGdAddress(addr), bluetooth::hci::Role::CENTRAL); } } // namespace shim } // namespace bluetooth