[Feature]Upload Modem source code

Change-Id: Id4294f30faced84d3e6fd6d5e61e1111bf287a37
diff --git a/mcu/custom/protocol/common/ps/custom_sml.c b/mcu/custom/protocol/common/ps/custom_sml.c
new file mode 100644
index 0000000..95421e5
--- /dev/null
+++ b/mcu/custom/protocol/common/ps/custom_sml.c
@@ -0,0 +1,2789 @@
+/*****************************************************************************
+ *
+ * Filename:
+ * ---------
+ * custom_sml.c
+ *
+ * Project:
+ * --------
+ *  UMOLYA
+ *
+ * Description:
+ * ------------
+ *  This file is for SIM ME Lock customization
+ *
+ * Author:
+ * -------
+ * -------
+ ****************************************************************************/
+#if !defined(__MAUI_BASIC__)
+
+#include <string.h>
+
+#include "kal_general_types.h"
+#include "kal_public_api.h"
+#include "global_def.h"
+
+#include "custom_sml.h"
+#include "custom_sml_trc.h"
+#include "custom_nvram_extra.h"
+
+#include "ps_public_enum.h"
+#include "sim_ps_enum.h"
+#include "smu_common_enums.h"
+
+#include "mcd_l3_inc_struct.h"
+
+#include "nvram_interface.h"
+#include "cust_chl_interface.h"
+#include "custom_sml_sec_verify.h"
+
+#include "l4c_utility.h"
+#include "ps_public_utility.h"
+
+
+extern void smu_nvram_write(nvram_lid_enum file_idx, kal_uint8 access_id, kal_bool is_write_protect2);
+
+
+
+#ifndef L4_NOT_PRESENT
+/****************************************************************************
+ *
+ *  SIM ME Lock
+ *
+ ****************************************************************************/
+
+#ifdef __CUST_SML_RULE__
+const kal_uint8 sml_gblob_max_cust_rule[SML_LOCK_CUST_CODE_SIZE + 1] = SML_GBLOB_MAX_CUST_RULE_LIST;
+#endif
+
+/*******************************************************************************
+ * FUNCTION
+ *  sml_mini_trace
+ * DESCRIPTION
+ *  trace for short strings
+ * PARAMETERS
+ *  title       [const kal_char]
+ *  data        [kal_uint8]
+ *  len         [kal_uint8]
+ * RETURN
+ *  void
+*******************************************************************************/
+void sml_mini_trace(const kal_char *title, kal_uint8 *data, kal_uint8 len)
+{    
+    kal_uint8 *buf = NULL;
+    kal_uint8 buf_len = (len < 128 ? len : 128);
+
+    buf = get_ctrl_buffer(128 + 1);
+    kal_mem_set(buf, 0, 128 + 1);
+
+    kal_mem_cpy(buf, data, buf_len);
+    kal_prompt_trace(kal_get_active_module_id(), "%s: ", title);
+    kal_prompt_trace(kal_get_active_module_id(), "%s", (const kal_char *)buf);
+}
+
+/*******************************************************************************
+ * FUNCTION  
+ *  custom_sml_query_key_input_type
+ * DESCRIPTION
+ *  This function is to query under particular protection algorithm and operation pair,
+ *    whether our key input is plaintext key (e.g. '123456') or hashed key (e.g. {0xAA, 0xBB, ...})
+ * PARAMETERS
+ *  algo    key protection algorithm
+ *  op      operation for querying key input type
+ * RETURN
+ *  SML_VERIFY_WITH_PLAINKEY: Input is plaintext key, may need to derive its hashed value for verification
+ *  SML_VERIFY_WITH_HCK: Input is hashed key, directly compare its stored hashed value for verification
+ * GLOBALS AFFECTED
+ *  N/A
+*******************************************************************************/
+sml_key_input_type_enum custom_sml_query_key_input_type(sml_key_algo_enum algo, sml_op_enum op)
+{
+    sml_key_input_type_enum input_type = SML_INPUT_WITH_PLAINKEY;
+
+    if (algo == SML_KEY_ALGO_BCD)     /* algo == 0 */
+    {
+        input_type = SML_INPUT_WITH_PLAINKEY;
+    }
+
+    else if (algo == SML_KEY_ALGO_PBKDF2_HMAC_SHA256_SALT128)      /* algo == 1 */
+    {
+        switch (op)
+        {
+            case SML_OP_VERIFY:
+            case SML_OP_CHANGE_PWD:
+                input_type = SML_INPUT_WITH_PLAINKEY;
+                break;
+
+            case SML_OP_UNLOCK:
+            case SML_OP_LOCK:
+            case SML_OP_ADD:
+            case SML_OP_REMOVE:
+            case SML_OP_DISABLE:
+            case SML_OP_UPDATE_AUTOLOCK_COUNT:
+                input_type = SML_INPUT_WITH_HCK;
+                break;
+
+            default:
+                break;
+        }
+    }
+
+    return input_type;
+}
+
+#ifdef __SML_PUK__
+/*******************************************************************************
+ * FUNCTION  
+ *  custom_sml_query_puk_key_input_type
+ * DESCRIPTION
+ *  This function is to query under particular protection algorithm and operation pair,
+ *    whether our key input is plaintext key (e.g. '123456') or hashed key (e.g. {0xAA, 0xBB, ...})
+ * PARAMETERS
+ *  algo    key protection algorithm
+ *  op      operation for querying key input type
+ * RETURN
+ *  SML_VERIFY_WITH_PLAINKEY: Input is plaintext key, may need to derive its hashed value for verification
+ *  SML_VERIFY_WITH_HCK: Input is hashed key, directly compare its stored hashed value for verification
+ * GLOBALS AFFECTED
+ *  N/A
+*******************************************************************************/
+sml_key_input_type_enum custom_sml_query_puk_key_input_type(sml_key_algo_enum algo, sml_puk_key_op_enum op)
+{
+    sml_key_input_type_enum input_type = SML_INPUT_WITH_PLAINKEY;
+
+    if (algo == SML_KEY_ALGO_BCD)     /* algo == 0 */
+    {
+        input_type = SML_INPUT_WITH_PLAINKEY;   // Only PLAINTEXT allowed
+    }
+
+    else if (algo == SML_KEY_ALGO_PBKDF2_HMAC_SHA256_SALT128)      /* algo == 1 */
+    {
+        switch (op)
+        {
+            case SML_PUK_OP_VERIFY:
+                input_type = SML_INPUT_WITH_PLAINKEY;
+                break;
+
+            case SML_PUK_OP_UPDATE:
+                input_type = SML_INPUT_WITH_HCK;
+                break;
+
+            default:
+                break;
+        }
+    }
+
+    return input_type;
+}
+#endif /* __SML_PUK__ */
+
+
+/****************************************************************************
+ *
+ *  Verizon SIM Lock
+ *
+ ****************************************************************************/
+
+/* define the Local variable of VZW SML object */
+static sml_vzw_sim_lock_context_struct sml_vzw_cntxt_obj[MAX_SIM_NUM];
+static nvram_ef_sml_vzw_sim_lock_obj_struct SMLVZWOBJ[MAX_SIM_NUM];
+
+/* define the Global access pointer of VZW SML object */
+nvram_ef_sml_vzw_sim_lock_obj_struct * pSMLVZWg = &SMLVZWOBJ[0];
+
+
+/*******************************************************************************
+ * FUNCTION  
+ *  sml_clean_vzw_cntxt
+ * DESCRIPTION
+ *  Clean sensitive data in MD Dump.
+ * PARAMETERS
+ *  N/A
+ * RETURN
+ *  N/A
+ * GLOBALS AFFECTED
+ *  sml_vzw_cntxt_obj
+*******************************************************************************/
+void sml_clean_vzw_cntxt(void)
+{
+    kal_mem_set(sml_vzw_cntxt_obj, 0x00, sizeof(sml_vzw_cntxt_obj));
+}
+
+/*******************************************************************************
+ * FUNCTION  
+ *  custom_sml_vzw_is_test_purpose
+ * DESCRIPTION
+ *  This function is to query if VzW testing functions are enabled
+ * PARAMETERS
+ *  N/A
+ * RETURN
+ *  KAL_TRUE: For test purpose, testing function enabled
+ *  KAL_FALSE: Normal purpose
+ * GLOBALS AFFECTED
+ *  N/A
+*******************************************************************************/
+kal_bool custom_sml_vzw_is_test_purpose(void)
+{
+#ifdef __VZW_RSU_TEST__
+    return KAL_TRUE;
+#else
+    return KAL_FALSE;
+#endif
+}
+
+
+/*******************************************************************************
+ * FUNCTION  
+ *  sml_vzw_give
+ * DESCRIPTION
+ *  This method copys the LID files read from NVRAM to the SML obj
+ * PARAMETERS
+ *  IN          * pLidToObj
+ * RETURN
+ *  void
+ * GLOBALS AFFECTED
+ *  SMLOBJ
+*******************************************************************************/
+void sml_vzw_give(void *pLidToObj, kal_uint8 source)
+{
+    sml_vzw_sim_lock_context_struct * pObj = NULL;
+  
+    if(NULL != pSMLVZWg[source].pObj)
+    {
+        pSMLVZWg[source].pObj = NULL;   
+    }
+       
+    pObj = &(sml_vzw_cntxt_obj[source]);
+    
+    kal_mem_cpy(pObj,
+                pLidToObj,
+                sizeof(sml_vzw_sim_lock_context_struct)
+                ); 
+   
+    pSMLVZWg[source].pObj = pObj;
+}
+
+/*******************************************************************************
+ * FUNCTION  
+ *  sml_vzw_take
+ * DESCRIPTION
+ *  This method copys the contex of the SML object to the provided NVRAM LID.
+ * PARAMETERS
+ *  OUT         * pObjToLid
+ * RETURN
+ *  void
+ * GLOBALS AFFECTED
+ *  SMLOBJ
+ *******************************************************************************/
+void sml_vzw_take( void *pObjToLid, kal_uint8 source )
+{
+    sml_vzw_sim_lock_context_struct * pObj = (sml_vzw_sim_lock_context_struct *) pSMLVZWg[source].pObj;
+
+    kal_mem_cpy(pObjToLid,
+                pObj,
+                sizeof(sml_vzw_sim_lock_context_struct)
+                );
+}
+
+/*******************************************************************************
+ * FUNCTION  
+ *  sml_vzw_destory
+ * DESCRIPTION
+ *  This method free the SML object in memory if it is not used.
+ * PARAMETERS
+ *  void
+ * RETURN
+ *  void
+ * GLOBALS AFFECTED
+ *  SMLOBJ
+ *******************************************************************************/    
+void sml_vzw_destory(kal_uint8 source)
+{
+    pSMLVZWg[source].pObj = NULL;
+}
+
+/*******************************************************************************
+ * FUNCTION  
+ *  sml_vzw_Load
+ * DESCRIPTION
+ *  This function loads the SML obj from NVRAM LID (NVRAM_READ_CNF)
+ * PARAMETERS
+ *  IN          pLid
+ * RETURN
+ *  kal_uint16  Obj size
+ * GLOBALS AFFECTED
+ *  SMLOBJ
+ *******************************************************************************/ 
+kal_uint16 sml_vzw_Load( void *pLid, kal_uint8 source )
+{
+    nvram_ef_sml_vzw_sim_lock_obj_struct *p = &pSMLVZWg[source];
+
+    kal_uint16 length = sizeof(sml_vzw_sim_lock_context_struct);
+
+    /* Clean the old ones */
+    (*p->destory)(source);
+
+    /* Load the new one */
+    (*p->give)(pLid, source);
+
+    return length;
+}
+
+/*******************************************************************************
+ * FUNCTION  
+ *  sml_vzw_Save
+ * DESCRIPTION
+ *  This function saves the SML obj to NVRAM LID (NVRAM_WRITE_REQ)
+ * PARAMETERS
+ *  OUT          pLid
+ * RETURN
+ *  kal_uint16  Obj size
+ * GLOBALS AFFECTED
+ *  SMLOBJ
+ *******************************************************************************/ 
+kal_uint16 sml_vzw_Save( void *pLid, kal_uint8 source )
+{
+    nvram_ef_sml_vzw_sim_lock_obj_struct *p = &pSMLVZWg[source];
+
+    kal_uint16 length = sizeof(sml_vzw_sim_lock_context_struct);
+
+    kal_uint8 lock_state = SML_VZW_LOCK_STATE_LOCK;
+
+    kal_bool ret_val = KAL_FALSE;
+
+    kal_bool temp_unlock_restore_required = KAL_FALSE;
+
+    /* Check if NW lock op is set to Temp unlock in SML VzW OBJ. If yes, then change it to Lock before performing 'take' operation.
+           Then restore back to Temp unlock after 'take' operation */
+
+    ret_val = sml_vzw_get_int_data(source, SML_VZW_CAT_NONE, SML_VZW_RSU_NETWORK_LOCK_OPERATION, &lock_state);
+
+    if (KAL_FALSE == ret_val)
+    {
+        DEBUG_ASSERT(0);
+    }
+    else
+    {
+        if (lock_state == SML_VZW_LOCK_STATE_TEMP_UNLOCK)
+        {
+            ret_val = sml_vzw_update_int_data(source, SML_VZW_CAT_NONE, SML_VZW_RSU_NETWORK_LOCK_OPERATION, SML_VZW_LOCK_STATE_LOCK);
+            if (ret_val == KAL_TRUE)
+            {
+                temp_unlock_restore_required = KAL_TRUE;
+            }
+        }
+    }
+
+    (*p->take)(pLid, source);
+
+    if (KAL_TRUE == temp_unlock_restore_required)
+    {
+        sml_vzw_update_int_data(source, SML_VZW_CAT_NONE, SML_VZW_RSU_NETWORK_LOCK_OPERATION, SML_VZW_LOCK_STATE_TEMP_UNLOCK);
+    }
+
+    return length;  
+}
+
+/*******************************************************************************
+ * FUNCTION  
+ *  sml_vzw_getItem
+ * DESCRIPTION
+ *  This method returns the structure pointer and length of the structure
+ *  of the desired SML object items.
+ * PARAMETERS
+ *  IN          cat
+ *  IN          item
+ *  OUT         *length
+ * RETURN
+ *  void *
+ * GLOBALS AFFECTED
+ *  SMLOBJ
+ *******************************************************************************/
+void * sml_vzw_getItem(sml_vzw_cat_enum category, 
+                              sml_ctx_enum item, 
+                              kal_uint16 *plength,
+                              kal_uint8 source)
+{
+    sml_vzw_sim_lock_context_struct *pObj = (sml_vzw_sim_lock_context_struct *) pSMLVZWg[source].pObj;
+
+    ASSERT(NULL != pObj);
+
+    switch(item)
+    {
+        case SML_VZW_RSU_MAJOR_VERSION:
+            *plength = sizeof(kal_uint8);
+            return (kal_uint8 *) &(pObj->major_version);
+
+        case SML_VZW_RSU_MINOR_VERSION:
+            *plength = sizeof(kal_uint8);
+            return (kal_uint8 *) &(pObj->minor_version);
+
+        case SML_VZW_RSU_PROTECTION_ALGORITHM:
+            *plength = sizeof(kal_uint8);
+            return (kal_uint8 *) &(pObj->protection_algo);
+
+        case SML_VZW_RSU_NETWORK_LOCK_OPERATION:
+            *plength = sizeof(kal_uint8);
+            return (kal_uint8 *) &(pObj->nw_lock_op);
+
+        case SML_VZW_RSU_TIME_STAMP:
+            *plength = SML_VZW_RSU_TIME_STAMP_LEN;
+            return (kal_uint8 *) &(pObj->timestamp[0]);
+
+        case SML_VZW_RSU_SESSION_ID:
+            *plength = SML_VZW_RSU_SESSION_ID_LEN;
+            return (kal_uint8 *) &(pObj->session_id[0]);
+
+        case SML_VZW_RSU_CAT_CODE:
+            switch(category)
+            {
+                case SML_VZW_CAT_N:
+                    *plength = SML_VZW_RSU_NW_LIST_LEN;
+                    return (kal_uint8 *) &(pObj->nw_list[0]);
+                    break;
+
+                case SML_VZW_CAT_NS:
+                    *plength = SML_VZW_RSU_NS_LIST_LEN;
+                    return (kal_uint8 *) &(pObj->ns_list[0]);
+                    break;
+
+                case SML_VZW_CAT_SP:
+                    *plength = SML_VZW_RSU_SP_LIST_LEN;
+                    return (kal_uint8 *) &(pObj->sp_list[0]);
+                    break;
+
+                case SML_VZW_CAT_EHPLMN:
+                    *plength = SML_VZW_RSU_EHPLMN_LIST_LEN;
+                    return (kal_uint8 *) &(pObj->ehplmn_list[0]);
+                    break;
+
+                default:
+                    /* do nothing */
+                    break;
+            }
+            break;
+
+        case SML_VZW_RSU_CAT_NUM:
+            switch(category)
+            {
+                case SML_VZW_CAT_N:
+                    *plength = sizeof(kal_uint8);
+                    return (kal_uint8 *) &(pObj->nw_num);
+                    break;
+        
+                case SML_VZW_CAT_NS:
+                    *plength = sizeof(kal_uint8);
+                    return (kal_uint8 *) &(pObj->ns_num);
+                    break;
+        
+                case SML_VZW_CAT_SP:
+                    *plength = sizeof(kal_uint8);
+                    return (kal_uint8 *) &(pObj->sp_num);
+                    break;
+        
+                case SML_VZW_CAT_EHPLMN:
+                    *plength = sizeof(kal_uint8);
+                    return (kal_uint8 *) &(pObj->ehplmn_num);
+                    break;
+        
+                default:
+                    /* do nothing */
+                    break;
+            }
+            break;
+
+        default:
+            break;
+    }
+
+    return NULL;
+}
+
+/*******************************************************************************
+ * FUNCTION  
+ *  sml_vzw_putItem
+ * DESCRIPTION
+ *  This method set the desired items of the SML object.
+ * PARAMETERS
+ *  IN          cat
+ *  IN          item
+ *  IN          *pItem
+ *  IN          *plength
+ * RETURN
+ *  void
+ * GLOBALS AFFECTED
+ *  SMLOBJ
+ *******************************************************************************/ 
+void sml_vzw_putItem(sml_vzw_cat_enum cat,
+                     sml_ctx_enum item, 
+                     void *pItem, 
+                     kal_uint16 *plength,
+                     kal_uint8 source)
+{
+    sml_vzw_sim_lock_context_struct *pObj = (sml_vzw_sim_lock_context_struct *) pSMLVZWg[source].pObj;
+
+    switch (item)
+    {
+        case SML_VZW_RSU_MAJOR_VERSION:
+            kal_mem_cpy(&(pObj->major_version), pItem, *plength);
+            break;
+
+        case SML_VZW_RSU_MINOR_VERSION:
+            kal_mem_cpy(&(pObj->minor_version), pItem, *plength);
+            break;
+
+        case SML_VZW_RSU_PROTECTION_ALGORITHM:
+            kal_mem_cpy(&(pObj->protection_algo), pItem, *plength);
+            break;
+            
+        case SML_VZW_RSU_NETWORK_LOCK_OPERATION:
+            kal_mem_cpy(&(pObj->nw_lock_op), pItem, *plength);
+            break;
+
+        case SML_VZW_RSU_SESSION_ID:
+            kal_mem_cpy(pObj->session_id, pItem, *plength);
+            break;
+
+        case SML_VZW_RSU_TIME_STAMP:
+            kal_mem_cpy(pObj->timestamp, pItem, *plength);
+            break;
+
+        case SML_VZW_RSU_CAT_CODE:
+            switch(cat)
+            {
+                case SML_VZW_CAT_N:
+                    kal_mem_cpy(pObj->nw_list, pItem, *plength);
+                    break;
+
+                case SML_VZW_CAT_NS:
+                    kal_mem_cpy(pObj->ns_list, pItem, *plength);
+                    break;
+
+                case SML_VZW_CAT_SP:
+                    kal_mem_cpy(pObj->sp_list, pItem, *plength);
+                    break;
+
+                case SML_VZW_CAT_EHPLMN:
+                    kal_mem_cpy(pObj->ehplmn_list, pItem, *plength);
+                    break;
+
+                default:
+                    /* do nothing */
+                    break;
+            }
+            break;
+
+        case SML_VZW_RSU_CAT_NUM:
+            switch(cat)
+            {
+                case SML_VZW_CAT_N:
+                    kal_mem_cpy(&(pObj->nw_num), pItem, *plength);
+                    break;
+        
+                case SML_VZW_CAT_NS:
+                    kal_mem_cpy(&(pObj->ns_num), pItem, *plength);
+                    break;
+        
+                case SML_VZW_CAT_SP:
+                    kal_mem_cpy(&(pObj->sp_num), pItem, *plength);
+                    break;
+        
+                case SML_VZW_CAT_EHPLMN:
+                    kal_mem_cpy(&(pObj->ehplmn_num), pItem, *plength);
+                    break;
+        
+                default:
+                    /* do nothing */
+                    break;
+            }
+            break;
+
+        default:
+            break;
+    }
+}
+
+/*******************************************************************************
+ * FUNCTION  
+ *  sml_vzw_Catcode
+ * DESCRIPTION
+ *  This function is used to compose the code of each category
+ * PARAMETERS
+ *  IN          cat
+ *  IN          *imsi
+ *  IN          *vzw_gid1_len
+ *  IN          *gid1
+ *  IN          *ehplmn
+ *  IN          mnc_len
+ *  OUT          *code
+ * RETURN
+ *  kal_uint8   code length
+ * GLOBALS AFFECTED
+ *  NONE
+ *******************************************************************************/ 
+kal_uint8 sml_vzw_Catcode( sml_vzw_cat_enum cat,
+                           kal_uint8 *imsi,
+                           kal_uint8 vzw_gid1_len,
+                           kal_uint8 *gid1,
+                           kal_uint8 *ehplmn,
+                           kal_uint8 mnc_len,
+                           kal_uint8 *code )
+{
+    kal_uint8 i = 0;
+    kal_uint8 gid1_start_pos = 7;
+    kal_uint8 ehplmn_start_pos = (vzw_gid1_len < NUM_GID1)? (gid1_start_pos + vzw_gid1_len) : (gid1_start_pos + NUM_GID1);
+
+    if (imsi == NULL)
+    {
+        return 0;
+    }
+
+    if(mnc_len == 3)
+    {
+        /* MCC/MNC */
+        code[0] = ((imsi[1]&0xF0)>>4) + '0';
+        code[1] = (imsi[2]&0x0F) + '0';
+        code[2] = ((imsi[2]&0xF0)>>4) + '0';
+        code[3] = (imsi[3]&0x0F) + '0';
+        code[4] = ((imsi[3]&0xF0)>>4) + '0';
+        code[5] = (imsi[4]&0x0F) + '0';
+        code[6] = ((imsi[4]&0xF0)>>4) + '0';
+        code[7] = (imsi[5]&0x0F) + '0';
+    }
+    else
+    {
+        /* MCC/MNC */
+        code[0] = ((imsi[1]&0xF0)>>4) + '0';
+        code[1] = (imsi[2]&0x0F) + '0';
+        code[2] = ((imsi[2]&0xF0)>>4) + '0';
+        code[3] = (imsi[3]&0x0F) + '0';
+        code[4] = ((imsi[3]&0xF0)>>4) + '0';
+        code[5] = 'F';
+        code[6] = (imsi[4]&0x0F) + '0';
+        code[7] = ((imsi[4]&0xF0)>>4) + '0';
+    }
+
+    switch(cat)
+    {        
+        case SML_VZW_CAT_N:
+            return SML_VZW_RSU_NW_CODE_LEN;
+        break;
+
+        case SML_VZW_CAT_NS:
+            return SML_VZW_RSU_NS_CODE_LEN;
+        break;
+
+        case SML_VZW_CAT_SP:
+            if (NULL != gid1)
+            {
+                code[6] = vzw_gid1_len;
+                /* GID */
+                for (i = 0; (i < vzw_gid1_len) && (i < NUM_GID1); i++)
+                {
+                    code[gid1_start_pos+i] = gid1[i];
+                }
+                return gid1_start_pos + i;
+            }
+            else
+            {
+                return 0;
+            }
+        break;
+
+        case SML_VZW_CAT_EHPLMN:
+            if (NULL != gid1)
+            {
+                code[6] = vzw_gid1_len;
+                /* Verizon use 8 bytes of GID1 */
+                for (i = 0; (i < vzw_gid1_len) && (i < NUM_GID1); i++)
+                {
+                    code[gid1_start_pos+i] = gid1[i];
+                }
+            }
+            else
+            {
+                return 0;
+            }
+
+            if (ehplmn != NULL)
+            {
+                if (*ehplmn == 0xff)
+                {
+                    return 0;
+                }
+                else
+                {
+                    /* EHPLMN format is :
+                       MCC2|MCC1 MNC3(opt)|MCC3 MNC2|MNC1
+                    */
+                    code[ehplmn_start_pos] = (ehplmn[0]&0x0F) + '0';      //MCC1
+                    code[ehplmn_start_pos+1] = ((ehplmn[0]&0xF0)>>4) + '0'; //MCC2
+                    code[ehplmn_start_pos+2] = (ehplmn[1]&0x0F) + '0';      //MCC3
+                    code[ehplmn_start_pos+3] = (ehplmn[2]&0x0F) + '0';      //MNC1
+                    code[ehplmn_start_pos+4] = ((ehplmn[2]&0xF0)>>4) + '0'; //MNC2
+                    
+                    if ((ehplmn[1] & 0xF0) == 0xF0) //this EHPLMN mnc len = 2
+                    {
+                        code[ehplmn_start_pos+5] = 0xFF;
+                    }
+                    else
+                    {
+                        code[ehplmn_start_pos+5] = ((ehplmn[1] & 0xF0)>>4) + '0'; //MNC3
+                    }
+                    return ehplmn_start_pos + 6;
+                }
+            }
+            else
+            {
+                return 0;
+            }
+        break;
+
+        default:
+
+        break;
+
+    }
+
+    return 0;
+}
+
+/*******************************************************************************
+ * FUNCTION
+ *  sml_vzw_GetCode
+ * DESCRIPTION
+ *  This function is used to compose the code of each category  whether 
+ *  mnc length is 2 or 3
+ * PARAMETERS
+ *  cat             [IN]    category of the SIM-ME-Lock
+ *  imsi            [IN]    imsi of the code source
+ *  vzw_gid1_len    [IN]    gid1 lengh from VZW code
+ *  gid1            [IN]    gid1 of the code source
+ *  sim_mnc_len     [IN]    the mnc length decided by SIM
+ *  pdata           [IN]    the saved code for comparing
+ *  pdata_len       [IN]    the length of saved code for comparing
+ *  code            [OUT]   the composed code according to all input parameters
+ *
+ * RETURN
+ *  kal_uint16 file size
+ * GLOBALS AFFECTED
+ *  SMLSLOBJ
+ *******************************************************************************/
+kal_uint8 sml_vzw_GetCode( sml_vzw_cat_enum cat, 
+                           kal_uint8 *imsi,
+                           kal_uint8 vzw_gid1_len,
+                           kal_uint8 *gid1,
+                           kal_uint8 *ehplmn,
+                           kal_uint8 sim_mnc_len, 
+                           kal_uint8 *pdata,
+                           kal_uint8 *pdata_len,
+                           kal_uint8 *code)
+{
+    kal_uint8 mnc_len=0;
+
+    if (SML_MNC_LENGTH_NEST == 1)
+    {
+        mnc_len = sim_mnc_len;
+    }
+    else
+    {
+        if (((*(pdata+5)) == 'F') || ((*(pdata+5)) == 'f'))
+        {
+            mnc_len = 2;
+            *(pdata+5) = 'F';
+        }
+        else
+        {
+            mnc_len = 3;
+        }
+    }
+
+    switch (cat)
+    {
+        case SML_VZW_CAT_N:
+            *pdata_len = SML_VZW_RSU_NW_CODE_LEN;
+            break;
+        case SML_VZW_CAT_NS:
+            *pdata_len = SML_VZW_RSU_NS_CODE_LEN;
+            break;
+        case SML_VZW_CAT_SP:
+            *pdata_len = SML_VZW_RSU_NW_CODE_LEN + 1 + vzw_gid1_len;
+            break;
+        case SML_VZW_CAT_EHPLMN:
+            *pdata_len = (SML_VZW_RSU_NW_CODE_LEN*2) + 1 + vzw_gid1_len;
+            break;
+        default:
+            DEBUG_ASSERT(0);
+            *pdata_len = 0;
+    }
+
+    return sml_vzw_Catcode(cat, imsi, vzw_gid1_len, gid1, ehplmn, mnc_len, code);
+}
+
+/*******************************************************************************
+ * FUNCTION  
+ *  sml_vzw_Check
+ * DESCRIPTION
+ *  This function is used to check if the code is in the Pass list
+ * PARAMETERS
+ *  IN          cat
+ *  IN          *imsi
+ *  IN          *gid1
+ *  IN          ehplmn_num
+ *  IN          *ehplmn_ptr
+ *  IN          len
+ *  IN          source
+ * RETURN
+ *  kal_bool
+ * GLOBALS AFFECTED
+ *  SMLOBJ
+ *******************************************************************************/
+kal_bool sml_vzw_Check( sml_vzw_cat_enum cat, 
+                        kal_uint8 *imsi, 
+                        kal_uint8 *gid1,
+                        kal_uint16 ehplmn_num,
+                        kal_uint8 *ehplmn_ptr,
+                        kal_uint8 sim_mnc_len,
+                        kal_uint8 source)
+{
+    nvram_ef_sml_vzw_sim_lock_obj_struct *p = &pSMLVZWg[source];
+    kal_uint8 *num_list = NULL;
+    kal_uint8 *list_data = NULL;
+    kal_uint8 *vzw_code_ptr = NULL;
+    kal_uint8 vzw_code_len = 0;
+    kal_uint16 length = 0;
+    kal_uint8 code[SML_VZW_RSU_EHPLMN_CODE_LEN] = {0}; //use ehplmn code len as max code len
+    kal_uint8 code_len = 0;
+    kal_uint8 vzw_gid1_len;
+    kal_uint16 i = 0;
+    kal_uint8 code_dbg_str[(SML_VZW_RSU_EHPLMN_CODE_LEN)*3 + 1] = {0};
+    kal_uint8 iter = 1; //iteration for EHPLMN Configuration, limited by MD1_MAX_NUM_HPLMN
+
+    /* Check the integration of SIM Lock blob first */
+    if (p->pObj== NULL)
+    {
+        MD_TRC_WARNING_SML_CHECK_VALIDITY_FAILED();
+    }
+    else
+    {
+        num_list = (kal_uint8 *)(*p->getItem)(cat, SML_VZW_RSU_CAT_NUM, &length, source);
+
+        if (*num_list == 0)
+        {
+            // TODO: list is empty, always pass or blocked? currently is pass
+            return KAL_TRUE;
+        }
+        else
+        {
+            list_data = (kal_uint8 *)(*p->getItem)(cat, SML_VZW_RSU_CAT_CODE, &length, source);
+            vzw_code_ptr = list_data;
+        }
+
+        for (i = 0; i < *num_list; i++)
+        {
+            kal_uint8 *temp_ehplmn_ptr = ehplmn_ptr;
+
+            if (SML_VZW_CAT_EHPLMN == cat)
+            {
+                iter = (ehplmn_num < MD1_MAX_NUM_HPLMN)? ehplmn_num : MD1_MAX_NUM_HPLMN;
+            }
+            else
+            {
+                iter = 1;
+            }
+
+            if ((SML_VZW_CAT_SP == cat) || (SML_VZW_CAT_EHPLMN == cat))
+            {
+                vzw_gid1_len = vzw_code_ptr[6];
+            }
+            else
+            {
+                vzw_gid1_len = 0;
+            }
+
+            while (iter > 0)
+            {
+                kal_uint8 j = 0, k = 0;
+
+                iter--;
+
+                code_len = sml_vzw_GetCode(cat, imsi, vzw_gid1_len, gid1, temp_ehplmn_ptr, sim_mnc_len, vzw_code_ptr, &vzw_code_len, code);
+
+                if (iter >= 1)
+                {
+                    temp_ehplmn_ptr += 3; //for next iteration if more than one EHPLMN from SIM
+                }
+
+                while ((j < code_len) && (k <= (sizeof(code_dbg_str) - 4)))
+                {
+                    kal_int8 temp_len;
+
+                    temp_len = kal_sprintf((kal_char*)code_dbg_str + k, "%02x ", code[j]);
+
+                    if (temp_len <= 0)
+                    {
+                        kal_mem_cpy(code_dbg_str + k, "ERR", sizeof("ERR"));
+                        k += 3;
+                        break;
+                    }
+
+                    k += temp_len;
+                    j++;
+                }
+                code_dbg_str[k] = '\0';
+                MD_TRC_INFO_SMU_CHECK_LENGTH(code_len, vzw_code_len, sim_mnc_len);
+                MD_TRC_INFO_SML_VZW_CODE_DEBUG((kal_char*)code_dbg_str);
+
+                /* we support dynamic comparing code length by using the code_len in stead of fixed length.
+                   After that, vzw_code_ptr will shift according to each individual code length.
+                   In addition, the VZW SIM Lock NVRAM structure is defined as max size.
+                */
+                if ((code_len > 0) && (kal_mem_cmp(code, vzw_code_ptr, code_len) == 0))
+                {
+                    return KAL_TRUE;
+                }
+
+                kal_mem_set(code, 0, SML_VZW_RSU_EHPLMN_CODE_LEN);
+            }
+            
+            //shift to next code of the compared category
+            vzw_code_ptr += vzw_code_len;
+        }
+    }
+
+    return KAL_FALSE;
+}
+
+kal_bool sml_vzw_update_int_data(kal_uint8 source, sml_vzw_cat_enum cat, sml_ctx_enum type, kal_uint8 data)
+{
+    nvram_ef_sml_vzw_sim_lock_obj_struct *p = &pSMLVZWg[source];
+    kal_uint16 length = sizeof(kal_uint8);
+
+    /* Check the integration of SIM Lock blob first */
+    if (p->pObj == NULL)
+    {
+        MD_TRC_WARNING_SML_CHECK_VALIDITY_FAILED();
+        return KAL_FALSE;
+    }
+
+    (*p->putItem)(cat, type, &data, &length, source);
+
+    return KAL_TRUE;
+}
+
+kal_bool sml_vzw_get_int_data(kal_uint8 source, sml_vzw_cat_enum cat, sml_ctx_enum type, kal_uint8* pData)
+{
+    nvram_ef_sml_vzw_sim_lock_obj_struct *p = &pSMLVZWg[source];
+    kal_uint16 length;
+    kal_bool ret_val = KAL_FALSE;
+
+    /* Check the integration of SIM Lock blob first */
+    if (p->pObj == NULL)
+    {
+        MD_TRC_WARNING_SML_CHECK_VALIDITY_FAILED();
+    }
+    else
+    {
+        *pData = *((kal_uint8 *)(*p->getItem)(cat, type, &length, source));
+
+        if (length == sizeof(kal_uint8))
+        {
+            ret_val = KAL_TRUE;
+        }
+        else
+        {
+            MD_TRC_WARNING_SML_VZW_RSU_GET_INT_DATA_FAILED(cat, type);
+        }
+    }
+    
+    return ret_val;
+}
+
+kal_bool sml_vzw_update_array_data(kal_uint8 source, sml_vzw_cat_enum cat, sml_ctx_enum type, kal_uint8* data, kal_uint16 data_len)
+{
+    nvram_ef_sml_vzw_sim_lock_obj_struct *p = &pSMLVZWg[source];
+
+    /* Check the integration of SIM Lock blob first */
+    if (p->pObj == NULL)
+    {
+        MD_TRC_WARNING_SML_CHECK_VALIDITY_FAILED();
+        return KAL_FALSE;
+    }
+
+    (*p->putItem)(cat, type, data, &data_len, source);
+
+    return KAL_TRUE;
+}
+
+kal_bool sml_vzw_get_array_data(kal_uint8 source, sml_vzw_cat_enum cat, sml_ctx_enum type, kal_uint8* data, kal_uint16* data_len)
+{
+    nvram_ef_sml_vzw_sim_lock_obj_struct *p = &pSMLVZWg[source];
+    kal_uint8* pData = NULL;
+
+    /* Check the integration of SIM Lock blob first */
+    if (p->pObj == NULL)
+    {
+        MD_TRC_WARNING_SML_CHECK_VALIDITY_FAILED();
+        return KAL_FALSE;
+    }
+
+    pData = (kal_uint8 *)(*p->getItem)(cat, type, data_len, source);
+
+    kal_mem_cpy(data, pData, *data_len);
+    
+    return KAL_TRUE;
+}
+
+kal_uint8 sml_vzw_get_major_version(kal_uint8 source)
+{
+    nvram_ef_sml_vzw_sim_lock_obj_struct *p = &pSMLVZWg[source];
+    kal_uint8 *pMajor_ver = NULL;
+    kal_uint16 length = 0;
+
+    /* Check the integration of SIM Lock blob first */
+    if (p->pObj == NULL)
+    {
+        MD_TRC_WARNING_SML_CHECK_VALIDITY_FAILED();
+        return KAL_FALSE;
+    }
+
+    pMajor_ver = (kal_uint8 *)(*p->getItem)(SML_VZW_CAT_NONE, SML_VZW_RSU_MAJOR_VERSION, &length, source);
+
+    return *pMajor_ver;
+}
+
+kal_uint8 sml_vzw_get_max_support_major_version()
+{
+    return SML_VZW_RSU_MAX_SUPPORT_MAJOR_VER;
+}
+
+kal_uint8 sml_vzw_get_minor_version(kal_uint8 source)
+{
+    nvram_ef_sml_vzw_sim_lock_obj_struct *p = &pSMLVZWg[source];
+    kal_uint8 *pMinor_ver = NULL;
+    kal_uint16 length = 0;
+
+    /* Check the integration of SIM Lock blob first */
+    if (p->pObj == NULL)
+    {
+        MD_TRC_WARNING_SML_CHECK_VALIDITY_FAILED();
+        return KAL_FALSE;
+    }
+
+    pMinor_ver = (kal_uint8 *)(*p->getItem)(SML_VZW_CAT_NONE, SML_VZW_RSU_MINOR_VERSION, &length, source);
+
+    return *pMinor_ver;
+}
+
+kal_uint8 sml_vzw_get_max_support_minor_version()
+{
+    return SML_VZW_RSU_MAX_SUPPORT_MINOR_VER;
+}
+
+extern const nvram_sml_vzw_sim_lock_context_struct NVRAM_EF_L4_SML_VZW_SIM_LOCK_DEFAULT;
+
+kal_bool sml_vzw_reset_rsu_data(kal_uint8 source)
+{
+    nvram_ef_sml_vzw_sim_lock_obj_struct* p = &pSMLVZWg[source];
+    sml_vzw_sim_lock_context_struct* pDefaultBlob = (sml_vzw_sim_lock_context_struct*)&NVRAM_EF_L4_SML_VZW_SIM_LOCK_DEFAULT;
+
+    /* Check the integration of SIM Lock blob first */
+    if (p->pObj == NULL)
+    {
+        MD_TRC_WARNING_SML_CHECK_VALIDITY_FAILED();
+        return KAL_FALSE;
+    }
+
+    // Set Network Lock
+    sml_vzw_update_int_data(source, SML_VZW_CAT_NONE, SML_VZW_RSU_NETWORK_LOCK_OPERATION, SML_VZW_LOCK_STATE_LOCK);
+
+    // Reset NW Configuration
+    sml_vzw_update_int_data(source, SML_VZW_CAT_N, SML_VZW_RSU_CAT_NUM, pDefaultBlob->nw_num);
+    sml_vzw_update_array_data(source, SML_VZW_CAT_N, SML_VZW_RSU_CAT_CODE, pDefaultBlob->nw_list, SML_VZW_RSU_NW_LIST_LEN);
+
+    // Reset NS Configuration
+    sml_vzw_update_int_data(source, SML_VZW_CAT_NS, SML_VZW_RSU_CAT_NUM, pDefaultBlob->ns_num);
+    sml_vzw_update_array_data(source, SML_VZW_CAT_NS, SML_VZW_RSU_CAT_CODE, pDefaultBlob->ns_list, SML_VZW_RSU_NS_LIST_LEN);
+
+    // Reset SP Configuration
+    sml_vzw_update_int_data(source, SML_VZW_CAT_SP, SML_VZW_RSU_CAT_NUM, pDefaultBlob->sp_num);
+    sml_vzw_update_array_data(source, SML_VZW_CAT_SP, SML_VZW_RSU_CAT_CODE, pDefaultBlob->sp_list, SML_VZW_RSU_SP_LIST_LEN);
+
+    // Reset EHPLMN Configuration
+    sml_vzw_update_int_data(source, SML_VZW_CAT_EHPLMN, SML_VZW_RSU_CAT_NUM, pDefaultBlob->ehplmn_num);
+    sml_vzw_update_array_data(source, SML_VZW_CAT_EHPLMN, SML_VZW_RSU_CAT_CODE, pDefaultBlob->ehplmn_list, SML_VZW_RSU_EHPLMN_LIST_LEN);
+
+    return KAL_TRUE;
+}
+
+void custom_vzw_rsu_get_pub_key_handle(kal_uint8 index, TYPE_CUST_CHL_KEY *key)
+{
+    TYPE_CUST_CHL_KEY pub_key[] = {
+        CUST_VZ_PUB_KEY // index == 0, do not change this.
+        // Add test key handle here
+    };
+    
+    #define VZW_KEY_SET_MAX_NUM (sizeof(pub_key)/sizeof(pub_key[0]))
+    
+    index = index > (VZW_KEY_SET_MAX_NUM - 1) ? 0 : index;
+    
+    if (NULL != key)
+    {
+        *key = pub_key[index];
+        MD_TRC_INFO_SML_RSU_PUB_KEY_HANDLE((*key));
+    }
+
+    return;
+}
+
+/****************************************************************************
+ *
+ *  TMO SIM Lock with Movial Solution
+ *
+ ****************************************************************************/
+#ifdef __TMO_RSU_OTP__
+static kal_bool custom_check_is_default_tmo_blob(kal_uint8 *imei);
+#endif /* __TMO_RSU_OTP__ */
+/* define the Local variable of TMO MOVIAL SML object */
+static sml_tmo_movial_sim_lock_context_struct sml_tmo_movial_cntxt_obj[MAX_SIM_NUM];
+static nvram_ef_sml_tmo_movial_sim_lock_obj_struct SMLTMMOBJ[MAX_SIM_NUM];
+
+/* define the Global access pointer of TMO MOVIAL SML object */
+nvram_ef_sml_tmo_movial_sim_lock_obj_struct* pSMLTMMg = &SMLTMMOBJ[0];
+
+/* time to temporary unlock expiry in seconds */
+kal_uint32 sml_tmo_movial_seconds_to_expire = 0;
+
+#ifdef UNIT_TEST
+kal_uint8 imei_bcd_ut[9];
+#endif /* UNIT_TEST */
+
+/*******************************************************************************
+ * FUNCTION  
+ *  sml_clean_tmo_movial_cntxt
+ * DESCRIPTION
+ *  Clean sensitive data in MD Dump.
+ * PARAMETERS
+ *  N/A
+ * RETURN
+ *  N/A
+ * GLOBALS AFFECTED
+ *  sml_tmo_movial_cntxt_obj
+*******************************************************************************/
+void sml_clean_tmo_movial_cntxt(void)
+{
+    kal_mem_set(sml_tmo_movial_cntxt_obj, 0x00, sizeof(sml_tmo_movial_cntxt_obj));
+}
+
+/*******************************************************************************
+ * FUNCTION
+ *  sml_tmo_movial_give
+ * DESCRIPTION
+ *  This method copys the LID files read from NVRAM to the SML obj
+ * PARAMETERS
+ *  IN          * pLidToObj
+ * RETURN
+ *  void
+ * GLOBALS AFFECTED
+ *  SMLTMMOBJ
+*******************************************************************************/
+void sml_tmo_movial_give( void *pLidToObj, kal_uint8 source )
+{
+    sml_tmo_movial_sim_lock_context_struct * pObj = NULL;
+
+    if(NULL != pSMLTMMg[source].pObj)
+    {
+        kal_sys_trace("SML: object is exist!");
+        pSMLTMMg[source].pObj = NULL;
+    }
+
+    pObj = &(sml_tmo_movial_cntxt_obj[source]);
+
+    kal_mem_cpy(pObj,
+                pLidToObj,
+                sizeof(sml_tmo_movial_sim_lock_context_struct)
+                );
+
+    pSMLTMMg[source].pObj = pObj;
+}
+
+
+/*******************************************************************************
+ * FUNCTION
+ *  sml_tmo_movial_take
+ * DESCRIPTION
+ *  This method copys the contex of the SML object to the provided NVRAM LID.
+ * PARAMETERS
+ *  OUT         * pObjToLid
+ * RETURN
+ *  void
+ * GLOBALS AFFECTED
+ *  SMLTMMOBJ
+ *******************************************************************************/
+
+void sml_tmo_movial_take( void *pObjToLid, kal_uint8 source )
+{
+    sml_tmo_movial_sim_lock_context_struct * pObj = (sml_tmo_movial_sim_lock_context_struct *) pSMLTMMg[source].pObj;
+
+    if (NULL == pObjToLid || NULL == pObj)
+    {
+        return;
+    }
+    
+    kal_mem_cpy(pObjToLid,
+                pObj,
+                sizeof(sml_tmo_movial_sim_lock_context_struct)
+                );
+}
+
+
+/*******************************************************************************
+ * FUNCTION
+ *  sml_tmo_movial_destory
+ * DESCRIPTION
+ *  This method free the SML object in memory if it is not used.
+ * PARAMETERS
+ *  void
+ * RETURN
+ *  void
+ * GLOBALS AFFECTED
+ *  SMLTMMOBJ
+ *******************************************************************************/
+void sml_tmo_movial_destory(kal_uint8 source)
+{
+    pSMLTMMg[source].pObj = NULL;
+}
+
+
+/*******************************************************************************
+ * FUNCTION
+ *  sml_tmo_movial_getItem
+ * DESCRIPTION
+ *  This method returns the structure pointer and length of the structure
+ *  of the desired SML object items.
+ * PARAMETERS
+ *  IN          cat
+ *  IN          item
+ *  OUT         *length
+ * RETURN
+ *  void *
+ * GLOBALS AFFECTED
+ *  SMLTMMOBJ
+ *******************************************************************************/
+void *sml_tmo_movial_getItem( sml_tmo_movial_cat_enum category,
+                              sml_ctx_enum item,
+                              kal_uint16 *plength,
+                              kal_uint8 source)
+{
+    sml_tmo_movial_sim_lock_context_struct *pObj = (sml_tmo_movial_sim_lock_context_struct *) pSMLTMMg[source].pObj;
+
+    ASSERT(NULL != pObj);
+
+    switch(item)
+    {
+        case SML_TMO_MOVIAL_CAT_MAJOR_VERSION:
+            *plength = sizeof(kal_uint8);
+            return (kal_uint8 *) &(pObj->major_version);
+
+        case SML_TMO_MOVIAL_CAT_MINOR_VERSION:
+            *plength = sizeof(kal_uint8);
+            return (kal_uint8 *) &(pObj->minor_version);
+
+        case SML_TMO_MOVIAL_CAT_PROTECTION_ALGORITHM:
+            *plength = sizeof(kal_uint8);
+            return (kal_uint8 *) &(pObj->protection_algorithm);
+
+        case SML_TMO_MOVIAL_CAT_LOCK_OPERATION:
+            *plength = sizeof(kal_uint8);
+            return (kal_uint8 *) &(pObj->lock_operation);
+
+        case SML_TMO_MOVIAL_CAT_IMEI:
+            *plength = SML_TMO_MOVIAL_BLOB_IMEI_SIZE;
+            return (kal_uint8 *) &(pObj->imei[0]);
+
+        case SML_TMO_MOVIAL_CAT_TIME_STAMP:
+            *plength = SML_TMO_MOVIAL_BLOB_TIME_STAMP_SIZE;
+            return (kal_uint8 *) &(pObj->time_stamp[0]);
+
+        case SML_TMO_MOVIAL_CAT_START_TIME:
+            *plength = SML_TMO_MOVIAL_SIZE_OF_START_TIME;
+            return (kal_uint8 *) &(pObj->start_time[0]);
+
+        case SML_TMO_MOVIAL_CAT_UNLOCK_DURATION:
+            *plength = SML_TMO_MOVIAL_SIZE_OF_UNLOCK_DURATION;
+            return (kal_uint8 *) &(pObj->unlock_duration[0]);
+            
+        case SML_TMO_MOVIAL_CAT_LENGTH:
+            *plength = SML_TMO_MOVIAL_BLOB_LENGTH_SIZE;
+            return (kal_uint16 *) &(pObj->length[0]);
+
+        case SML_TMO_MOVIAL_CAT_META:
+            *plength = sizeof(sml_tmo_movial_blob_meta_struct);
+            return (sml_tmo_movial_blob_meta_struct *) &(pObj->cat[category]);
+
+        case SML_TMO_MOVIAL_CAT_KEY:
+            *plength = sizeof(sml_tmo_movial_blob_key_struct);
+            return (sml_tmo_movial_blob_key_struct *) &(pObj->key[category]);
+
+        case SML_TMO_MOVIAL_CAT_SIGNATURE:
+            *plength = SML_TMO_MOVIAL_BLOB_SIZE_OF_SIGNATURE;
+            return (kal_uint8 *) &(pObj->signature[0]);
+
+        case SML_TMO_MOVIAL_CAT_UNLOCK_TIME_COUNTER:
+            *plength = SML_TMO_MOVIAL_SIZE_OF_UNLOCK_TIME;
+            return (kal_uint8 *) &(pObj->unlock_time[0]);
+
+        case SML_TMO_MOVIAL_CAT_CODE:
+            switch(category)
+            {
+                case SML_TMO_MOVIAL_CAT_N:
+                    *plength = SML_TMO_MOVIAL_BLOB_CAT_N_SIZE;
+                    return (kal_uint8 *) &(pObj->code_cat_n[0]);
+                    break;
+
+                case SML_TMO_MOVIAL_CAT_NS:
+                    *plength = SML_TMO_MOVIAL_BLOB_CAT_NS_SIZE;
+                    return (kal_uint8 *) &(pObj->code_cat_ns[0]);
+                    break;
+
+                case SML_TMO_MOVIAL_CAT_SP:
+                    *plength = SML_TMO_MOVIAL_BLOB_CAT_SP_SIZE;
+                    return (kal_uint8 *) &(pObj->code_cat_sp[0]);
+                    break;
+
+                default:
+                    /* do nothing */
+                    break;
+            }
+            break;
+
+        default:
+            break;
+    }
+
+    return NULL;
+}
+
+void sml_tmo_movial_putItem( sml_tmo_movial_cat_enum category,
+                             sml_ctx_enum item, 
+                             void *pItem, 
+                             kal_uint16 *plength,
+                             kal_uint8 source)
+{
+    sml_tmo_movial_sim_lock_context_struct *pObj = (sml_tmo_movial_sim_lock_context_struct *) pSMLTMMg[source].pObj;
+
+    ASSERT(NULL != pObj);
+
+    switch(item)
+    {
+        case SML_TMO_MOVIAL_CAT_UNLOCK_TIME_COUNTER:
+
+            kal_mem_cpy(&(pObj->unlock_time[0]),
+                        pItem,
+                        SML_TMO_MOVIAL_SIZE_OF_UNLOCK_TIME
+                        );
+            break;
+
+        case SML_TMO_MOVIAL_CAT_LOCK_OPERATION:
+
+            kal_mem_cpy(&(pObj->lock_operation),
+                        pItem,
+                        *plength);
+            break;
+
+        default:
+            break;
+    }
+}
+
+
+kal_bool sml_tmo_movial_ValidateIMEI(kal_uint8 *imei, kal_bool is_bypass_default, kal_uint8 source)
+{
+    kal_uint8 nvram_imei_bcd[8 + 1] = {0};
+    kal_uint8 nvram_imei_ascii[16 + 1] = {0};
+    kal_uint8 rec_id = 1 + l4c_gemini_get_actual_sim_id(source);
+    kal_bool result = KAL_FALSE;
+
+#ifdef UNIT_TEST    //Integrity check doesn't work on modis. Modify for UT.
+    kal_mem_cpy(&nvram_imei_bcd[0], &imei_bcd_ut[0], 9);
+#else
+    if (nvram_get_imei_value(8, nvram_imei_bcd, rec_id) == KAL_TRUE)
+#endif
+    {
+        if ((is_bypass_default == KAL_TRUE) 
+            && (KAL_TRUE == custom_check_is_default_imei(&nvram_imei_bcd[0])))
+        {
+            MD_TRC_INFO_SML_CUST_ALLOW_DEFAULT_IMEI();
+            result = KAL_TRUE;
+        }
+        else
+        {
+            // ch2-ch1, last digit is 0
+            nvram_imei_bcd[7] = nvram_imei_bcd[7] & 0x0f;
+            nvram_imei_bcd[8] = 0xff;
+            convert_to_digit((kal_uint8 *)nvram_imei_bcd, nvram_imei_ascii);
+
+            sml_mini_trace("UE IMEI", nvram_imei_ascii, SML_IMEI_PRINT_LEN);
+            sml_mini_trace("BLOB IMEI", &imei[0], SML_TMO_MOVIAL_BLOB_IMEI_SIZE);
+
+            if (kal_mem_cmp(&imei[0], nvram_imei_ascii, 15) == 0)
+            {
+                result = KAL_TRUE;
+            }
+        }
+    }
+
+    MD_TRC_INFO_SML_TMO_RSU_IMEI_CHECK_RESULT(result);
+    return result;
+}
+
+kal_bool sml_tmo_movial_ValidateTimeStamp(kal_uint8 *new_time_stamp, kal_uint8 source)
+{
+    nvram_ef_sml_tmo_movial_sim_lock_obj_struct *p = &pSMLTMMg[source];
+    kal_uint16 length = 0;
+    kal_uint8  *blob_time_stamp;
+    kal_uint64 new_time = 0;
+    kal_uint64 blob_time = 0;   
+    kal_uint8 i = 0;
+
+    blob_time_stamp = (kal_uint8 *)(*p->getItem)(SML_TMO_MOVIAL_CAT_NULL, SML_TMO_MOVIAL_CAT_TIME_STAMP, &length, source);
+
+    for (i = 0; i < SML_TMO_MOVIAL_BLOB_TIME_STAMP_SIZE-1; i++)
+    {
+        blob_time += blob_time_stamp[i];
+        blob_time = (blob_time << 8);
+
+        new_time += new_time_stamp[i];
+        new_time = (new_time << 8);
+    }
+
+    blob_time += blob_time_stamp[SML_TMO_MOVIAL_BLOB_TIME_STAMP_SIZE-1];
+    new_time += new_time_stamp[SML_TMO_MOVIAL_BLOB_TIME_STAMP_SIZE-1];
+
+    if (new_time > blob_time)
+    {
+        return KAL_TRUE;
+    }
+
+    return KAL_FALSE;
+}
+
+kal_bool sml_tmo_movial_ValidateConfigData(sml_tmo_movial_sim_lock_context_struct *pBlob)
+{
+    kal_uint16 cat_idx, data_idx;
+    kal_uint16 length = 0;
+    kal_uint8 *data = NULL;
+
+    for (cat_idx = SML_TMO_MOVIAL_CAT_N ; cat_idx < SML_TMO_MOVIAL_CAT_SIZE ; cat_idx++)
+    {
+        switch (cat_idx)
+        {
+            case SML_TMO_MOVIAL_CAT_N:
+                length = pBlob->cat[cat_idx].num * SML_TMO_MOVIAL_BLOB_SIZE_OF_CAT_N;
+                data = pBlob->code_cat_n;
+                break;
+
+            case SML_TMO_MOVIAL_CAT_NS:
+                length = pBlob->cat[cat_idx].num * SML_TMO_MOVIAL_BLOB_SIZE_OF_CAT_NS;
+                data = pBlob->code_cat_ns;
+                break;
+
+            case SML_TMO_MOVIAL_CAT_SP:
+                length = pBlob->cat[cat_idx].num * SML_TMO_MOVIAL_BLOB_SIZE_OF_CAT_SP;
+                data = pBlob->code_cat_sp;
+                break;
+
+            default:
+                break;
+        }
+
+        for (data_idx = 0; data_idx < length; data_idx++)
+        {
+            if (!((data[data_idx] >= RMMI_CHAR_0) && (data[data_idx] <= RMMI_CHAR_9)) && (data[data_idx] != RMMI_CHAR_F))
+            {
+                return KAL_FALSE;
+            }
+        }
+    }
+
+    return KAL_TRUE;
+}
+
+/*******************************************************************************
+ * FUNCTION
+ *  sml_tmo_movial_ConstructBlob
+ * DESCRIPTION
+ *  This function construct full size Bolb (internal NV structure) from a variant length Blob received in response message
+ * PARAMETERS
+ *  IN          *pObj
+ *  OUT         pLen
+ * RETURN
+ *  kal_uint8 * construct data
+ * GLOBALS AFFECTED
+ *  SMLTMMOBJ
+ *******************************************************************************/
+kal_uint8 *sml_tmo_movial_ConstructBlob(kal_uint8 *pObj, kal_uint16 slb_len, kal_uint8 *error_cause, kal_uint8 source)
+{
+    kal_uint16 sizeM, sizeN, sizeP;
+    kal_uint16 length = 0;
+    kal_uint16 idx;
+    sml_tmo_movial_sim_lock_context_struct *pBlob;
+    kal_uint8 cat_idx = 0;
+
+    MD_TRC_FUNC_SML_TMO_MOVIAL_CONSTRUCTBLOB();
+
+    pBlob = (sml_tmo_movial_sim_lock_context_struct *)get_ctrl_buffer(SML_TMO_MOVIAL_MAX_BLOB_SIZE);
+    kal_mem_set(pBlob, 0, SML_TMO_MOVIAL_MAX_BLOB_SIZE);
+
+    /* major_version + minor_version + protection_algorithm + lock_operation */
+    pBlob->major_version = pObj[length++];
+    pBlob->minor_version = pObj[length++];
+    pBlob->protection_algorithm = pObj[length++];
+    pBlob->lock_operation = pObj[length++];
+
+    /* imei */
+    kal_mem_cpy(pBlob->imei, &(pObj[length]), SML_TMO_MOVIAL_BLOB_IMEI_SIZE);
+    length += SML_TMO_MOVIAL_BLOB_IMEI_SIZE;
+
+    /* time stamp */
+    kal_mem_cpy(pBlob->time_stamp, &(pObj[length]), SML_TMO_MOVIAL_BLOB_TIME_STAMP_SIZE);
+    length += SML_TMO_MOVIAL_BLOB_TIME_STAMP_SIZE;
+
+    /* Temporary unlock start timer */
+    kal_mem_cpy(pBlob->start_time, &(pObj[length]), SML_TMO_MOVIAL_SIZE_OF_START_TIME);
+    length += SML_TMO_MOVIAL_SIZE_OF_START_TIME;
+
+    /* Temporary unlock duration */
+    kal_mem_cpy(pBlob->unlock_duration, &(pObj[length]), SML_TMO_MOVIAL_SIZE_OF_UNLOCK_DURATION);
+    length += SML_TMO_MOVIAL_SIZE_OF_UNLOCK_DURATION;
+
+    /* length */
+    kal_mem_cpy(pBlob->length, &(pObj[length]), SML_TMO_MOVIAL_BLOB_LENGTH_SIZE);
+    length += SML_TMO_MOVIAL_BLOB_LENGTH_SIZE;
+
+    if (pBlob->protection_algorithm >= SML_TMO_MOVIAL_PROTECTION_SCHEME_SIZE)
+    {
+        *error_cause = SML_TMO_MOVIAL_SLB_ERR_GENERIC;
+        free_ctrl_buffer(pBlob);
+        return NULL;
+    }
+
+    if (sml_tmo_movial_ValidateIMEI(pBlob->imei, KAL_FALSE, source) == KAL_FALSE)
+    {
+        *error_cause = SML_TMO_MOVIAL_SLB_ERR_IMEI_MISMATCH;
+        free_ctrl_buffer(pBlob);
+        return NULL;
+    }
+
+    if (sml_tmo_movial_ValidateTimeStamp(pBlob->time_stamp, source) == KAL_FALSE)
+    {
+        *error_cause = SML_TMO_MOVIAL_SLB_ERR_GENERIC;
+        free_ctrl_buffer(pBlob);
+        return NULL;
+    }
+
+    idx = length;
+
+    for (cat_idx = SML_TMO_MOVIAL_CAT_N ; cat_idx < SML_TMO_MOVIAL_CAT_SIZE ; cat_idx++)
+    {
+        pBlob->cat[cat_idx].change_flag = pObj[idx++];
+
+        /* iteration_count, salt, hck */
+        kal_mem_cpy(pBlob->key[cat_idx].iteration_count, &(pObj[idx]), SML_TMO_MOVIAL_BLOB_ITERATION_COUNT_SIZE);
+        idx += SML_TMO_MOVIAL_BLOB_ITERATION_COUNT_SIZE;
+
+        kal_mem_cpy(pBlob->key[cat_idx].salt, &(pObj[idx]), SML_TMO_MOVIAL_BLOB_SALT_SIZE);
+        idx += SML_TMO_MOVIAL_BLOB_SALT_SIZE;
+
+        kal_mem_cpy(pBlob->key[cat_idx].hck, &(pObj[idx]), SML_TMO_MOVIAL_BLOB_HCK_SIZE);
+        idx += SML_TMO_MOVIAL_BLOB_HCK_SIZE;
+
+        /* check m,n,p */
+        if (pObj[idx] > 0)
+        {
+            switch (cat_idx)
+            {
+                case SML_TMO_MOVIAL_CAT_N:
+                    sizeM = pObj[idx] * SML_TMO_MOVIAL_BLOB_SIZE_OF_CAT_N;
+                    if (sizeM > SML_TMO_MOVIAL_BLOB_CAT_N_SIZE)
+                    {
+                        *error_cause = SML_TMO_MOVIAL_SLB_ERR_GENERIC;
+                        free_ctrl_buffer(pBlob);
+                        return NULL;
+                    }
+
+                    pBlob->cat[cat_idx].num = pObj[idx++];
+                    kal_mem_cpy(pBlob->code_cat_n, &(pObj[idx]), sizeM);
+                    idx += sizeM;
+                    break;
+
+                case SML_TMO_MOVIAL_CAT_NS:
+                    sizeN = pObj[idx] * SML_TMO_MOVIAL_BLOB_SIZE_OF_CAT_NS;
+                    if (sizeN > SML_TMO_MOVIAL_BLOB_CAT_NS_SIZE)
+                    {
+                        *error_cause = SML_TMO_MOVIAL_SLB_ERR_GENERIC;
+                        free_ctrl_buffer(pBlob);
+                        return NULL;
+                    }
+
+                    pBlob->cat[cat_idx].num = pObj[idx++];
+                    kal_mem_cpy(pBlob->code_cat_ns, &(pObj[idx]), sizeN);
+                    idx += sizeN;
+                    break;
+
+                case SML_TMO_MOVIAL_CAT_SP:
+                    sizeP = pObj[idx] * SML_TMO_MOVIAL_BLOB_SIZE_OF_CAT_SP;
+                    if (sizeP > SML_TMO_MOVIAL_BLOB_CAT_SP_SIZE)
+                    {
+                        *error_cause = SML_TMO_MOVIAL_SLB_ERR_GENERIC;
+                        free_ctrl_buffer(pBlob);
+                        return NULL;
+                    }
+
+                    pBlob->cat[cat_idx].num = pObj[idx++];
+                    kal_mem_cpy(pBlob->code_cat_sp, &(pObj[idx]), sizeP);
+                    idx += sizeP;
+                    break;
+
+                default:
+                    break;
+            }
+        }
+        else /* m/n/p = 0 */
+        {
+            /* memset ensures pBlob->cat[cat_idx].num set to 0 */
+            idx += 1;
+        }
+    }
+
+    if (sml_tmo_movial_ValidateConfigData(pBlob) == KAL_FALSE)
+    {
+        *error_cause = SML_TMO_MOVIAL_SLB_ERR_GENERIC;
+        free_ctrl_buffer(pBlob);
+        return NULL;
+    }
+
+    kal_mem_cpy(pBlob->signature, &(pObj[idx]), SML_TMO_MOVIAL_BLOB_SIZE_OF_SIGNATURE);
+
+    sml_Dump("constructed blob", (kal_uint8 *)pBlob, SML_TMO_MOVIAL_MAX_BLOB_SIZE);
+
+    return (kal_uint8 *)pBlob;
+}
+
+
+/*******************************************************************************
+ * FUNCTION
+ *  sml_tmo_movial_ConstructSmlBlob
+ * DESCRIPTION
+ *  This function constructs BLOB for NVRAM updating based on change_flag param
+ *     change_flag == 0  => get cat / key / lock data from NVRAM
+ *     change_flag == 1  => get cat / key / lock data from pObj
+ * PARAMETERS
+ *  IN          *pObj  (constructed blob data)
+ *  OUT         pLen
+ * RETURN
+ *  kal_uint8 * construct data 
+ * GLOBALS AFFECTED
+ *  SMLTMMOBJ
+ *******************************************************************************/
+kal_uint8 *sml_tmo_movial_ConstructSmlBlob(sml_tmo_movial_sim_lock_context_struct *pObj, kal_uint8 source)
+{
+    sml_tmo_movial_sim_lock_context_struct *psmlBlob;
+    kal_uint8 cat_idx = 0;
+    kal_uint16 obj_len = 0;
+    nvram_ef_sml_tmo_movial_sim_lock_obj_struct *p = &pSMLTMMg[source];
+    sml_tmo_movial_blob_meta_struct *cat = NULL;
+    sml_tmo_movial_blob_key_struct *key = NULL;
+    kal_uint8 *pdata = NULL;
+
+    psmlBlob = (sml_tmo_movial_sim_lock_context_struct *)get_ctrl_buffer(SML_TMO_MOVIAL_MAX_BLOB_SIZE);
+    kal_mem_set(psmlBlob, 0, SML_TMO_MOVIAL_MAX_BLOB_SIZE);
+
+    /* major_version + minor_version + protection_algorithm + lock_operation */
+    psmlBlob->major_version = pObj->major_version;
+    psmlBlob->minor_version= pObj->minor_version;
+    psmlBlob->protection_algorithm= pObj->protection_algorithm;
+    psmlBlob->lock_operation= pObj->lock_operation;
+
+    /* imei */
+    kal_mem_cpy(psmlBlob->imei, pObj->imei, SML_TMO_MOVIAL_BLOB_IMEI_SIZE);
+
+    /* time stamp */
+    kal_mem_cpy(psmlBlob->time_stamp, pObj->time_stamp, SML_TMO_MOVIAL_BLOB_TIME_STAMP_SIZE);
+
+    /* Temporary unlock start time */
+    kal_mem_cpy(psmlBlob->start_time, pObj->start_time, SML_TMO_MOVIAL_SIZE_OF_START_TIME);
+
+    /* Temporary unlock duration */
+    kal_mem_cpy(psmlBlob->unlock_duration, pObj->unlock_duration, SML_TMO_MOVIAL_SIZE_OF_UNLOCK_DURATION);
+
+    /* length */
+    kal_mem_cpy(psmlBlob->length, pObj->length, SML_TMO_MOVIAL_BLOB_LENGTH_SIZE);
+
+    for (cat_idx = SML_TMO_MOVIAL_CAT_N ; cat_idx < SML_TMO_MOVIAL_CAT_SIZE ; cat_idx++)
+    {
+        /* existing configuration should be used if change_flag=0 */
+        if (pObj->cat[cat_idx].change_flag == 0 || SML_TMO_MOVIAL_STATE_TEMPORARY_UNLOCK == psmlBlob->lock_operation)
+        {
+            cat = (sml_tmo_movial_blob_meta_struct *) (*p->getItem)(cat_idx, SML_TMO_MOVIAL_CAT_META, &obj_len, source);
+            key = (sml_tmo_movial_blob_key_struct *) (*p->getItem)(cat_idx, SML_TMO_MOVIAL_CAT_KEY, &obj_len, source);
+            pdata = (kal_uint8 *) (*p->getItem)(cat_idx, SML_TMO_MOVIAL_CAT_CODE, &obj_len, source);
+        }
+        else
+        {
+            cat = &(pObj->cat[cat_idx]);
+            key = &(pObj->key[cat_idx]);
+
+            switch (cat_idx)
+            {
+                case SML_TMO_MOVIAL_CAT_N:
+                    pdata = pObj->code_cat_n;
+                    break;
+
+                case SML_TMO_MOVIAL_CAT_NS:
+                    pdata = pObj->code_cat_ns;
+                    break;
+
+                case SML_TMO_MOVIAL_CAT_SP:
+                    pdata = pObj->code_cat_sp;
+                    break;
+
+                default:
+                    break;
+            }
+        }
+
+        kal_mem_cpy(&(psmlBlob->cat[cat_idx]), cat, sizeof(sml_tmo_movial_blob_meta_struct));
+        kal_mem_cpy(&(psmlBlob->key[cat_idx]), key, sizeof(sml_tmo_movial_blob_key_struct));
+
+        switch (cat_idx)
+        {
+            case SML_TMO_MOVIAL_CAT_N:
+                kal_mem_cpy(psmlBlob->code_cat_n, pdata, SML_TMO_MOVIAL_BLOB_CAT_N_SIZE);
+                break;
+
+            case SML_TMO_MOVIAL_CAT_NS:
+                kal_mem_cpy(psmlBlob->code_cat_ns, pdata, SML_TMO_MOVIAL_BLOB_CAT_NS_SIZE);
+                break;
+
+            case SML_TMO_MOVIAL_CAT_SP:
+                kal_mem_cpy(psmlBlob->code_cat_sp, pdata, SML_TMO_MOVIAL_BLOB_CAT_SP_SIZE);
+                break;
+
+            default:
+                break;
+        }
+    }
+
+    kal_mem_cpy(psmlBlob->signature, pObj->signature, SML_TMO_MOVIAL_BLOB_SIZE_OF_SIGNATURE);
+
+    sml_Dump("constructed sml blob", (kal_uint8 *)psmlBlob, SML_TMO_MOVIAL_MAX_BLOB_SIZE);
+
+    return (kal_uint8 *)psmlBlob;
+}
+
+
+/*******************************************************************************
+ * FUNCTION
+ *  sml_tmo_movial_ReconstructBlob
+ * DESCRIPTION
+ *  This function restores the original message raw data from constructed internal blob structure
+ *  (used for signature verification)
+ * PARAMETERS
+ *  IN          *pObj  (constructed blob data)
+ *  OUT         pLen, length of returned raw data
+ *  OUT         error_cause
+ * RETURN
+ *  kal_uint8 * raw data
+ * GLOBALS AFFECTED
+ *  N/A
+ *******************************************************************************/
+kal_uint8 *sml_tmo_movial_ReconstructBlob(sml_tmo_movial_sim_lock_context_struct *pObj, kal_uint32 *pLen, kal_uint8 *error_cause)
+{
+    kal_uint8 *pData = NULL;
+    kal_uint32 blob_len, data_len;
+    kal_uint32 sizeM, sizeN, sizeP;
+    kal_uint32 len;
+    kal_uint8 cat_idx;
+
+    blob_len = sml_GetCount(&(pObj->length[0]));
+    sizeM = pObj->cat[SML_TMO_MOVIAL_CAT_N].num * SML_TMO_MOVIAL_BLOB_SIZE_OF_CAT_N;
+    sizeN = pObj->cat[SML_TMO_MOVIAL_CAT_NS].num * SML_TMO_MOVIAL_BLOB_SIZE_OF_CAT_NS;
+    sizeP = pObj->cat[SML_TMO_MOVIAL_CAT_SP].num * SML_TMO_MOVIAL_BLOB_SIZE_OF_CAT_SP;
+
+    /* RSA-PSS scheme */
+    if (pObj->protection_algorithm == 1)
+    {
+        data_len = blob_len - SML_TMO_MOVIAL_BLOB_SIZE_OF_SIGNATURE;
+    }
+    else
+    {
+        *error_cause = SML_TMO_MOVIAL_SLB_ERR_GENERIC;
+        return NULL;
+    }
+
+    pData = (kal_uint8 *)get_ctrl_buffer(data_len);
+
+    if (NULL == pData)
+    {
+        *error_cause = SML_TMO_MOVIAL_SLB_ERR_GENERIC;
+        return NULL;
+    }
+    /* major_version + minor_version + protection_algorithm + lock_operation */
+    len = 0;
+
+    pData[len++] = pObj->major_version;
+    pData[len++] = pObj->minor_version;
+    pData[len++] = pObj->protection_algorithm;
+    pData[len++] = pObj->lock_operation;
+
+    /* imei */
+    kal_mem_cpy((pData+len), pObj->imei, SML_TMO_MOVIAL_BLOB_IMEI_SIZE);
+    len += SML_TMO_MOVIAL_BLOB_IMEI_SIZE;
+
+    /* time stamp */
+    kal_mem_cpy((pData+len), pObj->time_stamp, SML_TMO_MOVIAL_BLOB_TIME_STAMP_SIZE);
+    len += SML_TMO_MOVIAL_BLOB_TIME_STAMP_SIZE;
+
+    /* temporary unlock start time */
+    kal_mem_cpy((pData+len), pObj->start_time, SML_TMO_MOVIAL_SIZE_OF_START_TIME);
+    len += SML_TMO_MOVIAL_SIZE_OF_START_TIME;
+
+    /* temporary unlock duration */
+    kal_mem_cpy((pData+len), pObj->unlock_duration, SML_TMO_MOVIAL_SIZE_OF_UNLOCK_DURATION);
+    len += SML_TMO_MOVIAL_SIZE_OF_UNLOCK_DURATION;
+
+    /* length */
+    kal_mem_cpy((pData+len), pObj->length, SML_TMO_MOVIAL_BLOB_LENGTH_SIZE);
+    len += SML_TMO_MOVIAL_BLOB_LENGTH_SIZE;
+
+    for (cat_idx = SML_TMO_MOVIAL_CAT_N ; cat_idx < SML_TMO_MOVIAL_CAT_SIZE; cat_idx++)
+    {
+        pData[len++] = pObj->cat[cat_idx].change_flag;
+
+        kal_mem_cpy((pData+len), (kal_uint8 *)&(pObj->key[cat_idx].iteration_count[0]), SML_TMO_MOVIAL_BLOB_ITERATION_COUNT_SIZE);
+        len += SML_TMO_MOVIAL_BLOB_ITERATION_COUNT_SIZE;
+
+        kal_mem_cpy((pData+len), (kal_uint8 *)&(pObj->key[cat_idx].salt[0]), SML_TMO_MOVIAL_BLOB_SALT_SIZE);
+        len += SML_TMO_MOVIAL_BLOB_SALT_SIZE;
+
+        kal_mem_cpy((pData+len), (kal_uint8 *)&(pObj->key[cat_idx].hck[0]), SML_TMO_MOVIAL_BLOB_HCK_SIZE);
+        len += SML_TMO_MOVIAL_BLOB_HCK_SIZE;
+
+        pData[len++] = pObj->cat[cat_idx].num;
+
+        switch (cat_idx)
+        {
+            case SML_TMO_MOVIAL_CAT_N:
+                kal_mem_cpy((pData+len), (kal_uint8 *)&(pObj->code_cat_n[0]), sizeM);
+                len += sizeM;
+                break;
+
+            case SML_TMO_MOVIAL_CAT_NS:
+                kal_mem_cpy((pData+len), (kal_uint8 *)&(pObj->code_cat_ns[0]), sizeN);
+                len += sizeN;
+                break;
+
+            case SML_TMO_MOVIAL_CAT_SP:
+                kal_mem_cpy((pData+len), (kal_uint8 *)&(pObj->code_cat_sp[0]), sizeP);
+                len += sizeP;
+                break;
+
+            default:
+                break;
+        }
+    }
+
+    *pLen = len;
+    sml_Dump("re-construct blob", pData, len);
+
+    return pData;
+}
+
+kal_bool sml_tmo_movial_checkValidity(void *pObj, kal_uint8 source, kal_uint8 *error_cause)
+{
+    sml_tmo_movial_sim_lock_context_struct *pSmlObj = (sml_tmo_movial_sim_lock_context_struct *) pObj;
+    kal_uint8 *pData = NULL;
+    kal_bool result = KAL_FALSE;
+    kal_uint32 data_len;
+
+    if (sml_tmo_movial_ValidateIMEI(pSmlObj->imei, KAL_FALSE, source) == KAL_FALSE)
+    {
+        *error_cause = SML_TMO_MOVIAL_SLB_ERR_IMEI_MISMATCH;
+        return KAL_FALSE;
+    }
+
+    if (pSmlObj == NULL)
+    {
+        *error_cause = SML_TMO_MOVIAL_SLB_ERR_GENERIC;
+        return KAL_FALSE;
+    }
+
+#ifdef UNIT_TEST
+    *error_cause = SML_TMO_MOVIAL_SLB_ERR_SUCCESS;
+    return KAL_TRUE;
+#endif /* UNIT_TEST */
+
+    pData = sml_tmo_movial_ReconstructBlob(pSmlObj, &data_len, error_cause);
+
+    if (pData == NULL)
+    {
+        *error_cause = SML_TMO_MOVIAL_SLB_ERR_GENERIC;
+        return KAL_FALSE;
+    }
+
+    if (pSmlObj->protection_algorithm == SML_TMO_MOVIAL_PROTECTION_SCHEME_RSA2048)
+    {
+        TYPE_CUST_CHL_KEY key_handle = CUST_TM_PUB_KEY2;
+        t_cust_chl_asym_key key;
+        kal_uint32 ret;
+        kal_uint8 key_index = sbp_query_md_feature_data_by_ps(SBP_TMO_MOVIAL_SELECT_KEY_SET, source);
+
+		custom_tmo_movial_rsu_get_pub_key_handle(key_index, NULL, &key_handle);
+		ret = CustCHL_Get_Asym_Key(key_handle, &key);
+        if (ret == CUST_CHL_ERROR_NONE)
+        {
+            ret = CustCHL_Verify_PSS_Signature(CUST_CHL_ALG_RSA_PSS_SHA256, pData, data_len,
+                                               &pSmlObj->signature[0], &key);
+
+            MD_TRC_INFO_SMU_RSA_PSS_VERIFY_SIGNATURE_CUST(ret);
+        }
+        result = (ret == CUST_CHL_ERROR_NONE) ? KAL_TRUE : KAL_FALSE;
+    }
+    else
+    {
+        result = KAL_FALSE;
+    }
+
+    if (KAL_TRUE == result)
+    {
+        *error_cause = SML_TMO_MOVIAL_SLB_ERR_SUCCESS;
+    }
+    else
+    {
+        *error_cause = SML_TMO_MOVIAL_SLB_ERR_VERIFY_FAIL;
+    }
+
+    free_ctrl_buffer(pData);
+
+    return result;
+}
+
+void sml_tmo_movial_Load(void *pLid, kal_uint8 source)
+{
+    nvram_ef_sml_tmo_movial_sim_lock_obj_struct *p = &pSMLTMMg[source];
+
+    /* Clean the old ones */
+    (*p->destory)(source);
+
+    /* Load the new one */
+    (*p->give)(pLid, source);
+
+}
+
+void sml_tmo_movial_FirstLoad(void *pLid, kal_uint8 source)
+{
+    nvram_ef_sml_tmo_movial_sim_lock_obj_struct *p = &pSMLTMMg[source];
+    nvram_sml_tmo_movial_sim_lock_context_struct *pSmlObj = NULL;
+#ifdef __TMO_RSU_OTP__
+    kal_bool is_default_blob = KAL_FALSE;
+#endif /* __TMO_RSU_OTP__ */
+
+    pSmlObj = (nvram_sml_tmo_movial_sim_lock_context_struct *) pLid;
+    // Allow UE default IMEI (e.g. under factory procedure) in validate check
+    if (KAL_FALSE == sml_tmo_movial_ValidateIMEI(pSmlObj->imei, KAL_TRUE, source))
+    {
+    #ifdef __TMO_RSU_OTP__
+        is_default_blob = custom_check_is_default_tmo_blob(&(pSmlObj->imei[0]));
+        if (KAL_TRUE == is_default_blob)
+        {
+            kal_uint8 imei_bcd[8+1] = {0};
+            kal_uint8 rec_id = 1 + l4c_gemini_get_actual_sim_id(source);
+            
+            if (nvram_get_imei_value(8, imei_bcd, rec_id) == KAL_TRUE)
+            {
+                kal_uint8 imei_ascii[16 + 1] = {0};
+                imei_bcd[7] = imei_bcd[7] & 0x0f;
+                imei_bcd[8] = 0xff;
+                convert_to_digit((kal_uint8 *)imei_bcd, imei_ascii);
+                MD_TRC_INFO_SML_TMO_RSU_COPY_IMEI();
+                kal_mem_cpy(&(pSmlObj->imei[0]), imei_ascii, SML_TMO_MOVIAL_BLOB_IMEI_SIZE);
+            }
+        }
+        else
+    #endif /* __TMO_RSU_OTP__ */
+        {
+            /* This can hit when BLOB/device IMEI is corrupted or hacked,
+             * hence ASSERT
+             */
+            MD_TRC_WARNING_SML_CHECK_IMEI_FAILED();
+            // ASSERT(0);
+        }
+    }
+    
+	/* Clean the old ones */
+	(*p->destory)(source);
+
+	/* Load the new one */
+	(*p->give)((void *)pSmlObj, source);
+    
+#ifdef __TMO_RSU_OTP__
+    if (KAL_TRUE == is_default_blob)
+    {
+        smu_nvram_write(NVRAM_EF_L4_SML_TMO_MOVIAL_SIM_LOCK_LID,        
+                          SML_TMO_MOVIAL_NVRAM_ACCESS_ID_UPDATE_SLB, KAL_FALSE);
+    }
+#endif /* __TMO_RSU_OTP__ */
+
+    return;
+}
+
+
+/*******************************************************************************
+ * FUNCTION  
+ *  sml_tmo_movial_Save
+ * DESCRIPTION
+ *  This function saves the SML obj to NVRAM LID
+ * PARAMETERS
+ *  OUT          pLid
+ * RETURN
+ *  kal_uint16  Obj size
+ * GLOBALS AFFECTED
+ *  SMLTMMOBJ
+ *******************************************************************************/ 
+kal_uint16 sml_tmo_movial_Save(void *pLid, kal_uint8 source)
+{
+    nvram_ef_sml_tmo_movial_sim_lock_obj_struct *p = &pSMLTMMg[source];
+
+    kal_uint16 length = sizeof(sml_tmo_movial_sim_lock_context_struct);
+
+    (*p->take)(pLid, source);
+
+    return length;
+}
+
+/*******************************************************************************
+ * FUNCTION
+ *  sml_tmo_movial_CheckTempUnlock
+ * DESCRIPTION
+ *  This method is to check if temporary unlock expires
+ * PARAMETERS
+ *  IN          source
+ * RETURN
+ *  TRUE        Temporary unlock expires
+ *  FALSE       Temporary unlock does not expire
+ * GLOBALS AFFECTED
+ *  SMLTMMOBJ
+ *******************************************************************************/
+kal_bool sml_tmo_movial_CheckTempUnlock(kal_uint8 source)
+{
+    nvram_ef_sml_tmo_movial_sim_lock_obj_struct *p = &pSMLTMMg[source];
+    kal_uint8 *lock_operation, *unlock_duration;
+    kal_uint16 length;
+    kal_uint32 duration_seconds = 0;
+    kal_uint8 i;
+
+    lock_operation = (kal_uint8 *)(*p->getItem)(SML_TMO_MOVIAL_CAT_NULL, SML_TMO_MOVIAL_CAT_LOCK_OPERATION, &length, source);
+    unlock_duration = (kal_uint8 *)(*p->getItem)(SML_TMO_MOVIAL_CAT_NULL, SML_TMO_MOVIAL_CAT_UNLOCK_DURATION, &length, source);
+
+    for (i = 0; i < SML_TMO_MOVIAL_SIZE_OF_UNLOCK_DURATION-1; i++)
+    {
+        duration_seconds += unlock_duration[i];
+        duration_seconds = (duration_seconds << 8);
+    }
+    duration_seconds += unlock_duration[SML_TMO_MOVIAL_SIZE_OF_UNLOCK_DURATION-1];
+
+    MD_TRC_INFO_SML_CHECK_TEMP_UNLOCK(sml_tmo_movial_seconds_to_expire, duration_seconds);
+
+    if ((sml_tmo_movial_seconds_to_expire + (SML_TMO_MOVIAL_TIMEOUT_PERIODIC_CHECK/KAL_TICKS_1_SEC)) >= duration_seconds)
+    {
+        *lock_operation = SML_TMO_MOVIAL_STATE_PERMANENT_LOCK;
+        // Should reset SLB/NVRAM in following action
+        return KAL_TRUE;
+    }
+    else
+    {
+        sml_tmo_movial_seconds_to_expire += (SML_TMO_MOVIAL_TIMEOUT_PERIODIC_CHECK/KAL_TICKS_1_SEC);
+        (*p->putItem)(SML_TMO_MOVIAL_CAT_NULL, SML_TMO_MOVIAL_CAT_UNLOCK_TIME_COUNTER, &sml_tmo_movial_seconds_to_expire, &length, source);
+        // Should write back to NVRAM in following action
+        return KAL_FALSE;
+    }
+}
+
+
+/*******************************************************************************
+ * FUNCTION
+ *  sml_tmo_movial_Catcode
+ * DESCRIPTION
+ *  This function is used to compose the code of each category
+ * PARAMETERS
+ *  IN          cat
+ *  IN          *imsi
+ *  IN          *gid1
+ *  IN          mnc_len
+ *  OUT          *code
+ * RETURN
+ *  kal_uint8   code length
+ * GLOBALS AFFECTED
+ *  NONE
+ *******************************************************************************/
+kal_uint8 sml_tmo_movial_Catcode( sml_tmo_movial_cat_enum cat,
+                                  kal_uint8 *imsi,
+                                  kal_uint8 *gid1,
+                                  kal_uint8 mnc_len,
+                                  kal_uint8 *code)
+{
+    if(mnc_len == 3)
+    {
+        code[0] = ((imsi[1] & 0xF0) >> 4) + RMMI_CHAR_0;
+        code[1] = (imsi[2] & 0x0F) + RMMI_CHAR_0;
+        code[2] = ((imsi[2] & 0xF0) >> 4) + RMMI_CHAR_0;
+        code[3] = (imsi[3] & 0x0F) + RMMI_CHAR_0;
+        code[4] = ((imsi[3] & 0xF0) >> 4) + RMMI_CHAR_0;
+        code[5] = (imsi[4] & 0x0F) + RMMI_CHAR_0;
+        code[6] = ((imsi[4] & 0xF0) >> 4) + RMMI_CHAR_0;
+        code[7] = (imsi[5] & 0x0F) + RMMI_CHAR_0;
+    }
+    else
+    {
+        code[0] = ((imsi[1] & 0xF0) >> 4) + RMMI_CHAR_0;
+        code[1] = (imsi[2] & 0x0F) + RMMI_CHAR_0;
+        code[2] = ((imsi[2] & 0xF0) >> 4) + RMMI_CHAR_0;
+        code[3] = (imsi[3] & 0x0F) + RMMI_CHAR_0;
+        code[4] = ((imsi[3] & 0xF0) >> 4) + RMMI_CHAR_0;
+        code[5] = RMMI_CHAR_F; // MNC length is 2, so the 3rd digit will be 'F'
+        code[6] = (imsi[4] & 0x0F) + RMMI_CHAR_0;
+        code[7] = ((imsi[4] & 0xF0) >> 4) + RMMI_CHAR_0;
+    }
+
+    switch(cat)
+    {
+        case SML_TMO_MOVIAL_CAT_N:
+            return SML_TMO_MOVIAL_BLOB_SIZE_OF_CAT_N;
+            break;
+
+        case SML_TMO_MOVIAL_CAT_NS:
+            return SML_TMO_MOVIAL_BLOB_SIZE_OF_CAT_NS;
+            break;
+
+        case SML_TMO_MOVIAL_CAT_SP:
+            if(gid1 != NULL)
+            {
+                code[6] = gid1[0]; // + RMMI_CHAR_0
+                return SML_TMO_MOVIAL_BLOB_SIZE_OF_CAT_SP;
+            }
+            break;
+
+        default:
+            break;
+    }
+
+    return 0;
+}
+
+
+/*******************************************************************************
+ * FUNCTION
+ *  sml_tmo_movial_GetCode
+ * DESCRIPTION
+ *  This function is used to compose the code of each category  whether
+ *  mnc length is 2 or 3
+ * PARAMETERS
+ *  cat         [IN]    category of the SIM-ME-Lock
+ *  imsi        [IN]    imsi of the code source 
+ *  gid1        [IN]    gid1 of the code source
+ *  sim_mnc_len [IN]    the mnc length decided by SIM
+ *  pdata       [IN]    the saved code for comparing
+ *  code        [OUT]   the composed code according to all input parameters
+ *
+ * RETURN
+ *  kal_uint8
+ * GLOBALS AFFECTED
+ *  SMLTMMOBJ
+ *******************************************************************************/
+kal_uint8 sml_tmo_movial_GetCode( sml_tmo_movial_cat_enum cat,
+                                  kal_uint8 * imsi,
+                                  kal_uint8 * gid1,
+                                  kal_uint8 sim_mnc_len,
+                                  kal_uint8 * pdata,
+                                  kal_uint8 * code)
+{
+    kal_uint8 mnc_len=0;
+
+    if (SML_MNC_LENGTH_NEST == 1)
+    {
+        mnc_len = sim_mnc_len;
+    }
+    else
+    {
+        if((*(pdata+5)) == 0x46 /* 'F' */)
+        {
+            mnc_len = 2;
+        }
+        else
+        {
+            mnc_len = 3;
+        }
+    }
+
+    return sml_tmo_movial_Catcode(cat, imsi, gid1, mnc_len, code);
+}
+
+
+/*******************************************************************************
+ * FUNCTION
+ *  sml_tmo_movial_Check
+ * DESCRIPTION
+ *  This function is used to check if the code is in the Pass list
+ * PARAMETERS
+ *  IN          cat
+ *  IN          *imsi
+ *  IN          *gid1
+ *  IN          sim_mnc_len
+ *  IN          source
+ * RETURN
+ *  kal_bool
+ * GLOBALS AFFECTED
+ *  SMLTMMOBJ
+ *******************************************************************************/
+kal_bool sml_tmo_movial_Check( sml_tmo_movial_cat_enum cat,     // category
+                               kal_uint8 *imsi,                 // 9 bytes array, read from SIM, mandatory file
+                               kal_uint8 *gid1,                 // 20 bytes array, read from SIM, NULL means gid1 invalid(file not exist)
+                               kal_uint8 sim_mnc_len,           // MNC length, read from SIM
+                               kal_uint8 source)                // 0:SIM1, 1:SIM2
+{
+    nvram_ef_sml_tmo_movial_sim_lock_obj_struct *p = &pSMLTMMg[source];
+    sml_tmo_movial_blob_meta_struct *meta = NULL;
+    kal_uint8 *pdata = NULL;
+    kal_uint8 idx = 0;
+    kal_uint16 length = 0, offset = 0;
+    kal_bool result = KAL_FALSE;
+    kal_uint8 code_len = 0;
+    kal_uint8 code[10] = {0x00};
+    kal_uint8 size_of_cat = 0;
+
+    meta = (sml_tmo_movial_blob_meta_struct *) (*p->getItem)(cat, SML_TMO_MOVIAL_CAT_META, &length, source);
+    pdata = (kal_uint8 *) (*p->getItem)(cat, SML_TMO_MOVIAL_CAT_CODE, &length, source);
+
+
+    if ((meta->cat_lock == SML_TMO_MOVIAL_CAT_UNLOCKED) || (meta->num == 0))
+    {
+         return KAL_TRUE;
+    }
+
+    switch(cat)
+    {
+        case SML_TMO_MOVIAL_CAT_N:
+        {
+            size_of_cat = SML_TMO_MOVIAL_BLOB_SIZE_OF_CAT_N;
+            break;
+        }
+        case SML_TMO_MOVIAL_CAT_NS:
+        {
+            size_of_cat = SML_TMO_MOVIAL_BLOB_SIZE_OF_CAT_NS;
+            break;
+        }
+        case SML_TMO_MOVIAL_CAT_SP:
+        {
+            size_of_cat = SML_TMO_MOVIAL_BLOB_SIZE_OF_CAT_SP;
+            break;
+        }
+        default:
+            break;
+    }
+
+    for (idx = 0; idx < meta->num; idx++)
+    {
+        offset = idx * size_of_cat;
+        code_len = sml_tmo_movial_GetCode(cat,
+                                          imsi,
+                                          gid1,
+                                          sim_mnc_len,
+                                          (pdata+offset),
+                                          code);
+
+        if (size_of_cat == code_len)
+        {
+            if (kal_mem_cmp(code, (pdata+offset), code_len) == 0)
+            {
+                result = KAL_TRUE;
+                break;
+            }
+        }
+    }
+
+    return result;
+}
+
+
+/*******************************************************************************
+ * FUNCTION
+ *  sml_tmo_movial_UpdateNwTimeAndCheckTempLock
+ * DESCRIPTION
+ *  This method is to update newtork time and check if temporary lock expires
+ * PARAMETERS
+ *  IN          source
+ *  IN          nw_time_zone
+ *  IN          nw_time
+ * RETURN
+ *  TRUE        Temporary unlock expires
+ *  FALSE       Temporary unlock does not expire
+ * GLOBALS AFFECTED
+ *  SMLOBJ
+ *******************************************************************************/
+kal_bool sml_tmo_movial_UpdateNwTimeAndCheckTempLock(kal_uint8 source, kal_uint8 nw_time_zone, nw_time_zone_time_struct *nw_time)
+{
+    nvram_ef_sml_tmo_movial_sim_lock_obj_struct *p = &pSMLTMMg[source];
+    kal_uint8 *start_time, *unlock_duration;
+    kal_uint8 *lock_operation = NULL;
+    kal_uint16 length;
+    kal_uint32 current_seconds = 0;
+    kal_uint64 start_seconds = 0;
+    kal_uint32 start_seconds_u32 = 0;
+    kal_uint32 duration_seconds = 0;
+    kal_uint8 i;
+
+    lock_operation = (kal_uint8 *)(*p->getItem)(SML_TMO_MOVIAL_CAT_NULL, SML_TMO_MOVIAL_CAT_LOCK_OPERATION, &length, source);
+    start_time = (kal_uint8 *)(*p->getItem)(SML_TMO_MOVIAL_CAT_NULL, SML_TMO_MOVIAL_CAT_START_TIME, &length, source);
+    unlock_duration = (kal_uint8 *)(*p->getItem)(SML_TMO_MOVIAL_CAT_NULL, SML_TMO_MOVIAL_CAT_UNLOCK_DURATION, &length, source);
+
+    if (*lock_operation != SML_TMO_MOVIAL_STATE_TEMPORARY_UNLOCK)
+    {
+        return KAL_FALSE;
+    }
+
+    /* calculate start time and duration in seconds */
+    start_seconds = 0;
+    for (i = 0; i < SML_TMO_MOVIAL_SIZE_OF_START_TIME-1; i++)
+    {
+        start_seconds += start_time[i];
+        start_seconds = (start_seconds << 8);
+    }
+    start_seconds += start_time[SML_TMO_MOVIAL_SIZE_OF_START_TIME-1];
+    start_seconds /= 1000;    /* from milliseconds to seconds */
+
+    start_seconds_u32 = (kal_uint32)start_seconds;
+
+    duration_seconds = 0;
+    for (i = 0; i < SML_TMO_MOVIAL_SIZE_OF_UNLOCK_DURATION-1; i++)
+    {
+        duration_seconds += unlock_duration[i];
+        duration_seconds = (duration_seconds << 8);
+    }
+    duration_seconds += unlock_duration[SML_TMO_MOVIAL_SIZE_OF_UNLOCK_DURATION-1];
+
+    /* calculate current time in seconds */
+    current_seconds = sml_rsu_nwTimeToSeconds(nw_time_zone, nw_time);
+
+    MD_TRC_INFO_SML_TEMP_UNLOCK_TIME(start_seconds_u32, duration_seconds, current_seconds);
+
+    if (current_seconds >= (start_seconds_u32 + duration_seconds))
+    {
+        MD_TRC_INFO_SML_NW_TIME_EXPIRED();
+        return KAL_TRUE;
+    }
+    else
+    {
+        /* update unlock time for power off accuracy: start ---> unlock time ---> NITZ ---> power off/on ---> end */
+        sml_tmo_movial_seconds_to_expire = current_seconds - start_seconds_u32;
+        (*p->putItem)(SML_TMO_MOVIAL_CAT_NULL, SML_TMO_MOVIAL_CAT_UNLOCK_TIME_COUNTER, &sml_tmo_movial_seconds_to_expire, &length, source);
+        smu_nvram_write(NVRAM_EF_L4_SML_TMO_MOVIAL_SIM_LOCK_LID, SML_TMO_MOVIAL_NVRAM_ACCESS_ID_UNLOCK_EXPIRE, KAL_FALSE);
+
+        return KAL_FALSE;
+    }
+}
+
+
+/*******************************************************************************
+ * FUNCTION
+ *  sml_tmo_movial_Verify
+ * DESCRIPTION
+ *  This function is used to verify the SML lock keys
+ * PARAMETERS
+ *  void
+ * RETURN
+ *  kal_bool    result
+ * GLOBALS AFFECTED
+ *  SMLTMMOBJ
+ *******************************************************************************/
+kal_bool sml_tmo_movial_Verify(sml_tmo_movial_cat_enum cat,
+                               kal_uint8 * key,
+                               kal_uint8 len,
+                               kal_uint8 source)
+{
+    nvram_ef_sml_tmo_movial_sim_lock_obj_struct *p = &pSMLTMMg[source];
+    sml_tmo_movial_blob_key_struct *catkey = NULL;
+    sml_tmo_movial_blob_meta_struct *meta = NULL;
+    kal_bool result = KAL_FALSE;
+    kal_uint16 length = 0;
+    kal_uint16 plength = 0;
+    kal_uint8 i = 0;
+    kal_uint32 blob_iter_count = 0;
+
+    catkey = (sml_tmo_movial_blob_key_struct *) (*p->getItem)(cat, SML_TMO_MOVIAL_CAT_KEY, &length, source);
+    meta = (sml_tmo_movial_blob_meta_struct *) (*p->getItem)(cat, SML_TMO_MOVIAL_CAT_META, &plength, source);
+    
+    for (i = 0; i < SML_TMO_MOVIAL_BLOB_ITERATION_COUNT_SIZE-1; i++)
+    {
+        blob_iter_count += catkey->iteration_count[i];
+        blob_iter_count = (blob_iter_count << 8);
+    }
+    blob_iter_count += catkey->iteration_count[SML_TMO_MOVIAL_BLOB_ITERATION_COUNT_SIZE-1];
+
+    if (blob_iter_count != 0)    /* blob has valid key data */
+    {
+        kal_uint32 verify_result = 0;
+
+        verify_result = cust_sec_hck_verify(TYPE_HCK_PBKDF2_HMAC_SHA256_SALT128,
+                                            (kal_char *)key, (kal_uint32)len,
+                                            catkey->salt,
+                                            blob_iter_count,
+                                            catkey->hck);
+
+        if (verify_result == ERR_SEC_CHECK_HCK_SUCCESS)
+        {
+            result = KAL_TRUE;
+        }
+    }
+
+    if (result == KAL_TRUE)
+    {
+        MD_TRC_INFO_SML_KEY_VERIFY_PASS_INFO_CUST();
+
+        /* Local unlock success; Unlock device permanently */
+        meta->cat_lock = SML_TMO_MOVIAL_CAT_UNLOCKED;
+        smu_nvram_write(NVRAM_EF_L4_SML_TMO_MOVIAL_SIM_LOCK_LID, SML_TMO_MOVIAL_NVRAM_ACCESS_ID_UPDATE_CAT_LOCK, KAL_FALSE);
+    }
+    else
+    {
+        MD_TRC_INFO_SML_KEY_VERIFY_FAIL_INFO_CUST();
+    }
+
+    return result;
+}
+
+
+kal_uint8 sml_tmo_movial_update_slb(void *blob, kal_uint8 source)
+{
+    kal_uint8 *psmlBlob = NULL;
+    kal_uint8 error_cause = SML_TMO_MOVIAL_SLB_ERR_GENERIC;
+    sml_tmo_movial_sim_lock_context_struct *pBlob = (sml_tmo_movial_sim_lock_context_struct *)blob;
+
+    if (NULL == pBlob)
+    {
+        MD_TRC_INFO_SML_TMO_RSU_EMPTY_BLOB();
+        return SML_TMO_MOVIAL_SLB_ERR_BLOB_TOO_SHORT;
+    }
+
+    if (KAL_FALSE == sml_tmo_movial_checkValidity(pBlob, source, &error_cause))
+    {
+        MD_TRC_INFO_SML_TMO_RSU_BLOB_VALIDITY_FAIL();
+        return error_cause;
+    }
+
+    psmlBlob = sml_tmo_movial_ConstructSmlBlob((sml_tmo_movial_sim_lock_context_struct *)pBlob, source);
+
+    if (NULL != psmlBlob)
+    {
+        sml_tmo_movial_Load(psmlBlob, source);
+        free_ctrl_buffer(psmlBlob);
+        error_cause = SML_TMO_MOVIAL_SLB_ERR_SUCCESS;
+    }
+
+    return error_cause;
+}
+
+
+/*******************************************************************************
+ * FUNCTION
+ *  sml_tmm_GetLockState
+ * DESCRIPTION
+ *  This method is used to get SLB lock state
+ * PARAMETERS
+ *  OUT       lock state
+ *  IN          source
+ * RETURN
+ *  void
+ * GLOBALS AFFECTED
+ *  none
+ *******************************************************************************/
+void sml_tmm_GetLockState(kal_uint8 *lock_state, kal_uint8 source)
+{
+    nvram_ef_sml_tmo_movial_sim_lock_obj_struct *p = &pSMLTMMg[source];
+    kal_uint16 length;
+    kal_uint8 *slb_state;
+
+    slb_state = (kal_uint8 *)(*p->getItem)(SML_TMO_MOVIAL_CAT_NULL, SML_TMO_MOVIAL_CAT_LOCK_OPERATION, &length, source);
+
+    kal_mem_cpy(lock_state, slb_state, 1);
+}
+
+
+/*******************************************************************************
+ * FUNCTION
+ *  sml_tmm_GetUnlockTimeLeft
+ * DESCRIPTION
+ *  This method is used to get SLB unlock time left in seconds
+ * PARAMETERS
+ *  IN          source
+ * RETURN
+ *  unlock time left
+ * GLOBALS AFFECTED
+ *  none
+ *******************************************************************************/
+kal_uint32 sml_tmm_GetUnlockTimeLeft(kal_uint8 source)
+{
+    nvram_ef_sml_tmo_movial_sim_lock_obj_struct *p = &pSMLTMMg[source];
+    kal_uint16 length;
+    kal_uint8 *slb_end_time;
+    kal_uint32 duration_seconds = 0;
+    kal_uint8 i;
+
+    slb_end_time = (kal_uint8 *)(*p->getItem)(SML_TMO_MOVIAL_CAT_NULL, SML_TMO_MOVIAL_CAT_UNLOCK_DURATION, &length, source);
+
+    for (i = 0; i < (SML_TMO_MOVIAL_SIZE_OF_UNLOCK_DURATION - 1); i++)
+    {
+        duration_seconds += slb_end_time[i];
+        duration_seconds = (duration_seconds << 8);
+    }
+    duration_seconds += slb_end_time[SML_TMO_MOVIAL_SIZE_OF_UNLOCK_DURATION - 1];
+
+    MD_TRC_INFO_SML_TMO_RSU_GET_UNLOCK_TIME_LEFT(duration_seconds, sml_tmo_movial_seconds_to_expire);
+
+    if (sml_tmo_movial_seconds_to_expire >= duration_seconds)
+    {
+        return 0;
+    }
+    else
+    {
+        return (duration_seconds - sml_tmo_movial_seconds_to_expire);
+    }
+}
+
+
+/*******************************************************************************
+ * FUNCTION
+ *  sml_tmo_movial_ConstructFirstBlob
+ * DESCRIPTION
+ *  This function construct full size Bolb (internal NV structure) from a variant length Blob received from AP
+ * PARAMETERS
+ *  IN          *pObj
+ *  OUT         pLen
+ * RETURN
+ *  kal_uint8 * construct data
+ * GLOBALS AFFECTED
+ *  SMLTMMOBJ
+ *******************************************************************************/
+kal_uint8 *sml_tmo_movial_ConstructFirstBlob(kal_uint8 *pObj, kal_uint16 slb_len, kal_uint8 source)
+{
+    kal_uint16 sizeM, sizeN, sizeP;
+    kal_uint16 length = 0;
+    kal_uint16 idx;
+    sml_tmo_movial_sim_lock_context_struct *pBlob;
+    kal_uint8 cat_idx = 0;
+
+    MD_TRC_FUNC_SML_TMO_MOVIAL_CONSTRUCTFIRSTBLOB();
+
+    pBlob = (sml_tmo_movial_sim_lock_context_struct *)get_ctrl_buffer(SML_TMO_MOVIAL_MAX_BLOB_SIZE);
+    kal_mem_set(pBlob, 0, SML_TMO_MOVIAL_MAX_BLOB_SIZE);
+
+    /* major_version + minor_version + protection_algorithm + lock_operation */
+    pBlob->major_version = pObj[length++];
+    pBlob->minor_version = pObj[length++];
+    pBlob->protection_algorithm = pObj[length++];
+    pBlob->lock_operation = pObj[length++];
+
+    /* imei */
+    kal_mem_cpy(pBlob->imei, &(pObj[length]), SML_TMO_MOVIAL_BLOB_IMEI_SIZE);
+    length += SML_TMO_MOVIAL_BLOB_IMEI_SIZE;
+
+    /* time stamp */
+    kal_mem_cpy(pBlob->time_stamp, &(pObj[length]), SML_TMO_MOVIAL_BLOB_TIME_STAMP_SIZE);
+    length += SML_TMO_MOVIAL_BLOB_TIME_STAMP_SIZE;
+
+    /* Temporary unlock start timer */
+    kal_mem_cpy(pBlob->start_time, &(pObj[length]), SML_TMO_MOVIAL_SIZE_OF_START_TIME);
+    length += SML_TMO_MOVIAL_SIZE_OF_START_TIME;
+
+    /* Temporary unlock duration */
+    kal_mem_cpy(pBlob->unlock_duration, &(pObj[length]), SML_TMO_MOVIAL_SIZE_OF_UNLOCK_DURATION);
+    length += SML_TMO_MOVIAL_SIZE_OF_UNLOCK_DURATION;
+
+    /* length */
+    kal_mem_cpy(pBlob->length, &(pObj[length]), SML_TMO_MOVIAL_BLOB_LENGTH_SIZE);
+    length += SML_TMO_MOVIAL_BLOB_LENGTH_SIZE;
+
+    if (pBlob->protection_algorithm >= SML_TMO_MOVIAL_PROTECTION_SCHEME_SIZE)
+    {
+        free_ctrl_buffer(pBlob);
+        return NULL;
+    }
+
+    if (sml_tmo_movial_ValidateIMEI(pBlob->imei, KAL_FALSE, source) == KAL_FALSE)
+    {
+        MD_TRC_WARNING_SML_CHECK_IMEI_FAILED();
+    }
+
+    idx = length;
+
+    for (cat_idx = SML_TMO_MOVIAL_CAT_N ; cat_idx < SML_TMO_MOVIAL_CAT_SIZE ; cat_idx++)
+    {
+        pBlob->cat[cat_idx].change_flag = pObj[idx++];
+
+        /* iteration_count, salt, hck */
+        kal_mem_cpy(pBlob->key[cat_idx].iteration_count, &(pObj[idx]), SML_TMO_MOVIAL_BLOB_ITERATION_COUNT_SIZE);
+        idx += SML_TMO_MOVIAL_BLOB_ITERATION_COUNT_SIZE;
+        
+        kal_mem_cpy(pBlob->key[cat_idx].salt, &(pObj[idx]), SML_TMO_MOVIAL_BLOB_SALT_SIZE);
+        idx += SML_TMO_MOVIAL_BLOB_SALT_SIZE;
+
+        kal_mem_cpy(pBlob->key[cat_idx].hck, &(pObj[idx]), SML_TMO_MOVIAL_BLOB_HCK_SIZE);
+        idx += SML_TMO_MOVIAL_BLOB_HCK_SIZE;
+
+        /* check m,n,p */
+        if (pObj[idx] > 0)
+        {
+            switch (cat_idx)
+            {
+                case SML_TMO_MOVIAL_CAT_N:
+                    sizeM = pObj[idx] * SML_TMO_MOVIAL_BLOB_SIZE_OF_CAT_N;
+                    if (sizeM > SML_TMO_MOVIAL_BLOB_CAT_N_SIZE)
+                    {
+                        free_ctrl_buffer(pBlob);
+                        return NULL;
+                    }
+
+                    pBlob->cat[cat_idx].num = pObj[idx++];
+                    kal_mem_cpy(pBlob->code_cat_n, &(pObj[idx]), sizeM);
+                    idx += sizeM;
+                    break;
+
+                case SML_TMO_MOVIAL_CAT_NS:
+                    sizeN = pObj[idx] * SML_TMO_MOVIAL_BLOB_SIZE_OF_CAT_NS;
+                    if (sizeN > SML_TMO_MOVIAL_BLOB_CAT_NS_SIZE)
+                    {
+                        free_ctrl_buffer(pBlob);
+                        return NULL;
+                    }
+
+                    pBlob->cat[cat_idx].num = pObj[idx++];
+                    kal_mem_cpy(pBlob->code_cat_ns, &(pObj[idx]), sizeN);
+                    idx += sizeN;
+                    break;
+
+                case SML_TMO_MOVIAL_CAT_SP:
+                    sizeP = pObj[idx] * SML_TMO_MOVIAL_BLOB_SIZE_OF_CAT_SP;
+                    if (sizeP > SML_TMO_MOVIAL_BLOB_CAT_SP_SIZE)
+                    {
+                        free_ctrl_buffer(pBlob);
+                        return NULL;
+                    }
+
+                    pBlob->cat[cat_idx].num = pObj[idx++];
+                    kal_mem_cpy(pBlob->code_cat_sp, &(pObj[idx]), sizeP);
+                    idx += sizeP;
+                    break;
+
+                default:
+                    break;
+            }
+        }
+        else /* m/n/p = 0 */
+        {
+            /* memset ensures pBlob->cat[cat_idx].num set to 0 */
+            idx += 1;
+        }
+    }
+
+    if (sml_tmo_movial_ValidateConfigData(pBlob) == KAL_FALSE)
+    {
+        free_ctrl_buffer(pBlob);
+        return NULL;
+    }
+
+    kal_mem_cpy(pBlob->signature, &(pObj[idx]), SML_TMO_MOVIAL_BLOB_SIZE_OF_SIGNATURE);
+
+    sml_Dump("constructed blob", (kal_uint8 *)pBlob, SML_TMO_MOVIAL_MAX_BLOB_SIZE);
+
+    return (kal_uint8 *)pBlob;
+}
+
+#ifdef __TMO_RSU_OTP__
+static kal_bool custom_check_is_default_tmo_blob(kal_uint8 *imei)
+{
+    kal_uint8 otp_default_imei[SML_TMO_MOVIAL_BLOB_IMEI_SIZE] = {0x00};
+     
+    if (kal_mem_cmp(&imei[0], &otp_default_imei[0], SML_TMO_MOVIAL_BLOB_IMEI_SIZE) == 0)
+    {
+        return KAL_TRUE;
+    }
+    else
+    {
+        return KAL_FALSE;
+    }
+}
+#endif /* __TMO_RSU_OTP__ */
+
+/*******************************************************************************
+ * FUNCTION  
+ *  custom_check_is_default_imei
+ * DESCRIPTION
+ *  Check if the IMEI is default IMEI
+ * PARAMETERS
+ *  imei       [kal_uint8 *]     
+ * RETURN
+ *  kal_bool
+*******************************************************************************/
+kal_bool custom_check_is_default_imei(kal_uint8 *imei)
+{
+#if defined(__SECURITY_OTP__) && defined(__NVRAM_OTP__)
+    kal_uint8 default_imei_bcd[8] = {0x00};
+#else
+    kal_uint8 default_imei_bcd[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+#endif
+
+    if (NULL == imei)
+    {
+        return KAL_FALSE;
+    }
+    
+    if (kal_mem_cmp(&imei[0], &default_imei_bcd[0], 8) == 0)
+    {
+        return KAL_TRUE;
+    }
+    else 
+    {
+        return KAL_FALSE;
+    }
+}
+
+void custom_tmo_movial_rsu_get_pub_key_handle(kal_uint8 index, 
+                               TYPE_CUST_CHL_KEY *key1, TYPE_CUST_CHL_KEY *key2)
+{
+    TYPE_CUST_CHL_KEY pub_key_group[][2] = {
+        // Pub Key 1,        Pub Key 2
+        {CUST_TM_PUB_KEY1, CUST_TM_PUB_KEY2}, // index == 0
+        // Add handles of new pub keys sets here 
+    };
+    
+    #define TMO_MOVIAL_KEY_SET_MAX_NUM (sizeof(pub_key_group)/sizeof(pub_key_group[0]))
+    
+    index = index > (TMO_MOVIAL_KEY_SET_MAX_NUM - 1) ? 0 : index;
+    
+    if (NULL != key1)
+    {
+        *key1 = pub_key_group[index][0];
+        MD_TRC_INFO_SML_RSU_PUB_KEY_HANDLE((*key1));
+    }
+    
+    if (NULL != key2)
+    {
+        *key2 = pub_key_group[index][1];
+        MD_TRC_INFO_SML_RSU_PUB_KEY_HANDLE((*key2));
+    }
+
+    return;
+}
+#endif /* L4_NOT_PRESENT */
+#endif /* !defined(__MAUI_BASIC__) */