Remote device changes for SMP certification

Use Case:
Certification test cases for SMP require various scenarios
where the remote device needs to show a specific behavior
where it fails the pairing in a certain way, and the DUT is
required to abort the pairing properly.
In abcense of a proper PTS suite to execute these test cases,
we can use another device running the same host by configuring
certain run time property.

Test Cases:
TP/SCJW/BI-02-C
TP/SCJW/BV-02-C
TP/SCPK/BI-03-C
TP/SCPK/BI-04-C
TP/SCPK/BV-02-C
TP/SCPK/BV-03-C
TP/SCJW/BI-01-C
TP/SCCT/BV-01-C
TP/SCCT/BV-02-C
TP/SCPK/BI-01-C
TP/SCPK/BI-02-C
TP/SCPK/BV-04-C
TP/SCPK/BV-01-C

Fix:
Added a property in the bt_stack.conf file. The property name
is "SmpFailureCase". The values 2 to 6(inclusive), are forcausing SMP
failures with various failure reasons.
Failure case 1 and 9 are for producing error "Confirm value failure".
Cases 7 and 8 are for generating specific errors at pair cancel.

Note:
The default use of this feature is controlled using a compile
time flag BTM_BLE_SMP_CERTIFICATION.
The BTM_BLE_SMP_CERTIFICATION = TRUE is needed only while we
wait for the PTS support for the LE Secure connections.

Bug: 27852645
Change-Id: I1f7a8ff2659d85b5978b75870c57162a34d394d0
diff --git a/system/btif/src/btif_dm.cc b/system/btif/src/btif_dm.cc
index 81cf1ac..7b6e385 100644
--- a/system/btif/src/btif_dm.cc
+++ b/system/btif/src/btif_dm.cc
@@ -2915,7 +2915,7 @@
 **                  add a node with label "SmpOptions" to the config file
 **                  and assign it a comma separated list of 5 values in the
 **                  format: auth, io, ikey, rkey, ksize, oob
-**                  eg: SmpOptions=0xD,0x4,0xf,0xf,0x10
+**                  eg: PTS_SmpOptions=0xD,0x4,0xf,0xf,0x10
 **
 ** Parameters:      tBTE_APPL_CFG*: pointer to struct defining pairing options
 **
