L2CAP: Save remote supported features in link
Save extended_features_supported. Don't send ERTM in initial config
request if remote doesn't support.
Test: run_cert.sh
Bug: 144770885
Change-Id: I17ee89855b0a05bd3265295f909b28787da355e9
diff --git a/gd/l2cap/classic/cert/cert.cc b/gd/l2cap/classic/cert/cert.cc
index 31c4760..63c8593 100644
--- a/gd/l2cap/classic/cert/cert.cc
+++ b/gd/l2cap/classic/cert/cert.cc
@@ -209,7 +209,7 @@
switch (request->type()) {
case InformationRequestType::CONNECTIONLESS_MTU: {
auto builder = InformationResponseConnectionlessMtuBuilder::Create(request->signal_id(),
- InformationRequestResult::NOT_SUPPORTED, 0);
+ InformationRequestResult::SUCCESS, 100);
auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder));
outgoing_packet_queue_.push(std::move(l2cap_builder));
send_packet_from_queue();
@@ -217,7 +217,7 @@
}
case InformationRequestType::EXTENDED_FEATURES: {
auto builder = InformationResponseExtendedFeaturesBuilder::Create(
- request->signal_id(), InformationRequestResult::NOT_SUPPORTED, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ request->signal_id(), InformationRequestResult::SUCCESS, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0);
auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder));
outgoing_packet_queue_.push(std::move(l2cap_builder));
send_packet_from_queue();
diff --git a/gd/l2cap/classic/internal/link.cc b/gd/l2cap/classic/internal/link.cc
index bc31996..7b5178f 100644
--- a/gd/l2cap/classic/internal/link.cc
+++ b/gd/l2cap/classic/internal/link.cc
@@ -157,6 +157,30 @@
local_cid_to_pending_dynamic_channel_connection_map_.erase(cid);
}
+void Link::SetRemoteConnectionlessMtu(Mtu mtu) {
+ remote_mtu_ = mtu;
+}
+
+Mtu Link::GetRemoteConnectionlessMtu() const {
+ return remote_mtu_;
+}
+
+void Link::SetRemoteSupportsErtm(bool supported) {
+ remote_supports_ertm_ = supported;
+}
+
+bool Link::GetRemoteSupportsErtm() const {
+ return remote_supports_ertm_;
+}
+
+void Link::SetRemoteSupportsFcs(bool supported) {
+ remote_supports_fcs_ = supported;
+}
+
+bool Link::GetRemoteSupportsFcs() const {
+ return remote_supports_fcs_;
+}
+
} // namespace internal
} // namespace classic
} // namespace l2cap
diff --git a/gd/l2cap/classic/internal/link.h b/gd/l2cap/classic/internal/link.h
index 7ed82e9..2c6c1b8 100644
--- a/gd/l2cap/classic/internal/link.h
+++ b/gd/l2cap/classic/internal/link.h
@@ -99,6 +99,14 @@
virtual void NotifyChannelCreation(Cid cid, std::unique_ptr<DynamicChannel> channel);
virtual void NotifyChannelFail(Cid cid);
+ // Information received from signalling channel
+ virtual void SetRemoteConnectionlessMtu(Mtu mtu);
+ virtual Mtu GetRemoteConnectionlessMtu() const;
+ virtual void SetRemoteSupportsErtm(bool supported);
+ virtual bool GetRemoteSupportsErtm() const;
+ virtual void SetRemoteSupportsFcs(bool supported);
+ virtual bool GetRemoteSupportsFcs() const;
+
private:
os::Handler* l2cap_handler_;
l2cap::internal::FixedChannelAllocator<FixedChannelImpl, Link> fixed_channel_allocator_{this, l2cap_handler_};
@@ -112,6 +120,9 @@
ClassicSignallingManager signalling_manager_;
std::unordered_map<Cid, PendingDynamicChannelConnection> local_cid_to_pending_dynamic_channel_connection_map_;
os::Alarm link_idle_disconnect_alarm_{l2cap_handler_};
+ Mtu remote_mtu_ = kMinimumClassicMtu;
+ bool remote_supports_ertm_ = false;
+ bool remote_supports_fcs_ = false;
DISALLOW_COPY_AND_ASSIGN(Link);
};
diff --git a/gd/l2cap/classic/internal/signalling_manager.cc b/gd/l2cap/classic/internal/signalling_manager.cc
index d86621c..66a3f51 100644
--- a/gd/l2cap/classic/internal/signalling_manager.cc
+++ b/gd/l2cap/classic/internal/signalling_manager.cc
@@ -149,6 +149,9 @@
ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE);
auto* service = dynamic_service_manager_->GetService(psm);
auto initial_config = service->GetConfigOption();
+ if (!link_->GetRemoteSupportsErtm()) {
+ initial_config.channel_mode = DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::L2CAP_BASIC;
+ }
auto mtu_configuration = std::make_unique<MtuConfigurationOption>();
mtu_configuration->mtu_ = initial_config.incoming_mtu;
auto fcs_option = std::make_unique<FrameCheckSequenceOption>();
@@ -209,6 +212,9 @@
}
alarm_.Cancel();
auto initial_config = link_->GetConfigurationForInitialConfiguration(new_channel->GetCid());
+ if (!link_->GetRemoteSupportsErtm()) {
+ initial_config.channel_mode = DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::L2CAP_BASIC;
+ }
auto mtu_configuration = std::make_unique<MtuConfigurationOption>();
mtu_configuration->mtu_ = initial_config.incoming_mtu;
auto retransmission_flow_control_configuration = std::make_unique<RetransmissionAndFlowControlConfigurationOption>();
@@ -407,7 +413,7 @@
}
}
-void ClassicSignallingManager::OnInformationResponse(SignalId signal_id, const InformationResponseView& view) {
+void ClassicSignallingManager::OnInformationResponse(SignalId signal_id, const InformationResponseView& response) {
if (pending_commands_.empty()) {
LOG_WARN("Unexpected response: no pending request");
return;
@@ -419,7 +425,40 @@
last_sent_command.command_code_ != CommandCode::INFORMATION_REQUEST) {
return;
}
- // TODO (hsz): Store the information response
+
+ auto type = response.GetInfoType();
+ switch (type) {
+ case InformationRequestInfoType::CONNECTIONLESS_MTU: {
+ auto view = InformationResponseConnectionlessMtuView::Create(response);
+ if (!view.IsValid()) {
+ LOG_WARN("Invalid InformationResponseConnectionlessMtu received");
+ return;
+ }
+ link_->SetRemoteConnectionlessMtu(view.GetConnectionlessMtu());
+ break;
+ }
+ case InformationRequestInfoType::EXTENDED_FEATURES_SUPPORTED: {
+ auto view = InformationResponseExtendedFeaturesView::Create(response);
+ if (!view.IsValid()) {
+ LOG_WARN("Invalid InformationResponseExtendedFeatures received");
+ return;
+ }
+ link_->SetRemoteSupportsErtm((view.GetEnhancedRetransmissionMode()));
+ link_->SetRemoteSupportsFcs(view.GetFcsOption());
+ // We don't care about other parameters
+ break;
+ }
+ case InformationRequestInfoType::FIXED_CHANNELS_SUPPORTED: {
+ auto view = InformationResponseFixedChannelsView::Create(response);
+ if (!view.IsValid()) {
+ LOG_WARN("Invalid InformationResponseFixedChannel received");
+ return;
+ }
+ // We don't use fixed channels (connectionless or BR/EDR security) for now so we don't care
+ break;
+ }
+ }
+
alarm_.Cancel();
handle_send_next_command();
}
diff --git a/gd/l2cap/classic/internal/signalling_manager.h b/gd/l2cap/classic/internal/signalling_manager.h
index 0ec6a28..0e17ec7 100644
--- a/gd/l2cap/classic/internal/signalling_manager.h
+++ b/gd/l2cap/classic/internal/signalling_manager.h
@@ -92,7 +92,7 @@
void OnInformationRequest(SignalId signal_id, InformationRequestInfoType type);
- void OnInformationResponse(SignalId signal_id, const InformationResponseView& view);
+ void OnInformationResponse(SignalId signal_id, const InformationResponseView& response);
private:
void on_incoming_packet();