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

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

RootCanal: Notify role change to remote

Bug: 272713533
Test: avatar
Test: atest pts-bot
Change-Id: I9de2591ca5a2156c7792a997823f15cd3fd5716c
parent 30666482
Loading
Loading
Loading
Loading
+84 −7
Original line number Diff line number Diff line
@@ -1817,6 +1817,12 @@ void LinkLayerController::IncomingPacket(
    case model::packets::PacketType::PING_RESPONSE:
      // ping responses require no action
      break;
    case model::packets::PacketType::ROLE_SWITCH_REQUEST:
      IncomingRoleSwitchRequest(incoming);
      break;
    case model::packets::PacketType::ROLE_SWITCH_RESPONSE:
      IncomingRoleSwitchResponse(incoming);
      break;
    default:
      LOG_WARN("Dropping unhandled packet of type %s",
               model::packets::PacketTypeText(incoming.GetType()).c_str());
@@ -4778,10 +4784,27 @@ void LinkLayerController::IncomingPageResponsePacket(

  CheckExpiringConnection(handle);

  auto addr = incoming.GetSourceAddress();
  auto response = model::packets::PageResponseView::Create(incoming);
  ASSERT(response.IsValid());
  /* Role change event before connection complete is a quirk commonly exists in
   * 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()) {
    auto role = bluetooth::hci::Role::PERIPHERAL;
    connections_.SetAclRole(handle, role);
    if (IsEventUnmasked(EventCode::ROLE_CHANGE)) {
      send_event_(bluetooth::hci::RoleChangeBuilder::Create(ErrorCode::SUCCESS,
                                                            addr, role));
    }
  }
  if (IsEventUnmasked(EventCode::CONNECTION_COMPLETE)) {
    send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create(
        ErrorCode::SUCCESS, handle, incoming.GetSourceAddress(),
        bluetooth::hci::LinkType::ACL, bluetooth::hci::Enable::DISABLED));
        ErrorCode::SUCCESS, handle, addr, bluetooth::hci::LinkType::ACL,
        bluetooth::hci::Enable::DISABLED));
  }

#ifndef ROOTCANAL_LMP
@@ -5384,6 +5407,20 @@ void LinkLayerController::MakePeripheralConnection(const Address& addr,

  CheckExpiringConnection(handle);

  /* Role change event before connection complete is a quirk commonly exists in
   * 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
                              : bluetooth::hci::Role::PERIPHERAL;
  connections_.SetAclRole(handle, role);
  if (IsEventUnmasked(EventCode::ROLE_CHANGE)) {
    send_event_(bluetooth::hci::RoleChangeBuilder::Create(ErrorCode::SUCCESS,
                                                          addr, role));
  }

  LOG_INFO("CreateConnection returned handle 0x%x", handle);
  if (IsEventUnmasked(EventCode::CONNECTION_COMPLETE)) {
    send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create(
@@ -5629,12 +5666,52 @@ ErrorCode LinkLayerController::SwitchRole(Address addr,
  if (handle == rootcanal::kReservedHandle) {
    return ErrorCode::UNKNOWN_CONNECTION;
  }
  SendLinkLayerPacket(model::packets::RoleSwitchRequestBuilder::Create(
      GetAddress(), addr, static_cast<uint8_t>(role)));
  return ErrorCode::SUCCESS;
}

void LinkLayerController::IncomingRoleSwitchRequest(
    model::packets::LinkLayerPacketView incoming) {
  auto addr = incoming.GetSourceAddress();
  auto handle = connections_.GetHandleOnlyAddress(addr);
  auto request = model::packets::RoleSwitchRequestView::Create(incoming);
  ASSERT(request.IsValid());

  Role remote_role = static_cast<Role>(request.GetInitiatorNewRole());
  Role local_role =
      remote_role == Role::CENTRAL ? Role::PERIPHERAL : Role::CENTRAL;
  connections_.SetAclRole(handle, local_role);
  if (IsEventUnmasked(EventCode::ROLE_CHANGE)) {
    ScheduleTask(kNoDelayMs, [this, addr, local_role]() {
      send_event_(bluetooth::hci::RoleChangeBuilder::Create(ErrorCode::SUCCESS,
                                                            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),
        static_cast<uint8_t>(remote_role)));
  });
}

void LinkLayerController::IncomingRoleSwitchResponse(
    model::packets::LinkLayerPacketView incoming) {
  auto addr = incoming.GetSourceAddress();
  auto handle = connections_.GetHandleOnlyAddress(addr);
  auto response = model::packets::RoleSwitchResponseView::Create(incoming);
  ASSERT(response.IsValid());

  // TODO(b/274248798): Handle if role switching is not allowed
  Role role = static_cast<Role>(response.GetInitiatorNewRole());
  connections_.SetAclRole(handle, role);
  if (IsEventUnmasked(EventCode::ROLE_CHANGE)) {
    ScheduleTask(kNoDelayMs, [this, addr, role]() {
      send_event_(bluetooth::hci::RoleChangeBuilder::Create(ErrorCode::SUCCESS,
                                                            addr, role));
    });
  return ErrorCode::SUCCESS;
  }
}

ErrorCode LinkLayerController::ReadLinkPolicySettings(uint16_t handle,
+2 −0
Original line number Diff line number Diff line
@@ -680,6 +680,8 @@ class LinkLayerController {
  void IncomingScoDisconnect(model::packets::LinkLayerPacketView incoming);

  void IncomingPingRequest(model::packets::LinkLayerPacketView incoming);
  void IncomingRoleSwitchRequest(model::packets::LinkLayerPacketView incoming);
  void IncomingRoleSwitchResponse(model::packets::LinkLayerPacketView incoming);

 public:
  bool IsEventUnmasked(bluetooth::hci::EventCode event) const;
+11 −0
Original line number Diff line number Diff line
@@ -63,6 +63,8 @@ enum PacketType : 8 {

    PING_REQUEST = 0x35,
    PING_RESPONSE = 0x36,
    ROLE_SWITCH_REQUEST = 0x38,
    ROLE_SWITCH_RESPONSE = 0x39,
}

packet LinkLayerPacket {
@@ -455,3 +457,12 @@ packet PingRequest : LinkLayerPacket (type = PING_REQUEST) {

packet PingResponse : LinkLayerPacket (type = PING_RESPONSE) {
}

packet RoleSwitchRequest : LinkLayerPacket (type = ROLE_SWITCH_REQUEST) {
  initiator_new_role: 8,
}

packet RoleSwitchResponse : LinkLayerPacket (type = ROLE_SWITCH_RESPONSE) {
  status: 8,
  initiator_new_role: 8,
}