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

Commit ed8fdb3e authored by Hansong Zhang's avatar Hansong Zhang
Browse files

L2cap: Implement LE connection parameter update

Bug: 145707677
Test: cert/run --host
Change-Id: I83d7f90de753ec221db306b466c9474b8af2cc58
parent af49ba68
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -108,6 +108,17 @@ class LeL2capTest(GdFacadeOnlyBaseTestClass):
        dut_channel = response_future.get_channel()
        return (dut_channel, cert_channel)

    def test_reject_connection_parameter_update_request(self):
        """
        L2CAP/LE/CPU/BI-02-C
        """
        self._setup_link_from_cert()
        self.cert_l2cap.get_control_channel().send(
            l2cap_packets.ConnectionParameterUpdateRequestBuilder(
                2, 100, 100, 512, 100))
        assertThat(self.cert_l2cap.get_control_channel()).emits(
            L2capMatchers.LeCommandReject())

    def test_segmentation(self):
        """
        L2CAP/COS/CFC/BV-01-C
+1 −0
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ void Link::Disconnect() {

void Link::UpdateConnectionParameter(SignalId signal_id, uint16_t conn_interval_min, uint16_t conn_interval_max,
                                     uint16_t conn_latency, uint16_t supervision_timeout) {
  // TODO: If we are slave and both only support legacy update connection parameter, use L2CAP
  acl_connection_->LeConnectionUpdate(
      conn_interval_min, conn_interval_max, conn_latency, supervision_timeout,
      common::BindOnce(&Link::on_connection_update_complete, common::Unretained(this), signal_id), l2cap_handler_);
+55 −15
Original line number Diff line number Diff line
@@ -56,9 +56,8 @@ LeSignallingManager::~LeSignallingManager() {
}

void LeSignallingManager::SendConnectionRequest(Psm psm, Cid local_cid, Mtu mtu) {
  PendingCommand pending_command = {
      next_signal_id_, LeCommandCode::LE_CREDIT_BASED_CONNECTION_REQUEST, psm, local_cid, {}, mtu, link_->GetMps(),
      link_->GetInitialCredit()};
  PendingCommand pending_command = PendingCommand::CreditBasedConnectionRequest(
      next_signal_id_, psm, local_cid, mtu, link_->GetMps(), link_->GetInitialCredit());
  next_signal_id_++;
  pending_commands_.push(pending_command);
  if (pending_commands_.size() == 1) {
@@ -66,9 +65,8 @@ void LeSignallingManager::SendConnectionRequest(Psm psm, Cid local_cid, Mtu mtu)
  }
}

void LeSignallingManager::SendDisconnectRequest(Cid local_cid, Cid remote_cid) {
  PendingCommand pending_command = {
      next_signal_id_, LeCommandCode::DISCONNECTION_REQUEST, {}, local_cid, remote_cid, {}, {}, {}};
void LeSignallingManager::SendDisconnectRequest(Cid scid, Cid dcid) {
  PendingCommand pending_command = PendingCommand::DisconnectionRequest(next_signal_id_, scid, dcid);
  next_signal_id_++;
  pending_commands_.push(pending_command);
  if (pending_commands_.size() == 1) {
@@ -78,7 +76,13 @@ void LeSignallingManager::SendDisconnectRequest(Cid local_cid, Cid remote_cid) {

void LeSignallingManager::SendConnectionParameterUpdateRequest(uint16_t interval_min, uint16_t interval_max,
                                                               uint16_t slave_latency, uint16_t timeout_multiplier) {
  LOG_ERROR("Not implemented");
  PendingCommand pending_command = PendingCommand::ConnectionParameterUpdate(
      next_signal_id_, interval_min, interval_max, slave_latency, timeout_multiplier);
  next_signal_id_++;
  pending_commands_.push(pending_command);
  if (pending_commands_.size() == 1) {
    handle_send_next_command();
  }
}

void LeSignallingManager::SendConnectionParameterUpdateResponse(SignalId signal_id,
@@ -113,13 +117,41 @@ void LeSignallingManager::OnCommandReject(LeCommandRejectView command_reject_vie
  LOG_WARN("Command rejected");
}

void LeSignallingManager::OnConnectionParameterUpdateRequest(uint16_t interval_min, uint16_t interval_max,
                                                             uint16_t slave_latency, uint16_t timeout_multiplier) {
  LOG_ERROR("Not implemented");
void LeSignallingManager::OnConnectionParameterUpdateRequest(SignalId signal_id, uint16_t interval_min,
                                                             uint16_t interval_max, uint16_t slave_latency,
                                                             uint16_t timeout_multiplier) {
  if (link_->GetRole() == hci::Role::SLAVE) {
    LOG_WARN("Received request from LL master");
    auto builder = LeCommandRejectNotUnderstoodBuilder::Create(signal_id.Value());
    enqueue_buffer_->Enqueue(std::move(builder), handler_);
    return;
  }
  if (interval_min < 6 || interval_min > 3200 || interval_max < 6 || interval_max > 3200 || slave_latency >= 500 ||
      timeout_multiplier < 10 || timeout_multiplier > 3200) {
    LOG_WARN("Received invalid connection parameter update request from LL master");
    auto builder = ConnectionParameterUpdateResponseBuilder::Create(signal_id.Value(),
                                                                    ConnectionParameterUpdateResponseResult::REJECTED);
    enqueue_buffer_->Enqueue(std::move(builder), handler_);
    return;
  }
  link_->UpdateConnectionParameter(signal_id, interval_min, interval_max, slave_latency, timeout_multiplier);
}

void LeSignallingManager::OnConnectionParameterUpdateResponse(ConnectionParameterUpdateResponseResult result) {
  LOG_ERROR("Not implemented");
void LeSignallingManager::OnConnectionParameterUpdateResponse(SignalId signal_id,
                                                              ConnectionParameterUpdateResponseResult result) {
  if (signal_id != command_just_sent_.signal_id_) {
    LOG_WARN("Unexpected response: no pending request");
    return;
  }
  if (command_just_sent_.command_code_ != LeCommandCode::CONNECTION_PARAMETER_UPDATE_REQUEST) {
    LOG_WARN("Unexpected response: no pending request");
    return;
  }
  alarm_.Cancel();
  command_just_sent_.signal_id_ = kInitialSignalId;
  if (result != ConnectionParameterUpdateResponseResult::ACCEPTED) {
    LOG_ERROR("Connection parameter update is not accepted");
  }
}

void LeSignallingManager::OnConnectionRequest(SignalId signal_id, Psm psm, Cid remote_cid, Mtu mtu, uint16_t mps,
@@ -290,8 +322,9 @@ void LeSignallingManager::on_incoming_packet() {
        return;
      }
      OnConnectionParameterUpdateRequest(
          parameter_update_req_view.GetIntervalMin(), parameter_update_req_view.GetIntervalMax(),
          parameter_update_req_view.GetSlaveLatency(), parameter_update_req_view.GetTimeoutMultiplier());
          parameter_update_req_view.GetIdentifier(), parameter_update_req_view.GetIntervalMin(),
          parameter_update_req_view.GetIntervalMax(), parameter_update_req_view.GetSlaveLatency(),
          parameter_update_req_view.GetTimeoutMultiplier());
      return;
    }
    case LeCommandCode::CONNECTION_PARAMETER_UPDATE_RESPONSE: {
@@ -300,7 +333,8 @@ void LeSignallingManager::on_incoming_packet() {
      if (!parameter_update_rsp_view.IsValid()) {
        return;
      }
      OnConnectionParameterUpdateResponse(parameter_update_rsp_view.GetResult());
      OnConnectionParameterUpdateResponse(parameter_update_rsp_view.GetIdentifier(),
                                          parameter_update_rsp_view.GetResult());
      return;
    }
    case LeCommandCode::LE_CREDIT_BASED_CONNECTION_REQUEST: {
@@ -411,6 +445,12 @@ void LeSignallingManager::handle_send_next_command() {
      alarm_.Schedule(common::BindOnce(&LeSignallingManager::on_command_timeout, common::Unretained(this)), kTimeout);
      break;
    }
    case LeCommandCode::CONNECTION_PARAMETER_UPDATE_REQUEST: {
      auto builder = ConnectionParameterUpdateRequestBuilder::Create(command_just_sent_.signal_id_.Value(), 0, 0, 0, 0);
      enqueue_buffer_->Enqueue(std::move(builder), handler_);
      alarm_.Schedule(common::BindOnce(&LeSignallingManager::on_command_timeout, common::Unretained(this)), kTimeout);
      break;
    }
    default: {
      LOG_WARN("Unsupported command code 0x%x", static_cast<int>(command_just_sent_.command_code_));
    }
+42 −3
Original line number Diff line number Diff line
@@ -49,6 +49,44 @@ struct PendingCommand {
  Mtu mtu_;
  uint16_t mps_;
  uint16_t credits_;
  uint16_t interval_min_;
  uint16_t interval_max_;
  uint16_t slave_latency_;
  uint16_t timeout_multiplier_;

  static PendingCommand CreditBasedConnectionRequest(SignalId signal_id, Psm psm, Cid scid, Mtu mtu, uint16_t mps,
                                                     uint16_t initial_credits) {
    PendingCommand pending_command;
    pending_command.signal_id_ = signal_id;
    pending_command.command_code_ = LeCommandCode::LE_CREDIT_BASED_CONNECTION_REQUEST;
    pending_command.psm_ = psm;
    pending_command.source_cid_ = scid;
    pending_command.mtu_ = mtu;
    pending_command.mps_ = mps;
    pending_command.credits_ = initial_credits;
    return pending_command;
  }

  static PendingCommand DisconnectionRequest(SignalId signal_id, Cid scid, Cid dcid) {
    PendingCommand pending_command;
    pending_command.signal_id_ = signal_id;
    pending_command.command_code_ = LeCommandCode::DISCONNECTION_REQUEST;
    pending_command.source_cid_ = scid;
    pending_command.destination_cid_ = dcid;
    return pending_command;
  }

  static PendingCommand ConnectionParameterUpdate(SignalId signal_id, uint16_t interval_min, uint16_t interval_max,
                                                  uint16_t slave_latency, uint16_t timeout_multiplier) {
    PendingCommand pending_command;
    pending_command.signal_id_ = signal_id;
    pending_command.command_code_ = LeCommandCode::CONNECTION_PARAMETER_UPDATE_REQUEST;
    pending_command.interval_min_ = interval_min;
    pending_command.interval_max_ = interval_max;
    pending_command.slave_latency_ = slave_latency;
    pending_command.timeout_multiplier_ = timeout_multiplier;
    return pending_command;
  }
};

class Link;
@@ -65,6 +103,7 @@ class LeSignallingManager {

  void SendDisconnectRequest(Cid local_cid, Cid remote_cid);

  // Note: Since Core 4.1, LL slave can send this through HCI command.
  void SendConnectionParameterUpdateRequest(uint16_t interval_min, uint16_t interval_max, uint16_t slave_latency,
                                            uint16_t timeout_multiplier);

@@ -76,9 +115,9 @@ class LeSignallingManager {

  void OnCommandReject(LeCommandRejectView command_reject_view);

  void OnConnectionParameterUpdateRequest(uint16_t interval_min, uint16_t interval_max, uint16_t slave_latency,
                                          uint16_t timeout_multiplier);
  void OnConnectionParameterUpdateResponse(ConnectionParameterUpdateResponseResult result);
  void OnConnectionParameterUpdateRequest(SignalId signal_id, uint16_t interval_min, uint16_t interval_max,
                                          uint16_t slave_latency, uint16_t timeout_multiplier);
  void OnConnectionParameterUpdateResponse(SignalId signal_id, ConnectionParameterUpdateResponseResult result);

  void OnConnectionRequest(SignalId signal_id, Psm psm, Cid remote_cid, Mtu mtu, uint16_t mps,
                           uint16_t initial_credits);