@@ -2924,13 +2924,13 @@
 *******************************************************************************/
 BOOLEAN btif_dm_get_smp_config(tBTE_APPL_CFG* p_cfg) {
 
-    if(!stack_config_get_interface()->get_smp_options()) {
+    if(!stack_config_get_interface()->get_pts_smp_options()) {
         BTIF_TRACE_DEBUG ("%s: SMP options not found in configuration", __func__);
         return FALSE;
     }
 
     char conf[64];
-    const char* recv = stack_config_get_interface()->get_smp_options();
+    const char* recv = stack_config_get_interface()->get_pts_smp_options();
     char* pch;
     char* endptr;
 
diff --git a/system/conf/bt_stack.conf b/system/conf/bt_stack.conf
index c7bbb5a..3a7f48b 100644
--- a/system/conf/bt_stack.conf
+++ b/system/conf/bt_stack.conf
@@ -40,7 +40,7 @@
 TRC_BNEP=2
 TRC_PAN=2
 
-# PTS testing helps
+# PTS testing helpers
 
 # Secure connections only mode.
 # PTS_SecurePairOnly=true
@@ -53,3 +53,19 @@
 
 # SMP Pair options (formatted as hex bytes) auth, io, ikey, rkey, ksize
 #PTS_SmpOptions=0xD,0x4,0xf,0xf,0x10
+
+# SMP Certification Failure Cases
+# Fail case number range from 1 to 9 will set up remote device for test
+# case execution. Setting PTS_SmpFailureCase to 0 means normal operation.
+# Failure modes:
+#  1 = SMP_CONFIRM_VALUE_ERR
+#  2 = SMP_PAIR_AUTH_FAIL
+#  3 = SMP_PAIR_FAIL_UNKNOWN
+#  4 = SMP_PAIR_NOT_SUPPORT
+#  5 = SMP_PASSKEY_ENTRY_FAIL
+#  6 = SMP_REPEATED_ATTEMPTS
+#  7 = PIN generation failure?
+#  8 = SMP_PASSKEY_ENTRY_FAIL
+#  9 = SMP_NUMERIC_COMPAR_FAIL;
+#PTS_SmpFailureCase=0
+
diff --git a/system/include/stack_config.h b/system/include/stack_config.h
index eb52071..b5278ce 100644
--- a/system/include/stack_config.h
+++ b/system/include/stack_config.h
@@ -37,7 +37,8 @@
   bool (*get_pts_secure_only_mode)(void);
   bool (*get_pts_conn_updates_disabled)(void);
   bool (*get_pts_crosskey_sdp_disable)(void);
-  const char* (*get_smp_options)(void);
+  const char* (*get_pts_smp_options)(void);
+  int (*get_pts_smp_failure_case)(void);
   config_t *(*get_all)(void);
 } stack_config_t;
 
diff --git a/system/main/stack_config.c b/system/main/stack_config.c
index 09904e3..3f8b8af 100644
--- a/system/main/stack_config.c
+++ b/system/main/stack_config.c
@@ -33,6 +33,7 @@
 const char *PTS_LE_CONN_UPDATED_DISABLED = "PTS_DisableConnUpdates";
 const char *PTS_DISABLE_SDP_LE_PAIR = "PTS_DisableSDPOnLEPair";
 const char *PTS_SMP_PAIRING_OPTIONS_KEY = "PTS_SmpOptions";
+const char *PTS_SMP_FAILURE_CASE_KEY = "PTS_SmpFailureCase";
 
 static config_t *config;
 
@@ -108,6 +109,10 @@
   return config_get_string(config, CONFIG_DEFAULT_SECTION, PTS_SMP_PAIRING_OPTIONS_KEY, NULL);
 }
 
+static int get_pts_smp_failure_case(void) {
+  return config_get_int(config, CONFIG_DEFAULT_SECTION, PTS_SMP_FAILURE_CASE_KEY, 0);
+}
+
 static config_t *get_all(void) {
   return config;
 }
@@ -121,6 +126,7 @@
   get_pts_conn_updates_disabled,
   get_pts_crosskey_sdp_disable,
   get_pts_smp_options,
+  get_pts_smp_failure_case,
   get_all
 };
 
diff --git a/system/stack/smp/smp_act.c b/system/stack/smp/smp_act.c
index c8fe9b2..1e3effe 100644
--- a/system/stack/smp/smp_act.c
+++ b/system/stack/smp/smp_act.c
@@ -63,6 +63,42 @@
     return acl->lmp_version < version;
 }
 
