eatt/l2cap: Add upper tester for L2CAP test cases

This patch adds upper tester for L2CAP ECOC testing e.g.
 - trigger sending data
 - trigger reconfiguration
 - trigger L2CAP ECOC creation as a peripheral
 - initiate ECOC with configurable number of channels
 - configure minimum encryption key size
 - force all profiles to use EATT

Bug: 242033442
Bug: 242032465
Bug: 237399985
Test: PTS Testing
Test: atest BluetoothInstrumentationTests
Tag: #feature

Merged-In: Iee13f61149381dc1adec485bfc6dd216361ad1b9
Change-Id: Iee13f61149381dc1adec485bfc6dd216361ad1b9
(cherry picked from commit 8512f5bb9fdf285f8c6901f0df33f655a0ce9fd4)
diff --git a/system/conf/bt_stack.conf b/system/conf/bt_stack.conf
index 8e2cbe3..daadeb3 100644
--- a/system/conf/bt_stack.conf
+++ b/system/conf/bt_stack.conf
@@ -47,13 +47,39 @@
 # Use EATT for the notifications
 #PTS_ForceEattForNotifications=true
 
+# PTS L2CAP Ecoc upper tester (hijack eatt)
+#PTS_L2capEcocUpperTester=true
+
+# PTS L2CAP initial number of channels
+#note: PTS_EnableL2capUpperTester shall be true
+#PTS_L2capEcocInitialChanCnt=3
+
+# PTS Min key size for L2CAP ECOC upper tester
+# note: PTS_EnableL2capUpperTester shall be true
+#PTS_L2capEcocMinKeySize=16
+
+# PTS Send connect request after connect confirmation
+# note: PTS_L2capEcocInitialChanCnt shall be less than 5
+#PTS_L2capEcocConnectRemaining=true
+
+#PTS L2CAP CoC schedule sending data after connection
+# note: PTS_EnableL2capUpperTester shall be true
+#PTS_L2capEcocSendNumOfSdu=2
+
 # Start EATT without validation Server Supported Features
+# note: PTS_EnableL2capUpperTester shall be true
 #PTS_ConnectEattUncondictionally=true
 
+# Trigger reconfiguration after connection
+# note: PTS_EnableL2capUpperTester shall be true
+#PTS_L2capEcocReconfigure=true
+
 # Start EATT on unecrypted link
+# note: PTS_EnableL2capUpperTester shall be true
 #PTS_ConnectEattUnencrypted=true
 
 # Force EATT implementation to connect EATT as a peripheral for collision test case
+# note: PTS_EnableL2capUpperTester shall be true
 #PTS_EattPeripheralCollionSupport=true
 
 # Disable BR/EDR discovery after LE pairing to avoid cross key derivation errors
@@ -68,6 +94,9 @@
 # Start broadcast with unecryption mode
 #PTS_BroadcastUnencrypted=true
 
+# Use EATT for all services
+#PTS_UseEattForAllServices=true
+
 # SMP Certification Failure Cases
 # Set any of the following SMP error values (from smp_api_types.h)
 # to induce pairing failues for various PTS SMP test cases.
diff --git a/system/internal_include/stack_config.h b/system/internal_include/stack_config.h
index 31d4067..9d396c7 100644
--- a/system/internal_include/stack_config.h
+++ b/system/internal_include/stack_config.h
@@ -38,6 +38,13 @@
   bool (*get_pts_connect_eatt_before_encryption)(void);
   bool (*get_pts_unencrypt_broadcast)(void);
   bool (*get_pts_eatt_peripheral_collision_support)(void);
+  bool (*get_pts_use_eatt_for_all_services)(void);
+  bool (*get_pts_l2cap_ecoc_upper_tester)(void);
+  int (*get_pts_l2cap_ecoc_min_key_size)(void);
+  int (*get_pts_l2cap_ecoc_initial_chan_cnt)(void);
+  bool (*get_pts_l2cap_ecoc_connect_remaining)(void);
+  int (*get_pts_l2cap_ecoc_send_num_of_sdu)(void);
+  bool (*get_pts_l2cap_ecoc_reconfigure)(void);
   const std::string* (*get_pts_broadcast_audio_config_options)(void);
   config_t* (*get_all)(void);
 } stack_config_t;
