Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ee8d9135 authored by Hansong Zhang's avatar Hansong Zhang
Browse files

L2cap: Add SecurityInterface

Add SecurityInterface as a bridge between L2cap and Security Module.

LinkSecurityInterface is used by Security Manager to access some link
methods (hold/release, disconnect). Also add a way for Security Manager
to initialize a link connection.

Test: cert/run --host
Tag: #gd-refactor
Change-Id: I08380c96f2f7ce38795d9b27b17209241fb2ec24
parent b7a2ca89
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -100,6 +100,15 @@ void Link::ReadClockOffset() {
  acl_connection_->ReadClockOffset();
}

void Link::AcquireSecurityHold() {
  used_by_security_module_ = true;
  RefreshRefCount();
}
void Link::ReleaseSecurityHold() {
  used_by_security_module_ = false;
  RefreshRefCount();
}

std::shared_ptr<FixedChannelImpl> Link::AllocateFixedChannel(Cid cid) {
  auto channel = fixed_channel_allocator_.AllocateChannel(cid);
  data_pipeline_manager_.AttachChannel(cid, channel, l2cap::internal::DataPipelineManager::ChannelMode::BASIC);
@@ -235,6 +244,9 @@ void Link::RefreshRefCount() {
  int ref_count = 0;
  ref_count += fixed_channel_allocator_.GetRefCount();
  ref_count += dynamic_channel_allocator_.NumberOfChannels();
  if (used_by_security_module_) {
    ref_count += 1;
  }
  ASSERT_LOG(ref_count >= 0, "ref_count %d is less than 0", ref_count);
  if (ref_count > 0) {
    link_idle_disconnect_alarm_.Cancel();
+7 −0
Original line number Diff line number Diff line
@@ -86,6 +86,12 @@ class Link : public l2cap::internal::ILink, public hci::acl_manager::ConnectionM

  virtual void ReadClockOffset();

  // Increase the link usage refcount to ensure the link won't be disconnected when SecurityModule needs it
  virtual void AcquireSecurityHold();

  // Decrease the link usage refcount when SecurityModule no longer needs it
  virtual void ReleaseSecurityHold();

  // FixedChannel methods

  std::shared_ptr<FixedChannelImpl> AllocateFixedChannel(Cid cid);
@@ -195,6 +201,7 @@ class Link : public l2cap::internal::ILink, public hci::acl_manager::ConnectionM
  std::list<Psm> pending_dynamic_psm_list_;
  std::list<Link::PendingDynamicChannelConnection> pending_dynamic_channel_callback_list_;
  std::list<uint16_t> pending_outgoing_configuration_request_list_;
  bool used_by_security_module_ = false;
  DISALLOW_COPY_AND_ASSIGN(Link);
};

+95 −0
Original line number Diff line number Diff line
@@ -109,6 +109,19 @@ void LinkManager::ConnectDynamicChannelServices(
  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;
}

Link* LinkManager::GetLink(const hci::Address device) {
  if (links_.find(device) == links_.end()) {
    return nullptr;
@@ -126,6 +139,76 @@ void LinkManager::TriggerPairing(Link* link) {
  link->ReadClockOffset();
}

/**
 * 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.
 */
struct LinkSecurityInterfaceImpl : public LinkSecurityInterface {
 public:
  LinkSecurityInterfaceImpl(os::Handler* handler, LinkManager* link_manager, Link* link)
      : handler_(handler), link_manager_(link_manager), link_(link), remote_(link_->GetDevice().GetAddress()) {}

  hci::Address GetRemoteAddress() override {
    return remote_;
  }

  void Hold() override {
    handler_->CallOn(this, &LinkSecurityInterfaceImpl::handle_hold);
  }

  void handle_hold() {
    if (link_manager_->GetLink(remote_) == nullptr) {
      LOG_WARN("Remote is disconnected");
      return;
    }
    link_->AcquireSecurityHold();
  }

  void Release() override {
    handler_->CallOn(this, &LinkSecurityInterfaceImpl::handle_release);
  }

  void handle_release() {
    if (link_manager_->GetLink(remote_) == nullptr) {
      LOG_WARN("Remote is disconnected");
      return;
    }
    link_->ReleaseSecurityHold();
  }

  void Disconnect() override {
    handler_->CallOn(this, &LinkSecurityInterfaceImpl::handle_disconnect);
  }

  void handle_disconnect() {
    if (link_manager_->GetLink(remote_) == nullptr) {
      LOG_WARN("Remote is disconnected");
      return;
    }
    link_->Disconnect();
  }

  void EnsureAuthenticated() override {
    handler_->CallOn(this, &LinkSecurityInterfaceImpl::handle_ensure_authenticated);
  }

  void handle_ensure_authenticated() {
    if (link_manager_->GetLink(remote_) == nullptr) {
      LOG_WARN("Remote is disconnected");
      return;
    }

    if (!link_->IsAuthenticated()) {
      link_->Authenticate();
    }
  }

  os::Handler* handler_;
  LinkManager* link_manager_;
  Link* link_;
  hci::Address remote_;
};

void LinkManager::OnConnectSuccess(std::unique_ptr<hci::acl_manager::ClassicAclConnection> acl_connection) {
  // Same link should not be connected twice
  hci::Address device = acl_connection->GetAddress();
@@ -155,6 +238,14 @@ void LinkManager::OnConnectSuccess(std::unique_ptr<hci::acl_manager::ClassicAclC
    pending_dynamic_channels_.erase(device);
    pending_dynamic_channels_callbacks_.erase(device);
  }
  // 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<LinkSecurityInterfaceImpl>(l2cap_handler_, this, link));
  }

  // Remove device from pending links list, if any
  pending_links_.erase(device);
}
@@ -194,6 +285,10 @@ void LinkManager::OnDisconnect(hci::Address device, hci::ErrorCode status) {
             device.ToString().c_str(), static_cast<uint8_t>(status));
  link->OnAclDisconnected(status);
  links_.erase(device);
  if (link_security_interface_listener_handler_ != nullptr) {
    link_security_interface_listener_handler_->CallOn(
        link_security_interface_listener_, &LinkSecurityInterfaceListener::OnLinkDisconnected, device);
  }
}

}  // namespace internal
+9 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include "l2cap/classic/internal/dynamic_channel_service_manager_impl.h"
#include "l2cap/classic/internal/fixed_channel_service_manager_impl.h"
#include "l2cap/classic/internal/link.h"
#include "l2cap/classic/link_security_interface.h"
#include "l2cap/internal/parameter_provider.h"
#include "l2cap/internal/scheduler.h"
#include "os/handler.h"
@@ -72,6 +73,12 @@ class LinkManager : public hci::acl_manager::ConnectionCallbacks {
  void ConnectDynamicChannelServices(hci::Address device,
                                     Link::PendingDynamicChannelConnection pending_dynamic_channel_connection, Psm psm);

  // For SecurityModule to initiate an ACL link
  void InitiateConnectionForSecurity(hci::Address remote);

  // LinkManager will handle sending OnLinkConnected() callback and construct a LinkSecurityInterface proxy.
  void RegisterLinkSecurityInterfaceListener(os::Handler* handler, LinkSecurityInterfaceListener* listener);

 private:
  void TriggerPairing(Link* link);

@@ -88,6 +95,8 @@ class LinkManager : public hci::acl_manager::ConnectionCallbacks {
  std::unordered_map<hci::Address, std::list<Psm>> pending_dynamic_channels_;
  std::unordered_map<hci::Address, std::list<Link::PendingDynamicChannelConnection>>
      pending_dynamic_channels_callbacks_;
  os::Handler* link_security_interface_listener_handler_ = nullptr;
  LinkSecurityInterfaceListener* link_security_interface_listener_ = nullptr;
  DISALLOW_COPY_AND_ASSIGN(LinkManager);
};

+27 −0
Original line number Diff line number Diff line
@@ -52,6 +52,27 @@ struct L2capClassicModule::impl {
  internal::DynamicChannelServiceManagerImpl dynamic_channel_service_manager_impl_{l2cap_handler_};
  internal::LinkManager link_manager_{l2cap_handler_, acl_manager_, &fixed_channel_service_manager_impl_,
                                      &dynamic_channel_service_manager_impl_, &parameter_provider_};

  struct SecurityInterfaceImpl : public SecurityInterface {
    SecurityInterfaceImpl(impl* module_impl) : module_impl_(module_impl) {}

    void RegisterLinkSecurityInterfaceListener(os::Handler* handler, LinkSecurityInterfaceListener* listener) {
      ASSERT(!registered_);
      module_impl_->link_manager_.RegisterLinkSecurityInterfaceListener(handler, listener);
    }

    void InitiateConnectionForSecurity(hci::Address remote) override {
      ASSERT(registered_);
      module_impl_->link_manager_.InitiateConnectionForSecurity(remote);
    }

    void Unregister() override {
      ASSERT(registered_);
      module_impl_->link_manager_.RegisterLinkSecurityInterfaceListener(nullptr, nullptr);
    }
    impl* module_impl_;
    bool registered_ = false;
  } security_interface_impl_{this};
};

L2capClassicModule::L2capClassicModule() {}
@@ -93,6 +114,12 @@ void L2capClassicModule::InjectSecurityEnforcementInterface(
  }
}

SecurityInterface* L2capClassicModule::GetSecurityInterface(
    os::Handler* handler, LinkSecurityInterfaceListener* listener) {
  pimpl_->security_interface_impl_.RegisterLinkSecurityInterfaceListener(handler, listener);
  return &pimpl_->security_interface_impl_;
}

}  // namespace classic
}  // namespace l2cap
}  // namespace bluetooth
Loading