Merge "HCI: Add LeSetExtendedScanParameter tests"
diff --git a/btif/co/bta_av_co.cc b/btif/co/bta_av_co.cc
index 0621bc8..f3d39e2 100644
--- a/btif/co/bta_av_co.cc
+++ b/btif/co/bta_av_co.cc
@@ -1005,6 +1005,11 @@
     memcpy(p_codec_info, p_peer->codec_config, AVDT_CODEC_SIZE);
   }
 
+  // report this peer selectable codecs after retrieved all its capabilities.
+  LOG(INFO) << __func__ << ": retrieved " << +p_peer->num_rx_sinks
+            << " capabilities from peer " << p_peer->addr;
+  ReportSourceCodecState(p_peer);
+
   return A2DP_SUCCESS;
 }
 
@@ -1402,8 +1407,7 @@
 }
 
 bool BtaAvCo::SetActivePeer(const RawAddress& peer_address) {
-  APPL_TRACE_DEBUG("%s: peer_address=%s", __func__,
-                   peer_address.ToString().c_str());
+  VLOG(1) << __func__ << ": peer_address=" << peer_address;
 
   std::lock_guard<std::recursive_mutex> lock(codec_lock_);
 
@@ -1422,8 +1426,8 @@
 
   active_peer_ = p_peer;
   memcpy(codec_config_, active_peer_->codec_config, AVDT_CODEC_SIZE);
-  APPL_TRACE_DEBUG("%s: codec = %s", __func__,
-                   A2DP_CodecInfoString(codec_config_).c_str());
+  LOG(INFO) << __func__ << ": codec = " << A2DP_CodecInfoString(codec_config_);
+  // report the selected codec configuration of this new active peer.
   ReportSourceCodecState(active_peer_);
   return true;
 }
@@ -1476,12 +1480,12 @@
   bool config_updated = false;
   bool success = true;
 