diff --git a/system/main/stack_config.cc b/system/main/stack_config.cc
index 2da9050..97033c5 100644
--- a/system/main/stack_config.cc
+++ b/system/main/stack_config.cc
@@ -40,6 +40,13 @@
 const char* PTS_BROADCAST_UNENCRYPTED = "PTS_BroadcastUnencrypted";
 const char* PTS_EATT_PERIPHERAL_COLLISION_SUPPORT =
     "PTS_EattPeripheralCollionSupport";
+const char* PTS_EATT_USE_FOR_ALL_SERVICES = "PTS_UseEattForAllServices";
+const char* PTS_L2CAP_ECOC_UPPER_TESTER = "PTS_L2capEcocUpperTester";
+const char* PTS_L2CAP_ECOC_MIN_KEY_SIZE = "PTS_L2capEcocMinKeySize";
+const char* PTS_L2CAP_ECOC_INITIAL_CHAN_CNT = "PTS_L2capEcocInitialChanCnt";
+const char* PTS_L2CAP_ECOC_CONNECT_REMAINING = "PTS_L2capEcocConnectRemaining";
+const char* PTS_L2CAP_ECOC_SEND_NUM_OF_SDU = "PTS_L2capEcocSendNumOfSdu";
+const char* PTS_L2CAP_ECOC_RECONFIGURE = "PTS_L2capEcocReconfigure";
 const char* PTS_BROADCAST_AUDIO_CONFIG_OPTION =
     "PTS_BroadcastAudioConfigOption";
 
@@ -144,6 +151,41 @@
                          PTS_EATT_PERIPHERAL_COLLISION_SUPPORT, false);
 }
 
+static bool get_pts_use_eatt_for_all_services(void) {
+  return config_get_bool(*config, CONFIG_DEFAULT_SECTION,
+                         PTS_EATT_USE_FOR_ALL_SERVICES, false);
+}
+
+static bool get_pts_l2cap_ecoc_upper_tester(void) {
+  return config_get_bool(*config, CONFIG_DEFAULT_SECTION,
+                         PTS_L2CAP_ECOC_UPPER_TESTER, false);
+}
+
+static int get_pts_l2cap_ecoc_min_key_size(void) {
+  return config_get_int(*config, CONFIG_DEFAULT_SECTION,
+                        PTS_L2CAP_ECOC_MIN_KEY_SIZE, -1);
+}
+
+static int get_pts_l2cap_ecoc_initial_chan_cnt(void) {
+  return config_get_int(*config, CONFIG_DEFAULT_SECTION,
+                        PTS_L2CAP_ECOC_INITIAL_CHAN_CNT, -1);
+}
+
+static bool get_pts_l2cap_ecoc_connect_remaining(void) {
+  return config_get_bool(*config, CONFIG_DEFAULT_SECTION,
+                         PTS_L2CAP_ECOC_CONNECT_REMAINING, false);
+}
+
+static int get_pts_l2cap_ecoc_send_num_of_sdu(void) {
+  return config_get_int(*config, CONFIG_DEFAULT_SECTION,
+                        PTS_L2CAP_ECOC_SEND_NUM_OF_SDU, -1);
+}
+
+static bool get_pts_l2cap_ecoc_reconfigure(void) {
+  return config_get_bool(*config, CONFIG_DEFAULT_SECTION,
+                         PTS_L2CAP_ECOC_RECONFIGURE, false);
+}
+
 static const std::string* get_pts_broadcast_audio_config_options(void) {
   if (!config) {
     LOG_INFO("Config isn't ready, use default option");
@@ -167,6 +209,13 @@
                                   get_pts_connect_eatt_before_encryption,
                                   get_pts_unencrypt_broadcast,
                                   get_pts_eatt_peripheral_collision_support,
+                                  get_pts_use_eatt_for_all_services,
+                                  get_pts_l2cap_ecoc_upper_tester,
+                                  get_pts_l2cap_ecoc_min_key_size,
+                                  get_pts_l2cap_ecoc_initial_chan_cnt,
+                                  get_pts_l2cap_ecoc_connect_remaining,
+                                  get_pts_l2cap_ecoc_send_num_of_sdu,
+                                  get_pts_l2cap_ecoc_reconfigure,
                                   get_pts_broadcast_audio_config_options,
                                   get_all};
 
diff --git a/system/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc b/system/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc
index 8aeff6b..55a5d89 100644
--- a/system/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc
+++ b/system/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc
@@ -60,7 +60,11 @@
                                   nullptr, nullptr,
                                   nullptr, nullptr,
                                   nullptr, nullptr,
-                                  nullptr, nullptr};
+                                  nullptr, nullptr,
+                                  nullptr, nullptr,
+                                  nullptr, nullptr,
+                                  nullptr, nullptr,
+                                  nullptr};
 
 void Callback(uint8_t, bool, std::unique_ptr<::bluetooth::PacketBuilder>) {}
 
