L2CAP Classic: Unreserve channel on connection response fail
Free the reserved cid when dynamic channel isn't opened
Test: bluetooth_test_gd and run_cert.sh
Bug: 145626799
Change-Id: I64f5e59cc15a1188cec94c827f7c5ea147803e22
diff --git a/gd/l2cap/classic/internal/link.cc b/gd/l2cap/classic/internal/link.cc
index ce55020..18e6703 100644
--- a/gd/l2cap/classic/internal/link.cc
+++ b/gd/l2cap/classic/internal/link.cc
@@ -79,6 +79,11 @@
signalling_manager_.SendConnectionRequest(psm, local_cid);
}
+void Link::OnOutgoingConnectionRequestFail(Cid local_cid) {
+ local_cid_to_pending_dynamic_channel_connection_map_.erase(local_cid);
+ dynamic_channel_allocator_.FreeChannel(local_cid);
+}
+
void Link::SendDisconnectionRequest(Cid local_cid, Cid remote_cid) {
signalling_manager_.SendDisconnectionRequest(local_cid, remote_cid);
}
diff --git a/gd/l2cap/classic/internal/link.h b/gd/l2cap/classic/internal/link.h
index 7a1c6dd..b29d767 100644
--- a/gd/l2cap/classic/internal/link.h
+++ b/gd/l2cap/classic/internal/link.h
@@ -79,6 +79,9 @@
virtual void SendConnectionRequest(Psm psm, Cid local_cid,
PendingDynamicChannelConnection pending_dynamic_channel_connection);
+ // Invoked by signalling manager to indicate an outgoing connection request failed and link shall free resources
+ virtual void OnOutgoingConnectionRequestFail(Cid local_cid);
+
virtual void SendInformationRequest(InformationRequestInfoType type);
virtual void SendDisconnectionRequest(Cid local_cid, Cid remote_cid) override;
diff --git a/gd/l2cap/classic/internal/signalling_manager.cc b/gd/l2cap/classic/internal/signalling_manager.cc
index 4adf633..869094e 100644
--- a/gd/l2cap/classic/internal/signalling_manager.cc
+++ b/gd/l2cap/classic/internal/signalling_manager.cc
@@ -217,6 +217,7 @@
}
alarm_.Cancel();
if (result != ConnectionResponseResult::SUCCESS) {
+ link_->OnOutgoingConnectionRequestFail(cid);
handle_send_next_command();
return;
}
@@ -224,6 +225,7 @@
auto new_channel = link_->AllocateReservedDynamicChannel(cid, pending_psm, remote_cid, {});
if (new_channel == nullptr) {
LOG_WARN("Can't allocate dynamic channel");
+ link_->OnOutgoingConnectionRequestFail(cid);
handle_send_next_command();
return;
}
@@ -665,6 +667,10 @@
auto last_sent_command = std::move(pending_commands_.front());
pending_commands_.pop();
switch (last_sent_command.command_code_) {
+ case CommandCode::CONNECTION_REQUEST: {
+ link_->OnOutgoingConnectionRequestFail(last_sent_command.source_cid_);
+ break;
+ }
case CommandCode::CONFIGURATION_REQUEST: {
SendDisconnectionRequest(last_sent_command.source_cid_, last_sent_command.destination_cid_);
break;
diff --git a/gd/l2cap/internal/dynamic_channel_allocator.cc b/gd/l2cap/internal/dynamic_channel_allocator.cc
index 6f00274..d0713a4 100644
--- a/gd/l2cap/internal/dynamic_channel_allocator.cc
+++ b/gd/l2cap/internal/dynamic_channel_allocator.cc
@@ -87,6 +87,7 @@
}
void DynamicChannelAllocator::FreeChannel(Cid cid) {
+ used_cid_.erase(cid);
auto channel = FindChannelByCid(cid);
if (channel == nullptr) {
LOG_INFO("Channel is not in use: psm %d, device %s", cid, link_->GetDevice().ToString().c_str());
@@ -94,7 +95,6 @@
}
used_remote_cid_.erase(channel->GetRemoteCid());
channels_.erase(cid);
- used_cid_.erase(cid);
}
bool DynamicChannelAllocator::IsPsmUsed(Psm psm) const {
diff --git a/gd/l2cap/le/internal/link.cc b/gd/l2cap/le/internal/link.cc
index ed58bda..66dd580 100644
--- a/gd/l2cap/le/internal/link.cc
+++ b/gd/l2cap/le/internal/link.cc
@@ -87,6 +87,11 @@
signalling_manager_.SendDisconnectRequest(local_cid, remote_cid);
}
+void Link::OnOutgoingConnectionRequestFail(Cid local_cid) {
+ local_cid_to_pending_dynamic_channel_connection_map_.erase(local_cid);
+ dynamic_channel_allocator_.FreeChannel(local_cid);
+}
+
std::shared_ptr<l2cap::internal::DynamicChannelImpl> Link::AllocateDynamicChannel(Psm psm, Cid remote_cid,
SecurityPolicy security_policy) {
auto channel = dynamic_channel_allocator_.AllocateChannel(psm, remote_cid, security_policy);
diff --git a/gd/l2cap/le/internal/link.h b/gd/l2cap/le/internal/link.h
index 095c3d8..633aa29 100644
--- a/gd/l2cap/le/internal/link.h
+++ b/gd/l2cap/le/internal/link.h
@@ -81,6 +81,9 @@
void SendDisconnectionRequest(Cid local_cid, Cid remote_cid) override;
+ // Invoked by signalling manager to indicate an outgoing connection request failed and link shall free resources
+ virtual void OnOutgoingConnectionRequestFail(Cid local_cid);
+
virtual std::shared_ptr<l2cap::internal::DynamicChannelImpl> AllocateDynamicChannel(Psm psm, Cid remote_cid,
SecurityPolicy security_policy);
diff --git a/gd/l2cap/le/internal/signalling_manager.cc b/gd/l2cap/le/internal/signalling_manager.cc
index 63043af..a67bd12 100644
--- a/gd/l2cap/le/internal/signalling_manager.cc
+++ b/gd/l2cap/le/internal/signalling_manager.cc
@@ -181,6 +181,7 @@
command_just_sent_.signal_id_ = kInitialSignalId;
if (result != LeCreditBasedConnectionResponseResult::SUCCESS) {
LOG_WARN("Connection failed: %s", LeCreditBasedConnectionResponseResultText(result).data());
+ link_->OnOutgoingConnectionRequestFail(command_just_sent_.source_cid_);
handle_send_next_command();
return;
}
@@ -188,6 +189,7 @@
link_->AllocateReservedDynamicChannel(command_just_sent_.source_cid_, command_just_sent_.psm_, remote_cid, {});
if (new_channel == nullptr) {
LOG_WARN("Can't allocate dynamic channel");
+ link_->OnOutgoingConnectionRequestFail(command_just_sent_.source_cid_);
handle_send_next_command();
return;
}
@@ -359,10 +361,19 @@
void LeSignallingManager::on_command_timeout() {
LOG_WARN("Response time out");
- if (command_just_sent_.signal_id_ == kInitialSignalId) {
+ if (command_just_sent_.signal_id_ == kInvalidSignalId) {
LOG_ERROR("No pending command");
return;
}
+ command_just_sent_.signal_id_ = kInvalidSignalId;
+ switch (command_just_sent_.command_code_) {
+ case LeCommandCode::CONNECTION_PARAMETER_UPDATE_REQUEST: {
+ link_->OnOutgoingConnectionRequestFail(command_just_sent_.source_cid_);
+ break;
+ }
+ default:
+ break;
+ }
handle_send_next_command();
}