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

Commit 36c2202d authored by Henri Chataing's avatar Henri Chataing
Browse files

Root-Canal: Fix SCO / eSCO connection bringup

- Recognize HCI command Accept Connection Request for
  accepting SCO connections
- Correct usage of negative packet type bits

Bug: 209800014
Tag: #feature
Test: cert/run
Change-Id: If9703aa2ce2aca858040798ca9dc03badbbb3bfc
parent e1e1f141
Loading
Loading
Loading
Loading
+17 −9
Original line number Diff line number Diff line
@@ -431,7 +431,7 @@ void AclConnectionHandler::CreateScoConnection(
}

bool AclConnectionHandler::HasPendingScoConnection(bluetooth::hci::Address addr) const {
  for (auto pair : sco_connections_) {
  for (const auto& pair : sco_connections_) {
    if (std::get<ScoConnection>(pair).GetAddress() == addr) {
      ScoState state = std::get<ScoConnection>(pair).GetState();
      return state == SCO_STATE_PENDING ||
@@ -443,7 +443,7 @@ bool AclConnectionHandler::HasPendingScoConnection(bluetooth::hci::Address addr)
}

ScoState AclConnectionHandler::GetScoConnectionState(bluetooth::hci::Address addr) const {
  for (auto pair : sco_connections_) {
  for (const auto& pair : sco_connections_) {
    if (std::get<ScoConnection>(pair).GetAddress() == addr) {
      return std::get<ScoConnection>(pair).GetState();
    }
@@ -452,7 +452,7 @@ ScoState AclConnectionHandler::GetScoConnectionState(bluetooth::hci::Address add
}

bool AclConnectionHandler::IsLegacyScoConnection(bluetooth::hci::Address addr) const {
  for (auto pair : sco_connections_) {
  for (const auto& pair : sco_connections_) {
    if (std::get<ScoConnection>(pair).GetAddress() == addr) {
      return std::get<ScoConnection>(pair).IsLegacy();
    }
@@ -471,8 +471,7 @@ void AclConnectionHandler::CancelPendingScoConnection(bluetooth::hci::Address ad

bool AclConnectionHandler::AcceptPendingScoConnection(bluetooth::hci::Address addr,
  ScoLinkParameters const &parameters) {

  for (auto pair : sco_connections_) {
  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);
@@ -484,8 +483,7 @@ bool AclConnectionHandler::AcceptPendingScoConnection(bluetooth::hci::Address ad

bool AclConnectionHandler::AcceptPendingScoConnection(bluetooth::hci::Address addr,
  ScoConnectionParameters const &parameters) {

  for (auto pair : sco_connections_) {
  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(
@@ -497,7 +495,7 @@ bool AclConnectionHandler::AcceptPendingScoConnection(bluetooth::hci::Address ad
}

uint16_t AclConnectionHandler::GetScoHandle(bluetooth::hci::Address addr) const {
  for (auto pair : sco_connections_) {
  for (const auto& pair : sco_connections_) {
    if (std::get<ScoConnection>(pair).GetAddress() == addr) {
      return std::get<0>(pair);
    }
@@ -505,8 +503,18 @@ uint16_t AclConnectionHandler::GetScoHandle(bluetooth::hci::Address addr) const
  return 0;
}

ScoConnectionParameters AclConnectionHandler::GetScoConnectionParameters(
    bluetooth::hci::Address addr) const {
  for (const auto& pair : sco_connections_) {
    if (std::get<ScoConnection>(pair).GetAddress() == addr) {
      return std::get<ScoConnection>(pair).GetConnectionParameters();
    }
  }
  return {};
}

ScoLinkParameters AclConnectionHandler::GetScoLinkParameters(bluetooth::hci::Address addr) const {
  for (auto pair : sco_connections_) {
  for (const auto& pair : sco_connections_) {
    if (std::get<ScoConnection>(pair).GetAddress() == addr) {
      return std::get<ScoConnection>(pair).GetLinkParameters();
    }
+2 −0
Original line number Diff line number Diff line
@@ -53,6 +53,8 @@ class AclConnectionHandler {
  bool AcceptPendingScoConnection(bluetooth::hci::Address addr,
    ScoConnectionParameters const &parameters);
  uint16_t GetScoHandle(bluetooth::hci::Address addr) const;
  ScoConnectionParameters GetScoConnectionParameters(
      bluetooth::hci::Address addr) const;
  ScoLinkParameters GetScoLinkParameters(bluetooth::hci::Address addr) const;

  bool CreatePendingLeConnection(bluetooth::hci::AddressWithType addr);
+61 −15
Original line number Diff line number Diff line
@@ -1505,9 +1505,11 @@ void LinkLayerController::IncomingScoConnectionResponse(
          bluetooth::hci::LinkType::SCO,
          bluetooth::hci::Enable::DISABLED));
    } else {
      ScoConnectionParameters connection_parameters =
          connections_.GetScoConnectionParameters(address);
      send_event_(bluetooth::hci::SynchronousConnectionCompleteBuilder::Create(
          status, 0, address,
          response.GetExtended() ?
          connection_parameters.IsExtended() ?
            bluetooth::hci::ScoLinkType::ESCO :
            bluetooth::hci::ScoLinkType::SCO,
          0, 0, 0, 0, bluetooth::hci::ScoAirMode::TRANSPARENT));
@@ -2571,22 +2573,61 @@ ErrorCode LinkLayerController::SetConnectionEncryption(
  return ErrorCode::SUCCESS;
}

ErrorCode LinkLayerController::AcceptConnectionRequest(const Address& addr,
ErrorCode LinkLayerController::AcceptConnectionRequest(const Address& bd_addr,
                                                       bool try_role_switch) {
  if (!connections_.HasPendingConnection(addr)) {
    LOG_INFO("No pending connection for %s", addr.ToString().c_str());
    return ErrorCode::UNKNOWN_CONNECTION;
  if (connections_.HasPendingConnection(bd_addr)) {
    LOG_INFO("Accepting connection request from %s",
             bd_addr.ToString().c_str());
    ScheduleTask(kLongDelayMs, [this, bd_addr, try_role_switch]() {
      LOG_INFO("Accepted connection from %s", bd_addr.ToString().c_str());
      MakePeripheralConnection(bd_addr, try_role_switch);
    });

    return ErrorCode::SUCCESS;
  }

  LOG_INFO("Accept in 200ms");
  ScheduleTask(kLongDelayMs, [this, addr, try_role_switch]() {
    LOG_INFO("Accepted");
    MakePeripheralConnection(addr, try_role_switch);
  // The HCI command Accept Connection may be used to accept incoming SCO
  // connection requests.
  if (connections_.HasPendingScoConnection(bd_addr)) {
    ErrorCode status = ErrorCode::SUCCESS;
    uint16_t sco_handle = 0;
    ScoLinkParameters link_parameters = {};
    ScoConnectionParameters connection_parameters =
        connections_.GetScoConnectionParameters(bd_addr);

    if (!connections_.AcceptPendingScoConnection(
          bd_addr, connection_parameters)) {
      connections_.CancelPendingScoConnection(bd_addr);
      status = ErrorCode::SCO_INTERVAL_REJECTED;  // TODO: proper status code
    } else {
      sco_handle = connections_.GetScoHandle(bd_addr);
      link_parameters = connections_.GetScoLinkParameters(bd_addr);
    }

    // Send eSCO connection response to peer.
    SendLinkLayerPacket(model::packets::ScoConnectionResponseBuilder::Create(
        properties_.GetAddress(), bd_addr, (uint8_t)status,
        link_parameters.transmission_interval,
        link_parameters.retransmission_window,
        link_parameters.rx_packet_length,
        link_parameters.tx_packet_length,
        link_parameters.air_mode,
        link_parameters.extended));

    // Schedule HCI Connection Complete event.
    ScheduleTask(kShortDelayMs, [this, status, sco_handle, bd_addr]() {
      send_event_(bluetooth::hci::ConnectionCompleteBuilder::Create(
          ErrorCode(status), sco_handle, bd_addr, bluetooth::hci::LinkType::SCO,
          bluetooth::hci::Enable::DISABLED));
    });

    return ErrorCode::SUCCESS;
  }

  LOG_INFO("No pending connection for %s", bd_addr.ToString().c_str());
  return ErrorCode::UNKNOWN_CONNECTION;
}

void LinkLayerController::MakePeripheralConnection(const Address& addr,
                                                   bool try_role_switch) {
  LOG_INFO("Sending page response to %s", addr.ToString().c_str());
@@ -3660,7 +3701,12 @@ ErrorCode LinkLayerController::AddScoConnection(
  ScoConnectionParameters connection_parameters = {
      8000, 8000, 0xffff, 0x60 /* 16bit CVSD */,
      (uint8_t)bluetooth::hci::RetransmissionEffort::NO_RETRANSMISSION,
    (uint16_t)((packet_type >> 5) & 0x7u)
      (uint16_t)(
        (uint16_t)((packet_type >> 5) & 0x7u) |
        (uint16_t)bluetooth::hci::SynchronousPacketTypeBits::NO_2_EV3_ALLOWED |
        (uint16_t)bluetooth::hci::SynchronousPacketTypeBits::NO_3_EV3_ALLOWED |
        (uint16_t)bluetooth::hci::SynchronousPacketTypeBits::NO_2_EV5_ALLOWED |
        (uint16_t)bluetooth::hci::SynchronousPacketTypeBits::NO_3_EV5_ALLOWED)
  };
  connections_.CreateScoConnection(
      connections_.GetAddress(connection_handle).GetAddress(),
@@ -3746,7 +3792,7 @@ ErrorCode LinkLayerController::AcceptSynchronousConnection(

  if (!connections_.AcceptPendingScoConnection(bd_addr, connection_parameters)) {
    connections_.CancelPendingScoConnection(bd_addr);
    status = ErrorCode::SCO_INTERVAL_REJECTED; // TODO: proper status code
    status = ErrorCode::STATUS_UNKNOWN;  // TODO: proper status code
  } else {
    sco_handle = connections_.GetScoHandle(bd_addr);
    link_parameters = connections_.GetScoLinkParameters(bd_addr);
+11 −3
Original line number Diff line number Diff line
@@ -29,7 +29,12 @@ bool ScoConnectionParameters::IsExtended() {
    (uint16_t)SynchronousPacketTypeBits::HV1_ALLOWED |
    (uint16_t)SynchronousPacketTypeBits::HV2_ALLOWED |
    (uint16_t)SynchronousPacketTypeBits::HV3_ALLOWED;
  return (packet_type & ~legacy) != 0;
  uint16_t edr =
    (uint16_t)SynchronousPacketTypeBits::NO_2_EV3_ALLOWED |
    (uint16_t)SynchronousPacketTypeBits::NO_3_EV3_ALLOWED |
    (uint16_t)SynchronousPacketTypeBits::NO_2_EV5_ALLOWED |
    (uint16_t)SynchronousPacketTypeBits::NO_3_EV5_ALLOWED;
  return ((packet_type ^ edr) & ~legacy) != 0;
}

std::optional<ScoLinkParameters> ScoConnectionParameters::GetLinkParameters() {
@@ -165,6 +170,7 @@ std::optional<ScoLinkParameters> ScoConnectionParameters::GetLinkParameters() {

  if (retransmission_effort == (uint8_t)RetransmissionEffort::OPTIMIZED_FOR_POWER ||
      retransmission_effort == (uint8_t)RetransmissionEffort::OPTIMIZED_FOR_LINK_QUALITY) {
    LOG_WARN("SCO Retransmission effort must be None or Don't care");
    return {};
  }

@@ -174,6 +180,7 @@ std::optional<ScoLinkParameters> ScoConnectionParameters::GetLinkParameters() {
  uint8_t air_coding = voice_setting & 0x3;

  if (max_latency != 0xffff && max_latency < latency) {
    LOG_WARN("SCO Max latency must be less than 1250 us");
    return {};
  }

@@ -183,10 +190,11 @@ std::optional<ScoLinkParameters> ScoConnectionParameters::GetLinkParameters() {
  } else if (packet_type & (uint16_t)SynchronousPacketTypeBits::HV2_ALLOWED) {
    transmission_interval = 4;
    packet_length = 20;
  } else if (packet_type & (uint16_t)SynchronousPacketTypeBits::HV3_ALLOWED) {
  } else if (packet_type & (uint16_t)SynchronousPacketTypeBits::HV1_ALLOWED) {
    transmission_interval = 2;
    packet_length = 10;
  } else {
    LOG_WARN("No SCO packet type enabled");
    return {};
  }

@@ -225,7 +233,7 @@ bool ScoConnection::NegotiateLinkParameters(ScoConnectionParameters const &peer)
  uint16_t packet_type = (peer.packet_type & parameters_.packet_type) & 0x3f;
  packet_type |= (peer.packet_type | parameters_.packet_type) & 0x3c0;

  if (packet_type == 0) {
  if (packet_type == 0x3c0) {
    LOG_WARN("Packet type requirements cannot be met");
    LOG_WARN("Remote packet type: 0x%04x",
             static_cast<unsigned>(parameters_.packet_type));