/* * 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. */ #include #include #include "hci/acl_manager/classic_acl_connection.h" #include "hci/address.h" #include "hci/class_of_device.h" #include "l2cap/classic/internal/link.h" #include "l2cap/internal/scheduler_fifo.h" #include "os/log.h" #include "l2cap/classic/internal/link_manager.h" namespace bluetooth { namespace l2cap { namespace classic { namespace internal { void LinkManager::ConnectFixedChannelServices(hci::Address device, PendingFixedChannelConnection pending_fixed_channel_connection) { // Check if there is any service registered auto fixed_channel_services = fixed_channel_service_manager_->GetRegisteredServices(); if (fixed_channel_services.empty()) { // If so, return error pending_fixed_channel_connection.handler_->Post(common::BindOnce( std::move(pending_fixed_channel_connection.on_fail_callback_), FixedChannelManager::ConnectionResult{ .connection_result_code = FixedChannelManager::ConnectionResultCode::FAIL_NO_SERVICE_REGISTERED})); return; } // Otherwise, check if device has an ACL connection auto* link = GetLink(device); if (link != nullptr) { // If device already have an ACL connection // Check if all registered services have an allocated channel and allocate one if not already allocated int num_new_channels = 0; for (auto& fixed_channel_service : fixed_channel_services) { if (link->IsFixedChannelAllocated(fixed_channel_service.first)) { // This channel is already allocated for this link, do not allocated twice continue; } // Allocate channel for newly registered fixed channels auto fixed_channel_impl = link->AllocateFixedChannel(fixed_channel_service.first); fixed_channel_service.second->NotifyChannelCreation( std::make_unique(fixed_channel_impl, l2cap_handler_)); num_new_channels++; } // Declare connection failure if no new channels are created if (num_new_channels == 0) { pending_fixed_channel_connection.handler_->Post(common::BindOnce( std::move(pending_fixed_channel_connection.on_fail_callback_), FixedChannelManager::ConnectionResult{ .connection_result_code = FixedChannelManager::ConnectionResultCode::FAIL_ALL_SERVICES_HAVE_CHANNEL})); } // No need to create ACL connection, return without saving any pending connections return; } // If not, create new ACL connection // Add request to pending link list first auto pending_link = pending_links_.find(device); if (pending_link == pending_links_.end()) { // Create pending link if not exist pending_links_.try_emplace(device); pending_link = pending_links_.find(device); } pending_link->second.pending_fixed_channel_connections_.push_back(std::move(pending_fixed_channel_connection)); // Then create new ACL connection acl_manager_->CreateConnection(device); } void LinkManager::ConnectDynamicChannelServices( hci::Address device, Link::PendingDynamicChannelConnection pending_dynamic_channel_connection, Psm psm) { if (!IsPsmValid(psm)) { return; } auto* link = GetLink(device); if (link == nullptr) { acl_manager_->CreateConnection(device); if (pending_dynamic_channels_.find(device) != pending_dynamic_channels_.end()) { pending_dynamic_channels_[device].push_back(psm); pending_dynamic_channels_callbacks_[device].push_back(std::move(pending_dynamic_channel_connection)); } else { pending_dynamic_channels_[device] = {psm}; pending_dynamic_channels_callbacks_[device].push_back(std::move(pending_dynamic_channel_connection)); } return; } link->SendConnectionRequest(psm, link->ReserveDynamicChannel(), std::move(pending_dynamic_channel_connection)); } void LinkManager::InitiateConnectionForSecurity(hci::Address remote) { auto* link = GetLink(remote); if (link != nullptr) { LOG_ERROR("Link already exists for %s", remote.ToString().c_str()); } acl_manager_->CreateConnection(remote); } void LinkManager::RegisterLinkSecurityInterfaceListener(os::Handler* handler, LinkSecurityInterfaceListener* listener) { link_security_interface_listener_handler_ = handler; link_security_interface_listener_ = listener; } LinkSecurityInterfaceListener* LinkManager::GetLinkSecurityInterfaceListener() { return link_security_interface_listener_; } void LinkManager::RegisterLinkPropertyListener(os::Handler* handler, LinkPropertyListener* listener) { link_property_callback_handler_ = handler; link_property_listener_ = listener; } void LinkManager::OnPendingPacketChange(hci::Address remote, int num_packets) { if (disconnected_links_.count(remote) != 0 && num_packets == 0) { links_.erase(remote); links_with_pending_packets_.erase(remote); } else if (num_packets != 0) { links_with_pending_packets_.emplace(remote); } else { links_with_pending_packets_.erase(remote); } } Link* LinkManager::GetLink(const hci::Address device) { if (links_.find(device) == links_.end()) { return nullptr; } return &links_.find(device)->second; } void LinkManager::handle_link_security_hold(hci::Address remote) { auto link = GetLink(remote); if (link == nullptr) { LOG_WARN("Remote is disconnected"); return; } link->AcquireSecurityHold(); } void LinkManager::handle_link_security_release(hci::Address remote) { auto link = GetLink(remote); if (link == nullptr) { LOG_WARN("Remote is disconnected"); return; } link->ReleaseSecurityHold(); } void LinkManager::handle_link_security_disconnect(hci::Address remote) { auto link = GetLink(remote); if (link == nullptr) { LOG_WARN("Remote is disconnected"); return; } link->Disconnect(); } void LinkManager::handle_link_security_ensure_authenticated(hci::Address remote) { auto link = GetLink(remote); if (link == nullptr) { LOG_WARN("Remote is disconnected"); return; } link->Authenticate(); } void LinkManager::handle_link_security_ensure_encrypted(hci::Address remote) { auto link = GetLink(remote); if (link == nullptr) { LOG_WARN("Remote is disconnected"); return; } link->Encrypt(); } /** * The implementation for LinkSecurityInterface, which allows the SecurityModule to access some link functionalities. * Note: All public methods implementing this interface are invoked from external context. */ class LinkSecurityInterfaceImpl : public LinkSecurityInterface { public: LinkSecurityInterfaceImpl(os::Handler* handler, LinkManager* link_manager, Link* link) : handler_(handler), link_manager_(link_manager), remote_(link->GetDevice().GetAddress()), acl_handle_(link->GetAclHandle()) {} hci::Address GetRemoteAddress() override { return remote_; } void Hold() override { handler_->CallOn(link_manager_, &LinkManager::handle_link_security_hold, remote_); } void Release() override { handler_->CallOn(link_manager_, &LinkManager::handle_link_security_release, remote_); } void Disconnect() override { handler_->CallOn(link_manager_, &LinkManager::handle_link_security_disconnect, remote_); } void EnsureAuthenticated() override { handler_->CallOn(link_manager_, &LinkManager::handle_link_security_ensure_authenticated, remote_); } void EnsureEncrypted() override { handler_->CallOn(link_manager_, &LinkManager::handle_link_security_ensure_encrypted, remote_); } uint16_t GetAclHandle() override { return acl_handle_; } hci::Role GetRole() override { return link_manager_->GetLink(remote_)->GetRole(); } os::Handler* handler_; LinkManager* link_manager_; hci::Address remote_; uint16_t acl_handle_; }; void LinkManager::OnConnectSuccess(std::unique_ptr acl_connection) { // Same link should not be connected twice hci::Address device = acl_connection->GetAddress(); ASSERT_LOG(GetLink(device) == nullptr, "%s is connected twice without disconnection", acl_connection->GetAddress().ToString().c_str()); links_.try_emplace(device, l2cap_handler_, std::move(acl_connection), parameter_provider_, dynamic_channel_service_manager_, fixed_channel_service_manager_, this); auto* link = GetLink(device); ASSERT(link != nullptr); link->SendInformationRequest(InformationRequestInfoType::EXTENDED_FEATURES_SUPPORTED); link->SendInformationRequest(InformationRequestInfoType::FIXED_CHANNELS_SUPPORTED); link->ReadRemoteVersionInformation(); link->ReadRemoteSupportedFeatures(); link->ReadRemoteExtendedFeatures(1); // Allocate and distribute channels for all registered fixed channel services auto fixed_channel_services = fixed_channel_service_manager_->GetRegisteredServices(); for (auto& fixed_channel_service : fixed_channel_services) { auto fixed_channel_impl = link->AllocateFixedChannel(fixed_channel_service.first); fixed_channel_service.second->NotifyChannelCreation( std::make_unique(fixed_channel_impl, l2cap_handler_)); } if (pending_dynamic_channels_.find(device) != pending_dynamic_channels_.end()) { auto psm_list = pending_dynamic_channels_[device]; auto& callback_list = pending_dynamic_channels_callbacks_[device]; link->SetPendingDynamicChannels(psm_list, std::move(callback_list)); pending_dynamic_channels_.erase(device); pending_dynamic_channels_callbacks_.erase(device); } // Notify link property listener if (link_property_callback_handler_ != nullptr) { link_property_callback_handler_->CallOn( link_property_listener_, &LinkPropertyListener::OnLinkConnected, device, link->GetAclHandle()); } // Notify security manager if (link_security_interface_listener_handler_ != nullptr) { link_security_interface_listener_handler_->CallOn( link_security_interface_listener_, &LinkSecurityInterfaceListener::OnLinkConnected, std::make_unique(l2cap_handler_, this, link)); } // Remove device from pending links list, if any pending_links_.erase(device); } void LinkManager::OnConnectFail(hci::Address device, hci::ErrorCode reason) { // Notify all pending links for this device auto pending_link = pending_links_.find(device); if (pending_link == pending_links_.end()) { // There is no pending link, exit LOG_INFO( "Connection to %s failed without a pending link; reason: %s", device.ToString().c_str(), hci::ErrorCodeText(reason).c_str()); if (pending_dynamic_channels_callbacks_.find(device) != pending_dynamic_channels_callbacks_.end()) { for (Link::PendingDynamicChannelConnection& callbacks : pending_dynamic_channels_callbacks_[device]) { callbacks.on_fail_callback_.Invoke(DynamicChannelManager::ConnectionResult{ .hci_error = hci::ErrorCode::CONNECTION_TIMEOUT, }); } pending_dynamic_channels_.erase(device); pending_dynamic_channels_callbacks_.erase(device); } return; } for (auto& pending_fixed_channel_connection : pending_link->second.pending_fixed_channel_connections_) { pending_fixed_channel_connection.handler_->Post(common::BindOnce( std::move(pending_fixed_channel_connection.on_fail_callback_), FixedChannelManager::ConnectionResult{ .connection_result_code = FixedChannelManager::ConnectionResultCode::FAIL_HCI_ERROR, .hci_error = reason})); } // Remove entry in pending link list pending_links_.erase(pending_link); } void LinkManager::HACK_OnEscoConnectRequest(hci::Address device, hci::ClassOfDevice cod) { LOG_ERROR("Remote ESCO connect request unimplemented"); } void LinkManager::HACK_OnScoConnectRequest(hci::Address device, hci::ClassOfDevice cod) { LOG_ERROR("Remote SCO connect request unimplemented"); } void LinkManager::OnDisconnect(hci::Address device, hci::ErrorCode status) { auto* link = GetLink(device); ASSERT_LOG(link != nullptr, "Device %s is disconnected with reason 0x%x, but not in local database", device.ToString().c_str(), static_cast(status)); if (link_security_interface_listener_handler_ != nullptr) { link_security_interface_listener_handler_->CallOn( link_security_interface_listener_, &LinkSecurityInterfaceListener::OnLinkDisconnected, device); } if (link_property_callback_handler_ != nullptr) { link_property_callback_handler_->CallOn(link_property_listener_, &LinkPropertyListener::OnLinkDisconnected, device); } if (links_with_pending_packets_.count(device) != 0) { disconnected_links_.emplace(device); } else { links_.erase(device); } } void LinkManager::OnAuthenticationComplete(hci::ErrorCode hci_status, hci::Address device) { if (link_security_interface_listener_handler_ != nullptr) { link_security_interface_listener_handler_->CallOn( link_security_interface_listener_, &LinkSecurityInterfaceListener::OnAuthenticationComplete, hci_status, device); } } void LinkManager::OnEncryptionChange(hci::Address device, hci::EncryptionEnabled enabled) { if (link_security_interface_listener_handler_ != nullptr) { link_security_interface_listener_handler_->CallOn( link_security_interface_listener_, &LinkSecurityInterfaceListener::OnEncryptionChange, device, enabled == hci::EncryptionEnabled::ON || enabled == hci::EncryptionEnabled::BR_EDR_AES_CCM); } } void LinkManager::OnReadRemoteVersionInformation( hci::ErrorCode hci_status, hci::Address device, uint8_t lmp_version, uint16_t manufacturer_name, uint16_t sub_version) { if (link_property_callback_handler_ != nullptr) { link_property_callback_handler_->CallOn( link_property_listener_, &LinkPropertyListener::OnReadRemoteVersionInformation, hci_status, device, lmp_version, manufacturer_name, sub_version); } } void LinkManager::OnReadRemoteSupportedFeatures(hci::Address device, uint64_t features) { if (link_property_callback_handler_ != nullptr) { link_property_callback_handler_->CallOn( link_property_listener_, &LinkPropertyListener::OnReadRemoteSupportedFeatures, device, features); } } void LinkManager::OnReadRemoteExtendedFeatures( hci::Address device, uint8_t page_number, uint8_t max_page_number, uint64_t features) { if (link_property_callback_handler_ != nullptr) { link_property_callback_handler_->CallOn( link_property_listener_, &LinkPropertyListener::OnReadRemoteExtendedFeatures, device, page_number, max_page_number, features); } } void LinkManager::OnRoleChange(hci::ErrorCode hci_status, hci::Address remote, hci::Role role) { if (link_property_callback_handler_ != nullptr) { link_property_callback_handler_->CallOn( link_property_listener_, &LinkPropertyListener::OnRoleChange, hci_status, remote, role); } } void LinkManager::OnReadClockOffset(hci::Address remote, uint16_t clock_offset) { if (link_property_callback_handler_ != nullptr) { link_property_callback_handler_->CallOn( link_property_listener_, &LinkPropertyListener::OnReadClockOffset, remote, clock_offset); } } void LinkManager::OnModeChange(hci::ErrorCode hci_status, hci::Address remote, hci::Mode mode, uint16_t interval) { if (link_property_callback_handler_ != nullptr) { link_property_callback_handler_->CallOn( link_property_listener_, &LinkPropertyListener::OnModeChange, hci_status, remote, mode, interval); } } void LinkManager::OnSniffSubrating( hci::ErrorCode hci_status, hci::Address remote, uint16_t max_tx_lat, uint16_t max_rx_lat, uint16_t min_remote_timeout, uint16_t min_local_timeout) { if (link_property_callback_handler_ != nullptr) { link_property_callback_handler_->CallOn( link_property_listener_, &LinkPropertyListener::OnSniffSubrating, hci_status, remote, max_tx_lat, max_rx_lat, min_remote_timeout, min_local_timeout); } } } // namespace internal } // namespace classic } // namespace l2cap } // namespace bluetooth