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

Commit af068eb6 authored by Henri Chataing's avatar Henri Chataing Committed by Gerrit Code Review
Browse files

Merge "Root-Canal: Handle eSCO disconnection requests"

parents 12980442 663670dc
Loading
Loading
Loading
Loading
+24 −4
Original line number Diff line number Diff line
@@ -31,8 +31,12 @@ bool AclConnectionHandler::HasHandle(uint16_t handle) const {
  return acl_connections_.count(handle) != 0;
}

bool AclConnectionHandler::HasScoHandle(uint16_t handle) const {
  return sco_connections_.count(handle) != 0;
}

uint16_t AclConnectionHandler::GetUnusedHandle() {
  while (HasHandle(last_handle_) ||
  while (HasHandle(last_handle_) || HasScoHandle(last_handle_) ||
         isochronous_connection_handler_.HasHandle(last_handle_)) {
    last_handle_ = (last_handle_ + 1) % kReservedHandle;
  }
@@ -131,7 +135,18 @@ uint16_t AclConnectionHandler::CreateLeConnection(AddressWithType addr,
}

bool AclConnectionHandler::Disconnect(uint16_t handle) {
  return acl_connections_.erase(handle) > 0;
  if (HasScoHandle(handle)) {
    sco_connections_.erase(handle);
    return true;
  }
  if (HasHandle(handle)) {
    // It is the responsibility of the caller to remove SCO connections
    // with connected peer first.
    ASSERT(GetScoHandle(GetAddress(handle).GetAddress()) == 0);
    acl_connections_.erase(handle);
    return true;
  }
  return false;
}

uint16_t AclConnectionHandler::GetHandle(AddressWithType addr) const {
@@ -154,12 +169,17 @@ uint16_t AclConnectionHandler::GetHandleOnlyAddress(
}

AddressWithType AclConnectionHandler::GetAddress(uint16_t handle) const {
  ASSERT_LOG(HasHandle(handle), "Handle unknown %hd", handle);
  ASSERT_LOG(HasHandle(handle), "Unknown handle %hd", handle);
  return acl_connections_.at(handle).GetAddress();
}

Address AclConnectionHandler::GetScoAddress(uint16_t handle) const {
  ASSERT_LOG(HasScoHandle(handle), "Unknown SCO handle %hd", handle);
  return sco_connections_.at(handle).GetAddress();
}

AddressWithType AclConnectionHandler::GetOwnAddress(uint16_t handle) const {
  ASSERT_LOG(HasHandle(handle), "Handle unknown %hd", handle);
  ASSERT_LOG(HasHandle(handle), "Unknown handle %hd", handle);
  return acl_connections_.at(handle).GetOwnAddress();
}

+2 −0
Original line number Diff line number Diff line
@@ -63,10 +63,12 @@ class AclConnectionHandler {
                              bluetooth::hci::AddressWithType own_addr);
  bool Disconnect(uint16_t handle);
  bool HasHandle(uint16_t handle) const;
  bool HasScoHandle(uint16_t handle) const;

  uint16_t GetHandle(bluetooth::hci::AddressWithType addr) const;
  uint16_t GetHandleOnlyAddress(bluetooth::hci::Address addr) const;
  bluetooth::hci::AddressWithType GetAddress(uint16_t handle) const;
  bluetooth::hci::Address GetScoAddress(uint16_t handle) const;
  bluetooth::hci::AddressWithType GetOwnAddress(uint16_t handle) const;

  void Encrypt(uint16_t handle);
+1 −0
Original line number Diff line number Diff line
@@ -568,6 +568,7 @@ void DualModeController::ReadLocalSupportedCommands(CommandView command) {
void DualModeController::ReadLocalSupportedFeatures(CommandView command) {
  auto command_view = gd_hci::ReadLocalSupportedFeaturesView::Create(command);
  ASSERT(command_view.IsValid());

  auto packet =
      bluetooth::hci::ReadLocalSupportedFeaturesCompleteBuilder::Create(
          kNumCommandPackets, ErrorCode::SUCCESS,
+140 −69
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

#include "link_layer_controller.h"

#include <cinttypes>
#include <hci/hci_packets.h>

#include "crypto_toolbox/crypto_toolbox.h"
@@ -390,6 +391,9 @@ void LinkLayerController::IncomingPacket(
    case model::packets::PacketType::ESCO_CONNECTION_RESPONSE:
      IncomingEScoConnectionResponse(incoming);
      break;
    case model::packets::PacketType::ESCO_DISCONNECT:
      IncomingEScoDisconnect(incoming);
      break;

    default:
      LOG_WARN("Dropping unhandled packet of type %s",
@@ -627,8 +631,7 @@ void LinkLayerController::IncomingDisconnectPacket(
             "GetHandle() returned invalid handle %hx", handle);

  uint8_t reason = disconnect.GetReason();
  ScheduleTask(kShortDelayMs,
               [this, handle, reason]() { DisconnectCleanup(handle, reason); });
  SendDisconnectionCompleteEvent(handle, reason);
}

void LinkLayerController::IncomingEncryptConnection(
@@ -1370,23 +1373,37 @@ void LinkLayerController::IncomingEScoConnectionRequest(

  Address address = incoming.GetSourceAddress();
  auto request = model::packets::EScoConnectionRequestView::Create(incoming);
  ASSERT(request.IsValid());

  LOG_INFO("Received eSCO connection request from %s",
           address.ToString().c_str());

  // Automatically reject if connection request was already sent
  // from the current device.
  if (connections_.HasPendingScoConnection(address)) {
    auto packet = model::packets::EScoConnectionResponseBuilder::Create(
    LOG_INFO("Rejecting eSCO connection request from %s, "
             "an eSCO connection already exist with this device",
             address.ToString().c_str());

    SendLinkLayerPacket(model::packets::EScoConnectionResponseBuilder::Create(
        properties_.GetLeAddress(), address,
      (uint8_t)ErrorCode::SYNCHRONOUS_CONNECTION_LIMIT_EXCEEDED, 0, 0, 0, 0, 0);
    SendLinkLayerPacket(std::move(packet));
        (uint8_t)ErrorCode::SYNCHRONOUS_CONNECTION_LIMIT_EXCEEDED,
        0, 0, 0, 0, 0));
    return;
  }

  // Send connection request event to use and wait for Accept or Reject
  // command.
  auto packet = bluetooth::hci::ConnectionRequestBuilder::Create(
  // Create local connection context.
  ScoConnectionParameters connection_parameters = {
    request.GetTransmitBandwidth(), request.GetReceiveBandwidth(),
    request.GetMaxLatency(), request.GetVoiceSetting(),
    request.GetRetransmissionEffort(), request.GetPacketType()
  };
  connections_.CreatePendingScoConnection(address, connection_parameters);

  // Send connection request event and wait for Accept or Reject command.
  send_event_(bluetooth::hci::ConnectionRequestBuilder::Create(
      address, ClassOfDevice(),
      bluetooth::hci::ConnectionRequestLinkType::ESCO);
  send_event_(std::move(packet));
      bluetooth::hci::ConnectionRequestLinkType::ESCO));
}

void LinkLayerController::IncomingEScoConnectionResponse(
@@ -1394,8 +1411,12 @@ void LinkLayerController::IncomingEScoConnectionResponse(

  Address address = incoming.GetSourceAddress();
  auto response = model::packets::EScoConnectionResponseView::Create(incoming);
  ASSERT(response.IsValid());
  auto status = response.GetStatus();

  LOG_INFO("Received eSCO connection response with status %" PRIx8 " from %s",
           status, incoming.GetSourceAddress().ToString().c_str());

  if (status == (uint8_t)ErrorCode::SUCCESS) {
    ScoLinkParameters link_parameters = {
      response.GetTransmissionInterval(),
@@ -1405,23 +1426,38 @@ void LinkLayerController::IncomingEScoConnectionResponse(
      response.GetAirMode(),
    };
    connections_.AcceptPendingScoConnection(address, link_parameters);
    auto packet = bluetooth::hci::SynchronousConnectionCompleteBuilder::Create(
    send_event_(bluetooth::hci::SynchronousConnectionCompleteBuilder::Create(
        ErrorCode(status), connections_.GetScoHandle(address), address,
        bluetooth::hci::ScoLinkType::ESCO,
        response.GetTransmissionInterval(),
        response.GetRetransmissionWindow(),
        response.GetRxPacketLength(),
        response.GetTxPacketLength(),
      bluetooth::hci::ScoAirMode(response.GetAirMode()));

    send_event_(std::move(packet));
        bluetooth::hci::ScoAirMode(response.GetAirMode())));
  } else {
    connections_.CancelPendingScoConnection(address);
    auto packet = bluetooth::hci::SynchronousConnectionCompleteBuilder::Create(
    send_event_(bluetooth::hci::SynchronousConnectionCompleteBuilder::Create(
        ErrorCode(status), 0, address, bluetooth::hci::ScoLinkType::ESCO,
      0, 0, 0, 0, bluetooth::hci::ScoAirMode::TRANSPARENT);
        0, 0, 0, 0, bluetooth::hci::ScoAirMode::TRANSPARENT));
  }
}

void LinkLayerController::IncomingEScoDisconnect(
    model::packets::LinkLayerPacketView incoming) {

  Address address = incoming.GetSourceAddress();
  auto request = model::packets::EScoDisconnectView::Create(incoming);
  ASSERT(request.IsValid());
  auto reason = request.GetReason();
  uint16_t handle = connections_.GetScoHandle(address);

    send_event_(std::move(packet));
  LOG_INFO("Received eSCO disconnection request with"
           " reason 0x%" PRIx8 " from %s",
           reason, incoming.GetSourceAddress().ToString().c_str());

  if (handle != 0) {
    connections_.Disconnect(handle);
    SendDisconnectionCompleteEvent(handle, reason);
  }
}

@@ -2546,39 +2582,67 @@ ErrorCode LinkLayerController::CreateConnectionCancel(const Address& addr) {
  return ErrorCode::SUCCESS;
}

void LinkLayerController::SendDisconnectionCompleteEvent(
    uint16_t handle, uint8_t reason)
{
  if (properties_.IsUnmasked(EventCode::DISCONNECTION_COMPLETE)) {
    ScheduleTask(kShortDelayMs, [this, handle, reason]() {
      send_event_(bluetooth::hci::DisconnectionCompleteBuilder::Create(
          ErrorCode::SUCCESS, handle, ErrorCode(reason)));
    });
  }
}

ErrorCode LinkLayerController::Disconnect(uint16_t handle, uint8_t reason) {
  if (connections_.HasScoHandle(handle)) {
    const Address remote = connections_.GetScoAddress(handle);
    LOG_INFO("Disconnecting eSCO connection with %s",
             remote.ToString().c_str());

    SendLinkLayerPacket(model::packets::EScoDisconnectBuilder::Create(
        properties_.GetAddress(), remote, reason));

    connections_.Disconnect(handle);
    SendDisconnectionCompleteEvent(handle, reason);
    return ErrorCode::SUCCESS;
  }

  if (!connections_.HasHandle(handle)) {
    return ErrorCode::UNKNOWN_CONNECTION;
  }

  const AddressWithType remote = connections_.GetAddress(handle);

  if (connections_.GetPhyType(handle) == Phy::Type::BR_EDR) {
    LOG_INFO("Disconnecting ACL connection with %s",
             remote.ToString().c_str());

    uint16_t sco_handle = connections_.GetScoHandle(remote.GetAddress());
    if (sco_handle != 0) {
      SendLinkLayerPacket(model::packets::EScoDisconnectBuilder::Create(
          properties_.GetAddress(), remote.GetAddress(), reason));

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

    SendLinkLayerPacket(model::packets::DisconnectBuilder::Create(
        properties_.GetAddress(), remote.GetAddress(), reason));

  } else {
    LOG_INFO("Disconnecting LE connection with %s",
             remote.ToString().c_str());

    SendLeLinkLayerPacket(model::packets::DisconnectBuilder::Create(
        connections_.GetOwnAddress(handle).GetAddress(), remote.GetAddress(),
        reason));
  }
  ASSERT_LOG(connections_.Disconnect(handle), "Disconnecting %hx", handle);

  ScheduleTask(kShortDelayMs, [this, handle]() {
    DisconnectCleanup(
        handle,
        static_cast<uint8_t>(ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST));
  });

  connections_.Disconnect(handle);
  SendDisconnectionCompleteEvent(handle, reason);
  return ErrorCode::SUCCESS;
}

void LinkLayerController::DisconnectCleanup(uint16_t handle, uint8_t reason) {
  // TODO: Clean up other connection state.
  if (properties_.IsUnmasked(EventCode::DISCONNECTION_COMPLETE)) {
    send_event_(bluetooth::hci::DisconnectionCompleteBuilder::Create(
        ErrorCode::SUCCESS, handle, static_cast<ErrorCode>(reason)));
  }
}

ErrorCode LinkLayerController::ChangeConnectionPacketType(uint16_t handle,
                                                          uint16_t types) {
  if (!connections_.HasHandle(handle)) {
@@ -3515,6 +3579,7 @@ ErrorCode LinkLayerController::SetupSynchronousConnection(
  if (!connections_.HasHandle(connection_handle)) {
    return ErrorCode::UNKNOWN_CONNECTION;
  }

  Address bd_addr = connections_.GetAddress(connection_handle).GetAddress();
  if (connections_.HasPendingScoConnection(bd_addr)) {
    // This command may be used to modify an exising eSCO link.
@@ -3523,6 +3588,8 @@ ErrorCode LinkLayerController::SetupSynchronousConnection(
    return ErrorCode::COMMAND_DISALLOWED;
  }

  LOG_INFO("Creating eSCO connection with %s", bd_addr.ToString().c_str());

  // Save connection parameters.
  ScoConnectionParameters connection_parameters = {
    transmit_bandwidth, receive_bandwidth, max_latency,
@@ -3533,11 +3600,10 @@ ErrorCode LinkLayerController::SetupSynchronousConnection(
    connection_parameters);

  // Send eSCO connection request to peer.
  auto packet = model::packets::EScoConnectionRequestBuilder::Create(
  SendLinkLayerPacket(model::packets::EScoConnectionRequestBuilder::Create(
      properties_.GetAddress(), bd_addr,
      transmit_bandwidth, receive_bandwidth, max_latency,
    voice_setting, retransmission_effort, packet_types);
  SendLinkLayerPacket(std::move(packet));
      voice_setting, retransmission_effort, packet_types));
  return ErrorCode::SUCCESS;
}

@@ -3550,7 +3616,12 @@ ErrorCode LinkLayerController::AcceptSynchronousConnection(
    uint8_t retransmission_effort,
    uint16_t packet_types) {

  LOG_INFO("Accepting eSCO connection request from %s",
           bd_addr.ToString().c_str());

  if (!connections_.HasPendingScoConnection(bd_addr)) {
    LOG_INFO("No pending eSCO connection for %s",
             bd_addr.ToString().c_str());
    return ErrorCode::COMMAND_DISALLOWED;
  }

@@ -3571,27 +3642,26 @@ ErrorCode LinkLayerController::AcceptSynchronousConnection(
  }

  // Send eSCO connection response to peer.
  auto packet = model::packets::EScoConnectionResponseBuilder::Create(
  SendLinkLayerPacket(model::packets::EScoConnectionResponseBuilder::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);
  SendLinkLayerPacket(std::move(packet));
      link_parameters.air_mode));

  // Schedule HCI Synchronous Connection Complete event.
  ScheduleTask(kShortDelayMs,
    [this, status, sco_handle, bd_addr, link_parameters]() {
      auto packet = bluetooth::hci::SynchronousConnectionCompleteBuilder::Create(
      send_event_(
          bluetooth::hci::SynchronousConnectionCompleteBuilder::Create(
            ErrorCode(status), sco_handle, bd_addr,
            bluetooth::hci::ScoLinkType::ESCO,
            link_parameters.transmission_interval,
            link_parameters.retransmission_window,
            link_parameters.rx_packet_length,
            link_parameters.tx_packet_length,
        bluetooth::hci::ScoAirMode(link_parameters.air_mode));
    send_event_(std::move(packet));
            bluetooth::hci::ScoAirMode(link_parameters.air_mode)));
  });

  return ErrorCode::SUCCESS;
@@ -3601,6 +3671,9 @@ ErrorCode LinkLayerController::RejectSynchronousConnection(
    Address bd_addr,
    uint16_t reason) {

  LOG_INFO("Rejecting eSCO connection request from %s",
           bd_addr.ToString().c_str());

  if (reason == (uint8_t)ErrorCode::SUCCESS) {
    reason = (uint8_t)ErrorCode::REMOTE_USER_TERMINATED_CONNECTION;
  }
@@ -3611,16 +3684,14 @@ ErrorCode LinkLayerController::RejectSynchronousConnection(
  connections_.CancelPendingScoConnection(bd_addr);

  // Send eSCO connection response to peer.
  auto packet = model::packets::EScoConnectionResponseBuilder::Create(
    properties_.GetAddress(), bd_addr, reason, 0, 0, 0, 0, 0);
  SendLinkLayerPacket(std::move(packet));
  SendLinkLayerPacket(model::packets::EScoConnectionResponseBuilder::Create(
      properties_.GetAddress(), bd_addr, reason, 0, 0, 0, 0, 0));

  // Schedule HCI Synchronous Connection Complete event.
  ScheduleTask(kShortDelayMs, [this, reason, bd_addr]() {
    auto packet = bluetooth::hci::SynchronousConnectionCompleteBuilder::Create(
    send_event_(bluetooth::hci::SynchronousConnectionCompleteBuilder::Create(
        ErrorCode(reason), 0, bd_addr, bluetooth::hci::ScoLinkType::ESCO,
      0, 0, 0, 0, bluetooth::hci::ScoAirMode::TRANSPARENT);
    send_event_(std::move(packet));
        0, 0, 0, 0, bluetooth::hci::ScoAirMode::TRANSPARENT));
  });

  return ErrorCode::SUCCESS;
+2 −1
Original line number Diff line number Diff line
@@ -95,7 +95,7 @@ class LinkLayerController {
  ErrorCode Disconnect(uint16_t handle, uint8_t reason);

 private:
  void DisconnectCleanup(uint16_t handle, uint8_t reason);
  void SendDisconnectionCompleteEvent(uint16_t handle, uint8_t reason);

 public:
  void IncomingPacket(model::packets::LinkLayerPacketView incoming);
@@ -446,6 +446,7 @@ class LinkLayerController {
      model::packets::LinkLayerPacketView packet);
  void IncomingEScoConnectionResponse(
      model::packets::LinkLayerPacketView packet);
  void IncomingEScoDisconnect(model::packets::LinkLayerPacketView packet);

 private:
  const DeviceProperties& properties_;
Loading