diff --git a/system/profile/avrcp/tests/avrcp_device_test.cc b/system/profile/avrcp/tests/avrcp_device_test.cc
index c69a4ad..e88bd6c 100644
--- a/system/profile/avrcp/tests/avrcp_device_test.cc
+++ b/system/profile/avrcp/tests/avrcp_device_test.cc
@@ -56,7 +56,11 @@
                                   nullptr, nullptr,
                                   nullptr, nullptr,
                                   nullptr, nullptr,
-                                  nullptr, nullptr};
+                                  nullptr, nullptr,
+                                  nullptr, nullptr,
+                                  nullptr, nullptr,
+                                  nullptr, nullptr,
+                                  nullptr};
 
 // TODO (apanicke): All the tests below are just basic positive unit tests.
 // Add more tests to increase code coverage.
diff --git a/system/stack/eatt/eatt_impl.h b/system/stack/eatt/eatt_impl.h
index f0f2e4e..4943b34 100644
--- a/system/stack/eatt/eatt_impl.h
+++ b/system/stack/eatt/eatt_impl.h
@@ -123,23 +123,9 @@
     remove_channel_by_cid(eatt_dev, lcid);
   }
 
-  void eatt_l2cap_connect_ind(const RawAddress& bda,
-                              std::vector<uint16_t>& lcids, uint16_t psm,
-                              uint16_t peer_mtu, uint8_t identifier) {
-    if (!stack_config_get_interface()
-             ->get_pts_connect_eatt_before_encryption() &&
-        !BTM_IsEncrypted(bda, BT_TRANSPORT_LE)) {
-      /* If Link is not encrypted, we shall not accept EATT channel creation. */
-      std::vector<uint16_t> empty;
-      uint16_t result = L2CAP_LE_RESULT_INSUFFICIENT_AUTHENTICATION;
-      if (BTM_IsLinkKeyKnown(bda, BT_TRANSPORT_LE)) {
-        result = L2CAP_LE_RESULT_INSUFFICIENT_ENCRYP;
-      }
-      LOG_ERROR("ACL to device %s is unencrypted.", bda.ToString().c_str());
-      L2CA_ConnectCreditBasedRsp(bda, identifier, empty, result, nullptr);
-      return;
-    }
-
+  bool eatt_l2cap_connect_ind_common(const RawAddress& bda,
+                                     std::vector<uint16_t>& lcids, uint16_t psm,
+                                     uint16_t peer_mtu, uint8_t identifier) {
     /* The assumption is that L2CAP layer already check parameters etc.
      * Get our capabilities and accept all the channels.
      */
@@ -164,7 +150,7 @@
 
     if (!L2CA_ConnectCreditBasedRsp(bda, identifier, lcids, L2CAP_CONN_OK,
                                     &local_coc_cfg))
-      return;
+      return false;
 
     if (!eatt_dev->eatt_tcb_) {
       eatt_dev->eatt_tcb_ =
@@ -186,13 +172,159 @@
       LOG(INFO) << __func__ << " Channel connected CID " << loghex(cid);
     }
 
+    return true;
+  }
+
+  /* This is for the L2CAP ECoC Testing. */
+  void upper_tester_send_data_if_needed(const RawAddress& bda,
+                                        uint16_t cid = 0) {
+    eatt_device* eatt_dev = find_device_by_address(bda);
+    auto num_of_sdu =
+        stack_config_get_interface()->get_pts_l2cap_ecoc_send_num_of_sdu();
+    LOG_INFO(" device %s, num: %d", eatt_dev->bda_.ToString().c_str(),
+             num_of_sdu);
+
+    if (num_of_sdu <= 0) {
+      return;
+    }
+
+    uint16_t mtu = 0;
+    if (cid != 0) {
+      auto chan = find_channel_by_cid(cid);
+      mtu = chan->tx_mtu_;
+    } else {
+      for (const std::pair<uint16_t, std::shared_ptr<EattChannel>>& el :
+           eatt_dev->eatt_channels) {
+        if (el.second->state_ == EattChannelState::EATT_CHANNEL_OPENED) {
+          cid = el.first;
+          mtu = el.second->tx_mtu_;
+          break;
+        }
+      }
+    }
+
+    if (cid == 0 || mtu == 0) {
+      LOG_ERROR("There is no OPEN cid or MTU is 0");
+      return;
+    }
+
+    for (int i = 0; i < num_of_sdu; i++) {
+      BT_HDR* p_buf = (BT_HDR*)osi_malloc(mtu + sizeof(BT_HDR));
+      p_buf->offset = L2CAP_MIN_OFFSET;
+      p_buf->len = mtu;
+
+      auto status = L2CA_DataWrite(cid, p_buf);
+      LOG_INFO("Data num: %d sent with status %d", i, static_cast<int>(status));
+    }
+  }
+
+  /* This is for the L2CAP ECoC Testing. */
+  void upper_tester_delay_connect_cb(const RawAddress& bda) {
+    LOG_INFO("device %s", bda.ToString().c_str());
+    eatt_device* eatt_dev = find_device_by_address(bda);
+    if (eatt_dev == nullptr) {
+      LOG_ERROR(" device is not available");
+      return;
+    }
+
+    connect_eatt_wrap(eatt_dev);
+  }
+
+  void upper_tester_delay_connect(const RawAddress& bda, int timeout_ms) {
+    bt_status_t status = do_in_main_thread_delayed(
+        FROM_HERE,
+        base::BindOnce(&eatt_impl::upper_tester_delay_connect_cb,
+                       base::Unretained(this), bda),
+#if BASE_VER < 931007
+        base::TimeDelta::FromMilliseconds(timeout_ms)
+#else
+        base::Milliseconds(timeout_ms)
+#endif
+    );
+
+    LOG_INFO("Scheduled peripheral connect eatt for device with status: %d",
+             (int)status);
+  }
+
+  void upper_tester_l2cap_connect_ind(const RawAddress& bda,
+                                      std::vector<uint16_t>& lcids,
+                                      uint16_t psm, uint16_t peer_mtu,
+                                      uint8_t identifier) {
+    /* This is just for L2CAP PTS test cases*/
+    auto min_key_size =
+        stack_config_get_interface()->get_pts_l2cap_ecoc_min_key_size();
+    if (min_key_size > 0 && (min_key_size >= 7 && min_key_size <= 16)) {
+      auto key_size = btm_ble_read_sec_key_size(bda);
+      if (key_size < min_key_size) {
+        std::vector<uint16_t> empty;
+        LOG_ERROR("Insufficient key size (%d<%d) for device %s", key_size,
+                  min_key_size, bda.ToString().c_str());
+        L2CA_ConnectCreditBasedRsp(bda, identifier, empty,
+                                   L2CAP_LE_RESULT_INSUFFICIENT_ENCRYP_KEY_SIZE,
+                                   nullptr);
+        return;
+      }
+    }
+
+    if (!eatt_l2cap_connect_ind_common(bda, lcids, psm, peer_mtu, identifier)) {
+      LOG_DEBUG("Reject L2CAP Connection request.");
+      return;
+    }
+
     /* Android let Central to create EATT (PTS initiates EATT). Some PTS test
      * cases wants Android to do it anyway (Android initiates EATT).
      */
     if (stack_config_get_interface()
             ->get_pts_eatt_peripheral_collision_support()) {
-      connect_eatt_wrap(eatt_dev);
+      upper_tester_delay_connect(bda, 500);
+      return;
     }
+
+    upper_tester_send_data_if_needed(bda);
+
+    if (stack_config_get_interface()->get_pts_l2cap_ecoc_reconfigure()) {
+      bt_status_t status = do_in_main_thread_delayed(
+          FROM_HERE,
+          base::BindOnce(&eatt_impl::reconfigure_all, base::Unretained(this),
+                         bda, 300),
+#if BASE_VER < 931007
+          base::TimeDelta::FromMilliseconds(4000)
+#else
+          base::Milliseconds(4000)
+#endif
+      );
+      LOG_INFO("Scheduled ECOC reconfiguration with status: %d", (int)status);
+    }
+  }
+
+  void eatt_l2cap_connect_ind(const RawAddress& bda,
+                              std::vector<uint16_t>& lcids, uint16_t psm,
+                              uint16_t peer_mtu, uint8_t identifier) {
+    LOG_INFO("Device %s, num of cids: %d, psm 0x%04x, peer_mtu %d",
+             bda.ToString().c_str(), static_cast<int>(lcids.size()), psm,
+             peer_mtu);
+
+    if (!stack_config_get_interface()
+             ->get_pts_connect_eatt_before_encryption() &&
+        !BTM_IsEncrypted(bda, BT_TRANSPORT_LE)) {
+      /* If Link is not encrypted, we shall not accept EATT channel creation. */
+      std::vector<uint16_t> empty;
+      uint16_t result = L2CAP_LE_RESULT_INSUFFICIENT_AUTHENTICATION;
+      if (BTM_IsLinkKeyKnown(bda, BT_TRANSPORT_LE)) {
+        result = L2CAP_LE_RESULT_INSUFFICIENT_ENCRYP;
+      }
+      LOG_ERROR("ACL to device %s is unencrypted.", bda.ToString().c_str());
+      L2CA_ConnectCreditBasedRsp(bda, identifier, empty, result, nullptr);
+      return;
+    }
+
+    if (stack_config_get_interface()->get_pts_l2cap_ecoc_upper_tester()) {
+      LOG_INFO(" Upper tester for the L2CAP ECoC enabled");
+      return upper_tester_l2cap_connect_ind(bda, lcids, psm, peer_mtu,
+                                            identifier);
+    }
+
+    eatt_l2cap_connect_ind_common(bda, lcids, psm, peer_mtu, identifier);
   }
 
   void eatt_retry_after_collision_if_needed(eatt_device* eatt_dev) {
@@ -219,17 +351,31 @@
       /* This is only for the PTS. Android does not setup EATT when is a
        * peripheral.
        */
-      bt_status_t status = do_in_main_thread_delayed(
-          FROM_HERE,
-          base::BindOnce(&eatt_impl::connect_eatt_wrap, base::Unretained(this),
-                         std::move(eatt_dev)),
-          base::TimeDelta::FromMilliseconds(500));
-
-      LOG_INFO("Scheduled peripheral connect eatt for device with status: %d",
-               (int)status);
+      upper_tester_delay_connect(eatt_dev->bda_, 500);
     }
   }
 
