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

Commit dc631d83 authored by Rahul Arya's avatar Rahul Arya Committed by Thomas Girardier
Browse files

[Rootcanal] Spoof SCO packets on offload path

If we are using SCO-over-HCI, no behavioral change. Otherwise, when a
SCO connection is up, we will send garbage data to the other side. This
is needed for PTS tests, and exercises the same code paths in the stack
as would be the case on real devices (since the datapath goes via the
modem, DSP, and then controller, skipping the AP entirely).

Tracking bug b/238708237 for a more realistic audio path using the
modem_simulator.

Bug: 245578454
Test: atest pts-bot
Ignore-AOSP-First: Cherry-picked from AOSP
Merged-In: Idd4457437a2aadc9743884908cd3413da1aefb40
Change-Id: Idd4457437a2aadc9743884908cd3413da1aefb40
parent fe57e5d2
Loading
Loading
Loading
Loading
+20 −6
Original line number Diff line number Diff line
@@ -27,6 +27,12 @@ using ::bluetooth::hci::Address;
using ::bluetooth::hci::AddressType;
using ::bluetooth::hci::AddressWithType;

void AclConnectionHandler::RegisterTaskScheduler(
    std::function<AsyncTaskId(std::chrono::milliseconds, const TaskCallback&)>
        event_scheduler) {
  schedule_task_ = event_scheduler;
}

bool AclConnectionHandler::HasHandle(uint16_t handle) const {
  return acl_connections_.count(handle) != 0;
}
@@ -148,8 +154,10 @@ uint16_t AclConnectionHandler::CreateLeConnection(AddressWithType addr,
  return kReservedHandle;
}

