Merge "RootCanal: use classes in bluetooth hci namespace"
diff --git a/gd/l2cap/Android.bp b/gd/l2cap/Android.bp
index 51258b4..0bdfbd2 100644
--- a/gd/l2cap/Android.bp
+++ b/gd/l2cap/Android.bp
@@ -2,14 +2,11 @@
     name: "BluetoothL2capSources",
     srcs: [
         "fcs.cc",
-        "classic/dynamic_channel.cc",
         "classic/dynamic_channel_manager.cc",
         "classic/dynamic_channel_service.cc",
         "classic/fixed_channel.cc",
         "classic/fixed_channel_manager.cc",
         "classic/fixed_channel_service.cc",
-        "classic/internal/dynamic_channel_allocator.cc",
-        "classic/internal/dynamic_channel_impl.cc",
         "classic/internal/dynamic_channel_service_manager_impl.cc",
         "classic/internal/fixed_channel_impl.cc",
         "classic/internal/fixed_channel_service_manager_impl.cc",
@@ -17,8 +14,11 @@
         "classic/internal/link_manager.cc",
         "classic/internal/signalling_manager.cc",
         "classic/l2cap_classic_module.cc",
+        "dynamic_channel.cc",
         "internal/basic_mode_channel_data_controller.cc",
         "internal/data_pipeline_manager.cc",
+        "internal/dynamic_channel_allocator.cc",
+        "internal/dynamic_channel_impl.cc",
         "internal/enhanced_retransmission_mode_channel_data_controller.cc",
         "internal/le_credit_based_channel_data_controller.cc",
         "internal/receiver.cc",
@@ -37,14 +37,14 @@
 filegroup {
     name: "BluetoothL2capTestSources",
     srcs: [
-        "classic/internal/dynamic_channel_allocator_test.cc",
-        "classic/internal/dynamic_channel_impl_test.cc",
         "classic/internal/dynamic_channel_service_manager_test.cc",
         "classic/internal/fixed_channel_impl_test.cc",
         "classic/internal/fixed_channel_service_manager_test.cc",
         "classic/internal/link_manager_test.cc",
         "classic/internal/signalling_manager_test.cc",
         "internal/basic_mode_channel_data_controller_test.cc",
+        "internal/dynamic_channel_allocator_test.cc",
+        "internal/dynamic_channel_impl_test.cc",
         "internal/enhanced_retransmission_mode_channel_data_controller_test.cc",
         "internal/fixed_channel_allocator_test.cc",
         "internal/le_credit_based_channel_data_controller_test.cc",
@@ -76,7 +76,7 @@
 filegroup {
     name: "BluetoothL2capFuzzTestSources",
     srcs: [
-        "classic/internal/dynamic_channel_allocator_fuzz_test.cc",
+        "internal/dynamic_channel_allocator_fuzz_test.cc",
         "l2cap_packet_fuzz_test.cc",
     ],
 }
diff --git a/gd/l2cap/classic/dynamic_channel_manager.h b/gd/l2cap/classic/dynamic_channel_manager.h
index 340d68d..4810270 100644
--- a/gd/l2cap/classic/dynamic_channel_manager.h
+++ b/gd/l2cap/classic/dynamic_channel_manager.h
@@ -19,9 +19,9 @@
 
 #include "hci/acl_manager.h"
 #include "hci/address.h"
-#include "l2cap/classic/dynamic_channel.h"
 #include "l2cap/classic/dynamic_channel_configuration_option.h"
 #include "l2cap/classic/dynamic_channel_service.h"
+#include "l2cap/dynamic_channel.h"
 #include "l2cap/l2cap_packets.h"
 #include "l2cap/psm.h"
 #include "l2cap/security_policy.h"
diff --git a/gd/l2cap/classic/internal/channel_configuration_state.h b/gd/l2cap/classic/internal/channel_configuration_state.h
new file mode 100644
index 0000000..b0dead5
--- /dev/null
+++ b/gd/l2cap/classic/internal/channel_configuration_state.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "l2cap/l2cap_packets.h"
+#include "l2cap/mtu.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+struct ChannelConfigurationState {
+ public:
+  enum State {
+    /**
+     * for the initiator path, a request has been sent but a positive response has not yet been received, and for the
+     * acceptor path, a request with acceptable options has not yet been received.
+     */
+    WAIT_CONFIG_REQ_RSP,
+    /**
+     * the acceptor path is complete after having responded to acceptable options, but for the initiator path, a
+     * positive response on the recent request has not yet been received.
+     */
+    WAIT_CONFIG_RSP,
+    /**
+     * the initiator path is complete after having received a positive response, but for the acceptor path, a request
+     * with acceptable options has not yet been received.
+     */
+    WAIT_CONFIG_REQ,
+    /**
+     * Configuration is complete
+     */
+    CONFIGURED,
+  };
+  State state_ = State::WAIT_CONFIG_REQ_RSP;
+
+  Mtu incoming_mtu_ = kDefaultClassicMtu;
+  Mtu outgoing_mtu_ = kDefaultClassicMtu;
+  RetransmissionAndFlowControlModeOption retransmission_and_flow_control_mode_;
+  RetransmissionAndFlowControlConfigurationOption local_retransmission_and_flow_control_;
+  RetransmissionAndFlowControlConfigurationOption remote_retransmission_and_flow_control_;
+  FcsType fcs_type_ = FcsType::DEFAULT;
+};
+}  // namespace internal
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/dynamic_channel_service_impl.h b/gd/l2cap/classic/internal/dynamic_channel_service_impl.h
index 2fcf3fc..672d24b 100644
--- a/gd/l2cap/classic/internal/dynamic_channel_service_impl.h
+++ b/gd/l2cap/classic/internal/dynamic_channel_service_impl.h
@@ -18,10 +18,10 @@
 
 #include "common/bind.h"
 
-#include "l2cap/classic/dynamic_channel.h"
 #include "l2cap/classic/dynamic_channel_configuration_option.h"
 #include "l2cap/classic/dynamic_channel_manager.h"
 #include "l2cap/classic/dynamic_channel_service.h"
+#include "l2cap/dynamic_channel.h"
 
 namespace bluetooth {
 namespace l2cap {
diff --git a/gd/l2cap/classic/internal/dynamic_channel_service_manager_impl_mock.h b/gd/l2cap/classic/internal/dynamic_channel_service_manager_impl_mock.h
index 34363f1..05d4b7f 100644
--- a/gd/l2cap/classic/internal/dynamic_channel_service_manager_impl_mock.h
+++ b/gd/l2cap/classic/internal/dynamic_channel_service_manager_impl_mock.h
@@ -15,8 +15,8 @@
  */
 #pragma once
 
-#include "l2cap/classic/internal/dynamic_channel_impl.h"
 #include "l2cap/classic/internal/dynamic_channel_service_manager_impl.h"
+#include "l2cap/internal/dynamic_channel_impl.h"
 
 #include <gmock/gmock.h>
 
diff --git a/gd/l2cap/classic/internal/fixed_channel_impl.cc b/gd/l2cap/classic/internal/fixed_channel_impl.cc
index 8ac6c94..9bfaef8 100644
--- a/gd/l2cap/classic/internal/fixed_channel_impl.cc
+++ b/gd/l2cap/classic/internal/fixed_channel_impl.cc
@@ -94,8 +94,6 @@
   link_->RefreshRefCount();
 }
 
-void FixedChannelImpl::SetSender(l2cap::internal::Sender* sender) {}
-
 }  // namespace internal
 }  // namespace classic
 }  // namespace l2cap
diff --git a/gd/l2cap/classic/internal/fixed_channel_impl.h b/gd/l2cap/classic/internal/fixed_channel_impl.h
index 6fde5c6..4c4e9f1 100644
--- a/gd/l2cap/classic/internal/fixed_channel_impl.h
+++ b/gd/l2cap/classic/internal/fixed_channel_impl.h
@@ -38,7 +38,7 @@
   virtual ~FixedChannelImpl() = default;
 
   hci::Address GetDevice() const {
-    return device_;
+    return device_.GetAddress();
   }
 
   virtual void RegisterOnCloseCallback(os::Handler* user_handler, FixedChannel::OnCloseCallback on_close_callback);
@@ -74,14 +74,13 @@
   Cid GetRemoteCid() const {
     return cid_;
   }
-  void SetSender(l2cap::internal::Sender* sender) override;
 
  private:
   // Constructor states
   // For logging purpose only
   const Cid cid_;
   // For logging purpose only
-  const hci::Address device_;
+  const hci::AddressWithType device_;
   // Needed to handle Acquire() and Release()
   Link* link_;
   os::Handler* l2cap_handler_;