-  VLOG(1) << __func__ << ": peer_address=" << peer_address.ToString()
-          << " codec_user_config=" << codec_user_config.ToString();
+  VLOG(1) << __func__ << ": peer_address=" << peer_address
+          << " codec_user_config={" << codec_user_config.ToString() << "}";
 
   BtaAvCoPeer* p_peer = FindPeer(peer_address);
   if (p_peer == nullptr) {
-    LOG(ERROR) << __func__ << ": cannot find peer " << peer_address.ToString()
+    LOG(ERROR) << __func__ << ": cannot find peer " << peer_address
                << " to configure";
     success = false;
     goto done;
@@ -1490,7 +1494,7 @@
   // Don't call BTA_AvReconfig() prior to retrieving all peer's capabilities
   if ((p_peer->num_rx_sinks != p_peer->num_sinks) &&
       (p_peer->num_sup_sinks != BTA_AV_CO_NUM_ELEMENTS(p_peer->sinks))) {
-    LOG(WARNING) << __func__ << ": peer " << p_peer->addr.ToString()
+    LOG(WARNING) << __func__ << ": peer " << p_peer->addr
                  << " : not all peer's capabilities have been retrieved";
     success = false;
     goto done;
@@ -1504,7 +1508,7 @@
     p_sink = p_peer->p_sink;
   }
   if (p_sink == nullptr) {
-    LOG(ERROR) << __func__ << ": peer " << p_peer->addr.ToString()
+    LOG(ERROR) << __func__ << ": peer " << p_peer->addr
                << " : cannot find peer SEP to configure for codec type "
                << codec_user_config.codec_type;
     success = false;
@@ -1529,7 +1533,7 @@
 
     p_sink = SelectSourceCodec(p_peer);
     if (p_sink == nullptr) {
-      LOG(ERROR) << __func__ << ": peer " << p_peer->addr.ToString()
+      LOG(ERROR) << __func__ << ": peer " << p_peer->addr
                  << " : cannot set up codec for the peer SINK";
       success = false;
       goto done;
@@ -1543,12 +1547,16 @@
   }
 
 done:
-  // NOTE: We unconditionally send the upcall even if there is no change
-  // or the user config failed. Thus, the caller would always know whether the
-  // request succeeded or failed.
+  // We send the upcall if there is no change or the user config failed for
+  // current active peer, so the caller would know it failed. If there is no
+  // error, the new selected codec configuration would be sent after we are
+  // ready to start a new session with the audio HAL.
+  // For none active peer, we unconditionally send the upcall, so the caller
+  // would always know the result.
   // NOTE: Currently, the input is restarted by sending an upcall
   // and informing the Media Framework about the change.
-  if (p_peer != nullptr) {
+  if (p_peer != nullptr &&
+      (!restart_output || !success || p_peer != active_peer_)) {
     return ReportSourceCodecState(p_peer);
   }
 
@@ -1574,7 +1582,7 @@
   // Don't call BTA_AvReconfig() prior to retrieving all peer's capabilities
   if ((p_peer->num_rx_sinks != p_peer->num_sinks) &&
       (p_peer->num_sup_sinks != BTA_AV_CO_NUM_ELEMENTS(p_peer->sinks))) {
-    LOG(WARNING) << __func__ << ": peer " << p_peer->addr.ToString()
+    LOG(WARNING) << __func__ << ": peer " << p_peer->addr
                  << " : not all peer's capabilities have been retrieved";
     return false;
   }
@@ -1582,7 +1590,7 @@
   // Use the current sink codec
   const BtaAvCoSep* p_sink = p_peer->p_sink;
   if (p_sink == nullptr) {
-    LOG(ERROR) << __func__ << ": peer " << p_peer->addr.ToString()
+    LOG(ERROR) << __func__ << ": peer " << p_peer->addr
                << " : cannot find peer SEP to configure";
     return false;
   }
@@ -1613,7 +1621,7 @@
 
   if (config_updated) {
     // NOTE: Currently, the input is restarted by sending an upcall
-    // and informing the Media Framework about the change.
+    // and informing the Media Framework about the change of selected codec.
     return ReportSourceCodecState(p_peer);
   }
 
@@ -1625,22 +1633,19 @@
   std::vector<btav_a2dp_codec_config_t> codecs_local_capabilities;
   std::vector<btav_a2dp_codec_config_t> codecs_selectable_capabilities;
 
-  APPL_TRACE_DEBUG("%s: peer_address=%s", __func__,
-                   p_peer->addr.ToString().c_str());
+  VLOG(1) << __func__ << ": peer_address=" << p_peer->addr;
   A2dpCodecs* codecs = p_peer->GetCodecs();
   CHECK(codecs != nullptr);
   if (!codecs->getCodecConfigAndCapabilities(&codec_config,
                                              &codecs_local_capabilities,
                                              &codecs_selectable_capabilities)) {
-    APPL_TRACE_WARNING(
-        "%s: Peer %s : error reporting audio source codec state: "
-        "cannot get codec config and capabilities",
-        __func__, p_peer->addr.ToString().c_str());
+    LOG(WARNING) << __func__ << ": Peer " << p_peer->addr
+                 << " : error reporting audio source codec state: cannot get "
+                    "codec config and capabilities";
     return false;
   }
-  APPL_TRACE_DEBUG("%s: peer %s codec_config=%s", __func__,
-                   p_peer->addr.ToString().c_str(),
-                   codec_config.ToString().c_str());
+  LOG(INFO) << __func__ << ": peer " << p_peer->addr << " codec_config={"
+            << codec_config.ToString() << "}";
   btif_av_report_source_codec_state(p_peer->addr, codec_config,
                                     codecs_local_capabilities,
                                     codecs_selectable_capabilities);
@@ -1747,19 +1752,14 @@
 
   // Select the codec
   for (const auto& iter : p_peer->GetCodecs()->orderedSourceCodecs()) {
-    APPL_TRACE_DEBUG("%s: trying codec %s", __func__, iter->name().c_str());
+    VLOG(1) << __func__ << ": trying codec " << iter->name();
     p_sink = AttemptSourceCodecSelection(*iter, p_peer);
     if (p_sink != nullptr) {
-      APPL_TRACE_DEBUG("%s: selected codec %s", __func__, iter->name().c_str());
+      VLOG(1) << __func__ << ": selected codec " << iter->name();
       break;
     }
-    APPL_TRACE_DEBUG("%s: cannot use codec %s", __func__, iter->name().c_str());
+    VLOG(1) << __func__ << ": cannot use codec " << iter->name();
   }
-
-  // NOTE: Unconditionally dispatch the event to make sure a callback with
-  // the most recent codec info is generated.
-  ReportSourceCodecState(p_peer);
-
   return p_sink;
 }
 
@@ -1999,10 +1999,8 @@
   bool restart_output = false;
   bool config_updated = false;
 
-  APPL_TRACE_DEBUG("%s: peer_address=%s", __func__,
-                   p_peer->addr.ToString().c_str());
-  APPL_TRACE_DEBUG("%s: codec: %s", __func__,
-                   A2DP_CodecInfoString(p_ota_codec_config).c_str());
+  LOG(INFO) << __func__ << ": peer_address=" << p_peer->addr
+            << ", codec: " << A2DP_CodecInfoString(p_ota_codec_config);
 
   *p_restart_output = false;
 
@@ -2013,8 +2011,8 @@
     // There are no peer SEPs if we didn't do the discovery procedure yet.
     // We have all the information we need from the peer, so we can
     // proceed with the OTA codec configuration.
-    APPL_TRACE_ERROR("%s: peer %s : cannot find peer SEP to configure",
-                     __func__, p_peer->addr.ToString().c_str());
+    LOG(ERROR) << __func__ << ": peer " << p_peer->addr
+               << " : cannot find peer SEP to configure";
     return false;
   }
 
@@ -2023,15 +2021,14 @@
   if (!p_peer->GetCodecs()->setCodecOtaConfig(
           p_ota_codec_config, &peer_params, result_codec_config, &restart_input,
           &restart_output, &config_updated)) {
-    APPL_TRACE_ERROR("%s: peer %s : cannot set OTA config", __func__,
-                     p_peer->addr.ToString().c_str());
+    LOG(ERROR) << __func__ << ": peer " << p_peer->addr
+               << " : cannot set OTA config";
     return false;
   }
 
   if (restart_output) {
-    APPL_TRACE_DEBUG("%s: restart output", __func__);
-    APPL_TRACE_DEBUG("%s: codec: %s", __func__,
-                     A2DP_CodecInfoString(result_codec_config).c_str());
+    VLOG(1) << __func__ << ": restart output for codec: "
+            << A2DP_CodecInfoString(result_codec_config);
 
     *p_restart_output = true;
     p_peer->p_sink = p_sink;
@@ -2041,7 +2038,7 @@
 
   if (restart_input || config_updated) {
     // NOTE: Currently, the input is restarted by sending an upcall
-    // and informing the Media Framework about the change.
+    // and informing the Media Framework about the change of selected codec.
     ReportSourceCodecState(p_peer);
   }
 
diff --git a/gd/Android.bp b/gd/Android.bp
index 6aaf2df..46108c6 100644
--- a/gd/Android.bp
+++ b/gd/Android.bp
@@ -605,7 +605,11 @@
       linux_glibc_x86_64: {
           include_dirs: ["external/python/cpython3/android/linux_x86_64/pyconfig"],
           cflags: ["-DSOABI=\"cpython-38android-x86_64-linux-gnu\""],
-          suffix: ".cpython-38android-x86_64-linux-gnu",
+          // Commenting out the Linux suffix so that cpython-38-x86_64-linux-gnu
+          // Python 3.8 can also import the untagged .so library per PEP 3149
+          // Keep this change until Android py3-cmd can run ACTS, gRPC and can
+          // Export Python native symbols such as PyType_Type
+          // suffix: ".cpython-38android-x86_64-linux-gnu",
       },
       windows: {
           enabled: false,
diff --git a/gd/cert/bluetooth_packets_python3_setup.py b/gd/cert/bluetooth_packets_python3_setup.py
new file mode 100644
index 0000000..bce14f0
--- /dev/null
+++ b/gd/cert/bluetooth_packets_python3_setup.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python3
+#
+#   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.
+
+
+# Usage:
+# 1. Run envsetup and lunch first in an Android checkout
+# 2. Make target bluetooth_packets_python3 that will generate C++ sources for the
+#    Extension
+# 3. Build only:
+#       python3 bluetooth_packets_python3_setup.py build_ext
+#   Then Find the .so file in build/lib.linux-x86_64-3.X
+# 4. Install:
+#       python3 bluetooth_packets_python3_setup.py install --user
+
+
+import os
+import glob
+from setuptools import setup, Extension
+
+ANDROID_BUILD_TOP = os.getenv("ANDROID_BUILD_TOP")
+PYBIND11_INCLUDE_DIR = os.path.join(ANDROID_BUILD_TOP,
+                                    "external/python/pybind11/include")
+GD_DIR = os.path.join(ANDROID_BUILD_TOP, "system/bt/gd")
+BT_PACKETS_GEN_DIR = os.path.join(ANDROID_BUILD_TOP,
+                                  "out/soong/.intermediates/system/bt/gd/BluetoothGeneratedPackets_h/gen")
+BT_PACKETS_PY3_GEN_DIR = os.path.join(ANDROID_BUILD_TOP,
+                                      "out/soong/.intermediates/system/bt/gd/BluetoothGeneratedPackets_python3_cc/gen")
+
+BT_PACKETS_BASE_SRCS = [
+    os.path.join(GD_DIR, "l2cap/fcs.cc"),
+    os.path.join(GD_DIR, "packet/bit_inserter.cc"),
+    os.path.join(GD_DIR, "packet/byte_inserter.cc"),
+    os.path.join(GD_DIR, "packet/byte_observer.cc"),
+    os.path.join(GD_DIR, "packet/iterator.cc"),
+    os.path.join(GD_DIR, "packet/fragmenting_inserter.cc"),
+    os.path.join(GD_DIR, "packet/packet_view.cc"),
+    os.path.join(GD_DIR, "packet/raw_builder.cc"),
+    os.path.join(GD_DIR, "packet/view.cc"),
+]
+
+BT_PACKETS_PY3_SRCs = \
+  [os.path.join(GD_DIR, "packet/python3_module.cc")] \
+  + glob.glob(os.path.join(BT_PACKETS_PY3_GEN_DIR, "hci", "*.cc")) \
+  + glob.glob(os.path.join(BT_PACKETS_PY3_GEN_DIR, "l2cap", "*.cc")) \
+  + glob.glob(os.path.join(BT_PACKETS_PY3_GEN_DIR, "security", "*.cc"))
+
+bluetooth_packets_python3_module = Extension('bluetooth_packets_python3',
+                                             sources=BT_PACKETS_BASE_SRCS + BT_PACKETS_PY3_SRCs,
+                                             include_dirs=[GD_DIR,
+                                                           BT_PACKETS_GEN_DIR,
+                                                           BT_PACKETS_PY3_GEN_DIR,
+                                                           PYBIND11_INCLUDE_DIR],
+                                             extra_compile_args=['-std=c++17']
+                                             )
+
+setup(name='bluetooth_packets_python3',
+      version='1.0',
+      author="Android Open Source Project",
+      description="""Bluetooth Packet Library""",
+      ext_modules=[bluetooth_packets_python3_module],
+      py_modules=["bluetooth_packets_python3"],
+      )
diff --git a/gd/cert/grpc_root_server.cc b/gd/cert/grpc_root_server.cc
index 7281867..48b2d5a 100644
--- a/gd/cert/grpc_root_server.cc
+++ b/gd/cert/grpc_root_server.cc
@@ -59,7 +59,7 @@
         break;
       case BluetoothModule::L2CAP:
         modules.add<::bluetooth::cert::ReadOnlyPropertyServerModule>();
-        modules.add<::bluetooth::l2cap::classic::cert::L2capModuleCertModule>();
+        modules.add<::bluetooth::l2cap::classic::cert::L2capClassicModuleCertModule>();
         break;
       default:
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "invalid module under test");
diff --git a/gd/cert/run_cert.sh b/gd/cert/run_cert.sh
index 81fe91e..a85b994 100755
--- a/gd/cert/run_cert.sh
+++ b/gd/cert/run_cert.sh
@@ -1,3 +1,5 @@
 #! /bin/bash
 
-act.py -c $ANDROID_BUILD_TOP/system/bt/gd/cert/host_only_config.json -tf $ANDROID_BUILD_TOP/system/bt/gd/cert/cert_testcases -tp $ANDROID_BUILD_TOP/system/bt/gd
+# For bluetooth_packets_python3
+export PYTHONPATH=$PYTHONPATH:$ANDROID_BUILD_TOP/out/host/linux-x86/lib64
+python3.8 `which act.py` -c $ANDROID_BUILD_TOP/system/bt/gd/cert/host_only_config.json -tf $ANDROID_BUILD_TOP/system/bt/gd/cert/cert_testcases -tp $ANDROID_BUILD_TOP/system/bt/gd
diff --git a/gd/cert/run_device_cert.sh b/gd/cert/run_device_cert.sh
index 44e5a89..7566f65 100755
--- a/gd/cert/run_device_cert.sh
+++ b/gd/cert/run_device_cert.sh
@@ -1,3 +1,5 @@
 #! /bin/bash
 
-act.py -c $ANDROID_BUILD_TOP/system/bt/gd/cert/android_devices_config.json -tf $ANDROID_BUILD_TOP/system/bt/gd/cert/cert_testcases -tp $ANDROID_BUILD_TOP/system/bt/gd
+# For bluetooth_packets_python3
+export PYTHONPATH=$PYTHONPATH:$ANDROID_BUILD_TOP/out/host/linux-x86/lib64
+python3.8 `which act.py` -c $ANDROID_BUILD_TOP/system/bt/gd/cert/android_devices_config.json -tf $ANDROID_BUILD_TOP/system/bt/gd/cert/cert_testcases -tp $ANDROID_BUILD_TOP/system/bt/gd
diff --git a/gd/cert/set_up_acts.sh b/gd/cert/set_up_acts.sh
index c8fa38b..ad4e775 100755
--- a/gd/cert/set_up_acts.sh
+++ b/gd/cert/set_up_acts.sh
@@ -46,9 +46,15 @@
     popd
 }
 
-function SetupPython3 {
-    echo "Setting up python3"
-    sudo apt-get install python3-dev
+function SetupPython38 {
+    echo "Setting up python3.8"
+    sudo apt-get install python3.8-dev
+}
+
+function CompileBluetoothPacketsPython3 {
+    echo "bluetooth_packets_python3 is not found, compiling"
+    croot
+    make -j bluetooth_packets_python3
 }
 
 if [[ "${BASH_SOURCE[0]}" == "${0}" ]] ; then
@@ -60,16 +66,41 @@
     SetUpAndroidBuild
 fi
 
-## Check python3 is installed properly
-dpkg -l python3-dev > /dev/null 2>&1
+## Check python3.8 is installed properly
+## Need Python 3.8 because bluetooth_packets_python3 is compiled against
+## Python 3.8 headers
+dpkg -l python3.8-dev > /dev/null 2>&1
 if [[ $? -ne 0 ]] ; then
-    SetupPython3
+    SetupPython38
+fi
+
+## Check bluetooth_packets_python3 is compiled succssfully
+export PYTHONPATH=$PYTHONPATH:$ANDROID_BUILD_TOP/out/host/linux-x86/lib64
+python3.8 -c "
+import bluetooth_packets_python3 as bp3
+bp3.BaseStruct
+"
+if [[ $? -ne 0 ]] ; then
+  pushd .
+  CompileBluetoothPacketsPython3
+  popd
+  python3.8 -c "
+import bluetooth_packets_python3 as bp3
+bp3.BaseStruct
+"
+  if [[ $? -ne 0 ]] ; then
+    echo "Setup failed as bluetooth_packets_python3 cannot be found"
+  else
+    echo "Found bluetooth_packets_python3 after compilation"
+  fi
+else
+  echo "Found bluetooth_packets_python3"
 fi
 
 ## All is good now so go ahead with the acts setup
 pushd .
 cd $ANDROID_BUILD_TOP/tools/test/connectivity/acts/framework/
-sudo python3 setup.py develop
+sudo python3.8 setup.py develop
 if [[ $? -eq 0 ]] ; then
     echo "cert setup complete"
 else
diff --git a/gd/facade/grpc_root_server.cc b/gd/facade/grpc_root_server.cc
index 29ccc59..e802dfe 100644
--- a/gd/facade/grpc_root_server.cc
+++ b/gd/facade/grpc_root_server.cc
@@ -60,7 +60,7 @@
         break;
       case BluetoothModule::L2CAP:
         modules.add<::bluetooth::facade::ReadOnlyPropertyServerModule>();
-        modules.add<::bluetooth::l2cap::classic::L2capModuleFacadeModule>();
+        modules.add<::bluetooth::l2cap::classic::L2capClassicModuleFacadeModule>();
         break;
       default:
         return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "invalid module under test");
diff --git a/gd/hci/acl_manager.h b/gd/hci/acl_manager.h
index 27c4fb3..3706aba 100644
--- a/gd/hci/acl_manager.h
+++ b/gd/hci/acl_manager.h
@@ -151,7 +151,7 @@
  private:
   friend AclManager;
   AclConnection(const AclManager* manager, uint16_t handle, Address address)
-      : manager_(manager), handle_(handle), address_(address) {}
+      : manager_(manager), handle_(handle), address_(address), address_type_(AddressType::PUBLIC_DEVICE_ADDRESS) {}
   AclConnection(const AclManager* manager, uint16_t handle, Address address, AddressType address_type, Role role)
       : manager_(manager), handle_(handle), address_(address), address_type_(address_type), role_(role) {}
   const AclManager* manager_;
diff --git a/gd/hci/classic_security_manager.cc b/gd/hci/classic_security_manager.cc
index 8425ae6..07aae77 100644
--- a/gd/hci/classic_security_manager.cc
+++ b/gd/hci/classic_security_manager.cc
@@ -46,6 +46,8 @@
                                      Bind(&impl::on_request_event, common::Unretained(this)), handler_);
     hci_layer_->RegisterEventHandler(EventCode::ENCRYPTION_KEY_REFRESH_COMPLETE,
                                      Bind(&impl::on_complete_event, common::Unretained(this)), handler_);
