From: Hansong Zhang Date: Fri, 20 Nov 2020 00:13:02 +0000 (-0800) Subject: L2cap shim: Introduce Classic Dynamic Channel Helper X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=d67452503c;p=android-x86%2Fsystem-bt.git L2cap shim: Introduce Classic Dynamic Channel Helper Same as LE. Tag: #gd-refactor Bug: 141555841 Test: cert/run --host Change-Id: Ie9c85f5bdadf5235095d357ae77d1668d7fcc694 --- diff --git a/main/shim/l2c_api.cc b/main/shim/l2c_api.cc index aa1ab61d6..74ef68c09 100644 --- a/main/shim/l2c_api.cc +++ b/main/shim/l2c_api.cc @@ -38,6 +38,205 @@ using namespace bluetooth::l2cap; static bluetooth::shim::legacy::L2cap shim_l2cap; +// Classic Dynamic Channel Shim Helper + +uint16_t classic_cid_token_counter_ = 1; + +struct ClassicDynamicChannelInfo { + uint16_t psm; + RawAddress remote; +}; +std::unordered_map + classic_cid_token_to_channel_map_; + +uint16_t add_classic_cid_token_entry(uint16_t psm, RawAddress remote) { + uint16_t new_token = classic_cid_token_counter_; + classic_cid_token_to_channel_map_[new_token] = {psm, remote}; + classic_cid_token_counter_++; + if (classic_cid_token_counter_ == 0) classic_cid_token_counter_++; + return new_token; +} + +void remove_classic_cid_token_entry(uint16_t cid_token) { + classic_cid_token_to_channel_map_.erase(cid_token); +} + +uint16_t find_classic_cid_token_by_psm_address(uint16_t psm, + RawAddress remote) { + for (const auto& entry : classic_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 ClassicDynamicChannelHelper { + ClassicDynamicChannelHelper(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::GetL2capClassicModule() + ->GetDynamicChannelManager() + ->RegisterService( + psm_, {}, {}, + bluetooth::shim::GetGdShimHandler()->BindOnceOn( + this, &ClassicDynamicChannelHelper::on_registration_complete), + bluetooth::shim::GetGdShimHandler()->BindOn( + this, &ClassicDynamicChannelHelper::on_channel_open)); + } + + 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(bluetooth::hci::AddressWithType device) { + if (channel_service_ == nullptr) { + return; + } + initiated_by_us_[device] = true; + bluetooth::shim::GetL2capClassicModule() + ->GetDynamicChannelManager() + ->ConnectChannel( + device.GetAddress(), {}, psm_, + bluetooth::shim::GetGdShimHandler()->BindOn( + this, &ClassicDynamicChannelHelper::on_channel_open), + bluetooth::shim::GetGdShimHandler()->BindOnceOn( + this, + &ClassicDynamicChannelHelper::on_outgoing_connection_fail)); + } + + 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::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(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_classic_cid_token_by_psm_address(psm_, address); + (appl_info_.pL2CA_DisconnectInd_Cb)(cid_token, false); + remove_classic_cid_token_entry(cid_token); + initiated_by_us_.erase(device); + + if (channel_service_ == nullptr && channels_.empty()) { + // Try again + bluetooth::shim::L2CA_Deregister(psm_); + } + } + + void on_channel_open(std::unique_ptr channel) { + auto device = channel->GetDevice(); + channel->RegisterOnCloseCallback( + bluetooth::shim::GetGdShimHandler()->BindOnceOn( + this, &ClassicDynamicChannelHelper::on_channel_close, device)); + channel_enqueue_buffer_[device] = std::make_unique< + bluetooth::os::EnqueueBuffer>( + channel->GetQueueUpEnd()); + channel->GetQueueUpEnd()->RegisterDequeue( + bluetooth::shim::GetGdShimHandler(), + bluetooth::common::Bind(&ClassicDynamicChannelHelper::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_classic_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_classic_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 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(remote.GetAddress()); + auto cid_token = find_classic_cid_token_by_psm_address(psm_, address); + appl_info_.pL2CA_DataInd_Cb(cid_token, buffer); + } + + void on_outgoing_connection_fail( + classic::DynamicChannelManager::ConnectionResult result) { + LOG(ERROR) << "Outgoing connection failed"; + } + + bool send(AddressWithType 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"; + return false; + } + buffer->second->Enqueue(std::move(packet), + bluetooth::shim::GetGdShimHandler()); + return true; + } + + std::unordered_map> + channels_; + std::unordered_map>> + channel_enqueue_buffer_; + std::unordered_map cid_map_; + std::unordered_map initiated_by_us_; + std::unordered_map disconnected_by_us_; +}; + +std::unordered_map> + classic_dynamic_channel_helper_map_; + // Helper: L2cap security enforcement shim std::unordered_map cid_token_to_channel_map_; +std::unordered_map le_cid_token_to_channel_map_; -uint16_t add_cid_token_entry(uint16_t psm, RawAddress remote) { - uint16_t new_token = cid_token_counter_; - cid_token_to_channel_map_[new_token] = {psm, remote}; - cid_token_counter_++; - if (cid_token_counter_ == 0) cid_token_counter_++; +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_cid_token_entry(uint16_t cid_token) { - cid_token_to_channel_map_.erase(cid_token); +void remove_le_cid_token_entry(uint16_t cid_token) { + le_cid_token_to_channel_map_.erase(cid_token); } -uint16_t find_cid_token_by_psm_address(uint16_t psm, RawAddress remote) { - for (const auto& entry : cid_token_to_channel_map_) { +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; } @@ -761,9 +960,9 @@ struct LeDynamicChannelHelper { channels_[device]->GetQueueUpEnd()->UnregisterDequeue(); channels_.erase(device); auto address = bluetooth::ToRawAddress(device.GetAddress()); - auto cid_token = find_cid_token_by_psm_address(psm_, address); + auto cid_token = find_le_cid_token_by_psm_address(psm_, address); (appl_info_.pL2CA_DisconnectInd_Cb)(cid_token, false); - remove_cid_token_entry(cid_token); + remove_le_cid_token_entry(cid_token); initiated_by_us_.erase(device); if (channel_service_ == nullptr && channels_.empty()) { @@ -788,14 +987,14 @@ struct LeDynamicChannelHelper { auto address = bluetooth::ToRawAddress(device.GetAddress()); if (initiated_by_us_[device]) { - auto cid_token = find_cid_token_by_psm_address(psm_, address); + 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_cid_token_entry(psm_, address); + auto cid_token = add_le_cid_token_entry(psm_, address); appl_info_.pL2CA_ConnectInd_Cb(address, cid_token, psm_, 0); } } @@ -813,7 +1012,7 @@ struct LeDynamicChannelHelper { 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_cid_token_by_psm_address(psm_, address); + auto cid_token = find_le_cid_token_by_psm_address(psm_, address); appl_info_.pL2CA_DataInd_Cb(cid_token, buffer); } @@ -891,17 +1090,17 @@ uint16_t bluetooth::shim::L2CA_ConnectLECocReq(uint16_t psm, } le_dynamic_channel_helper_map_[psm]->Connect( ToAddressWithType(p_bd_addr, Btm::GetAddressType(p_bd_addr))); - return add_cid_token_entry(psm, 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 (cid_token_to_channel_map_.count(cid) == 0) { + if (le_cid_token_to_channel_map_.count(cid) == 0) { LOG(ERROR) << __func__ << "Invalid cid: " << cid; return false; } - auto psm = cid_token_to_channel_map_[cid].psm; - auto remote = cid_token_to_channel_map_[cid].remote; + 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; @@ -913,12 +1112,12 @@ bool bluetooth::shim::L2CA_GetPeerLECocConfig(uint16_t cid, } bool bluetooth::shim::L2CA_DisconnectLECocReq(uint16_t cid) { - if (cid_token_to_channel_map_.count(cid) == 0) { + if (le_cid_token_to_channel_map_.count(cid) == 0) { LOG(ERROR) << __func__ << "Invalid cid: " << cid; return false; } - auto psm = cid_token_to_channel_map_[cid].psm; - auto remote = cid_token_to_channel_map_[cid].remote; + 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; @@ -929,12 +1128,12 @@ bool bluetooth::shim::L2CA_DisconnectLECocReq(uint16_t cid) { } uint8_t bluetooth::shim::L2CA_LECocDataWrite(uint16_t cid, BT_HDR* p_data) { - if (cid_token_to_channel_map_.count(cid) == 0) { + if (le_cid_token_to_channel_map_.count(cid) == 0) { LOG(ERROR) << __func__ << "Invalid cid: " << cid; return 0; } - auto psm = cid_token_to_channel_map_[cid].psm; - auto remote = cid_token_to_channel_map_[cid].remote; + 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;