+  /* This is for the L2CAP ECoC Testing. */
+  void upper_tester_l2cap_connect_cfm(eatt_device* eatt_dev) {
+    LOG_INFO("Upper tester for L2CAP Ecoc %s",
+             eatt_dev->bda_.ToString().c_str());
+    if (is_channel_connection_pending(eatt_dev)) {
+      LOG_INFO(" Waiting for all channels to be connected");
+      return;
+    }
+
+    if (stack_config_get_interface()->get_pts_l2cap_ecoc_connect_remaining() &&
+        (static_cast<int>(eatt_dev->eatt_channels.size()) <
+         L2CAP_CREDIT_BASED_MAX_CIDS)) {
+      LOG_INFO("Connecting remaining channels %d",
+               L2CAP_CREDIT_BASED_MAX_CIDS -
+                   static_cast<int>(eatt_dev->eatt_channels.size()));
+      upper_tester_delay_connect(eatt_dev->bda_, 1000);
+      return;
+    }
+    upper_tester_send_data_if_needed(eatt_dev->bda_);
+  }
+
   void eatt_l2cap_connect_cfm(const RawAddress& bda, uint16_t lcid,
                               uint16_t peer_mtu, uint16_t result) {
     LOG(INFO) << __func__ << " bda: " << bda << " cid: " << +lcid
@@ -267,6 +413,10 @@
     eatt_dev->eatt_tcb_->eatt++;
 
     LOG_INFO("Channel connected CID 0x%04x", lcid);
+
+    if (stack_config_get_interface()->get_pts_l2cap_ecoc_upper_tester()) {
+      upper_tester_l2cap_connect_cfm(eatt_dev);
+    }
   }
 
   void eatt_l2cap_reconfig_completed(const RawAddress& bda, uint16_t lcid,
@@ -293,6 +443,20 @@
 
     /* Go back to open state */
     channel->EattChannelSetState(EattChannelState::EATT_CHANNEL_OPENED);
+
+    if (stack_config_get_interface()->get_pts_l2cap_ecoc_reconfigure()) {
+      /* Upper tester for L2CAP - schedule sending data */
+      do_in_main_thread_delayed(
+          FROM_HERE,
+          base::BindOnce(&eatt_impl::upper_tester_send_data_if_needed,
+                         base::Unretained(this), bda, lcid),
+#if BASE_VER < 931007
+          base::TimeDelta::FromMilliseconds(1000)
+#else
+          base::Milliseconds(1000)
+#endif
+      );
+    }
   }
 
   void eatt_l2cap_collision_ind(const RawAddress& bda) {
@@ -655,6 +819,7 @@
   }
 
   void reconfigure_all(const RawAddress& bd_addr, uint16_t new_mtu) {
+    LOG_INFO(" Device %s, new mtu %d", bd_addr.ToString().c_str(), new_mtu);
     eatt_device* eatt_dev = find_device_by_address(bd_addr);
     if (!eatt_dev) {
       LOG(ERROR) << __func__ << "Unknown device " << bd_addr;
@@ -753,6 +918,44 @@
     eatt_dev->collision = false;
   }
 
+  void upper_tester_connect(const RawAddress& bd_addr, eatt_device* eatt_dev,
+                            uint8_t role) {
+    LOG_INFO(
+        "L2CAP Upper tester enabled, %s (%p), role: %s(%d)",
+        bd_addr.ToString().c_str(), eatt_dev,
+        role == HCI_ROLE_CENTRAL ? "HCI_ROLE_CENTRAL" : "HCI_ROLE_PERIPHERAL",
+        role);
+
+    auto num_of_chan =
+        stack_config_get_interface()->get_pts_l2cap_ecoc_initial_chan_cnt();
+    if (num_of_chan <= 0) {
+      num_of_chan = L2CAP_CREDIT_BASED_MAX_CIDS;
+    }
+
+    /* This is needed for L2CAP test cases */
+    if (stack_config_get_interface()->get_pts_connect_eatt_unconditionally()) {
+      /* Normally eatt_dev exist only if EATT is supported by remote device.
+       * Here it is created unconditionally */
+      if (eatt_dev == nullptr) eatt_dev = add_eatt_device(bd_addr);
+      /* For PTS just start connecting EATT right away */
+      connect_eatt(eatt_dev, num_of_chan);
+      return;
+    }
+
+    if (eatt_dev != nullptr && role == HCI_ROLE_CENTRAL) {
+      connect_eatt(eatt_dev, num_of_chan);
+      return;
+    }
+
+    /* If we don't know yet, read GATT server supported features. */
+    if (gatt_cl_read_sr_supp_feat_req(
+            bd_addr, base::BindOnce(&eatt_impl::supported_features_cb,
+                                    base::Unretained(this), role)) == false) {
+      LOG_INFO("Read server supported features failed for device %s",
+               bd_addr.ToString().c_str());
+    }
+  }
+
   void connect(const RawAddress& bd_addr) {
     eatt_device* eatt_dev = find_device_by_address(bd_addr);
 
@@ -762,6 +965,11 @@
       return;
     }
 
+    if (stack_config_get_interface()->get_pts_l2cap_ecoc_upper_tester()) {
+      upper_tester_connect(bd_addr, eatt_dev, role);
+      return;
+    }
+
     LOG_INFO("Device %s, role %s", bd_addr.ToString().c_str(),
              (role == HCI_ROLE_CENTRAL ? "central" : "peripheral"));
 
@@ -781,13 +989,7 @@
       return;
     }
 
