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

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

L2cap SignallingManager fix and improvement

* Fix SignallingManager to send configuration request after remote
feature is received.
* Merge duplicated code when we send configuration request to a helper
function.
* Correctly queue disconnection request.
* In L2capTest, explicitly send NO_FCS in configuration request and
response from CERT, if we don't want to use FCS. By default it's on.

Test: cert/run --host
Change-Id: Ida8474d27df1f90c026d7a90ce40e13a550bb8dd
parent 64f9b537
Loading
Loading
Loading
Loading
+24 −23
Original line number Diff line number Diff line
@@ -152,7 +152,7 @@ class L2capTest(GdBaseTestClass):
        self._setup_link_from_cert()

        (dut_channel, cert_channel) = self._open_channel_from_cert(
            scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM)
            mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)

        dut_channel.send(b'abc' * 34)
        assertThat(cert_channel).emits(
@@ -600,7 +600,7 @@ class L2capTest(GdBaseTestClass):
        self._setup_link_from_cert()

        (dut_channel, cert_channel) = self._open_channel_from_cert(
            scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM)
            mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)

        dut_channel.send(b'abc')
        assertThat(cert_channel).emits(
@@ -658,7 +658,7 @@ class L2capTest(GdBaseTestClass):
        self.cert_l2cap.turn_on_ertm()

        (dut_channel, cert_channel) = self._open_channel_from_cert(
            scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM)
            mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)

        dut_channel.send(b'abc')
        assertThat(cert_channel).emits(
@@ -675,7 +675,7 @@ class L2capTest(GdBaseTestClass):
        self.cert_l2cap.turn_on_ertm()

        (dut_channel, cert_channel) = self._open_channel_from_cert(
            scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM)
            mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)

        dut_channel.send(b"abc")
        assertThat(cert_channel).emits(
@@ -727,7 +727,7 @@ class L2capTest(GdBaseTestClass):
        self._setup_link_from_cert()

        (dut_channel, cert_channel) = self._open_channel_from_cert(
            scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM)
            mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)

        dut_channel.send(b'abc')
        assertThat(cert_channel).emits(
@@ -755,7 +755,7 @@ class L2capTest(GdBaseTestClass):
        self._setup_link_from_cert()

        (dut_channel, cert_channel) = self._open_channel_from_cert(
            scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM)
            mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)

        for i in range(3):
            cert_channel.send_i_frame(
@@ -794,7 +794,7 @@ class L2capTest(GdBaseTestClass):
        self._setup_link_from_cert()

        (dut_channel, cert_channel) = self._open_channel_from_cert(
            scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM)
            mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)

        for i in range(3):
            cert_channel.send_i_frame(
@@ -902,7 +902,7 @@ class L2capTest(GdBaseTestClass):
        self._setup_link_from_cert()

        (dut_channel, cert_channel) = self._open_channel_from_cert(
            scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM)
            mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)

        cert_channel.send_s_frame(req_seq=0, p=Poll.POLL)
        assertThat(cert_channel).emits(
@@ -919,7 +919,7 @@ class L2capTest(GdBaseTestClass):
        self._setup_link_from_cert()

        (dut_channel, cert_channel) = self._open_channel_from_cert(
            scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM)
            mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
        dut_channel.send(b'abc')

        assertThat(cert_channel).emits(
@@ -989,8 +989,9 @@ class L2capTest(GdBaseTestClass):
        self._setup_link_from_cert()

        (dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert(
            scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM)
        config = CertL2cap.config_option_ertm(tx_window_size=2, max_transmit=2)
            mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)
        config = CertL2cap.config_option_ertm(
            tx_window_size=2, max_transmit=2, fcs=FcsType.NO_FCS)
        cert_channel.verify_configuration_request_and_respond(options=config)
        cert_channel.send_configure_request(config)
        cert_channel.verify_configuration_response()
@@ -1087,7 +1088,7 @@ class L2capTest(GdBaseTestClass):
            tx_window_size=tx_window_size, max_transmit=2)

        (dut_channel, cert_channel) = self._open_channel_from_cert(
            scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM)
            mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)

        cert_channel.send_i_frame(
            tx_seq=0, req_seq=0, f=Final.NOT_SET, payload=SAMPLE_PACKET)