diff --git a/gd/l2cap/classic/internal/fixed_channel_impl_test.cc b/gd/l2cap/classic/internal/fixed_channel_impl_test.cc
index 750473d..3a35d82 100644
--- a/gd/l2cap/classic/internal/fixed_channel_impl_test.cc
+++ b/gd/l2cap/classic/internal/fixed_channel_impl_test.cc
@@ -61,16 +61,18 @@
 TEST_F(L2capClassicFixedChannelImplTest, get_device) {
   MockParameterProvider mock_parameter_provider;
   MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
-  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  hci::AddressWithType device{hci::Address{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
+                              hci::AddressType::PUBLIC_IDENTITY_ADDRESS};
   EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
   FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
-  EXPECT_EQ(device, fixed_channel_impl.GetDevice());
+  EXPECT_EQ(device.GetAddress(), fixed_channel_impl.GetDevice());
 }
 
 TEST_F(L2capClassicFixedChannelImplTest, close_triggers_callback) {
   MockParameterProvider mock_parameter_provider;
   MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
-  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  hci::AddressWithType device{hci::Address{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
+                              hci::AddressType::PUBLIC_IDENTITY_ADDRESS};
   EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
   FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
 
@@ -91,7 +93,8 @@
 TEST_F(L2capClassicFixedChannelImplTest, register_callback_after_close_should_call_immediately) {
   MockParameterProvider mock_parameter_provider;
   MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
-  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  hci::AddressWithType device{hci::Address{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
+                              hci::AddressType::PUBLIC_IDENTITY_ADDRESS};
   EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
   FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
 
@@ -112,7 +115,8 @@
 TEST_F(L2capClassicFixedChannelImplTest, close_twice_should_fail) {
   MockParameterProvider mock_parameter_provider;
   MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
-  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  hci::AddressWithType device{hci::Address{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
+                              hci::AddressType::PUBLIC_IDENTITY_ADDRESS};
   EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
   FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
 
@@ -136,7 +140,8 @@
 TEST_F(L2capClassicFixedChannelImplTest, multiple_registeration_should_fail) {
   MockParameterProvider mock_parameter_provider;
   MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
-  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  hci::AddressWithType device{hci::Address{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
+                              hci::AddressType::PUBLIC_IDENTITY_ADDRESS};
   EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
   FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
 
@@ -156,7 +161,8 @@
 TEST_F(L2capClassicFixedChannelImplTest, call_acquire_before_registeration_should_fail) {
   MockParameterProvider mock_parameter_provider;
   MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
-  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  hci::AddressWithType device{hci::Address{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
+                              hci::AddressType::PUBLIC_IDENTITY_ADDRESS};
   EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
   FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
   EXPECT_DEATH(fixed_channel_impl.Acquire(), ".*Acquire.*");
@@ -165,7 +171,8 @@
 TEST_F(L2capClassicFixedChannelImplTest, call_release_before_registeration_should_fail) {
   MockParameterProvider mock_parameter_provider;
   MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
-  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  hci::AddressWithType device{hci::Address{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
+                              hci::AddressType::PUBLIC_IDENTITY_ADDRESS};
   EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
   FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
   EXPECT_DEATH(fixed_channel_impl.Release(), ".*Release.*");
@@ -174,7 +181,8 @@
 TEST_F(L2capClassicFixedChannelImplTest, test_acquire_release_channel) {
   MockParameterProvider mock_parameter_provider;
   MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
-  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  hci::AddressWithType device{hci::Address{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
+                              hci::AddressType::PUBLIC_IDENTITY_ADDRESS};
   EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
   FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
 
@@ -202,7 +210,8 @@
 TEST_F(L2capClassicFixedChannelImplTest, test_acquire_after_close) {
   MockParameterProvider mock_parameter_provider;
   MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
-  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  hci::AddressWithType device{hci::Address{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
+                              hci::AddressType::PUBLIC_IDENTITY_ADDRESS};
   EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
   FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
 
diff --git a/gd/l2cap/classic/internal/link.cc b/gd/l2cap/classic/internal/link.cc
index 63f5f71..a23f5ec 100644
--- a/gd/l2cap/classic/internal/link.cc
+++ b/gd/l2cap/classic/internal/link.cc
@@ -36,8 +36,8 @@
     : l2cap_handler_(l2cap_handler), acl_connection_(std::move(acl_connection)),
       data_pipeline_manager_(l2cap_handler, acl_connection_->GetAclQueueEnd()), parameter_provider_(parameter_provider),
       dynamic_service_manager_(dynamic_service_manager), fixed_service_manager_(fixed_service_manager),
-      signalling_manager_(l2cap_handler_, this, dynamic_service_manager_, &dynamic_channel_allocator_,
-                          fixed_service_manager_) {
+      signalling_manager_(l2cap_handler_, this, &data_pipeline_manager_, dynamic_service_manager_,
+                          &dynamic_channel_allocator_, fixed_service_manager_) {
   ASSERT(l2cap_handler_ != nullptr);
   ASSERT(acl_connection_ != nullptr);
   ASSERT(parameter_provider_ != nullptr);
@@ -86,8 +86,8 @@
   signalling_manager_.SendInformationRequest(type);
 }
 
-std::shared_ptr<DynamicChannelImpl> Link::AllocateDynamicChannel(Psm psm, Cid remote_cid,
-                                                                 SecurityPolicy security_policy) {
+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);
   if (channel != nullptr) {
     data_pipeline_manager_.AttachChannel(channel->GetCid(), channel);
@@ -96,8 +96,8 @@
   return channel;
 }
 
-std::shared_ptr<DynamicChannelImpl> Link::AllocateReservedDynamicChannel(Cid reserved_cid, Psm psm, Cid remote_cid,
-                                                                         SecurityPolicy security_policy) {
+std::shared_ptr<l2cap::internal::DynamicChannelImpl> Link::AllocateReservedDynamicChannel(
+    Cid reserved_cid, Psm psm, Cid remote_cid, SecurityPolicy security_policy) {
   auto channel = dynamic_channel_allocator_.AllocateReservedChannel(reserved_cid, psm, remote_cid, security_policy);
   if (channel != nullptr) {
     data_pipeline_manager_.AttachChannel(channel->GetCid(), channel);
diff --git a/gd/l2cap/classic/internal/link.h b/gd/l2cap/classic/internal/link.h
index 44a5b25..8e1e0c9 100644
--- a/gd/l2cap/classic/internal/link.h
+++ b/gd/l2cap/classic/internal/link.h
@@ -21,13 +21,14 @@
 
 #include "hci/acl_manager.h"
 #include "l2cap/classic/dynamic_channel_configuration_option.h"
-#include "l2cap/classic/internal/dynamic_channel_allocator.h"
-#include "l2cap/classic/internal/dynamic_channel_impl.h"
 #include "l2cap/classic/internal/dynamic_channel_service_manager_impl.h"
 #include "l2cap/classic/internal/fixed_channel_impl.h"
 #include "l2cap/classic/internal/fixed_channel_service_manager_impl.h"
 #include "l2cap/internal/data_pipeline_manager.h"
+#include "l2cap/internal/dynamic_channel_allocator.h"
+#include "l2cap/internal/dynamic_channel_impl.h"
 #include "l2cap/internal/fixed_channel_allocator.h"
+#include "l2cap/internal/ilink.h"
 #include "l2cap/internal/parameter_provider.h"
 #include "os/alarm.h"
 #include "os/handler.h"
@@ -38,7 +39,7 @@
 namespace classic {
 namespace internal {
 
-class Link {
+class Link : public l2cap::internal::ILink {
  public:
   Link(os::Handler* l2cap_handler, std::unique_ptr<hci::AclConnection> acl_connection,
        l2cap::internal::ParameterProvider* parameter_provider,
@@ -47,8 +48,8 @@
 
   virtual ~Link() = default;
 
-  virtual hci::Address GetDevice() {
-    return acl_connection_->GetAddress();
+  virtual hci::AddressWithType GetDevice() {
+    return {acl_connection_->GetAddress(), acl_connection_->GetAddressType()};
   }
 
   struct PendingDynamicChannelConnection {
@@ -80,13 +81,13 @@
 
   virtual void SendInformationRequest(InformationRequestInfoType type);
 
-  virtual void SendDisconnectionRequest(Cid local_cid, Cid remote_cid);
+  virtual void SendDisconnectionRequest(Cid local_cid, Cid remote_cid) override;
 
-  virtual std::shared_ptr<DynamicChannelImpl> AllocateDynamicChannel(Psm psm, Cid remote_cid,
-                                                                     SecurityPolicy security_policy);
+  virtual std::shared_ptr<l2cap::internal::DynamicChannelImpl> AllocateDynamicChannel(Psm psm, Cid remote_cid,
+                                                                                      SecurityPolicy security_policy);
 
-  virtual std::shared_ptr<DynamicChannelImpl> AllocateReservedDynamicChannel(Cid reserved_cid, Psm psm, Cid remote_cid,
-                                                                             SecurityPolicy security_policy);
+  virtual std::shared_ptr<l2cap::internal::DynamicChannelImpl> AllocateReservedDynamicChannel(
+      Cid reserved_cid, Psm psm, Cid remote_cid, SecurityPolicy security_policy);
 
   virtual classic::DynamicChannelConfigurationOption GetConfigurationForInitialConfiguration(Cid cid);
 
@@ -113,7 +114,7 @@
  private:
   os::Handler* l2cap_handler_;
   l2cap::internal::FixedChannelAllocator<FixedChannelImpl, Link> fixed_channel_allocator_{this, l2cap_handler_};
-  DynamicChannelAllocator dynamic_channel_allocator_{this, l2cap_handler_};
+  l2cap::internal::DynamicChannelAllocator dynamic_channel_allocator_{this, l2cap_handler_};
   std::unique_ptr<hci::AclConnection> acl_connection_;
   l2cap::internal::DataPipelineManager data_pipeline_manager_;
   l2cap::internal::ParameterProvider* parameter_provider_;
diff --git a/gd/l2cap/classic/internal/link_manager.cc b/gd/l2cap/classic/internal/link_manager.cc
index 812b180..96e1333 100644
--- a/gd/l2cap/classic/internal/link_manager.cc
+++ b/gd/l2cap/classic/internal/link_manager.cc
@@ -20,7 +20,6 @@
 #include "hci/address.h"
 #include "l2cap/classic/internal/link.h"
 #include "l2cap/internal/scheduler_fifo.h"
-#include "os/handler.h"
 #include "os/log.h"
 
 #include "l2cap/classic/internal/link_manager.h"
diff --git a/gd/l2cap/classic/internal/link_mock.h b/gd/l2cap/classic/internal/link_mock.h
index cbbad15..4eb336e 100644
--- a/gd/l2cap/classic/internal/link_mock.h
+++ b/gd/l2cap/classic/internal/link_mock.h
@@ -38,10 +38,10 @@
   explicit MockLink(os::Handler* handler, l2cap::internal::ParameterProvider* parameter_provider,
                     std::unique_ptr<hci::AclConnection> acl_connection)
       : Link(handler, std::move(acl_connection), parameter_provider, nullptr, nullptr){};
-  MOCK_METHOD(hci::Address, GetDevice, (), (override));
+  MOCK_METHOD(hci::AddressWithType, GetDevice, (), (override));
   MOCK_METHOD(void, OnAclDisconnected, (hci::ErrorCode status), (override));
   MOCK_METHOD(void, Disconnect, (), (override));
-  MOCK_METHOD(std::shared_ptr<DynamicChannelImpl>, AllocateDynamicChannel,
+  MOCK_METHOD(std::shared_ptr<l2cap::internal::DynamicChannelImpl>, AllocateDynamicChannel,
               (Psm psm, Cid cid, SecurityPolicy security_policy), (override));
   MOCK_METHOD(bool, IsFixedChannelAllocated, (Cid cid), (override));
   MOCK_METHOD(void, RefreshRefCount, (), (override));
diff --git a/gd/l2cap/classic/internal/signalling_manager.cc b/gd/l2cap/classic/internal/signalling_manager.cc
index 7398c17..a89d0ad 100644
--- a/gd/l2cap/classic/internal/signalling_manager.cc
+++ b/gd/l2cap/classic/internal/signalling_manager.cc
@@ -19,7 +19,9 @@
 #include <chrono>
 
 #include "common/bind.h"
+#include "l2cap/classic/internal/channel_configuration_state.h"
 #include "l2cap/classic/internal/link.h"
+#include "l2cap/internal/data_pipeline_manager.h"
 #include "l2cap/l2cap_packets.h"
 #include "os/log.h"
 #include "packet/raw_builder.h"
@@ -31,11 +33,13 @@
 static constexpr auto kTimeout = std::chrono::seconds(3);
 
 ClassicSignallingManager::ClassicSignallingManager(os::Handler* handler, Link* link,
+                                                   l2cap::internal::DataPipelineManager* data_pipeline_manager,
                                                    DynamicChannelServiceManagerImpl* dynamic_service_manager,
-                                                   DynamicChannelAllocator* channel_allocator,
+                                                   l2cap::internal::DynamicChannelAllocator* channel_allocator,
                                                    FixedChannelServiceManagerImpl* fixed_service_manager)
-    : handler_(handler), link_(link), dynamic_service_manager_(dynamic_service_manager),
-      channel_allocator_(channel_allocator), fixed_service_manager_(fixed_service_manager), alarm_(handler) {
+    : handler_(handler), link_(link), data_pipeline_manager_(data_pipeline_manager),
+      dynamic_service_manager_(dynamic_service_manager), channel_allocator_(channel_allocator),
+      fixed_service_manager_(fixed_service_manager), alarm_(handler) {
   ASSERT(handler_ != nullptr);
   ASSERT(link_ != nullptr);
   signalling_channel_ = link_->AllocateFixedChannel(kClassicSignallingCid, {});
@@ -147,23 +151,35 @@
   }
   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::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>();
   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>();
-  fcs_option->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:
       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;
@@ -172,9 +188,8 @@
       retransmission_flow_control_configuration->maximum_pdu_size_ = 1010;
       break;
   }
+  configuration_state.local_retransmission_and_flow_control_ = *retransmission_flow_control_configuration;
 
-  new_channel->SetRetransmissionFlowControlConfig(*retransmission_flow_control_configuration);
-  new_channel->SetIncomingMtu(initial_config.incoming_mtu);
   std::vector<std::unique_ptr<ConfigurationOption>> config;
   config.emplace_back(std::move(mtu_configuration));
   config.emplace_back(std::move(retransmission_flow_control_configuration));
@@ -211,20 +226,35 @@
     return;
   }
   alarm_.Cancel();
+
+  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;
+  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>();
   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>();
   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:
       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;
@@ -233,11 +263,12 @@
       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(retransmission_flow_control_configuration));
+  config.emplace_back(std::move(fcs_option));
   SendConfigurationRequest(remote_cid, {});
 }
 
@@ -249,10 +280,13 @@
     return;
   }
 
+  auto& configuration_state = channel_configuration_[cid];
+
   for (auto& option : options) {
     switch (option->type_) {
       case ConfigurationOptionType::MTU: {
-        channel->SetIncomingMtu(MtuConfigurationOption::Specialize(option.get())->mtu_);
+        configuration_state.outgoing_mtu_ = MtuConfigurationOption::Specialize(option.get())->mtu_;
+        // TODO: If less than minimum (required by spec), reject
         break;
       }
       case ConfigurationOptionType::FLUSH_TIMEOUT: {
@@ -261,11 +295,11 @@
       }
       case ConfigurationOptionType::RETRANSMISSION_AND_FLOW_CONTROL: {
         auto config = RetransmissionAndFlowControlConfigurationOption::Specialize(option.get());
-        channel->SetRetransmissionFlowControlConfig(*config);
+        configuration_state.remote_retransmission_and_flow_control_ = *config;
         break;
       }
       case ConfigurationOptionType::FRAME_CHECK_SEQUENCE: {
-        channel->SetFcsType(FrameCheckSequenceOption::Specialize(option.get())->fcs_type_);
+        configuration_state.fcs_type_ = FrameCheckSequenceOption::Specialize(option.get())->fcs_type_;
         break;
       }
       default:
@@ -278,18 +312,22 @@
     }
   }
 
-  auto response = ConfigurationResponseBuilder::Create(signal_id.Value(), channel->GetRemoteCid(), is_continuation,
-                                                       ConfigurationResponseResult::SUCCESS, {});
-  enqueue_buffer_->Enqueue(std::move(response), handler_);
-  channel->SetIncomingConfigurationStatus(DynamicChannelImpl::ConfigurationStatus::CONFIGURED);
-  if (channel->GetOutgoingConfigurationStatus() == DynamicChannelImpl::ConfigurationStatus::CONFIGURED) {
+  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_) {
       link_->NotifyChannelCreation(cid, std::move(user_channel));
     } else {
       dynamic_service_manager_->GetService(channel->GetPsm())->NotifyChannelCreation(std::move(user_channel));
     }
+    configuration_state.state_ = ChannelConfigurationState::State::CONFIGURED;
+    data_pipeline_manager_->UpdateClassicConfiguration(cid, configuration_state);
+  } else if (configuration_state.state_ == ChannelConfigurationState::State::WAIT_CONFIG_REQ_RSP) {
+    configuration_state.state_ = ChannelConfigurationState::State::WAIT_CONFIG_RSP;
   }
+
+  auto response = ConfigurationResponseBuilder::Create(signal_id.Value(), channel->GetRemoteCid(), is_continuation,
+                                                       ConfigurationResponseResult::SUCCESS, {});
+  enqueue_buffer_->Enqueue(std::move(response), handler_);
 }
 
 void ClassicSignallingManager::OnConfigurationResponse(SignalId signal_id, Cid cid, Continuation is_continuation,
@@ -310,15 +348,50 @@
     return;
   }
 
-  channel->SetOutgoingConfigurationStatus(DynamicChannelImpl::ConfigurationStatus::CONFIGURED);
-  if (channel->GetIncomingConfigurationStatus() == DynamicChannelImpl::ConfigurationStatus::CONFIGURED) {
+  // TODO: Handle status not SUCCESS
+
+  auto& configuration_state = channel_configuration_[channel->GetCid()];
+
+  for (auto& option : options) {
+    switch (option->type_) {
+      case ConfigurationOptionType::MTU: {
+        auto config = MtuConfigurationOption::Specialize(option.get());
+        configuration_state.incoming_mtu_ = config->mtu_;
+        break;
+      }
+      case ConfigurationOptionType::FLUSH_TIMEOUT: {
+        // TODO: Handle this configuration option
+        break;
+      }
+      case ConfigurationOptionType::RETRANSMISSION_AND_FLOW_CONTROL: {
+        auto config = RetransmissionAndFlowControlConfigurationOption::Specialize(option.get());
+        configuration_state.retransmission_and_flow_control_mode_ = config->mode_;
+        configuration_state.local_retransmission_and_flow_control_ = *config;
+        break;
+      }
+      case ConfigurationOptionType::FRAME_CHECK_SEQUENCE: {
+        configuration_state.fcs_type_ = FrameCheckSequenceOption::Specialize(option.get())->fcs_type_;
+        break;
+      }
+      default:
+        LOG_WARN("Received some unsupported configuration option: %d", static_cast<int>(option->type_));
+        return;
+    }
+  }
+
+  if (configuration_state.state_ == ChannelConfigurationState::State::WAIT_CONFIG_RSP) {
     std::unique_ptr<DynamicChannel> user_channel = std::make_unique<DynamicChannel>(channel, handler_);
     if (channel->local_initiated_) {
       link_->NotifyChannelCreation(cid, std::move(user_channel));
     } else {
       dynamic_service_manager_->GetService(channel->GetPsm())->NotifyChannelCreation(std::move(user_channel));
     }
+    configuration_state.state_ = ChannelConfigurationState::State::CONFIGURED;
+    data_pipeline_manager_->UpdateClassicConfiguration(cid, configuration_state);
+  } else if (configuration_state.state_ == ChannelConfigurationState::State::WAIT_CONFIG_REQ_RSP) {
+    configuration_state.state_ = ChannelConfigurationState::State::WAIT_CONFIG_REQ;
   }
+
   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 0e17ec7..81c8c31 100644
--- a/gd/l2cap/classic/internal/signalling_manager.h
+++ b/gd/l2cap/classic/internal/signalling_manager.h
@@ -21,10 +21,12 @@
 #include <vector>
 
 #include "l2cap/cid.h"
-#include "l2cap/classic/internal/dynamic_channel_allocator.h"
+#include "l2cap/classic/internal/channel_configuration_state.h"
 #include "l2cap/classic/internal/dynamic_channel_service_manager_impl.h"
 #include "l2cap/classic/internal/fixed_channel_impl.h"
 #include "l2cap/classic/internal/fixed_channel_service_manager_impl.h"
+#include "l2cap/internal/data_pipeline_manager.h"
+#include "l2cap/internal/dynamic_channel_allocator.h"
 #include "l2cap/l2cap_packets.h"
 #include "l2cap/psm.h"
 #include "l2cap/signal_id.h"
@@ -53,8 +55,9 @@
 class ClassicSignallingManager {
  public:
   ClassicSignallingManager(os::Handler* handler, Link* link,
+                           l2cap::internal::DataPipelineManager* data_pipeline_manager,
                            classic::internal::DynamicChannelServiceManagerImpl* dynamic_service_manager,
-                           classic::internal::DynamicChannelAllocator* channel_allocator,
+                           l2cap::internal::DynamicChannelAllocator* channel_allocator,
                            classic::internal::FixedChannelServiceManagerImpl* fixed_service_manager);
 
   virtual ~ClassicSignallingManager();
@@ -103,15 +106,17 @@
 
   os::Handler* handler_;
   Link* link_;
+  [[maybe_unused]] l2cap::internal::DataPipelineManager* data_pipeline_manager_;
   std::shared_ptr<classic::internal::FixedChannelImpl> signalling_channel_;
   DynamicChannelServiceManagerImpl* dynamic_service_manager_;
-  DynamicChannelAllocator* channel_allocator_;
+  l2cap::internal::DynamicChannelAllocator* channel_allocator_;
   FixedChannelServiceManagerImpl* fixed_service_manager_;
   std::unique_ptr<os::EnqueueBuffer<packet::BasePacketBuilder>> enqueue_buffer_;
   PendingCommand last_sent_command_;
   std::queue<PendingCommand> pending_commands_;
   os::Alarm alarm_;
   SignalId next_signal_id_ = kInitialSignalId;
+  std::unordered_map<Cid, ChannelConfigurationState> channel_configuration_;
 };
 
 }  // namespace internal
diff --git a/gd/l2cap/classic/dynamic_channel.cc b/gd/l2cap/dynamic_channel.cc
similarity index 73%
rename from gd/l2cap/classic/dynamic_channel.cc
rename to gd/l2cap/dynamic_channel.cc
index b888b91..f8b64e6 100644
--- a/gd/l2cap/classic/dynamic_channel.cc
+++ b/gd/l2cap/dynamic_channel.cc
@@ -14,13 +14,12 @@
  * limitations under the License.
  */
 
-#include "l2cap/classic/dynamic_channel.h"
+#include "l2cap/dynamic_channel.h"
 #include "common/bind.h"
-#include "l2cap/classic/internal/dynamic_channel_impl.h"
+#include "l2cap/internal/dynamic_channel_impl.h"
 
 namespace bluetooth {
 namespace l2cap {
-namespace classic {
 
 hci::Address DynamicChannel::GetDevice() const {
   return impl_->GetDevice();
@@ -28,18 +27,17 @@
 
 void DynamicChannel::RegisterOnCloseCallback(os::Handler* user_handler,
                                              DynamicChannel::OnCloseCallback on_close_callback) {
-  l2cap_handler_->Post(common::BindOnce(&internal::DynamicChannelImpl::RegisterOnCloseCallback, impl_, user_handler,
-                                        std::move(on_close_callback)));
+  l2cap_handler_->Post(common::BindOnce(&l2cap::internal::DynamicChannelImpl::RegisterOnCloseCallback, impl_,
+                                        user_handler, std::move(on_close_callback)));
 }
 
 void DynamicChannel::Close() {
-  l2cap_handler_->Post(common::BindOnce(&internal::DynamicChannelImpl::Close, impl_));
+  l2cap_handler_->Post(common::BindOnce(&l2cap::internal::DynamicChannelImpl::Close, impl_));
 }
 
 common::BidiQueueEnd<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>>*
 DynamicChannel::GetQueueUpEnd() const {
   return impl_->GetQueueUpEnd();
 }
-}  // namespace classic
 }  // namespace l2cap
 }  // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/classic/dynamic_channel.h b/gd/l2cap/dynamic_channel.h
similarity index 92%
rename from gd/l2cap/classic/dynamic_channel.h
rename to gd/l2cap/dynamic_channel.h
index eb52c16..b7496f8 100644
--- a/gd/l2cap/classic/dynamic_channel.h
+++ b/gd/l2cap/dynamic_channel.h
@@ -24,7 +24,6 @@
 
 namespace bluetooth {
 namespace l2cap {
-namespace classic {
 
 namespace internal {
 class DynamicChannelImpl;
@@ -37,7 +36,7 @@
 class DynamicChannel {
  public:
   // Should only be constructed by modules that have access to LinkManager
-  DynamicChannel(std::shared_ptr<internal::DynamicChannelImpl> impl, os::Handler* l2cap_handler)
+  DynamicChannel(std::shared_ptr<l2cap::internal::DynamicChannelImpl> impl, os::Handler* l2cap_handler)
       : impl_(std::move(impl)), l2cap_handler_(l2cap_handler) {
     ASSERT(impl_ != nullptr);
     ASSERT(l2cap_handler_ != nullptr);
@@ -72,10 +71,9 @@
   common::BidiQueueEnd<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>>* GetQueueUpEnd() const;
 
  private:
-  std::shared_ptr<internal::DynamicChannelImpl> impl_;
+  std::shared_ptr<l2cap::internal::DynamicChannelImpl> impl_;
   os::Handler* l2cap_handler_;
 };
 
-}  // namespace classic
 }  // namespace l2cap
 }  // namespace bluetooth
diff --git a/gd/l2cap/internal/channel_impl.h b/gd/l2cap/internal/channel_impl.h
index ae17660..427a15f 100644
--- a/gd/l2cap/internal/channel_impl.h
+++ b/gd/l2cap/internal/channel_impl.h
@@ -47,13 +47,6 @@
   virtual Cid GetCid() const = 0;
 
   virtual Cid GetRemoteCid() const = 0;
-
-  /**
-   * Callback from the Scheduler to notify the Sender for this channel. On config update, channel might notify the
-   * configuration change to Sender.
-   * Fixed channel doesn't need to implement it, as it doesn't need to send config update to Sender.
-   */
-  virtual void SetSender(l2cap::internal::Sender* sender) = 0;
 };
 
 }  // namespace internal
diff --git a/gd/l2cap/internal/channel_impl_mock.h b/gd/l2cap/internal/channel_impl_mock.h
index 710e69a..4430487 100644
--- a/gd/l2cap/internal/channel_impl_mock.h
+++ b/gd/l2cap/internal/channel_impl_mock.h
@@ -34,7 +34,6 @@
               GetQueueDownEnd, (), (override));
   MOCK_METHOD(Cid, GetCid, (), (const, override));
   MOCK_METHOD(Cid, GetRemoteCid, (), (const, override));
-  MOCK_METHOD(void, SetSender, (l2cap::internal::Sender*), (override));
 };
 
 }  // namespace testing
diff --git a/gd/l2cap/internal/data_pipeline_manager.cc b/gd/l2cap/internal/data_pipeline_manager.cc
index d0023c0..1c8d973 100644
--- a/gd/l2cap/internal/data_pipeline_manager.cc
+++ b/gd/l2cap/internal/data_pipeline_manager.cc
@@ -30,9 +30,6 @@
   ASSERT(sender_map_.find(cid) == sender_map_.end());
   sender_map_.emplace(std::piecewise_construct, std::forward_as_tuple(cid),
                       std::forward_as_tuple(handler_, scheduler_.get(), channel));
-  if (channel->GetCid() >= kFirstDynamicChannel) {
-    channel->SetSender(&sender_map_.find(cid)->second);
-  }
 }
 
 void DataPipelineManager::DetachChannel(Cid cid) {
@@ -50,6 +47,11 @@
   sender_map_.find(cid)->second.OnPacketSent();
 }
 
+void DataPipelineManager::UpdateClassicConfiguration(Cid cid, classic::internal::ChannelConfigurationState config) {
+  ASSERT(sender_map_.find(cid) != sender_map_.end());
+  sender_map_.find(cid)->second.UpdateClassicConfiguration(config);
+}
+
 }  // namespace internal
 }  // namespace l2cap
 }  // namespace bluetooth
diff --git a/gd/l2cap/internal/data_pipeline_manager.h b/gd/l2cap/internal/data_pipeline_manager.h
index f801297..fffbfc7 100644
--- a/gd/l2cap/internal/data_pipeline_manager.h
+++ b/gd/l2cap/internal/data_pipeline_manager.h
@@ -23,6 +23,7 @@
 #include "common/bind.h"
 #include "data_controller.h"
 #include "l2cap/cid.h"
+#include "l2cap/classic/internal/channel_configuration_state.h"
 #include "l2cap/internal/channel_impl.h"
 #include "l2cap/internal/receiver.h"
 #include "l2cap/internal/scheduler.h"
@@ -61,6 +62,7 @@
   virtual void DetachChannel(Cid cid);
   virtual DataController* GetDataController(Cid cid);
   virtual void OnPacketSent(Cid cid);
+  virtual void UpdateClassicConfiguration(Cid cid, classic::internal::ChannelConfigurationState config);
   virtual ~DataPipelineManager() = default;
 
  private:
diff --git a/gd/l2cap/classic/internal/dynamic_channel_allocator.cc b/gd/l2cap/internal/dynamic_channel_allocator.cc
similarity index 97%
rename from gd/l2cap/classic/internal/dynamic_channel_allocator.cc
rename to gd/l2cap/internal/dynamic_channel_allocator.cc
index 95830e0..6f00274 100644
--- a/gd/l2cap/classic/internal/dynamic_channel_allocator.cc
+++ b/gd/l2cap/internal/dynamic_channel_allocator.cc
@@ -17,15 +17,14 @@
 #include <unordered_map>
 
 #include "l2cap/cid.h"
-#include "l2cap/classic/internal/dynamic_channel_allocator.h"
 #include "l2cap/classic/internal/link.h"
+#include "l2cap/internal/dynamic_channel_allocator.h"
+#include "l2cap/internal/dynamic_channel_impl.h"
 #include "l2cap/security_policy.h"
-#include "os/handler.h"
 #include "os/log.h"
 
 namespace bluetooth {
 namespace l2cap {
-namespace classic {
 namespace internal {
 
 std::shared_ptr<DynamicChannelImpl> DynamicChannelAllocator::AllocateChannel(Psm psm, Cid remote_cid,
@@ -135,6 +134,5 @@
 }
 
 }  // namespace internal
-}  // namespace classic
 }  // namespace l2cap
 }  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/dynamic_channel_allocator.h b/gd/l2cap/internal/dynamic_channel_allocator.h
similarity index 90%
rename from gd/l2cap/classic/internal/dynamic_channel_allocator.h
rename to gd/l2cap/internal/dynamic_channel_allocator.h
index 57e0f90..09a3588 100644
--- a/gd/l2cap/classic/internal/dynamic_channel_allocator.h
+++ b/gd/l2cap/internal/dynamic_channel_allocator.h
@@ -19,8 +19,9 @@
 #include <unordered_map>
 #include <unordered_set>
 
+#include "hci/acl_manager.h"
 #include "l2cap/cid.h"
-#include "l2cap/classic/internal/dynamic_channel_impl.h"
+#include "l2cap/internal/ilink.h"
 #include "l2cap/psm.h"
 #include "l2cap/security_policy.h"
 #include "os/handler.h"
@@ -28,16 +29,16 @@
 
 namespace bluetooth {
 namespace l2cap {
-namespace classic {
 namespace internal {
 
-class Link;
+class DynamicChannelImpl;
 
 // Helper class for keeping channels in a Link. It allocates and frees Channel object, and supports querying whether a
 // channel is in use
 class DynamicChannelAllocator {
  public:
-  DynamicChannelAllocator(Link* link, os::Handler* l2cap_handler) : link_(link), l2cap_handler_(l2cap_handler) {
+  DynamicChannelAllocator(l2cap::internal::ILink* link, os::Handler* l2cap_handler)
+      : link_(link), l2cap_handler_(l2cap_handler) {
     ASSERT(link_ != nullptr);
     ASSERT(l2cap_handler_ != nullptr);
   }
@@ -67,7 +68,7 @@
   void OnAclDisconnected(hci::ErrorCode hci_status);
 
  private:
-  Link* link_;
+  l2cap::internal::ILink* link_;
   os::Handler* l2cap_handler_;
   std::unordered_set<Cid> used_cid_;
   std::unordered_map<Cid, std::shared_ptr<DynamicChannelImpl>> channels_;
@@ -75,6 +76,5 @@
 };
 
 }  // namespace internal
-}  // namespace classic
 }  // namespace l2cap
 }  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/dynamic_channel_allocator_fuzz_test.cc b/gd/l2cap/internal/dynamic_channel_allocator_fuzz_test.cc
similarity index 89%
rename from gd/l2cap/classic/internal/dynamic_channel_allocator_fuzz_test.cc
rename to gd/l2cap/internal/dynamic_channel_allocator_fuzz_test.cc
index 48d9121..c3821dc 100644
--- a/gd/l2cap/classic/internal/dynamic_channel_allocator_fuzz_test.cc
+++ b/gd/l2cap/internal/dynamic_channel_allocator_fuzz_test.cc
@@ -14,25 +14,24 @@
  * limitations under the License.
  */
 
-#include "l2cap/classic/internal/dynamic_channel_allocator.h"
 #include "l2cap/classic/internal/link_mock.h"
+#include "l2cap/internal/dynamic_channel_allocator.h"
 #include "l2cap/internal/parameter_provider_mock.h"
 
 #include <gmock/gmock.h>
 
 namespace bluetooth {
 namespace l2cap {
-namespace classic {
 namespace internal {
 
+using classic::internal::testing::MockLink;
 using hci::testing::MockAclConnection;
 using l2cap::internal::testing::MockParameterProvider;
 using l2cap::internal::testing::MockScheduler;
-using testing::MockLink;
 using ::testing::NiceMock;
 using ::testing::Return;
 
-const hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+const hci::AddressWithType device{{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}, hci::AddressType::PUBLIC_IDENTITY_ADDRESS};
 
 class L2capClassicDynamicChannelAllocatorFuzzTest {
  public:
@@ -78,11 +77,10 @@
 };
 
 }  // namespace internal
-}  // namespace classic
 }  // namespace l2cap
 }  // namespace bluetooth
 
 void RunL2capClassicDynamicChannelAllocatorFuzzTest(const uint8_t* data, size_t size) {
-  bluetooth::l2cap::classic::internal::L2capClassicDynamicChannelAllocatorFuzzTest test;
+  bluetooth::l2cap::internal::L2capClassicDynamicChannelAllocatorFuzzTest test;
   test.RunTests(data, size);
 }
\ No newline at end of file
diff --git a/gd/l2cap/classic/internal/dynamic_channel_allocator_test.cc b/gd/l2cap/internal/dynamic_channel_allocator_test.cc
similarity index 93%
rename from gd/l2cap/classic/internal/dynamic_channel_allocator_test.cc
rename to gd/l2cap/internal/dynamic_channel_allocator_test.cc
index 8e3f66b..4fc0160 100644
--- a/gd/l2cap/classic/internal/dynamic_channel_allocator_test.cc
+++ b/gd/l2cap/internal/dynamic_channel_allocator_test.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "l2cap/classic/internal/dynamic_channel_allocator.h"
+#include "l2cap/internal/dynamic_channel_allocator.h"
 #include "l2cap/classic/internal/link_mock.h"
 #include "l2cap/internal/parameter_provider_mock.h"
 
@@ -23,14 +23,13 @@
 
 namespace bluetooth {
 namespace l2cap {
-namespace classic {
 namespace internal {
 
+using classic::internal::testing::MockLink;
 using l2cap::internal::testing::MockParameterProvider;
-using testing::MockLink;
 using ::testing::Return;
 
-const hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+const hci::AddressWithType device{{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}, hci::AddressType::PUBLIC_IDENTITY_ADDRESS};
 
 class L2capClassicDynamicChannelAllocatorTest : public ::testing::Test {
  protected:
@@ -89,6 +88,5 @@
 }
 
 }  // namespace internal
-}  // namespace classic
 }  // namespace l2cap
 }  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/dynamic_channel_impl.cc b/gd/l2cap/internal/dynamic_channel_impl.cc
similarity index 70%
rename from gd/l2cap/classic/internal/dynamic_channel_impl.cc
rename to gd/l2cap/internal/dynamic_channel_impl.cc
index c0614f9..947a32f 100644
--- a/gd/l2cap/classic/internal/dynamic_channel_impl.cc
+++ b/gd/l2cap/internal/dynamic_channel_impl.cc
@@ -17,8 +17,8 @@
 #include <unordered_map>
 
 #include "l2cap/cid.h"
-#include "l2cap/classic/internal/dynamic_channel_impl.h"
 #include "l2cap/classic/internal/link.h"
+#include "l2cap/internal/dynamic_channel_impl.h"
 #include "l2cap/internal/sender.h"
 #include "l2cap/psm.h"
 #include "l2cap/security_policy.h"
@@ -27,10 +27,10 @@
 
 namespace bluetooth {
 namespace l2cap {
-namespace classic {
 namespace internal {
 
-DynamicChannelImpl::DynamicChannelImpl(Psm psm, Cid cid, Cid remote_cid, Link* link, os::Handler* l2cap_handler)
+DynamicChannelImpl::DynamicChannelImpl(Psm psm, Cid cid, Cid remote_cid, l2cap::internal::ILink* link,
+                                       os::Handler* l2cap_handler)
     : psm_(psm), cid_(cid), remote_cid_(remote_cid), link_(link), l2cap_handler_(l2cap_handler),
       device_(link->GetDevice()) {
   ASSERT(IsPsmValid(psm_));
@@ -41,7 +41,7 @@
 }
 
 hci::Address DynamicChannelImpl::GetDevice() const {
-  return device_;
+  return device_.GetAddress();
 }
 
 void DynamicChannelImpl::RegisterOnCloseCallback(os::Handler* user_handler,
@@ -82,40 +82,6 @@
   return ss.str();
 }
 
-DynamicChannelImpl::ConfigurationStatus DynamicChannelImpl::GetOutgoingConfigurationStatus() const {
-  return outgoing_configuration_status_;
-}
-
-void DynamicChannelImpl::SetOutgoingConfigurationStatus(ConfigurationStatus status) {
-  outgoing_configuration_status_ = status;
-}
-
-DynamicChannelImpl::ConfigurationStatus DynamicChannelImpl::GetIncomingConfigurationStatus() const {
-  return incoming_configuration_status_;
-}
-
-void DynamicChannelImpl::SetIncomingConfigurationStatus(ConfigurationStatus status) {
-  incoming_configuration_status_ = status;
-}
-
-void DynamicChannelImpl::SetSender(l2cap::internal::Sender* sender) {
-  sender_ = sender;
-}
-
-void DynamicChannelImpl::SetIncomingMtu(Mtu mtu) {
-  sender_->SetIncomingMtu(mtu);
-}
-
-void DynamicChannelImpl::SetRetransmissionFlowControlConfig(
-    const RetransmissionAndFlowControlConfigurationOption& option) {
-  sender_->SetChannelRetransmissionFlowControlMode(option);
-}
-
-void DynamicChannelImpl::SetFcsType(FcsType fcs_type) {
-  sender_->SetFcsType(fcs_type);
-}
-
 }  // namespace internal
-}  // namespace classic
 }  // namespace l2cap
 }  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/dynamic_channel_impl.h b/gd/l2cap/internal/dynamic_channel_impl.h
similarity index 67%
rename from gd/l2cap/classic/internal/dynamic_channel_impl.h
rename to gd/l2cap/internal/dynamic_channel_impl.h
index 95be5c7..856e21d 100644
--- a/gd/l2cap/classic/internal/dynamic_channel_impl.h
+++ b/gd/l2cap/internal/dynamic_channel_impl.h
@@ -19,8 +19,9 @@
 #include "common/bidi_queue.h"
 #include "hci/address.h"
 #include "l2cap/cid.h"
-#include "l2cap/classic/dynamic_channel.h"
+#include "l2cap/dynamic_channel.h"
 #include "l2cap/internal/channel_impl.h"
+#include "l2cap/internal/ilink.h"
 #include "l2cap/l2cap_packets.h"
 #include "l2cap/mtu.h"
 #include "l2cap/psm.h"
@@ -29,14 +30,11 @@
 
 namespace bluetooth {
 namespace l2cap {
-namespace classic {
 namespace internal {
 
-class Link;
-
 class DynamicChannelImpl : public l2cap::internal::ChannelImpl {
  public:
-  DynamicChannelImpl(Psm psm, Cid cid, Cid remote_cid, Link* link, os::Handler* l2cap_handler);
+  DynamicChannelImpl(Psm psm, Cid cid, Cid remote_cid, l2cap::internal::ILink* link, os::Handler* l2cap_handler);
 
   virtual ~DynamicChannelImpl() = default;
 
@@ -68,26 +66,6 @@
     return psm_;
   }
 
-  enum class ConfigurationStatus { NOT_CONFIGURED, CONFIGURED };
-
-  virtual ConfigurationStatus GetOutgoingConfigurationStatus() const;
-  virtual void SetOutgoingConfigurationStatus(ConfigurationStatus status);
-
-  virtual ConfigurationStatus GetIncomingConfigurationStatus() const;
-  virtual void SetIncomingConfigurationStatus(ConfigurationStatus status);
-
-  /**
-   * Callback from the Scheduler to notify the Sender for this channel. On config update, channel might notify the
-   * configuration to Sender
-   */
-  void SetSender(l2cap::internal::Sender* sender) override;
-
-  virtual void SetIncomingMtu(Mtu mtu);
-
-  virtual void SetRetransmissionFlowControlConfig(const RetransmissionAndFlowControlConfigurationOption& mode);
-
-  virtual void SetFcsType(FcsType fcs_type);
-
   // TODO(cmanton) Do something a little bit better than this
   bool local_initiated_{false};
 
@@ -95,9 +73,9 @@
   const Psm psm_;
   const Cid cid_;
   const Cid remote_cid_;
-  Link* link_;
+  l2cap::internal::ILink* link_;
   os::Handler* l2cap_handler_;
-  const hci::Address device_;
+  const hci::AddressWithType device_;
 
   // User supported states
   os::Handler* user_handler_ = nullptr;
@@ -109,15 +87,10 @@
   static constexpr size_t kChannelQueueSize = 10;
   common::BidiQueue<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder> channel_queue_{
       kChannelQueueSize};
-  ConfigurationStatus outgoing_configuration_status_ = ConfigurationStatus::NOT_CONFIGURED;
-  ConfigurationStatus incoming_configuration_status_ = ConfigurationStatus::NOT_CONFIGURED;
-
-  l2cap::internal::Sender* sender_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(DynamicChannelImpl);
 };
 
 }  // namespace internal
-}  // namespace classic
 }  // namespace l2cap
 }  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/dynamic_channel_impl_test.cc b/gd/l2cap/internal/dynamic_channel_impl_test.cc
similarity index 89%
rename from gd/l2cap/classic/internal/dynamic_channel_impl_test.cc
rename to gd/l2cap/internal/dynamic_channel_impl_test.cc
index 2f6c649..677b504 100644
--- a/gd/l2cap/classic/internal/dynamic_channel_impl_test.cc
+++ b/gd/l2cap/internal/dynamic_channel_impl_test.cc
@@ -13,7 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include "l2cap/classic/internal/dynamic_channel_impl.h"
+
+#include "l2cap/internal/dynamic_channel_impl.h"
 
 #include "common/testing/bind_test_util.h"
 #include "l2cap/cid.h"
@@ -26,11 +27,10 @@
 
 namespace bluetooth {
 namespace l2cap {
-namespace classic {
 namespace internal {
 
+using classic::internal::testing::MockLink;
 using l2cap::internal::testing::MockParameterProvider;
-using testing::MockLink;
 using ::testing::Return;
 
 class L2capClassicDynamicChannelImplTest : public ::testing::Test {
@@ -61,17 +61,17 @@
 TEST_F(L2capClassicDynamicChannelImplTest, get_device) {
   MockParameterProvider mock_parameter_provider;
   MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
-  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  const hci::AddressWithType device{{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}, hci::AddressType::PUBLIC_IDENTITY_ADDRESS};
   EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
   DynamicChannelImpl dynamic_channel_impl(0x01, kFirstDynamicChannel, kFirstDynamicChannel, &mock_classic_link,
                                           l2cap_handler_);
-  EXPECT_EQ(device, dynamic_channel_impl.GetDevice());
+  EXPECT_EQ(device.GetAddress(), dynamic_channel_impl.GetDevice());
 }
 
 TEST_F(L2capClassicDynamicChannelImplTest, close_triggers_callback) {
   MockParameterProvider mock_parameter_provider;
   MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
-  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  const hci::AddressWithType device{{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}, hci::AddressType::PUBLIC_IDENTITY_ADDRESS};
   EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
   DynamicChannelImpl dynamic_channel_impl(0x01, kFirstDynamicChannel, kFirstDynamicChannel, &mock_classic_link,
                                           l2cap_handler_);
@@ -93,7 +93,7 @@
 TEST_F(L2capClassicDynamicChannelImplTest, register_callback_after_close_should_call_immediately) {
   MockParameterProvider mock_parameter_provider;
   MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
-  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  const hci::AddressWithType device{{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}, hci::AddressType::PUBLIC_IDENTITY_ADDRESS};
   EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
   DynamicChannelImpl dynamic_channel_impl(0x01, kFirstDynamicChannel, kFirstDynamicChannel, &mock_classic_link,
                                           l2cap_handler_);
@@ -115,7 +115,7 @@
 TEST_F(L2capClassicDynamicChannelImplTest, close_twice_should_fail) {
   MockParameterProvider mock_parameter_provider;
   MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
-  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  const hci::AddressWithType device{{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}, hci::AddressType::PUBLIC_IDENTITY_ADDRESS};
   EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
   DynamicChannelImpl dynamic_channel_impl(0x01, kFirstDynamicChannel, kFirstDynamicChannel, &mock_classic_link,
                                           l2cap_handler_);
@@ -140,7 +140,7 @@
 TEST_F(L2capClassicDynamicChannelImplTest, multiple_registeration_should_fail) {
   MockParameterProvider mock_parameter_provider;
   MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
-  hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+  const hci::AddressWithType device{{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}, hci::AddressType::PUBLIC_IDENTITY_ADDRESS};
   EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
   DynamicChannelImpl dynamic_channel_impl(0x01, kFirstDynamicChannel, kFirstDynamicChannel, &mock_classic_link,
                                           l2cap_handler_);
@@ -159,6 +159,5 @@
 }
 
 }  // namespace internal
-}  // namespace classic
 }  // namespace l2cap
 }  // namespace bluetooth
diff --git a/gd/l2cap/internal/fixed_channel_allocator_test.cc b/gd/l2cap/internal/fixed_channel_allocator_test.cc
index 2162d36..38eac13 100644
--- a/gd/l2cap/internal/fixed_channel_allocator_test.cc
+++ b/gd/l2cap/internal/fixed_channel_allocator_test.cc
@@ -31,7 +31,7 @@
 using testing::MockParameterProvider;
 using ::testing::Return;
 
-const hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+const hci::AddressWithType device{{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}, hci::AddressType::PUBLIC_IDENTITY_ADDRESS};
 
 class L2capFixedChannelAllocatorTest : public ::testing::Test {
  protected:
diff --git a/gd/l2cap/internal/ilink.h b/gd/l2cap/internal/ilink.h
new file mode 100644
index 0000000..4f0b6f6
--- /dev/null
+++ b/gd/l2cap/internal/ilink.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "hci/address_with_type.h"
+#include "l2cap/cid.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+/**
+ * Common interface for link (Classic ACL and LE)
+ */
+class ILink {
+ public:
+  virtual void SendDisconnectionRequest(Cid local_cid, Cid remote_cid) = 0;
+  virtual ~ILink() = default;
+  virtual hci::AddressWithType GetDevice() = 0;
+};
+}  // namespace internal
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/scheduler_fifo.cc b/gd/l2cap/internal/scheduler_fifo.cc
index 5e89c01..a19b7a1 100644
--- a/gd/l2cap/internal/scheduler_fifo.cc
+++ b/gd/l2cap/internal/scheduler_fifo.cc
@@ -16,7 +16,7 @@
 
 #include "l2cap/internal/scheduler_fifo.h"
 
-#include "l2cap/classic/internal/dynamic_channel_impl.h"
+#include "dynamic_channel_impl.h"
 #include "l2cap/internal/data_pipeline_manager.h"
 #include "l2cap/l2cap_packets.h"
 #include "os/log.h"
diff --git a/gd/l2cap/internal/sender.cc b/gd/l2cap/internal/sender.cc
index 7fe1dd7..1c146cf 100644
--- a/gd/l2cap/internal/sender.cc
+++ b/gd/l2cap/internal/sender.cc
@@ -14,20 +14,15 @@
  * limitations under the License.
  */
 
-#include <string>
 #include <unordered_map>
 
 #include "common/bind.h"
-#include "l2cap/cid.h"
-#include "l2cap/classic/internal/dynamic_channel_impl.h"
 #include "l2cap/internal/basic_mode_channel_data_controller.h"
 #include "l2cap/internal/enhanced_retransmission_mode_channel_data_controller.h"
 #include "l2cap/internal/scheduler.h"
 #include "l2cap/internal/sender.h"
 #include "os/handler.h"
 #include "os/log.h"
-#include "os/queue.h"
-#include "packet/base_packet_builder.h"
 
 namespace bluetooth {
 namespace l2cap {
@@ -55,32 +50,6 @@
   return data_controller_->GetNextPacket();
 }
 
-void Sender::SetChannelRetransmissionFlowControlMode(const RetransmissionAndFlowControlConfigurationOption& option) {
-  if (mode_ == option.mode_) {
-    return;
-  }
-  if (option.mode_ == RetransmissionAndFlowControlModeOption::L2CAP_BASIC) {
-    data_controller_ =
-        std::make_unique<BasicModeDataController>(channel_id_, remote_channel_id_, queue_end_, handler_, scheduler_);
-    return;
-  }
-  if (option.mode_ == RetransmissionAndFlowControlModeOption::ENHANCED_RETRANSMISSION) {
-    data_controller_ =
-        std::make_unique<ErtmController>(channel_id_, remote_channel_id_, queue_end_, handler_, scheduler_);
-    data_controller_->SetRetransmissionAndFlowControlOptions(option);
-    return;
-  }
-}
-
-void Sender::SetFcsType(FcsType fcs_type) {
-  // TODO: FCS is enabled when "not both side explicitly disable it".
-  data_controller_->EnableFcs(fcs_type == FcsType::DEFAULT);
-}
-
-void Sender::SetIncomingMtu(Mtu mtu) {
-  // TODO: Enforce MTU
-}
-
 DataController* Sender::GetDataController() {
   return data_controller_.get();
 }
@@ -101,6 +70,25 @@
   is_dequeue_registered_ = false;
 }
 
+void Sender::UpdateClassicConfiguration(classic::internal::ChannelConfigurationState config) {
+  auto mode = config.retransmission_and_flow_control_mode_;
+  if (mode == mode_) {
+    return;
+  }
+  if (mode == RetransmissionAndFlowControlModeOption::L2CAP_BASIC) {
+    data_controller_ =
+        std::make_unique<BasicModeDataController>(channel_id_, remote_channel_id_, queue_end_, handler_, scheduler_);
+    return;
+  }
+  if (mode == RetransmissionAndFlowControlModeOption::ENHANCED_RETRANSMISSION) {
+    data_controller_ =
+        std::make_unique<ErtmController>(channel_id_, remote_channel_id_, queue_end_, handler_, scheduler_);
+    data_controller_->SetRetransmissionAndFlowControlOptions(config.local_retransmission_and_flow_control_);
+    data_controller_->EnableFcs(config.fcs_type_ == FcsType::DEFAULT);
+    return;
+  }
+}
+
 }  // namespace internal
 }  // namespace l2cap
 }  // namespace bluetooth
diff --git a/gd/l2cap/internal/sender.h b/gd/l2cap/internal/sender.h
index 850a88d..46e0006 100644
--- a/gd/l2cap/internal/sender.h
+++ b/gd/l2cap/internal/sender.h
@@ -23,6 +23,7 @@
 #include "common/bind.h"
 #include "data_controller.h"
 #include "l2cap/cid.h"
+#include "l2cap/classic/internal/channel_configuration_state.h"
 #include "l2cap/internal/channel_impl.h"
 #include "l2cap/internal/data_controller.h"
 #include "l2cap/l2cap_packets.h"
@@ -61,10 +62,7 @@
    */
   std::unique_ptr<UpperDequeue> GetNextPacket();
 
-  void SetChannelRetransmissionFlowControlMode(const RetransmissionAndFlowControlConfigurationOption& option);
-  void SetFcsType(FcsType fcs_type);
-  void SetIncomingMtu(Mtu mtu);
-
+  void UpdateClassicConfiguration(classic::internal::ChannelConfigurationState config);
   DataController* GetDataController();
 
  private:
diff --git a/gd/l2cap/le/internal/fixed_channel_impl.cc b/gd/l2cap/le/internal/fixed_channel_impl.cc
index 9ae4e1f..e09b80d 100644
--- a/gd/l2cap/le/internal/fixed_channel_impl.cc
+++ b/gd/l2cap/le/internal/fixed_channel_impl.cc
@@ -107,10 +107,6 @@
   return cid_;
 }
 
-void FixedChannelImpl::SetSender(l2cap::internal::Sender* sender) {
-  ASSERT_LOG(false, "Should not set sender for fixed channel");
-}
-
 }  // namespace internal
 }  // namespace le
 }  // namespace l2cap
diff --git a/gd/l2cap/le/internal/fixed_channel_impl.h b/gd/l2cap/le/internal/fixed_channel_impl.h
index 82a4125..5d6a11d 100644
--- a/gd/l2cap/le/internal/fixed_channel_impl.h
+++ b/gd/l2cap/le/internal/fixed_channel_impl.h
@@ -55,7 +55,6 @@
 
   Cid GetCid() const override;
   Cid GetRemoteCid() const override;
-  void SetSender(l2cap::internal::Sender* sender) override;
   virtual void OnClosed(hci::ErrorCode status);
 
   virtual std::string ToString() {
diff --git a/gd/l2cap/le/internal/link.h b/gd/l2cap/le/internal/link.h
index 3e75da6..2807353 100644
--- a/gd/l2cap/le/internal/link.h
+++ b/gd/l2cap/le/internal/link.h
@@ -22,6 +22,7 @@
 #include "hci/acl_manager.h"
 #include "l2cap/internal/data_pipeline_manager.h"
 #include "l2cap/internal/fixed_channel_allocator.h"
+#include "l2cap/internal/ilink.h"
 #include "l2cap/internal/parameter_provider.h"
 #include "l2cap/le/internal/fixed_channel_impl.h"
 #include "os/alarm.h"
@@ -31,7 +32,7 @@
 namespace le {
 namespace internal {
 
-class Link {
+class Link : public l2cap::internal::ILink {
  public:
   Link(os::Handler* l2cap_handler, std::unique_ptr<hci::AclConnection> acl_connection,
        l2cap::internal::ParameterProvider* parameter_provider)
@@ -94,6 +95,8 @@
     return GetDevice().ToString();
   }
 
+  void SendDisconnectionRequest(Cid local_cid, Cid remote_cid) override {}
+
  private:
   os::Handler* l2cap_handler_;
   l2cap::internal::FixedChannelAllocator<FixedChannelImpl, Link> fixed_channel_allocator_{this, l2cap_handler_};
diff --git a/gd/shim/l2cap.cc b/gd/shim/l2cap.cc
index d703972..7af8f77 100644
--- a/gd/shim/l2cap.cc
+++ b/gd/shim/l2cap.cc
@@ -50,8 +50,7 @@
 
 using ServiceInterfaceCallback =
     std::function<void(l2cap::Psm psm, l2cap::classic::DynamicChannelManager::RegistrationResult result)>;
-using ConnectionInterfaceCallback =
-    std::function<void(l2cap::Psm psm, std::unique_ptr<l2cap::classic::DynamicChannel>)>;
+using ConnectionInterfaceCallback = std::function<void(l2cap::Psm psm, std::unique_ptr<l2cap::DynamicChannel>)>;
 
 std::unique_ptr<packet::RawBuilder> MakeUniquePacket(const uint8_t* data, size_t len) {
   packet::RawBuilder builder;
@@ -63,7 +62,7 @@
 
 class ConnectionInterface {
  public:
-  ConnectionInterface(ConnectionInterfaceDescriptor cid, std::unique_ptr<l2cap::classic::DynamicChannel> channel,
+  ConnectionInterface(ConnectionInterfaceDescriptor cid, std::unique_ptr<l2cap::DynamicChannel> channel,
                       os::Handler* handler)
       : cid_(cid), channel_(std::move(channel)), handler_(handler), on_data_ready_callback_(nullptr),
         on_connection_closed_callback_(nullptr), address_(channel_->GetDevice()) {
@@ -139,7 +138,7 @@
 
  private:
   const ConnectionInterfaceDescriptor cid_;
-  const std::unique_ptr<l2cap::classic::DynamicChannel> channel_;
+  const std::unique_ptr<l2cap::DynamicChannel> channel_;
   os::Handler* handler_;
 
   ReadDataReadyCallback on_data_ready_callback_;
@@ -155,7 +154,7 @@
 
 struct ConnectionInterfaceManager {
  public:
-  ConnectionInterfaceDescriptor AddChannel(std::unique_ptr<l2cap::classic::DynamicChannel> channel);
+  ConnectionInterfaceDescriptor AddChannel(std::unique_ptr<l2cap::DynamicChannel> channel);
   void RemoveConnection(ConnectionInterfaceDescriptor cid);
 
   void SetReadDataReadyCallback(ConnectionInterfaceDescriptor cid, ReadDataReadyCallback on_data_ready);
@@ -218,8 +217,7 @@
   return current_connection_interface_descriptor_++;
 }
 
-ConnectionInterfaceDescriptor ConnectionInterfaceManager::AddChannel(
-    std::unique_ptr<l2cap::classic::DynamicChannel> channel) {
+ConnectionInterfaceDescriptor ConnectionInterfaceManager::AddChannel(std::unique_ptr<l2cap::DynamicChannel> channel) {
   if (!HasResources()) {
     return kInvalidConnectionInterfaceDescriptor;
   }
@@ -267,7 +265,7 @@
       : connection_interface_manager_(connection_interface_manager), psm_(psm), address_(address),
         on_open_(std::move(on_open)), completed_(std::move(completed)) {}
 
-  void OnConnectionOpen(std::unique_ptr<l2cap::classic::DynamicChannel> channel) {
+  void OnConnectionOpen(std::unique_ptr<l2cap::DynamicChannel> channel) {
     LOG_DEBUG("Local initiated connection is open to device:%s for psm:%hd", address_.ToString().c_str(), psm_);
     ConnectionInterfaceDescriptor cid = connection_interface_manager_->AddChannel(std::move(channel));
     completed_.set_value(cid);
@@ -322,7 +320,7 @@
     completed_.set_value();
   }
 
-  void OnConnectionOpen(std::unique_ptr<l2cap::classic::DynamicChannel> channel) {
+  void OnConnectionOpen(std::unique_ptr<l2cap::DynamicChannel> channel) {
     LOG_DEBUG("Remote initiated connection is open from device:%s for psm:%hd", channel->GetDevice().ToString().c_str(),
               psm_);
     hci::Address address = channel->GetDevice();