| /* |
| * 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 <unordered_map> |
| #include <unordered_set> |
| |
| #include "main/shim/l2c_api.h" |
| #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/stack.h" |
| #include "osi/include/allocator.h" |
| #include "stack/btm/btm_sec.h" |
| #include "stack/include/acl_hci_link_interface.h" |
| #include "stack/include/btm_api.h" |
| #include "stack/include/btu.h" |
| |
| using bluetooth::hci::AddressWithType; |
| using namespace bluetooth::l2cap; |
| |
| // Classic Dynamic Channel Shim Helper |
| |
| uint16_t classic_cid_token_counter_ = 0x41; |
| |
| struct ClassicDynamicChannelInfo { |
| uint16_t psm; |
| }; |
| std::unordered_map<uint16_t, ClassicDynamicChannelInfo> |
| 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); |
| } |
| |
| 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() { |
| bluetooth::shim::GetL2capClassicModule() |
| ->GetDynamicChannelManager() |
| ->RegisterService( |
| psm_, config_, policy_, |
| bluetooth::shim::GetGdShimHandler()->BindOnceOn( |
| this, &ClassicDynamicChannelHelper::on_registration_complete), |
| bluetooth::shim::GetGdShimHandler()->BindOn( |
| this, &ClassicDynamicChannelHelper::on_channel_open, 0)); |
| } |
| |
| void on_registration_complete( |
| classic::DynamicChannelManager::RegistrationResult result, |
| std::unique_ptr<classic::DynamicChannelService> 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<classic::DynamicChannelService> channel_service_ = nullptr; |
| |
| void Connect(uint16_t cid_token, bluetooth::hci::AddressWithType device) { |
| if (channel_service_ == nullptr) { |
| return; |
| } |
| initiated_by_us_[cid_token] = true; |
| bluetooth::shim::GetL2capClassicModule() |
| ->GetDynamicChannelManager() |
| ->ConnectChannel( |
| device.GetAddress(), config_, psm_, |
| bluetooth::shim::GetGdShimHandler()->BindOn( |
| this, &ClassicDynamicChannelHelper::on_channel_open, cid_token), |
| bluetooth::shim::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( |
| bluetooth::shim::GetGdShimHandler()->BindOnceOn( |
| this, &ClassicDynamicChannelHelper::on_unregistered)); |
| channel_service_ = nullptr; |
| } |
| } |
| |
| void on_unregistered() { |
| for (const auto& device : channels_) { |
| device.second->Close(); |
| } |
| } |
| |
| void on_channel_close(uint16_t cid_token, |
| bluetooth::hci::ErrorCode error_code) { |
| channel_enqueue_buffer_[cid_token] = nullptr; |
| 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 |
| bluetooth::shim::L2CA_Deregister(psm_); |
| } |
| } |
| |
| void on_channel_open(uint16_t cid_token, |
| std::unique_ptr<classic::DynamicChannel> 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( |
| bluetooth::shim::GetGdShimHandler()->BindOnceOn( |
| this, &ClassicDynamicChannelHelper::on_channel_close, cid_token)); |
| |
| channel->GetQueueUpEnd()->RegisterDequeue( |
| bluetooth::shim::GetGdShimHandler(), |
| bluetooth::common::Bind(&ClassicDynamicChannelHelper::on_incoming_data, |
| bluetooth::common::Unretained(this), |
| cid_token)); |
| |
| channel_enqueue_buffer_[cid_token] = std::make_unique< |
| bluetooth::os::EnqueueBuffer<bluetooth::packet::BasePacketBuilder>>( |
| 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)); |
| |
| 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))); |
| } |
| } |
| |
| 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<uint8_t> packet_vector(packet->begin(), packet->end()); |
| BT_HDR* buffer = |
| static_cast<BT_HDR*>(osi_calloc(packet_vector.size() + sizeof(BT_HDR))); |
| std::copy(packet_vector.begin(), packet_vector.end(), buffer->data); |
| buffer->len = packet_vector.size(); |
| do_in_main_thread(FROM_HERE, |
| base::Bind(appl_info_.pL2CA_DataInd_Cb, cid_token, |
| base::Unretained(buffer))); |
| } |
| |
| void on_outgoing_connection_fail( |
| classic::DynamicChannelManager::ConnectionResult result) { |
| LOG(ERROR) << "Outgoing connection failed"; |
| } |
| |
| bool send(uint16_t cid, |
| std::unique_ptr<bluetooth::packet::BasePacketBuilder> 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), |
| bluetooth::shim::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(); |
| } |
| |
| std::unordered_map<uint16_t, std::unique_ptr<classic::DynamicChannel>> |
| channels_; |
| std::unordered_map<uint16_t, std::unique_ptr<bluetooth::os::EnqueueBuffer< |
| bluetooth::packet::BasePacketBuilder>>> |
| channel_enqueue_buffer_; |
| std::unordered_map<uint16_t, bool> initiated_by_us_; |
| }; |
| |
| std::unordered_map<uint16_t, std::unique_ptr<ClassicDynamicChannelHelper>> |
| classic_dynamic_channel_helper_map_; |
| |
| // Helper: L2cap security enforcement shim |
| |
| std::unordered_map<intptr_t, |
| bluetooth::common::ContextualOnceCallback<void(bool)>> |
| 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; |
| bool version_info_received = false; |
| bool role_switch_supported = false; |
| bool ssp_supported = false; |
| bool sc_supported = false; |
| }; |
| |
| std::unordered_map<RawAddress, RemoteFeature> remote_feature_map_; |
| |
| class SecurityListenerShim |
| : public bluetooth::l2cap::classic::LinkSecurityInterfaceListener { |
| public: |
| void OnLinkConnected( |
| std::unique_ptr<bluetooth::l2cap::classic::LinkSecurityInterface> |
| 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); |
| BTA_dm_acl_up(bda, BT_TRANSPORT_BR_EDR); |
| address_to_interface_[bda] = std::move(interface); |
| } |
| |
| void OnAuthenticationComplete(bluetooth::hci::Address remote) override { |
| auto bda = bluetooth::ToRawAddress(remote); |
| uint16_t handle = address_to_handle_[bda]; |
| btm_sec_auth_complete(handle, HCI_SUCCESS); |
| } |
| |
| 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); |
| } |
| |
| void OnEncryptionChange(bluetooth::hci::Address remote, |
| bool encrypted) override { |
| auto bda = bluetooth::ToRawAddress(remote); |
| uint16_t handle = address_to_handle_[bda]; |
| btm_sec_encrypt_change(handle, HCI_SUCCESS, encrypted); |
| } |
| |
| void OnReadRemoteVersionInformation(bluetooth::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(bluetooth::hci::Address remote, |
| uint8_t page_number, |
| uint8_t max_page_number, |
| uint64_t features) override { |
| auto bda = bluetooth::ToRawAddress(remote); |
| uint16_t handle = address_to_handle_[bda]; |
| uint8_t* features_array = (uint8_t*)&features; |
| if (page_number == 0) { |
| btm_read_remote_features_complete(handle, features_array); |
| } else { |
| btm_read_remote_ext_features_complete(handle, page_number, |
| max_page_number, features_array); |
| } |
| } |
| |
| 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<RawAddress, uint16_t> address_to_handle_; |
| std::unordered_map< |
| RawAddress, |
| std::unique_ptr<bluetooth::l2cap::classic::LinkSecurityInterface>> |
| address_to_interface_; |
| } security_listener_shim_; |
| |
| bluetooth::l2cap::classic::SecurityInterface* security_interface_ = nullptr; |
| |
| std::unordered_map<intptr_t, |
| bluetooth::common::ContextualOnceCallback<void(bool)>> |
| 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 = 0; |
| 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_; |
| |
| bool bluetooth::shim::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; |
| } |
| *lmp_version = entry.lmp_version; |
| *manufacturer = entry.manufacturer_name; |
| *lmp_sub_version = entry.sub_version; |
| return true; |
| } |
| |
| void bluetooth::shim::L2CA_UseLegacySecurityModule() { |
| LOG_INFO("GD L2cap is using legacy security module"); |
| bluetooth::shim::GetL2capClassicModule()->InjectSecurityEnforcementInterface( |
| &security_enforcement_shim_); |
| security_interface_ = |
| bluetooth::shim::GetL2capClassicModule()->GetSecurityInterface( |
| bluetooth::shim::GetGdShimHandler(), &security_listener_shim_); |
| |
| bluetooth::shim::GetL2capLeModule()->InjectSecurityEnforcementInterface( |
| &le_security_enforcement_shim_); |
| |
| // TODO(b/161543441): read the privacy policy from device-specific |
| // configuration, and IRK from config file. |
| hci::LeAddressManager::AddressPolicy address_policy = |
| hci::LeAddressManager::AddressPolicy::USE_RESOLVABLE_ADDRESS; |
| hci::AddressWithType empty_address_with_type( |
| hci::Address{}, hci::AddressType::RANDOM_DEVICE_ADDRESS); |
| crypto_toolbox::Octet16 rotation_irk = {0x44, 0xfb, 0x4b, 0x8d, 0x6c, 0x58, |
| 0x21, 0x0c, 0xf9, 0x3d, 0xda, 0xf1, |
| 0x64, 0xa3, 0xbb, 0x7f}; |
| /* 7 minutes minimum, 15 minutes maximum for random address refreshing */ |
| auto minimum_rotation_time = std::chrono::minutes(7); |
| auto maximum_rotation_time = std::chrono::minutes(15); |
| |
| GetAclManager()->SetPrivacyPolicyForInitiatorAddress( |
| address_policy, empty_address_with_type, rotation_irk, |
| minimum_rotation_time, maximum_rotation_time); |
| } |
| |
| /** |
| * Classic Service Registration APIs |
| */ |
| uint16_t bluetooth::shim::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<uint16_t>(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<ClassicDynamicChannelHelper>(client_psm, callbacks, |
| config, policy); |
| |
| classic_dynamic_channel_helper_map_[client_psm]->Register(); |
| return client_psm; |
| } |
| |
| void bluetooth::shim::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(); |
| if (classic_dynamic_channel_helper_map_[psm]->channels_.empty()) { |
| classic_dynamic_channel_helper_map_.erase(psm); |
| } |
| } |
| |
| /** |
| * Classic Connection Oriented Channel APIS |
| */ |
| uint16_t bluetooth::shim::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 bluetooth::shim::L2CA_DisconnectReq(uint16_t cid) { |
| auto psm = classic_cid_token_to_channel_map_[cid].psm; |
| 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 bluetooth::shim::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; |
| return 0; |
| } |
| auto psm = classic_cid_token_to_channel_map_[cid].psm; |
| if (classic_dynamic_channel_helper_map_.count(psm) == 0) { |
| LOG(ERROR) << __func__ << "Not registered psm: " << psm; |
| return 0; |
| } |
| auto len = p_data->len; |
| auto* data = p_data->data + p_data->offset; |
| return classic_dynamic_channel_helper_map_[psm]->send( |
| cid, MakeUniquePacket(data, len)) * |
| len; |
| } |
| |
| bool bluetooth::shim::L2CA_ReconfigCreditBasedConnsReq( |
| const RawAddress& bd_addr, std::vector<uint16_t>& 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<uint16_t> bluetooth::shim::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<uint16_t> result; |
| return result; |
| } |
| |
| bool bluetooth::shim::L2CA_ConnectCreditBasedRsp( |
| const RawAddress& bd_addr, uint8_t id, |
| std::vector<uint16_t>& 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 bluetooth::shim::L2CA_SetIdleTimeoutByBdAddr(const RawAddress& bd_addr, |
| uint16_t timeout, |
| tBT_TRANSPORT transport) { |
| LOG_INFO("UNIMPLEMENTED %s", __func__); |
| return false; |
| } |
| |
| bool bluetooth::shim::L2CA_SetAclPriority(const RawAddress& bd_addr, |
| tL2CAP_PRIORITY priority) { |
| LOG_INFO("UNIMPLEMENTED %s", __func__); |
| return false; |
| } |
| |
| bool bluetooth::shim::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<le::FixedChannelService> service) { |
| if (result != le::FixedChannelManager::RegistrationResult::SUCCESS) { |
| LOG(ERROR) << "Channel is not registered. cid=" << +cid_; |
| return; |
| } |
| channel_service_ = std::move(service); |
| } |
| |
| std::unique_ptr<le::FixedChannelService> channel_service_ = nullptr; |
| |
| void on_channel_close(bluetooth::hci::AddressWithType device, |
| bluetooth::hci::ErrorCode error_code) { |
| auto address = bluetooth::ToRawAddress(device.GetAddress()); |
| channel_enqueue_buffer_[device] = nullptr; |
| channels_[device]->GetQueueUpEnd()->UnregisterDequeue(); |
| channels_[device] = nullptr; |
| (freg_.pL2CA_FixedConn_Cb)(cid_, address, true, 0, 2); |
| } |
| |
| void on_channel_open(std::unique_ptr<le::FixedChannel> channel) { |
| auto device = channel->GetDevice(); |
| channel->RegisterOnCloseCallback( |
| bluetooth::shim::GetGdShimHandler(), |
| bluetooth::common::BindOnce(&LeFixedChannelHelper::on_channel_close, |
| bluetooth::common::Unretained(this), |
| device)); |
| channel->Acquire(); |
| channel_enqueue_buffer_[device] = std::make_unique< |
| bluetooth::os::EnqueueBuffer<bluetooth::packet::BasePacketBuilder>>( |
| channel->GetQueueUpEnd()); |
| channel->GetQueueUpEnd()->RegisterDequeue( |
| bluetooth::shim::GetGdShimHandler(), |
| bluetooth::common::Bind(&LeFixedChannelHelper::on_incoming_data, |
| bluetooth::common::Unretained(this), device)); |
| channels_[device] = std::move(channel); |
| |
| auto address = bluetooth::ToRawAddress(device.GetAddress()); |
| |
| (freg_.pL2CA_FixedConn_Cb)(cid_, address, true, 0, BT_TRANSPORT_LE); |
| bluetooth::shim::Btm::StoreAddressType( |
| address, static_cast<tBLE_ADDR_TYPE>(device.GetAddressType())); |
| } |
| |
| void on_incoming_data(bluetooth::hci::AddressWithType remote) { |
| auto channel = channels_.find(remote); |
| if (channel == channels_.end()) { |
| LOG_ERROR("Channel is not open"); |
| return; |
| } |
| auto packet = channel->second->GetQueueUpEnd()->TryDequeue(); |
| std::vector<uint8_t> packet_vector(packet->begin(), packet->end()); |
| BT_HDR* buffer = |
| static_cast<BT_HDR*>(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(remote.GetAddress()); |
| 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(AddressWithType remote, |
| std::unique_ptr<bluetooth::packet::BasePacketBuilder> packet) { |
| auto buffer = channel_enqueue_buffer_.find(remote); |
| if (buffer == channel_enqueue_buffer_.end() || buffer->second == nullptr) { |
| LOG(ERROR) << "Channel is not open"; |
| return false; |
| } |
| buffer->second->Enqueue(std::move(packet), |
| bluetooth::shim::GetGdShimHandler()); |
| return true; |
| } |
| |
| std::unordered_map<AddressWithType, std::unique_ptr<le::FixedChannel>> |
| channels_; |
| std::unordered_map<AddressWithType, |
| std::unique_ptr<bluetooth::os::EnqueueBuffer< |
| bluetooth::packet::BasePacketBuilder>>> |
| channel_enqueue_buffer_; |
| tL2CAP_FIXED_CHNL_REG freg_; |
| }; |
| |
| static LeFixedChannelHelper att_helper{4}; |
| static LeFixedChannelHelper smp_helper{6}; |
| static std::unordered_map<uint16_t, LeFixedChannelHelper&> |
| 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 bluetooth::shim::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; |
| } |
| bluetooth::shim::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 bluetooth::shim::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 = ToAddressWithType(rem_bda, Btm::GetAddressType(rem_bda)); |
| auto manager = bluetooth::shim::GetL2capLeModule()->GetFixedChannelManager(); |
| manager->ConnectServices( |
| remote, |
| common::BindOnce(&LeFixedChannelHelper::on_outgoing_connection_fail, |
| common::Unretained(helper), rem_bda), |
| GetGdShimHandler()); |
| return true; |
| } |
| |
| bool bluetooth::shim::L2CA_ConnectFixedChnl(uint16_t cid, |
| const RawAddress& rem_bda, |
| uint8_t initiating_phys) { |
| return bluetooth::shim::L2CA_ConnectFixedChnl(cid, rem_bda); |
| } |
| |
| uint16_t bluetooth::shim::L2CA_SendFixedChnlData(uint16_t cid, |
| const RawAddress& rem_bda, |
| BT_HDR* p_buf) { |
| if (cid != kAttCid && cid != kSmpCid) { |
| LOG(ERROR) << "Invalid cid " << cid; |
| return false; |
| } |
| auto* helper = &le_fixed_channel_helper_.find(cid)->second; |
| auto remote = ToAddressWithType(rem_bda, Btm::GetAddressType(rem_bda)); |
| auto len = p_buf->len; |
| auto* data = p_buf->data + p_buf->offset; |
| bool sent = helper->send(remote, MakeUniquePacket(data, len)); |
| return sent ? len : 0; |
| } |
| |
| bool bluetooth::shim::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 remote = ToAddressWithType(rem_bda, Btm::GetAddressType(rem_bda)); |
| auto channel = helper->channels_.find(remote); |
| if (channel == helper->channels_.end() || channel->second == nullptr) { |
| LOG(ERROR) << "Channel is not open"; |
| return false; |
| } |
| channel->second->Release(); |
| return true; |
| } |
| |
| /** |
| * Channel hygiene APIs |
| */ |
| bool bluetooth::shim::L2CA_GetRemoteCid(uint16_t lcid, uint16_t* rcid) { |
| auto psm = classic_cid_token_to_channel_map_[lcid].psm; |
| 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 bluetooth::shim::L2CA_SetTxPriority(uint16_t cid, |
| tL2CAP_CHNL_PRIORITY priority) { |
| LOG_INFO("UNIMPLEMENTED %s", __func__); |
| return false; |
| } |
| |
| bool bluetooth::shim::L2CA_SetFixedChannelTout(const RawAddress& rem_bda, |
| uint16_t fixed_cid, |
| uint16_t idle_tout) { |
| LOG_INFO("UNIMPLEMENTED %s", __func__); |
| return false; |
| } |
| |
| bool bluetooth::shim::L2CA_SetChnlFlushability(uint16_t cid, |
| bool is_flushable) { |
| LOG_INFO("UNIMPLEMENTED %s", __func__); |
| return false; |
| } |
| |
| uint16_t bluetooth::shim::L2CA_FlushChannel(uint16_t lcid, |
| uint16_t num_to_flush) { |
| LOG_INFO("UNIMPLEMENTED %s", __func__); |
| return 0; |
| } |
| |
| bool bluetooth::shim::L2CA_IsLinkEstablished(const RawAddress& bd_addr, |
| tBT_TRANSPORT transport) { |
| return security_listener_shim_.IsLinkUp(bd_addr); |
| } |
| |
| void bluetooth::shim::L2CA_ConnectForSecurity(const RawAddress& bd_addr) { |
| security_interface_->InitiateConnectionForSecurity( |
| bluetooth::ToGdAddress(bd_addr)); |
| } |
| |
| void bluetooth::shim::L2CA_SetBondingState(const RawAddress& bd_addr, |
| bool is_bonding) { |
| security_listener_shim_.UpdateLinkHoldForSecurity(bd_addr, is_bonding); |
| } |
| |
| void bluetooth::shim::L2CA_DisconnectLink(const RawAddress& remote) { |
| security_listener_shim_.Disconnect(remote); |
| } |
| |
| uint16_t bluetooth::shim::L2CA_GetNumLinks() { |
| return security_listener_shim_.GetNumAclLinks(); |
| } |
| |
| // LE COC Shim Helper |
| |
| uint16_t le_cid_token_counter_ = 1; |
| |
| struct LeCocChannelInfo { |
| uint16_t psm; |
| RawAddress remote; |
| }; |
| std::unordered_map<uint16_t, LeCocChannelInfo> le_cid_token_to_channel_map_; |
| |
| uint16_t add_le_cid_token_entry(uint16_t psm, RawAddress remote) { |
| uint16_t new_token = le_cid_token_counter_; |
| le_cid_token_to_channel_map_[new_token] = {psm, remote}; |
| le_cid_token_counter_++; |
| if (le_cid_token_counter_ == 0) le_cid_token_counter_++; |
| return new_token; |
| } |
| |
| void remove_le_cid_token_entry(uint16_t cid_token) { |
| le_cid_token_to_channel_map_.erase(cid_token); |
| } |
| |
| uint16_t find_le_cid_token_by_psm_address(uint16_t psm, RawAddress remote) { |
| for (const auto& entry : le_cid_token_to_channel_map_) { |
| if (entry.second.psm == psm && entry.second.remote == remote) { |
| return entry.first; |
| } |
| } |
| LOG(ERROR) << __func__ << "Can't find channel"; |
| return 0; |
| } |
| |
| struct LeDynamicChannelHelper { |
| LeDynamicChannelHelper(uint16_t psm, tL2CAP_APPL_INFO appl_info) |
| : psm_(psm), appl_info_(appl_info) {} |
| |
| uint16_t psm_; |
| tL2CAP_APPL_INFO appl_info_; |
| |
| void Register() { |
| bluetooth::shim::GetL2capLeModule() |
| ->GetDynamicChannelManager() |
| ->RegisterService( |
| psm_, {}, {}, |
| bluetooth::common::BindOnce( |
| &LeDynamicChannelHelper::on_registration_complete, |
| bluetooth::common::Unretained(this)), |
| bluetooth::common::Bind(&LeDynamicChannelHelper::on_channel_open, |
| bluetooth::common::Unretained(this)), |
| bluetooth::shim::GetGdShimHandler()); |
| } |
| |
| void on_registration_complete( |
| le::DynamicChannelManager::RegistrationResult result, |
| std::unique_ptr<le::DynamicChannelService> service) { |
| if (result != le::DynamicChannelManager::RegistrationResult::SUCCESS) { |
| LOG(ERROR) << "Channel is not registered. psm=" << +psm_ << (int)result; |
| return; |
| } |
| channel_service_ = std::move(service); |
| } |
| |
| std::unique_ptr<le::DynamicChannelService> channel_service_ = nullptr; |
| |
| void Connect(bluetooth::hci::AddressWithType device) { |
| if (channel_service_ == nullptr) { |
| return; |
| } |
| initiated_by_us_[device] = true; |
| bluetooth::shim::GetL2capLeModule() |
| ->GetDynamicChannelManager() |
| ->ConnectChannel( |
| device, {}, psm_, |
| bluetooth::common::Bind(&LeDynamicChannelHelper::on_channel_open, |
| bluetooth::common::Unretained(this)), |
| bluetooth::common::Bind( |
| &LeDynamicChannelHelper::on_outgoing_connection_fail, |
| bluetooth::common::Unretained(this)), |
| bluetooth::shim::GetGdShimHandler()); |
| } |
| |
| void Disconnect(bluetooth::hci::AddressWithType device) { |
| if (channel_service_ == nullptr) { |
| return; |
| } |
| if (channels_.count(device) == 0) { |
| return; |
| } |
| channels_[device]->Close(); |
| disconnected_by_us_[device] = true; |
| } |
| |
| void Unregister() { |
| if (channel_service_ != nullptr) { |
| channel_service_->Unregister( |
| bluetooth::common::BindOnce(&LeDynamicChannelHelper::on_unregistered, |
| bluetooth::common::Unretained(this)), |
| bluetooth::shim::GetGdShimHandler()); |
| channel_service_ = nullptr; |
| } |
| } |
| |
| void on_unregistered() { |
| for (const auto& device : channels_) { |
| device.second->Close(); |
| } |
| } |
| |
| void on_channel_close(bluetooth::hci::AddressWithType device, |
| bluetooth::hci::ErrorCode error_code) { |
| channel_enqueue_buffer_[device] = nullptr; |
| channels_[device]->GetQueueUpEnd()->UnregisterDequeue(); |
| channels_.erase(device); |
| auto address = bluetooth::ToRawAddress(device.GetAddress()); |
| auto cid_token = find_le_cid_token_by_psm_address(psm_, address); |
| (appl_info_.pL2CA_DisconnectInd_Cb)(cid_token, false); |
| remove_le_cid_token_entry(cid_token); |
| initiated_by_us_.erase(device); |
| |
| if (channel_service_ == nullptr && channels_.empty()) { |
| // Try again |
| bluetooth::shim::L2CA_DeregisterLECoc(psm_); |
| } |
| } |
| |
| void on_channel_open(std::unique_ptr<le::DynamicChannel> channel) { |
| auto device = channel->GetDevice(); |
| channel->RegisterOnCloseCallback( |
| bluetooth::shim::GetGdShimHandler()->BindOnceOn( |
| this, &LeDynamicChannelHelper::on_channel_close, device)); |
| channel_enqueue_buffer_[device] = std::make_unique< |
| bluetooth::os::EnqueueBuffer<bluetooth::packet::BasePacketBuilder>>( |
| channel->GetQueueUpEnd()); |
| channel->GetQueueUpEnd()->RegisterDequeue( |
| bluetooth::shim::GetGdShimHandler(), |
| bluetooth::common::Bind(&LeDynamicChannelHelper::on_incoming_data, |
| bluetooth::common::Unretained(this), device)); |
| channels_[device] = std::move(channel); |
| |
| auto address = bluetooth::ToRawAddress(device.GetAddress()); |
| if (initiated_by_us_[device]) { |
| auto cid_token = find_le_cid_token_by_psm_address(psm_, address); |
| appl_info_.pL2CA_ConnectCfm_Cb(cid_token, 0); |
| } else { |
| if (appl_info_.pL2CA_ConnectInd_Cb == nullptr) { |
| Disconnect(device); |
| return; |
| } |
| auto cid_token = add_le_cid_token_entry(psm_, address); |
| appl_info_.pL2CA_ConnectInd_Cb(address, cid_token, psm_, 0); |
| } |
| } |
| |
| void on_incoming_data(bluetooth::hci::AddressWithType remote) { |
| auto channel = channels_.find(remote); |
| if (channel == channels_.end()) { |
| LOG_ERROR("Channel is not open"); |
| return; |
| } |
| auto packet = channel->second->GetQueueUpEnd()->TryDequeue(); |
| std::vector<uint8_t> packet_vector(packet->begin(), packet->end()); |
| BT_HDR* buffer = |
| static_cast<BT_HDR*>(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(remote.GetAddress()); |
| auto cid_token = find_le_cid_token_by_psm_address(psm_, address); |
| appl_info_.pL2CA_DataInd_Cb(cid_token, buffer); |
| } |
| |
| void on_outgoing_connection_fail( |
| le::DynamicChannelManager::ConnectionResult result) { |
| LOG(ERROR) << "Outgoing connection failed"; |
| } |
| |
| bool send(AddressWithType remote, |
| std::unique_ptr<bluetooth::packet::BasePacketBuilder> packet) { |
| auto buffer = channel_enqueue_buffer_.find(remote); |
| if (buffer == channel_enqueue_buffer_.end() || buffer->second == nullptr) { |
| LOG(ERROR) << "Channel is not open"; |
| return false; |
| } |
| buffer->second->Enqueue(std::move(packet), |
| bluetooth::shim::GetGdShimHandler()); |
| return true; |
| } |
| |
| uint16_t GetMtu(AddressWithType remote) { |
| if (channels_.count(remote) == 0) { |
| return 0; |
| } |
| return static_cast<uint16_t>(channels_[remote]->GetMtu()); |
| } |
| |
| std::unordered_map<AddressWithType, std::unique_ptr<le::DynamicChannel>> |
| channels_; |
| std::unordered_map<AddressWithType, |
| std::unique_ptr<bluetooth::os::EnqueueBuffer< |
| bluetooth::packet::BasePacketBuilder>>> |
| channel_enqueue_buffer_; |
| std::unordered_map<AddressWithType, uint16_t> cid_map_; |
| std::unordered_map<AddressWithType, bool> initiated_by_us_; |
| std::unordered_map<AddressWithType, bool> disconnected_by_us_; |
| }; |
| |
| std::unordered_map<uint16_t, std::unique_ptr<LeDynamicChannelHelper>> |
| le_dynamic_channel_helper_map_; |
| |
| /** |
| * Le Connection Oriented Channel APIs |
| */ |
| |
| static std::unordered_set<uint16_t> assigned_dynamic_le_psm_; |
| static uint16_t next_assigned_dynamic_le_psm_ = 0x80; |
| |
| uint16_t bluetooth::shim::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 bluetooth::shim::L2CA_FreeLePSM(uint16_t psm) { |
| assigned_dynamic_le_psm_.erase(psm); |
| } |
| |
| uint16_t bluetooth::shim::L2CA_RegisterLECoc(uint16_t psm, |
| const tL2CAP_APPL_INFO& callbacks, |
| uint16_t sec_level) { |
| if (le_dynamic_channel_helper_map_.count(psm) != 0) { |
| LOG(ERROR) << __func__ << "Already registered psm: " << psm; |
| return 0; |
| } |
| le_dynamic_channel_helper_map_[psm] = |
| std::make_unique<LeDynamicChannelHelper>(psm, callbacks); |
| le_dynamic_channel_helper_map_[psm]->Register(); |
| return psm; |
| } |
| |
| void bluetooth::shim::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(); |
| if (le_dynamic_channel_helper_map_[psm]->channels_.empty()) { |
| le_dynamic_channel_helper_map_.erase(psm); |
| } |
| } |
| |
| uint16_t bluetooth::shim::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; |
| } |
| le_dynamic_channel_helper_map_[psm]->Connect( |
| ToAddressWithType(p_bd_addr, Btm::GetAddressType(p_bd_addr))); |
| return add_le_cid_token_entry(psm, p_bd_addr); |
| } |
| |
| bool bluetooth::shim::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].psm; |
| auto remote = le_cid_token_to_channel_map_[cid].remote; |
| 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( |
| bluetooth::ToAddressWithType(remote, Btm::GetAddressType(remote))); |
| peer_cfg->mtu = mtu; |
| return mtu; |
| } |
| |
| bool bluetooth::shim::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].psm; |
| auto remote = le_cid_token_to_channel_map_[cid].remote; |
| 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( |
| bluetooth::ToAddressWithType(remote, Btm::GetAddressType(remote))); |
| return true; |
| } |
| |
| uint8_t bluetooth::shim::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; |
| return 0; |
| } |
| auto psm = le_cid_token_to_channel_map_[cid].psm; |
| auto remote = le_cid_token_to_channel_map_[cid].remote; |
| if (le_dynamic_channel_helper_map_.count(psm) == 0) { |
| LOG(ERROR) << __func__ << "Not registered psm: " << psm; |
| return 0; |
| } |
| auto len = p_data->len; |
| auto* data = p_data->data + p_data->offset; |
| return le_dynamic_channel_helper_map_[psm]->send( |
| ToAddressWithType(remote, Btm::GetAddressType(remote)), |
| MakeUniquePacket(data, len)) * |
| len; |
| } |
| |
| void bluetooth::shim::L2CA_SwitchRoleToCentral(const RawAddress& addr) { |
| bluetooth::shim::GetAclManager()->SwitchRole(ToGdAddress(addr), |
| bluetooth::hci::Role::CENTRAL); |
| } |