+++ /dev/null
-/*
- * 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_gd_shim"
-
-#include "shim/l2cap.h"
-
-#include <cstdint>
-#include <functional>
-#include <memory>
-#include <queue>
-#include <set>
-#include <string>
-#include <unordered_map>
-#include <vector>
-
-#include "common/bind.h"
-#include "hci/address.h"
-#include "hci/hci_packets.h"
-#include "l2cap/classic/dynamic_channel_manager.h"
-#include "l2cap/classic/l2cap_classic_module.h"
-#include "l2cap/classic/security_policy.h"
-#include "l2cap/psm.h"
-#include "module.h"
-#include "os/handler.h"
-#include "os/log.h"
-#include "packet/packet_view.h"
-#include "packet/raw_builder.h"
-#include "shim/dumpsys.h"
-
-namespace bluetooth {
-namespace shim {
-
-namespace {
-
-constexpr char kModuleName[] = "shim::L2cap";
-
-constexpr bool kConnectionFailed = false;
-constexpr bool kConnectionOpened = true;
-
-using ConnectionInterfaceDescriptor = uint16_t;
-constexpr ConnectionInterfaceDescriptor kInvalidConnectionInterfaceDescriptor = 0;
-constexpr ConnectionInterfaceDescriptor kStartConnectionInterfaceDescriptor = 64;
-constexpr ConnectionInterfaceDescriptor kMaxConnections = UINT16_MAX - kStartConnectionInterfaceDescriptor - 1;
-
-using PendingConnectionId = int;
-
-using ConnectionClosed = std::function<void(ConnectionInterfaceDescriptor)>;
-using PendingConnectionOpen = std::function<void(std::unique_ptr<l2cap::classic::DynamicChannel>)>;
-using PendingConnectionFail = std::function<void(l2cap::classic::DynamicChannelManager::ConnectionResult)>;
-using RegisterServiceComplete = std::function<void(l2cap::Psm, bool is_registered)>;
-using UnregisterServiceDone = std::function<void()>;
-using ServiceConnectionOpen =
- std::function<void(ConnectionCompleteCallback, std::unique_ptr<l2cap::classic::DynamicChannel>)>;
-
-std::unique_ptr<packet::RawBuilder> MakeUniquePacket(const uint8_t* data, size_t len) {
- packet::RawBuilder builder;
- std::vector<uint8_t> bytes(data, data + len);
- auto payload = std::make_unique<packet::RawBuilder>();
- payload->AddOctets(bytes);
- return payload;
-}
-
-} // namespace
-
-class ConnectionInterface {
- public:
- ConnectionInterface(
- ConnectionInterfaceDescriptor cid,
- std::unique_ptr<l2cap::classic::DynamicChannel> channel,
- os::Handler* handler,
- ConnectionClosed on_closed)
- : cid_(cid),
- channel_(std::move(channel)),
- handler_(handler),
- on_data_ready_callback_(nullptr),
- on_connection_closed_callback_(nullptr),
- address_(channel_->GetDevice().GetAddress()),
- on_closed_(on_closed) {
- channel_->RegisterOnCloseCallback(handler_->BindOnceOn(this, &ConnectionInterface::OnConnectionClosed));
- channel_->GetQueueUpEnd()->RegisterDequeue(
- handler_, common::Bind(&ConnectionInterface::OnReadReady, common::Unretained(this)));
- dequeue_registered_ = true;
- }
-
- ~ConnectionInterface() {
- ASSERT(!dequeue_registered_);
- }
-
- void OnReadReady() {
- std::unique_ptr<packet::PacketView<packet::kLittleEndian>> packet = channel_->GetQueueUpEnd()->TryDequeue();
- if (packet == nullptr) {
- LOG_WARN("Got read ready from gd l2cap but no packet is ready");
- return;
- }
- std::vector<const uint8_t> data(packet->begin(), packet->end());
- ASSERT(on_data_ready_callback_ != nullptr);
- on_data_ready_callback_(cid_, data);
- }
-
- void SetReadDataReadyCallback(ReadDataReadyCallback on_data_ready) {
- ASSERT(on_data_ready != nullptr);
- ASSERT(on_data_ready_callback_ == nullptr);
- on_data_ready_callback_ = on_data_ready;
- }
-
- std::unique_ptr<packet::BasePacketBuilder> WriteReady() {
- auto data = std::move(write_queue_.front());
- write_queue_.pop();
- if (write_queue_.empty()) {
- channel_->GetQueueUpEnd()->UnregisterEnqueue();
- enqueue_registered_ = false;
- }
- return data;
- }
-
- void Write(std::unique_ptr<packet::RawBuilder> packet) {
- LOG_INFO("Writing packet cid:%hd size:%zd", cid_, packet->size());
- write_queue_.push(std::move(packet));
- if (!enqueue_registered_) {
- enqueue_registered_ = true;
- channel_->GetQueueUpEnd()->RegisterEnqueue(
- handler_, common::Bind(&ConnectionInterface::WriteReady, common::Unretained(this)));
- }
- }
-
- void Close() {
- if (dequeue_registered_) {
- channel_->GetQueueUpEnd()->UnregisterDequeue();
- dequeue_registered_ = false;
- }
- ASSERT(write_queue_.empty());
- channel_->Close();
- }
-
- void OnConnectionClosed(hci::ErrorCode error_code) {
- LOG_INFO(
- "Channel interface closed reason:%s cid:%hd device:%s",
- hci::ErrorCodeText(error_code).c_str(),
- cid_,
- address_.ToString().c_str());
- if (dequeue_registered_) {
- channel_->GetQueueUpEnd()->UnregisterDequeue();
- dequeue_registered_ = false;
- }
- ASSERT(on_connection_closed_callback_ != nullptr);
- on_connection_closed_callback_(cid_, static_cast<int>(error_code));
- on_closed_(cid_);
- }
-
- void SetConnectionClosedCallback(::bluetooth::shim::ConnectionClosedCallback on_connection_closed) {
- ASSERT(on_connection_closed != nullptr);
- ASSERT(on_connection_closed_callback_ == nullptr);
- on_connection_closed_callback_ = std::move(on_connection_closed);
- }
-
- hci::Address GetRemoteAddress() const {
- return address_;
- }
-
- private:
- const ConnectionInterfaceDescriptor cid_;
- const std::unique_ptr<l2cap::classic::DynamicChannel> channel_;
- os::Handler* handler_;
-
- ReadDataReadyCallback on_data_ready_callback_;
- ConnectionClosedCallback on_connection_closed_callback_;
-
- const hci::Address address_;
-
- ConnectionClosed on_closed_{};
-
- std::queue<std::unique_ptr<packet::PacketBuilder<hci::kLittleEndian>>> write_queue_;
-
- bool enqueue_registered_{false};
- bool dequeue_registered_{false};
-
- DISALLOW_COPY_AND_ASSIGN(ConnectionInterface);
-};
-
-class ConnectionInterfaceManager {
- public:
- void AddConnection(ConnectionInterfaceDescriptor cid, std::unique_ptr<l2cap::classic::DynamicChannel> channel);
- void RemoveConnection(ConnectionInterfaceDescriptor cid);
-
- void SetReadDataReadyCallback(ConnectionInterfaceDescriptor cid, ReadDataReadyCallback on_data_ready);
- void SetConnectionClosedCallback(ConnectionInterfaceDescriptor cid, ConnectionClosedCallback on_closed);
-
- bool Write(ConnectionInterfaceDescriptor cid, std::unique_ptr<packet::RawBuilder> packet);
-
- size_t NumberOfActiveConnections() const {
- return cid_to_interface_map_.size();
- }
-
- void ConnectionOpened(
- ConnectionCompleteCallback on_complete,
- l2cap::Psm psm,
- ConnectionInterfaceDescriptor cid,
- l2cap::Cid remote_cid) {
- hci::Address address = cid_to_interface_map_[cid]->GetRemoteAddress();
- LOG_INFO("Connection opened address:%s psm:%hd cid:%hd", address.ToString().c_str(), psm, cid);
- on_complete(
- address.ToString(),
- static_cast<uint16_t>(psm),
- static_cast<uint16_t>(cid),
- static_cast<uint16_t>(remote_cid),
- kConnectionOpened);
- }
-
- void ConnectionFailed(
- ConnectionCompleteCallback on_complete, hci::Address address, l2cap::Psm psm, ConnectionInterfaceDescriptor cid) {
- LOG_INFO("Connection failed address:%s psm:%hd", address.ToString().c_str(), psm);
- on_complete(address.ToString(), static_cast<uint16_t>(psm), static_cast<uint16_t>(cid), 0, kConnectionFailed);
- }
-
- ConnectionInterfaceManager(os::Handler* handler);
-
- ConnectionInterfaceDescriptor AllocateConnectionInterfaceDescriptor();
- void FreeConnectionInterfaceDescriptor(ConnectionInterfaceDescriptor cid);
-
- private:
- os::Handler* handler_;
- ConnectionInterfaceDescriptor current_connection_interface_descriptor_;
-
- bool HasResources() const;
- bool ConnectionExists(ConnectionInterfaceDescriptor id) const;
- bool CidExists(ConnectionInterfaceDescriptor id) const;
- void ConnectionClosed(ConnectionInterfaceDescriptor cid, std::unique_ptr<ConnectionInterface> connection);
-
- std::unordered_map<ConnectionInterfaceDescriptor, std::unique_ptr<ConnectionInterface>> cid_to_interface_map_;
- std::set<ConnectionInterfaceDescriptor> active_cid_set_;
-
- ConnectionInterfaceManager() = delete;
-};
-
-ConnectionInterfaceManager::ConnectionInterfaceManager(os::Handler* handler)
- : handler_(handler), current_connection_interface_descriptor_(kStartConnectionInterfaceDescriptor) {}
-
-bool ConnectionInterfaceManager::ConnectionExists(ConnectionInterfaceDescriptor cid) const {
- return cid_to_interface_map_.find(cid) != cid_to_interface_map_.end();
-}
-
-bool ConnectionInterfaceManager::CidExists(ConnectionInterfaceDescriptor cid) const {
- return active_cid_set_.find(cid) != active_cid_set_.end();
-}
-
-ConnectionInterfaceDescriptor ConnectionInterfaceManager::AllocateConnectionInterfaceDescriptor() {
- ASSERT(HasResources());
- while (CidExists(current_connection_interface_descriptor_)) {
- if (++current_connection_interface_descriptor_ == kInvalidConnectionInterfaceDescriptor) {
- current_connection_interface_descriptor_ = kStartConnectionInterfaceDescriptor;
- }
- }
- active_cid_set_.insert(current_connection_interface_descriptor_);
- return current_connection_interface_descriptor_++;
-}
-
-void ConnectionInterfaceManager::FreeConnectionInterfaceDescriptor(ConnectionInterfaceDescriptor cid) {
- ASSERT(CidExists(cid));
- active_cid_set_.erase(cid);
-}
-
-void ConnectionInterfaceManager::ConnectionClosed(
- ConnectionInterfaceDescriptor cid, std::unique_ptr<ConnectionInterface> connection) {
- cid_to_interface_map_.erase(cid);
- FreeConnectionInterfaceDescriptor(cid);
-}
-
-void ConnectionInterfaceManager::AddConnection(
- ConnectionInterfaceDescriptor cid, std::unique_ptr<l2cap::classic::DynamicChannel> channel) {
- ASSERT(cid_to_interface_map_.count(cid) == 0);
- cid_to_interface_map_.emplace(
- cid,
- std::make_unique<ConnectionInterface>(
- cid, std::move(channel), handler_, [this](ConnectionInterfaceDescriptor cid) {
- LOG_INFO("Deleting connection interface cid:%hd", cid);
- auto connection = std::move(cid_to_interface_map_.at(cid));
- handler_->Post(common::BindOnce(
- &ConnectionInterfaceManager::ConnectionClosed, common::Unretained(this), cid, std::move(connection)));
- }));
-}
-
-void ConnectionInterfaceManager::RemoveConnection(ConnectionInterfaceDescriptor cid) {
- if (cid_to_interface_map_.count(cid) == 1) {
- cid_to_interface_map_.find(cid)->second->Close();
- } else {
- LOG_WARN("Closing a pending connection cid:%hd", cid);
- }
-}
-
-bool ConnectionInterfaceManager::HasResources() const {
- return cid_to_interface_map_.size() < kMaxConnections;
-}
-
-void ConnectionInterfaceManager::SetReadDataReadyCallback(
- ConnectionInterfaceDescriptor cid, ReadDataReadyCallback on_data_ready) {
- ASSERT(ConnectionExists(cid));
- return cid_to_interface_map_[cid]->SetReadDataReadyCallback(on_data_ready);
-}
-
-void ConnectionInterfaceManager::SetConnectionClosedCallback(
- ConnectionInterfaceDescriptor cid, ConnectionClosedCallback on_closed) {
- ASSERT(ConnectionExists(cid));
- return cid_to_interface_map_[cid]->SetConnectionClosedCallback(on_closed);
-}
-
-bool ConnectionInterfaceManager::Write(ConnectionInterfaceDescriptor cid, std::unique_ptr<packet::RawBuilder> packet) {
- if (!ConnectionExists(cid)) {
- return false;
- }
- cid_to_interface_map_[cid]->Write(std::move(packet));
- return true;
-}
-
-class PendingConnection {
- public:
- PendingConnection(
- ConnectionInterfaceDescriptor cid,
- l2cap::Psm psm,
- hci::Address address,
- ConnectionCompleteCallback on_complete,
- PendingConnectionOpen pending_open,
- PendingConnectionFail pending_fail)
- : cid_(cid),
- psm_(psm),
- address_(address),
- on_complete_(std::move(on_complete)),
- pending_open_(pending_open),
- pending_fail_(pending_fail) {}
-
- void OnConnectionOpen(std::unique_ptr<l2cap::classic::DynamicChannel> channel) {
- LOG_INFO("Local initiated connection is open to device:%s for psm:%hd", address_.ToString().c_str(), psm_);
- ASSERT_LOG(
- address_ == channel->GetDevice().GetAddress(), " Expected remote device does not match actual remote device");
- pending_open_(std::move(channel));
- }
-
- void OnConnectionFailure(l2cap::classic::DynamicChannelManager::ConnectionResult result) {
- LOG_INFO("Connection failed to device:%s for psm:%hd", address_.ToString().c_str(), psm_);
- switch (result.connection_result_code) {
- case l2cap::classic::DynamicChannelManager::ConnectionResultCode::SUCCESS:
- LOG_WARN("Connection failed result:success hci:%s", hci::ErrorCodeText(result.hci_error).c_str());
- break;
- case l2cap::classic::DynamicChannelManager::ConnectionResultCode::FAIL_NO_SERVICE_REGISTERED:
- LOG_INFO("Connection failed result:no service registered hci:%s", hci::ErrorCodeText(result.hci_error).c_str());
- break;
- case l2cap::classic::DynamicChannelManager::ConnectionResultCode::FAIL_HCI_ERROR:
- LOG_INFO("Connection failed result:hci error hci:%s", hci::ErrorCodeText(result.hci_error).c_str());
- break;
- case l2cap::classic::DynamicChannelManager::ConnectionResultCode::FAIL_L2CAP_ERROR:
- LOG_INFO(
- "Connection failed result:l2cap error hci:%s l2cap:%s",
- hci::ErrorCodeText(result.hci_error).c_str(),
- l2cap::ConnectionResponseResultText(result.l2cap_connection_response_result).c_str());
- break;
- case l2cap::classic::DynamicChannelManager::ConnectionResultCode::FAIL_REMOTE_NOT_SUPPORT:
- LOG_INFO("Connection failed result:Remote not support required retransmission and flow control mode");
- break;
- case l2cap::classic::DynamicChannelManager::ConnectionResultCode::FAIL_SECURITY_BLOCK:
- LOG_INFO("Connection failed result:security block");
- break;
- }
- pending_fail_(result);
- }
-
- std::string ToString() const {
- return address_.ToString() + "." + std::to_string(psm_);
- }
-
- const ConnectionInterfaceDescriptor cid_;
- const l2cap::Psm psm_;
- const hci::Address address_;
- const ConnectionCompleteCallback on_complete_;
-
- private:
- const PendingConnectionOpen pending_open_;
- const PendingConnectionFail pending_fail_;
-
- DISALLOW_COPY_AND_ASSIGN(PendingConnection);
-};
-
-struct L2cap::impl {
- void RegisterService(
- l2cap::Psm psm,
- l2cap::classic::DynamicChannelConfigurationOption option,
- ConnectionCompleteCallback on_complete,
- RegisterServicePromise register_promise);
- void UnregisterService(l2cap::Psm psm, UnregisterServicePromise unregister_promise);
-
- void CreateConnection(
- l2cap::Psm psm,
- hci::Address address,
- ConnectionCompleteCallback on_complete,
- CreateConnectionPromise create_promise);
- void CloseConnection(ConnectionInterfaceDescriptor cid);
-
- void SetReadDataReadyCallback(ConnectionInterfaceDescriptor cid, ReadDataReadyCallback on_data_ready);
- void SetConnectionClosedCallback(ConnectionInterfaceDescriptor cid, ConnectionClosedCallback on_closed);
-
- void Write(ConnectionInterfaceDescriptor cid, std::unique_ptr<packet::RawBuilder> packet);
-
- void SendLoopbackResponse(std::function<void()> function);
-
- impl(L2cap& module, l2cap::classic::L2capClassicModule* l2cap_module);
-
- private:
- L2cap& module_;
- l2cap::classic::L2capClassicModule* l2cap_module_;
- os::Handler* handler_;
- ConnectionInterfaceManager connection_interface_manager_;
-
- std::unique_ptr<l2cap::classic::DynamicChannelManager> dynamic_channel_manager_;
-
- std::unordered_map<l2cap::Psm, std::unique_ptr<l2cap::classic::DynamicChannelService>> psm_to_service_interface_map_;
-
- PendingConnectionId pending_connection_id_{0};
- std::unordered_map<PendingConnectionId, std::unique_ptr<PendingConnection>> pending_connection_map_;
-
- void PendingConnectionOpen(
- PendingConnectionId id,
- std::unique_ptr<PendingConnection> connection,
- std::unique_ptr<l2cap::classic::DynamicChannel> channel);
- void PendingConnectionFail(
- PendingConnectionId id,
- std::unique_ptr<PendingConnection> connection,
- l2cap::classic::DynamicChannelManager::ConnectionResult result);
- l2cap::classic::SecurityPolicy GetSecurityPolicy(l2cap::Psm psm) const;
-};
-
-const ModuleFactory L2cap::Factory = ModuleFactory([]() { return new L2cap(); });
-
-L2cap::impl::impl(L2cap& module, l2cap::classic::L2capClassicModule* l2cap_module)
- : module_(module),
- l2cap_module_(l2cap_module),
- handler_(module_.GetHandler()),
- connection_interface_manager_(handler_) {
- dynamic_channel_manager_ = l2cap_module_->GetDynamicChannelManager();
-}
-
-l2cap::classic::SecurityPolicy L2cap::impl::GetSecurityPolicy(l2cap::Psm psm) const {
- if (psm == 1) {
- return l2cap::classic::SecurityPolicy::_SDP_ONLY_NO_SECURITY_WHATSOEVER_PLAINTEXT_TRANSPORT_OK;
- } else {
- return l2cap::classic::SecurityPolicy::ENCRYPTED_TRANSPORT;
- }
-}
-
-void L2cap::impl::RegisterService(
- l2cap::Psm psm,
- l2cap::classic::DynamicChannelConfigurationOption option,
- ConnectionCompleteCallback on_complete,
- RegisterServicePromise register_promise) {
- const l2cap::classic::SecurityPolicy security_policy = GetSecurityPolicy(psm);
-
- dynamic_channel_manager_->RegisterService(
- psm,
- option,
- security_policy,
- handler_->BindOnce(
- [](RegisterServicePromise register_promise,
- std::unordered_map<l2cap::Psm, std::unique_ptr<l2cap::classic::DynamicChannelService>>*
- psm_to_service_interface_map_,
- l2cap::classic::DynamicChannelManager::RegistrationResult result,
- std::unique_ptr<l2cap::classic::DynamicChannelService> service) {
- std::unique_ptr<l2cap::classic::DynamicChannelService> service_ = std::move(service);
- switch (result) {
- case l2cap::classic::DynamicChannelManager::RegistrationResult::SUCCESS:
- LOG_INFO("Service is registered for psm:%hd", service_->GetPsm());
- register_promise.set_value(service_->GetPsm());
- psm_to_service_interface_map_->emplace(service_->GetPsm(), std::move(service_));
- break;
- case l2cap::classic::DynamicChannelManager::RegistrationResult::FAIL_DUPLICATE_SERVICE:
- LOG_WARN("Failed to register duplicate service has psm:%hd", service_->GetPsm());
- register_promise.set_value(l2cap::kDefaultPsm);
- break;
- case l2cap::classic::DynamicChannelManager::RegistrationResult::FAIL_INVALID_SERVICE:
- LOG_WARN("Failed to register invalid service psm:%hd", service_->GetPsm());
- register_promise.set_value(l2cap::kDefaultPsm);
- break;
- }
- },
- std::move(register_promise),
- &psm_to_service_interface_map_),
- handler_->Bind(
- [](l2cap::Psm psm,
- ConnectionCompleteCallback on_complete,
- ConnectionInterfaceManager* connection_interface_manager_,
- std::unique_ptr<l2cap::classic::DynamicChannel> channel) {
- LOG_INFO("Remote initiated connection is open from device:%s", channel->GetDevice().ToString().c_str());
-
- ConnectionInterfaceDescriptor cid = connection_interface_manager_->AllocateConnectionInterfaceDescriptor();
- uint16_t remote_cid = channel->HACK_GetRemoteCid();
- connection_interface_manager_->AddConnection(cid, std::move(channel));
- connection_interface_manager_->ConnectionOpened(on_complete, psm, cid, remote_cid);
- LOG_INFO("connection open");
- },
- psm,
- on_complete,
- &connection_interface_manager_));
-}
-
-void L2cap::impl::UnregisterService(l2cap::Psm psm, UnregisterServicePromise unregister_promise) {
- ASSERT(psm_to_service_interface_map_.find(psm) != psm_to_service_interface_map_.end());
-
- psm_to_service_interface_map_[psm]->Unregister(handler_->BindOnce(
- [](std::unordered_map<l2cap::Psm, std::unique_ptr<l2cap::classic::DynamicChannelService>>*
- psm_to_service_interface_map_,
- UnregisterServicePromise unregister_promise,
- l2cap::Psm psm) {
- psm_to_service_interface_map_->erase(psm);
- unregister_promise.set_value();
- },
- &psm_to_service_interface_map_,
- std::move(unregister_promise),
- psm));
-}
-
-void L2cap::impl::PendingConnectionOpen(
- PendingConnectionId id,
- std::unique_ptr<PendingConnection> connection,
- std::unique_ptr<l2cap::classic::DynamicChannel> channel) {
- uint16_t remote_cid = channel->HACK_GetRemoteCid();
- connection_interface_manager_.AddConnection(connection->cid_, std::move(channel));
- connection_interface_manager_.ConnectionOpened(
- std::move(connection->on_complete_), connection->psm_, connection->cid_, remote_cid);
- pending_connection_map_.erase(id);
-}
-
-void L2cap::impl::PendingConnectionFail(
- PendingConnectionId id,
- std::unique_ptr<PendingConnection> connection,
- l2cap::classic::DynamicChannelManager::ConnectionResult result) {
- connection_interface_manager_.ConnectionFailed(
- std::move(connection->on_complete_), connection->address_, connection->psm_, connection->cid_);
- connection_interface_manager_.FreeConnectionInterfaceDescriptor(connection->cid_);
- pending_connection_map_.erase(id);
-}
-
-void L2cap::impl::CreateConnection(
- l2cap::Psm psm,
- hci::Address address,
- ConnectionCompleteCallback on_complete,
- CreateConnectionPromise create_promise) {
- ConnectionInterfaceDescriptor cid = connection_interface_manager_.AllocateConnectionInterfaceDescriptor();
- create_promise.set_value(cid);
-
- if (cid == kInvalidConnectionInterfaceDescriptor) {
- LOG_WARN("No resources to create a connection");
- return;
- }
-
- PendingConnectionId id = ++pending_connection_id_;
- pending_connection_map_.emplace(
- id,
- std::make_unique<PendingConnection>(
- cid,
- psm,
- address,
- on_complete,
- [this, id](std::unique_ptr<l2cap::classic::DynamicChannel> channel) {
- auto connection = std::move(pending_connection_map_.at(id));
- handler_->CallOn(this, &L2cap::impl::PendingConnectionOpen, id, std::move(connection), std::move(channel));
- },
- [this, id](l2cap::classic::DynamicChannelManager::ConnectionResult result) {
- auto connection = std::move(pending_connection_map_.at(id));
- handler_->CallOn(this, &L2cap::impl::PendingConnectionFail, id, std::move(connection), result);
- }));
-
- dynamic_channel_manager_->ConnectChannel(
- address,
- l2cap::classic::DynamicChannelConfigurationOption(),
- psm,
- handler_->BindOn(pending_connection_map_.at(id).get(), &PendingConnection::OnConnectionOpen),
- handler_->BindOnceOn(pending_connection_map_.at(id).get(), &PendingConnection::OnConnectionFailure));
-}
-
-void L2cap::impl::CloseConnection(ConnectionInterfaceDescriptor cid) {
- connection_interface_manager_.RemoveConnection(cid);
-}
-
-void L2cap::impl::SetReadDataReadyCallback(ConnectionInterfaceDescriptor cid, ReadDataReadyCallback on_data_ready) {
- connection_interface_manager_.SetReadDataReadyCallback(cid, on_data_ready);
-}
-
-void L2cap::impl::SetConnectionClosedCallback(ConnectionInterfaceDescriptor cid, ConnectionClosedCallback on_closed) {
- connection_interface_manager_.SetConnectionClosedCallback(cid, std::move(on_closed));
-}
-
-void L2cap::impl::Write(ConnectionInterfaceDescriptor cid, std::unique_ptr<packet::RawBuilder> packet) {
- connection_interface_manager_.Write(cid, std::move(packet));
-}
-
-void L2cap::impl::SendLoopbackResponse(std::function<void()> function) {
- function();
-}
-
-void L2cap::RegisterClassicService(
- uint16_t raw_psm,
- bool use_ertm,
- uint16_t mtu,
- uint16_t required_remote_mtu,
- ConnectionCompleteCallback on_complete,
- RegisterServicePromise register_promise) {
- l2cap::Psm psm{raw_psm};
- l2cap::classic::DynamicChannelConfigurationOption option;
- if (use_ertm) {
- option.channel_mode =
- l2cap::classic::DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::ENHANCED_RETRANSMISSION;
- }
- option.incoming_mtu = mtu;
- option.minimal_remote_mtu = required_remote_mtu;
- GetHandler()->Post(common::BindOnce(
- &L2cap::impl::RegisterService,
- common::Unretained(pimpl_.get()),
- psm,
- option,
- on_complete,
- std::move(register_promise)));
-}
-
-void L2cap::UnregisterClassicService(uint16_t raw_psm, UnregisterServicePromise unregister_promise) {
- l2cap::Psm psm{raw_psm};
- GetHandler()->Post(common::BindOnce(
- &L2cap::impl::UnregisterService, common::Unretained(pimpl_.get()), psm, std::move(unregister_promise)));
-}
-
-void L2cap::CreateClassicConnection(
- uint16_t raw_psm,
- const std::string address_string,
- ConnectionCompleteCallback on_complete,
- CreateConnectionPromise create_promise) {
- l2cap::Psm psm{raw_psm};
- hci::Address address;
- hci::Address::FromString(address_string, address);
-
- GetHandler()->Post(common::BindOnce(
- &L2cap::impl::CreateConnection,
- common::Unretained(pimpl_.get()),
- psm,
- address,
- on_complete,
- std::move(create_promise)));
-}
-
-void L2cap::CloseClassicConnection(uint16_t raw_cid) {
- ConnectionInterfaceDescriptor cid(raw_cid);
- GetHandler()->Post(common::Bind(&L2cap::impl::CloseConnection, common::Unretained(pimpl_.get()), cid));
-}
-
-void L2cap::SetReadDataReadyCallback(uint16_t raw_cid, ReadDataReadyCallback on_data_ready) {
- ConnectionInterfaceDescriptor cid(raw_cid);
- GetHandler()->Post(
- common::Bind(&L2cap::impl::SetReadDataReadyCallback, common::Unretained(pimpl_.get()), cid, on_data_ready));
-}
-
-void L2cap::SetConnectionClosedCallback(uint16_t raw_cid, ConnectionClosedCallback on_closed) {
- ConnectionInterfaceDescriptor cid(raw_cid);
- GetHandler()->Post(common::Bind(
- &L2cap::impl::SetConnectionClosedCallback, common::Unretained(pimpl_.get()), cid, std::move(on_closed)));
-}
-
-void L2cap::Write(uint16_t raw_cid, const uint8_t* data, size_t len) {
- ConnectionInterfaceDescriptor cid(raw_cid);
- auto packet = MakeUniquePacket(data, len);
- GetHandler()->Post(common::BindOnce(&L2cap::impl::Write, common::Unretained(pimpl_.get()), cid, std::move(packet)));
-}
-
-void L2cap::SendLoopbackResponse(std::function<void()> function) {
- GetHandler()->Post(common::BindOnce(&L2cap::impl::SendLoopbackResponse, common::Unretained(pimpl_.get()), function));
-}
-
-/**
- * Module methods
- */
-void L2cap::ListDependencies(ModuleList* list) {
- list->add<l2cap::classic::L2capClassicModule>();
-}
-
-void L2cap::Start() {
- pimpl_ = std::make_unique<impl>(*this, GetDependency<l2cap::classic::L2capClassicModule>());
-}
-
-void L2cap::Stop() {
- pimpl_.reset();
-}
-
-std::string L2cap::ToString() const {
- return kModuleName;
-}
-
-} // namespace shim
-} // namespace bluetooth
+++ /dev/null
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "shim/l2cap.h"
-
-#include <gtest/gtest.h>
-
-#include <future>
-#include <memory>
-
-#include "common/bind.h"
-#include "hci/address.h"
-#include "hci/address_with_type.h"
-#include "l2cap/classic/dynamic_channel_configuration_option.h"
-#include "l2cap/classic/dynamic_channel_manager.h"
-#include "l2cap/classic/internal/dynamic_channel_service_manager_impl_mock.h"
-#include "l2cap/classic/l2cap_classic_module.h"
-#include "l2cap/classic/security_policy.h"
-#include "l2cap/internal/ilink.h"
-#include "l2cap/psm.h"
-#include "os/handler.h"
-
-namespace bluetooth {
-namespace shim {
-namespace {
-
-constexpr uint16_t kPsm = 123;
-constexpr uint16_t kPsm2 = kPsm + 2;
-constexpr uint16_t kCid = 456;
-constexpr uint16_t kCid2 = kCid + 1;
-constexpr char device_address[] = "11:22:33:44:55:66";
-constexpr char device_address2[] = "aa:bb:cc:dd:ee:ff";
-constexpr bool kNoUseErtm = false;
-constexpr uint16_t kMtu = 1000;
-
-class TestDynamicChannelService : public l2cap::classic::DynamicChannelService {
- public:
- TestDynamicChannelService(
- l2cap::Psm psm, l2cap::classic::internal::DynamicChannelServiceManagerImpl* manager, os::Handler* handler)
- : DynamicChannelService(psm, manager, handler) {}
-};
-
-class TestLink : public l2cap::internal::ILink {
- public:
- hci::AddressWithType GetDevice() const {
- return device_with_type_;
- }
- hci::AddressWithType device_with_type_;
-
- void SendLeCredit(l2cap::Cid local_cid, uint16_t credit) {}
-
- void SendDisconnectionRequest(l2cap::Cid cid, l2cap::Cid remote_cid) {
- connection_closed_promise_.set_value();
- }
- std::promise<void> connection_closed_promise_;
-};
-
-class TestDynamicChannelManagerImpl {
- public:
- void ConnectChannel(
- hci::Address device,
- l2cap::classic::DynamicChannelConfigurationOption configuration_option,
- l2cap::Psm psm,
- l2cap::classic::DynamicChannelManager::OnConnectionOpenCallback on_open_callback,
- l2cap::classic::DynamicChannelManager::OnConnectionFailureCallback on_fail_callback) {
- connections_++;
- on_open_callback_ = std::move(on_open_callback);
- on_fail_callback_ = std::move(on_fail_callback);
-
- connected_promise_.set_value();
- }
- int connections_{0};
-
- void RegisterService(
- l2cap::Psm psm,
- l2cap::classic::DynamicChannelConfigurationOption configuration_option,
- const l2cap::classic::SecurityPolicy& security_policy,
- l2cap::classic::DynamicChannelManager::OnRegistrationCompleteCallback on_registration_complete,
- l2cap::classic::DynamicChannelManager::OnConnectionOpenCallback on_open_callback) {
- services_++;
- on_registration_complete_ = std::move(on_registration_complete);
- on_open_callback_ = std::move(on_open_callback);
-
- register_promise_.set_value();
- }
- int services_{0};
-
- void SetConnectionFuture() {
- connected_promise_ = std::promise<void>();
- }
-
- void WaitConnectionFuture() {
- connected_future_ = connected_promise_.get_future();
- connected_future_.wait();
- }
-
- void SetRegistrationFuture() {
- register_promise_ = std::promise<void>();
- }
-
- void WaitRegistrationFuture() {
- register_future_ = register_promise_.get_future();
- register_future_.wait();
- }
-
- void SetConnectionOnFail(l2cap::classic::DynamicChannelManager::ConnectionResult result, std::promise<void> promise) {
- std::move(on_fail_callback_).Invoke(result);
- promise.set_value();
- }
-
- void SetConnectionOnOpen(std::unique_ptr<l2cap::DynamicChannel> channel, std::promise<void> promise) {
- std::move(on_open_callback_).Invoke(std::move(channel));
- promise.set_value();
- }
-
- l2cap::classic::DynamicChannelManager::OnRegistrationCompleteCallback on_registration_complete_{};
- l2cap::classic::DynamicChannelManager::OnConnectionOpenCallback on_open_callback_{};
- l2cap::classic::DynamicChannelManager::OnConnectionFailureCallback on_fail_callback_{};
-
- TestDynamicChannelManagerImpl() = default;
- ~TestDynamicChannelManagerImpl() = default;
-
- private:
- std::promise<void> connected_promise_;
- std::future<void> connected_future_;
-
- std::promise<void> register_promise_;
- std::future<void> register_future_;
-};
-
-class TestDynamicChannelManager : public l2cap::classic::DynamicChannelManager {
- public:
- void ConnectChannel(
- hci::Address device,
- l2cap::classic::DynamicChannelConfigurationOption configuration_option,
- l2cap::Psm psm,
- l2cap::classic::DynamicChannelManager::OnConnectionOpenCallback on_open_callback,
- l2cap::classic::DynamicChannelManager::OnConnectionFailureCallback on_fail_callback) override {
- impl_.ConnectChannel(device, configuration_option, psm, std::move(on_open_callback), std::move(on_fail_callback));
- }
-
- void RegisterService(
- l2cap::Psm psm,
- l2cap::classic::DynamicChannelConfigurationOption configuration_option,
- const l2cap::classic::SecurityPolicy& security_policy,
- l2cap::classic::DynamicChannelManager::OnRegistrationCompleteCallback on_registration_complete,
- l2cap::classic::DynamicChannelManager::OnConnectionOpenCallback on_open_callback) override {
- impl_.RegisterService(
- psm, configuration_option, security_policy, std::move(on_registration_complete), std::move(on_open_callback));
- }
- TestDynamicChannelManager(TestDynamicChannelManagerImpl& impl) : impl_(impl) {}
- TestDynamicChannelManagerImpl& impl_;
-};
-
-class TestL2capClassicModule : public l2cap::classic::L2capClassicModule {
- public:
- std::unique_ptr<l2cap::classic::DynamicChannelManager> GetDynamicChannelManager() override {
- return std::make_unique<TestDynamicChannelManager>(*impl_);
- }
-
- void ListDependencies(ModuleList* list) override {}
- void Start() override;
- void Stop() override;
-
- std::unique_ptr<TestDynamicChannelManagerImpl> impl_;
-};
-
-void TestL2capClassicModule::Start() {
- impl_ = std::make_unique<TestDynamicChannelManagerImpl>();
- ASSERT_NE(impl_, nullptr);
-}
-
-void TestL2capClassicModule::Stop() {
- impl_.reset();
-}
-
-class ShimL2capTest : public ::testing::Test {
- public:
- void OnConnectionComplete(std::string string_address, uint16_t psm, uint16_t cid, bool connected) {
- connection_string_address_ = string_address;
- connection_psm_ = psm;
- connection_cid_ = cid;
- connection_connected_ = connected;
- connection_complete_promise_.set_value();
- }
-
- uint16_t CreateConnection(uint16_t psm, std::string device_address) {
- std::promise<uint16_t> promise;
- auto future = promise.get_future();
-
- shim_l2cap_->CreateClassicConnection(
- psm,
- device_address,
- std::bind(
- &bluetooth::shim::ShimL2capTest::OnConnectionComplete,
- this,
- std::placeholders::_1,
- std::placeholders::_2,
- std::placeholders::_3,
- std::placeholders::_4),
- std::move(promise));
- return future.get();
- }
-
- void SetConnectionFuture() {
- test_l2cap_classic_module_->impl_->SetConnectionFuture();
- }
-
- void WaitConnectionFuture() {
- test_l2cap_classic_module_->impl_->WaitConnectionFuture();
- }
-
- void SetRegistrationFuture() {
- test_l2cap_classic_module_->impl_->SetRegistrationFuture();
- }
-
- void WaitRegistrationFuture() {
- test_l2cap_classic_module_->impl_->WaitRegistrationFuture();
- }
-
- int NumberOfConnections() const {
- return test_l2cap_classic_module_->impl_->connections_;
- }
-
- int NumberOfServices() const {
- return test_l2cap_classic_module_->impl_->services_;
- }
-
- std::string connection_string_address_;
- uint16_t connection_psm_{0};
- uint16_t connection_cid_{0};
- bool connection_connected_{false};
-
- shim::L2cap* shim_l2cap_ = nullptr;
- TestL2capClassicModule* test_l2cap_classic_module_{nullptr};
-
- TestLink test_link_;
- std::promise<void> connection_complete_promise_;
-
- protected:
- void SetUp() override {
- handler_ = new os::Handler(&thread_);
-
- test_l2cap_classic_module_ = new TestL2capClassicModule();
- test_l2cap_classic_module_->Start();
- fake_registry_.InjectTestModule(&l2cap::classic::L2capClassicModule::Factory, test_l2cap_classic_module_);
-
- fake_registry_.Start<shim::L2cap>(&thread_);
- shim_l2cap_ = static_cast<shim::L2cap*>(fake_registry_.GetModuleUnderTest(&shim::L2cap::Factory));
- }
-
- void TearDown() override {
- fake_registry_.StopAll();
- handler_->Clear();
- delete handler_;
- }
- os::Handler* handler_ = nullptr;
- l2cap::classic::internal::testing::MockDynamicChannelServiceManagerImpl mock_;
-
- private:
- TestModuleRegistry fake_registry_;
- os::Thread& thread_ = fake_registry_.GetTestThread();
-};
-
-TEST_F(ShimL2capTest, CreateThenDisconnectBeforeCompletion) {
- SetConnectionFuture();
-
- ASSERT_EQ(NumberOfConnections(), 0);
- uint16_t cid = CreateConnection(kPsm, device_address);
- ASSERT_NE(cid, 0);
-
- WaitConnectionFuture();
- ASSERT_EQ(NumberOfConnections(), 1);
-
- shim_l2cap_->CloseClassicConnection(cid);
-}
-
-TEST_F(ShimL2capTest, MaxCreatedConnections) {
- for (int i = 0; i < 65536 - 64; i++) {
- SetConnectionFuture();
- uint16_t cid = CreateConnection(kPsm, device_address);
- ASSERT_NE(cid, 0);
- WaitConnectionFuture();
-
- ASSERT_EQ(NumberOfConnections(), i + 1);
- }
- uint16_t cid = CreateConnection(kPsm, device_address);
- ASSERT_EQ(cid, 0);
-
- ASSERT_EQ(NumberOfConnections(), 65536 - 64);
-}
-
-TEST_F(ShimL2capTest, TwoDifferentCreatedConnections) {
- {
- SetConnectionFuture();
- uint16_t cid = CreateConnection(kPsm, device_address);
- ASSERT_NE(cid, 0);
- WaitConnectionFuture();
-
- ASSERT_EQ(NumberOfConnections(), 1);
- }
-
- {
- SetConnectionFuture();
- uint16_t cid = CreateConnection(kPsm2, device_address2);
- ASSERT_NE(cid, 0);
- WaitConnectionFuture();
-
- ASSERT_EQ(NumberOfConnections(), 2);
- }
-}
-
-TEST_F(ShimL2capTest, ConnectFail) {
- SetConnectionFuture();
- uint16_t cid = CreateConnection(kPsm, device_address);
- ASSERT_NE(cid, 0);
- WaitConnectionFuture();
-
- ASSERT_EQ(NumberOfConnections(), 1);
-
- l2cap::classic::DynamicChannelManager::ConnectionResult result{
- .connection_result_code = TestDynamicChannelManager::ConnectionResultCode::FAIL_NO_SERVICE_REGISTERED,
- .hci_error = hci::ErrorCode::SUCCESS,
- .l2cap_connection_response_result = l2cap::ConnectionResponseResult::SUCCESS,
- };
-
- std::promise<void> on_fail_promise;
- auto on_fail_future = on_fail_promise.get_future();
- handler_->CallOn(
- test_l2cap_classic_module_->impl_.get(),
- &TestDynamicChannelManagerImpl::SetConnectionOnFail,
- result,
- std::move(on_fail_promise));
- on_fail_future.wait();
-
- ASSERT_EQ(connection_connected_, false);
-
- shim_l2cap_->CloseClassicConnection(cid);
-}
-
-TEST_F(ShimL2capTest, ConnectOpen) {
- SetConnectionFuture();
- uint16_t cid = CreateConnection(kPsm, device_address);
- ASSERT_NE(cid, 0);
- WaitConnectionFuture();
-
- ASSERT_EQ(NumberOfConnections(), 1);
-
- hci::Address address;
- hci::Address::FromString(device_address, address);
- test_link_.device_with_type_ = hci::AddressWithType(address, hci::AddressType::PUBLIC_DEVICE_ADDRESS);
-
- l2cap::Psm psm = kPsm;
- l2cap::Cid local_cid = kCid;
- l2cap::Cid remote_cid = kCid2;
-
- std::shared_ptr<l2cap::internal::DynamicChannelImpl> impl =
- std::make_shared<l2cap::internal::DynamicChannelImpl>(psm, local_cid, remote_cid, &test_link_, handler_);
-
- auto channel = std::make_unique<l2cap::DynamicChannel>(impl, handler_);
-
- std::promise<void> on_fail_promise;
- auto on_fail_future = on_fail_promise.get_future();
-
- auto connection_complete_future = connection_complete_promise_.get_future();
- handler_->CallOn(
- test_l2cap_classic_module_->impl_.get(),
- &TestDynamicChannelManagerImpl::SetConnectionOnOpen,
- std::move(channel),
- std::move(on_fail_promise));
- connection_complete_future.wait();
-
- on_fail_future.wait();
-
- ASSERT_EQ(connection_connected_, true);
-
- auto future = test_link_.connection_closed_promise_.get_future();
- shim_l2cap_->CloseClassicConnection(cid);
- future.wait();
-}
-
-TEST_F(ShimL2capTest, RegisterService_Success) {
- std::promise<uint16_t> registration_promise;
- auto registration_pending = registration_promise.get_future();
-
- SetRegistrationFuture();
- shim_l2cap_->RegisterClassicService(
- kPsm,
- kNoUseErtm,
- kMtu,
- kMtu,
- std::bind(
- &bluetooth::shim::ShimL2capTest::OnConnectionComplete,
- this,
- std::placeholders::_1,
- std::placeholders::_2,
- std::placeholders::_3,
- std::placeholders::_4),
- std::move(registration_promise));
- WaitRegistrationFuture();
- ASSERT_LOG(!test_l2cap_classic_module_->impl_->on_registration_complete_.IsEmpty(), "Synchronization failure");
- ASSERT_EQ(test_l2cap_classic_module_->impl_->services_, 1);
-
- l2cap::classic::DynamicChannelManager::RegistrationResult result{
- l2cap::classic::DynamicChannelManager::RegistrationResult::SUCCESS,
- };
- auto service = std::make_unique<TestDynamicChannelService>(kPsm, &mock_, handler_);
-
- test_l2cap_classic_module_->impl_->on_registration_complete_.Invoke(result, std::move(service));
- uint16_t psm = registration_pending.get();
- ASSERT_EQ(psm, kPsm);
-}
-
-TEST_F(ShimL2capTest, RegisterService_Duplicate) {
- std::promise<uint16_t> promise;
- auto future = promise.get_future();
-
- SetRegistrationFuture();
- shim_l2cap_->RegisterClassicService(
- kPsm,
- kNoUseErtm,
- kMtu,
- kMtu,
- std::bind(
- &bluetooth::shim::ShimL2capTest::OnConnectionComplete,
- this,
- std::placeholders::_1,
- std::placeholders::_2,
- std::placeholders::_3,
- std::placeholders::_4),
- std::move(promise));
- WaitRegistrationFuture();
- ASSERT_LOG(!test_l2cap_classic_module_->impl_->on_registration_complete_.IsEmpty(), "Synchronization failure");
- ASSERT_EQ(test_l2cap_classic_module_->impl_->services_, 1);
-
- l2cap::classic::DynamicChannelManager::RegistrationResult result{
- l2cap::classic::DynamicChannelManager::RegistrationResult::FAIL_DUPLICATE_SERVICE,
- };
- auto service = std::make_unique<TestDynamicChannelService>(kPsm, &mock_, handler_);
-
- test_l2cap_classic_module_->impl_->on_registration_complete_.Invoke(result, std::move(service));
- uint16_t psm = future.get();
- ASSERT_EQ(psm, l2cap::kDefaultPsm);
-}
-
-TEST_F(ShimL2capTest, RegisterService_Invalid) {
- std::promise<uint16_t> promise;
- auto future = promise.get_future();
-
- SetRegistrationFuture();
-
- shim_l2cap_->RegisterClassicService(
- kPsm,
- kNoUseErtm,
- kMtu,
- kMtu,
- std::bind(
- &bluetooth::shim::ShimL2capTest::OnConnectionComplete,
- this,
- std::placeholders::_1,
- std::placeholders::_2,
- std::placeholders::_3,
- std::placeholders::_4),
- std::move(promise));
-
- l2cap::classic::DynamicChannelManager::RegistrationResult result{
- l2cap::classic::DynamicChannelManager::RegistrationResult::FAIL_INVALID_SERVICE,
- };
- auto service = std::make_unique<TestDynamicChannelService>(kPsm, &mock_, handler_);
- WaitRegistrationFuture();
-
- ASSERT_LOG(!test_l2cap_classic_module_->impl_->on_registration_complete_.IsEmpty(), "Synchronization failure");
- test_l2cap_classic_module_->impl_->on_registration_complete_.Invoke(result, std::move(service));
- uint16_t psm = future.get();
- ASSERT_EQ(psm, l2cap::kDefaultPsm);
- ASSERT_EQ(test_l2cap_classic_module_->impl_->services_, 1);
-}
-
-} // namespace
-} // namespace shim
-} // namespace bluetooth