bool AclConnectionHandler::Disconnect(uint16_t handle) {
bool AclConnectionHandler::Disconnect(
    uint16_t handle, std::function<void(AsyncTaskId)> stopStream) {
  if (HasScoHandle(handle)) {
    sco_connections_.at(handle).StopStream(std::move(stopStream));
    sco_connections_.erase(handle);
    return true;
  }
@@ -452,10 +460,10 @@ StreamParameters AclConnectionHandler::GetStreamParameters(

void AclConnectionHandler::CreateScoConnection(
    bluetooth::hci::Address addr, ScoConnectionParameters const& parameters,
    ScoState state, bool legacy) {
    ScoState state, ScoDatapath datapath, bool legacy) {
  uint16_t sco_handle = GetUnusedHandle();
  sco_connections_.emplace(sco_handle,
                           ScoConnection(addr, parameters, state, legacy));
  sco_connections_.emplace(
      sco_handle, ScoConnection(addr, parameters, state, datapath, legacy));
}

bool AclConnectionHandler::HasPendingScoConnection(
@@ -502,11 +510,13 @@ void AclConnectionHandler::CancelPendingScoConnection(
}

bool AclConnectionHandler::AcceptPendingScoConnection(
    bluetooth::hci::Address addr, ScoLinkParameters const& parameters) {
    bluetooth::hci::Address addr, ScoLinkParameters const& parameters,
    std::function<AsyncTaskId()> startStream) {
  for (auto& pair : sco_connections_) {
    if (std::get<ScoConnection>(pair).GetAddress() == addr) {
      std::get<ScoConnection>(pair).SetLinkParameters(parameters);
      std::get<ScoConnection>(pair).SetState(ScoState::SCO_STATE_OPENED);
      std::get<ScoConnection>(pair).StartStream(std::move(startStream));
      return true;
    }
  }
@@ -514,13 +524,17 @@ bool AclConnectionHandler::AcceptPendingScoConnection(
}

bool AclConnectionHandler::AcceptPendingScoConnection(
    bluetooth::hci::Address addr, ScoConnectionParameters const& parameters) {
    bluetooth::hci::Address addr, ScoConnectionParameters const& parameters,
    std::function<AsyncTaskId()> startStream) {
  for (auto& pair : sco_connections_) {
    if (std::get<ScoConnection>(pair).GetAddress() == addr) {
      bool ok =
          std::get<ScoConnection>(pair).NegotiateLinkParameters(parameters);
      std::get<ScoConnection>(pair).SetState(ok ? ScoState::SCO_STATE_OPENED
                                                : ScoState::SCO_STATE_CLOSED);
      if (ok) {
        std::get<ScoConnection>(pair).StartStream(std::move(startStream));
      }
      return ok;
    }
  }
+16 −4
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

#pragma once

#include <chrono>
#include <cstdint>
#include <set>
#include <unordered_map>
@@ -24,6 +25,7 @@
#include "hci/address.h"
#include "hci/address_with_type.h"
#include "isochronous_connection_handler.h"
#include "model/setup/async_manager.h"
#include "phy.h"
#include "sco_connection.h"

@@ -36,6 +38,10 @@ class AclConnectionHandler {

  virtual ~AclConnectionHandler() = default;

  void RegisterTaskScheduler(
      std::function<AsyncTaskId(std::chrono::milliseconds, const TaskCallback&)>
          event_scheduler);

  bool CreatePendingConnection(bluetooth::hci::Address addr,
                               bool authenticate_on_connect);
  bool HasPendingConnection(bluetooth::hci::Address addr) const;
@@ -47,12 +53,15 @@ class AclConnectionHandler {
  bool IsLegacyScoConnection(bluetooth::hci::Address addr) const;
  void CreateScoConnection(bluetooth::hci::Address addr,
                           ScoConnectionParameters const& parameters,
                           ScoState state, bool legacy = false);
                           ScoState state, ScoDatapath datapath,
                           bool legacy = false);
  void CancelPendingScoConnection(bluetooth::hci::Address addr);
  bool AcceptPendingScoConnection(bluetooth::hci::Address addr,
                                  ScoLinkParameters const& parameters);
                                  ScoLinkParameters const& parameters,
                                  std::function<AsyncTaskId()> startStream);
  bool AcceptPendingScoConnection(bluetooth::hci::Address addr,
                                  ScoConnectionParameters const& parameters);
                                  ScoConnectionParameters const& parameters,
                                  std::function<AsyncTaskId()> startStream);
  uint16_t GetScoHandle(bluetooth::hci::Address addr) const;
  ScoConnectionParameters GetScoConnectionParameters(
      bluetooth::hci::Address addr) const;
@@ -69,7 +78,7 @@ class AclConnectionHandler {
  uint16_t CreateLeConnection(bluetooth::hci::AddressWithType addr,
                              bluetooth::hci::AddressWithType own_addr,
                              bluetooth::hci::Role role);
  bool Disconnect(uint16_t handle);
  bool Disconnect(uint16_t handle, std::function<void(AsyncTaskId)> stopStream);
  bool HasHandle(uint16_t handle) const;
  bool HasScoHandle(uint16_t handle) const;

@@ -143,6 +152,9 @@ class AclConnectionHandler {
  std::unordered_map<uint16_t, AclConnection> acl_connections_;
  std::unordered_map<uint16_t, ScoConnection> sco_connections_;

  std::function<AsyncTaskId(std::chrono::milliseconds, const TaskCallback&)>
      schedule_task_;

  bool classic_connection_pending_{false};
  bluetooth::hci::Address pending_connection_address_{
      bluetooth::hci::Address::kEmpty};
+14 −11
Original line number Diff line number Diff line
@@ -665,7 +665,8 @@ void DualModeController::AddScoConnection(CommandView command) {
  ASSERT(command_view.IsValid());

  auto status = link_layer_controller_.AddScoConnection(
      command_view.GetConnectionHandle(), command_view.GetPacketType());
      command_view.GetConnectionHandle(), command_view.GetPacketType(),
      ScoDatapath::NORMAL);

  send_event_(bluetooth::hci::AddScoConnectionStatusBuilder::Create(
      status, kNumCommandPackets));
@@ -682,7 +683,7 @@ void DualModeController::SetupSynchronousConnection(CommandView command) {
      command_view.GetReceiveBandwidth(), command_view.GetMaxLatency(),
      command_view.GetVoiceSetting(),
      static_cast<uint8_t>(command_view.GetRetransmissionEffort()),
      command_view.GetPacketType());
      command_view.GetPacketType(), ScoDatapath::NORMAL);

  send_event_(bluetooth::hci::SetupSynchronousConnectionStatusBuilder::Create(
      status, kNumCommandPackets));
@@ -762,15 +763,17 @@ void DualModeController::EnhancedSetupSynchronousConnection(
  }

  // Root-Canal does not implement audio data transport paths other than the
  // default HCI transport.
  // default HCI transport - other transports will receive spoofed data
  ScoDatapath datapath = ScoDatapath::NORMAL;
  if (command_view.GetInputDataPath() != bluetooth::hci::ScoDataPath::HCI ||
      command_view.GetOutputDataPath() != bluetooth::hci::ScoDataPath::HCI) {
    LOG_INFO(
        "EnhancedSetupSynchronousConnection: rejected Input_Data_Path (%u)"
        " and/or Output_Data_Path (%u) as they are un-implemented",
    LOG_WARN(
        "EnhancedSetupSynchronousConnection: Input_Data_Path (%u)"
        " and/or Output_Data_Path (%u) are not over HCI, so data will be "
        "spoofed",
        static_cast<unsigned>(command_view.GetInputDataPath()),
        static_cast<unsigned>(command_view.GetOutputDataPath()));
    status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS;
    datapath = ScoDatapath::SPOOFED;
  }

  // Either both the Transmit_Coding_Format and Input_Coding_Format shall be
@@ -842,7 +845,7 @@ void DualModeController::EnhancedSetupSynchronousConnection(
        command_view.GetConnectionHandle(), transmit_bandwidth,
        receive_bandwidth, command_view.GetMaxLatency(), 0 /* Voice_Setting */,
        static_cast<uint8_t>(command_view.GetRetransmissionEffort()),
        command_view.GetPacketType());
        command_view.GetPacketType(), datapath);
  }

  send_event_(
@@ -911,11 +914,11 @@ void DualModeController::EnhancedAcceptSynchronousConnection(
  if (command_view.GetInputDataPath() != bluetooth::hci::ScoDataPath::HCI ||
      command_view.GetOutputDataPath() != bluetooth::hci::ScoDataPath::HCI) {
    LOG_INFO(
        "EnhancedAcceptSynchronousConnection: rejected Input_Data_Path (%u)"
        " and/or Output_Data_Path (%u) as they are un-implemented",
        "EnhancedSetupSynchronousConnection: Input_Data_Path (%u)"
        " and/or Output_Data_Path (%u) are not over HCI, so data will be "
        "spoofed",
        static_cast<unsigned>(command_view.GetInputDataPath()),
        static_cast<unsigned>(command_view.GetOutputDataPath()));
    status = ErrorCode::INVALID_HCI_COMMAND_PARAMETERS;
  }

  // Either both the Transmit_Coding_Format and Input_Coding_Format shall be
+56 −15
Original line number Diff line number Diff line
@@ -2073,7 +2073,7 @@ void LinkLayerController::IncomingDisconnectPacket(
#ifdef ROOTCANAL_LMP
  auto is_br_edr = connections_.GetPhyType(handle) == Phy::Type::BR_EDR;
#endif
  ASSERT_LOG(connections_.Disconnect(handle),
  ASSERT_LOG(connections_.Disconnect(handle, cancel_task_),
             "GetHandle() returned invalid handle %hx", handle);

  uint8_t reason = disconnect.GetReason();
@@ -3579,7 +3579,8 @@ void LinkLayerController::IncomingScoConnectionRequest(
  connections_.CreateScoConnection(
      address, connection_parameters,
      extended ? ScoState::SCO_STATE_SENT_ESCO_CONNECTION_REQUEST
               : ScoState::SCO_STATE_SENT_SCO_CONNECTION_REQUEST);
               : ScoState::SCO_STATE_SENT_SCO_CONNECTION_REQUEST,
      ScoDatapath::NORMAL);

  // Send connection request event and wait for Accept or Reject command.
  send_event_(bluetooth::hci::ConnectionRequestBuilder::Create(
@@ -3610,7 +3611,12 @@ void LinkLayerController::IncomingScoConnectionResponse(
        response.GetAirMode(),
        extended,
    };
    connections_.AcceptPendingScoConnection(address, link_parameters);

    connections_.AcceptPendingScoConnection(
        address, link_parameters, [this, address] {
          return LinkLayerController::StartScoStream(address);
        });

    if (is_legacy) {
      send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create(
          ErrorCode::SUCCESS, connections_.GetScoHandle(address), address,
@@ -3659,7 +3665,7 @@ void LinkLayerController::IncomingScoDisconnect(
      incoming.GetSourceAddress().ToString().c_str());

  if (handle != kReservedHandle) {
    connections_.Disconnect(handle);
    connections_.Disconnect(handle, cancel_task_);
    SendDisconnectionCompleteEvent(handle, ErrorCode(reason));
  }
}
@@ -4821,6 +4827,17 @@ AsyncTaskId LinkLayerController::ScheduleTask(milliseconds delay_ms,
  }
}

AsyncTaskId LinkLayerController::SchedulePeriodicTask(
    milliseconds delay_ms, milliseconds period_ms,
    const TaskCallback& callback) {
  if (schedule_periodic_task_) {
    return schedule_periodic_task_(delay_ms, period_ms, callback);
  } else {
    LOG_ERROR("Unable to schedule task on delay");
    return 0;
  }
}

void LinkLayerController::RegisterPeriodicTaskScheduler(
    std::function<AsyncTaskId(milliseconds, milliseconds, const TaskCallback&)>
        periodic_event_scheduler) {
@@ -5328,8 +5345,10 @@ ErrorCode LinkLayerController::AcceptConnectionRequest(const Address& bd_addr,
    ScoConnectionParameters connection_parameters =
        connections_.GetScoConnectionParameters(bd_addr);

    if (!connections_.AcceptPendingScoConnection(bd_addr,
                                                 connection_parameters)) {
    if (!connections_.AcceptPendingScoConnection(
            bd_addr, connection_parameters, [this, bd_addr] {
              return LinkLayerController::StartScoStream(bd_addr);
            })) {
      connections_.CancelPendingScoConnection(bd_addr);
      status = ErrorCode::SCO_INTERVAL_REJECTED;  // TODO: proper status code
    } else {
@@ -5462,7 +5481,7 @@ ErrorCode LinkLayerController::Disconnect(uint16_t handle, ErrorCode reason) {
    SendLinkLayerPacket(model::packets::ScoDisconnectBuilder::Create(
        GetAddress(), remote, static_cast<uint8_t>(reason)));

    connections_.Disconnect(handle);
    connections_.Disconnect(handle, cancel_task_);
    SendDisconnectionCompleteEvent(handle, reason);
    return ErrorCode::SUCCESS;
  }
@@ -5482,7 +5501,7 @@ ErrorCode LinkLayerController::Disconnect(uint16_t handle, ErrorCode reason) {
      SendLinkLayerPacket(model::packets::ScoDisconnectBuilder::Create(
          GetAddress(), remote.GetAddress(), static_cast<uint8_t>(reason)));

      connections_.Disconnect(sco_handle);
      connections_.Disconnect(sco_handle, cancel_task_);
      SendDisconnectionCompleteEvent(sco_handle, reason);
    }

@@ -5496,7 +5515,7 @@ ErrorCode LinkLayerController::Disconnect(uint16_t handle, ErrorCode reason) {
        static_cast<uint8_t>(reason)));
  }

  connections_.Disconnect(handle);
  connections_.Disconnect(handle, cancel_task_);
  SendDisconnectionCompleteEvent(handle, ErrorCode(reason));
#ifdef ROOTCANAL_LMP
  if (is_br_edr) {
@@ -6182,7 +6201,8 @@ void LinkLayerController::SetPageTimeout(uint16_t page_timeout) {
}

ErrorCode LinkLayerController::AddScoConnection(uint16_t connection_handle,
                                                uint16_t packet_type) {
                                                uint16_t packet_type,
                                                ScoDatapath datapath) {
  if (!connections_.HasHandle(connection_handle)) {
    return ErrorCode::UNKNOWN_CONNECTION;
  }
@@ -6212,7 +6232,7 @@ ErrorCode LinkLayerController::AddScoConnection(uint16_t connection_handle,
                     NO_3_EV5_ALLOWED)};
  connections_.CreateScoConnection(
      connections_.GetAddress(connection_handle).GetAddress(),
      connection_parameters, SCO_STATE_PENDING, true);
      connection_parameters, SCO_STATE_PENDING, datapath, true);

  // Send SCO connection request to peer.
  SendLinkLayerPacket(model::packets::ScoConnectionRequestBuilder::Create(
@@ -6227,7 +6247,8 @@ ErrorCode LinkLayerController::AddScoConnection(uint16_t connection_handle,
ErrorCode LinkLayerController::SetupSynchronousConnection(
    uint16_t connection_handle, uint32_t transmit_bandwidth,
    uint32_t receive_bandwidth, uint16_t max_latency, uint16_t voice_setting,
    uint8_t retransmission_effort, uint16_t packet_types) {
    uint8_t retransmission_effort, uint16_t packet_types,
    ScoDatapath datapath) {
  if (!connections_.HasHandle(connection_handle)) {
    return ErrorCode::UNKNOWN_CONNECTION;
  }
@@ -6248,7 +6269,7 @@ ErrorCode LinkLayerController::SetupSynchronousConnection(
      voice_setting,      retransmission_effort, packet_types};
  connections_.CreateScoConnection(
      connections_.GetAddress(connection_handle).GetAddress(),
      connection_parameters, SCO_STATE_PENDING);
      connection_parameters, SCO_STATE_PENDING, datapath);

  // Send eSCO connection request to peer.
  SendLinkLayerPacket(model::packets::ScoConnectionRequestBuilder::Create(
@@ -6276,8 +6297,10 @@ ErrorCode LinkLayerController::AcceptSynchronousConnection(
      transmit_bandwidth, receive_bandwidth,     max_latency,
      voice_setting,      retransmission_effort, packet_types};

  if (!connections_.AcceptPendingScoConnection(bd_addr,
                                               connection_parameters)) {
  if (!connections_.AcceptPendingScoConnection(
          bd_addr, connection_parameters, [this, bd_addr] {
            return LinkLayerController::StartScoStream(bd_addr);
          })) {
    connections_.CancelPendingScoConnection(bd_addr);
    status = ErrorCode::STATUS_UNKNOWN;  // TODO: proper status code
  } else {
@@ -6372,4 +6395,22 @@ void LinkLayerController::IncomingPingRequest(
      packet.GetDestinationAddress(), packet.GetSourceAddress()));
}

AsyncTaskId LinkLayerController::StartScoStream(Address address) {
  auto sco_builder = bluetooth::hci::ScoBuilder::Create(
      connections_.GetScoHandle(address), PacketStatusFlag::CORRECTLY_RECEIVED,
      {0, 0, 0, 0, 0});

  auto bytes = std::make_shared<std::vector<uint8_t>>();
  bluetooth::packet::BitInserter bit_inserter(*bytes);
  sco_builder->Serialize(bit_inserter);
  auto raw_view =
      bluetooth::hci::PacketView<bluetooth::hci::kLittleEndian>(bytes);
  auto sco_view = bluetooth::hci::ScoView::Create(raw_view);
  ASSERT(sco_view.IsValid());

  return SchedulePeriodicTask(0ms, 20ms, [this, address, sco_view]() {
    LOG_INFO("SCO sending...");
    SendScoToRemote(sco_view);
  });
}
}  // namespace rootcanal
+10 −2
Original line number Diff line number Diff line
@@ -149,6 +149,10 @@ class LinkLayerController {
  AsyncTaskId ScheduleTask(std::chrono::milliseconds delay_ms,
                           const TaskCallback& task);

  AsyncTaskId SchedulePeriodicTask(std::chrono::milliseconds delay_ms,
                                   std::chrono::milliseconds period_ms,
                                   const TaskCallback& callback);

  void CancelScheduledTask(AsyncTaskId task);

  // Set the callbacks for sending packets to the HCI.
@@ -344,11 +348,13 @@ class LinkLayerController {
  void ReadLocalOobData();
  void ReadLocalOobExtendedData();

  ErrorCode AddScoConnection(uint16_t connection_handle, uint16_t packet_type);
  ErrorCode AddScoConnection(uint16_t connection_handle, uint16_t packet_type,
                             ScoDatapath datapath);
  ErrorCode SetupSynchronousConnection(
      uint16_t connection_handle, uint32_t transmit_bandwidth,
      uint32_t receive_bandwidth, uint16_t max_latency, uint16_t voice_setting,
      uint8_t retransmission_effort, uint16_t packet_types);
      uint8_t retransmission_effort, uint16_t packet_types,
      ScoDatapath datapath);
  ErrorCode AcceptSynchronousConnection(
      Address bd_addr, uint32_t transmit_bandwidth, uint32_t receive_bandwidth,
      uint16_t max_latency, uint16_t voice_setting,
@@ -767,6 +773,8 @@ class LinkLayerController {
    le_suggested_max_tx_time_ = max_tx_time;
  }

  AsyncTaskId StartScoStream(Address address);

 private:
  const Address& address_;
  const ControllerProperties& properties_;
Loading