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();
 }