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

Commit fe85f98b authored by Josh Wu's avatar Josh Wu
Browse files

RootCanal: Handle if role switch is not allowed

PTS SMP uses allow_role_switch to control if CTKD should be run.

Bug: 274248798
Test: pts-bot
Change-Id: If2662938cfa4ee5cead84fe09380f7a2f2de7e29
parent d6f17f0f
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -55,14 +55,16 @@ uint16_t AclConnectionHandler::GetUnusedHandle() {
  return unused_handle;
}

bool AclConnectionHandler::CreatePendingConnection(
    Address addr, bool authenticate_on_connect) {
bool AclConnectionHandler::CreatePendingConnection(Address addr,
                                                   bool authenticate_on_connect,
                                                   bool allow_role_switch) {
  if (classic_connection_pending_) {
    return false;
  }
  classic_connection_pending_ = true;
  pending_connection_address_ = addr;
  authenticate_pending_classic_connection_ = authenticate_on_connect;
  pending_classic_connection_allow_role_switch_ = allow_role_switch;
  return true;
}

@@ -622,4 +624,8 @@ bool AclConnectionHandler::HasLinkExpired(uint16_t handle) const {
  return acl_connections_.at(handle).HasExpired();
}

bool AclConnectionHandler::IsRoleSwitchAllowedForPendingConnection() const {
  return pending_classic_connection_allow_role_switch_;
}

}  // namespace rootcanal
+4 −1
Original line number Diff line number Diff line
@@ -43,7 +43,8 @@ class AclConnectionHandler {
  void Reset(std::function<void(TaskId)> stopStream);

  bool CreatePendingConnection(bluetooth::hci::Address addr,
                               bool authenticate_on_connect);
                               bool authenticate_on_connect,
                               bool allow_role_switch);
  bool HasPendingConnection(bluetooth::hci::Address addr) const;
  bool CancelPendingConnection(bluetooth::hci::Address addr);
  bool AuthenticatePendingConnection() const;