@@ -1122,7 +1123,7 @@ class L2capTest(GdBaseTestClass):
        self._setup_link_from_cert()

        (dut_channel, cert_channel) = self._open_channel_from_cert(
            scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM)
            mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)

        dut_channel.send(b'abc')

@@ -1145,7 +1146,7 @@ class L2capTest(GdBaseTestClass):
        self._setup_link_from_cert()

        (dut_channel, cert_channel) = self._open_channel_from_cert(
            scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM)
            mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)

        dut_channel.send(b'abc')

@@ -1233,7 +1234,7 @@ class L2capTest(GdBaseTestClass):
        ertm_tx_window_size = 5

        (dut_channel, cert_channel) = self._open_channel_from_cert(
            scid=0x41, psm=0x41, mode=RetransmissionFlowControlMode.ERTM)
            mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)

        cert_channel.send_i_frame(tx_seq=0, req_seq=0, payload=SAMPLE_PACKET)
        assertThat(cert_channel).emits(L2capMatchers.SFrame(req_seq=1))
@@ -1264,7 +1265,7 @@ class L2capTest(GdBaseTestClass):
        self._setup_link_from_cert()

        (dut_channel, cert_channel) = self._open_channel_from_cert(
            scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM)
            mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)

        dut_channel.send(b'abc')
        dut_channel.send(b'abc')
@@ -1297,7 +1298,7 @@ class L2capTest(GdBaseTestClass):
        self._setup_link_from_cert()

        (dut_channel, cert_channel) = self._open_channel_from_cert(
            scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM)
            mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)

        dut_channel.send(b'abc')
        dut_channel.send(b'abc')
@@ -1329,7 +1330,7 @@ class L2capTest(GdBaseTestClass):
        self._setup_link_from_cert()

        (dut_channel, cert_channel) = self._open_channel_from_cert(
            scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM)
            mode=RetransmissionFlowControlMode.ERTM, fcs=FcsType.NO_FCS)

        dut_channel.send(b'abc')
        dut_channel.send(b'abc')
@@ -1375,6 +1376,8 @@ class L2capTest(GdBaseTestClass):
        Verify the IUT can accept a Configuration Request from the Lower Tester
        containing an F&EC option that specifies Enhanced Retransmission Mode
        """
        asserts.skip("Need to send ERTM config request when we open from DUT")

        self._setup_link_from_cert()

        self._open_channel_from_dut(
@@ -1435,9 +1438,7 @@ class L2capTest(GdBaseTestClass):
        """
        self._setup_link_from_cert()
        (dut_channel, cert_channel) = self._open_unconfigured_channel_from_cert(
            scid=0x41, psm=0x33, mode=RetransmissionFlowControlMode.ERTM)
        assertThat(self.cert_l2cap.get_control_channel()).emits(
            L2capMatchers.ConfigurationRequest())
        cert_channel.send_configure_request(
            CertL2cap.config_option_basic_explicit())
            mode=RetransmissionFlowControlMode.ERTM)
        cert_channel.verify_configuration_request_and_respond(
            options=CertL2cap.config_option_basic_explicit())
        cert_channel.verify_disconnect_request()
+16 −0
Original line number Diff line number Diff line
@@ -165,6 +165,13 @@ void Link::connect_to_pending_dynamic_channels() {
  }
}

void Link::send_pending_configuration_requests() {
  for (auto local_cid : pending_outgoing_configuration_request_list_) {
    signalling_manager_.SendInitialConfigRequest(local_cid);
  }
  pending_outgoing_configuration_request_list_.clear();
}

