[Feature]Upload Modem source code

Change-Id: Id4294f30faced84d3e6fd6d5e61e1111bf287a37
diff --git a/mcu/service/mcf/src/mcf_util.c b/mcu/service/mcf/src/mcf_util.c
new file mode 100644
index 0000000..67e15a8
--- /dev/null
+++ b/mcu/service/mcf/src/mcf_util.c
@@ -0,0 +1,3978 @@
+/*****************************************************************************
+*  Copyright Statement:
+*  --------------------
+*  This software is protected by Copyright and the information contained
+*  herein is confidential. The software may not be copied and the information
+*  contained herein may not be used or disclosed except with the written
+*  permission of MediaTek Inc. (C) 2018
+*
+*  BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+*  THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+*  RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON
+*  AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+*  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+*  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+*  NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+*  SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+*  SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH
+*  THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO
+*  NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S
+*  SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM.
+*
+*  BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE
+*  LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+*  AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+*  OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO
+*  MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*
+*  THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE
+*  WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF
+*  LAWS PRINCIPLES.  ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND
+*  RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER
+*  THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC).
+*
+*****************************************************************************/
+
+/*******************************************************************************
+ * Filename:
+ * ---------
+ *   mcf_util.c
+ *
+ * Project:
+ * --------
+ *   UMOLYA
+ *
+ * Description:
+ * ------------
+ *   MD Configuration Framework internal utility.
+ *
+ * Author:
+ * -------
+ * -------
+ *
+ *==============================================================================
+ *                 HISTORY
+ * Below this line, this part is controlled by PVCS VM. DO NOT MODIFY!!
+ *------------------------------------------------------------------------------
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ *------------------------------------------------------------------------------
+ * Upper this line, this part is controlled by PVCS VM. DO NOT MODIFY!!
+ *==============================================================================
+ *******************************************************************************/
+
+#include "kal_public_api.h"
+#include "fs_general_api.h"
+
+#include "mcf_custom.h"
+#include "mcf_defs.h"
+#include "mcf_debug.h"
+#include "mcf_struct.h"
+#include "mcf_util.h"
+#include "mcf_object.h"
+#include "cust_chl_interface.h"
+#include "us_timer.h"
+#include <stdarg.h>
+#include "sleepdrv_interface.h" 
+
+/*------------------------------------------------------------------------------
+ * Global variables.
+ *----------------------------------------------------------------------------*/
+mcf_t               mcf_inst_g;
+kal_enhmutexid      mcf_enhmutex_g = NULL;
+event_scheduler    *mcf_timer_es_g = NULL;
+eventid             mcf_timer_eventid_g = NULL;
+mcf_common_t        com_Mcf;
+kal_enhmutexid      mcf_utfwk_enhmutex_g = NULL;
+mcf_file_info_t     new_file_info;
+mcf_file_info_t     old_file_info;
+
+#undef BOOT_TRC_MSG
+#define BOOT_TRC_MSG(_name,_format) {_format},
+static MCF_BOOT_LOG boot_trace_format[] = 
+{
+    #include "mcf_boot_trace.h"
+};
+
+/*------------------------------------------------------------------------------
+ * Helper macro.
+ *----------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------------
+ * Private data structure.
+ *----------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------------
+ * Private variables.
+  *----------------------------------------------------------------------------*/
+static KAL_ADM_ID mcf_mem_id = NULL;
+static kal_uint8  mcf_mem_pool[MCF_MAX_MEM_MALLOC_SIZE];
+static kal_bool   mcf_mem_init_flag = KAL_FALSE;
+/*------------------------------------------------------------------------------
+ * Private fucntions.
+ *----------------------------------------------------------------------------*/
+extern kal_char* release_verno(void);
+extern kal_char* build_date_time(void);
+/*------------------------------------------------------------------------------
+ * Public fucntions.
+ *----------------------------------------------------------------------------*/
+#if !defined(__HIF_CCCI_SUPPORT__) || !defined(__MTK_TARGET__)
+kal_int32 MCF_dummy_FS_CMPT_Read(const WCHAR * FileName, NVRAM_FS_PARAM_CMPT_T* nvram_param)
+{
+	return FS_NO_ERROR;
+}
+#include <stdio.h>
+#include <windows.h>
+kal_int32 MCF_Win_FS_CMPT_Read(const WCHAR * FileName, NVRAM_FS_PARAM_CMPT_T* nvram_param)
+{
+    char fname[MCF_FILE_MAX_NAME_LEN] = { 0 };
+	char fullpath[MCF_FILE_MAX_MD_PATH_LEN + MCF_FILE_MAX_NAME_LEN] = { 0 };
+    kal_uint32 i = 0;
+    FILE *fd = NULL;
+    if (mcf_utfwk_is_working_status == KAL_TRUE){
+        return FS_NO_ERROR;
+    }
+    
+    // translate wchar to char
+    WCHAR *ptr = FileName; // skip drive "S:"
+    while (*ptr != NULL) {
+        fname[i++] = (char)*ptr;
+        ptr++;
+    }
+	
+	if (GetModuleFileName(NULL, fullpath, MCF_FILE_MAX_MD_PATH_LEN + MCF_FILE_MAX_NAME_LEN) != NULL) {
+		char *pch = strrchr(fullpath, '\\');
+		*(++pch) = 0;
+		strncat(fullpath, fname, MCF_FILE_MAX_MD_PATH_LEN + MCF_FILE_MAX_NAME_LEN - 1);
+	}
+	else {
+		return FS_FILE_NOT_FOUND;
+	}
+    
+    // due to open & close operation are must, so always open & close file (ignore CCCI_FS_CMPT_OPEN & CCCI_FS_CMPT_CLOSE)
+    fd = fopen(fullpath, "rb");
+    if (fd == NULL)
+        return FS_FILE_NOT_FOUND;
+    //get file size
+    if (nvram_param->opid_map & CCCI_FS_CMPT_GETFILESIZE)
+    {
+        fseek(fd, 0, SEEK_END);
+        *nvram_param->FileSize = ftell(fd);
+        fseek(fd, 0, SEEK_SET);
+    }
+    // seek
+    if (nvram_param->opid_map & CCCI_FS_CMPT_SEEK)
+    {
+        fseek(fd, nvram_param->Offset, nvram_param->Whence);
+    }
+    // read
+    if (nvram_param->opid_map & CCCI_FS_CMPT_READ)
+    {
+		if (nvram_param->DataPtr != NULL) {
+			*nvram_param->Read = fread(nvram_param->DataPtr, nvram_param->Length, 1, fd);
+		}
+    }
+    fclose(fd);
+    return FS_NO_ERROR;
+}
+#endif
+
+void mcf_mem_init(void)
+{
+    if (mcf_mem_init_flag == KAL_FALSE)
+    {
+        mcf_mem_id = kal_adm_create((void*)mcf_mem_pool, sizeof(mcf_mem_pool), NULL, KAL_FALSE);
+        mcf_mem_init_flag = KAL_TRUE;
+    }
+}
+
+void *mcf_malloc(unsigned int size)
+{
+    mcf_mem_init();
+    if (NULL != mcf_mem_id) {
+        void *ret = kal_adm_alloc(mcf_mem_id, size);
+        if(ret == NULL)
+        {
+            MCF_BOOT_TRACE(MCF_BOOT_TR_ALLOC_MEM_ERROR);
+            MD_TRC_MCF_TR_ALLOC_MEM_ERROR();
+        }
+        return ret;
+    }
+    return NULL;
+}
+
+void mcf_free(void *ptr)
+{
+    if (NULL == mcf_mem_id) {
+        return;
+    }
+    kal_adm_free(mcf_mem_id, ptr);
+}
+
+void mcf_create_custom_folder(mcf_t *pMcf)
+{
+    kal_wchar   foldername[MCF_FILE_MAX_MD_PATH_LEN] = {0};
+    kal_int32   fs_api_ret;
+
+    kal_wsprintf(foldername, "%s\0", MCF_FS_CUSTOM_FOLDER_PATH);
+    fs_api_ret = FS_CreateDir(foldername);
+    if (fs_api_ret < FS_NO_ERROR) {
+        com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_CREATE_CUSTOM_FOLDER_FAIL;
+        MCF_BOOT_TRACE(MCF_BOOT_TR_CREATE_CUSTOM_FOLDER_FAIL, MCF_FS_CUSTOM_FOLDER_PATH, fs_api_ret);
+    }
+
+    return;
+}
+
+mcf_ota_result_e mcf_read_ota_file(
+    kal_bool                is_booting,
+    kal_char               *req_fs_root_path,
+    kal_char               *req_file_path_name,
+    l4c_mcf_path_type_enum *apply_path_type,
+    kal_char               *apply_filename,
+    mcf_t                  *pMcf)
+{
+    NVRAM_FS_PARAM_CMPT_T   fs_cmpt;
+    FS_FileDetail           fs_file_detail[L4C_MCF_PATH_TYPE_MAX] = {0};
+    kal_uint32              read_byte = 0;
+    kal_uint32              file_size = 0;
+    mcf_ota_result_e        ret = MCF_OTA_R_SUCCESS;
+    mcf_ota_file_t         *ota_file = &(pMcf->ota_file);
+    kal_wchar               filename[MCF_FILE_MAX_MD_PATH_LEN + MCF_FILE_MAX_NAME_LEN];
+    mcf_tool_file_info_t   *pFile;
+    kal_char                password[MCF_MAX_PASSWORD_LEN] = {0};
+    kal_bool                is_get_custom_filename = KAL_FALSE;
+    kal_bool                is_default_path;
+    kal_uint32              dummy_para;
+    kal_int32               fs_api_ret[L4C_MCF_PATH_TYPE_MAX];
+    kal_uint64              last_mod_time = 0;
+    kal_char                default_file_name_tag[30];
+    kal_uint64              ini_path_ota_file_last_mod_time = 0;
+    kal_uint64              ini_path_runtime_file_last_mod_time = 0;
+    kal_char                ini_root_path[20];
+
+    fs_cmpt.opid_map = NVRAM_FS_CMPT_OPEN | NVRAM_FS_CMPT_GETFILESIZE | NVRAM_FS_CMPT_CLOSE;
+    fs_cmpt.Flag = FS_READ_ONLY;
+    fs_cmpt.Length = 0;
+    fs_cmpt.Offset = 0;
+    fs_cmpt.Whence = FS_FILE_BEGIN;
+    fs_cmpt.DataPtr = &dummy_para;
+    fs_cmpt.Read = &dummy_para;
+    fs_cmpt.FileSize = &file_size;
+
+    if ( (strcmp(req_fs_root_path, "") != 0) && (strcmp(req_file_path_name, "") != 0) ) {
+        if (strcmp(req_fs_root_path, MCF_FS_DEFAULT_FOLDER_PATH) == 0) {
+            *apply_path_type = L4C_MCF_PATH_TYPE_OTA;
+        } else if (strcmp(req_fs_root_path, MCF_FS_CUSTOM_FOLDER_PATH) == 0) {
+            *apply_path_type = L4C_MCF_PATH_TYPE_RUNTIME;
+        }else{
+            MD_TRC_MCF_TR_READ_OTA_FILE_INVALID_PATH(req_fs_root_path);
+            ret = MCF_OTA_R_INVALID_PARAMETER;
+
+            return ret;
+        }
+        kal_wsprintf(filename, "%s\\%s\0", req_fs_root_path, req_file_path_name);
+        strncpy(apply_filename, req_file_path_name, MCF_FILE_MAX_NAME_LEN - 1);
+        is_default_path = KAL_FALSE;
+    } else {
+        is_get_custom_filename = mcf_get_custom_file_path_name((kal_uint8 *)apply_path_type, apply_filename);
+        strncpy(default_file_name_tag, "Default_OTA_File_Name", 29);
+        if (is_get_custom_filename == KAL_TRUE) {
+            if (*apply_path_type >= L4C_MCF_PATH_TYPE_MAX || *apply_path_type < 0) {
+                MD_TRC_MCF_TR_READ_OTA_FILE_INVALID_PATH_TYPE(*apply_path_type);
+                ret = MCF_OTA_R_INVALID_PARAMETER;
+
+                return ret;
+            }
+
+            if (*apply_path_type == L4C_MCF_PATH_TYPE_OTA) {
+                kal_wsprintf(filename, "%s\\%s\0", MCF_FS_DEFAULT_FOLDER_PATH, apply_filename);
+            } else if (*apply_path_type == L4C_MCF_PATH_TYPE_RUNTIME) {
+                kal_wsprintf(filename, "%s\\%s\0", MCF_FS_CUSTOM_FOLDER_PATH, apply_filename);
+            }
+        }
+        else {
+            /* Try to read default ota file name in INI file */
+            /* Compare modified time of ini file to select which file to be applied */
+            if(mcf_get_file_last_mod_time (MCF_FS_DEFAULT_INI_FILE_NAME, L4C_MCF_PATH_TYPE_OTA, &ini_path_ota_file_last_mod_time) == MCF_OTA_R_READ_OTA_FILE_FAIL){
+                ini_path_ota_file_last_mod_time = 0;
+                MD_TRC_MCF_TR_READ_OTA_FILE_READ_INI_FILE_FAIL(L4C_MCF_PATH_TYPE_OTA, MCF_OTA_R_READ_OTA_FILE_FAIL);
+                
+                if (mcf_get_file_last_mod_time (MCF_FS_DEFAULT_INI_FILE_NAME, L4C_MCF_PATH_TYPE_RUNTIME, &ini_path_runtime_file_last_mod_time) == MCF_OTA_R_READ_OTA_FILE_FAIL){
+                    ini_path_runtime_file_last_mod_time = 0;
+                    MD_TRC_MCF_TR_READ_OTA_FILE_READ_INI_FILE_FAIL(L4C_MCF_PATH_TYPE_RUNTIME, MCF_OTA_R_READ_OTA_FILE_FAIL);
+                }    
+            }
+
+            if(mcf_get_file_last_mod_time (MCF_FS_DEFAULT_INI_FILE_NAME, L4C_MCF_PATH_TYPE_RUNTIME, &ini_path_runtime_file_last_mod_time) == MCF_OTA_R_READ_OTA_FILE_FAIL){
+                ini_path_runtime_file_last_mod_time = 0;
+                MD_TRC_MCF_TR_READ_OTA_FILE_READ_INI_FILE_FAIL(L4C_MCF_PATH_TYPE_RUNTIME, MCF_OTA_R_READ_OTA_FILE_FAIL);
+                
+                if(mcf_get_file_last_mod_time (MCF_FS_DEFAULT_INI_FILE_NAME, L4C_MCF_PATH_TYPE_OTA, &ini_path_ota_file_last_mod_time) == MCF_OTA_R_READ_OTA_FILE_FAIL){
+                    ini_path_ota_file_last_mod_time = 0;
+                    MD_TRC_MCF_TR_READ_OTA_FILE_READ_INI_FILE_FAIL(L4C_MCF_PATH_TYPE_OTA, MCF_OTA_R_READ_OTA_FILE_FAIL);
+                }
+            }
+
+            kal_mem_set(ini_root_path,0,20);
+            if (ini_path_ota_file_last_mod_time > ini_path_runtime_file_last_mod_time){
+                strncpy(ini_root_path,MCF_FS_DEFAULT_FOLDER_PATH, 19);
+            }else{
+               strncpy(ini_root_path,MCF_FS_CUSTOM_FOLDER_PATH, 19);
+            }
+            if (mcf_read_ini_file(ini_root_path , MCF_FS_DEFAULT_INI_FILE_NAME, apply_path_type, apply_filename, pMcf) == MCF_OTA_R_SUCCESS &&
+                    mcf_find_ini_item((kal_char *)pMcf->ini_file.buff, default_file_name_tag, apply_filename, pMcf) == KAL_TRUE && strcmp(apply_filename, "") != 0) {
+                strncat (apply_filename,".mcfota", MCF_FILE_MAX_NAME_LEN - 1);
+                kal_wsprintf(filename, "%s\\%s\0", MCF_FS_DEFAULT_FOLDER_PATH, apply_filename);
+                MCF_BOOT_TRACE(MCF_BOOT_TR_DO_OTA_FULL_GET_DEFAULT_OTA_FILE_NAME_FROM_INI, apply_filename);
+                
+            }else{
+                kal_wsprintf(filename, "%s\\%s\0", MCF_FS_DEFAULT_FOLDER_PATH, MCF_FS_DEFAULT_OTA_FILE_NAME);
+                strncpy(apply_filename, MCF_FS_DEFAULT_OTA_FILE_NAME, MCF_FILE_MAX_NAME_LEN - 1);
+            }
+            
+            /* Compare modified time of OTA file to select which file to be applied */
+            fs_api_ret[L4C_MCF_PATH_TYPE_OTA] = FS_GetFileDetail(filename, &fs_file_detail[L4C_MCF_PATH_TYPE_OTA]);
+            MD_TRC_MCF_TR_READ_OTA_FILE_MODIFIED_TIME(L4C_MCF_PATH_TYPE_OTA, fs_api_ret[L4C_MCF_PATH_TYPE_OTA],
+                            (kal_uint32)((fs_file_detail[L4C_MCF_PATH_TYPE_OTA].LastStatusChangeTime >> 32) & 0xFFFFFFFF), (kal_uint32)(fs_file_detail[L4C_MCF_PATH_TYPE_OTA].LastStatusChangeTime & 0xFFFFFFFF));
+            if (fs_api_ret[L4C_MCF_PATH_TYPE_OTA] != FS_NO_ERROR) {
+                kal_mem_set(&fs_file_detail[L4C_MCF_PATH_TYPE_OTA], 0, sizeof(FS_FileDetail));
+            }
+            
+            kal_wsprintf(filename, "%s\\%s\0", MCF_FS_CUSTOM_FOLDER_PATH, MCF_FS_DEFAULT_OTA_FILE_NAME);
+            fs_api_ret[L4C_MCF_PATH_TYPE_RUNTIME] = FS_GetFileDetail(filename, &fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME]);
+            MD_TRC_MCF_TR_READ_OTA_FILE_MODIFIED_TIME(L4C_MCF_PATH_TYPE_RUNTIME, fs_api_ret[L4C_MCF_PATH_TYPE_RUNTIME],
+                            (kal_uint32)((fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME].LastStatusChangeTime >> 32) & 0xFFFFFFFF), (kal_uint32)(fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME].LastStatusChangeTime & 0xFFFFFFFF));
+            if (fs_api_ret[L4C_MCF_PATH_TYPE_RUNTIME] != FS_NO_ERROR) {
+                kal_mem_set(&fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME], 0, sizeof(FS_FileDetail));
+            }
+
+            if ( (fs_api_ret[L4C_MCF_PATH_TYPE_OTA] == FS_NO_ERROR) || (fs_api_ret[L4C_MCF_PATH_TYPE_RUNTIME] == FS_NO_ERROR) ) {
+                if (fs_file_detail[L4C_MCF_PATH_TYPE_OTA].LastStatusChangeTime > fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME].LastStatusChangeTime) {
+                    *apply_path_type = L4C_MCF_PATH_TYPE_OTA;
+                    kal_wsprintf(filename, "%s\\%s\0", MCF_FS_DEFAULT_FOLDER_PATH, apply_filename);
+                } else {
+                    *apply_path_type = L4C_MCF_PATH_TYPE_RUNTIME;
+                    kal_wsprintf(filename, "%s\\%s\0", MCF_FS_CUSTOM_FOLDER_PATH, MCF_FS_DEFAULT_OTA_FILE_NAME);
+                }
+            } else {
+                if (is_booting == KAL_TRUE) {
+                    com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_READ_OTA_FILE_FAIL;
+                    MCF_BOOT_TRACE(MCF_BOOT_TR_READ_OTA_FILE_COMPARE_FAIL);
+                }
+                MD_TRC_MCF_TR_READ_OTA_FILE_COMPARE_FAIL();
+                ret = MCF_OTA_R_READ_OTA_FILE_FAIL;
+
+                return ret;
+            }
+            
+        }
+        is_default_path = KAL_TRUE;
+    }
+
+    fs_api_ret[0] = MCF_FS_CMPT_Read(filename, &fs_cmpt);
+    if (fs_api_ret[0] < FS_NO_ERROR) {
+        if (is_booting == KAL_TRUE) {
+            MCF_BOOT_TRACE(MCF_BOOT_TR_READ_OTA_FILE_FAIL, *apply_path_type, fs_api_ret[0]);
+            MCF_BOOT_TRACE(MCF_BOOT_TR_STRING, apply_filename);
+        }
+        MD_TRC_MCF_TR_READ_OTA_FILE_FAIL(*apply_path_type, fs_api_ret[0]);
+        dhl_print_string(TRACE_INFO, DHL_USER_FLAG_NONE, MOD_MCF, apply_filename);
+
+        /* If cannot read given OTA file, read default OTA file */
+        if (is_default_path == KAL_FALSE) {
+            is_get_custom_filename = mcf_get_custom_file_path_name((kal_uint8 *)apply_path_type, apply_filename);
+            if (*apply_path_type >= L4C_MCF_PATH_TYPE_MAX || *apply_path_type < 0) {
+                MD_TRC_MCF_TR_READ_OTA_FILE_INVALID_PATH_TYPE(*apply_path_type);
+                ret = MCF_OTA_R_INVALID_PARAMETER;
+
+                return ret;
+            }
+
+            if (is_get_custom_filename == KAL_TRUE) {
+                if (*apply_path_type == L4C_MCF_PATH_TYPE_OTA) {
+                    kal_wsprintf(filename, "%s\\%s\0", MCF_FS_DEFAULT_FOLDER_PATH, apply_filename);
+                } else if (*apply_path_type == L4C_MCF_PATH_TYPE_RUNTIME) {
+                    kal_wsprintf(filename, "%s\\%s\0", MCF_FS_CUSTOM_FOLDER_PATH, apply_filename);
+                }
+            } else {
+                /* Compare modified time of OTA file to select which file to be applied */
+                kal_wsprintf(filename, "%s\\%s\0", MCF_FS_DEFAULT_FOLDER_PATH, MCF_FS_DEFAULT_OTA_FILE_NAME);
+                fs_api_ret[L4C_MCF_PATH_TYPE_OTA] = FS_GetFileDetail(filename, &fs_file_detail[L4C_MCF_PATH_TYPE_OTA]);
+                MD_TRC_MCF_TR_READ_OTA_FILE_MODIFIED_TIME(L4C_MCF_PATH_TYPE_OTA, fs_api_ret[L4C_MCF_PATH_TYPE_OTA],
+                                (kal_uint32)((fs_file_detail[L4C_MCF_PATH_TYPE_OTA].LastStatusChangeTime >> 32) & 0xFFFFFFFF), (kal_uint32)(fs_file_detail[L4C_MCF_PATH_TYPE_OTA].LastStatusChangeTime & 0xFFFFFFFF));
+                if (fs_api_ret[L4C_MCF_PATH_TYPE_OTA] != FS_NO_ERROR) {
+                    kal_mem_set(&fs_file_detail[L4C_MCF_PATH_TYPE_OTA], 0, sizeof(FS_FileDetail));
+                }
+
+                kal_wsprintf(filename, "%s\\%s\0", MCF_FS_CUSTOM_FOLDER_PATH, MCF_FS_DEFAULT_OTA_FILE_NAME);
+                fs_api_ret[L4C_MCF_PATH_TYPE_RUNTIME] = FS_GetFileDetail(filename, &fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME]);
+                MD_TRC_MCF_TR_READ_OTA_FILE_MODIFIED_TIME(L4C_MCF_PATH_TYPE_RUNTIME, fs_api_ret[L4C_MCF_PATH_TYPE_RUNTIME],
+                                (kal_uint32)((fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME].LastStatusChangeTime >> 32) & 0xFFFFFFFF), (kal_uint32)(fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME].LastStatusChangeTime & 0xFFFFFFFF));
+                if (fs_api_ret[L4C_MCF_PATH_TYPE_RUNTIME] != FS_NO_ERROR) {
+                    kal_mem_set(&fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME], 0, sizeof(FS_FileDetail));
+                }
+
+                if ( (fs_api_ret[L4C_MCF_PATH_TYPE_OTA] == FS_NO_ERROR) || (fs_api_ret[L4C_MCF_PATH_TYPE_RUNTIME] == FS_NO_ERROR) ) {
+                    if (fs_file_detail[L4C_MCF_PATH_TYPE_OTA].LastStatusChangeTime > fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME].LastStatusChangeTime) {
+                        *apply_path_type = L4C_MCF_PATH_TYPE_OTA;
+                        kal_wsprintf(filename, "%s\\%s\0", MCF_FS_DEFAULT_FOLDER_PATH, MCF_FS_DEFAULT_OTA_FILE_NAME);
+                    } else {
+                        *apply_path_type = L4C_MCF_PATH_TYPE_RUNTIME;
+                        kal_wsprintf(filename, "%s\\%s\0", MCF_FS_CUSTOM_FOLDER_PATH, MCF_FS_DEFAULT_OTA_FILE_NAME);
+                    }
+                } else {
+                    if (is_booting == KAL_TRUE) {
+                        com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_READ_OTA_FILE_FAIL;
+                        MCF_BOOT_TRACE(MCF_BOOT_TR_READ_OTA_FILE_COMPARE_FAIL);
+                    }
+                    MD_TRC_MCF_TR_READ_OTA_FILE_COMPARE_FAIL();
+                    ret = MCF_OTA_R_READ_OTA_FILE_FAIL;
+
+                    return ret;
+                }
+ 
+                strncpy(apply_filename, MCF_FS_DEFAULT_OTA_FILE_NAME, MCF_FILE_MAX_NAME_LEN - 1);
+
+            }
+
+            fs_api_ret[0] = MCF_FS_CMPT_Read(filename, &fs_cmpt);
+            if (fs_api_ret[0] < FS_NO_ERROR) {
+                if (is_booting == KAL_TRUE) {
+                    com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_READ_OTA_FILE_FAIL;
+                    MCF_BOOT_TRACE(MCF_BOOT_TR_READ_OTA_FILE_FAIL, *apply_path_type, fs_api_ret[0]);
+                    MCF_BOOT_TRACE(MCF_BOOT_TR_STRING, apply_filename);
+                }
+                MD_TRC_MCF_TR_READ_OTA_FILE_FAIL(*apply_path_type, fs_api_ret[0]);
+                dhl_print_string(TRACE_INFO, DHL_USER_FLAG_NONE, MOD_MCF, apply_filename);
+                ret = MCF_OTA_R_READ_OTA_FILE_FAIL;
+
+                return ret;
+            }
+        } else {
+            ret = MCF_OTA_R_READ_OTA_FILE_FAIL;
+
+            return ret;
+        }
+    }
+
+    if (file_size > MCF_MAX_OTA_FILE_SIZE) {
+        if (is_booting == KAL_TRUE) {
+            com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_OTA_FILE_OVERSIZE;
+            MCF_BOOT_TRACE(MCF_BOOT_TR_READ_OTA_FILE_OVERSIZE, file_size, MCF_MAX_OTA_FILE_SIZE);
+        }
+        MD_TRC_MCF_TR_READ_OTA_FILE_OVERSIZE(file_size, MCF_MAX_OTA_FILE_SIZE);
+        ret = MCF_OTA_R_READ_OTA_FILE_FAIL;
+
+        return ret;
+    }
+
+    /* Read file */
+    fs_cmpt.opid_map = NVRAM_FS_CMPT_OPEN | NVRAM_FS_CMPT_READ | NVRAM_FS_CMPT_CLOSE;
+    fs_cmpt.Flag = FS_READ_ONLY;
+    fs_cmpt.Length = file_size;
+    fs_cmpt.Offset = 0;
+    fs_cmpt.Whence = FS_FILE_BEGIN;
+    fs_cmpt.DataPtr = ota_file->buff;
+    fs_cmpt.Read = &read_byte;
+    fs_cmpt.FileSize = &dummy_para;
+    
+    fs_api_ret[*apply_path_type] = FS_GetFileDetail(filename, &fs_file_detail[*apply_path_type]);
+    MD_TRC_MCF_TR_READ_OTA_FILE_MODIFIED_TIME(*apply_path_type, fs_api_ret[*apply_path_type],
+                     (kal_uint32)((fs_file_detail[*apply_path_type].LastStatusChangeTime >> 32) & 0xFFFFFFFF), (kal_uint32)(fs_file_detail[*apply_path_type].LastStatusChangeTime & 0xFFFFFFFF));
+    if (fs_api_ret[*apply_path_type] == FS_NO_ERROR) {
+        last_mod_time = fs_file_detail[*apply_path_type].LastStatusChangeTime;
+    } else {
+        if (is_booting == KAL_TRUE) {
+            com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_READ_OTA_FILE_FAIL;
+            MCF_BOOT_TRACE(MCF_BOOT_TR_READ_OTA_FILE_FAIL, *apply_path_type, fs_api_ret[*apply_path_type]);
+            MCF_BOOT_TRACE(MCF_BOOT_TR_STRING, apply_filename);
+        }
+        MD_TRC_MCF_TR_READ_OTA_FILE_FAIL(*apply_path_type, fs_api_ret[*apply_path_type]);
+        dhl_print_string(TRACE_INFO, DHL_USER_FLAG_NONE, MOD_MCF, apply_filename);
+        ret = MCF_OTA_R_READ_OTA_FILE_FAIL;
+
+        return ret;
+    }
+
+    MCF_W_LOCK_OBJECT(ota_file, mcf_enhmutex_g);
+    if (ota_file) {
+        fs_api_ret[0] = MCF_FS_CMPT_Read(filename, &fs_cmpt);
+        if (fs_api_ret[0] < FS_NO_ERROR) {
+            MCF_W_UNLOCK_OBJECT(ota_file, mcf_enhmutex_g);
+            if (is_booting == KAL_TRUE) {
+                com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_READ_OTA_FILE_FAIL;
+                MCF_BOOT_TRACE(MCF_BOOT_TR_READ_OTA_FILE_FAIL, *apply_path_type, fs_api_ret[0]);
+                MCF_BOOT_TRACE(MCF_BOOT_TR_STRING, apply_filename);
+            }
+            MD_TRC_MCF_TR_READ_OTA_FILE_FAIL(*apply_path_type, fs_api_ret[0]);
+            dhl_print_string(TRACE_INFO, DHL_USER_FLAG_NONE, MOD_MCF, apply_filename);
+            ret = MCF_OTA_R_READ_OTA_FILE_FAIL;
+
+            return ret;
+        }
+
+        pFile = (mcf_tool_file_info_t *)(ota_file->buff);
+#ifdef __MCF_FIND_TAG_SUPPORT__
+        if (pFile->file_version == 2 || pFile->file_version == 3) { 
+#else
+        if (pFile->file_version == 3) {
+#endif
+            kal_uint32 operation_mask = 0;
+            
+            /* Check custom operation mask */
+            operation_mask = mcf_get_custom_operation_mask();
+            if ((pFile->operation_mask & operation_mask) != operation_mask) {				
+                if (is_booting == KAL_TRUE) {
+                    com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_OPERATION_MASK_FAIL;
+                    MCF_BOOT_TRACE(MCF_BOOT_TR_READ_OTA_FILE_OPERATION_MASK_FAIL, apply_filename, pFile->operation_mask, operation_mask);
+                }
+                MD_TRC_MCF_TR_READ_OTA_FILE_OPERATION_MASK_FAIL(apply_filename, pFile->operation_mask, operation_mask);
+                ret = MCF_OTA_R_INVALID_FILE;
+                
+                kal_mem_set(ota_file->buff, 0, MCF_MAX_OTA_FILE_SIZE);
+                kal_mem_set(ota_file->relative_path_name, 0, MCF_FILE_MAX_NAME_LEN);
+                ota_file->path_type = 0;
+                ota_file->last_mod_time = 0;
+                MCF_W_UNLOCK_OBJECT(ota_file, mcf_enhmutex_g);
+
+                return ret;
+			}
+            
+            /*  First check digest first 
+             *  If file is encrypted and has checksum.
+             *  Decrypt file before checking checksum.
+             */
+
+			 // RSA verify digest 
+			if ((pFile->operation_mask & MCF_FILE_OP_SHA256_RSA2048) != 0) {				
+
+				if (mcf_verify_digest(MCF_FILE_OP_SHA256_RSA2048, (mcf_tool_file_info_t *)(ota_file->buff), (mcf_digest *)(ota_file->buff + pFile->file_size)) != KAL_TRUE) {
+					kal_mem_set(ota_file->buff, 0, MCF_MAX_OTA_FILE_SIZE);
+                    kal_mem_set(ota_file->relative_path_name, 0, MCF_FILE_MAX_NAME_LEN);
+                    ota_file->path_type = 0;
+                    ota_file->last_mod_time = 0;
+					MCF_W_UNLOCK_OBJECT(ota_file, mcf_enhmutex_g);
+					if (is_booting == KAL_TRUE) {
+						com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_DIGEST_FAIL;
+						MCF_BOOT_TRACE(MCF_BOOT_TR_READ_OTA_FILE_DIGEST_FAIL, apply_filename);
+					}
+					MD_TRC_MCF_TR_READ_OTA_FILE_DIGEST_FAIL(apply_filename);
+					ret = MCF_OTA_R_DIGEST_FAIL;
+
+					return ret;
+				}
+
+			}
+
+			else if ((pFile->operation_mask & MCF_FILE_OP_SHA384_RSA3072) != 0) {
+
+				if (mcf_verify_digest(MCF_FILE_OP_SHA384_RSA3072, (mcf_tool_file_info_t *)(ota_file->buff), (mcf_digest *)(ota_file->buff + pFile->file_size)) != KAL_TRUE) {
+					kal_mem_set(ota_file->buff, 0, MCF_MAX_OTA_FILE_SIZE);
+                    kal_mem_set(ota_file->relative_path_name, 0, MCF_FILE_MAX_NAME_LEN);
+                    ota_file->path_type = 0;
+                    ota_file->last_mod_time = 0;
+					MCF_W_UNLOCK_OBJECT(ota_file, mcf_enhmutex_g);
+					if (is_booting == KAL_TRUE) {
+						com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_DIGEST_FAIL;
+						MCF_BOOT_TRACE(MCF_BOOT_TR_READ_OTA_FILE_DIGEST_FAIL, apply_filename);
+					}
+					MD_TRC_MCF_TR_READ_OTA_FILE_DIGEST_FAIL(apply_filename);
+					ret = MCF_OTA_R_DIGEST_FAIL;
+
+					return ret;
+				}
+
+			}
+
+            if ( (pFile->operation_mask & MCF_FILE_OP_AES_128) != 0) {
+                mcf_get_custom_aes_password(password);
+
+                if (mcf_decrypt_128bit(password, (kal_char *)(ota_file->buff + pFile->total_len), (pFile->file_size - pFile->total_len) ) != KAL_TRUE) {
+                    kal_mem_set(ota_file->buff, 0, MCF_MAX_OTA_FILE_SIZE);
+                    kal_mem_set(ota_file->relative_path_name, 0, MCF_FILE_MAX_NAME_LEN);
+                    ota_file->path_type = 0;
+                    ota_file->last_mod_time = 0;
+                    MCF_W_UNLOCK_OBJECT(ota_file, mcf_enhmutex_g);
+                    if (is_booting == KAL_TRUE) {
+                        com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_DECRYPTION_FAIL;
+                        MCF_BOOT_TRACE(MCF_BOOT_TR_READ_OTA_FILE_DECRYPTION_FAIL, apply_filename);
+                    }
+                    MD_TRC_MCF_TR_READ_OTA_FILE_DECRYPTION_FAIL(apply_filename);
+                    ret = MCF_OTA_R_DECRYPTION_FAIL;
+
+                    return ret;
+                }
+            }
+            // for AES_256  
+            else if ((pFile->operation_mask & MCF_FILE_OP_AES_256) != 0) {
+                mcf_get_custom_aes_password(password);
+                if (mcf_decrypt_256bit(password, (kal_char *)(ota_file->buff + pFile->total_len), (pFile->file_size - pFile->total_len)) != KAL_TRUE) {
+                    kal_mem_set(ota_file->buff, 0, MCF_MAX_OTA_FILE_SIZE);
+                    kal_mem_set(ota_file->relative_path_name, 0, MCF_FILE_MAX_NAME_LEN);
+                    ota_file->path_type = 0;
+                    ota_file->last_mod_time = 0;
+                    MCF_W_UNLOCK_OBJECT(ota_file, mcf_enhmutex_g);
+                    if (is_booting == KAL_TRUE) {
+                        com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_DECRYPTION_FAIL;
+                        MCF_BOOT_TRACE(MCF_BOOT_TR_READ_OTA_FILE_DECRYPTION_FAIL, apply_filename);
+                    }
+                    MD_TRC_MCF_TR_READ_OTA_FILE_DECRYPTION_FAIL(apply_filename);
+                    ret = MCF_OTA_R_DECRYPTION_FAIL;
+
+                    return ret;
+                }
+            }
+
+            if ( (pFile->operation_mask & MCF_FILE_OP_CHECKSUM) != 0) {
+                if (mcf_check_check_sum((kal_uint32 *)(ota_file->buff), pFile->file_size) != 0) {
+                    kal_mem_set(ota_file->buff, 0, MCF_MAX_OTA_FILE_SIZE);
+                    kal_mem_set(ota_file->relative_path_name, 0, MCF_FILE_MAX_NAME_LEN);
+                    ota_file->path_type = 0;
+                    ota_file->last_mod_time = 0;
+                    MCF_W_UNLOCK_OBJECT(ota_file, mcf_enhmutex_g);
+                    if (is_booting == KAL_TRUE) {
+                        com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_CHECKSUM_ERROR;
+                        MCF_BOOT_TRACE(MCF_BOOT_TR_READ_OTA_FILE_CHECKSUM_ERROR, apply_filename);
+                    }
+                    MD_TRC_MCF_TR_READ_OTA_FILE_CHECKSUM_ERROR(apply_filename);
+                    ret = MCF_OTA_R_CHECKSUM_ERROR;
+
+                    return ret;
+                }
+            }
+        } else {
+            if (is_booting == KAL_TRUE) {
+                com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_INVALID_FILE;
+                MCF_BOOT_TRACE(MCF_BOOT_TR_READ_OTA_FILE_INVALID_FILE_VERSION, pFile->file_version);
+            }
+            MD_TRC_MCF_TR_READ_OTA_FILE_INVALID_FILE_VERSION(pFile->file_version);
+            kal_mem_set(ota_file->buff, 0, MCF_MAX_OTA_FILE_SIZE);
+            kal_mem_set(ota_file->relative_path_name, 0, MCF_FILE_MAX_NAME_LEN);
+            ota_file->path_type = 0;
+            ota_file->last_mod_time = 0;
+            MCF_W_UNLOCK_OBJECT(ota_file, mcf_enhmutex_g);
+            ret = MCF_OTA_R_INVALID_FILE;
+
+            return ret;
+        }
+
+        ota_file->path_type = *apply_path_type;
+        ota_file->last_mod_time = last_mod_time;   
+#if defined(__MCF_UT_FRAMEWORK_SUPPORT__)        
+        if (strcmp(ota_file->relative_path_name, "") == 0){
+            strncpy(ota_file->relative_path_name, apply_filename, MCF_FILE_MAX_NAME_LEN - 1);
+        }else{
+            strncpy(apply_filename, ota_file->relative_path_name, MCF_FILE_MAX_NAME_LEN - 1);
+        }
+#else
+        strncpy(ota_file->relative_path_name, apply_filename, MCF_FILE_MAX_NAME_LEN - 1);
+#endif 
+        MCF_W_UNLOCK_OBJECT(ota_file, mcf_enhmutex_g);
+    } else {
+        if (is_booting == KAL_TRUE) {
+            com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_TAKE_WRITE_LOCK_FAIL;
+            MCF_BOOT_TRACE(MCF_BOOT_TR_READ_OTA_FILE_TAKE_WRITE_LOCK_FAIL, apply_filename, *apply_path_type);
+        }
+        MD_TRC_MCF_TR_READ_OTA_FILE_TAKE_WRITE_LOCK_FAIL(apply_filename, *apply_path_type);
+        ret = MCF_OTA_R_READ_OTA_FILE_FAIL;
+    }
+
+    return ret;
+}
+
+mcf_ota_result_e mcf_read_tlvota_file(
+    kal_bool                is_booting,
+    kal_uint8               sim_id,
+    kal_char               *req_fs_root_path,
+    kal_char               *req_file_path_name,
+    l4c_mcf_path_type_enum *apply_path_type,
+    kal_char               *apply_filename,
+    mcf_t                  *pMcf)
+{
+    NVRAM_FS_PARAM_CMPT_T   fs_cmpt;
+    FS_FileDetail           fs_file_detail[L4C_MCF_PATH_TYPE_MAX] = {0};
+    kal_uint32              read_byte = 0;
+    kal_uint32              file_size = 0;
+    mcf_ota_result_e        ret = MCF_OTA_R_SUCCESS;
+    mcf_tlvota_file_t      *tlvota_file = &(pMcf->tlvota_file[sim_id]);
+    kal_wchar               filename[MCF_FILE_MAX_MD_PATH_LEN + MCF_FILE_MAX_NAME_LEN];
+    mcf_tool_file_info_t   *pFile;
+    kal_char                password[MCF_MAX_PASSWORD_LEN] = {0};
+    kal_bool                is_default_path;
+    kal_uint32              dummy_para;
+    kal_int32               fs_api_ret[L4C_MCF_PATH_TYPE_MAX];
+    kal_uint64              last_mod_time = 0;
+
+    fs_cmpt.opid_map = NVRAM_FS_CMPT_OPEN | NVRAM_FS_CMPT_GETFILESIZE | NVRAM_FS_CMPT_CLOSE;
+    fs_cmpt.Flag = FS_READ_ONLY;
+    fs_cmpt.Length = 0;
+    fs_cmpt.Offset = 0;
+    fs_cmpt.Whence = FS_FILE_BEGIN;
+    fs_cmpt.DataPtr = &dummy_para;
+    fs_cmpt.Read = &dummy_para;
+    fs_cmpt.FileSize = &file_size;
+
+    if ( (strcmp(req_fs_root_path, "") != 0) && (strcmp(req_file_path_name, "") != 0) ) {
+        if (strcmp(req_fs_root_path, MCF_FS_DEFAULT_FOLDER_PATH) == 0) {
+            *apply_path_type = L4C_MCF_PATH_TYPE_OTA;
+        } else if (strcmp(req_fs_root_path, MCF_FS_CUSTOM_FOLDER_PATH) == 0) {
+            *apply_path_type = L4C_MCF_PATH_TYPE_RUNTIME;
+        } else{
+            MD_TRC_MCF_TR_READ_TLVOTA_FILE_INVALID_PATH(req_fs_root_path);
+            ret = MCF_OTA_R_INVALID_PARAMETER;
+
+            return ret;
+        }
+        kal_wsprintf(filename, "%s\\%s\0", req_fs_root_path, req_file_path_name);
+        strncpy(apply_filename, req_file_path_name, MCF_FILE_MAX_NAME_LEN - 1);
+        is_default_path = KAL_FALSE;
+    } else {
+        /* Compare modified time of OP-OTA file to select which file to be applied */
+        kal_wsprintf(filename, "%s\\%s\0", MCF_FS_DEFAULT_FOLDER_PATH, MCF_FS_DEFAULT_TLVOTA_FILE_NAME);
+        fs_api_ret[L4C_MCF_PATH_TYPE_OTA] = FS_GetFileDetail(filename, &fs_file_detail[L4C_MCF_PATH_TYPE_OTA]);
+        MD_TRC_MCF_TR_READ_TLVOTA_FILE_MODIFIED_TIME(L4C_MCF_PATH_TYPE_OTA, fs_api_ret[L4C_MCF_PATH_TYPE_OTA],
+                         (kal_uint32)((fs_file_detail[L4C_MCF_PATH_TYPE_OTA].LastStatusChangeTime >> 32) & 0xFFFFFFFF), (kal_uint32)(fs_file_detail[L4C_MCF_PATH_TYPE_OTA].LastStatusChangeTime & 0xFFFFFFFF));
+        if (fs_api_ret[L4C_MCF_PATH_TYPE_OTA] != FS_NO_ERROR) {
+            kal_mem_set(&fs_file_detail[L4C_MCF_PATH_TYPE_OTA], 0, sizeof(FS_FileDetail));
+        }
+
+        kal_wsprintf(filename, "%s\\%s\0", MCF_FS_CUSTOM_FOLDER_PATH, MCF_FS_DEFAULT_TLVOTA_FILE_NAME);
+        fs_api_ret[L4C_MCF_PATH_TYPE_RUNTIME] = FS_GetFileDetail(filename, &fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME]);
+        MD_TRC_MCF_TR_READ_TLVOTA_FILE_MODIFIED_TIME(L4C_MCF_PATH_TYPE_RUNTIME, fs_api_ret[L4C_MCF_PATH_TYPE_RUNTIME],
+                         (kal_uint32)((fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME].LastStatusChangeTime >> 32) & 0xFFFFFFFF), (kal_uint32)(fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME].LastStatusChangeTime & 0xFFFFFFFF));
+        if (fs_api_ret[L4C_MCF_PATH_TYPE_RUNTIME] != FS_NO_ERROR) {
+            kal_mem_set(&fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME], 0, sizeof(FS_FileDetail));
+        }
+
+        if ( (fs_api_ret[L4C_MCF_PATH_TYPE_OTA] == FS_NO_ERROR) || (fs_api_ret[L4C_MCF_PATH_TYPE_RUNTIME] == FS_NO_ERROR) ) {
+            if (fs_file_detail[L4C_MCF_PATH_TYPE_OTA].LastStatusChangeTime > fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME].LastStatusChangeTime) {
+                *apply_path_type = L4C_MCF_PATH_TYPE_OTA;
+                kal_wsprintf(filename, "%s\\%s\0", MCF_FS_DEFAULT_FOLDER_PATH, MCF_FS_DEFAULT_TLVOTA_FILE_NAME);
+            } else {
+                *apply_path_type = L4C_MCF_PATH_TYPE_RUNTIME;
+                kal_wsprintf(filename, "%s\\%s\0", MCF_FS_CUSTOM_FOLDER_PATH, MCF_FS_DEFAULT_TLVOTA_FILE_NAME);
+            }
+        } else {
+            if (is_booting == KAL_TRUE) {
+                com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_READ_OTA_FILE_FAIL;
+                MCF_BOOT_TRACE(MCF_BOOT_TR_READ_TLVOTA_FILE_COMPARE_FAIL);
+            }
+            MD_TRC_MCF_TR_READ_TLVOTA_FILE_COMPARE_FAIL();
+            ret = MCF_OTA_R_READ_OTA_FILE_FAIL;
+
+            return ret;
+        }
+
+        strncpy(apply_filename, MCF_FS_DEFAULT_TLVOTA_FILE_NAME, MCF_FILE_MAX_NAME_LEN - 1);
+
+        is_default_path = KAL_TRUE;
+    }
+
+    fs_api_ret[0] = MCF_FS_CMPT_Read(filename, &fs_cmpt);
+    if (fs_api_ret[0] < FS_NO_ERROR) {
+        if (is_booting == KAL_TRUE) {
+            MCF_BOOT_TRACE(MCF_BOOT_TR_READ_TLVOTA_FILE_FAIL, *apply_path_type, sim_id, fs_api_ret[0]);
+            MCF_BOOT_TRACE(MCF_BOOT_TR_STRING, apply_filename);
+        }
+        MD_TRC_MCF_TR_READ_TLVOTA_FILE_FAIL(*apply_path_type, sim_id, fs_api_ret[0]);
+        dhl_print_string(TRACE_INFO, DHL_USER_FLAG_NONE, MOD_MCF, apply_filename);
+
+        /* If cannot read given TLV-OTA file, read default TLV-OTA file */
+        if (is_default_path == KAL_FALSE) {
+            /* Compare modified time of OP-OTA file to select which file to be applied */
+            kal_wsprintf(filename, "%s\\%s\0", MCF_FS_DEFAULT_FOLDER_PATH, MCF_FS_DEFAULT_TLVOTA_FILE_NAME);
+            fs_api_ret[L4C_MCF_PATH_TYPE_OTA] = FS_GetFileDetail(filename, &fs_file_detail[L4C_MCF_PATH_TYPE_OTA]);
+            MD_TRC_MCF_TR_READ_TLVOTA_FILE_MODIFIED_TIME(L4C_MCF_PATH_TYPE_OTA, fs_api_ret[L4C_MCF_PATH_TYPE_OTA],
+                             (kal_uint32)((fs_file_detail[L4C_MCF_PATH_TYPE_OTA].LastStatusChangeTime >> 32) & 0xFFFFFFFF), (kal_uint32)(fs_file_detail[L4C_MCF_PATH_TYPE_OTA].LastStatusChangeTime & 0xFFFFFFFF));
+            if (fs_api_ret[L4C_MCF_PATH_TYPE_OTA] != FS_NO_ERROR) {
+                kal_mem_set(&fs_file_detail[L4C_MCF_PATH_TYPE_OTA], 0, sizeof(FS_FileDetail));
+            }
+
+            kal_wsprintf(filename, "%s\\%s\0", MCF_FS_CUSTOM_FOLDER_PATH, MCF_FS_DEFAULT_TLVOTA_FILE_NAME);
+            fs_api_ret[L4C_MCF_PATH_TYPE_RUNTIME] = FS_GetFileDetail(filename, &fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME]);
+            MD_TRC_MCF_TR_READ_TLVOTA_FILE_MODIFIED_TIME(L4C_MCF_PATH_TYPE_RUNTIME, fs_api_ret[L4C_MCF_PATH_TYPE_RUNTIME],
+                             (kal_uint32)((fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME].LastStatusChangeTime >> 32) & 0xFFFFFFFF), (kal_uint32)(fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME].LastStatusChangeTime & 0xFFFFFFFF));
+            if (fs_api_ret[L4C_MCF_PATH_TYPE_RUNTIME] != FS_NO_ERROR) {
+                kal_mem_set(&fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME], 0, sizeof(FS_FileDetail));
+            }
+
+            if ( (fs_api_ret[L4C_MCF_PATH_TYPE_OTA] == FS_NO_ERROR) || (fs_api_ret[L4C_MCF_PATH_TYPE_RUNTIME] == FS_NO_ERROR) ) {
+                if (fs_file_detail[L4C_MCF_PATH_TYPE_OTA].LastStatusChangeTime > fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME].LastStatusChangeTime) {
+                    *apply_path_type = L4C_MCF_PATH_TYPE_OTA;
+                    kal_wsprintf(filename, "%s\\%s\0", MCF_FS_DEFAULT_FOLDER_PATH, MCF_FS_DEFAULT_TLVOTA_FILE_NAME);
+                } else {
+                    *apply_path_type = L4C_MCF_PATH_TYPE_RUNTIME;
+                    kal_wsprintf(filename, "%s\\%s\0", MCF_FS_CUSTOM_FOLDER_PATH, MCF_FS_DEFAULT_TLVOTA_FILE_NAME);
+                }
+            } else {
+                if (is_booting == KAL_TRUE) {
+                    com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_READ_OTA_FILE_FAIL;
+                    MCF_BOOT_TRACE(MCF_BOOT_TR_READ_TLVOTA_FILE_COMPARE_FAIL);
+                }
+                MD_TRC_MCF_TR_READ_TLVOTA_FILE_COMPARE_FAIL();
+                ret = MCF_OTA_R_READ_OTA_FILE_FAIL;
+
+                return ret;
+            }
+
+            strncpy(apply_filename, MCF_FS_DEFAULT_TLVOTA_FILE_NAME, MCF_FILE_MAX_NAME_LEN - 1);
+
+            fs_api_ret[0] = MCF_FS_CMPT_Read(filename, &fs_cmpt);
+            if (fs_api_ret[0] < FS_NO_ERROR) {
+                if (is_booting == KAL_TRUE) {
+                    com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_READ_TLVOTA_FILE_FAIL;
+                    MCF_BOOT_TRACE(MCF_BOOT_TR_READ_TLVOTA_FILE_FAIL, *apply_path_type, sim_id, fs_api_ret[0]);
+                    MCF_BOOT_TRACE(MCF_BOOT_TR_STRING, apply_filename);
+                }
+                MD_TRC_MCF_TR_READ_TLVOTA_FILE_FAIL(*apply_path_type, sim_id, fs_api_ret[0]);
+                dhl_print_string(TRACE_INFO, DHL_USER_FLAG_NONE, MOD_MCF, apply_filename);
+                ret = MCF_OTA_R_READ_OTA_FILE_FAIL;
+
+                return ret;
+            }
+        } else {
+            ret = MCF_OTA_R_READ_OTA_FILE_FAIL;
+
+            return ret;
+        }
+    }
+
+    if (file_size > MCF_MAX_TLVOTA_FILE_SIZE) {
+        if (is_booting == KAL_TRUE) {
+            com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_TLVOTA_FILE_OVERSIZE;
+            MCF_BOOT_TRACE(MCF_BOOT_TR_READ_TLVOTA_FILE_OVERSIZE, file_size, MCF_MAX_TLVOTA_FILE_SIZE);
+        }
+        MD_TRC_MCF_TR_READ_TLVOTA_FILE_OVERSIZE(file_size, MCF_MAX_TLVOTA_FILE_SIZE);
+        ret = MCF_OTA_R_READ_OTA_FILE_FAIL;
+
+        return ret;
+    }
+
+    /* Read file */
+    fs_cmpt.opid_map = NVRAM_FS_CMPT_OPEN | NVRAM_FS_CMPT_READ | NVRAM_FS_CMPT_CLOSE;
+    fs_cmpt.Flag = FS_READ_ONLY;
+    fs_cmpt.Length = file_size;
+    fs_cmpt.Offset = 0;
+    fs_cmpt.Whence = FS_FILE_BEGIN;
+    fs_cmpt.DataPtr = tlvota_file->buff;
+    fs_cmpt.Read = &read_byte;
+    fs_cmpt.FileSize = &dummy_para;
+
+    fs_api_ret[*apply_path_type] = FS_GetFileDetail(filename, &fs_file_detail[*apply_path_type]);
+    MD_TRC_MCF_TR_READ_TLVOTA_FILE_MODIFIED_TIME(*apply_path_type, fs_api_ret[*apply_path_type],
+                     (kal_uint32)((fs_file_detail[*apply_path_type].LastStatusChangeTime >> 32) & 0xFFFFFFFF), (kal_uint32)(fs_file_detail[*apply_path_type].LastStatusChangeTime & 0xFFFFFFFF));
+    if (fs_api_ret[*apply_path_type] == FS_NO_ERROR) {
+        last_mod_time = fs_file_detail[*apply_path_type].LastStatusChangeTime;
+    } else {
+        if (is_booting == KAL_TRUE) {
+            com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_READ_TLVOTA_FILE_FAIL;
+            MCF_BOOT_TRACE(MCF_BOOT_TR_READ_TLVOTA_FILE_FAIL, *apply_path_type, sim_id, fs_api_ret[0]);
+            MCF_BOOT_TRACE(MCF_BOOT_TR_STRING, apply_filename);
+        }
+        MD_TRC_MCF_TR_READ_TLVOTA_FILE_FAIL(*apply_path_type, sim_id, fs_api_ret[*apply_path_type]);
+        dhl_print_string(TRACE_INFO, DHL_USER_FLAG_NONE, MOD_MCF, apply_filename);
+        ret = MCF_OTA_R_READ_OTA_FILE_FAIL;
+
+        return ret;
+    }
+    
+    MCF_W_LOCK_OBJECT(tlvota_file, mcf_enhmutex_g);
+    if (tlvota_file) {
+        fs_api_ret[0] = MCF_FS_CMPT_Read(filename, &fs_cmpt);
+        if (fs_api_ret[0] < FS_NO_ERROR) {
+            MCF_W_UNLOCK_OBJECT(tlvota_file, mcf_enhmutex_g);
+            if (is_booting == KAL_TRUE) {
+                com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_READ_TLVOTA_FILE_FAIL;
+                MCF_BOOT_TRACE(MCF_BOOT_TR_READ_TLVOTA_FILE_FAIL, *apply_path_type, sim_id, fs_api_ret[0]);
+                MCF_BOOT_TRACE(MCF_BOOT_TR_STRING, apply_filename);
+            }
+            MD_TRC_MCF_TR_READ_TLVOTA_FILE_FAIL(*apply_path_type, sim_id, fs_api_ret[0]);
+            dhl_print_string(TRACE_INFO, DHL_USER_FLAG_NONE, MOD_MCF, apply_filename);
+            ret = MCF_OTA_R_READ_OTA_FILE_FAIL;
+
+            return ret;
+        }
+
+        pFile = (mcf_tool_file_info_t *)(tlvota_file->buff);
+#ifdef __MCF_FIND_TAG_SUPPORT__
+        if (pFile->file_version == 2 || pFile->file_version == 3) { 
+#else
+        if (pFile->file_version == 3) {
+#endif
+            kal_uint32 operation_mask = 0;
+            
+            /* Check custom operation mask */
+            operation_mask = mcf_get_custom_operation_mask();
+            if ((pFile->operation_mask & operation_mask) != operation_mask) {				
+                if (is_booting == KAL_TRUE) {
+                    com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_OPERATION_MASK_FAIL;
+                    MCF_BOOT_TRACE(MCF_BOOT_TR_READ_TLVOTA_FILE_OPERATION_MASK_FAIL, apply_filename, pFile->operation_mask, operation_mask);
+                }
+                MD_TRC_MCF_TR_READ_TLVOTA_FILE_OPERATION_MASK_FAIL(apply_filename, pFile->operation_mask, operation_mask);
+                ret = MCF_OTA_R_INVALID_FILE;
+                
+                kal_mem_set(tlvota_file->buff, 0, MCF_MAX_TLVOTA_FILE_SIZE);
+                kal_mem_set(tlvota_file->relative_path_name, 0, MCF_FILE_MAX_NAME_LEN);
+                tlvota_file->path_type = 0;
+                tlvota_file->last_mod_time = 0;
+                kal_mem_set(&(tlvota_file->last_file), 0, sizeof(mcf_file_info_t));
+                MCF_W_UNLOCK_OBJECT(tlvota_file, mcf_enhmutex_g);
+
+                return ret;
+			}
+            
+            /*  First check digest first 
+             *  If file is encrypted and has checksum.
+             *  Decrypt file before checking checksum.
+             */
+              // RSA verify digest 
+            if ((pFile->operation_mask & MCF_FILE_OP_SHA256_RSA2048) != 0) {
+
+                if (mcf_verify_digest(MCF_FILE_OP_SHA256_RSA2048, (mcf_tool_file_info_t *)(tlvota_file->buff), (mcf_digest *)(tlvota_file->buff + pFile->file_size)) != KAL_TRUE) {
+                    kal_mem_set(tlvota_file->buff, 0, MCF_MAX_TLVOTA_FILE_SIZE);
+                    kal_mem_set(tlvota_file->relative_path_name, 0, MCF_FILE_MAX_NAME_LEN);
+                    tlvota_file->path_type = 0;
+                    tlvota_file->last_mod_time = 0;
+                    kal_mem_set(&(tlvota_file->last_file), 0, sizeof(mcf_file_info_t));
+                    MCF_W_UNLOCK_OBJECT(tlvota_file, mcf_enhmutex_g);
+                    if (is_booting == KAL_TRUE) {
+                        com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_DIGEST_FAIL;
+                        MCF_BOOT_TRACE(MCF_BOOT_TR_READ_TLVOTA_FILE_DIGEST_FAIL, apply_filename);
+                    }
+                    MD_TRC_MCF_TR_READ_TLVOTA_FILE_DIGEST_FAIL(apply_filename);
+                    ret = MCF_OTA_R_DIGEST_FAIL;
+
+                    return ret;
+                }
+
+            }
+            else if ((pFile->operation_mask & MCF_FILE_OP_SHA384_RSA3072) != 0) {
+
+                if (mcf_verify_digest(MCF_FILE_OP_SHA384_RSA3072, (mcf_tool_file_info_t *)(tlvota_file->buff), (mcf_digest *)(tlvota_file->buff + pFile->file_size)) != KAL_TRUE) {
+                    kal_mem_set(tlvota_file->buff, 0, MCF_MAX_TLVOTA_FILE_SIZE);
+                    kal_mem_set(tlvota_file->relative_path_name, 0, MCF_FILE_MAX_NAME_LEN);
+                    tlvota_file->path_type = 0;
+                    tlvota_file->last_mod_time = 0;
+                    kal_mem_set(&(tlvota_file->last_file), 0, sizeof(mcf_file_info_t));
+                    MCF_W_UNLOCK_OBJECT(tlvota_file, mcf_enhmutex_g);
+                    if (is_booting == KAL_TRUE) {
+                        com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_DIGEST_FAIL;
+                        MCF_BOOT_TRACE(MCF_BOOT_TR_READ_TLVOTA_FILE_DIGEST_FAIL, apply_filename);
+                    }
+                    MD_TRC_MCF_TR_READ_TLVOTA_FILE_DIGEST_FAIL(apply_filename);
+                    ret = MCF_OTA_R_DIGEST_FAIL;
+
+                    return ret;
+                }
+
+            }
+            
+            if ( (pFile->operation_mask & MCF_FILE_OP_AES_128) != 0) {
+                mcf_get_custom_aes_password(password);
+
+                if (mcf_decrypt_128bit(password, (kal_char *)(tlvota_file->buff + pFile->total_len), (pFile->file_size - pFile->total_len) ) != KAL_TRUE) {
+                    kal_mem_set(tlvota_file->buff, 0, MCF_MAX_TLVOTA_FILE_SIZE);
+                    kal_mem_set(tlvota_file->relative_path_name, 0, MCF_FILE_MAX_NAME_LEN);
+                    tlvota_file->path_type = 0;
+                    tlvota_file->last_mod_time = 0;
+                    kal_mem_set(&(tlvota_file->last_file), 0, sizeof(mcf_file_info_t));
+                    MCF_W_UNLOCK_OBJECT(tlvota_file, mcf_enhmutex_g);
+                    if (is_booting == KAL_TRUE) {
+                        com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_DECRYPTION_FAIL;
+                        MCF_BOOT_TRACE(MCF_BOOT_TR_READ_TLVOTA_FILE_DECRYPTION_FAIL, apply_filename);
+                    }
+                    MD_TRC_MCF_TR_READ_TLVOTA_FILE_DECRYPTION_FAIL(apply_filename);
+                    ret = MCF_OTA_R_DECRYPTION_FAIL;
+
+                    return ret;
+                }
+            }
+            else if ((pFile->operation_mask & MCF_FILE_OP_AES_256) != 0) { // for AES_256  
+                mcf_get_custom_aes_password(password);
+
+                if (mcf_decrypt_256bit(password, (kal_char *)(tlvota_file->buff + pFile->total_len), (pFile->file_size - pFile->total_len)) != KAL_TRUE) {
+                    kal_mem_set(tlvota_file->buff, 0, MCF_MAX_TLVOTA_FILE_SIZE);
+                    kal_mem_set(tlvota_file->relative_path_name, 0, MCF_FILE_MAX_NAME_LEN);
+                    tlvota_file->path_type = 0;
+                    tlvota_file->last_mod_time = 0;
+                    kal_mem_set(&(tlvota_file->last_file), 0, sizeof(mcf_file_info_t));
+                    MCF_W_UNLOCK_OBJECT(tlvota_file, mcf_enhmutex_g);
+                    if (is_booting == KAL_TRUE) {
+                        com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_DECRYPTION_FAIL;
+                        MCF_BOOT_TRACE(MCF_BOOT_TR_READ_TLVOTA_FILE_DECRYPTION_FAIL, apply_filename);
+                    }
+                    MD_TRC_MCF_TR_READ_TLVOTA_FILE_DECRYPTION_FAIL(apply_filename);
+                    ret = MCF_OTA_R_DECRYPTION_FAIL;
+
+                    return ret;
+                }
+            }
+
+            if ( (pFile->operation_mask & MCF_FILE_OP_CHECKSUM) != 0) {
+                if (mcf_check_check_sum((kal_uint32 *)(tlvota_file->buff), pFile->file_size) != 0) {
+                    kal_mem_set(tlvota_file->buff, 0, MCF_MAX_TLVOTA_FILE_SIZE);
+                    kal_mem_set(tlvota_file->relative_path_name, 0, MCF_FILE_MAX_NAME_LEN);
+                    tlvota_file->path_type = 0;
+                    tlvota_file->last_mod_time = 0;
+                    kal_mem_set(&(tlvota_file->last_file), 0, sizeof(mcf_file_info_t));
+                    MCF_W_UNLOCK_OBJECT(tlvota_file, mcf_enhmutex_g);
+                    if (is_booting == KAL_TRUE) {
+                        com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_CHECKSUM_ERROR;
+                        MCF_BOOT_TRACE(MCF_BOOT_TR_READ_TLVOTA_FILE_CHECKSUM_ERROR, apply_filename);
+                    }
+                    MD_TRC_MCF_TR_READ_TLVOTA_FILE_CHECKSUM_ERROR(apply_filename);
+                    ret = MCF_OTA_R_CHECKSUM_ERROR;
+
+                    return ret;
+                }
+            }
+        } else {
+            if (is_booting == KAL_TRUE) {
+                com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_INVALID_FILE;
+                MCF_BOOT_TRACE(MCF_BOOT_TR_READ_TLVOTA_FILE_INVALID_FILE_VERSION, pFile->file_version);
+            }
+            MD_TRC_MCF_TR_READ_TLVOTA_FILE_INVALID_FILE_VERSION(apply_filename);
+            kal_mem_set(tlvota_file->buff, 0, MCF_MAX_TLVOTA_FILE_SIZE);
+            kal_mem_set(tlvota_file->relative_path_name, 0, MCF_FILE_MAX_NAME_LEN);
+            tlvota_file->path_type = 0;
+            tlvota_file->last_mod_time = 0;
+            kal_mem_set(&(tlvota_file->last_file), 0, sizeof(mcf_file_info_t));
+            MCF_W_UNLOCK_OBJECT(tlvota_file, mcf_enhmutex_g);
+            ret = MCF_OTA_R_INVALID_FILE;
+
+            return ret;
+        }
+
+        tlvota_file->path_type = *apply_path_type;
+        tlvota_file->last_mod_time = last_mod_time;
+        tlvota_file->last_file.last_mod_time = last_mod_time;
+
+#if defined(__MCF_UT_FRAMEWORK_SUPPORT__)        
+        if (strcmp(tlvota_file->relative_path_name, "") == 0){
+            strncpy(tlvota_file->relative_path_name, apply_filename, MCF_FILE_MAX_NAME_LEN - 1);
+        }else{
+            strncpy(apply_filename, tlvota_file->relative_path_name, MCF_FILE_MAX_NAME_LEN - 1);
+        }
+#else   
+        strncpy(tlvota_file->relative_path_name, apply_filename, MCF_FILE_MAX_NAME_LEN - 1);
+#endif 
+        MCF_W_UNLOCK_OBJECT(tlvota_file, mcf_enhmutex_g);
+    } else {
+        if (is_booting == KAL_TRUE) {
+            com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_TAKE_WRITE_LOCK_FAIL;
+            MCF_BOOT_TRACE(MCF_BOOT_TR_READ_TLVOTA_FILE_TAKE_WRITE_LOCK_FAIL, apply_filename, *apply_path_type, sim_id);
+        }
+        MD_TRC_MCF_TR_READ_TLVOTA_FILE_TAKE_WRITE_LOCK_FAIL(apply_filename, *apply_path_type, sim_id);
+        ret = MCF_OTA_R_READ_OTA_FILE_FAIL;
+    }
+
+    return ret;
+}
+
+mcf_ota_result_e mcf_read_general_tlvota_file(
+    kal_bool                is_booting,
+    kal_char               *req_fs_root_path,
+    kal_char               *req_file_path_name,
+    l4c_mcf_path_type_enum *apply_path_type,
+    kal_char               *apply_filename,
+    mcf_t                  *pMcf)
+{
+    NVRAM_FS_PARAM_CMPT_T               fs_cmpt;
+    FS_FileDetail                       fs_file_detail[L4C_MCF_PATH_TYPE_MAX] = {0};
+    kal_uint32                          read_byte = 0;
+    kal_uint32                          file_size = 0;
+    mcf_ota_result_e                    ret = MCF_OTA_R_SUCCESS;
+    mcf_tlvota_file_t                  *tlvota_file = &(pMcf->general_tlvota_file);
+    kal_wchar                           filename[MCF_FILE_MAX_MD_PATH_LEN + MCF_FILE_MAX_NAME_LEN];
+    mcf_tool_file_info_t               *pFile;
+    kal_char                            password[MCF_MAX_PASSWORD_LEN] = {0};
+    kal_bool                            is_default_path;
+    kal_uint32                          dummy_para;
+    kal_int32                           fs_api_ret[L4C_MCF_PATH_TYPE_MAX];
+    kal_uint64                          last_mod_time = 0;
+    mcf_tool_gid_tlvota_file_item_t    *pItem;
+    kal_uint16                          item_cnt = 0;
+
+    com_Mcf.is_iccid = KAL_FALSE;
+
+    fs_cmpt.opid_map = NVRAM_FS_CMPT_OPEN | NVRAM_FS_CMPT_GETFILESIZE | NVRAM_FS_CMPT_CLOSE;
+    fs_cmpt.Flag = FS_READ_ONLY;
+    fs_cmpt.Length = 0;
+    fs_cmpt.Offset = 0;
+    fs_cmpt.Whence = FS_FILE_BEGIN;
+    fs_cmpt.DataPtr = &dummy_para;
+    fs_cmpt.Read = &dummy_para;
+    fs_cmpt.FileSize = &file_size;
+
+    if ( (strcmp(req_fs_root_path, "") != 0) && (strcmp(req_file_path_name, "") != 0) ) {
+        if (strcmp(req_fs_root_path, MCF_FS_DEFAULT_FOLDER_PATH) == 0) {
+            *apply_path_type = L4C_MCF_PATH_TYPE_OTA;
+        } else if (strcmp(req_fs_root_path, MCF_FS_CUSTOM_FOLDER_PATH) == 0) {
+            *apply_path_type = L4C_MCF_PATH_TYPE_RUNTIME;
+        } else{
+            MD_TRC_MCF_TR_READ_GENERAL_TLVOTA_FILE_INVALID_PATH(req_fs_root_path);
+            ret = MCF_OTA_R_INVALID_PARAMETER;
+
+            return ret;
+        }
+        kal_wsprintf(filename, "%s\\%s\0", req_fs_root_path, req_file_path_name);
+        strncpy(apply_filename, req_file_path_name, MCF_FILE_MAX_NAME_LEN - 1);
+        is_default_path = KAL_FALSE;
+    } else {
+        /* Compare modified time of general OP-OTA file to select which file to be applied */
+        kal_wsprintf(filename, "%s\\%s\0", MCF_FS_DEFAULT_FOLDER_PATH, MCF_FS_GENERAL_TLVOTA_FILE_NAME);
+        fs_api_ret[L4C_MCF_PATH_TYPE_OTA] = FS_GetFileDetail(filename, &fs_file_detail[L4C_MCF_PATH_TYPE_OTA]);
+        MD_TRC_MCF_TR_READ_GENERAL_TLVOTA_FILE_MODIFIED_TIME(L4C_MCF_PATH_TYPE_OTA, fs_api_ret[L4C_MCF_PATH_TYPE_OTA],
+                         (kal_uint32)((fs_file_detail[L4C_MCF_PATH_TYPE_OTA].LastStatusChangeTime >> 32) & 0xFFFFFFFF), (kal_uint32)(fs_file_detail[L4C_MCF_PATH_TYPE_OTA].LastStatusChangeTime & 0xFFFFFFFF));
+        if (fs_api_ret[L4C_MCF_PATH_TYPE_OTA] != FS_NO_ERROR) {
+            kal_mem_set(&fs_file_detail[L4C_MCF_PATH_TYPE_OTA], 0, sizeof(FS_FileDetail));
+        }
+
+        kal_wsprintf(filename, "%s\\%s\0", MCF_FS_CUSTOM_FOLDER_PATH, MCF_FS_GENERAL_TLVOTA_FILE_NAME);
+        fs_api_ret[L4C_MCF_PATH_TYPE_RUNTIME] = FS_GetFileDetail(filename, &fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME]);
+        MD_TRC_MCF_TR_READ_GENERAL_TLVOTA_FILE_MODIFIED_TIME(L4C_MCF_PATH_TYPE_RUNTIME, fs_api_ret[L4C_MCF_PATH_TYPE_RUNTIME],
+                         (kal_uint32)((fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME].LastStatusChangeTime >> 32) & 0xFFFFFFFF), (kal_uint32)(fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME].LastStatusChangeTime & 0xFFFFFFFF));
+        if (fs_api_ret[L4C_MCF_PATH_TYPE_RUNTIME] != FS_NO_ERROR) {
+            kal_mem_set(&fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME], 0, sizeof(FS_FileDetail));
+        }
+
+        if ( (fs_api_ret[L4C_MCF_PATH_TYPE_OTA] == FS_NO_ERROR) || (fs_api_ret[L4C_MCF_PATH_TYPE_RUNTIME] == FS_NO_ERROR) ) {
+            if (fs_file_detail[L4C_MCF_PATH_TYPE_OTA].LastStatusChangeTime > fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME].LastStatusChangeTime) {
+                *apply_path_type = L4C_MCF_PATH_TYPE_OTA;
+                kal_wsprintf(filename, "%s\\%s\0", MCF_FS_DEFAULT_FOLDER_PATH, MCF_FS_GENERAL_TLVOTA_FILE_NAME);
+            } else {
+                *apply_path_type = L4C_MCF_PATH_TYPE_RUNTIME;
+                kal_wsprintf(filename, "%s\\%s\0", MCF_FS_CUSTOM_FOLDER_PATH, MCF_FS_GENERAL_TLVOTA_FILE_NAME);
+            }
+        } else {
+            if (is_booting == KAL_TRUE) {
+                com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_READ_OTA_FILE_FAIL;
+                MCF_BOOT_TRACE(MCF_BOOT_TR_READ_GENERAL_TLVOTA_FILE_COMPARE_FAIL);
+            }
+            MD_TRC_MCF_TR_READ_GENERAL_TLVOTA_FILE_COMPARE_FAIL();
+            ret = MCF_OTA_R_READ_OTA_FILE_FAIL;
+
+            return ret;
+        }
+
+        strncpy(apply_filename, MCF_FS_GENERAL_TLVOTA_FILE_NAME, MCF_FILE_MAX_NAME_LEN - 1);
+        is_default_path = KAL_TRUE;
+    }
+
+    fs_api_ret[0] = MCF_FS_CMPT_Read(filename, &fs_cmpt);
+    if (fs_api_ret[0] < FS_NO_ERROR) {
+        if (is_booting == KAL_TRUE) {
+            MCF_BOOT_TRACE(MCF_BOOT_TR_READ_GENERAL_TLVOTA_FILE_FAIL, *apply_path_type, fs_api_ret[0]);
+            MCF_BOOT_TRACE(MCF_BOOT_TR_STRING, apply_filename);
+        }
+        MD_TRC_MCF_TR_READ_GENERAL_TLVOTA_FILE_FAIL(*apply_path_type, fs_api_ret[0]);
+        dhl_print_string(TRACE_INFO, DHL_USER_FLAG_NONE, MOD_MCF, apply_filename);
+
+        /* If cannot read given TLV-OTA file, read default TLV-OTA file */
+        if (is_default_path == KAL_FALSE) {
+            /* Compare modified time of general OP-OTA file to select which file to be applied */
+            kal_wsprintf(filename, "%s\\%s\0", MCF_FS_DEFAULT_FOLDER_PATH, MCF_FS_GENERAL_TLVOTA_FILE_NAME);
+            fs_api_ret[L4C_MCF_PATH_TYPE_OTA] = FS_GetFileDetail(filename, &fs_file_detail[L4C_MCF_PATH_TYPE_OTA]);
+            MD_TRC_MCF_TR_READ_GENERAL_TLVOTA_FILE_MODIFIED_TIME(L4C_MCF_PATH_TYPE_OTA, fs_api_ret[L4C_MCF_PATH_TYPE_OTA],
+                             (kal_uint32)((fs_file_detail[L4C_MCF_PATH_TYPE_OTA].LastStatusChangeTime >> 32) & 0xFFFFFFFF), (kal_uint32)(fs_file_detail[L4C_MCF_PATH_TYPE_OTA].LastStatusChangeTime & 0xFFFFFFFF));
+            if (fs_api_ret[L4C_MCF_PATH_TYPE_OTA] != FS_NO_ERROR) {
+                kal_mem_set(&fs_file_detail[L4C_MCF_PATH_TYPE_OTA], 0, sizeof(FS_FileDetail));
+            }
+
+            kal_wsprintf(filename, "%s\\%s\0", MCF_FS_CUSTOM_FOLDER_PATH, MCF_FS_GENERAL_TLVOTA_FILE_NAME);
+            fs_api_ret[L4C_MCF_PATH_TYPE_RUNTIME] = FS_GetFileDetail(filename, &fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME]);
+            MD_TRC_MCF_TR_READ_GENERAL_TLVOTA_FILE_MODIFIED_TIME(L4C_MCF_PATH_TYPE_RUNTIME, fs_api_ret[L4C_MCF_PATH_TYPE_RUNTIME],
+                             (kal_uint32)((fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME].LastStatusChangeTime >> 32) & 0xFFFFFFFF), (kal_uint32)(fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME].LastStatusChangeTime & 0xFFFFFFFF));
+            if (fs_api_ret[L4C_MCF_PATH_TYPE_RUNTIME] != FS_NO_ERROR) {
+                kal_mem_set(&fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME], 0, sizeof(FS_FileDetail));
+            }
+
+            if ( (fs_api_ret[L4C_MCF_PATH_TYPE_OTA] == FS_NO_ERROR) || (fs_api_ret[L4C_MCF_PATH_TYPE_RUNTIME] == FS_NO_ERROR) ) {
+                if (fs_file_detail[L4C_MCF_PATH_TYPE_OTA].LastStatusChangeTime > fs_file_detail[L4C_MCF_PATH_TYPE_RUNTIME].LastStatusChangeTime) {
+                    *apply_path_type = L4C_MCF_PATH_TYPE_OTA;
+                    kal_wsprintf(filename, "%s\\%s\0", MCF_FS_DEFAULT_FOLDER_PATH, MCF_FS_GENERAL_TLVOTA_FILE_NAME);
+                } else {
+                    *apply_path_type = L4C_MCF_PATH_TYPE_RUNTIME;
+                    kal_wsprintf(filename, "%s\\%s\0", MCF_FS_CUSTOM_FOLDER_PATH, MCF_FS_GENERAL_TLVOTA_FILE_NAME);
+                }
+            } else {
+                if (is_booting == KAL_TRUE) {
+                    com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_READ_OTA_FILE_FAIL;
+                    MCF_BOOT_TRACE(MCF_BOOT_TR_READ_GENERAL_TLVOTA_FILE_COMPARE_FAIL);
+                }
+                MD_TRC_MCF_TR_READ_GENERAL_TLVOTA_FILE_COMPARE_FAIL();
+                ret = MCF_OTA_R_READ_OTA_FILE_FAIL;
+
+                return ret;
+            }
+
+            strncpy(apply_filename, MCF_FS_GENERAL_TLVOTA_FILE_NAME, MCF_FILE_MAX_NAME_LEN - 1);
+
+            fs_api_ret[0] = MCF_FS_CMPT_Read(filename, &fs_cmpt);
+            if (fs_api_ret[0] < FS_NO_ERROR) {
+                if (is_booting == KAL_TRUE) {
+                    com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_READ_TLVOTA_FILE_FAIL;
+                    MCF_BOOT_TRACE(MCF_BOOT_TR_READ_GENERAL_TLVOTA_FILE_FAIL, *apply_path_type, fs_api_ret[0]);
+                    MCF_BOOT_TRACE(MCF_BOOT_TR_STRING, apply_filename);
+                }
+                MD_TRC_MCF_TR_READ_GENERAL_TLVOTA_FILE_FAIL(*apply_path_type, fs_api_ret[0]);
+                dhl_print_string(TRACE_INFO, DHL_USER_FLAG_NONE, MOD_MCF, apply_filename);
+                ret = MCF_OTA_R_READ_OTA_FILE_FAIL;
+
+                return ret;
+            }
+        } else {
+            ret = MCF_OTA_R_READ_OTA_FILE_FAIL;
+
+            return ret;
+        }
+    }
+
+    if (file_size > MCF_MAX_TLVOTA_FILE_SIZE) {
+        if (is_booting == KAL_TRUE) {
+            com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_TLVOTA_FILE_OVERSIZE;
+            MCF_BOOT_TRACE(MCF_BOOT_TR_READ_GENERAL_TLVOTA_FILE_OVERSIZE, file_size, MCF_MAX_TLVOTA_FILE_SIZE);
+        }
+        MD_TRC_MCF_TR_READ_GENERAL_TLVOTA_FILE_OVERSIZE(file_size, MCF_MAX_TLVOTA_FILE_SIZE);
+        ret = MCF_OTA_R_READ_OTA_FILE_FAIL;
+
+        return ret;
+    }
+
+    /* Read file */
+    fs_cmpt.opid_map = NVRAM_FS_CMPT_OPEN | NVRAM_FS_CMPT_READ | NVRAM_FS_CMPT_CLOSE;
+    fs_cmpt.Flag = FS_READ_ONLY;
+    fs_cmpt.Length = file_size;
+    fs_cmpt.Offset = 0;
+    fs_cmpt.Whence = FS_FILE_BEGIN;
+    fs_cmpt.DataPtr = tlvota_file->buff;
+    fs_cmpt.Read = &read_byte;
+    fs_cmpt.FileSize = &dummy_para;
+
+    fs_api_ret[*apply_path_type] = FS_GetFileDetail(filename, &fs_file_detail[*apply_path_type]);
+    MD_TRC_MCF_TR_READ_GENERAL_TLVOTA_FILE_MODIFIED_TIME(*apply_path_type, fs_api_ret[*apply_path_type],
+                     (kal_uint32)((fs_file_detail[*apply_path_type].LastStatusChangeTime >> 32) & 0xFFFFFFFF), (kal_uint32)(fs_file_detail[*apply_path_type].LastStatusChangeTime & 0xFFFFFFFF));
+    if (fs_api_ret[*apply_path_type] == FS_NO_ERROR) {
+        last_mod_time = fs_file_detail[*apply_path_type].LastStatusChangeTime;
+    } else {
+        if (is_booting == KAL_TRUE) {
+            com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_READ_TLVOTA_FILE_FAIL;
+            MCF_BOOT_TRACE(MCF_BOOT_TR_READ_GENERAL_TLVOTA_FILE_FAIL, *apply_path_type, fs_api_ret[0]);
+            MCF_BOOT_TRACE(MCF_BOOT_TR_STRING, apply_filename);
+        }
+        MD_TRC_MCF_TR_READ_GENERAL_TLVOTA_FILE_FAIL(*apply_path_type, fs_api_ret[*apply_path_type]);
+        dhl_print_string(TRACE_INFO, DHL_USER_FLAG_NONE, MOD_MCF, apply_filename);
+        ret = MCF_OTA_R_READ_OTA_FILE_FAIL;
+
+        return ret;
+    }
+
+    MCF_W_LOCK_OBJECT(tlvota_file, mcf_enhmutex_g);
+    if (tlvota_file) {
+        fs_api_ret[0] = MCF_FS_CMPT_Read(filename, &fs_cmpt);
+        if (fs_api_ret[0] < FS_NO_ERROR) {
+            MCF_W_UNLOCK_OBJECT(tlvota_file, mcf_enhmutex_g);
+            if (is_booting == KAL_TRUE) {
+                com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_READ_TLVOTA_FILE_FAIL;
+                MCF_BOOT_TRACE(MCF_BOOT_TR_READ_GENERAL_TLVOTA_FILE_FAIL, *apply_path_type, fs_api_ret[0]);
+                MCF_BOOT_TRACE(MCF_BOOT_TR_STRING, apply_filename);
+            }
+            MD_TRC_MCF_TR_READ_GENERAL_TLVOTA_FILE_FAIL(*apply_path_type, fs_api_ret[0]);
+            dhl_print_string(TRACE_INFO, DHL_USER_FLAG_NONE, MOD_MCF, apply_filename);
+            ret = MCF_OTA_R_READ_OTA_FILE_FAIL;
+
+            return ret;
+        }
+
+        com_Mcf.is_iccid = KAL_FALSE;
+        pFile = (mcf_tool_file_info_t *)(tlvota_file->buff);
+#ifdef __MCF_FIND_TAG_SUPPORT__
+        if (pFile->file_version == 2 || pFile->file_version == 3) { 
+#else
+        if (pFile->file_version == 3) {
+#endif
+            kal_uint32 operation_mask = 0;
+            
+            /* Check custom operation mask */
+            operation_mask = mcf_get_custom_operation_mask();
+            if ((pFile->operation_mask & operation_mask) != operation_mask) {				
+                if (is_booting == KAL_TRUE) {
+                    com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_OPERATION_MASK_FAIL;
+                    MCF_BOOT_TRACE(MCF_BOOT_TR_READ_GENERAL_TLVOTA_FILE_OPERATION_MASK_FAIL, apply_filename, pFile->operation_mask, operation_mask);
+                }
+                MD_TRC_MCF_TR_READ_GENERAL_TLVOTA_FILE_OPERATION_MASK_FAIL(apply_filename, pFile->operation_mask, operation_mask);
+                ret = MCF_OTA_R_INVALID_FILE;
+                
+                kal_mem_set(tlvota_file->buff, 0, MCF_MAX_TLVOTA_FILE_SIZE);
+                kal_mem_set(tlvota_file->relative_path_name, 0, MCF_FILE_MAX_NAME_LEN);
+                tlvota_file->path_type = 0;
+                tlvota_file->last_mod_time = 0;
+                kal_mem_set(&(tlvota_file->last_file), 0, sizeof(mcf_file_info_t));
+                MCF_W_UNLOCK_OBJECT(tlvota_file, mcf_enhmutex_g);
+
+                return ret;
+			}
+            /*  First check digest first 
+             *  If file is encrypted and has checksum.
+             *  Decrypt file before checking checksum.
+             */
+              // RSA verify digest 
+            if ((pFile->operation_mask & MCF_FILE_OP_SHA256_RSA2048) != 0) {
+
+                if (mcf_verify_digest(MCF_FILE_OP_SHA256_RSA2048, (mcf_tool_file_info_t *)(tlvota_file->buff), (mcf_digest *)(tlvota_file->buff + pFile->file_size)) != KAL_TRUE) {
+                    kal_mem_set(tlvota_file->buff, 0, MCF_MAX_TLVOTA_FILE_SIZE );
+                    kal_mem_set(tlvota_file->relative_path_name, 0, MCF_FILE_MAX_NAME_LEN);
+                    tlvota_file->path_type = 0;
+                    tlvota_file->last_mod_time = 0;
+                    kal_mem_set(&(tlvota_file->last_file), 0, sizeof(mcf_file_info_t));
+                    MCF_W_UNLOCK_OBJECT(tlvota_file, mcf_enhmutex_g);
+                    if (is_booting == KAL_TRUE) {
+                        com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_DIGEST_FAIL;
+                        MCF_BOOT_TRACE(MCF_BOOT_TR_READ_GENERAL_TLVOTA_FILE_DIGEST_FAIL, apply_filename);
+                    }
+                    MD_TRC_MCF_TR_READ_GENERAL_TLVOTA_FILE_DIGEST_FAIL(apply_filename); 
+                    ret = MCF_OTA_R_DIGEST_FAIL;
+
+                    return ret;
+                }
+
+            }
+
+            else if ((pFile->operation_mask & MCF_FILE_OP_SHA384_RSA3072) != 0) {
+
+                if (mcf_verify_digest(MCF_FILE_OP_SHA384_RSA3072, (mcf_tool_file_info_t *)(tlvota_file->buff), (mcf_digest *)(tlvota_file->buff + pFile->file_size)) != KAL_TRUE) {
+                    kal_mem_set(tlvota_file->buff, 0, MCF_MAX_TLVOTA_FILE_SIZE );
+                    kal_mem_set(tlvota_file->relative_path_name, 0, MCF_FILE_MAX_NAME_LEN);
+                    tlvota_file->path_type = 0;
+                    tlvota_file->last_mod_time = 0;
+                    kal_mem_set(&(tlvota_file->last_file), 0, sizeof(mcf_file_info_t));
+                    MCF_W_UNLOCK_OBJECT(tlvota_file, mcf_enhmutex_g);
+                    if (is_booting == KAL_TRUE) {
+                        com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_DIGEST_FAIL;
+                        MCF_BOOT_TRACE(MCF_BOOT_TR_READ_GENERAL_TLVOTA_FILE_DIGEST_FAIL, apply_filename);
+                    }
+                    MD_TRC_MCF_TR_READ_GENERAL_TLVOTA_FILE_DIGEST_FAIL(apply_filename); 
+                    ret = MCF_OTA_R_DIGEST_FAIL;
+
+                    return ret;
+                }
+
+            }
+            
+            if ( (pFile->operation_mask & MCF_FILE_OP_AES_128) != 0) {
+                mcf_get_custom_aes_password(password);
+
+                if (mcf_decrypt_128bit(password, (kal_char *)(tlvota_file->buff + pFile->total_len), (pFile->file_size - pFile->total_len) ) != KAL_TRUE) {
+                    kal_mem_set(tlvota_file->buff, 0, MCF_MAX_TLVOTA_FILE_SIZE );
+                    kal_mem_set(tlvota_file->relative_path_name, 0, MCF_FILE_MAX_NAME_LEN);
+                    tlvota_file->path_type = 0;
+                    tlvota_file->last_mod_time = 0;
+                    kal_mem_set(&(tlvota_file->last_file), 0, sizeof(mcf_file_info_t));
+                    MCF_W_UNLOCK_OBJECT(tlvota_file, mcf_enhmutex_g);
+                    if (is_booting == KAL_TRUE) {
+                        com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_DECRYPTION_FAIL;
+                        MCF_BOOT_TRACE(MCF_BOOT_TR_READ_GENERAL_TLVOTA_FILE_DECRYPTION_FAIL, apply_filename);
+                    }
+                    MD_TRC_MCF_TR_READ_GENERAL_TLVOTA_FILE_DECRYPTION_FAIL(apply_filename);
+                    ret = MCF_OTA_R_DECRYPTION_FAIL;
+
+                    return ret;
+                }
+            }
+            else if ((pFile->operation_mask & MCF_FILE_OP_AES_256) != 0) { // for AES_256  
+                mcf_get_custom_aes_password(password);
+
+                if (mcf_decrypt_256bit(password, (kal_char *)(tlvota_file->buff + pFile->total_len), (pFile->file_size - pFile->total_len)) != KAL_TRUE) {
+                    kal_mem_set(tlvota_file->buff, 0, MCF_MAX_TLVOTA_FILE_SIZE);
+                    kal_mem_set(tlvota_file->relative_path_name, 0, MCF_FILE_MAX_NAME_LEN);
+                    tlvota_file->path_type = 0;
+                    tlvota_file->last_mod_time = 0;
+                    kal_mem_set(&(tlvota_file->last_file), 0, sizeof(mcf_file_info_t));
+                    MCF_W_UNLOCK_OBJECT(tlvota_file, mcf_enhmutex_g);
+                    if (is_booting == KAL_TRUE) {
+                        com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_DECRYPTION_FAIL;
+                        MCF_BOOT_TRACE(MCF_BOOT_TR_READ_GENERAL_TLVOTA_FILE_DECRYPTION_FAIL, apply_filename);
+                    }
+                    MD_TRC_MCF_TR_READ_GENERAL_TLVOTA_FILE_DECRYPTION_FAIL(apply_filename); 
+                    ret = MCF_OTA_R_DECRYPTION_FAIL;
+
+                    return ret;
+                }
+            }
+
+            if ( (pFile->operation_mask & MCF_FILE_OP_CHECKSUM) != 0) {
+                if (mcf_check_check_sum((kal_uint32 *)(tlvota_file->buff), pFile->file_size) != 0) {
+                    kal_mem_set(tlvota_file->buff, 0, MCF_MAX_TLVOTA_FILE_SIZE);
+                    kal_mem_set(tlvota_file->relative_path_name, 0, MCF_FILE_MAX_NAME_LEN);
+                    tlvota_file->path_type = 0;
+                    tlvota_file->last_mod_time = 0;
+                    kal_mem_set(&(tlvota_file->last_file), 0, sizeof(mcf_file_info_t));
+                    MCF_W_UNLOCK_OBJECT(tlvota_file, mcf_enhmutex_g);
+                    if (is_booting == KAL_TRUE) {
+                        com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_CHECKSUM_ERROR;
+                        MCF_BOOT_TRACE(MCF_BOOT_TR_READ_GENERAL_TLVOTA_FILE_CHECKSUM_ERROR, apply_filename);
+                    }
+                    MD_TRC_MCF_TR_READ_GENERAL_TLVOTA_FILE_CHECKSUM_ERROR(apply_filename);
+                    ret = MCF_OTA_R_CHECKSUM_ERROR;
+
+                    return ret;
+                }
+            }
+            
+            //Check whether general TLV-OTA have iccid tag
+            pItem = (mcf_tool_gid_tlvota_file_item_t *)(tlvota_file->buff + pFile->total_len);
+            while (item_cnt < pFile->item_num) {
+                if ((pItem->tag_type == MCF_TLVOTA_TAG_ICCID)) {
+                    com_Mcf.is_iccid = KAL_TRUE;
+                    MD_TRC_MCF_TR_READ_GENERAL_TLVOTA_FILE_TAG_TYPE(MCF_TLVOTA_TAG_ICCID);
+                    break;
+                }
+                pItem = (mcf_tool_gid_tlvota_file_item_t *)((kal_uint8 *)pItem + pItem->total_len);
+                item_cnt++;
+            }
+        } else {
+            if (is_booting == KAL_TRUE) {
+                com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_INVALID_FILE;
+                MCF_BOOT_TRACE(MCF_BOOT_TR_READ_GENERAL_TLVOTA_FILE_INVALID_FILE_VERSION, pFile->file_version);
+            }
+            MD_TRC_MCF_TR_READ_GENERAL_TLVOTA_FILE_INVALID_FILE_VERSION(pFile->file_version);
+            kal_mem_set(tlvota_file->buff, 0, MCF_MAX_TLVOTA_FILE_SIZE);
+            kal_mem_set(tlvota_file->relative_path_name, 0, MCF_FILE_MAX_NAME_LEN);
+            tlvota_file->path_type = 0;
+            tlvota_file->last_mod_time = 0;
+            kal_mem_set(&(tlvota_file->last_file), 0, sizeof(mcf_file_info_t));
+            MCF_W_UNLOCK_OBJECT(tlvota_file, mcf_enhmutex_g);
+            ret = MCF_OTA_R_INVALID_FILE;
+
+            return ret;
+        }
+
+        tlvota_file->path_type = *apply_path_type;  
+#if defined(__MCF_UT_FRAMEWORK_SUPPORT__)        
+        if (strcmp(tlvota_file->relative_path_name, "") == 0){
+            strncpy(tlvota_file->relative_path_name, apply_filename, MCF_FILE_MAX_NAME_LEN - 1);
+        }else{
+            strncpy(apply_filename, tlvota_file->relative_path_name, MCF_FILE_MAX_NAME_LEN - 1);
+        }
+#else
+        strncpy(tlvota_file->relative_path_name, apply_filename, MCF_FILE_MAX_NAME_LEN - 1);
+#endif  
+        tlvota_file->last_mod_time = last_mod_time;
+        tlvota_file->last_file.last_mod_time = last_mod_time;
+        MCF_W_UNLOCK_OBJECT(tlvota_file, mcf_enhmutex_g);
+    } else {
+        if (is_booting == KAL_TRUE) {
+            com_Mcf.boot_trace_flag |= MCF_BOOT_TRACE_F_TAKE_WRITE_LOCK_FAIL;
+            MCF_BOOT_TRACE(MCF_BOOT_TR_READ_GENERAL_TLVOTA_FILE_TAKE_WRITE_LOCK_FAIL, apply_filename, *apply_path_type);
+        }
+        MD_TRC_MCF_TR_READ_GENERAL_TLVOTA_FILE_TAKE_WRITE_LOCK_FAIL(apply_filename, *apply_path_type);
+        ret = MCF_OTA_R_READ_OTA_FILE_FAIL;
+    }
+    
+    
+    return ret;
+}
+
+mcf_ota_result_e mcf_read_ini_file(
+    kal_char               *req_fs_root_path,
+    kal_char               *req_file_path_name,
+    l4c_mcf_path_type_enum *apply_path_type,
+    kal_char               *apply_filename,
+    mcf_t                  *pMcf)
+{
+    NVRAM_FS_PARAM_CMPT_T   fs_cmpt;
+    kal_uint32              read_byte = 0;
+    kal_uint32              file_size = 0;
+    mcf_ota_result_e        ret = MCF_OTA_R_SUCCESS;
+    mcf_ini_file_t         *ini_file = &(pMcf->ini_file);
+    kal_wchar               filename[MCF_FILE_MAX_MD_PATH_LEN + MCF_FILE_MAX_NAME_LEN];
+    kal_bool                is_default_path;
+    kal_uint32              dummy_para;
+    kal_int32               fs_api_ret[L4C_MCF_PATH_TYPE_MAX];
+
+    fs_cmpt.opid_map = NVRAM_FS_CMPT_OPEN | NVRAM_FS_CMPT_GETFILESIZE | NVRAM_FS_CMPT_CLOSE;
+    fs_cmpt.Flag = FS_READ_ONLY;
+    fs_cmpt.Length = 0;
+    fs_cmpt.Offset = 0;
+    fs_cmpt.Whence = FS_FILE_BEGIN;
+    fs_cmpt.DataPtr = &dummy_para;
+    fs_cmpt.Read = &dummy_para;
+    fs_cmpt.FileSize = &file_size;
+
+    
+    if ( (strcmp(req_fs_root_path, "") != 0) && (strcmp(req_file_path_name, "") != 0) ) {
+        if (strcmp(req_fs_root_path, MCF_FS_DEFAULT_FOLDER_PATH) == 0) {
+            *apply_path_type = L4C_MCF_PATH_TYPE_OTA;
+        } else if (strcmp(req_fs_root_path, MCF_FS_CUSTOM_FOLDER_PATH) == 0) {
+            *apply_path_type = L4C_MCF_PATH_TYPE_RUNTIME;
+        }
+        kal_wsprintf(filename, "%s\\%s\0", req_fs_root_path, req_file_path_name);
+        strncpy(apply_filename, req_file_path_name, MCF_FILE_MAX_NAME_LEN - 1);
+        is_default_path = KAL_FALSE;
+    } else {
+        if (*apply_path_type == L4C_MCF_PATH_TYPE_OTA) {
+            kal_wsprintf(filename, "%s\\%s\0", MCF_FS_DEFAULT_FOLDER_PATH, apply_filename);
+        } else if (*apply_path_type == L4C_MCF_PATH_TYPE_RUNTIME) {
+            kal_wsprintf(filename, "%s\\%s\0", MCF_FS_CUSTOM_FOLDER_PATH, apply_filename);
+        }
+        strncpy(apply_filename, MCF_FS_DEFAULT_INI_FILE_NAME, MCF_FILE_MAX_NAME_LEN - 1);
+        is_default_path = KAL_TRUE;
+    }
+
+    fs_api_ret[0] = MCF_FS_CMPT_Read(filename, &fs_cmpt);
+    if (fs_api_ret[0] < FS_NO_ERROR) {
+        
+        MD_TRC_MCF_TR_READ_INI_FILE_FAIL(*apply_path_type, fs_api_ret[0]);
+        dhl_print_string(TRACE_INFO, DHL_USER_FLAG_NONE, MOD_MCF, apply_filename);
+
+        /* If cannot read given INI file, read default INI file */
+        if (is_default_path == KAL_FALSE) {
+            if (*apply_path_type == L4C_MCF_PATH_TYPE_OTA) {
+                kal_wsprintf(filename, "%s\\%s\0", MCF_FS_DEFAULT_FOLDER_PATH, apply_filename);
+            } else if (*apply_path_type == L4C_MCF_PATH_TYPE_RUNTIME) {
+                kal_wsprintf(filename, "%s\\%s\0", MCF_FS_CUSTOM_FOLDER_PATH, apply_filename);
+            }
+            strncpy(apply_filename, MCF_FS_DEFAULT_INI_FILE_NAME, MCF_FILE_MAX_NAME_LEN - 1);
+
+            fs_api_ret[0] = MCF_FS_CMPT_Read(filename, &fs_cmpt);
+            if (fs_api_ret[0] < FS_NO_ERROR) {
+                
+                MD_TRC_MCF_TR_READ_INI_FILE_FAIL(*apply_path_type, fs_api_ret[0]);
+                dhl_print_string(TRACE_INFO, DHL_USER_FLAG_NONE, MOD_MCF, apply_filename);
+                ret = MCF_OTA_R_READ_INI_FILE_FAIL;
+
+                return ret;
+            }
+        } else {
+            ret = MCF_OTA_R_READ_INI_FILE_FAIL;
+
+            return ret;
+        }
+    }
+    if (file_size >= MCF_MAX_INI_FILE_SIZE-1) {
+        MD_TRC_MCF_TR_READ_INI_FILE_OVERSIZE(file_size, MCF_MAX_INI_FILE_SIZE);
+        ret = MCF_OTA_R_READ_INI_FILE_FAIL;
+
+        return ret;
+    }
+
+    /* Read file */
+    fs_cmpt.opid_map = NVRAM_FS_CMPT_OPEN | NVRAM_FS_CMPT_READ | NVRAM_FS_CMPT_CLOSE;
+    fs_cmpt.Flag = FS_READ_ONLY;
+    fs_cmpt.Length = file_size;
+    fs_cmpt.Offset = 0;
+    fs_cmpt.Whence = FS_FILE_BEGIN;
+    fs_cmpt.DataPtr = ini_file->buff;
+    fs_cmpt.Read = &read_byte;
+    fs_cmpt.FileSize = &dummy_para;
+
+    
+    fs_api_ret[0] = MCF_FS_CMPT_Read(filename, &fs_cmpt);
+    if (fs_api_ret[0] < FS_NO_ERROR) {
+        MD_TRC_MCF_TR_READ_INI_FILE_FAIL(*apply_path_type, fs_api_ret[0]);
+        dhl_print_string(TRACE_INFO, DHL_USER_FLAG_NONE, MOD_MCF, apply_filename);
+        ret = MCF_OTA_R_READ_OTA_FILE_FAIL;
+        return ret;
+    }
+    
+    if (file_size < MCF_MAX_INI_FILE_SIZE){
+        ini_file->buff[file_size] = '\0';
+    }
+    
+    
+    return ret;
+}
+
+kal_bool mcf_find_ini_item(kal_char* buff, kal_char *item, kal_char *value, mcf_t *pMcf)
+{
+    kal_bool   ret = KAL_TRUE;
+    kal_char *varstr = NULL, *substr = NULL;
+    kal_char *saveptr = NULL;
+    kal_char *item_ptr = NULL;
+    kal_char *item_tag = NULL;
+    mcf_ini_file_t *ini_file = &(pMcf->ini_file);
+    kal_char  *buffer = (kal_char *)ini_file->tmp_buff;
+     
+    
+    
+    //buff and item cannot be NULL
+    if(buff == NULL || item == NULL) {
+        MD_TRC_MCF_TR_FIND_INI_ITEM_ERROR_INPUT_NULL();
+        ret = KAL_FALSE;
+        return ret;
+    }
+    
+    MD_TRC_MCF_TR_FIND_INI_ITEM_START(item);
+        
+    /* Remove space and to uppercase */
+    mcf_remove_spaces_and_carrier_return(buff);
+    mcf_toupper(buff);
+    mcf_toupper(item);
+    mcf_remove_spaces_and_carrier_return(item);
+    
+    kal_mem_set(buffer,0,MCF_MAX_INI_FILE_SIZE);
+    strncpy(buffer,buff,MCF_MAX_INI_FILE_SIZE-1);
+    buffer[MCF_MAX_INI_FILE_SIZE-1] = '\0';
+    
+    
+    item_ptr = strstr (buffer,item);
+    if (item_ptr != 0) {
+        item_tag = kal_strtok_r(item_ptr,"=",&saveptr);
+        substr = kal_strtok_r(NULL,"=",&saveptr);
+        if (item_tag != 0) {
+            if (strcmp(item_tag,item) == 0){ 
+                if (substr != NULL){
+                    varstr = strstr(substr,"\n");
+                    if (varstr == NULL){
+                        if (strlen(substr) > MCF_MAX_INI_ITEM_VALUE_LEN-1){
+                            memset(value, 0, MCF_MAX_INI_ITEM_VALUE_LEN);
+                            strncpy(value, substr, MCF_MAX_INI_ITEM_VALUE_LEN);
+                        }else{
+                            memset(value, 0, MCF_MAX_INI_ITEM_VALUE_LEN);
+                            strncpy(value, substr, strlen(substr));
+                        }
+                        
+                    }else{
+                        if (strlen(substr)-strlen(varstr) + 1 > MCF_MAX_INI_ITEM_VALUE_LEN-1){
+                            memset(value, 0, MCF_MAX_INI_ITEM_VALUE_LEN);
+                            strncpy(value, substr, MCF_MAX_INI_ITEM_VALUE_LEN);
+                        }else{
+                            memset(value, 0, MCF_MAX_INI_ITEM_VALUE_LEN);
+                            strncpy(value, substr, strlen(substr)-strlen(varstr));
+                        }
+                        
+                        
+                    }
+                }else{
+                    value = NULL;
+                    MD_TRC_MCF_TR_FIND_INI_ITEM_ERROR_CAN_NOT_FIND_ITEM();
+                    ret = KAL_FALSE;
+                    return ret;
+                }
+            }else{
+                value = NULL;
+                MD_TRC_MCF_TR_FIND_INI_ITEM_ERROR_ITEM_LENGTH();
+                ret = KAL_FALSE;
+                return ret;
+            }
+            
+        } else {
+            value = NULL;
+            MD_TRC_MCF_TR_FIND_INI_ITEM_ERROR_CAN_NOT_FIND_ITEM();
+            ret = KAL_FALSE;
+            return ret;
+        }
+    } else {
+        value = NULL;
+        MD_TRC_MCF_TR_FIND_INI_ITEM_ERROR_CAN_NOT_FIND_ITEM();
+        ret = KAL_FALSE;
+        return ret;
+    }
+            
+    
+    
+    MD_TRC_MCF_TR_FIND_INI_ITEM_RETURN_VALUE(item, value);
+    
+    return ret;
+}
+
+kal_bool mcf_find_ini_sbp_id(kal_char *tag_str, kal_uint32 *sbp_id, kal_uint16 *sbp_id_num, kal_bool *general)
+{
+    kal_uint16 i = 0;
+    kal_bool   ret = KAL_TRUE;
+    kal_char *saveptr = NULL, *varstr = NULL, *substr = NULL, *tmpstr = NULL;
+    kal_char *sbp_id_tag[MCF_MAX_TAG_NUM];
+    kal_uint16 tag_cnt = 0;
+    kal_char *tag[MCF_MAX_TAG_NUM];
+    kal_uint16 tag_num = 0;
+    
+    MD_TRC_MCF_TR_FIND_INI_SBP_ID_START(tag_str);
+    
+    //buff and item cannot be NULL
+    if(tag_str == NULL) {
+        MD_TRC_MCF_TR_FIND_INI_SBP_ID_ERROR_INPUT_NULL();
+        ret = KAL_FALSE;
+        return ret;
+    }
+    
+    
+    //Split ',' from tag
+    substr = kal_strtok_r(tag_str, ",", &saveptr);
+    
+    if (substr == NULL){
+        MD_TRC_MCF_TR_FIND_INI_SBP_ID_ERROR_CAN_NOT_FIND_ITEM();
+        ret = KAL_FALSE;
+        return ret;
+    }
+
+    
+    while(substr != NULL){
+        tag[tag_cnt] = substr;
+        tag_cnt++;
+        substr = kal_strtok_r(NULL, ",",&saveptr); 
+   }
+    
+    
+    
+    /* ICCID case should apply general tlvota*/
+    tmpstr = strstr(tag[0], "_");
+    if (tmpstr == NULL){
+        *general = KAL_TRUE;
+        MD_TRC_MCF_TR_FIND_INI_SBP_ID_ICCID_USIR(tag[0]);
+    }
+    
+    //Split '_' from SBPID_MNC_MCC tag
+    sbp_id_tag[0] = kal_strtok_r(tag[0], "_", &saveptr);
+    
+    if (strcmp(sbp_id_tag[0],"") == 0){
+        MD_TRC_MCF_TR_FIND_INI_SBP_ID_ERROR_CAN_NOT_FIND_ITEM();
+    }
+    
+    
+    /* NA case should apply general tlvota */
+    if (strcmp(sbp_id_tag[0],"NA") == 0){
+        *general = KAL_TRUE;
+        MD_TRC_MCF_TR_FIND_INI_SBP_ID_NA(*general);
+    }
+    
+    for (i = 1; i < tag_cnt; i++){
+        
+        tmpstr = strstr(tag[i], "_");
+        if (tmpstr == NULL){
+            *general = KAL_TRUE;
+            if(i+1 < tag_cnt){
+                i++;
+            }
+        }else{
+            varstr = kal_strtok_r(tag[i], "_",&saveptr);
+            if(varstr == NULL){
+				*general = KAL_TRUE;
+                if(i+1 < tag_cnt){
+                    i++;
+                }
+			}else{
+				if(strcmp(varstr,"NA") == 0){
+					*general = KAL_TRUE;
+					if(i+1 < tag_cnt){
+						i++;
+					}
+                }
+				if (strcmp(varstr,sbp_id_tag[tag_num]) != 0){
+					//save different sbp_id
+					tag_num++;
+					sbp_id_tag[tag_num] = varstr;
+				}
+			}
+        }
+   }
+   
+   for (i = 0; i < tag_num + 1; i++){
+       sbp_id[i] = mcf_atoi(sbp_id_tag[i]);
+   }
+   
+ 
+   
+   *sbp_id_num = tag_num + 1;
+   
+    MD_TRC_MCF_TR_FIND_INI_SBP_ID_RETURN_NUM(*sbp_id_num);
+    
+    return ret;
+}
+
+kal_bool mcf_compose_ini_item(kal_char *orig_buff, kal_char *new_buff, kal_char *item, kal_char *orig_value, kal_char *value)
+{
+    kal_bool ret = KAL_TRUE;
+    kal_char *tmpstr = NULL, *varstr = NULL, *substr = NULL;
+    kal_uint32 len = 0;
+    
+    MD_TRC_MCF_TR_COMPOSE_INI_ITEM_START(item, orig_value);
+    
+    mcf_remove_spaces_and_carrier_return(orig_buff);
+    mcf_remove_spaces_and_carrier_return(item);
+    kal_mem_set(new_buff, 0, MCF_MAX_INI_FILE_SIZE);
+    
+    substr = strstr (orig_buff,"\0");
+    if (substr != NULL){
+        len = strlen(orig_buff);
+    }else{
+        MD_TRC_MCF_TR_COMPOSE_INI_ITEM_INVALID_BUFF();
+        ret = KAL_FALSE;
+        return ret;
+    }
+    
+    
+    
+    substr = strstr (orig_buff,item);
+    if (substr != NULL){
+        varstr = strstr(substr,"=");
+        if (varstr != NULL){
+            if (strlen(substr)-strlen(varstr) == strlen(item)){
+				if(strcmp(orig_value,"") != 0){
+                    tmpstr = strstr(substr,orig_value);
+                    if (tmpstr != NULL){
+                        if ((len-strlen(varstr)+4+strlen(value)+strlen(tmpstr)-strlen(orig_value)) >= MCF_MAX_INI_FILE_SIZE){
+                            MD_TRC_MCF_TR_COMPOSE_INI_ITEM_INVALID_BUFF_LENGTH();
+                            ret = KAL_FALSE;
+                            return ret;
+                        }
+                        strncpy(new_buff,orig_buff,len-strlen(varstr));
+                        strncat (new_buff,"=", MCF_MAX_INI_FILE_SIZE - 1);
+                        strncat (new_buff,value, MCF_MAX_INI_FILE_SIZE - 1);
+                        strncat (new_buff,tmpstr+strlen(orig_value), MCF_MAX_INI_FILE_SIZE - 1);
+                        strncat (new_buff,"\n\0", MCF_MAX_INI_FILE_SIZE - 1);
+                    }else{
+                        MD_TRC_MCF_TR_COMPOSE_INI_ITEM_INVALID_ORIGINAL_VALUE(orig_value);
+                        ret = KAL_FALSE;
+                        return ret;
+                    }
+				}else{
+                    if ((len-strlen(varstr)+4+strlen(value)+strlen(substr)-strlen(item)) >= MCF_MAX_INI_FILE_SIZE){
+                        MD_TRC_MCF_TR_COMPOSE_INI_ITEM_INVALID_BUFF_LENGTH();
+                        ret = KAL_FALSE;
+                        return ret;
+                    }
+                    strncpy(new_buff,orig_buff,len-strlen(varstr));
+                    strncat (new_buff,"=", MCF_MAX_INI_FILE_SIZE - 1);
+                    strncat (new_buff,value, MCF_MAX_INI_FILE_SIZE - 1);
+                    strncat (new_buff,"\n", MCF_MAX_INI_FILE_SIZE - 1);
+                    strncat (new_buff,substr+strlen(item)+1, MCF_MAX_INI_FILE_SIZE - 1);
+                    strncat (new_buff,"\n\0", MCF_MAX_INI_FILE_SIZE - 1);
+                }
+            }else{
+                MD_TRC_MCF_TR_COMPOSE_INI_ITEM_ERROR_ITEM_LENGTH();
+                ret = KAL_FALSE;
+                return ret;
+                
+            }
+        }else{
+            tmpstr = strstr(substr,orig_value);
+            if (tmpstr != NULL){
+                if ((len+4+strlen(value)+strlen(tmpstr)-strlen(orig_value)) >= MCF_MAX_INI_FILE_SIZE){
+                    MD_TRC_MCF_TR_COMPOSE_INI_ITEM_INVALID_BUFF_LENGTH();
+                    ret = KAL_FALSE;
+                    return ret;
+                }
+                strncpy(new_buff,orig_buff,len);
+                strncat (new_buff,"=", MCF_MAX_INI_FILE_SIZE - 1);
+                strncat (new_buff,value, MCF_MAX_INI_FILE_SIZE - 1);
+                strncat (new_buff,tmpstr+strlen(orig_value), MCF_MAX_INI_FILE_SIZE - 1);
+                strncat (new_buff,"\n\0", MCF_MAX_INI_FILE_SIZE - 1);
+            }else{
+                MD_TRC_MCF_TR_COMPOSE_INI_ITEM_INVALID_ORIGINAL_VALUE(orig_value);
+                ret = KAL_FALSE;
+                return ret;
+            }
+        }
+
+        
+    }
+    else{
+        //new item
+        if ((len+5+strlen(item)+strlen(value)) >= MCF_MAX_INI_FILE_SIZE){
+            MD_TRC_MCF_TR_COMPOSE_INI_ITEM_INVALID_BUFF_LENGTH();
+            ret = KAL_FALSE;
+            return ret;
+        }
+        strncpy(new_buff,orig_buff, MCF_MAX_INI_FILE_SIZE - 1);
+        strncat(new_buff,"\n", MCF_MAX_INI_FILE_SIZE - 1);
+        strncat(new_buff,item, MCF_MAX_INI_FILE_SIZE - 1);
+        strncat(new_buff,"=", MCF_MAX_INI_FILE_SIZE - 1);
+        strncat(new_buff,value, MCF_MAX_INI_FILE_SIZE - 1);
+        strncat (new_buff,"\n\0", MCF_MAX_INI_FILE_SIZE - 1);
+    }
+    
+    
+    return ret;
+}
+
+void mcf_dump_data(kal_bool is_booting, void *p_data, kal_uint32 len)
+{
+    kal_uint32  i = 0;
+    kal_uint32  buff;
+
+    for (i = 0; len > 0; i++){
+        if (len >= 4) {
+            buff = 0;
+            kal_mem_cpy(&buff, (kal_uint8 *)p_data + (i * 4), 4);
+            len -= 4;
+        } else {
+            buff = 0;
+            kal_mem_cpy(&buff, (kal_uint8 *)p_data + (i * 4), len);
+            len = 0;
+        }
+
+        if (is_booting == KAL_TRUE) {
+            MCF_BOOT_TRACE(MCF_BOOT_TR_DATA_DUMP_TRACE, i, buff);
+        }
+        MD_TRC_MCF_TR_DATA_DUMP_TRACE(i, buff);
+    }
+}
+
+#define GUARD_PARRTEN 0xAABBCCDD
+#define FULL_PARRTEN  0xAABBFFFF
+void mcf_write_boot_trace(kal_uint32 trace_enum, ...)
+{
+    va_list ap;
+    kal_uint32 i = 0;
+    kal_uint32 *value= NULL;
+    char *substr = NULL;
+    // store into com_Mcf.boot_trace_buff
+    // enum, num, type, size, value, type, size, value
+    // enum, num, type, size, value, type, size, value
+    // enum, num, type, size, value, type, size, value
+    mcf_boot_trace_struct *trace_ptr = (mcf_boot_trace_struct *)com_Mcf.boot_trace_buff_ptr;
+    mcf_boot_trace_value_struct *value_ptr = NULL;
+    
+    if(com_Mcf.boot_trace_buff_ptr == NULL ){
+        com_Mcf.boot_trace_buff_ptr = (kal_uint32 *)com_Mcf.boot_trace_buff;
+        trace_ptr = (mcf_boot_trace_struct *)com_Mcf.boot_trace_buff_ptr;
+    } 
+    
+    value_ptr = &trace_ptr->value_ptr;
+    
+    if((char *)trace_ptr + 512 > (char *)com_Mcf.boot_trace_buff + sizeof(com_Mcf.boot_trace_buff))
+    {
+        if(com_Mcf.boot_trace_full == 1) return;
+		com_Mcf.boot_trace_full = 1;
+        trace_ptr->guard_pattern = GUARD_PARRTEN;
+        trace_ptr->trace_enum = FULL_PARRTEN;
+        com_Mcf.boot_trace_buff_ptr = (kal_uint32 *)(trace_ptr+1);
+        return;
+    }        
+    
+    trace_ptr->guard_pattern = GUARD_PARRTEN;
+    trace_ptr->trace_enum = trace_enum;
+    
+    substr = strstr(boot_trace_format[trace_enum].log_format, "%");
+    va_start(ap, trace_enum);
+    while ( (kal_uint32)(value = (kal_uint32 *)va_arg(ap,void *)) != END_PATTERN)
+    {
+        if(substr == NULL) break;
+
+        switch(*(substr + 1))
+        {
+            case 's':
+            {
+                char *string_ptr = (char *)value;
+                value_ptr->size = strlen(string_ptr);
+                kal_mem_cpy(&value_ptr->type_u.string, string_ptr, value_ptr->size + 1);
+                value_ptr->size = ((value_ptr->size + 4) >> 2 ) << 2 ; // size pedding to 4 byte alignment
+                value_ptr->type = MCF_TYPE_STRING;
+            }
+            break;
+            default:
+            {
+                value_ptr->size = sizeof(kal_uint32);
+                value_ptr->type_u.integer = (kal_uint32)value;
+                value_ptr->type = MCF_TYPE_INTEGER;
+            }
+            break;
+        }
+        
+        i++;
+        value_ptr = (mcf_boot_trace_value_struct *)((kal_uint8 *)&value_ptr->type_u.value + value_ptr->size);
+        
+        substr = strstr(substr + 1, "%");
+    }
+    va_end(ap);
+    
+    trace_ptr->total_num = i;
+    
+    if(trace_ptr->total_num == 0 ) com_Mcf.boot_trace_buff_ptr = (kal_uint32 *)(trace_ptr+1);
+    else com_Mcf.boot_trace_buff_ptr = (kal_uint32 *)value_ptr;
+}
+
+void mcf_dump_boot_trace(void)
+{
+    mcf_boot_trace_struct *trace_ptr = (mcf_boot_trace_struct *)com_Mcf.boot_trace_buff;
+    kal_uint32 i = 0;
+    mcf_boot_trace_value_struct value_list[7]; // max DHL arg is 7
+    mcf_boot_trace_value_struct *current_value;
+    
+    while ((char *)trace_ptr < (char *)com_Mcf.boot_trace_buff_ptr)
+    {
+        ASSERT(trace_ptr->guard_pattern == GUARD_PARRTEN);
+        current_value = &trace_ptr->value_ptr;
+        
+        if(trace_ptr->trace_enum == FULL_PARRTEN)
+        {
+            MCF_BOOT_PRINT("[MCF] boot trace buffer full!!!");
+            break;
+        }
+        
+        for(i = 0 ; i < trace_ptr->total_num ; i++)
+        {
+            value_list[i].size = current_value->size;
+            switch(current_value->type)
+            {
+                case MCF_TYPE_INTEGER:
+                    value_list[i].type_u.value = current_value->type_u.integer;
+                break;
+                case MCF_TYPE_STRING:
+                    value_list[i].type_u.value = (kal_uint32)&current_value->type_u.string;
+                break;
+                default:
+                break;
+            }
+            current_value = (mcf_boot_trace_value_struct *)((kal_uint8 *)&current_value->type_u.value + current_value->size);
+        }
+        switch(trace_ptr->total_num)
+        {
+            case 0:
+            MCF_BOOT_PRINT(boot_trace_format[trace_ptr->trace_enum].log_format);
+            break;
+            case 1:
+            MCF_BOOT_PRINT(boot_trace_format[trace_ptr->trace_enum].log_format, value_list[0].type_u.value);
+            break;
+            case 2:
+            MCF_BOOT_PRINT(boot_trace_format[trace_ptr->trace_enum].log_format, value_list[0].type_u.value, value_list[1].type_u.value);
+            break;
+            case 3:
+            MCF_BOOT_PRINT(boot_trace_format[trace_ptr->trace_enum].log_format, value_list[0].type_u.value, value_list[1].type_u.value, value_list[2].type_u.value);
+            break;
+            case 4:
+            MCF_BOOT_PRINT(boot_trace_format[trace_ptr->trace_enum].log_format, value_list[0].type_u.value, value_list[1].type_u.value, value_list[2].type_u.value, value_list[3].type_u.value);
+            break;
+            case 5:
+            MCF_BOOT_PRINT(boot_trace_format[trace_ptr->trace_enum].log_format, value_list[0].type_u.value, value_list[1].type_u.value, value_list[2].type_u.value, value_list[3].type_u.value, value_list[4].type_u.value);
+            break;
+            case 6:
+            MCF_BOOT_PRINT(boot_trace_format[trace_ptr->trace_enum].log_format, value_list[0].type_u.value, value_list[1].type_u.value, value_list[2].type_u.value, value_list[3].type_u.value, value_list[4].type_u.value, value_list[5].type_u.value);
+            break;
+            case 7:
+            MCF_BOOT_PRINT(boot_trace_format[trace_ptr->trace_enum].log_format, value_list[0].type_u.value, value_list[1].type_u.value, value_list[2].type_u.value, value_list[3].type_u.value, value_list[4].type_u.value, value_list[5].type_u.value, value_list[6].type_u.value);
+            break;
+        }
+        
+        if(trace_ptr->total_num == 0) trace_ptr++;
+        else trace_ptr = (mcf_boot_trace_struct *)current_value;
+    }
+}
+
+mcf_ota_result_e mcf_write_buffer(
+    kal_char *folder_path,
+    kal_char *file_name,
+    kal_uint8 *buffer,
+    kal_uint32 total_size)
+{
+    mcf_ota_result_e    mcf_ret = MCF_OTA_R_SUCCESS;
+#if defined(__MTK_TARGET__)	
+    kal_wchar           file_path_name[MCF_FILE_MAX_MD_PATH_LEN * 2];
+    FS_HANDLE           file_handle;
+    kal_uint32          len = 0;
+    kal_int32           ret = FS_NO_ERROR;
+
+    MD_TRC_MCF_TR_WRITE_BUFFER_START(file_name, folder_path, total_size);
+
+    kal_wsprintf(file_path_name, "%s\\%s\0", folder_path, file_name);
+    file_handle = FS_Open(file_path_name, FS_CREATE | FS_READ_WRITE | FS_OPEN_NO_DIR);
+
+    ret = FS_Write(file_handle, buffer, total_size, &len);
+    if (ret != FS_NO_ERROR) {
+        MD_TRC_MCF_TR_WRITE_BUFFER_FAIL(file_handle, ret);
+        mcf_ret = MCF_OTA_R_WRITE_DISK_FAIL;
+    }
+
+    FS_Close(file_handle);
+#endif
+    return mcf_ret;
+}
+
+mcf_ota_result_e mcf_get_file_last_mod_time(
+    kal_char *apply_filename,
+    l4c_mcf_path_type_enum apply_path_type,
+    kal_uint64 *last_mod_time)
+{
+    mcf_ota_result_e    mcf_ret = MCF_OTA_R_SUCCESS;
+    kal_wchar           filename[MCF_FILE_MAX_MD_PATH_LEN + MCF_FILE_MAX_NAME_LEN];
+    FS_FileDetail       fs_file_detail[L4C_MCF_PATH_TYPE_MAX] = {0};
+    kal_int32           fs_api_ret[L4C_MCF_PATH_TYPE_MAX];
+
+    MD_TRC_MCF_TR_GET_FILE_LAST_MOD_TIME_START(apply_filename, apply_path_type);
+    if (apply_path_type == L4C_MCF_PATH_TYPE_OTA){
+        kal_wsprintf(filename, "%s\\%s\0", MCF_FS_DEFAULT_FOLDER_PATH, apply_filename);
+    }else if(apply_path_type == L4C_MCF_PATH_TYPE_RUNTIME){
+        kal_wsprintf(filename, "%s\\%s\0", MCF_FS_CUSTOM_FOLDER_PATH, apply_filename);
+    }else{
+        *last_mod_time = 0;
+        MD_TRC_MCF_TR_GET_FILE_LAST_MOD_TIME_INVALID_PATH_TYPE(apply_path_type);
+        mcf_ret = MCF_OTA_R_INVALID_PARAMETER;
+        return mcf_ret;
+    }
+    fs_api_ret[apply_path_type] = FS_GetFileDetail(filename, &fs_file_detail[apply_path_type]);
+    MD_TRC_MCF_TR_GET_FILE_LAST_MOD_TIME(apply_path_type, fs_api_ret[apply_path_type],
+                     (kal_uint32)((fs_file_detail[apply_path_type].LastStatusChangeTime >> 32) & 0xFFFFFFFF), (kal_uint32)(fs_file_detail[apply_path_type].LastStatusChangeTime & 0xFFFFFFFF));
+    if (fs_api_ret[apply_path_type] == FS_NO_ERROR) {
+        *last_mod_time = fs_file_detail[apply_path_type].LastStatusChangeTime;
+    } else {
+        *last_mod_time = 0;
+        MD_TRC_MCF_TR_GET_FILE_LAST_MOD_TIME_FAIL(L4C_MCF_PATH_TYPE_OTA, fs_api_ret[L4C_MCF_PATH_TYPE_OTA]);
+        mcf_ret = MCF_OTA_R_READ_OTA_FILE_FAIL;
+        return mcf_ret;
+    }
+
+    return mcf_ret;
+}
+
+void mcf_dump_important_info(void)
+{
+    mcf_t              *pMcf = mcf_get_instance();
+    mcf_ota_file_t     *ota_file = &(pMcf->ota_file);
+    mcf_tlvota_file_t  *tlvota_file;
+    kal_uint8           path_type;
+    kal_char            relative_path_name[MCF_FILE_MAX_NAME_LEN];
+    kal_uint8           i = 0;
+    
+    MCF_R_LOCK_OBJECT(ota_file, mcf_enhmutex_g);
+    if (ota_file) {
+        path_type = ota_file->path_type;
+        strncpy(relative_path_name, ota_file->relative_path_name, MCF_FILE_MAX_NAME_LEN - 1);
+        MD_TRC_MCF_TR_DUMP_IMPORTANT_INFO_OTA_FILE(path_type, relative_path_name);
+        MCF_R_UNLOCK_OBJECT(ota_file, mcf_enhmutex_g);
+    } else {
+        MD_TRC_MCF_TR_DUMP_IMPORTANT_INFO_TAKE_READ_LOCK_FAIL();
+    }
+    
+    for (i = 0; i < MAX_SIM_NUM; i++) {
+        tlvota_file = &(pMcf->tlvota_file[i]);
+        MCF_R_LOCK_OBJECT(tlvota_file, mcf_enhmutex_g);
+        if (tlvota_file) {
+            path_type = tlvota_file->path_type;
+            strncpy(relative_path_name, tlvota_file->relative_path_name, MCF_FILE_MAX_NAME_LEN - 1);
+            MD_TRC_MCF_TR_DUMP_IMPORTANT_INFO_TLVOTA_FILE(i, path_type, relative_path_name);
+            MCF_R_UNLOCK_OBJECT(tlvota_file, mcf_enhmutex_g);
+        } else {
+            MD_TRC_MCF_TR_DUMP_IMPORTANT_INFO_TAKE_READ_LOCK_FAIL();
+        }
+    }
+    
+    tlvota_file = &(pMcf->general_tlvota_file);
+    MCF_R_LOCK_OBJECT(tlvota_file, mcf_enhmutex_g);
+    if (tlvota_file) {
+        path_type = tlvota_file->path_type;
+        strncpy(relative_path_name, tlvota_file->relative_path_name, MCF_FILE_MAX_NAME_LEN - 1);
+        MD_TRC_MCF_TR_DUMP_IMPORTANT_INFO_GENERAL_TLVOTA_FILE(path_type, relative_path_name);
+        MCF_R_UNLOCK_OBJECT(tlvota_file, mcf_enhmutex_g);
+    } else {
+        MD_TRC_MCF_TR_DUMP_IMPORTANT_INFO_TAKE_READ_LOCK_FAIL();
+    }
+    
+}
+
+kal_int32 mcf_atoi(const void *src)
+{
+    kal_int32 res=0;
+    kal_int8 *p_src=(kal_int8*)src;
+
+    while( *p_src>='0' && *p_src<='9' ){
+        res = res*10 + (*p_src - '0');
+        p_src++;
+    }
+
+    return res;
+}
+
+kal_int32 mcf_str_strcmp(const void *str1, const void *str2)
+{
+    kal_int8 *p_str1=(kal_int8*)str1, *p_str2=(kal_int8*)str2;
+
+    if( p_str1==NULL || p_str2==NULL ){
+        return 1;
+    }
+
+    while(*p_str1==*p_str2 && *p_str1!='\0'){
+        p_str1++;
+        p_str2++;
+    }
+    return *p_str1 - *p_str2;
+}
+
+void mcf_remove_spaces_and_carrier_return(kal_char* src)
+{
+    kal_char* str1 = src;
+    kal_char* str2 = src;
+    while(*str2 != 0)
+    {
+    
+        *str1 = *str2++;
+        
+        /* 32 = space, 13 = "\r" */
+        /* Windows uses \r\n to a new line, Linux uses \n to a new line */
+    
+        if(*str1 != 32 && *str1 != 13){
+            str1++;
+        }
+    }
+    *str1 = 0;
+    
+}
+
+void mcf_toupper(kal_char* src)
+{
+    kal_uint32 k = 0;
+    while(src[k] != 0)
+    {
+        if(src[k] >= 'a' && src[k] <= 'z'){
+            src[k] = src[k]-32;
+        }
+        k++;
+    }
+    
+}
+
+kal_int32 mcf_str_strlen(const void *src)
+{
+    kal_int8 *p_src=(kal_int8*)src;
+    kal_int32 len=0;
+    
+    if( p_src==NULL ){
+        return 0;
+    }
+    
+    while('\0' != *p_src){
+        len++;
+        p_src++;
+    }
+    return len;
+}
+
+kal_bool mcf_hex_str_reverse(kal_char *str, kal_uint32 length)
+{
+    kal_char      temp1;
+	kal_char      temp2;
+	kal_uint32    i;
+	
+	if(str == NULL || length < 0 || length %2 != 0){
+		return KAL_FALSE;
+	}
+	
+	if(length < 4){
+		return KAL_TRUE;
+	}
+	
+	for(i = 0; i < length/2; i+=2){
+		temp1 = str[i];
+		str[i] = str[length-2-i];
+		str[length-2-i] = temp1;
+		
+		temp2 = str[i+1];
+		str[i+1] = str[length-1-i];
+		str[length-1-i] = temp2;
+	}
+	
+	return KAL_TRUE;
+}
+
+kal_int16 mcf_binary_search_lid(kal_uint16 find_lid, kal_uint16 *lid_arr, kal_uint16 lid_size, kal_uint16 *new_pos)
+{
+    kal_int16 first = 0,             // First array element
+        last = lid_size - 1,       // Last array element
+        middle = 0,                // Mid point of search
+        position = -1;         // Position of search value
+    kal_bool found = KAL_FALSE;        // Flag
+
+    while (!found && first <= last)
+    {
+        middle = (first + last) / 2;     // Calculate mid point
+        if(middle < 0)
+            return -1;
+        if (lid_arr[middle] == find_lid)      // If value is found at mid
+        {
+            found = KAL_TRUE;
+            position = middle;
+        }
+        else if (lid_arr[middle] > find_lid){  // If value is in lower half
+            last = middle - 1;
+            *new_pos = middle;
+        }
+        else{
+            first = middle + 1;           // If value is in upper half
+            *new_pos = first;
+        }
+    }
+    if(lid_size == 0){
+        *new_pos = 0;
+    }
+    
+    
+    return position;
+}
+
+kal_bool mcf_insert_lid(kal_uint16 new_lid, kal_uint16 *lid_arr, kal_uint16 lid_size, kal_uint16 new_pos)
+{
+    kal_bool ret = KAL_TRUE;
+    kal_uint16 i = 0;
+    if (lid_size >= NVRAM_MCF_SAVE_LAST_LID_CNT){
+        ret = KAL_FALSE;
+        return ret;
+    }
+    
+    for(i = lid_size; i > new_pos; i--){
+        lid_arr[i] = lid_arr[i-1];
+    }
+    lid_arr[new_pos] = new_lid;
+    
+    return ret;
+}
+
+#ifdef __MCF_COMBINE_FILE_SUPPORT__
+kal_int16 mcf_binary_search_lid_struct(kal_uint16 find_lid, nvram_mcf_lid_config_struct *lid_conf, kal_uint16 lid_size, kal_uint16 *new_pos)
+{
+    kal_int16 first = 0,             // First array element
+        last = lid_size - 1,       // Last array element
+        middle = 0,                // Mid point of search
+        position = -1;         // Position of search value
+    kal_bool found = KAL_FALSE;        // Flag
+
+    while (!found && first <= last)
+    {
+        middle = (first + last) / 2;     // Calculate mid point
+        if(middle < 0)
+            return -1;
+        if (lid_conf[middle].lid == find_lid)      // If value is found at mid
+        {
+            found = KAL_TRUE;
+            position = middle;
+        }
+        else if (lid_conf[middle].lid > find_lid){  // If value is in lower half
+            last = middle - 1;
+            *new_pos = middle;
+        }
+        else{
+            first = middle + 1;           // If value is in upper half
+            *new_pos = first;
+        }
+    }
+    if(lid_size == 0){
+        *new_pos = 0;
+    }
+    
+    
+    return position;
+}
+
+kal_bool mcf_insert_lid_struct(kal_uint16 new_lid, nvram_mcf_lid_config_struct *lid_conf, kal_uint16 lid_size, kal_uint16 new_pos, kal_bool not_reset, kal_bool set_combined)
+{
+    kal_bool ret = KAL_TRUE;
+    kal_uint16 i = 0;
+    if (lid_size >= NVRAM_MCF_SAVE_LAST_LID_CNT){
+        ret = KAL_FALSE;
+        return ret;
+    }
+    
+    for(i = lid_size; i > new_pos; i--){
+        kal_mem_cpy(&lid_conf[i], &lid_conf[i-1], sizeof(nvram_mcf_lid_config_struct));
+    }
+    lid_conf[new_pos].lid = new_lid;
+	lid_conf[new_pos].not_reset = not_reset;
+	lid_conf[new_pos].set_combined = set_combined;
+    
+    return ret;
+}
+
+kal_bool mcf_clear_last_modified_lid(nvram_mcf_lid_config_struct *lid_conf, kal_uint16 *lid_size)
+{
+    kal_bool ret = KAL_TRUE;
+	kal_uint16 i = 0;
+	kal_uint16 index = 0;
+	kal_uint16 lid_cnt = 0;
+    kal_uint16 total_cnt = 0;
+    
+	lid_cnt = *lid_size;
+	
+	if (lid_cnt >= NVRAM_MCF_SAVE_LAST_LID_CNT){
+        ret = KAL_FALSE;
+        return ret;
+    }
+
+    for(i = 0; i < lid_cnt; i++){
+        
+        if(lid_conf[i].set_combined == KAL_TRUE ){
+            kal_mem_set(&lid_conf[i], 0, sizeof(nvram_mcf_lid_config_struct));
+            index++;
+            while(index < lid_cnt && lid_conf[index].set_combined == KAL_TRUE){
+                kal_mem_set(&lid_conf[index], 0, sizeof(nvram_mcf_lid_config_struct));
+                index++;
+            }
+		}
+        
+        if (index < lid_cnt && i != index){
+            kal_mem_cpy(&lid_conf[i], &lid_conf[index], sizeof(nvram_mcf_lid_config_struct));
+            kal_mem_set(&lid_conf[index], 0, sizeof(nvram_mcf_lid_config_struct));
+            total_cnt++;
+        }else if(i == index){
+            total_cnt++;
+        }
+        
+        index ++;
+
+    }
+	
+	*lid_size = total_cnt;
+
+    
+    return ret;
+}
+#endif
+
+kal_int8* mcf_bytes_to_hex(const void *bytes, kal_int32 length, kal_bool upperCase, void *hex)
+{
+    kal_int8 *p_hex=(kal_int8*)hex, *p_bytes=(kal_int8*)bytes;
+    kal_int8 LCaseHexArray[] = "0123456789abcdef";
+    kal_int8 UCaseHexArray[] = "0123456789ABCDEF";
+    kal_uint32 i=0, v=0;
+    kal_mem_set(p_hex, 0, length*2 + 1);
+    
+    if (p_bytes == NULL) {
+        return NULL;
+    }
+    
+    for (i=0; i<length; i++) {
+        v=p_bytes[i]&0xFF;
+        if( v<0 || (v>>4)>=sizeof(LCaseHexArray) || (v&0x0F)>=sizeof(LCaseHexArray) || (v>>4) < 0 || (v&0x0F) < 0){
+            return NULL;
+        } else if( upperCase ){
+            p_hex[i*2] = UCaseHexArray[v >> 4];
+            p_hex[i*2 + 1] = UCaseHexArray[v & 0x0F];
+        } else{
+            p_hex[i*2] = LCaseHexArray[v >> 4];
+            p_hex[i*2 + 1] = LCaseHexArray[v & 0x0F];
+        }
+        
+    }
+    return p_hex;
+}
+
+kal_int8* mcf_hex_to_bytes(const void *hex, kal_int32 *length, void *bytes)
+{
+    kal_int8 *p_hex=(kal_int8*)hex, *p_bytes=(kal_int8*)bytes;
+    kal_int32 len_hex=mcf_str_strlen(p_hex), i=0, j=0;
+    kal_int8 temp[2];
+    
+    //EXT_ASSERT(len_hex%2==0, len_hex, bytes, 0);
+    if( len_hex%2==1 || len_hex<0 ){
+        return NULL;
+    }
+    
+    kal_mem_set(p_bytes, 0, len_hex / 2);
+    *length = 0;
+    
+    for( i=0; i<(len_hex/2); i++ ) {
+        temp[0] = p_hex[i * 2];
+		temp[1] = p_hex[i * 2 + 1];
+
+        for (j=0; j<2; j++) {
+            if (temp[j] >= 'A' && temp[j] <= 'F') {
+                temp[j] = temp[j] - 'A' + 10;
+            } else if (temp[j] >= 'a' && temp[j] <= 'f') {
+                temp[j] = temp[j] - 'a' + 10;
+            } else if (temp[j] >= '0' && temp[j] <= '9') {
+                temp[j] = temp[j] - '0';
+            } else {
+                return NULL;
+            }
+        }
+        p_bytes[i] = (temp[0]<<4) | temp[1];
+    }
+	*length = len_hex / 2;
+    
+    return p_bytes;
+}
+
+void mcf_replace_char(kal_char* src, kal_char old_ch, kal_char new_ch)
+{
+    kal_uint32 k = 0;
+    while(src[k] != 0)
+    {
+        if(src[k] == old_ch){
+            src[k] = new_ch;
+        }
+        k++;
+    }
+    
+}
+
+void mcf_snprintf(kal_char * str, size_t num, const char * fmt, ...)
+{
+    kal_int32     ret_snprintf = 0;
+    va_list       arglist;
+    
+    va_start(arglist, fmt);
+    ret_snprintf = vsnprintf(str, num, fmt, arglist);
+    va_end(arglist);
+    if (ret_snprintf < 0 || ret_snprintf > num){
+        strncpy(str, "unknown error", num - 1);
+        MD_TRC_MCF_TR_MCF_SNPRINTF_FAIL(num, ret_snprintf);
+    }
+}
+
+#ifdef __MCF_FIND_TAG_SUPPORT__
+extern MCF_DB_LID_MAPPING mcf_db_lid_mapping_tbl[];
+extern MCF_DB_STRUCT_IDX mcf_db_struct_idx_tbl[];
+kal_int32 mcf_parser_binary_search_struct_list(char *find_string, MCF_DB_STRUCT_VARIABLE const *struct_ptr, kal_uint32 struct_size)
+{
+    kal_int32 first = 0,             // First array element
+        last = struct_size - 1,       // Last array element
+        middle,                // Mid point of search
+        position = -1;         // Position of search value
+    kal_bool found = KAL_FALSE;        // Flag
+
+    while (!found && first <= last)
+    {
+        middle = (first + last) / 2;     // Calculate mid point
+        if(middle < 0)
+            return -1;
+        if (mcf_str_strcmp(struct_ptr[middle].variable_name, find_string) == 0)      // If value is found at mid
+        {
+            found = KAL_TRUE;
+            position = middle;
+        }
+        else if (mcf_str_strcmp(struct_ptr[middle].variable_name, find_string) > 0)  // If value is in lower half
+            last = middle - 1;
+        else
+            first = middle + 1;           // If value is in upper half
+    }
+    return position;
+}
+#endif
+kal_bool mcf_find_tag_offset(
+    kal_uint32 lid_num, 
+    char *tag_name, 
+    kal_uint16 *byte_offset, 
+    kal_uint16 *bit_offset, 
+    kal_uint32 *size,
+    MCF_DB_STRUCT_VARIABLE const **var_ptr,
+    mcf_tag_info_struct *tag_ptr)
+{
+#ifdef __MCF_FIND_TAG_SUPPORT__
+    kal_uint16 i = 0;
+    kal_uint16 array_size_cnt = 1;
+    kal_int32 lid_idx = -1, struct_idx = -1;
+    char *saveptr = NULL, *saveptr2 = NULL, *varstr = NULL, *substr = NULL;
+    char var_name[MAX_VAR_LEN] = {0};
+    kal_bool next_is_bit = KAL_FALSE;
+    kal_uint32 start_time = GET_CURRENT_TIME();
+    
+    if(tag_name == NULL || byte_offset == NULL || bit_offset == NULL || size == NULL)
+    {
+        MD_TRC_MCF_TR_FIND_TAG_ERROR_INPUT_NULL();
+        return KAL_FALSE;
+    }
+    
+    *byte_offset = 0;
+    *bit_offset = 0;
+    *size= 0;
+    dhl_print_string(TRACE_INFO, DHL_USER_FLAG_NONE, MOD_MCF, tag_name);
+    
+    for(i = 0 ; i < MCF_LID_MAPPING_TBL_SIZE ; i++)
+    {
+        if(mcf_db_lid_mapping_tbl[i].lid_num == lid_num)
+        {
+           lid_idx = i;
+           struct_idx = mcf_db_lid_mapping_tbl[i].struct_idx;
+           break;
+        }
+    }
+    
+    // can not find this lid_num in mcf_db_lid_mapping_tbl
+    if(lid_idx == -1 || struct_idx > MCF_STRUCT_LIST_TBL_SIZE)
+    {
+        MD_TRC_MCF_TR_FIND_TAG_ERROR_CAN_NOT_FIND_LID_NUM(lid_num, struct_idx);
+        return KAL_FALSE;
+    }
+    
+    // split "." for each variable
+    substr = kal_strtok_r(tag_name, ".", &saveptr);    
+    while (substr){
+        kal_int32 pos = -1;
+        MCF_DB_STRUCT_VARIABLE const *var_struct_ptr = NULL;
+        
+        // split "[" for get array num
+        varstr = kal_strtok_r(substr, "[", &saveptr2);
+        if(next_is_bit == KAL_TRUE){
+            kal_uint32 len = strlen(var_name);
+            var_name[len] = '.';
+            strcpy(var_name + len + 1, varstr);
+        }
+        else
+        {
+            strcpy(var_name, varstr);
+        }
+        
+        var_struct_ptr = mcf_db_struct_idx_tbl[struct_idx].struct_ptr;
+        pos =  mcf_parser_binary_search_struct_list(var_name, var_struct_ptr, mcf_db_struct_idx_tbl[struct_idx].struct_size);
+        if(pos == -1)
+        {
+            MCF_BOOT_TRACE(MCF_BOOT_TR_FIND_TAG_ERROR_CAN_NOT_FIND_TAG);
+            MD_TRC_MCF_TR_FIND_TAG_ERROR_CAN_NOT_FIND_TAG();
+            dhl_print_string(TRACE_ERROR, DHL_USER_FLAG_NONE, MOD_MCF, var_name);
+            return KAL_FALSE;
+        }
+        
+        // get array size
+        if(next_is_bit == KAL_TRUE)
+        {
+            *bit_offset += var_struct_ptr[pos].bit_offset;
+            *size = var_struct_ptr[pos].total_size;
+        }
+        else
+        {
+            kal_uint32 array_size;
+            kal_uint8 i = 0;
+            tag_ptr->arr_cnt = 0;
+            *byte_offset += var_struct_ptr[pos].byte_offset;
+            *size = var_struct_ptr[pos].variable_size;
+            
+            varstr = kal_strtok_r(NULL, "[", &saveptr2);
+            if(varstr != NULL){
+                do{
+                    kal_uint8 j = 0;
+                    kal_uint32 n = 1;
+                    array_size = mcf_atoi(varstr);
+                    j = i+1;
+                    while(var_struct_ptr[pos].array_size[j] != 0)
+                    {
+                        n *= (var_struct_ptr[pos].array_size[j]);
+                        j++;
+                        array_size_cnt++;
+                    }
+                    i++;
+                    *byte_offset += (array_size * n * var_struct_ptr[pos].variable_size);
+                    tag_ptr->array_size[tag_ptr->arr_cnt] = array_size;
+                    tag_ptr->arr_cnt++;
+                }while((varstr = kal_strtok_r(NULL, "[", &saveptr2)) != NULL);
+
+                if (i > array_size_cnt){
+                    MD_TRC_MCF_TR_FIND_TAG_ERROR_OVER_SIZE(i, array_size_cnt);
+                    dhl_print_string(TRACE_ERROR, DHL_USER_FLAG_NONE, MOD_MCF, var_name);
+                    return KAL_FALSE;
+                }
+            }
+            else{
+                *size = var_struct_ptr[pos].total_size;
+            }
+        }
+
+        if(var_struct_ptr[pos].is_bit)
+        {
+            next_is_bit = KAL_TRUE;
+            tag_ptr->is_bit = KAL_TRUE;
+            tag_ptr->upper_vsize = var_struct_ptr[pos].variable_size;
+        }
+
+        if(var_struct_ptr[pos].struct_idx != -1)
+        {
+            struct_idx = var_struct_ptr[pos].struct_idx;
+        }
+
+        substr = kal_strtok_r(NULL, ".", &saveptr);
+        if (substr != 0){
+            tag_ptr->arr_cnt = 0;
+            kal_mem_set(tag_ptr->array_size, 0, 5);
+        }
+        *var_ptr = &var_struct_ptr[pos];
+    };
+    
+    MD_TRC_MCF_TR_FIND_TAG_RETURN_VALUE(lid_num, *byte_offset, *bit_offset, *size, CALCULATE_LETENCY_DURATION(start_time, GET_CURRENT_TIME()));
+    
+    return KAL_TRUE;
+#else
+    return KAL_FALSE;
+#endif
+}
+
+#ifdef __MCF_FIND_GID_SUPPORT__
+extern MCF_DB_GID_LIST_STRUCT MCF_DB_GID_LIST[];
+extern MCF_DB_GID_FORMULA_STRUCT MCF_DB_FORMULA_LIST[];
+kal_int32 mcf_gid_binary_search_gid_list(kal_uint32 gid)
+{
+    kal_int32 first = 0,             // First array element
+        last = MCF_MAX_GID_LIST_SIZE - 1,       // Last array element
+        middle,                // Mid point of search
+        position = -1;         // Position of search value
+    kal_bool found = KAL_FALSE;        // Flag
+
+    while (!found && first <= last)
+    {
+        middle = (first + last) / 2;     // Calculate mid point
+        if(middle < 0)
+            return -1;
+        if (gid == MCF_DB_GID_LIST[middle].gid)      // If value is found at mid
+        {
+            found = KAL_TRUE;
+            position = middle;
+        }
+        else if (gid < MCF_DB_GID_LIST[middle].gid)  // If value is in lower half
+            last = middle - 1;
+        else
+            first = middle + 1;           // If value is in upper half
+    }
+    return position;
+}
+kal_int32 mcf_gid_binary_search_gid_formula_list(kal_uint32 gid)
+{
+    kal_int32 first = 0,             // First array element
+        last = MCF_MAX_GID_FORMULA_LIST_SIZE - 1,       // Last array element
+        middle,                // Mid point of search
+        position = -1;         // Position of search value
+    kal_bool found = KAL_FALSE;        // Flag
+
+    while (!found && first <= last)
+    {
+        middle = (first + last) / 2;     // Calculate mid point
+        if(middle < 0)
+            return -1;
+        if (gid == MCF_DB_FORMULA_LIST[middle].gid)      // If value is found at mid
+        {
+            found = KAL_TRUE;
+            position = middle;
+        }
+        else if (gid < MCF_DB_FORMULA_LIST[middle].gid)  // If value is in lower half
+            last = middle - 1;
+        else
+            first = middle + 1;           // If value is in upper half
+    }
+    return position;
+}
+#endif
+kal_bool mcf_find_gid_offset(
+    kal_uint32 gid,
+    char *array_idx_string,
+    kal_uint16 *lid_num,
+    kal_uint16 *byte_offset,
+    kal_uint16 *bit_offset,
+    kal_uint32 *size,
+    kal_bool *is_bit
+)
+{
+#ifdef __MCF_FIND_GID_SUPPORT__
+    kal_int32 gid_list_pos = 0, gid_formula_list_pos = 0;
+    kal_uint32 start_time = GET_CURRENT_TIME();
+
+    if(byte_offset == NULL || bit_offset == NULL || size == NULL || is_bit == NULL || array_idx_string == NULL)
+    {
+        MD_TRC_MCF_TR_FIND_GID_ERROR_INPUT_NULL();
+        return KAL_FALSE;
+    }
+    
+    MD_TRC_MCF_TR_FIND_GID_START(gid, array_idx_string);
+    
+    gid_list_pos = mcf_gid_binary_search_gid_list(gid);
+    if(gid_list_pos == -1 || gid_list_pos < 0)
+    {
+        MCF_BOOT_TRACE(MCF_BOOT_TR_FIND_GID_ERROR_CAN_NOT_FIND_GID, gid);
+        MD_TRC_MCF_TR_FIND_GID_ERROR_CAN_NOT_FIND_GID(gid);
+        return KAL_FALSE;
+    }
+
+    *lid_num = MCF_DB_GID_LIST[gid_list_pos].lid_num;
+    *size = MCF_DB_GID_LIST[gid_list_pos].variable_size;
+    *is_bit = MCF_DB_GID_LIST[gid_list_pos].is_bit;
+    *bit_offset = MCF_DB_GID_LIST[gid_list_pos].bit_offset;
+    if(MCF_DB_GID_LIST[gid_list_pos].array_formula == KAL_FALSE)
+    {
+        *byte_offset = MCF_DB_GID_LIST[gid_list_pos].byte_offset;
+    }
+    else
+    {
+		kal_int32 array_size[10] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
+        kal_uint32 i = 0, j = 0;
+        kal_uint32 current_array_i = 0;
+        char *saveptr = NULL, *saveptr2 = NULL, *varstr = NULL, *substr = NULL;
+		char gid_formula_string[MCF_MAX_FORMULA_LEN] = {0};
+        char temp_array_idx[64] = {0};
+
+        *byte_offset = 0;
+        strncpy(temp_array_idx, array_idx_string, 63);
+        temp_array_idx[63] = '\0';
+        // parsing array_idx_string
+        varstr = kal_strtok_r(temp_array_idx, "$", &saveptr);
+        if(varstr != NULL){
+            do{
+                array_size[i++] = mcf_atoi(varstr);
+                if(i >= 10)
+               {
+                    MCF_BOOT_TRACE(MCF_BOOT_TR_FIND_GID_ERROR_FORMULA_OUT_OF_BOUND , gid);
+                    MD_TRC_MCF_TR_FIND_GID_ERROR_FORMULA_OUT_OF_BOUND(gid);
+                    dhl_print_string(TRACE_ERROR, DHL_USER_FLAG_NONE, MOD_MCF, temp_array_idx);
+                    return KAL_FALSE;
+                }
+            }while((varstr = kal_strtok_r(NULL, "$", &saveptr)) != NULL);
+
+        }
+
+        gid_formula_list_pos = mcf_gid_binary_search_gid_formula_list(gid);
+        if(gid_formula_list_pos == -1 || gid_formula_list_pos < 0)
+        {
+            MCF_BOOT_TRACE(MCF_BOOT_TR_FIND_GID_ERROR_CAN_NOT_FIND_FORMULA, gid);
+            MD_TRC_MCF_TR_FIND_GID_ERROR_CAN_NOT_FIND_FORMULA(gid);
+            return KAL_FALSE;
+        }
+
+        //[5](0,164)+[8](4,20)+[5](0,4)+0
+        //[10](0,12)+2+2
+        //[2,8,2](4,2)
+		strncpy(gid_formula_string, MCF_DB_FORMULA_LIST[gid_formula_list_pos].byte_offset_formula, MCF_MAX_FORMULA_LEN - 1);
+        substr = kal_strtok_r(gid_formula_string, "+", &saveptr);
+        if(substr != NULL){
+            do{
+				kal_int32 max_array_idx[5] = {-1,-1,-1,-1,-1};
+                kal_uint32 local_base = 0, local_size = 0, base = 0;
+                kal_uint32 max_array_i = 0;
+                kal_bool max_array_start = KAL_FALSE, local_start = KAL_FALSE, base_start = KAL_TRUE;
+				char temp[20] = {0};
+
+				j = 0;
+                while(substr[j] != '\0')
+                {
+                    if(substr[j] == '['){ 
+                        max_array_start = KAL_TRUE; local_start = KAL_FALSE; base_start = KAL_FALSE;
+						kal_mem_set(temp, 0, 20);
+						i = 0;
+                    } 
+                    else if(substr[j] == ']'){ 
+                        max_array_start = KAL_FALSE; local_start = KAL_FALSE; base_start = KAL_FALSE;
+						varstr = kal_strtok_r(temp, ",", &saveptr2);
+                        if(varstr != NULL){
+                            do{
+                                max_array_idx[max_array_i++] = mcf_atoi(varstr);
+                            }while((varstr = kal_strtok_r(NULL, ",", &saveptr2)) != NULL);
+                        }
+                    }
+                    else if(substr[j] == '('){
+                        max_array_start =  KAL_FALSE; local_start = KAL_TRUE; base_start = KAL_FALSE;
+						kal_mem_set(temp, 0, 20);
+						i = 0;
+                    }
+                    else if(substr[j] == ')'){
+                        max_array_start =  KAL_FALSE; local_start = KAL_FALSE; base_start = KAL_FALSE;
+						varstr = kal_strtok_r(temp, ",", &saveptr2);
+                        if (varstr != NULL){
+                            local_base = mcf_atoi(varstr);
+                        }
+                        varstr = kal_strtok_r(NULL, ",", &saveptr2);
+                        if (varstr != NULL){
+                            local_size = mcf_atoi(varstr);
+                        }
+                    }
+                    else // digit
+                    {
+                        // get max array idx
+                        if(max_array_start == KAL_TRUE)
+                        {
+                            temp[i++] = substr[j];
+                        }
+                        else if(local_start == KAL_TRUE)
+                        {
+                            temp[i++] = substr[j];
+                        }
+                        else if(base_start == KAL_TRUE)
+                        {
+                            base = mcf_atoi(substr);
+                        }
+                    }
+
+                    j++;
+                }
+                {
+                    kal_uint32 temp_offset = 0;
+                    for(i = 0; i< max_array_i; i++)
+                    {
+                        kal_uint32 array_idx = array_size[current_array_i++];
+                        kal_uint32 array_offset = 0;
+                        if(array_idx == -1) break;
+                        array_offset = array_idx * local_size;
+
+                        if(array_idx >= max_array_idx[i])
+                        {
+                            return KAL_FALSE; // array size error
+                        }
+                        for(j = i + 1 ; j < 5 ; j++)
+                        {
+                            if(max_array_idx[j] == -1) break;
+                            array_offset *= max_array_idx[j];
+                        }
+                        temp_offset += array_offset;
+
+                    }
+                    *byte_offset += temp_offset + local_base;
+
+                }
+                *byte_offset += base;
+           
+            }while((substr = kal_strtok_r(NULL, "+", &saveptr)) != NULL);
+        }
+
+
+    }
+
+    MD_TRC_MCF_TR_FIND_GID_RETURN_VALUE(*lid_num, *byte_offset, *bit_offset, *size, *is_bit, CALCULATE_LETENCY_DURATION(start_time, GET_CURRENT_TIME()));
+
+    return KAL_TRUE;
+#else
+    return KAL_FALSE;
+#endif
+}
+
+kal_uint16 mcf_find_gid_return_lid_num(kal_uint32 gid)
+{
+#ifdef __MCF_FIND_GID_SUPPORT__
+     kal_int32 gid_list_pos = 0;
+    gid_list_pos = mcf_gid_binary_search_gid_list(gid);
+    if(gid_list_pos == -1 || gid_list_pos < 0)
+    {
+        MCF_BOOT_TRACE(MCF_BOOT_TR_FIND_GID_RETURN_LID_NUM_ERROR_CAN_NOT_FIND_GID, gid);
+        MD_TRC_MCF_TR_FIND_GID_RETURN_LID_NUM_ERROR_CAN_NOT_FIND_GID(gid);
+        return -1; // not found
+    }
+    return MCF_DB_GID_LIST[gid_list_pos].lid_num;
+#else
+    return -1;
+#endif
+}
+
+kal_uint32 mcf_calc_check_sum(kal_uint32 *ptr, kal_uint32 len)
+{
+    kal_uint32 check_sum = 0, i = 0;
+    for(i = 0; i< (len/sizeof(kal_uint32)) ; i++, ptr++)
+        check_sum += *ptr;
+    check_sum = ~check_sum + 1;
+    return check_sum;
+}
+kal_uint32 mcf_check_check_sum(kal_uint32 *ptr, kal_uint32 len)
+{
+    kal_uint32 check_sum = 0, i = 0;
+    for(i = 0; i< (len/sizeof(kal_uint32)) ; i++, ptr++)
+        check_sum += *ptr;
+    
+    if(check_sum != 0)
+        MD_TRC_MCF_TR_CHECKSUM_ERROR(check_sum);
+    
+    return check_sum;
+}
+
+// password will be auto padding to 16B
+// content should be padding to 16B alignment
+// conrent length should be mod by 16
+kal_bool mcf_encrypt_128bit(char *password, char *content, kal_uint32 content_length)
+{
+    kal_uint8 iv[]  = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
+    kal_uint8 copy_len = 0; 
+    kal_uint32 output_len;
+    t_cust_chl_sym_key key;
+    AES_PARAM aes_param;
+    kal_uint32 ret = CUST_CHL_ERROR_NONE;
+    kal_uint32 start_time = ust_get_current_time();
+    
+    if(content == NULL) return KAL_FALSE;
+    if(content_length % 16 != 0) return KAL_FALSE;
+    
+    copy_len = strlen(password);
+    if(copy_len > 16) copy_len = 16;
+    
+    key.m_key_len = 16;
+    kal_mem_set(key.m_key, 0, sizeof(key.m_key));
+    kal_mem_cpy(&key.m_key, password, copy_len);
+    aes_param.IVLength = 16;
+    aes_param.IV = iv;
+    ret = CustCHL_AES_Encrypt_data(CUST_CHL_ALG_AES128, CUST_CHL_MODE_CBC, content_length, (kal_uint8 *)content, &output_len, (kal_uint8 *)content, &key, &aes_param);
+    
+    MD_TRC_MCF_TR_ENCRYPT(ust_us_duration(start_time, ust_get_current_time()));
+    if (ret != CUST_CHL_ERROR_NONE)
+        return KAL_FALSE;
+    return KAL_TRUE;
+}
+
+// password will be auto padding to 16B
+// content should be padding to 16B alignment
+// conrent length should be mod by 16
+kal_bool mcf_decrypt_128bit(char *password, char *content, kal_uint32 content_length)
+{
+    kal_uint8 iv[]  = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
+    kal_uint8 copy_len = 0; 
+    kal_uint32 output_len;
+    t_cust_chl_sym_key key;
+    AES_PARAM aes_param;
+    kal_uint32 ret = CUST_CHL_ERROR_NONE;
+    kal_uint32 start_time = ust_get_current_time();
+    
+    if(content == NULL) return KAL_FALSE;
+    if(content_length % 16 != 0) return KAL_FALSE;
+    
+    copy_len = strlen(password);
+    if(copy_len > 16) copy_len = 16;
+    
+    key.m_key_len = 16;
+    kal_mem_set(key.m_key, 0, sizeof(key.m_key));
+    kal_mem_cpy(&key.m_key, password, copy_len);
+    aes_param.IVLength = 16;
+    aes_param.IV = iv;
+    ret = CustCHL_AES_Decrypt_data(CUST_CHL_ALG_AES128, CUST_CHL_MODE_CBC, content_length, (kal_uint8 *)content, &output_len, (kal_uint8 *)content, &key, &aes_param);
+   
+    MD_TRC_MCF_TR_DECRYPT(ust_us_duration(start_time, ust_get_current_time()));
+    if (ret != CUST_CHL_ERROR_NONE)
+        return KAL_FALSE;
+    
+    return KAL_TRUE;
+}
+#ifdef __MCF_COMBINE_FILE_SUPPORT__
+void mcf_merge_insert_node(mcf_merge_link_list_struct *pre_node, mcf_merge_link_list_struct *next_node, mcf_merge_link_list_struct *insert_node, void *insert_data)
+{
+    if(pre_node != NULL) pre_node->next_node = insert_node;
+    if(next_node != NULL) next_node->pre_node = insert_node;
+    insert_node->pre_node = pre_node;
+    insert_node->next_node = next_node;
+    insert_node->data = insert_data;
+    MD_TRC_MCF_TR_MERGE_LINK_LIST_INSERT_NODE_INFO((pre_node != NULL)?(kal_uint32)pre_node->next_node : 0, 
+                                                   (next_node != NULL)?(kal_uint32)next_node->pre_node : 0, 
+                                                   (kal_uint32)insert_node->pre_node, (kal_uint32)insert_node->next_node);
+}
+
+// comparison sequence : LID => RID => GID => array idx
+kal_int8 mcf_merge_compare_ota_data(mcf_tool_gid_ota_file_item_t *first_data, mcf_tool_gid_ota_file_item_t *second_data)
+{
+    kal_uint16 first_lid_num = mcf_find_gid_return_lid_num(first_data->global_id);
+    kal_uint16 second_lid_num = mcf_find_gid_return_lid_num(second_data->global_id);
+    kal_int32 array_cmp_result = 0;
+    
+    MD_TRC_MCF_TR_MERGE_CMP_OTA_DATA_INFO(first_lid_num, first_data->record_idx, first_data->global_id, second_lid_num, second_data->record_idx, second_data->global_id);
+
+    if(first_lid_num < second_lid_num) return -1;
+    else if (first_lid_num > second_lid_num) return 1;
+    
+    if(first_data->record_idx < second_data->record_idx) return -1;
+    else if (first_data->record_idx > second_data->record_idx) return 1;
+    
+    if(first_data->global_id < second_data->global_id) return -1;
+    else if (first_data->global_id > second_data->global_id) return 1;
+    
+    if (first_data->array_index_len > 0)
+    {
+        array_cmp_result= strncmp(&(first_data->buff_start), &(second_data->buff_start), first_data->array_index_len);
+        MD_TRC_MCF_TR_MERGE_CMP_OTA_DATA_ARRAY_INFO(array_cmp_result);
+        if (array_cmp_result < 0) return -1;
+        if (array_cmp_result > 0) return 1;
+    }
+
+    return 0;
+}
+
+kal_int8 mcf_merge_compare_ota_by_op_tag(char *tag1, char *tag2)
+{
+	kal_uint16 tag1_sbpid= 0, tag1_mcc=0, tag1_mnc=0, tag2_sbpid=0, tag2_mcc=0, tag2_mnc=0; // use 0 as "NA"
+	kal_char sbp_id_tag[MCF_MAX_TAG_NUM] = {0};
+	const char *delim = "_";
+	char * pch;
+    kal_char *saveptr = NULL;
+	// parsing tag1
+	strncpy(sbp_id_tag, tag1, MCF_MAX_TAG_NUM-1);
+	pch = kal_strtok_r(sbp_id_tag, delim, &saveptr);
+	if (pch != NULL && strcmp(pch, "NA") != 0) tag1_sbpid = mcf_atoi(pch);
+	pch = kal_strtok_r(NULL, delim, &saveptr);
+	if (pch != NULL && strcmp(pch, "NA") != 0) tag1_mcc = mcf_atoi(pch);
+	pch = kal_strtok_r(NULL, delim, &saveptr);
+	if (pch != NULL && strcmp(pch, "NA") != 0) tag1_mnc = mcf_atoi(pch);
+	// parsing tag2
+	strncpy(sbp_id_tag, tag2, MCF_MAX_TAG_NUM-1);
+	pch = kal_strtok_r(sbp_id_tag, delim, &saveptr);
+	if (pch != NULL && strcmp(pch, "NA") != 0) tag2_sbpid = mcf_atoi(pch);
+	pch = kal_strtok_r(NULL, delim, &saveptr);
+	if (pch != NULL && strcmp(pch, "NA") != 0) tag2_mcc = mcf_atoi(pch);
+	pch = kal_strtok_r(NULL, delim, &saveptr);
+	if (pch != NULL && strcmp(pch, "NA") != 0) tag2_mnc = mcf_atoi(pch);
+
+	// comparion
+	// SBP
+	if ((tag1_sbpid == tag2_sbpid) && (tag1_mcc == tag2_mcc) && (tag1_mnc == tag2_mnc))
+		return 0;
+	else if (tag1_sbpid > tag2_sbpid)
+		return 1;
+	else if (tag1_sbpid < tag2_sbpid)
+		return -1;
+	else
+	{
+		// SBP is equal, then compare MCC
+		if (tag1_mcc > tag2_mcc)      return 1;
+		else if (tag1_mcc < tag2_mcc) return -1;
+		else
+		{
+			// SBP and MCC are equal, then compare MNC
+			if (tag1_mnc > tag2_mnc)      return 1;
+			else if (tag1_mnc < tag2_mnc) return -1;
+		}
+	}
+	return 0;
+}
+
+// comparison sequence : LID => TAG type=> TAG => GID => array idx
+kal_int8 mcf_merge_compare_ota_by_op_data(mcf_tool_gid_tlvota_file_item_t *first_data, mcf_tool_gid_tlvota_file_item_t *second_data)
+{
+    kal_uint16 first_lid_num = mcf_find_gid_return_lid_num(first_data->global_id);
+    kal_uint16 second_lid_num = mcf_find_gid_return_lid_num(second_data->global_id);
+    kal_int32 array_cmp_result = 0;
+
+    MD_TRC_MCF_TR_MERGE_CMP_OTA_DATA_INFO(first_lid_num, first_data->tag_type, first_data->global_id, second_lid_num, second_data->tag_type, second_data->global_id);
+    
+    if(first_lid_num < second_lid_num) return -1;
+    else if (first_lid_num > second_lid_num) return 1;
+    
+    if(first_data->tag_type < second_data->tag_type) return -1;
+    else if (first_data->tag_type > second_data->tag_type) return 1;
+    
+    {
+        kal_char sbp_tag1[MCF_FILE_MAX_TAG_LEN] = {0};
+        kal_char sbp_tag2[MCF_FILE_MAX_TAG_LEN] = {0};
+        kal_int8 result= 0;
+        
+        strncpy(sbp_tag1, &(first_data->buff_start) , first_data->tag_len);
+        strncpy(sbp_tag2, &(second_data->buff_start) , second_data->tag_len);
+        
+        result= mcf_merge_compare_ota_by_op_tag(sbp_tag1, sbp_tag2);
+        if(result < 0) return -1;
+        if(result > 0) return 1;
+    }
+    
+    if(first_data->global_id < second_data->global_id) return -1;
+    else if (first_data->global_id > second_data->global_id) return 1;
+    
+    if (first_data->array_index_len > 0)
+    {
+        array_cmp_result = strncmp(&(first_data->buff_start) + first_data->tag_len, &(second_data->buff_start) + second_data->tag_len, first_data->array_index_len);
+        MD_TRC_MCF_TR_MERGE_CMP_OTA_DATA_ARRAY_INFO(array_cmp_result);
+        if (array_cmp_result < 0) return -1;
+        if (array_cmp_result > 0) return 1;
+    }
+
+    return 0;
+}
+
+// sort by ascending 
+mcf_merge_link_list_struct * mcf_merge_link_list_insert(mcf_merge_link_list_struct *head, mcf_merge_link_list_struct *tail, mcf_merge_link_list_struct *current, void *insert_data, mcf_ota_type_enum type)
+{
+    mcf_merge_link_list_struct *current_node = head->next_node;
+    mcf_merge_link_list_struct *new_node = NULL;
+    kal_int8 result = 0;
+    if (type == MCF_TYPE_OTA)			 MD_TRC_MCF_TR_MERGE_LINK_LIST_INSERT_DATA_START(((mcf_tool_gid_ota_file_item_t *)insert_data)->global_id);
+    else if (type == MCF_TYPE_OTA_BY_OP) MD_TRC_MCF_TR_MERGE_LINK_LIST_INSERT_DATA_START(((mcf_tool_gid_tlvota_file_item_t *)insert_data)->global_id);
+
+    if (current != NULL)
+    {
+        // quick determine
+        if (type == MCF_TYPE_OTA)
+        {
+            result = mcf_merge_compare_ota_data((mcf_tool_gid_ota_file_item_t *)insert_data, (mcf_tool_gid_ota_file_item_t *)current->data);
+        }
+        else if (type == MCF_TYPE_OTA_BY_OP)
+        {
+            result = mcf_merge_compare_ota_by_op_data((mcf_tool_gid_tlvota_file_item_t *)insert_data, (mcf_tool_gid_tlvota_file_item_t *)current->data);
+        }
+        else
+        {
+            DEBUG_ASSERT(0);
+            return NULL;
+        }
+        MD_TRC_MCF_TR_MERGE_LINK_LIST_INSERT_CMP_RESULT(result);
+        // if insert data >= current, then start from current.
+        // if insert data < current, back to head to find again.
+        if (result == 1 || result == 0) {
+            current_node = current;
+            MD_TRC_MCF_TR_MERGE_LINK_LIST_USE_CURRENT_AS_START();
+        }
+        else {
+            current_node = head->next_node;
+            MD_TRC_MCF_TR_MERGE_LINK_LIST_USE_HEAD_AS_START();
+        }
+    }
+
+    while (current_node != tail)
+    {
+        // ========= COMPARE NODE =========
+        result = 0;
+        if (type == MCF_TYPE_OTA)
+        {
+            result = mcf_merge_compare_ota_data((mcf_tool_gid_ota_file_item_t *)insert_data, (mcf_tool_gid_ota_file_item_t *)current_node->data);
+        }
+        else if (type == MCF_TYPE_OTA_BY_OP)
+        {
+            result = mcf_merge_compare_ota_by_op_data((mcf_tool_gid_tlvota_file_item_t *)insert_data, (mcf_tool_gid_tlvota_file_item_t *)current_node->data);
+        }
+        else
+        {
+            DEBUG_ASSERT(0);
+            return NULL;
+        }
+        MD_TRC_MCF_TR_MERGE_LINK_LIST_INSERT_CMP_RESULT(result);
+        // ========= INSERT NODE =========
+        // insert data should be inserted BEFORE current node
+        if (result == -1)
+        {
+            new_node = mcf_malloc(sizeof(mcf_merge_link_list_struct)); 
+            if(new_node == NULL) return NULL;
+            MD_TRC_MCF_TR_MERGE_OTA_BUFFER_ALLOCATE((kal_uint32)new_node);
+            kal_mem_set(new_node, 0, sizeof(mcf_merge_link_list_struct));
+            mcf_merge_insert_node(current_node->pre_node, current_node, new_node, insert_data);
+            return current_node->pre_node;
+        }
+        // insert data should be REPLACED current node
+        else if (result == 0)
+        {
+            current_node->data = insert_data;
+            return current_node;
+        }
+        // insert data should be inserted AFTER current node
+        else if (result == 1)
+        {
+            // due to the link list is acending, skip
+        }
+        else
+            DEBUG_ASSERT(0);
+
+        current_node = current_node->next_node;
+    }
+
+    // insert the last
+    new_node = mcf_malloc(sizeof(mcf_merge_link_list_struct)); 
+    if(new_node == NULL) return NULL;
+    MD_TRC_MCF_TR_MERGE_OTA_BUFFER_ALLOCATE((kal_uint32)new_node);
+    kal_mem_set(new_node, 0, sizeof(mcf_merge_link_list_struct));
+    mcf_merge_insert_node(current_node->pre_node, current_node, new_node, insert_data);
+
+    return current_node->pre_node;
+}
+
+void mcf_merge_link_list_free(mcf_merge_link_list_struct *head)
+{
+    mcf_merge_link_list_struct *current = head;
+    while (current != NULL)
+    {
+        mcf_merge_link_list_struct *next = current->next_node;
+        MD_TRC_MCF_TR_MERGE_OTA_BUFFER_FREE((kal_uint32)current);
+        mcf_free(current);
+        current = next;
+    }
+}
+
+kal_bool mcf_merge_read_buffer_to_linklist(void *buffer, mcf_merge_link_list_struct *head, mcf_merge_link_list_struct *tail, mcf_ota_type_enum type)
+{
+    mcf_tool_file_info_t *file_header = (mcf_tool_file_info_t *)buffer;
+    kal_uint32 item_cnt = 0; 
+    mcf_merge_link_list_struct *current = NULL;
+    
+    if (type == MCF_TYPE_OTA) {
+        mcf_tool_gid_ota_file_item_t *current_data = (mcf_tool_gid_ota_file_item_t *)((kal_uint8 *)file_header + file_header->total_len);
+        MD_TRC_MCF_TR_MERGE_READ_BUFFER_TO_LINKLIST_TOTAL_ITEM(file_header->item_num);
+        for (item_cnt = 0 ; item_cnt < file_header->item_num ; item_cnt ++)
+        {
+            current = mcf_merge_link_list_insert(head, tail, current, current_data, type);
+            if(current == NULL) return KAL_FALSE;
+            MD_TRC_MCF_TR_MERGE_READ_BUFFER_TO_LINKLIST_ITEM_INFO(item_cnt, current_data->global_id);
+            current_data = (mcf_tool_gid_ota_file_item_t *)((kal_uint8 *)current_data + current_data->total_len);
+        }   
+    }
+    else if (type == MCF_TYPE_OTA_BY_OP)
+    {
+        mcf_tool_gid_tlvota_file_item_t *current_data = (mcf_tool_gid_tlvota_file_item_t *)((kal_uint8 *)file_header + file_header->total_len);
+        MD_TRC_MCF_TR_MERGE_READ_BUFFER_TO_LINKLIST_TOTAL_ITEM(file_header->item_num);
+        for (item_cnt = 0 ; item_cnt < file_header->item_num ; item_cnt ++)
+        {
+            current = mcf_merge_link_list_insert(head, tail, current, current_data, type);
+            if(current == NULL) return KAL_FALSE;
+            MD_TRC_MCF_TR_MERGE_READ_BUFFER_TO_LINKLIST_ITEM_INFO(item_cnt, current_data->global_id);
+            current_data = (mcf_tool_gid_tlvota_file_item_t *)((kal_uint8 *)current_data + current_data->total_len);
+        }   
+    }
+    else
+    {
+        DEBUG_ASSERT(0);
+        return KAL_FALSE;
+    }
+    return KAL_TRUE;
+}
+
+void mcf_merge_make_ota_file_header(mcf_tool_file_info_t *output_header, mcf_tool_file_info_t *copy_header)
+{
+    kal_char sw_version[MCF_SW_VERNO_LEN] = {0};
+    kal_char gen_time[MCF_FILE_MAX_GEN_TIME_LEN] = {0};
+    
+    struct tm current_time;
+    
+#if defined(__MTK_TARGET__) && defined(__SUPPORT_CLIB_TIME__)
+	time_t currenttime;
+	kal_mem_set(&current_time, 0, sizeof(struct tm));
+	if (time(&currenttime) != -1)
+		localtime_r(&currenttime, &current_time);
+#else
+    current_time.tm_year = 118;
+    current_time.tm_mon = 0;
+    current_time.tm_mday = 1;
+    current_time.tm_hour = 0;
+    current_time.tm_min = 0;
+    current_time.tm_sec = 0;
+#endif
+    MD_TRC_MCF_TR_MERGE_MAKE_OTA_FILE_HEADER_START();
+    kal_mem_set(output_header, 0, sizeof(mcf_tool_file_info_t));
+    
+    kal_mem_set(sw_version, 0, sizeof(kal_char) * MCF_SW_VERNO_LEN);
+    kal_mem_set(gen_time, 0, sizeof(kal_char) * MCF_FILE_MAX_GEN_TIME_LEN);
+    
+    if(sprintf(gen_time,"%04d.%02d%02d.%02d%02d%02d", current_time.tm_year + 1900, current_time.tm_mon + 1, current_time.tm_mday, current_time.tm_hour, current_time.tm_min, current_time.tm_sec) <0)
+		DEBUG_ASSERT(0);
+    strncpy(sw_version, release_verno(), MCF_SW_VERNO_LEN-1);
+
+    output_header->sw_version_len = strlen(sw_version);
+    output_header->gen_time_len = strlen(gen_time);
+    output_header->file_version = copy_header->file_version;
+    output_header->operation_mask = copy_header->operation_mask;
+    if((output_header->operation_mask & MCF_FILE_OP_SHA256_RSA2048) || (output_header->operation_mask & MCF_FILE_OP_SHA384_RSA3072))
+    {
+        output_header->operation_mask &= ~(MCF_FILE_OP_SHA256_RSA2048);
+        output_header->operation_mask &= ~(MCF_FILE_OP_SHA384_RSA3072);
+    }
+    strcpy(output_header->file_type, copy_header->file_type);
+    // copy header
+    {
+        // use copy_len to prevent out of array
+        kal_uint32 copy_len = 0;
+        if (output_header->sw_version_len >= MCF_SW_VERNO_LEN -1) copy_len = MCF_SW_VERNO_LEN -1;
+        else copy_len = output_header->sw_version_len;
+        strncpy(&output_header->buff_start, sw_version, copy_len);
+        
+        if (output_header->gen_time_len >= MCF_FILE_MAX_GEN_TIME_LEN -1) copy_len = MCF_FILE_MAX_GEN_TIME_LEN -1;
+        else copy_len = output_header->gen_time_len;
+        strncpy(&output_header->buff_start + output_header->sw_version_len, gen_time, copy_len);
+    }
+    output_header->total_len = (kal_uint32)&output_header->buff_start + output_header->sw_version_len + output_header->gen_time_len - (kal_uint32)output_header;    // end addr - start addr
+    if ((output_header->total_len % 4) != 0)
+        output_header->total_len += 4 - (output_header->total_len % 4); // 4 bytes alignment
+    MD_TRC_MCF_TR_MERGE_MAKE_OTA_FILE_HEADER_END();
+}
+
+// if first buffer has same gid, it will be replaced by second_buffer
+kal_bool mcf_merge_ota_buffer(void *first_buffer, void *second_buffer, void *output_buffer, kal_uint32 output_buffer_size)
+{
+    mcf_merge_link_list_struct *head, *tail; 
+    mcf_ota_type_enum type = 0;
+    kal_bool ret = KAL_FALSE;
+    kal_uint32 coreID = kal_get_current_core_id();
+
+    MD_TRC_MCF_TR_MERGE_OTA_BUFFER_START();
+    MD_TRC_MCF_TR_MERGE_OTA_BUFFER_MCF_CORE(coreID);
+    //If MCF is running on Core0, need to wake up Core1 to run other task
+    if (coreID == 0){
+        SleepDrv_LockSleep( SLEEP_CTL_MCF, CORE1);
+        MD_TRC_MCF_TR_MERGE_OTA_BUFFER_LOCK_CORE(CORE1, coreID);
+    }
+    if (first_buffer == NULL || second_buffer == NULL || output_buffer == NULL) {
+        MD_TRC_MCF_TR_MERGE_OTA_BUFFER_INPUT_PARAM_ERROR((kal_uint32)first_buffer, (kal_uint32)second_buffer, (kal_uint32)output_buffer);
+        if (coreID == 0){
+            SleepDrv_UnlockSleep( SLEEP_CTL_MCF, CORE1);
+            MD_TRC_MCF_TR_MERGE_OTA_BUFFER_UNLOCK_CORE(CORE1, coreID);
+        }
+        return KAL_FALSE;
+    }
+    
+    // head init
+    head = mcf_malloc(sizeof(mcf_merge_link_list_struct)); 
+    tail = mcf_malloc(sizeof(mcf_merge_link_list_struct)); 
+    if(head == NULL || tail == NULL){
+        if (coreID == 0){
+            SleepDrv_UnlockSleep( SLEEP_CTL_MCF, CORE1);
+            MD_TRC_MCF_TR_MERGE_OTA_BUFFER_UNLOCK_CORE(CORE1, coreID);
+        }
+        return KAL_FALSE;
+    }
+    kal_mem_set(head, 0, sizeof(mcf_merge_link_list_struct));
+    kal_mem_set(tail, 0, sizeof(mcf_merge_link_list_struct));
+    head->next_node = tail;
+    tail->pre_node = head;
+    MD_TRC_MCF_TR_MERGE_OTA_BUFFER_ALLOCATE_HEAD_TAIL((kal_uint32)head, (kal_uint32)tail);
+    // ========== read first buffer ==========
+    {
+        mcf_tool_file_info_t *file_header = (mcf_tool_file_info_t *)first_buffer;
+        if (strcmp(file_header->file_type, MCF_FILE_TYPE_OTA) == 0) type = MCF_TYPE_OTA;
+        else if (strcmp(file_header->file_type, MCF_FILE_TYPE_TLVOTA) == 0) type = MCF_TYPE_OTA_BY_OP;
+        else{
+            DEBUG_ASSERT(0);
+            if (coreID == 0){
+                SleepDrv_UnlockSleep( SLEEP_CTL_MCF, CORE1);
+                MD_TRC_MCF_TR_MERGE_OTA_BUFFER_UNLOCK_CORE(CORE1, coreID);
+            }
+            return KAL_FALSE;
+        }
+        MD_TRC_MCF_TR_MERGE_OTA_BUFFER_FIRST_BUFFER_TYPE(type);
+        ret = mcf_merge_read_buffer_to_linklist(first_buffer, head, tail, type);
+        if(ret == KAL_FALSE){
+            if (coreID == 0){
+                SleepDrv_UnlockSleep( SLEEP_CTL_MCF, CORE1);
+                MD_TRC_MCF_TR_MERGE_OTA_BUFFER_UNLOCK_CORE(CORE1, coreID);
+            }
+            return KAL_FALSE;
+        }
+    }
+    // ========== read second buffer ==========
+    {
+        mcf_tool_file_info_t *file_header = (mcf_tool_file_info_t *)second_buffer;
+        if (strcmp(file_header->file_type, MCF_FILE_TYPE_OTA) == 0) type = MCF_TYPE_OTA;
+        else if (strcmp(file_header->file_type, MCF_FILE_TYPE_TLVOTA) == 0) type = MCF_TYPE_OTA_BY_OP;
+        else{
+            DEBUG_ASSERT(0);
+            if (coreID == 0){
+                SleepDrv_UnlockSleep( SLEEP_CTL_MCF, CORE1);
+                MD_TRC_MCF_TR_MERGE_OTA_BUFFER_UNLOCK_CORE(CORE1, coreID);
+            }
+            return KAL_FALSE;
+        }
+        MD_TRC_MCF_TR_MERGE_OTA_BUFFER_SECOND_BUFFER_TYPE(type);
+        ret = mcf_merge_read_buffer_to_linklist(second_buffer, head, tail, type);
+        if(ret == KAL_FALSE){
+            if (coreID == 0){
+                SleepDrv_UnlockSleep( SLEEP_CTL_MCF, CORE1);
+                MD_TRC_MCF_TR_MERGE_OTA_BUFFER_UNLOCK_CORE(CORE1, coreID);
+            }
+            return KAL_FALSE;
+        }
+    }
+    // ========== output buffer ==========
+    {
+        mcf_tool_file_info_t *copy_header = (mcf_tool_file_info_t *)second_buffer;
+        mcf_tool_file_info_t *output_header = (mcf_tool_file_info_t *)output_buffer;
+        kal_uint8 *current_pos = NULL;
+        mcf_merge_link_list_struct *current_node = head->next_node;
+        
+        mcf_merge_make_ota_file_header(output_header, copy_header); // copy first header to output header
+        current_pos = (kal_uint8 *)output_header + output_header->total_len;
+        
+        if (strcmp(output_header->file_type, MCF_FILE_TYPE_OTA) == 0) type = MCF_TYPE_OTA;
+        else if (strcmp(output_header->file_type, MCF_FILE_TYPE_TLVOTA) == 0) type = MCF_TYPE_OTA_BY_OP;
+        else{
+            DEBUG_ASSERT(0);
+            if (coreID == 0){
+                SleepDrv_UnlockSleep( SLEEP_CTL_MCF, CORE1);
+                MD_TRC_MCF_TR_MERGE_OTA_BUFFER_UNLOCK_CORE(CORE1, coreID);
+            }
+            return KAL_FALSE;
+        }
+            
+        while (current_node != tail)
+        {
+            if (type == MCF_TYPE_OTA)
+            {
+                mcf_tool_gid_ota_file_item_t *current_ota_data = current_node->data;
+                kal_mem_cpy(current_pos, current_ota_data, current_ota_data->total_len);
+                current_pos += current_ota_data->total_len;
+                MD_TRC_MCF_TR_MERGE_OTA_BUFFER_OUTPUT_GID(current_ota_data->global_id);
+                mcf_dump_data(KAL_FALSE, &current_ota_data->buff_start + current_ota_data->array_index_len, current_ota_data->value_len);
+            }
+            else if (type == MCF_TYPE_OTA_BY_OP)
+            {
+                mcf_tool_gid_tlvota_file_item_t *current_ota_by_data = current_node->data;
+                kal_mem_cpy(current_pos, current_ota_by_data, current_ota_by_data->total_len);
+                current_pos += current_ota_by_data->total_len;
+                MD_TRC_MCF_TR_MERGE_OTA_BUFFER_OUTPUT_GID(current_ota_by_data->global_id);
+                mcf_dump_data(KAL_FALSE, &current_ota_by_data->buff_start + current_ota_by_data->tag_len + current_ota_by_data->array_index_len, current_ota_by_data->value_len);
+            }
+            current_node = current_node->next_node;
+            output_header->item_num++;
+            output_header->file_size = (kal_uint32)((kal_uint8 *)current_pos - (kal_uint8 *)output_header);
+            if (output_header->file_size > output_buffer_size)
+            {
+                MD_TRC_MCF_TR_MERGE_OTA_BUFFER_OUTPUT_BUFFER_OUT_OF_SIZE(output_header->file_size, output_buffer_size);
+                if (coreID == 0){
+                    SleepDrv_UnlockSleep( SLEEP_CTL_MCF, CORE1);
+                    MD_TRC_MCF_TR_MERGE_OTA_BUFFER_UNLOCK_CORE(CORE1, coreID);
+                }
+                return KAL_FALSE;
+            }
+        }
+        
+        if ((output_header->operation_mask & MCF_FILE_OP_AES_128) || (output_header->operation_mask & MCF_FILE_OP_AES_256))
+		{
+			if (((output_header->file_size - output_header->total_len) % 16) != 0)
+				output_header->file_size += 16 - (output_header->file_size - output_header->total_len) % 16; // content should be 16 bytes alignment
+		}
+		else if (((output_header->file_size - output_header->total_len) % 4) != 0)
+		{
+			output_header->file_size += 4 - (output_header->file_size - output_header->total_len) % 4; // content should be 4 bytes alignment
+		}
+        
+    }
+    
+    // ========== security ==========
+    {
+        mcf_tool_file_info_t *file_header = (mcf_tool_file_info_t *)output_buffer;
+        // checksum
+        if (file_header->operation_mask & MCF_FILE_OP_CHECKSUM) 
+        {
+            file_header->checksum = 0;
+            file_header->checksum = mcf_calc_check_sum((kal_uint32 *)output_buffer, file_header->file_size);
+        }
+        // encrypt
+        if (file_header->operation_mask & MCF_FILE_OP_AES_128) 
+        {
+            kal_char password[MCF_MAX_PASSWORD_LEN] = {0};
+            mcf_get_custom_aes_password(password);
+            if (mcf_encrypt_128bit(password, (kal_char *)((kal_uint8 *)file_header + file_header->total_len), (file_header->file_size - file_header->total_len)) == KAL_FALSE)
+            {
+                if (coreID == 0){
+                    SleepDrv_UnlockSleep( SLEEP_CTL_MCF, CORE1);
+                    MD_TRC_MCF_TR_MERGE_OTA_BUFFER_UNLOCK_CORE(CORE1, coreID);
+                }
+                return KAL_FALSE;
+            }
+        }
+        else if (file_header->operation_mask & MCF_FILE_OP_AES_256) 
+        {
+            kal_char password[MCF_MAX_PASSWORD_LEN] = {0};
+            mcf_get_custom_aes_password(password);
+            if (mcf_encrypt_256bit(password, (kal_char *)((kal_uint8 *)file_header + file_header->total_len), (file_header->file_size - file_header->total_len)) == KAL_FALSE)
+            {
+                if (coreID == 0){
+                    SleepDrv_UnlockSleep( SLEEP_CTL_MCF, CORE1);
+                    MD_TRC_MCF_TR_MERGE_OTA_BUFFER_UNLOCK_CORE(CORE1, coreID);
+                }
+                return KAL_FALSE;
+            }
+        }
+    }
+    
+    mcf_merge_link_list_free(head);
+    MD_TRC_MCF_TR_MERGE_OTA_BUFFER_END();
+    if (coreID == 0){
+        SleepDrv_UnlockSleep( SLEEP_CTL_MCF, CORE1);
+        MD_TRC_MCF_TR_MERGE_OTA_BUFFER_UNLOCK_CORE(CORE1, coreID);
+    }
+    return KAL_TRUE;
+}
+
+// NOTE : if this gid needs to merge to a file, call mcf_merge_ota_buffer to combine this buffer
+kal_bool mcf_merge_one_gid(void *new_gid, mcf_ota_type_enum type, void *output_buffer, kal_uint32 output_buffer_size, kal_uint32 operation_mask)
+{
+    MD_TRC_MCF_TR_MERGE_ONE_GID_START();
+    if (new_gid == NULL || output_buffer == NULL) {
+        MD_TRC_MCF_TR_MERGE_ONE_GID_INPUT_PARAM_ERROR((kal_uint32)new_gid, (kal_uint32)output_buffer);
+        return KAL_FALSE;
+    }
+    
+    mcf_tool_file_info_t copy_header;
+    mcf_tool_file_info_t *output_header = (mcf_tool_file_info_t *)output_buffer;
+    kal_uint32 gid_size = 0;
+    copy_header.file_version = 3;
+    copy_header.operation_mask = operation_mask;
+    mcf_merge_make_ota_file_header(output_header, &copy_header); // copy first header to output header
+    if (type == MCF_TYPE_OTA)
+    {
+        strcpy(output_header->file_type, MCF_FILE_TYPE_OTA);
+        mcf_tool_gid_ota_file_item_t *ota = new_gid;
+        gid_size = ota->total_len;
+        MD_TRC_MCF_TR_MERGE_OTA_BUFFER_OUTPUT_GID(ota->global_id);
+        mcf_dump_data(KAL_FALSE, &ota->buff_start + ota->array_index_len, ota->value_len);
+    }
+    else if (type == MCF_TYPE_OTA_BY_OP)
+    {
+        strcpy(output_header->file_type, MCF_FILE_TYPE_TLVOTA);
+        mcf_tool_gid_tlvota_file_item_t *ota_by_op = new_gid;
+        gid_size = ota_by_op->total_len;
+        MD_TRC_MCF_TR_MERGE_OTA_BUFFER_OUTPUT_GID(ota_by_op->global_id);
+        mcf_dump_data(KAL_FALSE, &ota_by_op->buff_start + ota_by_op->tag_len + ota_by_op->array_index_len, ota_by_op->value_len);
+    }
+    else
+    {
+        return KAL_FALSE;
+    }
+    // check buffer size
+    if ((output_header->total_len + gid_size) > output_buffer_size) {
+        MD_TRC_MCF_TR_MERGE_OTA_BUFFER_OUTPUT_BUFFER_OUT_OF_SIZE((output_header->total_len + gid_size), output_buffer_size);
+        return KAL_FALSE;
+    }
+    
+    kal_mem_cpy((kal_uint8 *)output_buffer + output_header->total_len, new_gid, gid_size);
+    output_header->item_num = 1;
+    output_header->file_size = (kal_uint32)((kal_uint8 *)output_buffer + output_header->total_len + gid_size - (kal_uint8 *)output_header);
+    if (((output_header->file_size - output_header->total_len) % 4) != 0)
+        output_header->file_size += 4 - (output_header->file_size - output_header->total_len) % 4; // content should be 16 bytes alignment
+    // ========== security ==========
+    {
+        mcf_tool_file_info_t *file_header = (mcf_tool_file_info_t *)output_buffer;
+        // checksum
+        if (file_header->operation_mask & MCF_FILE_OP_CHECKSUM)
+        {
+            file_header->checksum = 0;
+            file_header->checksum = mcf_calc_check_sum((kal_uint32 *)output_buffer, file_header->file_size);
+        }
+        // encrypt
+        if (file_header->operation_mask & MCF_FILE_OP_AES_128 || file_header->operation_mask & MCF_FILE_OP_AES_256)
+        {
+            // this output is temp buffer, no need to encrypt
+            file_header->operation_mask &= ~(MCF_FILE_OP_AES_128);
+            file_header->operation_mask &= ~(MCF_FILE_OP_AES_256);
+        }
+    }
+    MD_TRC_MCF_TR_MERG_ONE_GID_END();
+    return KAL_TRUE;
+}
+#endif
+
+// password will be auto padding to 32B
+// content should be padding to 32B alignment
+// conrent length should be mod by 32
+kal_bool mcf_encrypt_256bit(char *password, char *content, kal_uint32 content_length)
+{
+    kal_uint8 iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
+    kal_uint8 copy_len = 0;
+    kal_uint32 output_len;
+    t_cust_chl_sym_key key;
+    AES_PARAM aes_param;
+    kal_uint32 ret = CUST_CHL_ERROR_NONE;
+    kal_uint32 start_time = ust_get_current_time();
+
+    kal_mem_set(&aes_param, 0, sizeof(AES_PARAM));
+
+    if (content == NULL) return KAL_FALSE;
+    if (content_length % 16 != 0) return KAL_FALSE;
+
+    copy_len = strlen(password);
+    if (copy_len > 32) copy_len = 32;
+
+    key.m_key_len = 32;
+    kal_mem_set(key.m_key, 0, sizeof(key.m_key));
+    kal_mem_cpy(&key.m_key, password, copy_len);
+    aes_param.IVLength = 16;
+    aes_param.IV = iv;
+    ret = CustCHL_AES_Encrypt_data(CUST_CHL_ALG_AES256, CUST_CHL_MODE_CBC, content_length, (kal_uint8 *)content, &output_len, (kal_uint8 *)content, &key, &aes_param);
+
+    MD_TRC_MCF_TR_ENCRYPT(ust_us_duration(start_time, ust_get_current_time()));
+    if (ret != CUST_CHL_ERROR_NONE)
+        return KAL_FALSE;
+
+    return KAL_TRUE;
+}
+
+// password will be auto padding to 32B
+// content should be padding to 32B alignment
+// conrent length should be mod by 32
+kal_bool mcf_decrypt_256bit(char *password, char *content, kal_uint32 content_length)
+{
+    kal_uint8 iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
+    kal_uint8 copy_len = 0;
+    kal_uint32 output_len;
+    t_cust_chl_sym_key key;
+    AES_PARAM aes_param;
+    kal_uint32 ret = CUST_CHL_ERROR_NONE;
+    kal_uint32 start_time = ust_get_current_time();
+
+    kal_mem_set(&aes_param, 0, sizeof(AES_PARAM));
+
+    if (content == NULL) return KAL_FALSE;
+    if (content_length % 16 != 0) return KAL_FALSE;
+
+    copy_len = strlen(password);
+    if (copy_len > 32) copy_len = 32;
+
+    key.m_key_len = 32;
+    kal_mem_set(key.m_key, 0, sizeof(key.m_key));
+    kal_mem_cpy(&key.m_key, password, copy_len);
+    aes_param.IVLength = 16;
+    aes_param.IV = iv;
+    ret = CustCHL_AES_Decrypt_data(CUST_CHL_ALG_AES256, CUST_CHL_MODE_CBC, content_length, (kal_uint8 *)content, &output_len, (kal_uint8 *)content, &key, &aes_param);
+
+    MD_TRC_MCF_TR_DECRYPT(ust_us_duration(start_time, ust_get_current_time()));
+    if (ret != CUST_CHL_ERROR_NONE)
+        return KAL_FALSE;
+
+    return KAL_TRUE;
+}
+
+// digest verify  
+kal_bool mcf_verify_digest(kal_uint32 digest_tag, mcf_tool_file_info_t *ota_file, mcf_digest *sign)
+{
+    kal_uint32 ret = KAL_FALSE;
+    t_cust_chl_asym_key key;
+
+    if (digest_tag == MCF_FILE_OP_SHA256_RSA2048) {
+        ret = mcf_get_custom_digest_public_key(sign->sequence, &key);
+        if (ret == KAL_FALSE) return KAL_FALSE;
+        ret = CustCHL_Verify_RSA_Signature(CUST_CHL_ALG_RSA_PKCS1_V15_SHA256_ASN1, (kal_uint8 *)ota_file, ota_file->file_size, sign->digest_value, sign->digest_len, &key);
+    }
+    else if(digest_tag == MCF_FILE_OP_SHA384_RSA3072){
+        ret = mcf_get_custom_digest_public_key(sign->sequence, &key);
+        if (ret == KAL_FALSE) return KAL_FALSE;
+        ret = CustCHL_Verify_RSA_Signature(CUST_CHL_ALG_RSA_PKCS1_V15_SHA384_ASN1, (kal_uint8 *)ota_file, ota_file->file_size, sign->digest_value, sign->digest_len, &key);
+    }
+    else
+    {
+        // not support
+        return KAL_FALSE;
+    }
+
+    if (ret != CUST_CHL_ERROR_NONE)
+        return KAL_FALSE;
+
+    return KAL_TRUE;
+}
+
+void mcf_make_file_info(mcf_file_info_t *file_info, kal_uint8 path_type, kal_char *name, kal_char *sw_version, kal_uint8 sw_version_len, kal_char *gen_time, kal_uint8 gen_time_len, kal_uint64 last_mod_time, kal_uint32 checksum)
+{   
+    MD_TRC_MCF_TR_MAKE_FILE_INFO_START(path_type, last_mod_time & 0xFFFFFFFF, checksum & 0xFFFFFFFF);
+    
+    kal_mem_set(file_info, 0, sizeof(mcf_file_info_t));
+    file_info->path_type = path_type;
+    strncpy(file_info->name, name, MCF_FILE_MAX_NAME_LEN-1);
+    strncpy(file_info->sw_version, sw_version, sw_version_len);
+    strncpy(file_info->gen_time, gen_time, gen_time_len);
+    file_info->last_mod_time = last_mod_time;
+    file_info->checksum = checksum;
+    file_info->sw_version_len = sw_version_len;
+    file_info->gen_time_len = gen_time_len;
+}
+
+kal_bool mcf_compare_file_info(mcf_file_info_t *old_file, mcf_file_info_t *new_file)
+{   
+    static nvram_ef_mcf_sw_info_struct             nv_sw_info;
+
+    MD_TRC_MCF_TR_COMPARE_FILE_INFO_START();
+    MD_TRC_MCF_TR_COMPARE_FILE_INFO_OLD_FILE_INFO(old_file->sw_version, old_file->gen_time);
+    MD_TRC_MCF_TR_COMPARE_FILE_INFO_NEW_FILE_INFO(new_file->sw_version, new_file->gen_time);
+    MD_TRC_MCF_TR_COMPARE_FILE_INFO_FILE_CHECKSUM(old_file->checksum & 0xFFFFFFFF, new_file->checksum & 0xFFFFFFFF);
+    MD_TRC_MCF_TR_COMPARE_FILE_INFO_FILE_LAST_MOD_TIME(old_file->last_mod_time & 0xFFFFFFFF, new_file->last_mod_time & 0xFFFFFFFF);
+    if ( (strncmp(old_file->sw_version, new_file->sw_version, new_file->sw_version_len) == 0) &&
+            (strncmp(old_file->gen_time, new_file->gen_time, new_file->gen_time_len) == 0) &&
+            (old_file->path_type == new_file->path_type) &&
+            (strncmp(old_file->name, new_file->name, MCF_FILE_MAX_NAME_LEN) == 0) &&
+            (old_file->last_mod_time == new_file->last_mod_time) &&
+            (old_file->checksum == new_file->checksum) ) {
+        
+        if ( !nvram_external_read_data(NVRAM_EF_MCF_SW_INFO_LID, 1, (kal_uint8 *)&nv_sw_info, sizeof(nvram_ef_mcf_sw_info_struct))) {
+            MD_TRC_MCF_TR_COMPARE_FILE_INFO_READ_FILE_NVRAM_FAIL(NVRAM_EF_MCF_SW_INFO_LID);
+            return KAL_FALSE;
+        }    
+
+        if ((strncmp(nv_sw_info.version, release_verno(), MCF_SW_VERNO_LEN) == 0) &&
+            (strncmp(nv_sw_info.build_time, build_date_time(), MCF_SW_BUILD_TIME_LEN) == 0)){
+            MD_TRC_MCF_TR_COMPARE_FILE_INFO_MD_INFO(nv_sw_info.version, nv_sw_info.build_time);  
+            return KAL_TRUE;
+        }else{
+            MD_TRC_MCF_TR_COMPARE_FILE_INFO_FILE_NOT_THE_SAME();
+            return KAL_FALSE;
+        }
+    }else{
+        MD_TRC_MCF_TR_COMPARE_FILE_INFO_FILE_NOT_THE_SAME();
+        return KAL_FALSE;
+        
+    }
+
+}
+