@@ -151,6 +152,7 @@ class AclConnectionHandler {
  std::chrono::steady_clock::duration TimeUntilLinkExpired(
      uint16_t handle) const;
  bool HasLinkExpired(uint16_t handle) const;
  bool IsRoleSwitchAllowedForPendingConnection() const;

 private:
  std::unordered_map<uint16_t, AclConnection> acl_connections_;
@@ -160,6 +162,7 @@ class AclConnectionHandler {
  bluetooth::hci::Address pending_connection_address_{
      bluetooth::hci::Address::kEmpty};
  bool authenticate_pending_classic_connection_{false};
  bool pending_classic_connection_allow_role_switch_{false};
  bool le_connection_pending_{false};
  bluetooth::hci::AddressWithType pending_le_connection_address_{
      bluetooth::hci::Address::kEmpty,
+24 −13
Original line number Diff line number Diff line
@@ -4730,9 +4730,11 @@ void LinkLayerController::IncomingPagePacket(
  ASSERT(page.IsValid());
  LOG_INFO("from %s", incoming.GetSourceAddress().ToString().c_str());

  bool allow_role_switch = page.GetAllowRoleSwitch();
  if (!connections_.CreatePendingConnection(
          incoming.GetSourceAddress(),
          authentication_enable_ == AuthenticationEnable::REQUIRED)) {
          authentication_enable_ == AuthenticationEnable::REQUIRED,
          allow_role_switch)) {
    // Send a response to indicate that we're busy, or drop the packet?
    LOG_WARN("Failed to create a pending connection for %s",
             incoming.GetSourceAddress().ToString().c_str());
@@ -4791,9 +4793,9 @@ void LinkLayerController::IncomingPageResponsePacket(
   * Android-capatable Bluetooth controllers.
   * On the initiator side, only connection in peripheral role should be
   * accompanied with a role change event */
  // TODO(b/274248798): Reject role switch if disabled by host
  // TODO(b/274476773): Add a config option for this quirk
  if (response.GetTryRoleSwitch()) {
  if (connections_.IsRoleSwitchAllowedForPendingConnection() &&
      response.GetTryRoleSwitch()) {
    auto role = bluetooth::hci::Role::PERIPHERAL;
    connections_.SetAclRole(handle, role);
    if (IsEventUnmasked(EventCode::ROLE_CHANGE)) {
@@ -5411,9 +5413,10 @@ void LinkLayerController::MakePeripheralConnection(const Address& addr,
   * Android-capatable Bluetooth controllers.
   * On the responder side, any connection should be accompanied with a role
   * change event */
  // TODO(b/274248798): Reject role switch if disabled by host
  // TODO(b/274476773): Add a config option for this quirk
  auto role = try_role_switch ? bluetooth::hci::Role::CENTRAL
  auto role =
      try_role_switch && connections_.IsRoleSwitchAllowedForPendingConnection()
          ? bluetooth::hci::Role::CENTRAL
          : bluetooth::hci::Role::PERIPHERAL;
  connections_.SetAclRole(handle, role);
  if (IsEventUnmasked(EventCode::ROLE_CHANGE)) {
@@ -5463,7 +5466,8 @@ ErrorCode LinkLayerController::CreateConnection(const Address& addr,
                                                uint16_t /* clock_offset */,
                                                uint8_t allow_role_switch) {
  if (!connections_.CreatePendingConnection(
          addr, authentication_enable_ == AuthenticationEnable::REQUIRED)) {
          addr, authentication_enable_ == AuthenticationEnable::REQUIRED,
          allow_role_switch)) {
    return ErrorCode::CONTROLLER_BUSY;
  }

@@ -5666,6 +5670,7 @@ ErrorCode LinkLayerController::SwitchRole(Address addr,
  if (handle == rootcanal::kReservedHandle) {
    return ErrorCode::UNKNOWN_CONNECTION;
  }
  // TODO(b/274248798): Reject role switch if disabled in link policy
  SendLinkLayerPacket(model::packets::RoleSwitchRequestBuilder::Create(
      GetAddress(), addr, static_cast<uint8_t>(role)));
  return ErrorCode::SUCCESS;
@@ -5678,6 +5683,7 @@ void LinkLayerController::IncomingRoleSwitchRequest(
  auto request = model::packets::RoleSwitchRequestView::Create(incoming);
  ASSERT(request.IsValid());

  // TODO(b/274248798): Reject role switch if disabled in link policy
  Role remote_role = static_cast<Role>(request.GetInitiatorNewRole());
  Role local_role =
      remote_role == Role::CENTRAL ? Role::PERIPHERAL : Role::CENTRAL;
@@ -5688,7 +5694,6 @@ void LinkLayerController::IncomingRoleSwitchRequest(
                                                            addr, local_role));
    });
  }
  // TODO(b/274248798): Reject if role switching is not allowed
  ScheduleTask(kNoDelayMs, [this, addr, remote_role]() {
    SendLinkLayerPacket(model::packets::RoleSwitchResponseBuilder::Create(
        GetAddress(), addr, static_cast<uint8_t>(ErrorCode::SUCCESS),
@@ -5703,13 +5708,19 @@ void LinkLayerController::IncomingRoleSwitchResponse(
  auto response = model::packets::RoleSwitchResponseView::Create(incoming);
  ASSERT(response.IsValid());

  // TODO(b/274248798): Handle if role switching is not allowed
  // TODO(b/274248798): Reject role switch if disabled in link policy
  ErrorCode status = ErrorCode::SUCCESS;
  Role role = static_cast<Role>(response.GetInitiatorNewRole());
  if (response.GetStatus() == static_cast<uint8_t>(ErrorCode::SUCCESS)) {
    connections_.SetAclRole(handle, role);
  } else {
    status = static_cast<ErrorCode>(response.GetStatus());
  }

  if (IsEventUnmasked(EventCode::ROLE_CHANGE)) {
    ScheduleTask(kNoDelayMs, [this, addr, role]() {
      send_event_(bluetooth::hci::RoleChangeBuilder::Create(ErrorCode::SUCCESS,
                                                            addr, role));
    ScheduleTask(kNoDelayMs, [this, status, addr, role]() {
      send_event_(
          bluetooth::hci::RoleChangeBuilder::Create(status, addr, role));
    });
  }
}