void Link::OnOutgoingConnectionRequestFail(Cid local_cid) {
  if (local_cid_to_pending_dynamic_channel_connection_map_.find(local_cid) !=
      local_cid_to_pending_dynamic_channel_connection_map_.end()) {
@@ -178,6 +185,14 @@ void Link::OnOutgoingConnectionRequestFail(Cid local_cid) {
  dynamic_channel_allocator_.FreeChannel(local_cid);
}

void Link::SendInitialConfigRequestOrQueue(Cid local_cid) {
  if (remote_extended_feature_received_) {
    signalling_manager_.SendInitialConfigRequest(local_cid);
  } else {
    pending_outgoing_configuration_request_list_.push_back(local_cid);
  }
}

void Link::SendDisconnectionRequest(Cid local_cid, Cid remote_cid) {
  signalling_manager_.SendDisconnectionRequest(local_cid, remote_cid);
}
@@ -272,6 +287,7 @@ void Link::OnRemoteExtendedFeatureReceived(bool ertm_supported, bool fcs_support
  remote_supports_fcs_ = fcs_supported;
  remote_extended_feature_received_ = true;
  connect_to_pending_dynamic_channels();
  send_pending_configuration_requests();
}

void Link::AddChannelPendingingAuthentication(PendingAuthenticateDynamicChannelConnection pending_channel) {
+4 −0
Original line number Diff line number Diff line
@@ -105,6 +105,8 @@ class Link : public l2cap::internal::ILink, public hci::ConnectionManagementCall
  // Invoked by signalling manager to indicate an outgoing connection request failed and link shall free resources
  virtual void OnOutgoingConnectionRequestFail(Cid local_cid);

  virtual void SendInitialConfigRequestOrQueue(Cid local_cid);

  virtual void SendInformationRequest(InformationRequestInfoType type);

  virtual void SendDisconnectionRequest(Cid local_cid, Cid remote_cid) override;
@@ -168,6 +170,7 @@ class Link : public l2cap::internal::ILink, public hci::ConnectionManagementCall

 private:
  void connect_to_pending_dynamic_channels();
  void send_pending_configuration_requests();

  os::Handler* l2cap_handler_;
  l2cap::internal::FixedChannelAllocator<FixedChannelImpl, Link> fixed_channel_allocator_{this, l2cap_handler_};
@@ -188,6 +191,7 @@ class Link : public l2cap::internal::ILink, public hci::ConnectionManagementCall
  std::list<Link::PendingAuthenticateDynamicChannelConnection> pending_channel_list_;
  std::list<Psm> pending_dynamic_psm_list_;
  std::list<Link::PendingDynamicChannelConnection> pending_dynamic_channel_callback_list_;
  std::list<uint16_t> pending_outgoing_configuration_request_list_;
  DISALLOW_COPY_AND_ASSIGN(Link);
};

+85 −111
Original line number Diff line number Diff line
@@ -81,7 +81,7 @@ void ClassicSignallingManager::SendConnectionRequest(Psm psm, Cid local_cid) {
  }
}

void ClassicSignallingManager::SendConfigurationRequest(Cid remote_cid,
void ClassicSignallingManager::send_configuration_request(Cid remote_cid,
                                                          std::vector<std::unique_ptr<ConfigurationOption>> config) {
  PendingCommand pending_command = {next_signal_id_,  CommandCode::CONFIGURATION_REQUEST, {}, {}, remote_cid, {},
                                    std::move(config)};
@@ -93,16 +93,13 @@ void ClassicSignallingManager::SendConfigurationRequest(Cid remote_cid,
}

void ClassicSignallingManager::SendDisconnectionRequest(Cid local_cid, Cid remote_cid) {
  command_just_sent_ = {next_signal_id_, CommandCode::DISCONNECTION_REQUEST, {}, local_cid, remote_cid, {}, {}};
  PendingCommand pending_command = {
      next_signal_id_, CommandCode::DISCONNECTION_REQUEST, {}, local_cid, remote_cid, {}, {}};
  next_signal_id_++;

  auto signal_id = command_just_sent_.signal_id_;
  auto source_cid = command_just_sent_.source_cid_;
  auto destination_cid = command_just_sent_.destination_cid_;

  auto builder = DisconnectionRequestBuilder::Create(signal_id.Value(), destination_cid, source_cid);
  enqueue_buffer_->Enqueue(std::move(builder), handler_);
  alarm_.Schedule(common::BindOnce(&ClassicSignallingManager::on_command_timeout, common::Unretained(this)), kTimeout);
  pending_commands_.push(std::move(pending_command));
  if (command_just_sent_.signal_id_ == kInvalidSignalId) {
    handle_send_next_command();
  }
}

void ClassicSignallingManager::SendInformationRequest(InformationRequestInfoType type) {
@@ -157,51 +154,8 @@ void ClassicSignallingManager::OnConnectionRequest(SignalId signal_id, Psm psm,
  }
  send_connection_response(signal_id, remote_cid, new_channel->GetCid(), ConnectionResponseResult::SUCCESS,
                           ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE);
  auto& configuration_state = channel_configuration_[new_channel->GetCid()];
  auto* service = dynamic_service_manager_->GetService(psm);
  auto initial_config = service->GetConfigOption();

  auto mtu_configuration = std::make_unique<MtuConfigurationOption>();
  mtu_configuration->mtu_ = initial_config.incoming_mtu;
  configuration_state.incoming_mtu_ = initial_config.incoming_mtu;

  auto fcs_option = std::make_unique<FrameCheckSequenceOption>();
  fcs_option->fcs_type_ = FcsType::NO_FCS;
  configuration_state.fcs_type_ = FcsType::NO_FCS;
  if (link_->GetRemoteSupportsFcs()) {
    fcs_option->fcs_type_ = FcsType::DEFAULT;
    configuration_state.fcs_type_ = FcsType::DEFAULT;
  }

  auto retransmission_flow_control_configuration = std::make_unique<RetransmissionAndFlowControlConfigurationOption>();
  switch (initial_config.channel_mode) {
    case DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::L2CAP_BASIC:
      retransmission_flow_control_configuration->mode_ = RetransmissionAndFlowControlModeOption::L2CAP_BASIC;
      configuration_state.retransmission_and_flow_control_mode_ = RetransmissionAndFlowControlModeOption::L2CAP_BASIC;
      break;
    case DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::ENHANCED_RETRANSMISSION:
    case DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::ENHANCED_RETRANSMISSION_OPTIONAL:
      retransmission_flow_control_configuration->mode_ =
          RetransmissionAndFlowControlModeOption::ENHANCED_RETRANSMISSION;
      configuration_state.retransmission_and_flow_control_mode_ =
          RetransmissionAndFlowControlModeOption::ENHANCED_RETRANSMISSION;
      // TODO: Decide where to put initial values
      retransmission_flow_control_configuration->tx_window_size_ = 10;
      retransmission_flow_control_configuration->max_transmit_ = 20;
      retransmission_flow_control_configuration->retransmission_time_out_ = 2000;
      retransmission_flow_control_configuration->monitor_time_out_ = 12000;
      retransmission_flow_control_configuration->maximum_pdu_size_ = 1010;
      break;
  }
  configuration_state.local_retransmission_and_flow_control_ = *retransmission_flow_control_configuration;

  std::vector<std::unique_ptr<ConfigurationOption>> config;
  config.emplace_back(std::move(mtu_configuration));
  if (initial_config.channel_mode != DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::L2CAP_BASIC) {
    config.emplace_back(std::move(retransmission_flow_control_configuration));
    config.emplace_back(std::move(fcs_option));
  }
  SendConfigurationRequest(remote_cid, std::move(config));
  link_->SendInitialConfigRequestOrQueue(new_channel->GetCid());
}

void ClassicSignallingManager::OnConnectionResponse(SignalId signal_id, Cid remote_cid, Cid cid,
@@ -240,50 +194,7 @@ void ClassicSignallingManager::OnConnectionResponse(SignalId signal_id, Cid remo
    return;
  }

  auto& configuration_state = channel_configuration_[new_channel->GetCid()];
  auto initial_config = link_->GetConfigurationForInitialConfiguration(new_channel->GetCid());

  auto mtu_configuration = std::make_unique<MtuConfigurationOption>();
  mtu_configuration->mtu_ = initial_config.incoming_mtu;
  configuration_state.incoming_mtu_ = initial_config.incoming_mtu;

  auto fcs_option = std::make_unique<FrameCheckSequenceOption>();
  fcs_option->fcs_type_ = FcsType::DEFAULT;
  configuration_state.fcs_type_ = FcsType::DEFAULT;
  if (!link_->GetRemoteSupportsFcs()) {
    fcs_option->fcs_type_ = FcsType::NO_FCS;
    configuration_state.fcs_type_ = FcsType::NO_FCS;
  }

  auto retransmission_flow_control_configuration = std::make_unique<RetransmissionAndFlowControlConfigurationOption>();
  switch (initial_config.channel_mode) {
    case DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::L2CAP_BASIC:
      retransmission_flow_control_configuration->mode_ = RetransmissionAndFlowControlModeOption::L2CAP_BASIC;
      configuration_state.retransmission_and_flow_control_mode_ = RetransmissionAndFlowControlModeOption::L2CAP_BASIC;
      break;
    case DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::ENHANCED_RETRANSMISSION:
    case DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::ENHANCED_RETRANSMISSION_OPTIONAL:
      retransmission_flow_control_configuration->mode_ =
          RetransmissionAndFlowControlModeOption::ENHANCED_RETRANSMISSION;
      configuration_state.retransmission_and_flow_control_mode_ =
          RetransmissionAndFlowControlModeOption::ENHANCED_RETRANSMISSION;
      // TODO: Decide where to put initial values
      retransmission_flow_control_configuration->tx_window_size_ = 10;
      retransmission_flow_control_configuration->max_transmit_ = 20;
      retransmission_flow_control_configuration->retransmission_time_out_ = 2000;
      retransmission_flow_control_configuration->monitor_time_out_ = 12000;
      retransmission_flow_control_configuration->maximum_pdu_size_ = 1010;
      break;
  }
  configuration_state.local_retransmission_and_flow_control_ = *retransmission_flow_control_configuration;

  std::vector<std::unique_ptr<ConfigurationOption>> config;
  config.emplace_back(std::move(mtu_configuration));
  if (initial_config.channel_mode != DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::L2CAP_BASIC) {
    config.emplace_back(std::move(retransmission_flow_control_configuration));
    config.emplace_back(std::move(fcs_option));
  }
  SendConfigurationRequest(remote_cid, std::move(config));
  link_->SendInitialConfigRequestOrQueue(cid);
}

void ClassicSignallingManager::OnConfigurationRequest(SignalId signal_id, Cid cid, Continuation is_continuation,
@@ -297,6 +208,7 @@ void ClassicSignallingManager::OnConfigurationRequest(SignalId signal_id, Cid ci
  auto& configuration_state = channel_configuration_[cid];
  std::vector<std::unique_ptr<ConfigurationOption>> rsp_options;
  ConfigurationResponseResult result = ConfigurationResponseResult::SUCCESS;
  auto remote_rfc_mode = RetransmissionAndFlowControlModeOption::L2CAP_BASIC;

  for (auto& option : options) {
    switch (option->type_) {
@@ -317,6 +229,7 @@ void ClassicSignallingManager::OnConfigurationRequest(SignalId signal_id, Cid ci
      }
      case ConfigurationOptionType::RETRANSMISSION_AND_FLOW_CONTROL: {
        auto* config = RetransmissionAndFlowControlConfigurationOption::Specialize(option.get());
        remote_rfc_mode = config->mode_;
        if (config->mode_ == RetransmissionAndFlowControlModeOption::ENHANCED_RETRANSMISSION) {
          if (config->retransmission_time_out_ == 0) {
            config->retransmission_time_out_ = 2000;
@@ -324,14 +237,6 @@ void ClassicSignallingManager::OnConfigurationRequest(SignalId signal_id, Cid ci
          if (config->monitor_time_out_ == 0) {
            config->monitor_time_out_ = 12000;
          }
        } else if (config->mode_ == RetransmissionAndFlowControlModeOption::L2CAP_BASIC) {
          auto initial_config_option = dynamic_service_manager_->GetService(channel->GetPsm())->GetConfigOption();
          if (initial_config_option.channel_mode ==
              DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::ENHANCED_RETRANSMISSION) {
            LOG_WARN("ERTM mandatory not allow mode configuration, disconnect channel.");
            SendDisconnectionRequest(channel->GetCid(), channel->GetRemoteCid());
            return;
          }
        }
        configuration_state.remote_retransmission_and_flow_control_ = *config;
        configuration_state.retransmission_and_flow_control_mode_ = config->mode_;
@@ -339,7 +244,7 @@ void ClassicSignallingManager::OnConfigurationRequest(SignalId signal_id, Cid ci
        break;
      }
      case ConfigurationOptionType::FRAME_CHECK_SEQUENCE: {
        configuration_state.fcs_type_ = FrameCheckSequenceOption::Specialize(option.get())->fcs_type_;
        // We determine whether to use FCS or not when we send config request
        break;
      }
      default:
@@ -355,6 +260,16 @@ void ClassicSignallingManager::OnConfigurationRequest(SignalId signal_id, Cid ci
    }
  }

  auto initial_config_option = dynamic_service_manager_->GetService(channel->GetPsm())->GetConfigOption();

  if (remote_rfc_mode == RetransmissionAndFlowControlModeOption::L2CAP_BASIC &&
      initial_config_option.channel_mode ==
          DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::ENHANCED_RETRANSMISSION) {
    LOG_WARN("ERTM mandatory not allow mode configuration, disconnect channel.");
    SendDisconnectionRequest(channel->GetCid(), channel->GetRemoteCid());
    return;
  }

  if (configuration_state.state_ == ChannelConfigurationState::State::WAIT_CONFIG_REQ) {
    std::unique_ptr<DynamicChannel> user_channel = std::make_unique<DynamicChannel>(channel, handler_);
    if (channel->local_initiated_) {
@@ -374,6 +289,56 @@ void ClassicSignallingManager::OnConfigurationRequest(SignalId signal_id, Cid ci
  enqueue_buffer_->Enqueue(std::move(response), handler_);
}

void ClassicSignallingManager::SendInitialConfigRequest(Cid local_cid) {
  auto channel = channel_allocator_->FindChannelByCid(local_cid);
  auto psm = channel->GetPsm();
  auto& configuration_state = channel_configuration_[local_cid];
  auto* service = dynamic_service_manager_->GetService(psm);
  auto initial_config = service->GetConfigOption();

  auto mtu_configuration = std::make_unique<MtuConfigurationOption>();
  mtu_configuration->mtu_ = initial_config.incoming_mtu;
  configuration_state.incoming_mtu_ = initial_config.incoming_mtu;

  auto fcs_option = std::make_unique<FrameCheckSequenceOption>();
  fcs_option->fcs_type_ = FcsType::NO_FCS;
  configuration_state.fcs_type_ = FcsType::NO_FCS;
  if (link_->GetRemoteSupportsFcs()) {
    fcs_option->fcs_type_ = FcsType::DEFAULT;
    configuration_state.fcs_type_ = FcsType::DEFAULT;
  }

  auto retransmission_flow_control_configuration = std::make_unique<RetransmissionAndFlowControlConfigurationOption>();
  switch (initial_config.channel_mode) {
    case DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::L2CAP_BASIC:
      retransmission_flow_control_configuration->mode_ = RetransmissionAndFlowControlModeOption::L2CAP_BASIC;
      configuration_state.retransmission_and_flow_control_mode_ = RetransmissionAndFlowControlModeOption::L2CAP_BASIC;
      break;
    case DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::ENHANCED_RETRANSMISSION:
    case DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::ENHANCED_RETRANSMISSION_OPTIONAL:
      retransmission_flow_control_configuration->mode_ =
          RetransmissionAndFlowControlModeOption::ENHANCED_RETRANSMISSION;
      configuration_state.retransmission_and_flow_control_mode_ =
          RetransmissionAndFlowControlModeOption::ENHANCED_RETRANSMISSION;
      // TODO: Decide where to put initial values
      retransmission_flow_control_configuration->tx_window_size_ = 10;
      retransmission_flow_control_configuration->max_transmit_ = 20;
      retransmission_flow_control_configuration->retransmission_time_out_ = 2000;
      retransmission_flow_control_configuration->monitor_time_out_ = 12000;
      retransmission_flow_control_configuration->maximum_pdu_size_ = 1010;
      break;
  }
  configuration_state.local_retransmission_and_flow_control_ = *retransmission_flow_control_configuration;

  std::vector<std::unique_ptr<ConfigurationOption>> config;
  config.emplace_back(std::move(mtu_configuration));
  if (initial_config.channel_mode != DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::L2CAP_BASIC) {
    config.emplace_back(std::move(retransmission_flow_control_configuration));
    config.emplace_back(std::move(fcs_option));
  }
  send_configuration_request(channel->GetRemoteCid(), std::move(config));
}

void ClassicSignallingManager::negotiate_configuration(Cid cid, Continuation is_continuation,
                                                       std::vector<std::unique_ptr<ConfigurationOption>> options) {
  auto channel = channel_allocator_->FindChannelByCid(cid);
@@ -429,7 +394,9 @@ void ClassicSignallingManager::negotiate_configuration(Cid cid, Continuation is_
    }
  }
  if (can_negotiate) {
    SendConfigurationRequest(channel->GetRemoteCid(), std::move(negotiation_config));
    send_configuration_request(channel->GetRemoteCid(), std::move(negotiation_config));
  } else {
    LOG_DEBUG("No suggested parameter received");
  }
}

@@ -457,6 +424,7 @@ void ClassicSignallingManager::OnConfigurationResponse(SignalId signal_id, Cid c
    case ConfigurationResponseResult::UNKNOWN_OPTIONS:
    case ConfigurationResponseResult::FLOW_SPEC_REJECTED:
      LOG_WARN("Configuration response not SUCCESS: %s", ConfigurationResponseResultText(result).c_str());
      alarm_.Cancel();
      handle_send_next_command();
      return;

@@ -490,7 +458,12 @@ void ClassicSignallingManager::OnConfigurationResponse(SignalId signal_id, Cid c
      }
      case ConfigurationOptionType::RETRANSMISSION_AND_FLOW_CONTROL: {
        auto config = RetransmissionAndFlowControlConfigurationOption::Specialize(option.get());
        configuration_state.retransmission_and_flow_control_mode_ = config->mode_;
        if (configuration_state.retransmission_and_flow_control_mode_ != config->mode_) {
          SendDisconnectionRequest(cid, channel->GetRemoteCid());
          alarm_.Cancel();
          handle_send_next_command();
          return;
        }
        configuration_state.local_retransmission_and_flow_control_ = *config;
        break;
      }
@@ -500,6 +473,8 @@ void ClassicSignallingManager::OnConfigurationResponse(SignalId signal_id, Cid c
      }
      default:
        LOG_WARN("Received some unsupported configuration option: %d", static_cast<int>(option->type_));
        alarm_.Cancel();
        handle_send_next_command();
        return;
    }
  }
@@ -597,7 +572,6 @@ void ClassicSignallingManager::OnInformationRequest(SignalId signal_id, Informat
      break;
    }
    case InformationRequestInfoType::EXTENDED_FEATURES_SUPPORTED: {
      // TODO: implement this response
      auto response = InformationResponseExtendedFeaturesBuilder::Create(
          signal_id.Value(), InformationRequestResult::SUCCESS, 0, 0, 0, 1 /* ERTM */, 0 /* Streaming mode */,
          1 /* FCS */, 0, 1 /* Fixed Channels */, 0, 0);
+3 −1
Original line number Diff line number Diff line
@@ -66,7 +66,7 @@ class ClassicSignallingManager {

  void SendConnectionRequest(Psm psm, Cid local_cid);

  void SendConfigurationRequest(Cid remote_cid, std::vector<std::unique_ptr<ConfigurationOption>> config);
  void SendInitialConfigRequest(Cid local_cid);

  void SendDisconnectionRequest(Cid local_cid, Cid remote_cid);

@@ -109,6 +109,8 @@ class ClassicSignallingManager {
  void negotiate_configuration(Cid cid, Continuation is_continuation,
                               std::vector<std::unique_ptr<ConfigurationOption>>);

  void send_configuration_request(Cid remote_cid, std::vector<std::unique_ptr<ConfigurationOption>> config);

  os::Handler* handler_;
  Link* link_;
  l2cap::internal::DataPipelineManager* data_pipeline_manager_;