Merge cherrypicks of ['googleplex-android-review.googlesource.com/22919959', 'googleplex-android-review.googlesource.com/24737501', 'googleplex-android-review.googlesource.com/24737502', 'googleplex-android-review.googlesource.com/24737503', 'googleplex-android-review.googlesource.com/24737504', 'googleplex-android-review.googlesource.com/24737505', 'googleplex-android-review.googlesource.com/24638916', 'googleplex-android-review.googlesource.com/24638579', 'googleplex-android-review.googlesource.com/23356997', 'googleplex-android-review.googlesource.com/24234506', 'googleplex-android-review.googlesource.com/24972364'] into security-aosp-tm-release.

Change-Id: I142169e5149703456243dd64c09a14453e5ae332
diff --git a/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp b/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp
index 1c86ca8..2bff59b 100644
--- a/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp
+++ b/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp
@@ -644,6 +644,7 @@
     }
     vm->DetachCurrentThread();
     sHaveCallbackThread = false;
+    callbackEnv = NULL;
   }
 }
 
diff --git a/system/btif/src/btif_avrcp_audio_track.cc b/system/btif/src/btif_avrcp_audio_track.cc
index 8ca5c97..e17f80f 100644
--- a/system/btif/src/btif_avrcp_audio_track.cc
+++ b/system/btif/src/btif_avrcp_audio_track.cc
@@ -23,6 +23,8 @@
 #include <base/logging.h>
 #include <utils/StrongPointer.h>
 
+#include <algorithm>
+
 #include "bt_target.h"
 #include "osi/include/log.h"
 