+static bool pts_test_send_authentication_complete_failure(tSMP_CB *p_cb)
+{
+    uint8_t reason = 0;
+
+    if (p_cb->cert_failure < 2 || p_cb->cert_failure > 6)
+        return false;
+
+    SMP_TRACE_ERROR("%s failure case = %d", __func__, p_cb->cert_failure);
+
+    switch (p_cb->cert_failure)
+    {
+        case 2:
+            reason = SMP_PAIR_AUTH_FAIL;
+            smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+            break;
+        case 3:
+            reason = SMP_PAIR_FAIL_UNKNOWN;
+            smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+            break;
+        case 4:
+            reason = SMP_PAIR_NOT_SUPPORT;
+            smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+            break;
+        case 5:
+            reason = SMP_PASSKEY_ENTRY_FAIL;
+            smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+            break;
+        case 6:
+            reason = SMP_REPEATED_ATTEMPTS;
+            smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+            break;
+    }
+
+    return true;;
+}
+
 /*******************************************************************************
 ** Function         smp_update_key_mask
 ** Description      This function updates the key mask for sending or receiving.
@@ -550,6 +586,10 @@
         return;
     }
 
+    // PTS Testing failure modes
+    if (pts_test_send_authentication_complete_failure(p_cb))
+        return;
+
     if (p_cb->role == HCI_ROLE_SLAVE)
     {
         if (!(p_cb->flags & SMP_PAIR_FLAGS_WE_STARTED_DD))
@@ -1403,6 +1443,11 @@
         {
             if (smp_request_oob_data(p_cb)) return;
         }
+
+        // PTS Testing failure modes
+        if (pts_test_send_authentication_complete_failure(p_cb))
+            return;
+
         smp_send_pair_rsp(p_cb, NULL);
     }
 }
@@ -1638,6 +1683,14 @@
 
     SMP_TRACE_DEBUG("%s start ", __func__);
 
+    // PTS Testing failure modes
+    if (p_cb->cert_failure == 1) {
+        SMP_TRACE_ERROR("%s failure case = %d", __func__, p_cb->cert_failure);
+        reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR;
+        smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
+        return;
+    }
+
     switch(p_cb->selected_association_model)
     {
         case SMP_MODEL_SEC_CONN_JUSTWORKS:
@@ -1671,7 +1724,7 @@
             break;
         case SMP_MODEL_SEC_CONN_PASSKEY_ENT:
         case SMP_MODEL_SEC_CONN_PASSKEY_DISP:
-            if (!smp_check_commitment(p_cb))
+            if (!smp_check_commitment(p_cb) && p_cb->cert_failure != 9)
             {
                 reason = p_cb->failure = SMP_CONFIRM_VALUE_ERR;
                 smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
diff --git a/system/stack/smp/smp_api.c b/system/stack/smp/smp_api.c
index 03f7518..b3373b5 100644
--- a/system/stack/smp/smp_api.c
+++ b/system/stack/smp/smp_api.c
@@ -26,6 +26,8 @@
 
 #include "bt_target.h"
 #include "bt_utils.h"
+#include "stack_config.h"
+
 #if SMP_INCLUDED == TRUE
     #include "smp_int.h"
     #include "smp_api.h"
@@ -61,6 +63,11 @@
     smp_l2cap_if_init();
     /* initialization of P-256 parameters */
     p_256_init_curve(KEY_LENGTH_DWORDS_P256);
+
+    /* Initialize failure case for certification */
+    smp_cb.cert_failure = stack_config_get_interface()->get_pts_smp_failure_case();
+    if (smp_cb.cert_failure)
+        SMP_TRACE_ERROR ("%s PTS FAILURE MODE IN EFFECT (CASE %d)", __func__, smp_cb.cert_failure);
 }
 
 
@@ -219,6 +226,12 @@
     UINT8     err_code = SMP_PAIR_FAIL_UNKNOWN;
     BOOLEAN   status = FALSE;
 
+    // PTS SMP failure test cases
+    if (p_cb->cert_failure == 7)
+        err_code = SMP_PASSKEY_ENTRY_FAIL;
+    else if (p_cb->cert_failure == 8)
+        err_code = SMP_NUMERIC_COMPAR_FAIL;
+
     BTM_TRACE_EVENT ("SMP_CancelPair state=%d flag=0x%x ", p_cb->state, p_cb->flags);
     if ( (p_cb->state != SMP_STATE_IDLE)  &&
          (!memcmp (p_cb->pairing_bda, bd_addr, BD_ADDR_LEN)) )
diff --git a/system/stack/smp/smp_int.h b/system/stack/smp/smp_int.h
index 8f272da..54f2371 100644
--- a/system/stack/smp/smp_int.h
+++ b/system/stack/smp/smp_int.h
@@ -343,7 +343,8 @@
     UINT8           rcvd_cmd_len;
     UINT16          total_tx_unacked;
     BOOLEAN         wait_for_authorization_complete;
-}tSMP_CB;
+    UINT8           cert_failure; /*failure case for certification */
+} tSMP_CB;
 
 /* Server Action functions are of this type */
 typedef void (*tSMP_ACT)(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);