| /* |
| * 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 <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/psm.h" |
| #include "l2cap/security_policy.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" |
| #include "shim/l2cap.h" |
| |
| namespace bluetooth { |
| namespace shim { |
| |
| namespace { |
| |
| constexpr char kModuleName[] = "shim::L2cap"; |
| |
| constexpr bool kConnectionFailed = false; |
| constexpr bool kConnectionOpened = true; |
| constexpr bool kRegistrationFailed = false; |
| constexpr bool kRegistrationSuccess = 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()), on_closed_(on_closed) { |
| channel_->RegisterOnCloseCallback( |
| handler_, common::BindOnce(&ConnectionInterface::OnConnectionClosed, common::Unretained(this))); |
| 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_DEBUG("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_DEBUG("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) { |
| hci::Address address = cid_to_interface_map_[cid]->GetRemoteAddress(); |
| LOG_DEBUG("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), kConnectionOpened); |
| } |
| |
| void ConnectionFailed(ConnectionCompleteCallback on_complete, hci::Address address, l2cap::Psm psm, |
| ConnectionInterfaceDescriptor cid) { |
| LOG_DEBUG("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), 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_DEBUG("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_DEBUG("Local initiated connection is open to device:%s for psm:%hd", address_.ToString().c_str(), psm_); |
| ASSERT_LOG(address_ == channel->GetDevice(), " Expected remote device does not match actual remote device"); |
| pending_open_(std::move(channel)); |
| } |
| |
| void OnConnectionFailure(l2cap::classic::DynamicChannelManager::ConnectionResult result) { |
| LOG_DEBUG("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_DEBUG("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_DEBUG("Connection failed result:hci error hci:%s", hci::ErrorCodeText(result.hci_error).c_str()); |
| break; |
| case l2cap::classic::DynamicChannelManager::ConnectionResultCode::FAIL_L2CAP_ERROR: |
| LOG_DEBUG("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; |
| } |
| 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); |
| }; |
| |
| class ServiceInterface { |
| public: |
| ServiceInterface(l2cap::Psm psm, l2cap::SecurityPolicy security_policy, ConnectionCompleteCallback on_complete, |
| RegisterServiceComplete register_complete, ServiceConnectionOpen connection_open, |
| RegisterServicePromise register_promise) |
| : psm_(psm), security_policy_(security_policy), on_complete_(on_complete), |
| register_complete_(std::move(register_complete)), connection_open_(std::move(connection_open)), |
| register_promise_(std::move(register_promise)) {} |
| |
| void NotifyRegistered(l2cap::Psm psm) { |
| register_promise_.set_value(psm); |
| } |
| |
| void NotifyUnregistered() { |
| unregister_promise_.set_value(); |
| } |
| |
| void UnregisterService(os::Handler* handler, UnregisterServicePromise unregister_promise, |
| UnregisterServiceDone unregister_done) { |
| unregister_promise_ = std::move(unregister_promise); |
| unregister_done_ = std::move(unregister_done); |
| |
| service_->Unregister(common::BindOnce(&ServiceInterface::OnUnregistrationComplete, common::Unretained(this)), |
| handler); |
| } |
| |
| l2cap::SecurityPolicy GetSecurityPolicy() const { |
| return security_policy_; |
| } |
| |
| void OnRegistrationComplete(l2cap::classic::DynamicChannelManager::RegistrationResult result, |
| std::unique_ptr<l2cap::classic::DynamicChannelService> service) { |
| ASSERT(service_ == nullptr); |
| ASSERT(service->GetPsm() == psm_); |
| service_ = std::move(service); |
| |
| switch (result) { |
| case l2cap::classic::DynamicChannelManager::RegistrationResult::SUCCESS: |
| LOG_DEBUG("Service is registered for psm:%hd", psm_); |
| register_complete_(psm_, kRegistrationSuccess); |
| break; |
| case l2cap::classic::DynamicChannelManager::RegistrationResult::FAIL_DUPLICATE_SERVICE: |
| LOG_WARN("Failed to register duplicate service has psm:%hd", psm_); |
| register_complete_(l2cap::kDefaultPsm, kRegistrationFailed); |
| break; |
| case l2cap::classic::DynamicChannelManager::RegistrationResult::FAIL_INVALID_SERVICE: |
| LOG_WARN("Failed to register invalid service psm:%hd", psm_); |
| register_complete_(l2cap::kDefaultPsm, kRegistrationFailed); |
| break; |
| } |
| } |
| |
| void OnUnregistrationComplete() { |
| LOG_DEBUG("Unregistered psm:%hd", psm_); |
| unregister_done_(); |
| } |
| |
| void OnConnectionOpen(std::unique_ptr<l2cap::classic::DynamicChannel> channel) { |
| LOG_DEBUG("Remote initiated connection is open from device:%s for psm:%hd", channel->GetDevice().ToString().c_str(), |
| psm_); |
| connection_open_(on_complete_, std::move(channel)); |
| } |
| |
| private: |
| const l2cap::Psm psm_; |
| const l2cap::SecurityPolicy security_policy_; |
| const ConnectionCompleteCallback on_complete_; |
| const RegisterServiceComplete register_complete_; |
| const ServiceConnectionOpen connection_open_; |
| RegisterServicePromise register_promise_; |
| UnregisterServicePromise unregister_promise_; |
| UnregisterServiceDone unregister_done_; |
| |
| std::unique_ptr<l2cap::classic::DynamicChannelService> service_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ServiceInterface); |
| }; |
| |
| 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); |
| |
| void Dump(int fd); |
| |
| 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<ServiceInterface>> 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); |
| void ServiceUnregistered(l2cap::Psm psm, std::unique_ptr<ServiceInterface> service); |
| const l2cap::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(); |
| } |
| |
| void L2cap::impl::Dump(int fd) { |
| if (psm_to_service_interface_map_.empty()) { |
| dprintf(fd, "%s no psms registered\n", kModuleName); |
| } else { |
| for (auto& service : psm_to_service_interface_map_) { |
| dprintf(fd, "%s psm registered:%hd\n", kModuleName, service.first); |
| } |
| } |
| |
| if (pending_connection_map_.empty()) { |
| dprintf(fd, "%s no pending classic connections\n", kModuleName); |
| } else { |
| for (auto& pending : pending_connection_map_) { |
| if (pending.second != nullptr) { |
| dprintf(fd, "%s pending connection:%s\n", kModuleName, pending.second->ToString().c_str()); |
| } else { |
| dprintf(fd, "%s old pending connection:%d\n", kModuleName, pending.first); |
| } |
| } |
| } |
| } |
| |
| void L2cap::impl::ServiceUnregistered(l2cap::Psm psm, std::unique_ptr<ServiceInterface> service) { |
| LOG_INFO("Unregistered service psm:%hd", psm); |
| psm_to_service_interface_map_.erase(psm); |
| service->NotifyUnregistered(); |
| } |
| |
| const l2cap::SecurityPolicy L2cap::impl::GetSecurityPolicy(l2cap::Psm psm) const { |
| l2cap::SecurityPolicy security_policy; |
| if (psm == 1) { |
| security_policy.security_level_ = l2cap::SecurityPolicy::Level::LEVEL_0; |
| } else { |
| security_policy.security_level_ = l2cap::SecurityPolicy::Level::LEVEL_3; |
| } |
| return security_policy; |
| } |
| |
| void L2cap::impl::RegisterService(l2cap::Psm psm, l2cap::classic::DynamicChannelConfigurationOption option, |
| ConnectionCompleteCallback on_complete, RegisterServicePromise register_promise) { |
| ASSERT(psm_to_service_interface_map_.find(psm) == psm_to_service_interface_map_.end()); |
| |
| const l2cap::SecurityPolicy security_policy = GetSecurityPolicy(psm); |
| |
| psm_to_service_interface_map_.emplace( |
| psm, |
| std::make_unique<ServiceInterface>( |
| psm, security_policy, on_complete, |
| [this, psm](l2cap::Psm actual_psm, bool is_registered) { |
| psm_to_service_interface_map_.at(psm)->NotifyRegistered(actual_psm); |
| if (!is_registered) { |
| auto service = std::move(psm_to_service_interface_map_.at(psm)); |
| } |
| }, |
| [this, psm](ConnectionCompleteCallback on_complete, std::unique_ptr<l2cap::classic::DynamicChannel> channel) { |
| ConnectionInterfaceDescriptor cid = connection_interface_manager_.AllocateConnectionInterfaceDescriptor(); |
| connection_interface_manager_.AddConnection(cid, std::move(channel)); |
| connection_interface_manager_.ConnectionOpened(on_complete, psm, cid); |
| LOG_DEBUG("connection open"); |
| }, |
| std::move(register_promise))); |
| |
| bool rc = dynamic_channel_manager_->RegisterService( |
| psm, option, security_policy, |
| common::BindOnce(&ServiceInterface::OnRegistrationComplete, |
| common::Unretained(psm_to_service_interface_map_.at(psm).get())), |
| common::Bind(&ServiceInterface::OnConnectionOpen, |
| common::Unretained(psm_to_service_interface_map_.at(psm).get())), |
| handler_); |
| ASSERT_LOG(rc == true, "Failed to register classic service"); |
| } |
| |
| 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]->UnregisterService(handler_, std::move(unregister_promise), [this, psm]() { |
| auto service = std::move(psm_to_service_interface_map_.at(psm)); |
| handler_->Post( |
| common::BindOnce(&L2cap::impl::ServiceUnregistered, common::Unretained(this), psm, std::move(service))); |
| }); |
| } |
| |
| void L2cap::impl::PendingConnectionOpen(PendingConnectionId id, std::unique_ptr<PendingConnection> connection, |
| std::unique_ptr<l2cap::classic::DynamicChannel> channel) { |
| connection_interface_manager_.AddConnection(connection->cid_, std::move(channel)); |
| connection_interface_manager_.ConnectionOpened(std::move(connection->on_complete_), connection->psm_, |
| connection->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_->Post(common::BindOnce(&L2cap::impl::PendingConnectionOpen, common::Unretained(this), id, |
| std::move(connection), std::move(channel))); |
| }, |
| [this, id](l2cap::classic::DynamicChannelManager::ConnectionResult result) { |
| auto connection = std::move(pending_connection_map_.at(id)); |
| handler_->Post(common::BindOnce(&L2cap::impl::PendingConnectionFail, common::Unretained(this), id, |
| std::move(connection), result)); |
| })); |
| |
| bool rc = dynamic_channel_manager_->ConnectChannel( |
| address, l2cap::classic::DynamicChannelConfigurationOption(), psm, |
| common::Bind(&PendingConnection::OnConnectionOpen, common::Unretained(pending_connection_map_.at(id).get())), |
| common::BindOnce(&PendingConnection::OnConnectionFailure, |
| common::Unretained(pending_connection_map_.at(id).get())), |
| handler_); |
| ASSERT_LOG(rc == true, "Failed to create classic connection"); |
| } |
| |
| 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::RegisterService(uint16_t raw_psm, bool use_ertm, uint16_t 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; |
| GetHandler()->Post(common::BindOnce(&L2cap::impl::RegisterService, common::Unretained(pimpl_.get()), psm, option, |
| on_complete, std::move(register_promise))); |
| } |
| |
| void L2cap::UnregisterService(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::CreateConnection(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::CloseConnection(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<shim::Dumpsys>(); |
| list->add<l2cap::classic::L2capClassicModule>(); |
| } |
| |
| void L2cap::Start() { |
| pimpl_ = std::make_unique<impl>(*this, GetDependency<l2cap::classic::L2capClassicModule>()); |
| GetDependency<shim::Dumpsys>()->RegisterDumpsysFunction(static_cast<void*>(this), |
| [this](int fd) { pimpl_->Dump(fd); }); |
| } |
| |
| void L2cap::Stop() { |
| GetDependency<shim::Dumpsys>()->UnregisterDumpsysFunction(static_cast<void*>(this)); |
| pimpl_.reset(); |
| } |
| |
| std::string L2cap::ToString() const { |
| return kModuleName; |
| } |
| |
| } // namespace shim |
| } // namespace bluetooth |