-    /* This is needed for L2CAP test cases */
-    if (stack_config_get_interface()->get_pts_connect_eatt_unconditionally()) {
-      /* For PTS just start connecting EATT right away */
-      eatt_device* eatt_dev = add_eatt_device(bd_addr);
-      connect_eatt_wrap(eatt_dev);
-      return;
-    }
+    if (role != HCI_ROLE_CENTRAL) return;
 
     if (gatt_profile_get_eatt_support(bd_addr)) {
       LOG_DEBUG("Eatt is supported for device %s", bd_addr.ToString().c_str());
diff --git a/system/stack/gatt/gatt_api.cc b/system/stack/gatt/gatt_api.cc
index 2673928..b956924 100644
--- a/system/stack/gatt/gatt_api.cc
+++ b/system/stack/gatt/gatt_api.cc
@@ -1114,6 +1114,11 @@
     }
   }
 
+  if (stack_config_get_interface()->get_pts_use_eatt_for_all_services()) {
+    LOG_INFO("PTS: Force to use EATT for servers");
+    eatt_support = true;
+  }
+
   for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS;
        i_gatt_if++, p_reg++) {
     if (!p_reg->in_use) {
diff --git a/system/stack/test/btm/stack_btm_test.cc b/system/stack/test/btm/stack_btm_test.cc
index d4b78f5..5895d68 100644
--- a/system/stack/test/btm/stack_btm_test.cc
+++ b/system/stack/test/btm/stack_btm_test.cc
@@ -77,6 +77,13 @@
 bool get_pts_connect_eatt_before_encryption(void) { return false; }
 bool get_pts_unencrypt_broadcast(void) { return false; }
 bool get_pts_eatt_peripheral_collision_support(void) { return false; }
+bool get_pts_use_eatt_for_all_services(void) { return false; }
+bool get_pts_l2cap_ecoc_upper_tester(void) { return false; }
+int get_pts_l2cap_ecoc_min_key_size(void) { return -1; }
+int get_pts_l2cap_ecoc_initial_chan_cnt(void) { return -1; }
+bool get_pts_l2cap_ecoc_connect_remaining(void) { return false; }
+int get_pts_l2cap_ecoc_send_num_of_sdu(void) { return -1; }
+bool get_pts_l2cap_ecoc_reconfigure(void) { return false; }
 const std::string* get_pts_broadcast_audio_config_options(void) {
   return &kBroadcastAudioConfigOptions;
 }
@@ -100,6 +107,13 @@
     .get_pts_unencrypt_broadcast = get_pts_unencrypt_broadcast,
     .get_pts_eatt_peripheral_collision_support =
         get_pts_eatt_peripheral_collision_support,
+    .get_pts_l2cap_ecoc_upper_tester = get_pts_l2cap_ecoc_upper_tester,
+    .get_pts_l2cap_ecoc_min_key_size = get_pts_l2cap_ecoc_min_key_size,
+    .get_pts_l2cap_ecoc_initial_chan_cnt = get_pts_l2cap_ecoc_initial_chan_cnt,
+    .get_pts_l2cap_ecoc_connect_remaining =
+        get_pts_l2cap_ecoc_connect_remaining,
+    .get_pts_l2cap_ecoc_send_num_of_sdu = get_pts_l2cap_ecoc_send_num_of_sdu,
+    .get_pts_l2cap_ecoc_reconfigure = get_pts_l2cap_ecoc_reconfigure,
     .get_pts_broadcast_audio_config_options =
         get_pts_broadcast_audio_config_options,
     .get_all = get_all,
diff --git a/system/stack/test/common/mock_btm_api_layer.cc b/system/stack/test/common/mock_btm_api_layer.cc
index c1779c5..93c5fdb 100644
--- a/system/stack/test/common/mock_btm_api_layer.cc
+++ b/system/stack/test/common/mock_btm_api_layer.cc
@@ -41,3 +41,7 @@
                         tBT_TRANSPORT transport) {
   return btm_api_interface->IsLinkKeyKnown(remote_bd_addr, transport);
 }
+
+uint8_t btm_ble_read_sec_key_size(const RawAddress& bd_addr) {
+  return btm_api_interface->ReadSecKeySize(bd_addr);
+}
\ No newline at end of file
diff --git a/system/stack/test/common/mock_btm_api_layer.h b/system/stack/test/common/mock_btm_api_layer.h
index 8c92fb3..2dd5659 100644
--- a/system/stack/test/common/mock_btm_api_layer.h
+++ b/system/stack/test/common/mock_btm_api_layer.h
@@ -36,6 +36,7 @@
                            tBT_TRANSPORT transport) = 0;
   virtual bool IsLinkKeyKnown(const RawAddress& remote_bd_addr,
                               tBT_TRANSPORT transport) = 0;