+    hci_layer_->RegisterEventHandler(EventCode::LINK_KEY_NOTIFICATION,
+                                     Bind(&impl::on_link_key_notification, common::Unretained(this)), handler_);
   }
 
   void Stop() {
@@ -224,6 +226,12 @@
     LOG_DEBUG("receive complete event %d", (uint8_t)event_code);
   }
 
+  void on_link_key_notification(EventPacketView packet) {
+    auto view = LinkKeyNotificationView::Create(packet);
+    ASSERT(view.IsValid());
+    LOG_DEBUG("receive link key notification, key type %d", (uint8_t)view.GetKeyType());
+  }
+
   void on_command_complete(CommandCompleteView status) {
     if (client_handler_ != nullptr) {
       client_handler_->Post(common::BindOnce(&ClassicSecurityCommandCallbacks::OnCommandComplete,
diff --git a/gd/hci/hci_packets.pdl b/gd/hci/hci_packets.pdl
index f5868c4..c048c80 100644
--- a/gd/hci/hci_packets.pdl
+++ b/gd/hci/hci_packets.pdl
@@ -1530,7 +1530,7 @@
   authentication_enable : AuthenticationEnable,
 }
 
-packet WriteAuthenticationEnable : CommandPacket (op_code = WRITE_AUTHENTICATION_ENABLE) {
+packet WriteAuthenticationEnable : SecurityCommand (op_code = WRITE_AUTHENTICATION_ENABLE) {
   authentication_enable : AuthenticationEnable,
 }
 
@@ -1911,7 +1911,7 @@
   secure_connections_host_support : Enable,
 }
 
-packet WriteSecureConnectionsHostSupport : CommandPacket (op_code = WRITE_SECURE_CONNECTIONS_HOST_SUPPORT) {
+packet WriteSecureConnectionsHostSupport : SecurityCommand (op_code = WRITE_SECURE_CONNECTIONS_HOST_SUPPORT) {
   secure_connections_host_support : Enable,
 }
 
diff --git a/gd/hci/security_interface.h b/gd/hci/security_interface.h
index efb20d0..ea15aa0 100644
--- a/gd/hci/security_interface.h
+++ b/gd/hci/security_interface.h
@@ -43,6 +43,7 @@
       hci::EventCode::IO_CAPABILITY_REQUEST,     hci::EventCode::IO_CAPABILITY_RESPONSE,
       hci::EventCode::REMOTE_OOB_DATA_REQUEST,   hci::EventCode::SIMPLE_PAIRING_COMPLETE,
       hci::EventCode::USER_PASSKEY_NOTIFICATION, hci::EventCode::KEYPRESS_NOTIFICATION,
+      hci::EventCode::USER_CONFIRMATION_REQUEST, hci::EventCode::USER_PASSKEY_REQUEST,
   };
 };
 }  // namespace hci
diff --git a/gd/l2cap/cid.h b/gd/l2cap/cid.h
index 9a21abb..729272c 100644
--- a/gd/l2cap/cid.h
+++ b/gd/l2cap/cid.h
@@ -36,5 +36,7 @@
 constexpr Cid kSmpCid = 6;
 constexpr Cid kSmpBrCid = 7;
 
+constexpr Cid kClassicPairingTriggerCid = kLastFixedChannel - 1;
+
 }  // namespace l2cap
 }  // namespace bluetooth