@@ -152,7 +154,7 @@
                                   BtifAvrcpAudioTrack* trackHolder) {
   size_t sampleSize = sampleSizeFor(trackHolder);
   size_t i = 0;
-  for (; i <= length / sampleSize; i++) {
+  for (; i < std::min(trackHolder->bufferLength, length / sampleSize); i++) {
     trackHolder->buffer[i] = ((int16_t*)buffer)[i] * kScaleQ15ToFloat;
   }
   return i * sampleSize;
@@ -162,7 +164,7 @@
                                   BtifAvrcpAudioTrack* trackHolder) {
   size_t sampleSize = sampleSizeFor(trackHolder);
   size_t i = 0;
-  for (; i <= length / sampleSize; i++) {
+  for (; i < std::min(trackHolder->bufferLength, length / sampleSize); i++) {
     size_t offset = i * sampleSize;
     int32_t sample = *((int32_t*)(buffer + offset - 1)) & 0x00FFFFFF;
     trackHolder->buffer[i] = sample * kScaleQ23ToFloat;
@@ -174,7 +176,7 @@
                                   BtifAvrcpAudioTrack* trackHolder) {
   size_t sampleSize = sampleSizeFor(trackHolder);
   size_t i = 0;
-  for (; i <= length / sampleSize; i++) {
+  for (; i < std::min(trackHolder->bufferLength, length / sampleSize); i++) {
     trackHolder->buffer[i] = ((int32_t*)buffer)[i] * kScaleQ31ToFloat;
   }
   return i * sampleSize;
diff --git a/system/main/Android.bp b/system/main/Android.bp
index 8f8a245..e64f62d 100644
--- a/system/main/Android.bp
+++ b/system/main/Android.bp
@@ -188,6 +188,7 @@
         "shim/metrics_api.cc",
         "shim/shim.cc",
         "shim/stack.cc",
+        "shim/utils.cc",
         "test/common_stack_test.cc",
         "test/main_shim_dumpsys_test.cc",
         "test/main_shim_test.cc",
diff --git a/system/main/shim/Android.bp b/system/main/shim/Android.bp
index b8aca32..ce39d30 100644
--- a/system/main/shim/Android.bp
+++ b/system/main/shim/Android.bp
@@ -29,5 +29,6 @@
         "metrics_api.cc",
         "shim.cc",
         "stack.cc",
-    ]
+        "utils.cc",
+    ],
 }
diff --git a/system/main/shim/BUILD.gn b/system/main/shim/BUILD.gn
index 8362dd8..2c6a88b 100644
--- a/system/main/shim/BUILD.gn
+++ b/system/main/shim/BUILD.gn
@@ -35,6 +35,7 @@
     "metrics_api.cc",
     "shim.cc",
     "stack.cc",
+    "utils.cc",
   ]
 
   include_dirs = [
diff --git a/system/main/shim/le_advertising_manager.cc b/system/main/shim/le_advertising_manager.cc
index dc8f81a..0fec4e0 100644
--- a/system/main/shim/le_advertising_manager.cc
+++ b/system/main/shim/le_advertising_manager.cc
@@ -17,6 +17,7 @@
 #define LOG_TAG "bt_shim_advertiser"
 
 #include "le_advertising_manager.h"
+#include "utils.h"
 
 #include <base/logging.h>
 #include <hardware/bluetooth.h>
@@ -43,6 +44,7 @@
 using bluetooth::hci::ErrorCode;
 using bluetooth::hci::GapData;
 using bluetooth::hci::OwnAddressType;
+using bluetooth::shim::parse_gap_data;
 using std::vector;
 
 namespace {
@@ -88,23 +90,8 @@
   void SetData(int advertiser_id, bool set_scan_rsp, vector<uint8_t> data,
                StatusCallback cb) override {
     LOG(INFO) << __func__ << " in shim layer";
-
-    size_t offset = 0;
     std::vector<GapData> advertising_data = {};
-
-    while (offset < data.size()) {
-      GapData gap_data;
-      uint8_t len = data[offset];
-      auto begin = data.begin() + offset;
-      auto end = begin + len + 1;  // 1 byte for len
-      auto data_copy = std::make_shared<std::vector<uint8_t>>(begin, end);
-      bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian> packet(
-          data_copy);
-      GapData::Parse(&gap_data, packet.begin());
-      advertising_data.push_back(gap_data);
-      offset += len + 1;  // 1 byte for len
-    }
-
+    parse_gap_data(data, advertising_data);
     bluetooth::shim::GetAdvertising()->SetData(advertiser_id, set_scan_rsp,
                                                advertising_data);
   }
@@ -128,33 +115,8 @@
     bluetooth::hci::ExtendedAdvertisingConfig config{};
     parse_parameter(config, params);
 
-    size_t offset = 0;
-    while (offset < advertise_data.size()) {
-      GapData gap_data;
-      uint8_t len = advertise_data[offset];
-      auto begin = advertise_data.begin() + offset;
-      auto end = begin + len + 1;  // 1 byte for len
-      auto data_copy = std::make_shared<std::vector<uint8_t>>(begin, end);
-      bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian> packet(
-          data_copy);
-      GapData::Parse(&gap_data, packet.begin());
-      config.advertisement.push_back(gap_data);
-      offset += len + 1;  // 1 byte for len
-    }
-
-    offset = 0;
-    while (offset < scan_response_data.size()) {
-      GapData gap_data;
-      uint8_t len = scan_response_data[offset];
-      auto begin = scan_response_data.begin() + offset;
-      auto end = begin + len + 1;  // 1 byte for len
-      auto data_copy = std::make_shared<std::vector<uint8_t>>(begin, end);
-      bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian> packet(
-          data_copy);
-      GapData::Parse(&gap_data, packet.begin());
-      config.scan_response.push_back(gap_data);
-      offset += len + 1;  // 1 byte for len
-    }
+    parse_gap_data(advertise_data, config.advertisement);
+    parse_gap_data(scan_response_data, config.scan_response);
 
     bluetooth::shim::GetAdvertising()->StartAdvertising(
         advertiser_id, config, timeout_s * 100, cb, timeout_cb, scan_callback,
@@ -180,47 +142,9 @@
         periodic_params.periodic_advertising_properties;
     config.periodic_advertising_parameters = periodic_parameters;
 
-    size_t offset = 0;
-    while (offset < advertise_data.size()) {
-      GapData gap_data;
-      uint8_t len = advertise_data[offset];
-      auto begin = advertise_data.begin() + offset;
-      auto end = begin + len + 1;  // 1 byte for len
-      auto data_copy = std::make_shared<std::vector<uint8_t>>(begin, end);
-      bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian> packet(
-          data_copy);
-      GapData::Parse(&gap_data, packet.begin());
-      config.advertisement.push_back(gap_data);
-      offset += len + 1;  // 1 byte for len
-    }
-
-    offset = 0;
-    while (offset < scan_response_data.size()) {
-      GapData gap_data;
-      uint8_t len = scan_response_data[offset];
-      auto begin = scan_response_data.begin() + offset;
-      auto end = begin + len + 1;  // 1 byte for len
-      auto data_copy = std::make_shared<std::vector<uint8_t>>(begin, end);
-      bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian> packet(
-          data_copy);
-      GapData::Parse(&gap_data, packet.begin());
-      config.scan_response.push_back(gap_data);
-      offset += len + 1;  // 1 byte for len
-    }
-
-    offset = 0;
-    while (offset < periodic_data.size()) {
-      GapData gap_data;
-      uint8_t len = periodic_data[offset];
-      auto begin = periodic_data.begin() + offset;
-      auto end = begin + len + 1;  // 1 byte for len
-      auto data_copy = std::make_shared<std::vector<uint8_t>>(begin, end);
-      bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian> packet(
-          data_copy);
-      GapData::Parse(&gap_data, packet.begin());
-      config.periodic_data.push_back(gap_data);
-      offset += len + 1;  // 1 byte for len
-    }
+    parse_gap_data(advertise_data, config.advertisement);
+    parse_gap_data(scan_response_data, config.scan_response);
+    parse_gap_data(periodic_data, config.periodic_data);
 
     bluetooth::hci::AdvertiserId id =
         bluetooth::shim::GetAdvertising()->ExtendedCreateAdvertiser(
@@ -249,23 +173,8 @@
   void SetPeriodicAdvertisingData(int advertiser_id, std::vector<uint8_t> data,
                                   StatusCallback cb) override {
     LOG(INFO) << __func__ << " in shim layer";
-
-    size_t offset = 0;
     std::vector<GapData> advertising_data = {};
-
-    while (offset < data.size()) {
-      GapData gap_data;
-      uint8_t len = data[offset];
-      auto begin = data.begin() + offset;
-      auto end = begin + len + 1;  // 1 byte for len
-      auto data_copy = std::make_shared<std::vector<uint8_t>>(begin, end);
-      bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian> packet(
-          data_copy);
-      GapData::Parse(&gap_data, packet.begin());
-      advertising_data.push_back(gap_data);
-      offset += len + 1;  // 1 byte for len
-    }
-
+    parse_gap_data(data, advertising_data);
     bluetooth::shim::GetAdvertising()->SetPeriodicData(advertiser_id,
                                                        advertising_data);
   }
diff --git a/system/main/shim/utils.cc b/system/main/shim/utils.cc
new file mode 100644
index 0000000..9f18ddc
--- /dev/null
+++ b/system/main/shim/utils.cc
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2023 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.
+ */
+
+#include "utils.h"
+
+namespace bluetooth {
+namespace shim {
+void parse_gap_data(const std::vector<uint8_t> &raw_data,
+                    std::vector<hci::GapData> &output) {
+    size_t offset = 0;
+    while (offset < raw_data.size()) {
+      hci::GapData gap_data;
+      uint8_t len = raw_data[offset];
+
+      if (offset + len + 1 > raw_data.size()) {
+        break;
+      }
+
+      auto begin = raw_data.begin() + offset;
+      auto end = begin + len + 1;  // 1 byte for len
+      auto data_copy = std::make_shared<std::vector<uint8_t>>(begin, end);
+      bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian> packet(
+          data_copy);
+      hci::GapData::Parse(&gap_data, packet.begin());
+      output.push_back(gap_data);
+      offset += len + 1;  // 1 byte for len
+    }
+}
+
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/system/main/shim/utils.h b/system/main/shim/utils.h
new file mode 100644
index 0000000..56da2a0
--- /dev/null
+++ b/system/main/shim/utils.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2023 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 <vector>
+
+#include "hci/hci_packets.h"
+
+namespace bluetooth {
+namespace shim {
+/**
+ * @brief Parsing gap data from raw bytes
+ *
+ * @param raw_data input, raw bytes
+ * @param output vector of GapData
+ */
+void parse_gap_data(const std::vector<uint8_t> &raw_data,
+                    std::vector<hci::GapData> &output);
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/system/stack/btm/btm_ble.cc b/system/stack/btm/btm_ble.cc
index 3a18f25..fb488ed 100644
--- a/system/stack/btm/btm_ble.cc
+++ b/system/stack/btm/btm_ble.cc
@@ -25,12 +25,15 @@
 
 #define LOG_TAG "bt_btm_ble"
 
+#include <base/logging.h>
+
 #include <cstdint>
 
 #include "device/include/controller.h"
 #include "main/shim/btm_api.h"
 #include "main/shim/l2c_api.h"
 #include "main/shim/shim.h"
+#include "openssl/mem.h"
 #include "osi/include/allocator.h"
 #include "osi/include/properties.h"
 #include "stack/btm/btm_dev.h"
@@ -48,8 +51,6 @@
 #include "stack/include/smp_api.h"
 #include "types/raw_address.h"
 
-#include <base/logging.h>
-
 extern tBTM_CB btm_cb;
 
 extern bool btm_ble_init_pseudo_addr(tBTM_SEC_DEV_REC* p_dev_rec,
@@ -1991,7 +1992,7 @@
 
     crypto_toolbox::aes_cmac(p_rec->ble.keys.pcsrk, p_orig, len,
                              BTM_CMAC_TLEN_SIZE, p_mac);
-    if (memcmp(p_mac, p_comp, BTM_CMAC_TLEN_SIZE) == 0) {
+    if (CRYPTO_memcmp(p_mac, p_comp, BTM_CMAC_TLEN_SIZE) == 0) {
       btm_ble_increment_sign_ctr(bd_addr, false);
       verified = true;
     }
diff --git a/system/stack/btm/btm_ble_gap.cc b/system/stack/btm/btm_ble_gap.cc
index b4e52f6..7083c88 100644
--- a/system/stack/btm/btm_ble_gap.cc
+++ b/system/stack/btm/btm_ble_gap.cc
@@ -916,6 +916,12 @@
   uint8_t options = 0;
   uint8_t cte_type = 7;
   int index = btm_ble_get_psync_index(sid, addr);
+
+  if (index == MAX_SYNC_TRANSACTION) {
+    LOG_ERROR("Failed to get sync transfer index");
+    return;
+  }
+
   tBTM_BLE_PERIODIC_SYNC* p = &btm_ble_pa_sync_cb.p_sync[index];
   p->sync_state = PERIODIC_SYNC_PENDING;
 
@@ -989,6 +995,11 @@
 
   int index = btm_ble_get_psync_index(adv_sid, address);
 
+  if (index == MAX_SYNC_TRANSACTION) {
+    LOG_ERROR("Failed to get sync transfer index");
+    return;
+  }
+
   tBTM_BLE_PERIODIC_SYNC* p = &btm_ble_pa_sync_cb.p_sync[index];
 
   if (BleScanningManager::IsInitialized()) {
@@ -1192,11 +1203,14 @@
                               SyncLostCb lostCb) {
   LOG_DEBUG("%s", "[PSync]");
   int index = btm_ble_get_free_psync_index();
-  tBTM_BLE_PERIODIC_SYNC* p = &btm_ble_pa_sync_cb.p_sync[index];
+
   if (index == MAX_SYNC_TRANSACTION) {
     syncCb.Run(BTM_NO_RESOURCES, 0, adv_sid, BLE_ADDR_RANDOM, address, 0, 0);
     return;
   }
+
+  tBTM_BLE_PERIODIC_SYNC* p = &btm_ble_pa_sync_cb.p_sync[index];
+
   p->in_use = true;
   p->remote_bda = address;
   p->sid = adv_sid;
@@ -1328,6 +1342,12 @@
   }
 
   int index = btm_ble_get_free_sync_transfer_index();
+  if (index == MAX_SYNC_TRANSACTION) {
+    BTM_TRACE_ERROR("Failed to get sync transfer index");
+    cb.Run(BTM_ILLEGAL_VALUE, addr);
+    return;
+  }
+
   tBTM_BLE_PERIODIC_SYNC_TRANSFER* p_sync_transfer =
       &btm_ble_pa_sync_cb.sync_transfer[index];
   p_sync_transfer->in_use = true;
@@ -1367,6 +1387,12 @@
   }
 
   int index = btm_ble_get_free_sync_transfer_index();
+  if (index == MAX_SYNC_TRANSACTION) {
+    BTM_TRACE_ERROR("Failed to get sync transfer index");
+    cb.Run(BTM_ILLEGAL_VALUE, addr);
+    return;
+  }
+
   tBTM_BLE_PERIODIC_SYNC_TRANSFER* p_sync_transfer =
       &btm_ble_pa_sync_cb.sync_transfer[index];
   p_sync_transfer->in_use = true;
diff --git a/system/stack/btm/btm_sec.cc b/system/stack/btm/btm_sec.cc
index 4a83cde..c77c405 100644
--- a/system/stack/btm/btm_sec.cc
+++ b/system/stack/btm/btm_sec.cc
@@ -209,6 +209,25 @@
 
 /*******************************************************************************
  *
+ * Function         access_secure_service_from_temp_bond
+ *
+ * Description      a utility function to test whether an access to
+ *                  secure service from temp bonding is happening
+ *
+ * Returns          true if the aforementioned condition holds,
+ *                  false otherwise
+ *
+ ******************************************************************************/
+static bool access_secure_service_from_temp_bond(const tBTM_SEC_DEV_REC* p_dev_rec,
+                                                 bool locally_initiated,
+                                                 uint16_t security_req) {
+  return !locally_initiated && (security_req & BTM_SEC_IN_AUTHENTICATE) &&
+    p_dev_rec->is_device_authenticated() &&
+    p_dev_rec->is_bond_type_temporary();
+}
+
+/*******************************************************************************
+ *
  * Function         BTM_SecRegister
  *
  * Description      Application manager calls this function to register for
@@ -1609,9 +1628,14 @@
       }
 
       if (rc == BTM_SUCCESS) {
+        if (access_secure_service_from_temp_bond(p_dev_rec, is_originator, security_required)) {
+          LOG_ERROR("Trying to access a secure service from a temp bonding, rejecting");
+          rc = BTM_FAILED_ON_SECURITY;
+        }
+
         if (p_callback)
-          (*p_callback)(&bd_addr, transport, (void*)p_ref_data, BTM_SUCCESS);
-        return (BTM_SUCCESS);
+          (*p_callback)(&bd_addr, transport, (void*)p_ref_data, rc);
+        return (rc);
       }
     }
 
@@ -1627,15 +1651,15 @@
       btm_cb.security_mode == BTM_SEC_MODE_SC) {
     if (BTM_SEC_IS_SM4(p_dev_rec->sm4)) {
       if (is_originator) {
-        /* SM4 to SM4 -> always authenticate & encrypt */
-        security_required |= (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT);
+        /* SM4 to SM4 -> always encrypt */
+        security_required |= BTM_SEC_OUT_ENCRYPT;
       } else /* acceptor */
       {
         /* SM4 to SM4: the acceptor needs to make sure the authentication is
          * already done */
         chk_acp_auth_done = true;
-        /* SM4 to SM4 -> always authenticate & encrypt */
-        security_required |= (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT);
+        /* SM4 to SM4 -> always encrypt */
+        security_required |= BTM_SEC_IN_ENCRYPT;
       }
     } else if (!(BTM_SM4_KNOWN & p_dev_rec->sm4)) {
       /* the remote features are not known yet */
@@ -1874,6 +1898,11 @@
                                security_required, p_callback, p_ref_data);
     } else /* rc == BTM_SUCCESS */
     {
+      if (access_secure_service_from_temp_bond(p_dev_rec,
+          is_originator, security_required)) {
+        LOG_ERROR("Trying to access a secure rfcomm service from a temp bonding, reject");
+        rc = BTM_FAILED_ON_SECURITY;
+      }
       if (p_callback) {
         LOG_DEBUG("Notifying client that security access has been granted");
         (*p_callback)(&bd_addr, transport, p_ref_data, rc);
@@ -4361,48 +4390,67 @@
 
   /* If connection is not authenticated and authentication is required */
   /* start authentication and return PENDING to the caller */
-  if ((((!(p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED)) &&
-        ((p_dev_rec->IsLocallyInitiated() &&
-          (p_dev_rec->security_required & BTM_SEC_OUT_AUTHENTICATE)) ||
-         (!p_dev_rec->IsLocallyInitiated() &&
-          (p_dev_rec->security_required & BTM_SEC_IN_AUTHENTICATE)))) ||
-       (!(p_dev_rec->sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED) &&
-        (!p_dev_rec->IsLocallyInitiated() &&
-         (p_dev_rec->security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN)))) &&
-      (p_dev_rec->hci_handle != HCI_INVALID_HANDLE)) {
-    /*
-     * We rely on BTM_SEC_16_DIGIT_PIN_AUTHED being set if MITM is in use,
-     * as 16 DIGIT is only needed if MITM is not used. Unfortunately, the
-     * BTM_SEC_AUTHENTICATED is used for both MITM and non-MITM
-     * authenticated connections, hence we cannot distinguish here.
-     */
+  if (p_dev_rec->hci_handle != HCI_INVALID_HANDLE) {
+    bool start_auth = false;
 
-    LOG_DEBUG("Security Manager: Start authentication");
-
-    /*
-     * If we do have a link-key, but we end up here because we need an
-     * upgrade, then clear the link-key known and authenticated flag before
-     * restarting authentication.
-     * WARNING: If the controller has link-key, it is optional and
-     * recommended for the controller to send a Link_Key_Request.
-     * In case we need an upgrade, the only alternative would be to delete
-     * the existing link-key. That could lead to very bad user experience
-     * or even IOP issues, if a reconnect causes a new connection that
-     * requires an upgrade.
-     */
-    if ((p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) &&
-        (!(p_dev_rec->sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED) &&
-         (!p_dev_rec->IsLocallyInitiated() &&
-          (p_dev_rec->security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN)))) {
-      p_dev_rec->sec_flags &=
-          ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED |
-            BTM_SEC_AUTHENTICATED);
+    // Check link status of BR/EDR
+    if (!(p_dev_rec->sec_flags & BTM_SEC_AUTHENTICATED)) {
+      if (p_dev_rec->IsLocallyInitiated()) {
+        if (p_dev_rec->security_required &
+            (BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_OUT_ENCRYPT)) {
+          LOG_DEBUG("Outgoing authentication/encryption Required");
+          start_auth = true;
+        }
+      } else {
+        if (p_dev_rec->security_required &
+            (BTM_SEC_IN_AUTHENTICATE | BTM_SEC_IN_ENCRYPT)) {
+          LOG_DEBUG("Incoming authentication/encryption Required");
+          start_auth = true;
+        }
+      }
     }
 
-    btm_sec_wait_and_start_authentication(p_dev_rec);
-    return (BTM_CMD_STARTED);
-  } else {
-    LOG_DEBUG("Authentication not required");
+    if (!(p_dev_rec->sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED)) {
+      /*
+       * We rely on BTM_SEC_16_DIGIT_PIN_AUTHED being set if MITM is in use,
+       * as 16 DIGIT is only needed if MITM is not used. Unfortunately, the
+       * BTM_SEC_AUTHENTICATED is used for both MITM and non-MITM
+       * authenticated connections, hence we cannot distinguish here.
+       */
+      if (!p_dev_rec->IsLocallyInitiated()) {
+        if (p_dev_rec->security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN) {
+          LOG_DEBUG("BTM_SEC_IN_MIN_16_DIGIT_PIN Required");
+          start_auth = true;
+        }
+      }
+    }
+
+    if (start_auth) {
+      LOG_DEBUG("Security Manager: Start authentication");
+
+      /*
+       * If we do have a link-key, but we end up here because we need an
+       * upgrade, then clear the link-key known and authenticated flag before
+       * restarting authentication.
+       * WARNING: If the controller has link-key, it is optional and
+       * recommended for the controller to send a Link_Key_Request.
+       * In case we need an upgrade, the only alternative would be to delete
+       * the existing link-key. That could lead to very bad user experience
+       * or even IOP issues, if a reconnect causes a new connection that
+       * requires an upgrade.
+       */
+      if ((p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_KNOWN) &&
+          (!(p_dev_rec->sec_flags & BTM_SEC_16_DIGIT_PIN_AUTHED) &&
+          (!p_dev_rec->IsLocallyInitiated() &&
+            (p_dev_rec->security_required & BTM_SEC_IN_MIN_16_DIGIT_PIN)))) {
+        p_dev_rec->sec_flags &=
+            ~(BTM_SEC_LINK_KEY_KNOWN | BTM_SEC_LINK_KEY_AUTHED |
+              BTM_SEC_AUTHENTICATED);
+      }
+
+      btm_sec_wait_and_start_authentication(p_dev_rec);
+      return (BTM_CMD_STARTED);
+    }
   }
 
   /* If connection is not encrypted and encryption is required */
@@ -4430,6 +4478,13 @@
     return (BTM_FAILED_ON_SECURITY);
   }
 
+  if (access_secure_service_from_temp_bond(p_dev_rec,
+                                           p_dev_rec->IsLocallyInitiated(),
+                                           p_dev_rec->security_required)) {
+    LOG_ERROR("Trying to access a secure service from a temp bonding, rejecting");
+    return (BTM_FAILED_ON_SECURITY);
+  }
+
   /* All required  security procedures already established */
   p_dev_rec->security_required &=
       ~(BTM_SEC_OUT_AUTHENTICATE | BTM_SEC_IN_AUTHENTICATE |