+  virtual uint8_t ReadSecKeySize(const RawAddress& remote_bd_addr) = 0;
   virtual ~BtmApiInterface() = default;
 };
 
@@ -51,6 +52,7 @@
                bool(const RawAddress& remote_bd_addr, tBT_TRANSPORT transport));
   MOCK_METHOD2(IsLinkKeyKnown,
                bool(const RawAddress& remote_bd_addr, tBT_TRANSPORT transport));
+  MOCK_METHOD1(ReadSecKeySize, uint8_t(const RawAddress& remote_bd_addr));
 };
 
 /**
diff --git a/system/stack/test/stack_smp_test.cc b/system/stack/test/stack_smp_test.cc
index 7a12fc9..f057c6c 100644
--- a/system/stack/test/stack_smp_test.cc
+++ b/system/stack/test/stack_smp_test.cc
@@ -52,6 +52,13 @@
 bool get_pts_connect_eatt_before_encryption(void) { return false; }
 bool get_pts_unencrypt_broadcast(void) { return false; }
 bool get_pts_eatt_peripheral_collision_support(void) { return false; }
+bool get_pts_use_eatt_for_all_services(void) { return false; }
+bool get_pts_l2cap_ecoc_upper_tester(void) { return false; }
+int get_pts_l2cap_ecoc_min_key_size(void) { return -1; }
+int get_pts_l2cap_ecoc_initial_chan_cnt(void) { return -1; }
+bool get_pts_l2cap_ecoc_connect_remaining(void) { return false; }
+int get_pts_l2cap_ecoc_send_num_of_sdu(void) { return -1; }
+bool get_pts_l2cap_ecoc_reconfigure(void) { return false; }
 const std::string* get_pts_broadcast_audio_config_options(void) {
   return &kBroadcastAudioConfigOptions;
 }
@@ -75,6 +82,14 @@
     .get_pts_unencrypt_broadcast = get_pts_unencrypt_broadcast,
     .get_pts_eatt_peripheral_collision_support =
         get_pts_eatt_peripheral_collision_support,
+    .get_pts_use_eatt_for_all_services = get_pts_use_eatt_for_all_services,
+    .get_pts_l2cap_ecoc_upper_tester = get_pts_l2cap_ecoc_upper_tester,
+    .get_pts_l2cap_ecoc_min_key_size = get_pts_l2cap_ecoc_min_key_size,
+    .get_pts_l2cap_ecoc_initial_chan_cnt = get_pts_l2cap_ecoc_initial_chan_cnt,
+    .get_pts_l2cap_ecoc_connect_remaining =
+        get_pts_l2cap_ecoc_connect_remaining,
+    .get_pts_l2cap_ecoc_send_num_of_sdu = get_pts_l2cap_ecoc_send_num_of_sdu,
+    .get_pts_l2cap_ecoc_reconfigure = get_pts_l2cap_ecoc_reconfigure,
     .get_pts_broadcast_audio_config_options =
         get_pts_broadcast_audio_config_options,
     .get_all = get_all,
diff --git a/system/test/common/stack_config.cc b/system/test/common/stack_config.cc
index ffc1ccb..9078a9c 100644
--- a/system/test/common/stack_config.cc
+++ b/system/test/common/stack_config.cc
@@ -37,6 +37,13 @@
 bool get_pts_connect_eatt_before_encryption(void) { return false; }
 bool get_pts_unencrypt_broadcast(void) { return false; }
 bool get_pts_eatt_peripheral_collision_support(void) { return false; }
+bool get_pts_use_eatt_for_all_services(void) { return false; }
+bool get_pts_l2cap_ecoc_upper_tester(void) { return false; }
+int get_pts_l2cap_ecoc_min_key_size(void) { return -1; }
+int get_pts_l2cap_ecoc_initial_chan_cnt(void) { return -1; }
+bool get_pts_l2cap_ecoc_connect_remaining(void) { return false; }
+int get_pts_l2cap_ecoc_send_num_of_sdu(void) { return -1; }
+bool get_pts_l2cap_ecoc_reconfigure(void) { return false; }
 const std::string* get_pts_broadcast_audio_config_options(void) {
   return &kBroadcastAudioConfigOptions;
 }
@@ -62,6 +69,14 @@
     .get_pts_unencrypt_broadcast = get_pts_unencrypt_broadcast,
     .get_pts_eatt_peripheral_collision_support =
         get_pts_eatt_peripheral_collision_support,
+    .get_pts_use_eatt_for_all_services = get_pts_use_eatt_for_all_services,
+    .get_pts_l2cap_ecoc_upper_tester = get_pts_l2cap_ecoc_upper_tester,
+    .get_pts_l2cap_ecoc_min_key_size = get_pts_l2cap_ecoc_min_key_size,
+    .get_pts_l2cap_ecoc_initial_chan_cnt = get_pts_l2cap_ecoc_initial_chan_cnt,
+    .get_pts_l2cap_ecoc_connect_remaining =
+        get_pts_l2cap_ecoc_connect_remaining,
+    .get_pts_l2cap_ecoc_send_num_of_sdu = get_pts_l2cap_ecoc_send_num_of_sdu,
+    .get_pts_l2cap_ecoc_reconfigure = get_pts_l2cap_ecoc_reconfigure,
     .get_pts_broadcast_audio_config_options =
         get_pts_broadcast_audio_config_options,
     .get_all = get_all,