diff --git a/gd/l2cap/classic/cert/api.proto b/gd/l2cap/classic/cert/api.proto
index c7e68d5..687686f 100644
--- a/gd/l2cap/classic/cert/api.proto
+++ b/gd/l2cap/classic/cert/api.proto
@@ -5,7 +5,7 @@
 import "google/protobuf/empty.proto";
 import "facade/common.proto";
 
-service L2capModuleCert {
+service L2capClassicModuleCert {
   rpc SendL2capPacket(L2capPacket) returns (google.protobuf.Empty) {}
 
   rpc SetupLink(SetupLinkRequest) returns (SetupLinkResponse) {}
diff --git a/gd/l2cap/classic/cert/cert.cc b/gd/l2cap/classic/cert/cert.cc
index 63c8593..2de345c 100644
--- a/gd/l2cap/classic/cert/cert.cc
+++ b/gd/l2cap/classic/cert/cert.cc
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#include "l2cap/classic/cert/cert.h"
-
 #include <condition_variable>
 #include <cstdint>
 #include <memory>
@@ -29,6 +27,7 @@
 #include "hci/cert/cert.h"
 #include "hci/hci_packets.h"
 #include "l2cap/classic/cert/api.grpc.pb.h"
+#include "l2cap/classic/cert/cert.h"
 #include "l2cap/classic/l2cap_classic_module.h"
 #include "l2cap/l2cap_packets.h"
 #include "os/log.h"
@@ -52,9 +51,9 @@
 
 constexpr auto kEventTimeout = std::chrono::seconds(1);
 
-class L2capModuleCertService : public L2capModuleCert::Service {
+class L2capClassicModuleCertService : public L2capClassicModuleCert::Service {
  public:
-  L2capModuleCertService(hci::AclManager* acl_manager, os::Handler* facade_handler)
+  L2capClassicModuleCertService(hci::AclManager* acl_manager, os::Handler* facade_handler)
       : handler_(facade_handler), acl_manager_(acl_manager) {
     ASSERT(handler_ != nullptr);
     acl_manager_->RegisterCallbacks(&acl_callbacks, handler_);
@@ -323,7 +322,7 @@
   void send_packet_from_queue() {
     if (outgoing_packet_queue_.size() == 1) {
       acl_connection_->GetAclQueueEnd()->RegisterEnqueue(
-          handler_, common::Bind(&L2capModuleCertService::enqueue_packet_to_acl, common::Unretained(this)));
+          handler_, common::Bind(&L2capClassicModuleCertService::enqueue_packet_to_acl, common::Unretained(this)));
     }
   }
 
@@ -473,12 +472,13 @@
 
   class AclCallbacks : public hci::ConnectionCallbacks {
    public:
-    AclCallbacks(L2capModuleCertService* module) : module_(module) {}
+    AclCallbacks(L2capClassicModuleCertService* module) : module_(module) {}
     void OnConnectSuccess(std::unique_ptr<hci::AclConnection> connection) override {
       module_->acl_connection_ = std::move(connection);
       module_->acl_connection_->RegisterDisconnectCallback(common::BindOnce([](hci::ErrorCode) {}), module_->handler_);
       module_->acl_connection_->GetAclQueueEnd()->RegisterDequeue(
-          module_->handler_, common::Bind(&L2capModuleCertService::on_incoming_packet, common::Unretained(module_)));
+          module_->handler_,
+          common::Bind(&L2capClassicModuleCertService::on_incoming_packet, common::Unretained(module_)));
       dequeue_registered_ = true;
       FetchL2capLogResponse response;
       response.mutable_link_up()->mutable_remote()->set_address(module_->acl_connection_->GetAddress().ToString());
@@ -494,36 +494,36 @@
 
     bool dequeue_registered_ = false;
 
-    L2capModuleCertService* module_;
+    L2capClassicModuleCertService* module_;
   } acl_callbacks{this};
 
   std::mutex mutex_;
 };
 
-void L2capModuleCertModule::ListDependencies(ModuleList* list) {
+void L2capClassicModuleCertModule::ListDependencies(ModuleList* list) {
   ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
   list->add<hci::AclManager>();
   list->add<hci::HciLayer>();
 }
 
-void L2capModuleCertModule::Start() {
+void L2capClassicModuleCertModule::Start() {
   ::bluetooth::grpc::GrpcFacadeModule::Start();
   GetDependency<hci::HciLayer>()->EnqueueCommand(hci::WriteScanEnableBuilder::Create(hci::ScanEnable::PAGE_SCAN_ONLY),
                                                  common::BindOnce([](hci::CommandCompleteView) {}), GetHandler());
-  service_ = new L2capModuleCertService(GetDependency<hci::AclManager>(), GetHandler());
+  service_ = new L2capClassicModuleCertService(GetDependency<hci::AclManager>(), GetHandler());
 }
 
-void L2capModuleCertModule::Stop() {
+void L2capClassicModuleCertModule::Stop() {
   delete service_;
   ::bluetooth::grpc::GrpcFacadeModule::Stop();
 }
 
-::grpc::Service* L2capModuleCertModule::GetService() const {
+::grpc::Service* L2capClassicModuleCertModule::GetService() const {
   return service_;
 }
 
-const ModuleFactory L2capModuleCertModule::Factory =
-    ::bluetooth::ModuleFactory([]() { return new L2capModuleCertModule(); });
+const ModuleFactory L2capClassicModuleCertModule::Factory =
+    ::bluetooth::ModuleFactory([]() { return new L2capClassicModuleCertModule(); });
 
 }  // namespace cert
 }  // namespace classic
diff --git a/gd/l2cap/classic/cert/cert.h b/gd/l2cap/classic/cert/cert.h
index c8015d6..d3108cd 100644
--- a/gd/l2cap/classic/cert/cert.h
+++ b/gd/l2cap/classic/cert/cert.h
@@ -9,9 +9,9 @@
 namespace classic {
 namespace cert {
 
-class L2capModuleCertService;
+class L2capClassicModuleCertService;
 
-class L2capModuleCertModule : public ::bluetooth::grpc::GrpcFacadeModule {
+class L2capClassicModuleCertModule : public ::bluetooth::grpc::GrpcFacadeModule {
  public:
   static const ModuleFactory Factory;
 
@@ -22,7 +22,7 @@
   ::grpc::Service* GetService() const override;
 
  private:
-  L2capModuleCertService* service_;
+  L2capClassicModuleCertService* service_;
 };
 
 }  // namespace cert
diff --git a/gd/l2cap/classic/facade.cc b/gd/l2cap/classic/facade.cc
index 9613c75..64f3810 100644
--- a/gd/l2cap/classic/facade.cc
+++ b/gd/l2cap/classic/facade.cc
@@ -39,9 +39,9 @@
 namespace l2cap {
 namespace classic {
 
-class L2capModuleFacadeService : public L2capModuleFacade::Service {
+class L2capClassicModuleFacadeService : public L2capClassicModuleFacade::Service {
  public:
-  L2capModuleFacadeService(L2capClassicModule* l2cap_layer, os::Handler* facade_handler)
+  L2capClassicModuleFacadeService(L2capClassicModule* l2cap_layer, os::Handler* facade_handler)
       : l2cap_layer_(l2cap_layer), facade_handler_(facade_handler) {
     ASSERT(l2cap_layer_ != nullptr);
     ASSERT(facade_handler_ != nullptr);
@@ -126,8 +126,8 @@
 
   class L2capFixedChannelHelper {
    public:
-    L2capFixedChannelHelper(L2capModuleFacadeService* service, L2capClassicModule* l2cap_layer, os::Handler* handler,
-                            Cid cid)
+    L2capFixedChannelHelper(L2capClassicModuleFacadeService* service, L2capClassicModule* l2cap_layer,
+                            os::Handler* handler, Cid cid)
         : facade_service_(service), l2cap_layer_(l2cap_layer), handler_(handler), cid_(cid) {
       fixed_channel_manager_ = l2cap_layer_->GetFixedChannelManager();
       fixed_channel_manager_->RegisterService(
@@ -173,7 +173,7 @@
       return packet_one;
     };
 
-    L2capModuleFacadeService* facade_service_;
+    L2capClassicModuleFacadeService* facade_service_;
     L2capClassicModule* l2cap_layer_;
     os::Handler* handler_;
     std::unique_ptr<FixedChannelManager> fixed_channel_manager_;
@@ -192,8 +192,8 @@
 
   class L2capDynamicChannelHelper {
    public:
-    L2capDynamicChannelHelper(L2capModuleFacadeService* service, L2capClassicModule* l2cap_layer, os::Handler* handler,
-                              Psm psm, RetransmissionFlowControlMode mode)
+    L2capDynamicChannelHelper(L2capClassicModuleFacadeService* service, L2capClassicModule* l2cap_layer,
+                              os::Handler* handler, Psm psm, RetransmissionFlowControlMode mode)
         : facade_service_(service), l2cap_layer_(l2cap_layer), handler_(handler), psm_(psm) {
       dynamic_channel_manager_ = l2cap_layer_->GetDynamicChannelManager();
       DynamicChannelConfigurationOption configuration_option;
@@ -255,7 +255,7 @@
       return packet_one;
     };
 
-    L2capModuleFacadeService* facade_service_;
+    L2capClassicModuleFacadeService* facade_service_;
     L2capClassicModule* l2cap_layer_;
     os::Handler* handler_;
     std::unique_ptr<DynamicChannelManager> dynamic_channel_manager_;
@@ -271,7 +271,7 @@
 
   class L2capStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<L2capPacket, L2capPacket> {
    public:
-    L2capStreamCallback(L2capModuleFacadeService* service) : service_(service) {}
+    L2capStreamCallback(L2capClassicModuleFacadeService* service) : service_(service) {}
 
     ~L2capStreamCallback() {
       for (const auto& connection : service_->fixed_channel_helper_map_) {
@@ -329,7 +329,7 @@
       response->CopyFrom(event);
     }
 
-    L2capModuleFacadeService* service_;
+    L2capClassicModuleFacadeService* service_;
     std::map<Cid, bool> subscribed_fixed_channel_;
     std::map<Psm, bool> subscribed_dynamic_channel_;
 
@@ -339,30 +339,30 @@
   std::mutex mutex_;
 };
 
-void L2capModuleFacadeModule::ListDependencies(ModuleList* list) {
+void L2capClassicModuleFacadeModule::ListDependencies(ModuleList* list) {
   ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
   list->add<l2cap::classic::L2capClassicModule>();
   list->add<hci::HciLayer>();
 }
 
-void L2capModuleFacadeModule::Start() {
+void L2capClassicModuleFacadeModule::Start() {
   ::bluetooth::grpc::GrpcFacadeModule::Start();
   GetDependency<hci::HciLayer>()->EnqueueCommand(hci::WriteScanEnableBuilder::Create(hci::ScanEnable::PAGE_SCAN_ONLY),
                                                  common::BindOnce([](hci::CommandCompleteView) {}), GetHandler());
-  service_ = new L2capModuleFacadeService(GetDependency<l2cap::classic::L2capClassicModule>(), GetHandler());
+  service_ = new L2capClassicModuleFacadeService(GetDependency<l2cap::classic::L2capClassicModule>(), GetHandler());
 }
 
-void L2capModuleFacadeModule::Stop() {
+void L2capClassicModuleFacadeModule::Stop() {
   delete service_;
   ::bluetooth::grpc::GrpcFacadeModule::Stop();
 }
 
-::grpc::Service* L2capModuleFacadeModule::GetService() const {
+::grpc::Service* L2capClassicModuleFacadeModule::GetService() const {
   return service_;
 }
 
-const ModuleFactory L2capModuleFacadeModule::Factory =
-    ::bluetooth::ModuleFactory([]() { return new L2capModuleFacadeModule(); });
+const ModuleFactory L2capClassicModuleFacadeModule::Factory =
+    ::bluetooth::ModuleFactory([]() { return new L2capClassicModuleFacadeModule(); });
 
 }  // namespace classic
 }  // namespace l2cap
diff --git a/gd/l2cap/classic/facade.h b/gd/l2cap/classic/facade.h
index 425940a..ebaee0d 100644
--- a/gd/l2cap/classic/facade.h
+++ b/gd/l2cap/classic/facade.h
@@ -16,15 +16,16 @@
 #pragma once
 
 #include <grpc++/grpc++.h>
+
 #include "grpc/grpc_module.h"
 
 namespace bluetooth {
 namespace l2cap {
 namespace classic {
 
-class L2capModuleFacadeService;
+class L2capClassicModuleFacadeService;
 
-class L2capModuleFacadeModule : public ::bluetooth::grpc::GrpcFacadeModule {
+class L2capClassicModuleFacadeModule : public ::bluetooth::grpc::GrpcFacadeModule {
  public:
   static const ModuleFactory Factory;
 
@@ -35,7 +36,7 @@
   ::grpc::Service* GetService() const override;
 
  private:
-  L2capModuleFacadeService* service_;
+  L2capClassicModuleFacadeService* service_;
 };
 
 }  // namespace classic
diff --git a/gd/l2cap/classic/facade.proto b/gd/l2cap/classic/facade.proto
index 7eb780d..ab2a911 100644
--- a/gd/l2cap/classic/facade.proto
+++ b/gd/l2cap/classic/facade.proto
@@ -5,7 +5,7 @@
 import "google/protobuf/empty.proto";
 import "facade/common.proto";
 
-service L2capModuleFacade {
+service L2capClassicModuleFacade {
   rpc RegisterChannel(RegisterChannelRequest) returns (google.protobuf.Empty) {
     // Testing Android Bluetooth stack only. Optional for other stack.
   }
diff --git a/gd/l2cap/classic/fixed_channel_manager.h b/gd/l2cap/classic/fixed_channel_manager.h
index 69812df..5e8f6ab 100644
--- a/gd/l2cap/classic/fixed_channel_manager.h
+++ b/gd/l2cap/classic/fixed_channel_manager.h
@@ -31,6 +31,10 @@
 
 class L2capClassicModule;
 
+namespace testing {
+class MockFixedChannelManager;
+}
+
 namespace internal {
 class LinkManager;
 class FixedChannelServiceManagerImpl;
@@ -102,7 +106,7 @@
    *
    * Returns: true if connection was able to be initiated, false otherwise.
    */
-  bool ConnectServices(hci::Address device, OnConnectionFailureCallback on_fail_callback, os::Handler* handler);
+  virtual bool ConnectServices(hci::Address device, OnConnectionFailureCallback on_fail_callback, os::Handler* handler);
 
   /**
    * Register a service to receive incoming connections bound to a specific channel.
@@ -124,11 +128,14 @@
    * @param on_open_callback: A callback to indicate success of a connection initiated from a remote device.
    * @param handler: The handler context in which to execute the @callback parameter.
    */
-  bool RegisterService(Cid cid, const SecurityPolicy& security_policy,
-                       OnRegistrationCompleteCallback on_registration_complete,
-                       OnConnectionOpenCallback on_connection_open, os::Handler* handler);
+  virtual bool RegisterService(Cid cid, const SecurityPolicy& security_policy,
+                               OnRegistrationCompleteCallback on_registration_complete,
+                               OnConnectionOpenCallback on_connection_open, os::Handler* handler);
+
+  virtual ~FixedChannelManager() = default;
 
   friend class L2capClassicModule;
+  friend class testing::MockFixedChannelManager;
 
  private:
   // The constructor is not to be used by user code
diff --git a/gd/l2cap/classic/fixed_channel_manager_mock.h b/gd/l2cap/classic/fixed_channel_manager_mock.h
new file mode 100644
index 0000000..5ead957
--- /dev/null
+++ b/gd/l2cap/classic/fixed_channel_manager_mock.h
@@ -0,0 +1,42 @@
+/*
+ * 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/classic/fixed_channel_manager.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace testing {
+
+class MockFixedChannelManager : public FixedChannelManager {
+ public:
+  MockFixedChannelManager() : FixedChannelManager(nullptr, nullptr, nullptr){};
+  MOCK_METHOD(bool, ConnectServices,
+              (hci::Address device, OnConnectionFailureCallback on_fail_callback, os::Handler* handler), (override));
+  MOCK_METHOD(bool, RegisterService,
+              (Cid cid, const SecurityPolicy& security_policy, OnRegistrationCompleteCallback on_registration_complete,
+               OnConnectionOpenCallback on_connection_open, os::Handler* handler),
+              (override));
+};
+
+}  // namespace testing
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/dynamic_channel_impl.cc b/gd/l2cap/classic/internal/dynamic_channel_impl.cc
index ba613a6..c0614f9 100644
--- a/gd/l2cap/classic/internal/dynamic_channel_impl.cc
+++ b/gd/l2cap/classic/internal/dynamic_channel_impl.cc
@@ -102,21 +102,17 @@
   sender_ = sender;
 }
 
-Mtu DynamicChannelImpl::GetIncomingMtu() const {
-  return incoming_mtu_;
-}
-
 void DynamicChannelImpl::SetIncomingMtu(Mtu mtu) {
-  incoming_mtu_ = mtu;
+  sender_->SetIncomingMtu(mtu);
 }
 
 void DynamicChannelImpl::SetRetransmissionFlowControlConfig(
     const RetransmissionAndFlowControlConfigurationOption& option) {
-  sender_->SetChannelRetransmissionFlowControlMode(option.mode_);
+  sender_->SetChannelRetransmissionFlowControlMode(option);
 }
 
 void DynamicChannelImpl::SetFcsType(FcsType fcs_type) {
-  fcs_type_ = fcs_type;
+  sender_->SetFcsType(fcs_type);
 }
 
 }  // namespace internal
diff --git a/gd/l2cap/classic/internal/dynamic_channel_impl.h b/gd/l2cap/classic/internal/dynamic_channel_impl.h
index ac1f02c..95be5c7 100644
--- a/gd/l2cap/classic/internal/dynamic_channel_impl.h
+++ b/gd/l2cap/classic/internal/dynamic_channel_impl.h
@@ -82,7 +82,6 @@
    */
   void SetSender(l2cap::internal::Sender* sender) override;
 
-  virtual Mtu GetIncomingMtu() const;
   virtual void SetIncomingMtu(Mtu mtu);
 
   virtual void SetRetransmissionFlowControlConfig(const RetransmissionAndFlowControlConfigurationOption& mode);
@@ -114,9 +113,6 @@
   ConfigurationStatus incoming_configuration_status_ = ConfigurationStatus::NOT_CONFIGURED;
 
   l2cap::internal::Sender* sender_ = nullptr;
-  Mtu incoming_mtu_ = kDefaultClassicMtu;
-  // TODO: Add all RetransmissionAndFlowControlConfigurationOptions
-  FcsType fcs_type_ = FcsType::DEFAULT;
 
   DISALLOW_COPY_AND_ASSIGN(DynamicChannelImpl);
 };
diff --git a/gd/l2cap/classic/internal/link.h b/gd/l2cap/classic/internal/link.h
index 2c6c1b8..09d7eb9 100644
--- a/gd/l2cap/classic/internal/link.h
+++ b/gd/l2cap/classic/internal/link.h
@@ -99,7 +99,7 @@
   virtual void NotifyChannelCreation(Cid cid, std::unique_ptr<DynamicChannel> channel);
   virtual void NotifyChannelFail(Cid cid);
 
-  // Information received from signalling channel
+  // Information received from signaling channel
   virtual void SetRemoteConnectionlessMtu(Mtu mtu);
   virtual Mtu GetRemoteConnectionlessMtu() const;
   virtual void SetRemoteSupportsErtm(bool supported);
@@ -107,6 +107,10 @@
   virtual void SetRemoteSupportsFcs(bool supported);
   virtual bool GetRemoteSupportsFcs() const;
 
+  virtual std::string ToString() {
+    return GetDevice().ToString();
+  }
+
  private:
   os::Handler* l2cap_handler_;
   l2cap::internal::FixedChannelAllocator<FixedChannelImpl, Link> fixed_channel_allocator_{this, l2cap_handler_};
diff --git a/gd/l2cap/classic/internal/signalling_manager.cc b/gd/l2cap/classic/internal/signalling_manager.cc
index 66a3f51..7398c17 100644
--- a/gd/l2cap/classic/internal/signalling_manager.cc
+++ b/gd/l2cap/classic/internal/signalling_manager.cc
@@ -310,7 +310,6 @@
     return;
   }
 
-  RetransmissionAndFlowControlConfigurationOption rfc_option;
   channel->SetOutgoingConfigurationStatus(DynamicChannelImpl::ConfigurationStatus::CONFIGURED);
   if (channel->GetIncomingConfigurationStatus() == DynamicChannelImpl::ConfigurationStatus::CONFIGURED) {
     std::unique_ptr<DynamicChannel> user_channel = std::make_unique<DynamicChannel>(channel, handler_);
diff --git a/gd/l2cap/classic/l2cap_classic_module.cc b/gd/l2cap/classic/l2cap_classic_module.cc
index bc30c86..ca5a0d5 100644
--- a/gd/l2cap/classic/l2cap_classic_module.cc
+++ b/gd/l2cap/classic/l2cap_classic_module.cc
@@ -50,6 +50,10 @@
                                       &dynamic_channel_service_manager_impl_, &parameter_provider_};
 };
 
+L2capClassicModule::L2capClassicModule() {}
+
+L2capClassicModule::~L2capClassicModule() {}
+
 void L2capClassicModule::ListDependencies(ModuleList* list) {
   list->add<hci::AclManager>();
 }
@@ -78,4 +82,4 @@
 
 }  // namespace classic
 }  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/l2cap_classic_module.h b/gd/l2cap/classic/l2cap_classic_module.h
index 7255bc3..388cae2 100644
--- a/gd/l2cap/classic/l2cap_classic_module.h
+++ b/gd/l2cap/classic/l2cap_classic_module.h
@@ -27,18 +27,18 @@
 
 class L2capClassicModule : public bluetooth::Module {
  public:
-  L2capClassicModule() = default;
-  ~L2capClassicModule() = default;
+  L2capClassicModule();
+  virtual ~L2capClassicModule();
 
   /**
    * Get the api to the classic fixed channel l2cap module
    */
-  std::unique_ptr<FixedChannelManager> GetFixedChannelManager();
+  virtual std::unique_ptr<FixedChannelManager> GetFixedChannelManager();
 
   /**
    * Get the api to the classic dynamic channel l2cap module
    */
-  std::unique_ptr<DynamicChannelManager> GetDynamicChannelManager();
+  virtual std::unique_ptr<DynamicChannelManager> GetDynamicChannelManager();
 
   static const ModuleFactory Factory;
 
@@ -59,4 +59,4 @@
 
 }  // namespace classic
 }  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace bluetooth
diff --git a/gd/l2cap/classic/l2cap_classic_module_mock.h b/gd/l2cap/classic/l2cap_classic_module_mock.h
new file mode 100644
index 0000000..1252854
--- /dev/null
+++ b/gd/l2cap/classic/l2cap_classic_module_mock.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 "l2cap/classic/l2cap_classic_module.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace testing {
+
+class MockL2capClassicModule : public L2capClassicModule {
+ public:
+  MOCK_METHOD(std::unique_ptr<FixedChannelManager>, GetFixedChannelManager, (), (override));
+  MOCK_METHOD(std::unique_ptr<DynamicChannelManager>, GetDynamicChannelManager, (), (override));
+};
+
+}  // namespace testing
+}  // namespace classic
+}  // namespace l2cap
+}  // namespace bluetooth
diff --git a/gd/l2cap/internal/basic_mode_channel_data_controller.h b/gd/l2cap/internal/basic_mode_channel_data_controller.h
index c19fb93..41d03fa 100644
--- a/gd/l2cap/internal/basic_mode_channel_data_controller.h
+++ b/gd/l2cap/internal/basic_mode_channel_data_controller.h
@@ -50,6 +50,9 @@
 
   std::unique_ptr<BasicFrameBuilder> GetNextPacket() override;
 
+  void EnableFcs(bool enabled) override {}
+  void SetRetransmissionAndFlowControlOptions(const RetransmissionAndFlowControlConfigurationOption& option) override {}
+
  private:
   Cid cid_;
   Cid remote_cid_;
diff --git a/gd/l2cap/internal/data_controller.h b/gd/l2cap/internal/data_controller.h
index 18cff2a..33bfbcf 100644
--- a/gd/l2cap/internal/data_controller.h
+++ b/gd/l2cap/internal/data_controller.h
@@ -38,6 +38,14 @@
 
   // Used by Scheduler to get next PDU
   virtual std::unique_ptr<BasicFrameBuilder> GetNextPacket() = 0;
+
+  // Set FCS mode. This only applies to some modes (ERTM).
+  virtual void EnableFcs(bool enabled) = 0;
+
+  // Set retransmission and flow control. Ignore the mode option because each DataController only handles one mode.
+  // This only applies to some modes (ERTM).
+  virtual void SetRetransmissionAndFlowControlOptions(
+      const RetransmissionAndFlowControlConfigurationOption& option) = 0;
 };
 
 }  // namespace internal
diff --git a/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller.cc b/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller.cc
index 3e5042d..08a4bbe 100644
--- a/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller.cc
+++ b/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller.cc
@@ -875,11 +875,23 @@
   }
 }
 
+void ErtmController::EnableFcs(bool enabled) {
+  fcs_enabled_ = enabled;
+}
+
 void ErtmController::send_pdu(std::unique_ptr<BasicFrameBuilder> pdu) {
   pdu_queue_.emplace(std::move(pdu));
   scheduler_->OnPacketsReady(cid_, 1);
 }
 
+void ErtmController::SetRetransmissionAndFlowControlOptions(
+    const RetransmissionAndFlowControlConfigurationOption& option) {
+  local_tx_window_ = option.tx_window_size_;
+  local_max_transmit_ = option.max_transmit_;
+  local_retransmit_timeout_ms_ = option.retransmission_time_out_;
+  local_monitor_timeout_ms_ = option.monitor_time_out_;
+}
+
 void ErtmController::close_channel() {
   // TODO: Get a reference to signalling manager
 }
diff --git a/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller.h b/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller.h
index 0566e0b..2038fd3 100644
--- a/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller.h
+++ b/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller.h
@@ -49,16 +49,17 @@
   void OnSdu(std::unique_ptr<packet::BasePacketBuilder> sdu) override;
   void OnPdu(BasicFrameView pdu) override;
   std::unique_ptr<BasicFrameBuilder> GetNextPacket() override;
+  void EnableFcs(bool enabled) override;
+  void SetRetransmissionAndFlowControlOptions(const RetransmissionAndFlowControlConfigurationOption& option) override;
 
  private:
-  [[maybe_unused]] Cid cid_;
-  [[maybe_unused]] Cid remote_cid_;
-  [[maybe_unused]] os::EnqueueBuffer<UpperEnqueue> enqueue_buffer_;
-  [[maybe_unused]] os::Handler* handler_;
+  Cid cid_;
+  Cid remote_cid_;
+  os::EnqueueBuffer<UpperEnqueue> enqueue_buffer_;
+  os::Handler* handler_;
   std::queue<std::unique_ptr<BasicFrameBuilder>> pdu_queue_;
-  [[maybe_unused]] Scheduler* scheduler_;
-  // TODO: Support FCS
-  [[maybe_unused]] FcsType fcs_type_ = FcsType::NO_FCS;
+  Scheduler* scheduler_;
+  bool fcs_enabled_ = false;
 
   class PacketViewForReassembly : public packet::PacketView<kLittleEndian> {
    public:
@@ -89,7 +90,6 @@
   void close_channel();
 
   // Configuration options
-  // TODO: Configure these number
   uint16_t local_tx_window_ = 10;
   uint16_t local_max_transmit_ = 20;
   uint16_t local_retransmit_timeout_ms_ = 2000;
diff --git a/gd/l2cap/internal/fixed_channel_allocator.h b/gd/l2cap/internal/fixed_channel_allocator.h
index a421c91..b821cb1 100644
--- a/gd/l2cap/internal/fixed_channel_allocator.h
+++ b/gd/l2cap/internal/fixed_channel_allocator.h
@@ -44,20 +44,17 @@
   // Allocates a channel. If cid is used, return nullptr. NOTE: The returned BaseFixedChannelImpl object is still
   // owned by the channel allocator, NOT the client.
   virtual std::shared_ptr<FixedChannelImplType> AllocateChannel(Cid cid, SecurityPolicy security_policy) {
-    ASSERT_LOG(!IsChannelAllocated((cid)), "Cid 0x%x for device %s is already in use", cid,
-               link_->GetDevice().ToString().c_str());
+    ASSERT_LOG(!IsChannelAllocated((cid)), "Cid 0x%x for link %s is already in use", cid, link_->ToString().c_str());
     ASSERT_LOG(cid >= kFirstFixedChannel && cid <= kLastFixedChannel, "Cid %d out of bound", cid);
     auto elem = channels_.try_emplace(cid, std::make_shared<FixedChannelImplType>(cid, link_, l2cap_handler_));
-    ASSERT_LOG(elem.second, "Failed to create channel for cid 0x%x device %s", cid,
-               link_->GetDevice().ToString().c_str());
+    ASSERT_LOG(elem.second, "Failed to create channel for cid 0x%x link %s", cid, link_->ToString().c_str());
     ASSERT(elem.first->second != nullptr);
     return elem.first->second;
   }
 
   // Frees a channel. If cid doesn't exist, it will crash
   virtual void FreeChannel(Cid cid) {
-    ASSERT_LOG(IsChannelAllocated(cid), "Channel is not in use: cid %d, device %s", cid,
-               link_->GetDevice().ToString().c_str());
+    ASSERT_LOG(IsChannelAllocated(cid), "Channel is not in use: cid %d, link %s", cid, link_->ToString().c_str());
     channels_.erase(cid);
   }
 
@@ -66,8 +63,7 @@
   }
 
   virtual std::shared_ptr<FixedChannelImplType> FindChannel(Cid cid) {
-    ASSERT_LOG(IsChannelAllocated(cid), "Channel is not in use: cid %d, device %s", cid,
-               link_->GetDevice().ToString().c_str());
+    ASSERT_LOG(IsChannelAllocated(cid), "Channel is not in use: cid %d, link %s", cid, link_->ToString().c_str());
     return channels_.find(cid)->second;
   }
 
diff --git a/gd/l2cap/internal/sender.cc b/gd/l2cap/internal/sender.cc
index ffe2755..7fe1dd7 100644
--- a/gd/l2cap/internal/sender.cc
+++ b/gd/l2cap/internal/sender.cc
@@ -55,22 +55,28 @@
   return data_controller_->GetNextPacket();
 }
 
-void Sender::SetChannelRetransmissionFlowControlMode(RetransmissionAndFlowControlModeOption mode) {
-  if (mode_ == mode) {
+void Sender::SetChannelRetransmissionFlowControlMode(const RetransmissionAndFlowControlConfigurationOption& option) {
+  if (mode_ == option.mode_) {
     return;
   }
-  if (mode == RetransmissionAndFlowControlModeOption::L2CAP_BASIC) {
+  if (option.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) {
+  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
 }
diff --git a/gd/l2cap/internal/sender.h b/gd/l2cap/internal/sender.h
index 22f7737..850a88d 100644
--- a/gd/l2cap/internal/sender.h
+++ b/gd/l2cap/internal/sender.h
@@ -25,6 +25,7 @@
 #include "l2cap/cid.h"
 #include "l2cap/internal/channel_impl.h"
 #include "l2cap/internal/data_controller.h"
+#include "l2cap/l2cap_packets.h"
 #include "l2cap/mtu.h"
 #include "os/handler.h"
 #include "os/queue.h"
@@ -60,8 +61,8 @@
    */
   std::unique_ptr<UpperDequeue> GetNextPacket();
 
-  void SetChannelRetransmissionFlowControlMode(RetransmissionAndFlowControlModeOption mode);
-
+  void SetChannelRetransmissionFlowControlMode(const RetransmissionAndFlowControlConfigurationOption& option);
+  void SetFcsType(FcsType fcs_type);
   void SetIncomingMtu(Mtu mtu);
 
   DataController* GetDataController();
diff --git a/gd/l2cap/le/fixed_channel.cc b/gd/l2cap/le/fixed_channel.cc
index 1e6a163..d02dad6 100644
--- a/gd/l2cap/le/fixed_channel.cc
+++ b/gd/l2cap/le/fixed_channel.cc
@@ -49,4 +49,4 @@
 }
 }  // namespace le
 }  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace bluetooth
diff --git a/gd/l2cap/le/fixed_channel_manager.h b/gd/l2cap/le/fixed_channel_manager.h
index ea1a346..4583310 100644
--- a/gd/l2cap/le/fixed_channel_manager.h
+++ b/gd/l2cap/le/fixed_channel_manager.h
@@ -50,9 +50,9 @@
     hci::ErrorCode hci_error = hci::ErrorCode::SUCCESS;
   };
   /**
-   * OnConnectionFailureCallback(std::string failure_reason);
+   * OnConnectionFailureCallback(ConnectionResult failure_reason);
    */
-  using OnConnectionFailureCallback = common::OnceCallback<void(ConnectionResult result)>;
+  using OnConnectionFailureCallback = common::OnceCallback<void(ConnectionResult)>;
 
   /**
    * OnConnectionOpenCallback(FixedChannel channel);
diff --git a/gd/l2cap/le/internal/fixed_channel_impl_test.cc b/gd/l2cap/le/internal/fixed_channel_impl_test.cc
index 9874936..a4270b4 100644
--- a/gd/l2cap/le/internal/fixed_channel_impl_test.cc
+++ b/gd/l2cap/le/internal/fixed_channel_impl_test.cc
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 #include "l2cap/le/internal/fixed_channel_impl.h"
-
 #include "common/testing/bind_test_util.h"
+#include "hci/address_with_type.h"
 #include "l2cap/cid.h"
 #include "l2cap/internal/parameter_provider_mock.h"
 #include "l2cap/le/internal/link_mock.h"
diff --git a/gd/l2cap/le/internal/link.h b/gd/l2cap/le/internal/link.h
index 5dc8ae4..783e03b 100644
--- a/gd/l2cap/le/internal/link.h
+++ b/gd/l2cap/le/internal/link.h
@@ -90,6 +90,10 @@
     }
   }
 
+  virtual std::string ToString() {
+    return GetDevice().ToString();
+  }
+
  private:
   os::Handler* l2cap_handler_;
   l2cap::internal::FixedChannelAllocator<FixedChannelImpl, Link> fixed_channel_allocator_{this, l2cap_handler_};
diff --git a/gd/l2cap/le/internal/link_mock.h b/gd/l2cap/le/internal/link_mock.h
index 3411c95..08ea629 100644
--- a/gd/l2cap/le/internal/link_mock.h
+++ b/gd/l2cap/le/internal/link_mock.h
@@ -16,7 +16,7 @@
 #pragma once
 
 #include "hci/acl_manager_mock.h"
-#include "hci/address.h"
+#include "hci/address_with_type.h"
 #include "l2cap/internal/scheduler_mock.h"
 #include "l2cap/le/internal/link.h"
 
@@ -50,4 +50,4 @@
 }  // namespace internal
 }  // namespace le
 }  // namespace l2cap
-}  // namespace bluetooth
\ No newline at end of file
+}  // namespace bluetooth
diff --git a/test/rootcanal/bluetooth_hci.cc b/test/rootcanal/bluetooth_hci.cc
index 3a636f5..2bebd9a 100644
--- a/test/rootcanal/bluetooth_hci.cc
+++ b/test/rootcanal/bluetooth_hci.cc
@@ -104,7 +104,9 @@
 
   controller_ = std::make_shared<DualModeController>();
 
-  controller_->Initialize({"dmc", "3C:5A:B4:01:02:03"});
+  char mac_property[PROPERTY_VALUE_MAX] = "";
+  property_get("bt.rootcanal_mac_address", mac_property, "3C:5A:B4:01:02:03");
+  controller_->Initialize({"dmc", std::string(mac_property)});
 
   controller_->RegisterEventChannel(
       [this, cb](std::shared_ptr<std::vector<uint8_t>> packet) {