diff --git a/code/application/source/cardv/SrcCode/UIWnd/LVGL_SPORTCAM/UIInfo/UIInfo.h b/code/application/source/cardv/SrcCode/UIWnd/LVGL_SPORTCAM/UIInfo/UIInfo.h index cc84e5bdd..abb3cb8b5 100755 --- a/code/application/source/cardv/SrcCode/UIWnd/LVGL_SPORTCAM/UIInfo/UIInfo.h +++ b/code/application/source/cardv/SrcCode/UIWnd/LVGL_SPORTCAM/UIInfo/UIInfo.h @@ -486,6 +486,13 @@ typedef struct _UIMenuUIMenuStoreInfo { CHAR PicUpDailyReport; /////////////////////// #endif + + CHAR ProfileSwitchFlg; + CHAR ProfileEnableCmdVal; + CHAR UpdateFlg; + CHAR PreActiveProfileIccid[22]; + CHAR EsimEid[40]; + CHAR CamNameStr[13]; CHAR PwdStr[7]; diff --git a/code/application/source/sf_app/code/include/sf_commu_mcu_reg.h b/code/application/source/sf_app/code/include/sf_commu_mcu_reg.h old mode 100644 new mode 100755 index 816d06ccc..3f255f7e7 --- a/code/application/source/sf_app/code/include/sf_commu_mcu_reg.h +++ b/code/application/source/sf_app/code/include/sf_commu_mcu_reg.h @@ -375,6 +375,9 @@ void sf_set_gprs_errno(SINT32 value); SINT32 sf_get_gprs_errno(void); BOOL sf_get_signal_ready_flag(void); void sf_set_signal_ready_flag(BOOL Flag); +S32 sf_mcu_rebootall(U8 McuPoweroffVal); + + extern unsigned short TrigType; diff --git a/code/application/source/sf_app/code/include/sf_eg91_sim.h b/code/application/source/sf_app/code/include/sf_eg91_sim.h old mode 100644 new mode 100755 index bbf75a5b0..238115849 --- a/code/application/source/sf_app/code/include/sf_eg91_sim.h +++ b/code/application/source/sf_app/code/include/sf_eg91_sim.h @@ -16,6 +16,8 @@ extern "C" { #define MODULE_ICCID_LEN 20 //500ms * 480 = 240s = 4min #define SF_QUECTEL_NET_REG_CALLTIME_MAX 480 +#define SF_MODULE_RESET_WAIT_TIME 30 + #define SF_NTP_SITE1 "time.windows.com" #define SF_NTP_SITE2 "time.nist.gov" @@ -34,6 +36,7 @@ extern "C" { #define APNGPRSTEMP "CTNET" #define APNGPRSTEMP2 "3gnet" #define APNGPRSTEMP3 "CMNET" + typedef enum SIM_SLEEP_E { SIM_SLEEP_FIRST = (unsigned char)0x01, @@ -167,7 +170,13 @@ typedef enum SF_QUECTEL_NETREG typedef enum _GPRS_MODULE_ERR_CODE_E{ GPRS_MODULE_ERROR_OPEN = 1, GPRS_MODULE_ERROR_WRITE = 2, - GPRS_MODULE_ERROR_READ = 3, + GPRS_MODULE_ERROR_READ = 3, + SIM_ERROR_SWITCH_PROFILE = 11, + SIM_SWITCH_ATT_PROFILE = 12, + SIM_SWITCH_VERIZON_PROFILE = 13, + SIM_ERROR_REG_NET_TIMEOUT = 14, + SIM_ERROR_REG_NET_REFUSE = 15, + SIM_SWITCH_OTHER_PROFILE = 16, GPRS_MODULE_ERROR_BUTT, }GPRS_MODULE_ERR_CODE_e; @@ -175,6 +184,15 @@ typedef enum _GPRS_MODULE_ERR_CODE_E{ #define SF_GPRS_MODULE_ERROR_WRITE SF_ERR_ID(SF_MOD_4G, GPRS_MODULE_ERROR_WRITE) #define SF_GPRS_MODULE_ERROR_READ SF_ERR_ID(SF_MOD_4G, GPRS_MODULE_ERROR_READ) +#define SF_SIM_ERROR_SWITCH_PROFILE SF_ERR_ID(SF_MOD_SIM, SIM_ERROR_SWITCH_PROFILE) +#define SF_SIM_SWITCH_ATT_PROFILE SF_ERR_ID(SF_MOD_SIM, SIM_SWITCH_ATT_PROFILE) +#define SF_SIM_SWITCH_VERIZON_PROFILE SF_ERR_ID(SF_MOD_SIM, SIM_SWITCH_VERIZON_PROFILE) +#define SF_SIM_SWITCH_OTHER_PROFILE SF_ERR_ID(SF_MOD_SIM, SIM_SWITCH_OTHER_PROFILE) + +#define SF_SIM_ERROR_REG_NET_TIMEOUT SF_ERR_ID(SF_MOD_SIM, SIM_ERROR_REG_NET_TIMEOUT) +#define SF_SIM_ERROR_REG_NET_REFUSE SF_ERR_ID(SF_MOD_SIM, SIM_ERROR_REG_NET_REFUSE) + + typedef enum _SIM_ERR_CODE_E{ SIM_COM_SUCCEED = 0, SIM_ERROR_NO_SIGNAL = 1, @@ -306,6 +324,9 @@ SINT32 sf_net_regist_manual(void); SINT32 sf_auto_net_reg(void); +int sf_get_operatorname(char *strname); + + SINT32 eg915q_set_usbnet(SF_FN_PARAM_S *pfnParam); #ifdef __cplusplus #if __cplusplus diff --git a/code/application/source/sf_app/code/include/sf_service.h b/code/application/source/sf_app/code/include/sf_service.h index ed930acc1..a75726ef7 100755 --- a/code/application/source/sf_app/code/include/sf_service.h +++ b/code/application/source/sf_app/code/include/sf_service.h @@ -16,6 +16,29 @@ extern "C" { #define SF_APP_ERROR_WRITE SF_ERR_ID(SF_MOD_APP, ERROR_WRITE) #define SF_APP_ERROR_FILE_SEND SF_ERR_ID(SF_MOD_APP, ERROR_FILE_SEND) +#define SF_STRLEN(a) (UINT32)strlen((char *)a) +#define SF_STRCPY(a, b) strcpy((char *)a, (char *)b) +#define SF_STRNCPY(a, b, c) strncpy((char *)a, (char *)b, c) +#define SF_STRCMP(a, b) strcmp((char *)a, (char *)b) +#define SF_STRNCMP(a, b, c) strncmp((char *)a, (char *)b, c) +#define SF_STRSTR(a, b) (UINT8 *)strstr((char *)a, (char *)b) +#define SF_STRTOK(a, b) (UINT8 *)strtok((char *)a, (char *)b) +#define SF_SPRINTF(a, ...) sprintf((char *)a, __VA_ARGS__) +#define SF_STRCASECMP(a, b) strcasecmp((char *)a, (char *)b) +#define SF_STRSEP(a, b) strsep((char **)a, (char *)b) +#define SF_STRCAT(a, b) strcat((char *)a, (char *)b) +#define SF_STRTOLL(a, b, c) strtoll((char *)a, (char **)b, c) +#define SF_MEMSET(a, b, c) memset((void *) a, (char) b, (int) c) + +#define SF_OPEN(a, b, c) open((void *) a, (int) b, (int) c) +#define SF_CLOSE(a) close((int) a) +#define SF_READ(a, b, c) read((int) a, (char *)b, (int) c) +#define SF_WRITE(a, b, c) write((int) a, (char *)b, (int) c) +#define SF_SEEK(a, b, c) lseek((int) a, (int) b, (int) c) +#define SF_SYNC() sync() +#define SF_DELETE(a) remove((char *)a) +#define SF_RENAME(a, b) rename((char *)a, (char *)b) + #define SF_APP_CHECK_RANGE(cmd, min,max) \ do { \ if(cmd < min || cmd > max)\ @@ -39,6 +62,19 @@ typedef enum SF_CMD_TYPE_E { SF_CMD_SYNC_CFG, SF_CMD_BUTT } SF_CMD_TYPE_E; + +typedef struct SF_OPERATORS_LIST_S +{ + UINT8 OperatorNameLong[20]; + UINT8 OperatorNameShort[10]; + UINT8 OperatorNum[10]; + UINT8 SignalVal; + UINT8 NetType; + UINT8 Index; + struct SF_OPERATORS_LIST_S *pPre; + struct SF_OPERATORS_LIST_S *pNext; +} SF_OPERATORS_LIST_T; + typedef struct sf_gps_param { int timeout_ms; int period_ms; @@ -63,6 +99,7 @@ SINT32 open_gps(const SINT32 utc); int get_gps_location(void); void keep_get_gps_location(const SF_GPS_PARAM param); void keep_seraching_gps_location(const int timeout_ms); +void app_RegisterNet_stop(); #ifdef __cplusplus #if __cplusplus diff --git a/code/application/source/sf_app/code/include/sf_wifi_svr.h b/code/application/source/sf_app/code/include/sf_wifi_svr.h old mode 100644 new mode 100755 index 83e8182d3..7d437fd5a --- a/code/application/source/sf_app/code/include/sf_wifi_svr.h +++ b/code/application/source/sf_app/code/include/sf_wifi_svr.h @@ -17,7 +17,7 @@ #define LISTEN_PARAM 5 #endif -#define SF_LPA_SDK 0 +#define SF_LPA_SDK 1 #define DEBUG_INFO_ON_LCD 0 #define DBG_LOG 0 diff --git a/code/application/source/sf_app/code/source/4gMng/sf_4G_sms_lpa_cmd.c b/code/application/source/sf_app/code/source/4gMng/sf_4G_sms_lpa_cmd.c new file mode 100755 index 000000000..774f5458d --- /dev/null +++ b/code/application/source/sf_app/code/source/4gMng/sf_4G_sms_lpa_cmd.c @@ -0,0 +1,2060 @@ +/************************************************************************** + * + * Copyright (c) 2009-2018 by SiFar Technology, Inc. + * + * This software is copyrighted by and is the property of SiFar + * Technology, Inc.. All rights are reserved by SiFar Technology, Inc.. + * This software may only be used in accordance with the corresponding + * license agreement. Any unauthorized use, duplication, distribution, + * or disclosure of this software is expressly forbidden. + * + * This Copyright notice MUST not be removed or modified without prior + * written consent of SiFar Technology, Inc.. + * + * SiFar Technology, Inc. reserves the right to modify this software without notice. + * + * Author: HAC + * Ver: 1.0.0 2021.04.12 + * Description: creat +**************************************************************************/ +#include +#include +#include +#include + +#if !SIFAR_PLATFORM_ICATCH +#include +#include +#endif +#include "sf_4g_lpa.h" +#include "sf_common.h" +#include "sf_wifi_svr.h" +#include "sf_data_transfer.h" +#include "lpasdk/api/semedia/semedia.h" +#include "lpasdk/api/lpasdk_api.h" + +#include "sf_log.h" +#include "sf_sim.h" +#include "sf_systemMng.h" +#include "sf_service.h" +#include "sf_4G_sms_lpa_cmd.h" +#include "sf_file.h" + + + +#ifdef SAMPLE__GENERIC_MODEM + +#if !SIFAR_PLATFORM_ICATCH +#include +#include +#include +#include +#endif + +#endif + +/************************************************************************** + * C O N S T A N T S * + **************************************************************************/ + +/************************************************************************** + * M A C R O S * + **************************************************************************/ + + +/************************************************************************** + * D A T A T Y P E S * + **************************************************************************/ + + +/************************************************************************** + * G L O B A L D A T A * + **************************************************************************/ +//static SP5K_EVENT_FLAGS_GROUP SmsLpaEvent = 0; +static SF_SMS_LPA_CMD_LIST_T *pSmsLpaCmdListHead = NULL; +//static UINT16 ProfileEnableCmdVal = 0; +static SF_BOOL LpaCommandSendLog = FALSE; + +static SINT8 LpaProfileNeedEnableIccid[SF_SMS_LPA_ICCID_MAX_SIZE + 1] = {0}; +static SINT8 LpaDownLoadProfileApn[SF_SMS_LPA_APN_MAX_SIZE + 1] = {0}; +static SINT8 LpaDownLoadEnableProfileApn[SF_SMS_LPA_APN_MAX_SIZE + 1] = {0}; + +/************************************************************************** + * E X T E R N A L R E F E R E N C E S * + **************************************************************************/ +//extern uiPara_t *pPara_sms_saved; +//extern SF_CAMERA_CMD_S CameraCmd; + + +extern void sha256(const char* d, int ld, char* out, int* t); +//extern SINT32 sf_4g_usb_net_init(void); + +/************************************************************************** + * F U N C T I O N D E C L A R A T I O N S * + **************************************************************************/ +//#define SF_SUNPLS +#define SF_LINUX + +#ifdef SF_SUNPLS +void sf_sms_lpa_event_flags_group_init(void) +{ + UINT32 err = 0; + + err = sp5kOsEventFlagsCreate(&SmsLpaEvent, "SmsLpaEvent"); + + HOST_ASSERT(err == SP5K_SUCCESS); +} + +void sf_sms_lpa_event_flags_group_del(void) +{ + sp5kOsEventFlagsDelete(&SmsLpaEvent); + SmsLpaEvent = 0; +} + +void sf_sms_lpa_event_set(void) +{ + UINT32 err = 0; + + err = sp5kOsEventFlagsSet(&SmsLpaEvent, 0x01, TX_OR); + HOST_ASSERT(err == SP5K_SUCCESS); +} + +SINT32 sf_sms_lpa_event_get(ULONG timeOut) +{ + ULONG flags = 0; + + sp5kOsEventFlagsGet(&SmsLpaEvent, 0x01, TX_OR_CLEAR, &flags, timeOut); + + if(flags & 0x01) + return SF_SUCCESS; + + return SF_FAILURE; +} +#endif + +#ifdef SF_LINUX + + +SF_THREAD_S LpaEnableTask = +{ + .IsRun = 0, +}; + +SF_THREAD_S LpaCmdExcuteTask = +{ + .IsRun = 0, +}; + +#endif + +/************************************************* + Function: sf_read_file + Description: read file to disk + Input: filename:read file name + Output: filebuff:data buff, len: file size + Return: success/fail + Others: N/A +*************************************************/ +UINT32 sf_read_file(UINT8* filename, UINT8* buff, UINT32 len) +{ + UINT32 fd = 0, rLen = 0; + + if((filename == NULL) || (buff == NULL)) + { + printf("input param null\n"); + return FAIL; + } + + fd = SF_OPEN(filename, O_RDWR, 0777); + if(!fd) + { + printf("open %s fail\n", filename); + return FAIL; + } + + rLen = SF_READ(fd, buff, len); + printf("rLen = %d\n", rLen); + SF_CLOSE(fd); + + return SUCCESS; +} + +#if 0 +/************************************************* + Function: sf_get_file_size + Description: get file size + Input: N/A + Output: N/A + Return: file size + Others: N/A +*************************************************/ +UINT32 sf_get_file_size(UINT8 * fname) +{ + UINT32 fd = 0, fSize = 0; + struct stat statBuf; + + if(fname == NULL) + { + printf("fname null\n"); + return fSize; + } + + fd = SF_OPEN(fname, O_RDWR, 0777); + + if(fd >= 0) + { + fstat(fd, &statBuf); + fSize = statBuf.st_size; + printf("fSize=%d\n", fSize); + SF_CLOSE(fd); + } + + return fSize; +} +#endif + +SINT32 sf_file_exsit(CHAR *fileName) +{ + if(access(fileName, F_OK) == 0) + return SUCCESS; + else + return FAIL; +} + +/************************************************* + Function: sf_save_file + Description: save file to disk + Input: filename:save file name, filebuff:data buff, len: file size + Output: file + Return: success/fail + Others: N/A +*************************************************/ +UINT32 sf_save_file(UINT8* filename, UINT8* filebuff, UINT32 len) +{ + UINT32 fd = 0; + UINT32 fileSize = 0; + + printf("\nsave %s %d\n", filename, len); + + remove(filename); + + fd = open(filename, O_WRONLY | O_CREAT, 0777); + + if (fd==0) + { + printf("CREATE %s err\n", filename); + + return FAIL; + } + + fileSize = write(fd, filebuff, len); + + close(fd); + + if(fileSize != len) + { + printf("Write size err,write=%d len=%d\n", fileSize, len); + + return FAIL; + } + + printf("save end\n"); + + return SUCCESS; +} + + +SF_SMS_LPA_CMD_LIST_T *sf_sms_lpa_cmd_list_head_get(void) +{ + return pSmsLpaCmdListHead; +} + +/************************************************* + Function: sf_operator_list_print + Description: printf operator list + Input: N/A + Output: N/A + Return: N/A + Others: N/A +*************************************************/ +void sf_sms_lpa_cmd_list_print(void) +{ + SF_SMS_LPA_CMD_LIST_T *pList = sf_sms_lpa_cmd_list_head_get(); + + SLOGD("lpa cmd list print:\n"); + + while(pList != NULL) + { + SLOGD("cmd:0x%x\n", pList->LpaCmd.CmdVal); + SLOGD("Param1:%s\n", pList->LpaCmd.Param1Buff[0] != '\0' ? (SINT8 *)&pList->LpaCmd.Param1Buff[0] : (SINT8 *)"null"); + SLOGD("Param2:%s\n", pList->LpaCmd.Param2Buff[0] != '\0' ? (SINT8 *)&pList->LpaCmd.Param2Buff[0] : (SINT8 *)"null"); + SLOGD("Param3:%s\n", pList->LpaCmd.Param3Buff[0] != '\0' ? (SINT8 *)&pList->LpaCmd.Param3Buff[0] : (SINT8 *)"null"); + pList = pList->pNext; + } +} + +/************************************************* + Function: sf_sms_lpa_cmd_list_total_get + Description: get sms lpa cmd total + Input: N/A + Output: N/A + Return: total + Others: N/A +*************************************************/ +UINT8 sf_sms_lpa_cmd_list_total_get(void) +{ + SF_SMS_LPA_CMD_LIST_T *pList = sf_sms_lpa_cmd_list_head_get(); + UINT8 total = 0; + + while(pList != NULL) + { + total++; + pList = pList->pNext; + } + + SLOGD("lpa cmd list total:%d\n", total); + + return total; +} + +/************************************************* + Function: sf_sms_lpa_cmd_list_item_get + Description: get sms cmd list item + Input: N/A + Output: N/A + Return: N/A + Others: N/A +*************************************************/ +SINT32 sf_sms_lpa_cmd_list_item_get(SF_SMS_LPA_CMD_T *pLpaCmd) +{ + SF_SMS_LPA_CMD_LIST_T *pList = sf_sms_lpa_cmd_list_head_get(); + + SLOGD("lpa cmd list item get:\n"); + + if(pList != NULL) + { + memcpy(pLpaCmd, &pList->LpaCmd, sizeof(SF_SMS_LPA_CMD_T)); + SLOGD("cmd:0x%x\n", pLpaCmd->CmdVal); + SLOGD("Param1:%s\n", pLpaCmd->Param1Buff[0] != '\0' ? (SINT8 *)&pLpaCmd->Param1Buff[0] : (SINT8 *)"null"); + SLOGD("Param2:%s\n", pLpaCmd->Param2Buff[0] != '\0' ? (SINT8 *)&pLpaCmd->Param2Buff[0] : (SINT8 *)"null"); + SLOGD("Param3:%s\n", pLpaCmd->Param3Buff[0] != '\0' ? (SINT8 *)&pLpaCmd->Param3Buff[0] : (SINT8 *)"null"); + pSmsLpaCmdListHead = pList->pNext; + free(pList); + + return SF_SUCCESS; + } + + return SF_FAILURE; +} + +/************************************************* + Function: sf_sms_lpa_cmd_list_item_add + Description: add sms lpa cmd to list + Input: SF_SMS_LPA_CMD_T addr + Output: N/A + Return: N/A + Others: N/A +*************************************************/ +SINT32 sf_sms_lpa_cmd_list_item_add(SF_SMS_LPA_CMD_T *pLpaCmd) +{ + SF_SMS_LPA_CMD_LIST_T *pList = sf_sms_lpa_cmd_list_head_get(); + + if(pLpaCmd == NULL) + { + SLOGD("input pLpaCmd null\n"); + + return SF_FAILURE; + } + + SLOGD("lpa cmd list add cmd:%d\n", pLpaCmd->CmdVal); + + SF_SMS_LPA_CMD_LIST_T *pLpaCmdItem = malloc(sizeof(SF_SMS_LPA_CMD_LIST_T)); + + if(pLpaCmdItem == NULL) + { + SLOGD("lpa cmd list add cmd: memory error\n"); + + return SF_FAILURE; + } + + memset(pLpaCmdItem, 0, sizeof(SF_SMS_LPA_CMD_LIST_T)); + memcpy(&pLpaCmdItem->LpaCmd, pLpaCmd, sizeof(SF_SMS_LPA_CMD_T)); + + if(pSmsLpaCmdListHead == NULL) + { + pSmsLpaCmdListHead = pLpaCmdItem; + + return SF_SUCCESS; + } + + while(pList != NULL) + { + if(pList->pNext == NULL) + { + pList->pNext = pLpaCmdItem; + + return SF_SUCCESS; + } + + pList = pList->pNext; + } + + return SF_FAILURE; +} + +/************************************************* + Function: sf_sms_lpa_cmd_list_item_add_to_head + Description: add sms lpa cmd to list + Input: SF_SMS_LPA_CMD_T addr + Output: N/A + Return: N/A + Others: N/A +*************************************************/ +SINT32 sf_sms_lpa_cmd_list_item_add_to_head(SF_SMS_LPA_CMD_T *pLpaCmd) +{ + SF_SMS_LPA_CMD_LIST_T *pLpaCmdItem = NULL; + + if(pLpaCmd == NULL) + { + SLOGD("input pLpaCmd null\n"); + + return SF_FAILURE; + } + + SLOGD("lpa cmd list add cmd to head:%d\n", pLpaCmd->CmdVal); + + pLpaCmdItem = malloc(sizeof(SF_SMS_LPA_CMD_LIST_T)); + + if(pLpaCmdItem == NULL) + { + SLOGD("lpa cmd list add cmd to head: memory error\n"); + + return SF_FAILURE; + } + + memset(pLpaCmdItem, 0, sizeof(SF_SMS_LPA_CMD_LIST_T)); + memcpy(&pLpaCmdItem->LpaCmd, pLpaCmd, sizeof(SF_SMS_LPA_CMD_T)); + SLOGD("add cmd to head:%d\n", pLpaCmdItem->LpaCmd.CmdVal); + SLOGD("Param3:%s\n", pLpaCmdItem->LpaCmd.Param3Buff); + + if(pSmsLpaCmdListHead == NULL) + { + pSmsLpaCmdListHead = pLpaCmdItem; + + return SF_SUCCESS; + } + + pLpaCmdItem->pNext = pSmsLpaCmdListHead; + pSmsLpaCmdListHead = pLpaCmdItem; + + return SF_SUCCESS; +} + +SINT32 sf_sms_lpa_command_info_extract(const SINT8 *cmdStr, UINT16 *cmdId, SINT8 *param1, SINT8 *param2, SINT8 *param3) +{ + UINT16 lpaCmd = SF_SMS_LPA_CMD_UNKNOWN; + SINT8 urlStr[SF_SMS_LPA_URL_MAX_SIZE + 1] = { 0 }; + SINT8 hashStr[SF_SMS_LPA_HASH_MAX_SIZE + 2] = { 0 }; + SINT8 apnStr[SF_SMS_LPA_APN_MAX_SIZE + 1] = { 0 }; + UINT8 *tmp = NULL; + SINT32 ret = SF_LPA_CUSTOM_ERROR_CMD_UNKNOWN; + UINT8 len = 0; + + SLOGD("cmd extract:%s\n", cmdStr); + if(SF_STRLEN(cmdStr) > 0) + { + + /* 获取第一个分隔符后的子字符串 */ + tmp = SF_STRTOK(cmdStr, "$"); + SLOGD("tmp:%s\n", tmp); + + /* 输出两个$符号之间的数据 */ + if (tmp != NULL) + { + if(SF_STRNCMP(tmp, "R0e*1#1", SF_STRLEN(tmp)) == 0) + { + lpaCmd = SF_SMS_LPA_CMD_DOWNLOAD_PROFILE_1; + } + else if(SF_STRNCMP(tmp, "R0e*1#1#1", SF_STRLEN(tmp)) == 0) + { + lpaCmd = SF_SMS_LPA_CMD_DOWNLOAD_PROFILE_2; + } + else if(SF_STRNCMP(tmp, "R0e*1#2", SF_STRLEN(tmp)) == 0) + { + lpaCmd = SF_SMS_LPA_CMD_DOWNLOAD_ENABLE_PROFILE_1; + } + else if(SF_STRNCMP(tmp, "R0e*1#2#1", SF_STRLEN(tmp)) == 0) + { + lpaCmd = SF_SMS_LPA_CMD_DOWNLOAD_ENABLE_PROFILE_2; + } + else if(SF_STRNCMP(tmp, "R0e*2#0", SF_STRLEN(tmp)) == 0) + { + lpaCmd = SF_SMS_LPA_CMD_ENABLE_PROFILE; + } + else if(SF_STRNCMP(tmp, "R0e*2#1", SF_STRLEN(tmp)) == 0) + { + lpaCmd = SF_SMS_LPA_CMD_DELETE_PROFILE; + } + else if(SF_STRNCMP(tmp, "R0e*3#1", SF_STRLEN(tmp)) == 0) + { + lpaCmd = SF_SMS_LPA_CMD_DELETE_PROFILE_NITIFY; + } + + *cmdId = lpaCmd; + SLOGD("lpaCmd:%d\n", lpaCmd); + + } + } + + switch(lpaCmd) + { + case SF_SMS_LPA_CMD_DOWNLOAD_PROFILE_1: + case SF_SMS_LPA_CMD_DOWNLOAD_ENABLE_PROFILE_1: + tmp = SF_STRTOK(NULL, "\r\n"); + SLOGD("tmp:%s\n", tmp); + + if (tmp != NULL) + { + //ex: $R0e*1#2$LPA:1$thales1-livelab.prod.ondemandconnectivity.com$EA32034190806A2DA57E03A449492361343BCFBA040A92E2E1E90C0E5A6097A8^ + //get ac code,not with "LPA:": 1$thales1-livelab.prod.ondemandconnectivity.com$EA32034190806A2DA57E03A449492361343BCFBA040A92E2E1E90C0E5A6097A8 + SF_STRNCPY(urlStr, tmp+SF_SMS_LPA_AC_PRE_MAX_SIZE, SF_SMS_LPA_URL_MAX_SIZE); + len = SF_STRLEN(urlStr); + + if (*(urlStr + len - 2) == '$') + { + *(urlStr + len - 2) = '\0'; + } + + urlStr[SF_SMS_LPA_URL_MAX_SIZE] = '\0'; + SF_STRCPY(param1, urlStr); + ret = SF_SUCCESS; + } + break; + + case SF_SMS_LPA_CMD_DOWNLOAD_PROFILE_2: + case SF_SMS_LPA_CMD_DOWNLOAD_ENABLE_PROFILE_2: + case SF_SMS_LPA_CMD_ENABLE_PROFILE: + case SF_SMS_LPA_CMD_DELETE_PROFILE: + tmp = SF_STRTOK(NULL, "$"); + SLOGD("tmp:%s\n", tmp); + if (tmp != NULL) + { + SF_STRNCPY(apnStr, tmp, SF_SMS_LPA_APN_MAX_SIZE); + apnStr[SF_SMS_LPA_APN_MAX_SIZE] = '\0'; + SF_STRCPY(param1, apnStr); + } + + tmp = SF_STRTOK(NULL, "$"); + SLOGD("tmp:%s\n", tmp); + if (tmp != NULL) + { + SF_STRNCPY(hashStr, tmp, SF_SMS_LPA_HASH_MAX_SIZE); + hashStr[SF_SMS_LPA_HASH_MAX_SIZE] = '\0'; + SF_STRCPY(param2, hashStr); + ret = SF_SUCCESS; + } + break; + + case SF_SMS_LPA_CMD_DELETE_PROFILE_NITIFY: + tmp = SF_STRTOK(NULL, "$"); + SLOGD("tmp:%s\n", tmp); + if (tmp != NULL) + { + SF_STRNCPY(apnStr, tmp, SF_SMS_LPA_APN_MAX_SIZE); + apnStr[SF_SMS_LPA_APN_MAX_SIZE] = '\0'; + SF_STRCPY(param1, apnStr); + } + + tmp = SF_STRTOK(NULL, "$"); + SLOGD("tmp:%s\n", tmp); + if (tmp != NULL) + { + SF_STRNCPY(urlStr, tmp, SF_SMS_LPA_URL_MAX_SIZE); + urlStr[SF_SMS_LPA_URL_MAX_SIZE] = '\0'; + SF_STRCPY(param2, urlStr); + } + + tmp = SF_STRTOK(NULL, "$"); + SLOGD("tmp:%s\n", tmp); + if (tmp != NULL) + { + SF_STRNCPY(hashStr, tmp, SF_SMS_LPA_HASH_MAX_SIZE); + hashStr[SF_SMS_LPA_HASH_MAX_SIZE] = '\0'; + SF_STRCPY(param3, hashStr); + ret = SF_SUCCESS; + } + break; + + default: + ret = SF_LPA_CUSTOM_ERROR_CMD_UNKNOWN; + break; + } + + return ret; + +} + + +SINT8* sf_sms_lpa_log_file_name_get(void) +{ + static SINT8 logFileName[64] = {0}; + UIMenuStoreInfo *sfParam = sf_app_ui_para_get(); + if(logFileName[0] == '\0') + SF_SPRINTF(logFileName, "LPA%sTS.log", sfParam->ModuleImei); + + return logFileName; +} + +void sf_lpa_get_cmd_str(SF_SMS_LPA_CMD_T* pLpaCmd, SINT8* cmdStr) +{ + if(cmdStr == NULL) + return; + + if(pLpaCmd == NULL) + { + SF_SPRINTF(cmdStr, "%s", "local switch"); + } + /* + else if(pLpaCmd->LpaCmd == SF_SMS_LPA_CMD_DOWNLOAD_PROFILE_1) + { + SF_SPRINTF(cmdStr, "$R0e*1#1$LPA:%s^", pLpaCmd->Param1Buff); + }*/ + else if(pLpaCmd->CmdVal == SF_SMS_LPA_CMD_DOWNLOAD_PROFILE_2) + { + if(pLpaCmd->Param3Buff[0] == '\0') + SF_SPRINTF(cmdStr, "$R0e*1#1#1$%s$$", pLpaCmd->Param1Buff); + else + SF_SPRINTF(cmdStr, "$R0e*1#1#1$LPA:%s$%s$$", pLpaCmd->Param3Buff, pLpaCmd->Param1Buff); + } + /* + else if(pLpaCmd->LpaCmd == SF_SMS_LPA_CMD_DOWNLOAD_ENABLE_PROFILE_1) + { + SF_SPRINTF(cmdStr, "$R0e*1#2$LPA:%s^", pLpaCmd->Param1Buff); + }*/ + else if(pLpaCmd->CmdVal == SF_SMS_LPA_CMD_DOWNLOAD_ENABLE_PROFILE_2) + { + if(pLpaCmd->Param3Buff[0] == '\0') + SF_SPRINTF(cmdStr, "$R0e*1#2#1$%s$$", pLpaCmd->Param1Buff); + else + SF_SPRINTF(cmdStr, "$R0e*1#2#1$LPA:%s$%s$$", pLpaCmd->Param3Buff, pLpaCmd->Param1Buff); + } + else if(pLpaCmd->CmdVal == SF_SMS_LPA_CMD_ENABLE_PROFILE) + { + SF_SPRINTF(cmdStr, "$R0e*2#0$%s$$", pLpaCmd->Param1Buff); + } + else if(pLpaCmd->CmdVal == SF_SMS_LPA_CMD_DELETE_PROFILE) + { + SF_SPRINTF(cmdStr, "$R0e*2#1$%s$$", pLpaCmd->Param1Buff); + } + else if(pLpaCmd->CmdVal == SF_SMS_LPA_CMD_DELETE_PROFILE_NITIFY) + { + SF_SPRINTF(cmdStr, "$R0e*3#1$%s$%s$$", pLpaCmd->Param1Buff, pLpaCmd->Param2Buff); + } + else + { + SF_SPRINTF(cmdStr, "%s", "null"); + } + + return; +} + +void sf_lpa_get_status_str(SINT8 status, SINT8* statusStr) +{ + if(statusStr == NULL) + return; + + if(status == SF_SMS_LPA_CMD_SUCCESS) + SF_SPRINTF(statusStr, "%s", "Success"); + else if(status == SF_SMS_LPA_CMD_FAIL) + SF_SPRINTF(statusStr, "%s", "Failure"); + else + SF_SPRINTF(statusStr, "%s", "Unknown Err"); +} + +void sf_lpa_get_source_str(SINT8 source, SINT8* sourceStr) +{ + if(sourceStr == NULL) + return; + + if(source == SF_SMS_LPA_CMD_ERROR_SOURCE_ESIM) + SF_SPRINTF(sourceStr, "%s", "eSIM"); + else if(source == SF_SMS_LPA_CMD_ERROR_SOURCE_SMDP) + SF_SPRINTF(sourceStr, "%s", "SM-DP+"); + else if(source == SF_SMS_LPA_CMD_ERROR_SOURCE_OTHER) + SF_SPRINTF(sourceStr, "%s", "Other"); + else + SF_SPRINTF(sourceStr, "%s", "Unknown Err"); +} + +void sf_lpa_get_times_stamp(SINT8* timesTamp) +{ + //appRTC_t rtcTime; + SF_PARA_TIME_S rtcTime = { 0 }; + sf_sys_rtc_time_get(&rtcTime); + + //appRtcGet(&rtcTime); + SF_SPRINTF(timesTamp, "%d-%02d-%02dT%02d:%02d:%02dZ", rtcTime.Year, rtcTime.Mon, rtcTime.Day, rtcTime.Hour, rtcTime.Min, rtcTime.Sec); +} + +int sf_get_line(int fd) +{ + int line = 0; + int ret = 0; + char ch[2] = { 0 }; + + SF_SEEK(fd, 0, SEEK_SET); + while(1) + { + ret = read(fd, ch, 1); + if(ret <= 0) + return line; + + if(ch[0] == 0x0A) + line++; + } +} + +int sf_move_line(int fd, int line) +{ + char ch[2] = { 0 }; + int n = 0; + int ret = 0; + + SF_SEEK(fd, 0, SEEK_SET); + while(1) + { + if(n == line) + return 0; + + ret = SF_READ(fd, ch, 1); + if(ret <= 0) + return -1; + + if(ch[0] == 0x0A) + n++; + } +} + +void sf_write_log_content(int fd, SF_SMS_LPA_CMD_T* pLpaCmd, SINT8 status, unsigned short errorCode, SINT8 Source) +{ + UINT8 tmpStr[512] = { 0 }; + + sf_sms_lpa_set_send_lpa_log_flg(1); + + //append log concent in the file end + SF_SEEK(fd, 0, SEEK_END); + + sf_lpa_get_times_stamp(tmpStr); + SF_WRITE(fd, tmpStr, strlen(tmpStr)); + SF_WRITE(fd, ",", 1); + SLOGD("%s", tmpStr); + printf(","); + + memset(tmpStr, '\0', sizeof(tmpStr)); + sf_lpa_get_all_iccid(tmpStr); + SF_WRITE(fd, tmpStr, strlen(tmpStr)); + SF_WRITE(fd, ",", 1); + printf("%s", tmpStr); + printf(","); + + SF_MEMSET(tmpStr, '\0', sizeof(tmpStr)); + sf_get_eid(tmpStr); + SF_WRITE(fd, tmpStr, strlen(tmpStr)); + SF_WRITE(fd, ",", 1); + printf("%s", tmpStr); + printf(","); + + SF_MEMSET(tmpStr, '\0', sizeof(tmpStr)); + sf_lpa_get_cmd_str(pLpaCmd, tmpStr); + SF_WRITE(fd, tmpStr, strlen(tmpStr)); + SF_WRITE(fd, ",", 1); + printf("%s", tmpStr); + printf(","); + + memset(tmpStr, '\0', sizeof(tmpStr)); + sf_lpa_get_status_str(status, tmpStr); + SF_WRITE(fd, tmpStr, strlen(tmpStr)); + SF_WRITE(fd, ",", 1); + printf("%s", tmpStr); + printf(","); + + SF_MEMSET(tmpStr, '\0', sizeof(tmpStr)); + if(errorCode == 0) + SF_SPRINTF(tmpStr, "%s", "FFFF"); + else + SF_SPRINTF(tmpStr, "%04d", errorCode); + + SF_WRITE(fd, tmpStr, strlen(tmpStr)); + SF_WRITE(fd, ",", 1); + printf("%s", tmpStr); + printf(","); + + memset(tmpStr, '\0', sizeof(tmpStr)); + sf_lpa_get_source_str(Source, tmpStr); + SF_WRITE(fd, tmpStr, strlen(tmpStr)); + SF_WRITE(fd, "\r\n", 2); + printf("%s\r\n", tmpStr); +} + + +int sf_sms_lpa_command_log(SF_SMS_LPA_CMD_T* pLpaCmd, SINT8 status, unsigned short errorCode, SINT8 Source) +{ + SINT32 lineNum = 0; + SINT32 delLineNum = 0; + SINT32 readCnt = 0; + SINT32 fdOld = -1; + SINT32 fdNew = -1; + SF_CHAR ch[2] = { 0 }; + SF_CHAR filePath[64] = { 0 }; + SF_CHAR newFilePath[64] = { 0 }; + + UIMenuStoreInfo *sfParam = sf_app_ui_para_get(); + + SF_SPRINTF(filePath, "%sLPA%sTS.log", SF_LPA_LOG_FILE_PATH, sfParam->ModuleImei); + SLOGD("filePath:%s\n", filePath); + + fdOld = SF_OPEN(filePath, O_RDWR, 0777); + if(fdOld >= 0) + { + //1.read all content, get line number + lineNum = sf_get_line(fdOld); + SLOGD("file lineNum:%d\n", lineNum); + + //2.if line numer >= 50, delete the first line + if(lineNum >= 50) + { + + delLineNum = lineNum - 50; + sf_move_line(fdOld, delLineNum + 1); + SLOGD("delLineNum:%d\n", delLineNum); + + SF_SPRINTF(newFilePath, "%sLPA.log", SF_LPA_LOG_FILE_PATH); + fdNew = SF_OPEN(newFilePath, O_WRONLY | O_CREAT, 0777); + if(fdNew >= 0) + { + while(1) + { + readCnt = SF_READ(fdOld, ch, 1); + if(readCnt <= 0) + break; + SF_WRITE(fdNew, ch, 1); + } + sf_write_log_content(fdNew, pLpaCmd, status, errorCode, Source); + SF_CLOSE(fdNew); + } + + SF_CLOSE(fdOld); + + SF_DELETE(filePath); + SF_SYNC(); + + SF_RENAME(newFilePath, filePath); + + } + else + { + // line num is less than 50, record log direct + sf_write_log_content(fdOld, pLpaCmd, status, errorCode, Source); + SF_CLOSE(fdOld); + } + + + } + else + { + //old log file in sd card, not exist + SLOGD("\n"); + SF_SPRINTF(filePath, "%sLPA%sTS.log", SF_LPA_LOG_FILE_PATH, sfParam->ModuleImei); + SLOGD("filePath:%s\n", filePath); + fdNew = SF_OPEN(filePath, O_WRONLY | O_CREAT, 0777); + if(fdNew >= 0) + sf_write_log_content(fdNew, pLpaCmd, status, errorCode, Source); + SF_CLOSE(fdNew); + } + + SF_SYNC(); + +} + +void sf_sms_lpa_delete_lpa_log(void) +{ + UINT8 fileName[64] = { 0 }; + + SF_SPRINTF(fileName, "%s%s", SF_LPA_LOG_FILE_PATH, sf_sms_lpa_log_file_name_get()); + + if(sf_file_exsit(fileName) == SF_SUCCESS) + { + SLOGD("Delete %s\n", fileName); + SF_DELETE(fileName); + SF_SYNC(); + } +} + +SINT32 sf_sms_lpa_command_recombination(SF_SMS_LPA_CMD_T *pLpaCmd) +{ + SINT8 iccid[SF_SMS_LPA_ICCID_MAX_SIZE + 1] = {0}; + + if(pLpaCmd == NULL) + { + return SF_FAILURE; + } + + SLOGD("lpa cmd recombination\n"); + if(sf_lpa_get_active_profile_iccid(iccid) == SF_FAILURE) + { + SLOGD("get active iccid fail\n"); + + return SF_FAILURE; + } + + pLpaCmd->CmdVal = sf_sms_lpa_get_enable_profile_cmd_val(); + + if(pLpaCmd->CmdVal == SF_SMS_LPA_CMD_DOWNLOAD_ENABLE_PROFILE_2) + { + if(sf_sms_lpa_get_profile_info_item(iccid, pLpaCmd->Param1Buff, pLpaCmd->Param3Buff) == SF_FAILURE) + return FAIL; + } + else if(pLpaCmd->CmdVal == SF_SMS_LPA_CMD_ENABLE_PROFILE) + { + SF_STRNCPY(pLpaCmd->Param1Buff, iccid, SF_SMS_LPA_ICCID_MAX_SIZE + 1); + } + + return SF_SUCCESS; +} + +SINT32 sf_sms_lpa_command_recombination_log(SINT8 status, UINT16 errorCode) +{ + SF_SMS_LPA_CMD_T *pLpaCmd = malloc(sizeof(SF_SMS_LPA_CMD_T)); + + if(pLpaCmd == NULL) + { + //sf_sms_lpa_command_log(NULL, status, errorCode, SF_SMS_LPA_CMD_ERROR_SOURCE_OTHER); + + return SF_FAILURE; + } + + memset(pLpaCmd, 0, sizeof(SF_SMS_LPA_CMD_T)); + sf_sms_lpa_command_recombination(pLpaCmd); + + if(pLpaCmd->CmdVal == SF_SMS_LPA_CMD_DOWNLOAD_ENABLE_PROFILE_2) + { + if(status == SF_SMS_LPA_CMD_SUCCESS) + sf_sms_lpa_command_log(pLpaCmd, status, errorCode, SF_SMS_LPA_CMD_ERROR_SOURCE_OTHER); + else + sf_sms_lpa_command_log(pLpaCmd, status, errorCode, SF_SMS_LPA_CMD_ERROR_SOURCE_SMDP); + } + else + { + if(status == SF_SMS_LPA_CMD_SUCCESS) + sf_sms_lpa_command_log(pLpaCmd, status, errorCode, SF_SMS_LPA_CMD_ERROR_SOURCE_OTHER); + else + sf_sms_lpa_command_log(pLpaCmd, status, errorCode, SF_SMS_LPA_CMD_ERROR_SOURCE_ESIM); + } + + free(pLpaCmd); + + return SF_SUCCESS; +} + + +SINT32 sf_sms_lpa_hash_signature(const SINT8 *eid, const SINT8 *secret, SINT8 *signature) /*signature size need >= SF_SMS_LPA_CMD_HASH_KEY_LENGTH * 2 + 1*/ +{ + UINT8 buf[256] = {0}; + UINT8 hash[32] = {0}; + int lenOut = 32; + UINT8 i = 0; + UIMenuStoreInfo *sfParam = sf_app_ui_para_get(); + + SF_SPRINTF(buf, "%s,%s,%s", sfParam->ModuleImei, eid, secret); + // SF_SPRINTF(buf, "%s", "860322065282227,89033023425110000000024642328469,Tact^$werew"); + SLOGD("buf:%s\n", buf); + + sha256(buf, SF_STRLEN(buf), hash, &lenOut); + + for (i = 0; i < SF_SMS_LPA_CMD_HASH_KEY_LENGTH; i++) { + SF_SPRINTF(signature + i * 2, "%02x", hash[i]); + } + + signature[SF_SMS_LPA_CMD_HASH_KEY_LENGTH * 2] = '\0'; + + for(i = 0; i < (SF_SMS_LPA_CMD_HASH_KEY_LENGTH * 2); i++) + { + if((signature[i] >= 'a') && (signature[i] <= 'z')) + { + signature[i] = signature[i] - 32; + } + } + + SLOGD("signature:%s\n", signature); + + return SF_SUCCESS; +} + +SINT32 sf_sms_lpa_save_download_profile_activation_code(UINT16 cmdVal, const SINT8* activationCodeStr) +{ + + #if 0 + if(activationCodeStr == NULL) + return SF_FAILURE; + + SF_STRNCPY(LpaProfileActivationCode, activationCodeStr, SF_SMS_LPA_AC_MAX_SIZE); + + SLOGD("LpaProfileActivationCode:%s\n", LpaProfileActivationCode); + + return SF_SUCCESS; + + #else + UINT8 fileName[64] = { 0 }; + + if((activationCodeStr == NULL) || ((cmdVal != SF_SMS_LPA_CMD_DOWNLOAD_PROFILE_1) && (cmdVal != SF_SMS_LPA_CMD_DOWNLOAD_ENABLE_PROFILE_1))) + { + return SF_FAILURE; + } + + SLOGD("save Cmd:%d ActivationCode:%s\n", cmdVal, activationCodeStr); + + if(cmdVal == SF_SMS_LPA_CMD_DOWNLOAD_PROFILE_1) + { + sprintf(fileName, "%s", SF_LPA_DOWNLOAD_PROFILE_AC_FILENEME); + } + else + { + sprintf(fileName, "%s", SF_LPA_DOWNLOAD_ENABLE_PROFILE_AC_FILENEME); + } + + if(sf_save_file(fileName, (UINT8*)activationCodeStr, SF_STRLEN(activationCodeStr)) == FAIL) + { + return SF_FAILURE; + } + + return SF_SUCCESS; + #endif +} + +SINT32 sf_sms_lpa_load_download_profile_activation_code(UINT16 cmdVal, SINT8* activationCodeStr) +{ + #if 0 + if(activationCodeStr == NULL) + return SF_FAILURE; + + SF_STRNCPY(activationCodeStr, LpaProfileActivationCode, SF_SMS_LPA_AC_MAX_SIZE); + SLOGD("LpaProfileActivationCode:%s\n", LpaProfileActivationCode); + + return SF_SUCCESS; + + #else + UINT32 fSize = 0; + UINT8 fileName[64] = { 0 }; + + if((activationCodeStr == NULL) || ((cmdVal != SF_SMS_LPA_CMD_DOWNLOAD_PROFILE_1) && (cmdVal != SF_SMS_LPA_CMD_DOWNLOAD_ENABLE_PROFILE_1))) + { + return SF_FAILURE; + } + + if(cmdVal == SF_SMS_LPA_CMD_DOWNLOAD_PROFILE_1) + { + sprintf(fileName, "%s", SF_LPA_DOWNLOAD_PROFILE_AC_FILENEME); + } + else + { + sprintf(fileName, "%s", SF_LPA_DOWNLOAD_ENABLE_PROFILE_AC_FILENEME); + } + + fSize = sf_get_file_size(fileName); + + if(fSize == 0) + { + return SF_FAILURE; + } + + if(sf_read_file(fileName, (UINT8 *)activationCodeStr, fSize) == FAIL) + { + return SF_FAILURE; + } + + SLOGD("load Cmd:%d ActivationCode:%s\n", cmdVal, activationCodeStr); + + return SF_SUCCESS; + #endif +} + +void sf_sms_lpa_delete_download_profile_activation_code(UINT16 cmdVal) +{ + UINT8 fileName[64] = { 0 }; + + if(cmdVal == SF_SMS_LPA_CMD_DOWNLOAD_PROFILE_1) + { + sprintf(fileName, "%s", SF_LPA_DOWNLOAD_PROFILE_AC_FILENEME); + } + else + { + sprintf(fileName, "%s", SF_LPA_DOWNLOAD_ENABLE_PROFILE_AC_FILENEME); + } + + SLOGD("Delete %s\n", fileName); + SF_DELETE(fileName); + SF_SYNC(); +} + +SINT32 sf_sms_lpa_save_download_profile_apn(UINT16 cmdVal, const SINT8* apn) +{ + if((apn == NULL) || ((cmdVal != SF_SMS_LPA_CMD_DOWNLOAD_PROFILE_2) && (cmdVal != SF_SMS_LPA_CMD_DOWNLOAD_ENABLE_PROFILE_2))) + { + return SF_FAILURE; + } + + if(cmdVal == SF_SMS_LPA_CMD_DOWNLOAD_PROFILE_2) + { + SF_STRNCPY(LpaDownLoadProfileApn, apn, SF_SMS_LPA_APN_MAX_SIZE); + } + else + { + SF_STRNCPY(LpaDownLoadEnableProfileApn, apn, SF_SMS_LPA_APN_MAX_SIZE); + } + + SLOGD("save Cmd:%d apn:%s\n", cmdVal, apn); + + return SF_SUCCESS; +} + +SINT32 sf_sms_lpa_load_download_profile_apn(UINT16 cmdVal, SINT8* apn) +{ + if((apn == NULL) || ((cmdVal != SF_SMS_LPA_CMD_DOWNLOAD_PROFILE_2) && (cmdVal != SF_SMS_LPA_CMD_DOWNLOAD_ENABLE_PROFILE_2))) + { + return SF_FAILURE; + } + + if(cmdVal == SF_SMS_LPA_CMD_DOWNLOAD_PROFILE_2) + { + SF_STRNCPY(apn, LpaDownLoadProfileApn, SF_SMS_LPA_APN_MAX_SIZE); + } + else + { + SF_STRNCPY(apn, LpaDownLoadEnableProfileApn, SF_SMS_LPA_APN_MAX_SIZE); + } + + SLOGD("load Cmd:%d apn:%s\n", cmdVal, apn); + + return SF_SUCCESS; +} + + +SINT32 sf_sms_lpa_save_profile_info_item(const SINT8* iccid, const SINT8* apn, const SINT8* activationCodeStr) +{ + + UINT32 fd = 0; + SINT8 buff[256] = {0}; + + if((iccid == NULL) || (apn == NULL) || (activationCodeStr == NULL)) + { + return SF_FAILURE; + } + + SLOGD("Add %s to %s\n", iccid, SF_LPA_PROFILE_INFO_FILENEME); + + fd = SF_OPEN(SF_LPA_PROFILE_INFO_FILENEME, O_WRONLY | O_CREAT, 0777); + + if(fd < 0) + { + SLOGD("Add fail\n"); + return SF_FAILURE; + } + + SF_SEEK(fd, 0, SEEK_END); + SF_SPRINTF(buff, "ICCID:%s APN:%s AC:%s\r\n", iccid, apn, activationCodeStr); + SLOGD("%s", buff); + SF_WRITE(fd, (UINT8 *)buff, SF_STRLEN(buff)); + SF_CLOSE(fd); + + SF_DELETE(SF_LPA_PROFILE_INFO_BACKUP_FILENEME); + memset(buff, '\0', sizeof(buff)); + sprintf(buff, "cp %s /sdcard/mmcblk0p1/ -f", SF_LPA_PROFILE_INFO_FILENEME); + system(buff); + + SF_SYNC(); + SLOGD("Add Success\n"); + + return SF_SUCCESS; +} + +SINT32 sf_sms_lpa_delete_profile_info_item(const SINT8* iccid) +{ + UINT32 fSize = 0; + UINT32 len = 0; + UINT8 delItem[30] = {0}; + SINT8 buff[256] = {0}; + UINT8 *fileBuff = NULL; + UINT8 *tmpFileBuff = NULL; + UINT8 *pStrStart = NULL; + UINT8 *pStrEnd = NULL; + UINT8 *ptmpAddr = NULL; + + if(iccid == NULL) + { + return SF_FAILURE; + } + + SLOGD("Delete %s to %s\n", iccid, SF_LPA_PROFILE_INFO_FILENEME); + + fSize = sf_get_file_size(SF_LPA_PROFILE_INFO_FILENEME); + + if(fSize != 0) + { + fileBuff = (UINT8 *)malloc(fSize + 1); + + if(fileBuff == NULL) + { + return SF_FAILURE; + } + + memset(fileBuff, '\0', fSize + 1); + + if(sf_read_file(SF_LPA_PROFILE_INFO_FILENEME, fileBuff, fSize) == FAIL) + { + free(fileBuff); + + return SF_FAILURE; + } + + SF_SPRINTF(delItem, "ICCID:%s ", iccid); + pStrStart = SF_STRSTR(fileBuff, delItem); + + if(pStrStart == NULL) + { + SLOGD("%s not found\n", delItem); + free(fileBuff); + return SF_SUCCESS; + } + + pStrEnd = SF_STRSTR(pStrStart, "\r\n"); + + if(pStrEnd == NULL) + { + SLOGD("file Fromt error\n"); + free(fileBuff); + return SF_FAILURE; + } + + pStrEnd = pStrEnd + 2; + tmpFileBuff = (UINT8 *)malloc(fSize + 1); + + if(tmpFileBuff == NULL) + { + SLOGD("memory error\n"); + free(fileBuff); + return SF_FAILURE; + } + + + + + memset(tmpFileBuff, '\0', fSize + 1); + len = abs(pStrStart - fileBuff); + + if(len) + { + memcpy(tmpFileBuff, fileBuff, len); + } + + ptmpAddr = tmpFileBuff + len; + len = fSize - len - abs(pStrEnd - pStrStart); + + if(len) + { + memcpy(ptmpAddr, pStrEnd, len); + } + + len = fSize - abs(pStrEnd - pStrStart); + + if(sf_save_file(SF_LPA_PROFILE_INFO_FILENEME, tmpFileBuff, len) == FAIL) + { + memset(buff, '\0', sizeof(buff)); + sprintf(buff, "cp %s /appfs/ -f", SF_LPA_PROFILE_INFO_BACKUP_FILENEME); + system(buff); + SF_SYNC(); + + SLOGD("refresh error\n"); + free(fileBuff); + free(tmpFileBuff); + return SF_FAILURE; + } + + SF_DELETE(SF_LPA_PROFILE_INFO_BACKUP_FILENEME); + memset(buff, '\0', sizeof(buff)); + sprintf(buff, "cp %s /sdcard/mmcblk0p1/ -f", SF_LPA_PROFILE_INFO_FILENEME); + system(buff); + SF_SYNC(); + + free(fileBuff); + free(tmpFileBuff); + } + + SLOGD("delete success\n"); + + return SF_SUCCESS; +} + +SINT32 sf_sms_lpa_get_profile_info_item(const SINT8* iccid, SINT8* apn, SINT8* activationCodeStr) +{ + UINT32 fSize = 0; + UINT8 dstItem[30] = {0}; + UINT8 buff[256] = {0}; + UINT8 *fileBuff = NULL; + UINT8 *pStr = NULL; + UINT8 *pStrEnd = NULL; + UINT8 fileName[64] = { 0 }; + UINT8 len = 0; + + if((iccid == NULL) || (apn == NULL) || (activationCodeStr == NULL)) + { + return SF_FAILURE; + } + + if((sf_sd_status_get() == SF_SD_OK) || (sf_sd_status_get() == SF_SD_FULL)) + { + if((sf_file_exsit(SF_LPA_PROFILE_INFO_FILENEME) != SUCCESS) && (sf_file_exsit(SF_LPA_PROFILE_INFO_BACKUP_FILENEME) == SUCCESS)) + { + memset(buff, '\0', sizeof(buff)); + sprintf(buff, "cp %s /appfs/ -f", SF_LPA_PROFILE_INFO_BACKUP_FILENEME); + system(buff); + SF_SYNC(); + } + else if((sf_file_exsit(SF_LPA_PROFILE_INFO_FILENEME) == SUCCESS) && (sf_file_exsit(SF_LPA_PROFILE_INFO_BACKUP_FILENEME) != SUCCESS)) + { + memset(buff, '\0', sizeof(buff)); + sprintf(buff, "cp %s /sdcard/mmcblk0p1/ -f", SF_LPA_PROFILE_INFO_FILENEME); + system(buff); + SF_SYNC(); + } + } + + memset(buff, '\0', sizeof(buff)); + SLOGD("get Profile item:%s\n", iccid); + sprintf(fileName, "%s", SF_LPA_PROFILE_INFO_FILENEME); + fSize = sf_get_file_size(fileName); + + if(fSize == 0) + { + sprintf(fileName, "%s", SF_LPA_PROFILE_INFO_BACKUP_FILENEME); + fSize = sf_get_file_size(fileName); + } + + if(fSize != 0) + { + fileBuff = (UINT8 *)malloc(fSize + 1); + + if(fileBuff == NULL) + { + SLOGD("memory error\n"); + return SF_FAILURE; + } + + memset(fileBuff, '\0', fSize + 1); + + if(sf_read_file(fileName, fileBuff, fSize) == FAIL) + { + SLOGD("read file error\n"); + free(fileBuff); + return SF_FAILURE; + } + + SF_SPRINTF(dstItem, "ICCID:%s ", iccid); + pStr = SF_STRSTR(fileBuff, dstItem); + + if(pStr == NULL) + { + SLOGD("%s not found\n", dstItem); + free(fileBuff); + return SF_FAILURE; + } + + if(sf_fgets((SINT8 **)&pStr, (SINT8 *)buff) == 0) + { + SLOGD("file Fromt error\n"); + free(fileBuff); + return SF_FAILURE; + } + + free(fileBuff); + + pStr = SF_STRSTR(buff, "APN:"); + + if(pStr == NULL) + { + SLOGD("APN not found\n"); + return SF_FAILURE; + } + + pStr = pStr + 4; + pStrEnd = SF_STRSTR(pStr, " "); + + if(pStrEnd == NULL) + { + SLOGD("APN Fromt error\n"); + return SF_FAILURE; + } + + len = abs(pStrEnd - pStr); + + memcpy(apn, pStr, len); + *(apn + len) = '\0'; + + pStr = SF_STRSTR(buff, "AC:"); + + if(pStr == NULL) + { + SLOGD("AC not found\n"); + return SF_FAILURE; + } + + pStr = pStr + 3; + len = SF_STRLEN(pStr); + memcpy(activationCodeStr, pStr, len); + *(activationCodeStr + len) = '\0'; + SLOGD("success\n"); + SLOGD("ICCID:%s\n", iccid); + SLOGD("APN:%s\n", apn); + SLOGD("AC:%s\n", activationCodeStr); + + return SF_SUCCESS; + } + + SLOGD("profile info file error\n"); + + return SF_FAILURE; +} + +//1'$thales1-livelab.prod.ondemandconnectivity.com'$M0GTA91V8C6QGFH5 +SINT32 sf_sms_lpa_smdp_addr_get(const SINT8* activationCodeStr, SINT8 *smdpAddr) +{ + UINT8 *pStr = NULL; + UINT8 *pStrEnd = NULL; + + if(activationCodeStr == NULL) + { + return SF_FAILURE; + } + + pStr = SF_STRSTR(activationCodeStr, "1$"); + + if(pStr == NULL) + { + SLOGD("activationCode error\n"); + return SF_FAILURE; + } + + pStr = pStr + 2; + + pStrEnd = SF_STRSTR(pStr, "$"); + + if(pStrEnd == NULL) + { + SLOGD("activationCode error\n"); + return SF_FAILURE; + } + + memcpy(smdpAddr, pStr, abs(pStrEnd - pStr)); + SLOGD("get smdpAddr:%s\n", smdpAddr); + + return SF_SUCCESS; +} + +void sf_sms_lpa_set_profile_switch_reboot_flg(UINT8 flg) +{ + UIMenuStoreInfo *pCustomerParam = sf_app_ui_para_get(); + + + pCustomerParam->ProfileSwitchFlg = flg; + + if(flg) + { + SLOGD("set camera need reboot\n"); + pCustomerParam->NetWorkNeedSearch = 1; + } + + //sf_set_param_save_flag(); +} + +SF_BOOL sf_sms_lpa_is_need_profile_switch_reboot(void) +{ + UIMenuStoreInfo *pCustomerParam = sf_app_ui_para_get(); + + if(pCustomerParam->ProfileSwitchFlg) + { + SLOGD("camera need reboot\n"); + return TRUE; + } + + return FALSE; +} + +void sf_sms_lpa_set_send_lpa_log_flg(SF_BOOL flg) +{ + LpaCommandSendLog = flg; +} + +SF_BOOL sf_sms_lpa_is_need_send_lpa_log(void) +{ + return LpaCommandSendLog; +} + +SINT32 sf_sms_lpa_save_pre_active_profile_iccid(const SINT8* iccid) +{ + UIMenuStoreInfo *pCustomerParam = sf_app_ui_para_get(); + + if(iccid == NULL) + return SF_FAILURE; + + SF_STRNCPY(pCustomerParam->PreActiveProfileIccid, iccid, SF_SMS_LPA_ICCID_MAX_SIZE); + pCustomerParam->PreActiveProfileIccid[SF_SMS_LPA_ICCID_MAX_SIZE] = '\0'; + SLOGD("pre acitve profile:%s\n", pCustomerParam->PreActiveProfileIccid); + //sf_set_param_save_flag(); + + return SF_SUCCESS; +} + +void sf_sms_lpa_save_enable_profile_cmd_val(UINT16 cmdVal) +{ + #if 1 + UIMenuStoreInfo *pCustomerParam = sf_app_ui_para_get(); + + pCustomerParam->ProfileEnableCmdVal = cmdVal; + //sf_set_param_save_flag(); + + SLOGD("set enable profile cmd:%d\n", pCustomerParam->ProfileEnableCmdVal); + #else + ProfileEnableCmdVal = cmdVal; + #endif +} + +UINT16 sf_sms_lpa_get_enable_profile_cmd_val(void) +{ + #if 1 + UIMenuStoreInfo *pCustomerParam = sf_app_ui_para_get(); + + SLOGD("get enable profile cmd:%d\n", pCustomerParam->ProfileEnableCmdVal); + + return pCustomerParam->ProfileEnableCmdVal; + #else + SLOGD("enable profile cmd:%d\n", ProfileEnableCmdVal); + + return ProfileEnableCmdVal; + #endif +} + +void sf_sms_lpa_clean_need_enable_iccid(void) +{ + memset(LpaProfileNeedEnableIccid, '\0', SF_SMS_LPA_ICCID_MAX_SIZE); +} + +SINT32 sf_sms_lpa_set_need_enable_iccid(const SINT8* iccid) +{ + if(iccid == NULL) + return SF_FAILURE; + + SF_STRNCPY(LpaProfileNeedEnableIccid, iccid, SF_SMS_LPA_ICCID_MAX_SIZE); + SLOGD("need enable profile:%s\n", LpaProfileNeedEnableIccid); + + return SF_SUCCESS; +} + +SINT32 sf_sms_lpa_get_need_enable_iccid(SINT8* iccid) +{ + if(iccid == NULL) + return SF_FAILURE; + + SF_STRNCPY(iccid, LpaProfileNeedEnableIccid, SF_SMS_LPA_ICCID_MAX_SIZE); + SLOGD("need enable profile:%s\n", LpaProfileNeedEnableIccid); + + return SF_SUCCESS; +} + +SF_BOOL sf_sms_lpa_is_need_enable_profile(void) +{ + if(LpaProfileNeedEnableIccid[0] == '\0') + return FALSE; + + return TRUE; +} + +void sf_sms_lpa_command_execute_thread(ULONG parm) +{ + SINT32 ret = 0; + SF_SMS_LPA_CMD_T *pLpaCmd = malloc(sizeof(SF_SMS_LPA_CMD_T)); + LPA_API_ERROR errCode = LPA_NO_ERROR; + SINT8 lpaProfileIccid[SF_SMS_LPA_ICCID_MAX_SIZE + 1] = {0}; + UINT8 i = 0; + + if(pLpaCmd != NULL) + { + memset(pLpaCmd, 0, sizeof(SF_SMS_LPA_CMD_T)); + while(sf_sms_lpa_cmd_list_item_get(pLpaCmd) == SF_SUCCESS) + { + if((pLpaCmd->CmdVal == SF_SMS_LPA_CMD_DOWNLOAD_PROFILE_2) || (pLpaCmd->CmdVal == SF_SMS_LPA_CMD_DOWNLOAD_ENABLE_PROFILE_2)) + { + sf_USB_net_init(); + + if(ret == SUCCESS) + { + errCode = sf_lpa_download_profile(pLpaCmd->Param3Buff); + + #if 0 //test + errCode = LPA_NO_ERROR; + sf_get_profile_iccid((UINT8 *)"TS48 CTS ECHO34_SAIP21", (UINT8 *)lpaProfileIccid); + sf_lpa_set_download_profile_iccid(lpaProfileIccid); + #endif + + if(errCode == LPA_NO_ERROR) + { + sf_lpa_profile_info_refresh(); + sf_lpa_get_download_profile_iccid(lpaProfileIccid); + sf_sms_lpa_delete_profile_info_item(lpaProfileIccid);//delete old profile info + sf_sms_lpa_save_profile_info_item(lpaProfileIccid, pLpaCmd->Param1Buff, pLpaCmd->Param3Buff); + + if(pLpaCmd->CmdVal == SF_SMS_LPA_CMD_DOWNLOAD_PROFILE_2) + { + sf_sms_lpa_command_log(pLpaCmd, SF_SMS_LPA_CMD_SUCCESS, errCode, SF_SMS_LPA_CMD_ERROR_SOURCE_OTHER); + } + + if(pLpaCmd->CmdVal == SF_SMS_LPA_CMD_DOWNLOAD_ENABLE_PROFILE_2) + { + sf_sms_lpa_set_need_enable_iccid(lpaProfileIccid); + sf_sms_lpa_save_enable_profile_cmd_val(pLpaCmd->CmdVal); + } + } + else + { + sf_sms_lpa_command_log(pLpaCmd, SF_SMS_LPA_CMD_FAIL, errCode, SF_SMS_LPA_CMD_ERROR_SOURCE_SMDP); + } + } + else + { + SLOGD("usb net init fail\n"); + sf_sms_lpa_command_log(pLpaCmd, SF_SMS_LPA_CMD_FAIL, SF_LPA_CUSTOM_ERROR_USBNET, SF_SMS_LPA_CMD_ERROR_SOURCE_OTHER); + } + + } + else if(pLpaCmd->CmdVal == SF_SMS_LPA_CMD_ENABLE_PROFILE) + { + /*Enable profile only after all work is completed*/ + sf_sms_lpa_set_need_enable_iccid(pLpaCmd->Param1Buff); + sf_sms_lpa_save_enable_profile_cmd_val(pLpaCmd->CmdVal); + } + else if((pLpaCmd->CmdVal == SF_SMS_LPA_CMD_DELETE_PROFILE) || (pLpaCmd->CmdVal == SF_SMS_LPA_CMD_DELETE_PROFILE_NITIFY)) + { + errCode = sf_lpa_delete_profile_from_iccid(pLpaCmd->Param1Buff); + + if(errCode == LPA_NO_ERROR) + { + sf_sms_lpa_delete_profile_info_item(pLpaCmd->Param1Buff); + sf_lpa_profile_info_refresh(); + + if(pLpaCmd->CmdVal == SF_SMS_LPA_CMD_DELETE_PROFILE) + { + sf_sms_lpa_command_log(pLpaCmd, SF_SMS_LPA_CMD_SUCCESS, errCode, SF_SMS_LPA_CMD_ERROR_SOURCE_OTHER); + } + } + else + { + sf_sms_lpa_command_log(pLpaCmd, SF_SMS_LPA_CMD_FAIL, errCode, SF_SMS_LPA_CMD_ERROR_SOURCE_ESIM); + } + + if(pLpaCmd->CmdVal == SF_SMS_LPA_CMD_DELETE_PROFILE_NITIFY) + { + sf_USB_net_init(); + + if(ret == SUCCESS) + { + errCode = sf_lpa_set_smdp_addr((const char*)pLpaCmd->Param2Buff); + if(errCode != LPA_NO_ERROR) + errCode = sf_lpa_set_smdp_addr((const char*)pLpaCmd->Param2Buff); + + if(errCode != LPA_NO_ERROR) + sf_sms_lpa_command_log(pLpaCmd, SF_SMS_LPA_CMD_FAIL, errCode, SF_SMS_LPA_CMD_ERROR_SOURCE_ESIM); + + for(i = 0; i < 5; i++) + { + errCode = sf_lpa_send_pending_notifications(); + + if(errCode == LPA_NO_ERROR) + break; + + sleep(2); + } + + if(errCode == LPA_NO_ERROR) + { + sf_sms_lpa_command_log(pLpaCmd, SF_SMS_LPA_CMD_SUCCESS, errCode, SF_SMS_LPA_CMD_ERROR_SOURCE_OTHER); + } + else + { + sf_sms_lpa_command_log(pLpaCmd, SF_SMS_LPA_CMD_FAIL, errCode, SF_SMS_LPA_CMD_ERROR_SOURCE_SMDP); + } + } + else + { + SLOGD("usb net init fail\n"); + sf_sms_lpa_command_log(pLpaCmd, SF_SMS_LPA_CMD_FAIL, SF_LPA_CUSTOM_ERROR_USBNET, SF_SMS_LPA_CMD_ERROR_SOURCE_OTHER); + } + } + } + } + } + else + { + //sf_sms_lpa_command_log(NULL, SF_SMS_LPA_CMD_FAIL, SF_LPA_CUSTOM_ERROR_MEMORY, SF_SMS_LPA_CMD_ERROR_SOURCE_OTHER); + SLOGD("memory error\n"); + } + + free(pLpaCmd); + //sf_sms_lpa_event_set(); + //sp5kOsThreadDelete(NULL); +} + + +/************************************************* + Function: sf_sms_lpa_command_handle + Description: + Input: + Output: N/A + Return: N/A + Others: N/A +*************************************************/ +void sf_sms_lpa_command_execute(void) +{ + sf_sms_lpa_command_execute_thread(0); + //sf_sms_lpa_event_flags_group_init(); + //pthread_create(&LpaCmdExcuteTask.TskId, NULL, sf_sms_lpa_command_execute_thread, (ULONG)0); + //sf_sms_lpa_event_get(TX_WAIT_FOREVER); + //sf_sms_lpa_event_flags_group_del(); +} + +void* sf_sms_lpa_command_enable_profile_handle_thread(ULONG parm) +{ + SINT8 lpaProfileIccid[SF_SMS_LPA_ICCID_MAX_SIZE + 1] = {0}; + SINT8 preEnableProfileIccid[SF_SMS_LPA_ICCID_MAX_SIZE + 1] = {0}; + LPA_API_ERROR errCode = LPA_NO_ERROR; + SF_SMS_LPA_CMD_T *lpaCmd = malloc(sizeof(SF_SMS_LPA_CMD_T)); + + if(lpaCmd == NULL) + { + goto SF_LPA_COMMAND_HANDLE_THREAD_END; + } + + memset(lpaCmd, '\0', sizeof(SF_SMS_LPA_CMD_T)); + lpaCmd->CmdVal = parm & 0xffff; + SLOGD("enable profile handle cmd:%d\n", lpaCmd->CmdVal); + + sf_sms_lpa_get_need_enable_iccid(lpaProfileIccid); + + if(lpaCmd->CmdVal == SF_SMS_LPA_CMD_DOWNLOAD_ENABLE_PROFILE_2) + { + sf_sms_lpa_get_profile_info_item(lpaProfileIccid, lpaCmd->Param1Buff, lpaCmd->Param2Buff); + } + else if(lpaCmd->CmdVal == SF_SMS_LPA_CMD_ENABLE_PROFILE) + { + SF_STRNCPY(lpaCmd->Param1Buff, lpaProfileIccid, SF_SMS_LPA_ICCID_MAX_SIZE); + } + else + { + SLOGD("cmd:%d ERROR\n", lpaCmd->CmdVal); + goto SF_LPA_COMMAND_HANDLE_THREAD_END; + } + + sf_lpa_get_active_profile_iccid(preEnableProfileIccid); + errCode = sf_lpa_enable_profile_from_iccid(lpaProfileIccid); + + if(errCode != LPA_NO_ERROR) + { + sf_sms_lpa_command_log(lpaCmd, SF_SMS_LPA_CMD_FAIL, errCode, SF_SMS_LPA_CMD_ERROR_SOURCE_ESIM); + sf_sms_lpa_set_profile_switch_reboot_flg(0); + } + else + { + sf_sms_lpa_save_pre_active_profile_iccid(preEnableProfileIccid); + //sf_sms_lpa_command_log(lpaCmd, SF_SMS_LPA_CMD_SUCCESS, errCode, SF_SMS_LPA_CMD_ERROR_SOURCE_ESIM); + sf_sms_lpa_set_profile_switch_reboot_flg(1); + } + +SF_LPA_COMMAND_HANDLE_THREAD_END: + if(lpaCmd) + { + free(lpaCmd); + } + + return NULL; +} + +/************************************************* + Function: sf_sms_lpa_command_enable_profile_handle + Description: + Input: + Output: N/A + Return: N/A + Others: N/A +*************************************************/ +void sf_sms_lpa_command_enable_profile_handle(UINT16 cmdVal) +{ + sf_sms_lpa_command_enable_profile_handle_thread(cmdVal); + //sf_sms_lpa_event_flags_group_init(); + //pthread_create(&LpaEnableTask.TskId, NULL, sf_sms_lpa_command_enable_profile_handle_thread, (ULONG)cmdVal); + //sf_sms_lpa_event_get(TX_WAIT_FOREVER); + //sf_sms_lpa_event_flags_group_del(); +} + +SINT32 sf_sms_lpa_load_profile_apn(const SINT8 *iccid, SINT8 *apn) +{ + SINT8 activationCode[SF_SMS_LPA_AC_MAX_SIZE + 1] = {0}; + UINT8 index = 0; + + if(sf_get_profile_active_index(&index) == SUCCESS) + { + if(index > 1) + { + sf_sms_lpa_get_profile_info_item(iccid, apn, activationCode); + + return SF_SUCCESS; + } + } + + return SF_FAILURE; +} + +SINT32 sf_sms_lpa_profile_rool_back(const SINT8 *iccid) +{ + LPA_API_ERROR errCode = LPA_NO_ERROR; + + if(iccid == NULL) + return SF_FAILURE; + + SLOGD("profile rool back\n"); + + errCode = sf_lpa_enable_profile_from_iccid(iccid); + + if(errCode != LPA_NO_ERROR) + { + //sf_sms_lpa_command_recombination_log(SF_SMS_LPA_CMD_FAIL, errCode); + sf_sms_lpa_set_profile_switch_reboot_flg(0); + return SF_FAILURE; + } + else + { + sf_lpa_profile_info_refresh(); + //sf_sms_lpa_command_recombination_log(SF_SMS_LPA_CMD_SUCCESS, errCode); + sf_sms_lpa_set_profile_switch_reboot_flg(1); + } + + return SF_SUCCESS; +} + +/************************************************* + Function: sf_sms_lpa_command_handle + Description: + Input: + Output: N/A + Return: N/A + Others: N/A +*************************************************/ +SINT32 sf_sms_lpa_command_handle(SF_SMS_LPA_CMD_T *pLpaCmd) +{ + UINT16 timeOut = 0; + SINT8 simEid[40] = {0}; + SINT8 hashSignature[SF_SMS_LPA_CMD_HASH_KEY_LENGTH * 2 + 1] = {0}; + SINT8 *lpaProfileHash = NULL; + + sf_sample_lpa_init( ); + timeOut = 60; + + while(!sf_is_esim_init_finish() && timeOut--) + { + sleep(1); + } + + if(!sf_is_esim_init_finish()) + { + /*need powe off*/ + SLOGD("esim init timeout\n"); + sf_sms_lpa_command_log(pLpaCmd, SF_SMS_LPA_CMD_FAIL, SF_LPA_CUSTOM_ERROR_LPA_ERROR, SF_SMS_LPA_CMD_ERROR_SOURCE_ESIM); + + return SF_FAILURE; + } + + if(!sf_is_esim_card()) + { + SLOGD("!esim card\n"); + sf_sms_lpa_command_log(pLpaCmd, SF_SMS_LPA_CMD_FAIL, SF_LPA_CUSTOM_ERROR_SIM_NOT_SUPPORTED, SF_SMS_LPA_CMD_ERROR_SOURCE_ESIM); + + return SF_FAILURE; + } + + if(sf_get_eid((UINT8 *)simEid) == FALSE) + { + SLOGD("get eid error\n"); + sf_sms_lpa_command_log(pLpaCmd, SF_SMS_LPA_CMD_FAIL, SF_LPA_CUSTOM_ERROR_SIM_EID, SF_SMS_LPA_CMD_ERROR_SOURCE_ESIM); + + return SF_FAILURE; + } + + sf_sms_lpa_hash_signature(simEid, (const SINT8 *)"Tact^$werew", hashSignature); + + if(pLpaCmd->CmdVal == SF_SMS_LPA_CMD_DELETE_PROFILE_NITIFY) + lpaProfileHash = pLpaCmd->Param3Buff; + else + lpaProfileHash = pLpaCmd->Param2Buff; + + if(SF_STRNCMP(lpaProfileHash, hashSignature, sizeof(hashSignature)) != 0) + { + SLOGD("hash check fail\n"); + sf_sms_lpa_command_log(pLpaCmd, SF_SMS_LPA_CMD_FAIL, SF_LPA_CUSTOM_ERROR_HASH, SF_SMS_LPA_CMD_ERROR_SOURCE_OTHER); + + return SF_FAILURE; + } + + if((pLpaCmd->CmdVal == SF_SMS_LPA_CMD_DOWNLOAD_PROFILE_2) || (pLpaCmd->CmdVal == SF_SMS_LPA_CMD_DOWNLOAD_ENABLE_PROFILE_2)) + { + sf_sms_lpa_save_download_profile_apn(pLpaCmd->CmdVal, pLpaCmd->Param1Buff); + + } + else + { + sf_sms_lpa_cmd_list_item_add(pLpaCmd); + } + + return SF_SUCCESS; +} + +SINT32 sf_sms_lpa_download_command_add_to_list(void) +{ + SF_SMS_LPA_CMD_T *pLpaCmd = NULL; + + pLpaCmd = malloc(sizeof(SF_SMS_LPA_CMD_T)); + + if(pLpaCmd == NULL) + { + return SF_FAILURE; + } + + SLOGD("download cmd add to list\n"); + memset(pLpaCmd, 0, sizeof(SF_SMS_LPA_CMD_T)); + sf_sms_lpa_load_download_profile_apn(SF_SMS_LPA_CMD_DOWNLOAD_PROFILE_2, pLpaCmd->Param1Buff); + sf_sms_lpa_load_download_profile_activation_code(SF_SMS_LPA_CMD_DOWNLOAD_PROFILE_1, pLpaCmd->Param3Buff); + SLOGD("load D ac:%s\n", pLpaCmd->Param3Buff); + + if((pLpaCmd->Param1Buff[0] != '\0') && (pLpaCmd->Param3Buff[0] != '\0')) + { + pLpaCmd->CmdVal = SF_SMS_LPA_CMD_DOWNLOAD_PROFILE_2; + sf_sms_lpa_cmd_list_item_add_to_head(pLpaCmd); + sf_sms_lpa_delete_download_profile_activation_code(SF_SMS_LPA_CMD_DOWNLOAD_PROFILE_1); + } + else if((pLpaCmd->Param1Buff[0] != '\0') && (pLpaCmd->Param3Buff[0] == '\0')) + { + pLpaCmd->CmdVal = SF_SMS_LPA_CMD_DOWNLOAD_PROFILE_2; + //sf_sms_lpa_command_log(pLpaCmd, SF_SMS_LPA_CMD_FAIL, SF_LPA_CUSTOM_ERROR_ACTIVATION_CODE, SF_SMS_LPA_CMD_ERROR_SOURCE_SMDP); + } + + memset(pLpaCmd, 0, sizeof(SF_SMS_LPA_CMD_T)); + sf_sms_lpa_load_download_profile_apn(SF_SMS_LPA_CMD_DOWNLOAD_ENABLE_PROFILE_2, pLpaCmd->Param1Buff); + sf_sms_lpa_load_download_profile_activation_code(SF_SMS_LPA_CMD_DOWNLOAD_ENABLE_PROFILE_1, pLpaCmd->Param3Buff); + SLOGD("load DE ac:%s\n", pLpaCmd->Param3Buff); + + if((pLpaCmd->Param1Buff[0] != '\0') && (pLpaCmd->Param3Buff[0] != '\0')) + { + pLpaCmd->CmdVal = SF_SMS_LPA_CMD_DOWNLOAD_ENABLE_PROFILE_2; + sf_sms_lpa_cmd_list_item_add_to_head(pLpaCmd); + sf_sms_lpa_delete_download_profile_activation_code(SF_SMS_LPA_CMD_DOWNLOAD_ENABLE_PROFILE_1); + } + else if((pLpaCmd->Param1Buff[0] != '\0') && (pLpaCmd->Param3Buff[0] == '\0')) + { + pLpaCmd->CmdVal = SF_SMS_LPA_CMD_DOWNLOAD_ENABLE_PROFILE_2; + //sf_sms_lpa_command_log(pLpaCmd, SF_SMS_LPA_CMD_FAIL, SF_LPA_CUSTOM_ERROR_ACTIVATION_CODE, SF_SMS_LPA_CMD_ERROR_SOURCE_SMDP); + } + + free(pLpaCmd); + + return SF_SUCCESS; +} + + + +void sf_sms_lpa_cmd_test(UINT8 *sms) +{ + UINT8 *lpaCmdStr = NULL; + SF_SMS_LPA_CMD_T *pLpaCmd = NULL; + + lpaCmdStr = SF_STRSTR(sms, "$R0e*"); + + if(lpaCmdStr != NULL) + { + pLpaCmd = malloc(sizeof(SF_SMS_LPA_CMD_T)); + memset(pLpaCmd, 0, sizeof(SF_SMS_LPA_CMD_T)); + + if(pLpaCmd != NULL) + { + if(sf_sms_lpa_command_info_extract((SINT8 *)lpaCmdStr, &pLpaCmd->CmdVal, pLpaCmd->Param1Buff, pLpaCmd->Param2Buff, pLpaCmd->Param3Buff) == SF_SUCCESS) + { + if((pLpaCmd->CmdVal == SF_SMS_LPA_CMD_DOWNLOAD_PROFILE_1) || (pLpaCmd->CmdVal == SF_SMS_LPA_CMD_DOWNLOAD_ENABLE_PROFILE_1)) + { + sf_sms_lpa_save_download_profile_activation_code(pLpaCmd->CmdVal, pLpaCmd->Param1Buff); + //sf_sms_lpa_command_log(pLpaCmd, SF_SMS_LPA_CMD_SUCCESS, LPA_NO_ERROR, SF_SMS_LPA_CMD_ERROR_SOURCE_OTHER); + } + else if((pLpaCmd->CmdVal == SF_SMS_LPA_CMD_DOWNLOAD_PROFILE_2) || (pLpaCmd->CmdVal == SF_SMS_LPA_CMD_DOWNLOAD_ENABLE_PROFILE_2)) + { + sf_sms_lpa_command_handle(pLpaCmd); + } + else if(pLpaCmd->CmdVal == SF_SMS_LPA_CMD_ENABLE_PROFILE) + { + sf_sms_lpa_command_handle(pLpaCmd); + //sf_sms_lpa_command_enable_profile_handle(sf_sms_lpa_get_enable_profile_cmd_val()); + } + else if((pLpaCmd->CmdVal == SF_SMS_LPA_CMD_DELETE_PROFILE) || (pLpaCmd->CmdVal == SF_SMS_LPA_CMD_DELETE_PROFILE_NITIFY)) + { + sf_sms_lpa_command_handle(pLpaCmd); + } + else + { + /*cmd prase fail,need send lpa log*/ + //sf_sms_lpa_command_log(pLpaCmd, SF_SMS_LPA_CMD_FAIL, SF_LPA_CUSTOM_ERROR_CMD_UNKNOWN, SF_SMS_LPA_CMD_ERROR_SOURCE_OTHER); + printf("Error Parameter line:%d\n", __LINE__); + } + } + else + { + /*cmd prase fail,need send lpa log*/ + //sf_sms_lpa_command_log(NULL, SF_SMS_LPA_CMD_FAIL, SF_LPA_CUSTOM_ERROR_CMD_UNKNOWN, SF_SMS_LPA_CMD_ERROR_SOURCE_OTHER); + printf("Error Format line:%d\n", __LINE__); + } + + free(pLpaCmd); + } + else + { + /*cmd prase fail,need send lpa log*/ + //sf_sms_lpa_command_log(NULL, SF_SMS_LPA_CMD_FAIL, SF_LPA_CUSTOM_ERROR_MEMORY, SF_SMS_LPA_CMD_ERROR_SOURCE_OTHER); + printf("Error Memory line:%d\n", __LINE__); + } + } + else + { + /*cmd prase fail,need send lpa log*/ + //sf_sms_lpa_command_log(NULL, SF_SMS_LPA_CMD_FAIL, SF_LPA_CUSTOM_ERROR_CMD_UNKNOWN, SF_SMS_LPA_CMD_ERROR_SOURCE_OTHER); + printf("Error Format line:%d\n", __LINE__); + } +} + + +void sf_sms_lpa_cmd_enable_test(void) +{ + if(sf_sms_lpa_is_need_enable_profile()) + { + sf_sms_lpa_command_enable_profile_handle(sf_sms_lpa_get_enable_profile_cmd_val()); + sf_sms_lpa_clean_need_enable_iccid(); + + if(!sf_sms_lpa_is_need_profile_switch_reboot() && sf_sms_lpa_is_need_send_lpa_log()) + { + sf_sms_lpa_set_send_lpa_log_flg(FALSE); + printf("enter send LPA LOG\n"); + } + } +} + + diff --git a/code/application/source/sf_app/code/source/4gMng/sf_4g_lpa.c b/code/application/source/sf_app/code/source/4gMng/sf_4g_lpa.c new file mode 100755 index 000000000..53edf9ab3 --- /dev/null +++ b/code/application/source/sf_app/code/source/4gMng/sf_4g_lpa.c @@ -0,0 +1,3395 @@ + /* +* Copyright 2018-2020 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform : Window, Linux. +* Language : C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of THALES and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + + +//#define SAMPLE__GENERIC_MODEM +//#define SAMPLE__MODEM_PORT "/dev/ttyUSB0" //Cinterion EHS8 +//#define SAMPLE__MODEM_PORT "/dev/ttyACM1" //Cinterion PLS83-W +//#define SAMPLE__MODEM_PORT "/dev/ttyACM2" //Cinterion PLS83-EP + +//#define SAMPLE__USE_MODEM_CONNECTIVITY + + +#include +#include +#if !SIFAR_PLATFORM_ICATCH +#include +#include +#endif +#include "sf_log.h" +#include "sf_4g_lpa.h" +#include "sf_common.h" +#include "sf_wifi_svr.h" +#include "sf_data_transfer.h" +#include "lpasdk/api/semedia/semedia.h" +#include "lpasdk/api/lpasdk_api.h" +#include "sf_eg91_sim.h" +#include "sf_4G_sms_lpa_cmd.h" +#include "sf_param_struct.h" +#include "sf_service.h" +#include "sf_ledmng.h" +#include "sf_commu_mcu_reg.h" + + + + +#ifdef SAMPLE__GENERIC_MODEM + +#if !SIFAR_PLATFORM_ICATCH +#include +#include +#include +#include +#endif + + +static int fd; + +bool Modem_OpenAndConfigurePort() +{ +#if !SIFAR_PLATFORM_ICATCH + struct termios options; + + // Open port + fd = open(SAMPLE__MODEM_PORT, O_RDWR | O_NOCTTY | O_NDELAY); + + //printf("Opening serial port - fd=%d \n",fd); + if (fd < 0) + { + //printf("Error opening serial port\n"); + return(false); + } + + // Configure port + //printf("Configuring options..."); + bzero(&options, sizeof(options)); + options.c_cflag = B115200 | CS8 | CLOCAL | CREAD ; + tcflush(fd, TCIFLUSH); + tcsetattr(fd, TCSANOW, &options); + //printf("done\n\n"); +#endif + return(true); +} + +void Modem_WaitForModemIsDetected() +{ +#if !SIFAR_PLATFORM_ICATCH + bool ModemIsDetected; + const long sleep_duration = 500000; // 500ms + int timeout = 40; // => timeout = 20s + + printf("\nWait for modem detection on \"%s\"\n",SAMPLE__MODEM_PORT); + + //Open and configure port - will have to be closed + ModemIsDetected = Modem_OpenAndConfigurePort(); + + while( ModemIsDetected == false && timeout>0) + { + usleep(sleep_duration); + printf(".\n"); + ModemIsDetected = Modem_OpenAndConfigurePort(); + timeout--; + } + + if(ModemIsDetected == false) + { + printf("\nModem detection on \"%s\" has failed.\n",SAMPLE__MODEM_PORT); + exit (1); + } + + printf("Modem has been detected.\n"); + + // Close port + close(fd); +#endif +} + +#if SIFAR_PLATFORM_ICATCH +static unsigned char GsmPara[SF_4G_UART_BUFF_SIZE] = {0}; +void Modem_SendAT(unsigned char* at_cmd, unsigned char* at_resp) +{ + SINT32 ttyRet = 0; + int timeout = 200; // => timeout = 10s + int nbLoops = timeout; + + sf_4g_data_buff_clear(); + ttyRet = sf_4g_send_data(at_cmd, strlen((const char *)at_cmd)); + + if (0 > ttyRet) + { + printf("[%s:%d]error:%x%x\n",__FUNCTION__,__LINE__, ttyRet); + return; + } + + while (strstr(GsmPara, "OK") == NULL && strstr(GsmPara, "ERROR") == NULL && timeout>0) + { + sf_4g_get_data(GsmPara, 200, 0); + timeout--; + } + + nbLoops -= timeout; + printf("Received from modem after %d waiting loop(s):\n----------\n%s\n----------\n",nbLoops,GsmPara); + strcpy(at_resp,GsmPara); +} +#else +void Modem_SendAT(unsigned char* at_cmd, unsigned char* at_resp) +{ + unsigned char recv[1000]; + const long sleep_duration = 50000; // 50ms + int timeout = 200; // => timeout = 10s + + printf("AT command: %s\n",at_cmd); + + at_resp[0]='\0'; + + // Send AT command + if (write(fd, at_cmd, strlen(at_cmd)) < strlen(at_cmd)) + { + printf("Write error - %s \n", strerror(errno)); + return; + } + + // Retrieve AT command response + recv[0]='\0'; + int nbNewReceivedChars=0; + int nbTotalReceivedChars=0; + int nbLoops = timeout; + while (strstr(recv,"\nOK") == NULL && strstr(recv,"ERROR") == NULL && timeout>0) + { + usleep(sleep_duration); + nbNewReceivedChars = read(fd,recv+nbTotalReceivedChars,sizeof(recv)-nbTotalReceivedChars); + if(nbNewReceivedChars>0) + { + nbTotalReceivedChars += nbNewReceivedChars; + } + recv[nbTotalReceivedChars]='\0'; + timeout--; + } + + nbLoops -= timeout; + printf("Received from modem after %d waiting loop(s):\n----------\n%s\n----------\n",nbLoops,recv); + + strcpy(at_resp,recv); +} +#endif + +void Modem_GetProductIdentificationInformation(unsigned char* ProductIdInfo) +{ + unsigned char *ATcommand="ATI\r"; + + //Open and configure port - will have to be closed + if( Modem_OpenAndConfigurePort() == false) + { + ProductIdInfo[0]='\0'; + return; + } + + Modem_SendAT(ATcommand,ProductIdInfo); + + +#if SIFAR_PLATFORM_ICATCH + if(strstr(ProductIdInfo,"OK") == NULL) + ProductIdInfo[0]='\0'; +#else + // Close port + close(fd); + // Erase response if OK is not received + if(strstr(ProductIdInfo,"\nOK") == NULL) ProductIdInfo[0]='\0'; +#endif +} + + +void Modem_WaitForModemReady_AT() +{ +#if !SIFAR_PLATFORM_ICATCH + unsigned char ATcommandExecution[250]; + const char* ATresultReady="OK"; + const long sleep_duration = 500000; // 500ms + int timeout = 20; // => timeout = 10s + + printf("\nWait for modem to be ready (try to get result from AT command)...\n"); + + Modem_GetProductIdentificationInformation(ATcommandExecution); + + while (strstr(ATcommandExecution,ATresultReady) == NULL && timeout>0) + { + usleep(sleep_duration); + Modem_GetProductIdentificationInformation(ATcommandExecution); + timeout--; + } + + printf("Wait 3s more...\n"); + usleep(3000000); + printf("3s!\n"); +#endif +} + +bool SampleLPA_GetEID(UINT8 *eidStr); + + +void Modem_WaitForModemReady_EID() +{ + LPA_GET_EID getEID; + bool res; + const long sleep_duration = 500000; // 500ms + int timeout = 20; // => timeout = 10s + + printf("\nWait for modem to be ready (try to get EID)...\n"); + + res = SampleLPA_GetEID(SimEid); + + while (res == false && timeout>0) + { +#if SIFAR_PLATFORM_ICATCH + sp5kTimeDelay(SP5K_TIME_DELAY_1US , sleep_duration); +#else + usleep(sleep_duration); +#endif + res = SampleLPA_GetEID(SimEid); + timeout--; + } + + printf("Wait 3s more...\n"); +#if SIFAR_PLATFORM_ICATCH + sp5kTimeDelay(SP5K_TIME_DELAY_1US , 3000000); +#else + usleep(3000000); +#endif + printf("3s!\n"); + +} + + +void Modem_SendAPDU(unsigned char* apdu_cmd, unsigned char* apdu_resp) +{ + unsigned char ATcommand[1000]; + unsigned char recv[3500]; + char apdu_length[4]; + const long sleep_duration = 50000; // 50ms + int timeout = 200; // => timeout = 10s + + // Change APDU into AT command (AT+CSIM) + // AT+CSIM=apdu_length,"apdu_cmd"\r + sprintf(apdu_length, "%d", strlen(apdu_cmd)); // int to str conversion + strcpy(ATcommand, "AT+CSIM="); // add AT+CSIM prefix + strcat(ATcommand, apdu_length); // add apdu command length + strcat(ATcommand, ",\""); // add comma and opening quote + strcat(ATcommand, apdu_cmd); // add apdu command + strcat(ATcommand, "\"\r"); // add closing quote and CR + + Modem_SendAT(ATcommand,recv); + + // Extract APDU response + apdu_resp[0]='\0'; + if(strstr(recv,"\nOK")) + { + unsigned char* response_part = strstr(recv, "\n+CSIM:"); + unsigned char* first_quote = strstr(response_part, "\""); + unsigned char* first_char = first_quote+1; + unsigned char* second_quote = strstr(first_char, "\""); + if(second_quote != NULL) + { + second_quote[0] = '\0'; + strcpy(apdu_resp,first_char); + } + } +} + +#endif //SAMPLE__GENERIC_MODEM + +#if SF_LPA_SDK +#define SCANF_MAX_LEN 20 +#define SCANF_MAX_ARGC 10 +static UINT8 ScanfStr[SCANF_MAX_ARGC][SCANF_MAX_LEN] = {{0}}; +static UINT32 ScanfVal[SCANF_MAX_ARGC] = {0}; + +static UINT32 IsEsimFlag = TRUE; +static UINT32 EsimInitFinish = FALSE; +static UINT8 SimEid[40] = {0}; +static SINT32 WifiSocket=0; +static UINT8 DownLoadProfileIccid[2*LPA_PROFILE_ICCID_BUFFER_MAX_SIZE+1] = {0}; +static UINT8 WifiCurrentCmd=0; + +LPA_GET_PROFILES_INFO getProfilesInfo; +LPA_PROFILE_INFO *ProfileData = NULL; +LPA_PROFILE_INFO ProfileActive; + +void sf_set_wifi_socket(int fd) +{ + WifiSocket = fd; +} + +int sf_get_wifi_socket(void) +{ + return WifiSocket; +} + +void sf_set_wifi_cmd(UINT8 cmd) +{ + WifiCurrentCmd = cmd; +} + +UINT8 sf_get_wifi_cmd() +{ + return WifiCurrentCmd; +} + +void sf_scanf(UINT8 num, UINT8 *buff) +{ + if (num >= SCANF_MAX_ARGC) + return; + + while(ScanfStr[num][0] == '\0') + { +#if 0 + if(!sf_is_esim_init_finish()) + { + *buff = 'X'; + return; + } + else + { + usleep(100*1000); + } +#endif + usleep(100*1000); + } + + memcpy(buff, &ScanfStr[num][0], SCANF_MAX_LEN); + memset(&ScanfStr[num][0], '\0', SCANF_MAX_LEN); +} + + +char sf_getchar(void) +{ + char c = 0; + + while(ScanfStr[0][0] == '\0') + { + usleep(100*1000); + } + + c = (char)ScanfStr[0][0]; + + return c; +} +#endif + +SINT32 sf_lpa_set_download_profile_iccid(SINT8* iccid) +{ + if(iccid == NULL) + { + memset(DownLoadProfileIccid, '\0', 2*LPA_PROFILE_ICCID_BUFFER_MAX_SIZE); + } + else + { + SF_STRNCPY(DownLoadProfileIccid, iccid, 2*LPA_PROFILE_ICCID_BUFFER_MAX_SIZE); + } + + printf("download profile iccid:%s\n", iccid); + + return SF_SUCCESS; +} + + + +#ifdef SAMPLE__USE_MODEM_CONNECTIVITY +bool cellularAutoConnect = false; + +void External_ConnectCellular() +{ + system("sh connectCellular.sh"); +} + +void External_DisconnectCellular() +{ + system("sh disconnectCellular.sh"); +} + +void ToggleCellularAutoConnect() +{ + if(cellularAutoConnect==true) + { + cellularAutoConnect=false; + } + else + { + cellularAutoConnect=true; + } +} +#endif //SAMPLE__USE_MODEM_CONNECTIVITY + +void SampleLPA_GetIccidStr(unsigned char* IccidStr, unsigned char* ProfileIdByteArray, size_t ProfileIdByteArraySize) +{ + unsigned char digit_left; + unsigned char digit_right; + size_t indexByte; + + for (indexByte = 0; indexByte < ProfileIdByteArraySize; indexByte ++) + { + digit_left = (ProfileIdByteArray[indexByte] & 0xF0)>>4; + digit_right = (ProfileIdByteArray[indexByte] & 0x0F); + IccidStr[2*indexByte] = digit_right == 0x0F ? 'F' : '0' + digit_right; + IccidStr[2*indexByte+1] = digit_left == 0x0F ? 'F' : '0' + digit_left; + } + IccidStr[2*indexByte]='\0'; +} + +bool SampleLPA_Initialize() +{ + char ExePath[100]; + bool res; + +#if SIFAR_PLATFORM_ICATCH + sprintf(ExePath, "%s", SF_LPA_FOLDER); + printf("=> Execute lpaInitialize...\n"); + res=lpaInitialize(ExePath); + printf("=> Result for lpaInitialize is \"%s\"\n", (res ? "true" : "false")); +#else + char InputPath[100]; + char OutputPath[100]; + DIR *rep_in; + DIR *rep_out; + bool UseInitWithInOutFolders; + + if( getcwd(ExePath,100) == NULL ) + { + return(false); + } + + ExePath[0]='/'; + strcpy(InputPath, ExePath); + strcat(InputPath, INPUT_SUBFOLDER); + strcpy(OutputPath, ExePath); + strcat(OutputPath, OUTPUT_SUBFOLDER); + + printf("ExePath = %s \n",ExePath); + + UseInitWithInOutFolders = true; + + rep_in = opendir(InputPath); + if(rep_in) + { + printf("InputPath \"%s\" exists\n",InputPath); + closedir(rep_in); + } + else + { + printf("InputPath \"%s\" does not exist\n",InputPath); + UseInitWithInOutFolders = false; + } + + rep_out = opendir(OutputPath); + if(rep_out) + { + printf("OutputPath \"%s\" exists\n",OutputPath); + closedir(rep_out); + } + else + { + printf("OutputPath \"%s\" does not exist\n",OutputPath); + UseInitWithInOutFolders = false; + } + + if(UseInitWithInOutFolders == true) + { + printf("=> Execute lpaInitializeWithInputOutputFolder...\n"); + res = lpaInitializeWithInputOutputFolder(InputPath,OutputPath); + printf("=> Result for lpaInitializeWithInputOutputFolder is \"%s\"\n", (res ? "true" : "false")); + } + else + { + printf("=> Execute lpaInitialize...\n"); + res=lpaInitialize(ExePath); + printf("=> Result for lpaInitialize is \"%s\"\n", (res ? "true" : "false")); + } +#endif + if (lpaIsInitialized()) + { + printf("=> LPA SDK module is initialized\n\n"); + } + else + { + printf("=> LPA SDK module is not initialized\n\n"); + } + + return(res); +} + +void SampleLPA_GetAndSetReader() +{ + size_t index = 0; + size_t countReader = 0; + LPA_SE_MEDIA_READER_NAME_INFO readerInfo[16]; + + bool res = lpaGetReaderList( readerInfo, 16, &countReader); + printf("lpaGetReaderList API returned %s\n", (res ? "true" : "false")); + if (res) + { + if (countReader > 0) + { + printf(" <%d> reader(s) detected : \n", countReader); + for (index = 0; index < countReader; index ++) + { + printf(" - \"%s\"\n", readerInfo[index].readerName); + lpaSetConfigParameter("readerName",LPA_PARAMETER_TYPE_STRING,readerInfo[index].readerName); + } + + // The reader has been set to the last enumerated one. + + #ifdef SAMPLE__GENERIC_MODEM + // Force readerName to the value SAMPLE__MODEM_PORT, that is defined in this sample: + lpaSetConfigParameter("readerName",LPA_PARAMETER_TYPE_STRING,SAMPLE__MODEM_PORT); + #endif //SAMPLE__GENERIC_MODEM + + // Now readerInfo[0].readerName is used for reading the reader name that has been set: + if( lpaGetConfigParameter("readerName",LPA_PARAMETER_TYPE_STRING,readerInfo[0].readerName,LPA_CFG_READER_NAME_MAX_SIZE) ) + { + printf("\nReader is set to: \"%s\"\n\n",readerInfo[0].readerName); + } + else + { + printf("\nError while retrieving parameter \"readerName\"\n\n"); + } + } + else + printf(" No reader detected\n\n"); + } + else + { + printf("=> Error code: %s\n", lpaGetErrorCodeDescription(lpaGetErrorCode())); + } +} + + +bool SampleLPA_GetEID(UINT8 *eidStr) + { + size_t index = 0; + LPA_GET_EID getEID; + UINT8 str[4] = {0}; + + bool res = lpaGetEID(&getEID); + printf("lpaGetEID API returned %s\n", (res ? "true" : "false")); + + if(eidStr== NULL) + return FALSE; + + if(res) + { + memset(eidStr, 0, 20); + + for (index = 0; index < getEID.EID_DataSize; index ++) + { + SF_SPRINTF(str, "%02X", getEID.EID_Data[index]); + SF_STRCAT(eidStr, (const char *)str); + } + + printf(" EID = %s\n", eidStr); + } + else + { + printf("=> Error code: %s\n", lpaGetErrorCodeDescription(lpaGetErrorCode())); + } + + return(res); + } + + + +bool SampleLPA_GetEUICCInfo() +{ + size_t index = 0; + LPA_GET_EUICC_INFO getEUICCInfo; + bool res = lpaGetEUICCInfo(&getEUICCInfo); + printf("lpaGetEUICCInfo API returned %s\n", (res ? "true" : "false")); + if(res) + { + printf(" EUICCInfo2 = "); + for (index = 0; index < getEUICCInfo.EUICC_Info_DataSize; index ++) + { + printf("%02X",getEUICCInfo.EUICC_Info_Data[index]); + } + printf("\n"); + } + else + { + printf("=> Error code: %s\n", lpaGetErrorCodeDescription(lpaGetErrorCode())); + } + return(res); +} + + +void SampleLPA_GetSMDPAddress() +{ + size_t index = 0; + ADDRESS_DATA AddressData; + bool res = lpaGetSMDPAddress(&AddressData); + printf("lpaGetSMDPAddress API returned %s\n", (res ? "true" : "false")); + if(res) + { + printf(" SMDP Address (hex) = "); + for (index = 0; index < AddressData.address_DataSize; index ++) + { + printf("%02X",AddressData.address_Data[index]); + } + + printf("\n"); + AddressData.address_Data[AddressData.address_DataSize]='\0'; + printf(" SMDP address from eUICC = %s\n",AddressData.address_Data); + } + else + { + printf("=> Error code: %s\n", lpaGetErrorCodeDescription(lpaGetErrorCode())); + } +} + + +void SampleLPA_GetSMDSAddress() +{ + size_t index = 0; + ADDRESS_DATA AddressData; + bool res = lpaGetSMDSAddress(&AddressData); + printf("lpaGetSMDSAddress API returned %s\n", (res ? "true" : "false")); + if(res) + { + printf(" SMDS Address (hex) = "); + for (index = 0; index < AddressData.address_DataSize; index ++) + { + printf("%02X",AddressData.address_Data[index]); + } + printf("\n"); + AddressData.address_Data[AddressData.address_DataSize]='\0'; + printf(" SMDS address from eUICC = %s\n",AddressData.address_Data); + } + else + { + printf("=> Error code: %s\n", lpaGetErrorCodeDescription(lpaGetErrorCode())); + } +} + +void SampleLPA_DisplayUsedAddresse(bool requestedAddress) +{ + bool res1; + bool res2; + char deviceAddress[LPA_SMDP_ADDRESS_SIZE]; + //char eUICCAddress[LPA_SMDP_ADDRESS_SIZE]; + char usedAddress[LPA_SMDP_ADDRESS_SIZE]; + bool fromConfigParam; + ADDRESS_DATA AddressData; + + if(requestedAddress == REQUEST_SMDS_ADDRESS) + { + res1 = lpaGetConfigParameter("deviceSMDSAddress",LPA_PARAMETER_TYPE_STRING,deviceAddress,LPA_SMDP_ADDRESS_SIZE); + res2 = lpaGetSMDSAddress(&AddressData); + } + else + { + res1 = lpaGetConfigParameter("deviceDefaultSMDPAddress",LPA_PARAMETER_TYPE_STRING,deviceAddress,LPA_SMDP_ADDRESS_SIZE); + res2 = lpaGetSMDPAddress(&AddressData); + } + + if (res1 == true && res2 == true) + { + if(strcmp(deviceAddress,"") == 0) + { + //Here, the configuration parameter is an empty string, then the used address is the one from the eUICC + AddressData.address_Data[AddressData.address_DataSize]='\0'; + strcpy(usedAddress,AddressData.address_Data); + fromConfigParam = false; + } + else + { + //Here, the configuration parameter is not an empty string, then it is used as server address + strcpy(usedAddress,deviceAddress); + fromConfigParam = true; + } + + printf("Used address = \"%s\" (%s)\n",usedAddress,fromConfigParam ? "from configuration parameter" : "from eUICC"); + } + else + { + printf("Error occured while estimating used address. Error code: %s\n", lpaGetErrorCodeDescription(lpaGetErrorCode())); + } +} + +void SampleLPA_SetCurlParameters() +{ + bool res; + bool ParamValue=false; + printf("Setting CURL_SSL_VERIFYPEER to false (this operation is supposed to fail when SDK is not built with LPA_SDK__USING_EX_API option)...\n"); + res = lpaSetConfigParameter("CURL_SSL_VERIFYPEER",LPA_PARAMETER_TYPE_BOOL,&ParamValue); + printf(" Operation %s \n", (res ? "is successful:" : "has failed.")); + res = lpaGetConfigParameter("CURL_SSL_VERIFYPEER",LPA_PARAMETER_TYPE_BOOL,&ParamValue,1); + if(res) printf(" CURL_SSL_VERIFYPEER set to %s\n", (ParamValue ? "true" : "false")); +} + +void SampleLPA_SetParameter_CertPath(char *ParamValue) +{ +#if 1 + // Instead of setting the CA certificate path in the LPA, it is actually advised to install the CA certificates in the certificates store + // On Linux we are completing /etc/ssl/certs/ca-certificates.crt with the content of both GSMA_CE_TEST_CI.crt and GSMA_CE_LIVE_CI.crt + printf("\nPlease ensure the CA certificates (GSMA_CE_LIVE_CI, GSMA_CE_TEST_CI,...) are installed.\n"); + printf("On Debian/Ubuntu, this could consist in :\n"); + printf("\t1.Copying the .crt files in /usr/local/share/ca-certificates/\n"); + printf("\t2.Executing update-ca-certificates -f\n\n"); + + + bool res; + + printf("Setting CertPath to %s...\n",ParamValue); + res = lpaSetConfigParameter("CertPath",LPA_PARAMETER_TYPE_STRING,ParamValue); + printf(" Operation %s \n", (res ? "is successful:" : "has failed.")); + + res= lpaGetConfigParameter("CertPath",LPA_PARAMETER_TYPE_STRING,ParamValue,100); + if(res) printf(" CertPath set to \"%s\"\n\n", ParamValue); +#endif +} + + + + +void SampleLPA_SetParameter_deviceInfoTlv() +{ + bool res; + char ParamValue[132] = { 0 }; + strcpy(ParamValue,"A13F800411223344A12D800302000081030000008203000000830300000084030000008503000000860300000087030000008803020000820835374589362765F6"); + printf("Setting deviceInfoTlv to %s...\n",ParamValue); + res = lpaSetConfigParameter("deviceInfoTlv",LPA_PARAMETER_TYPE_STRING,ParamValue); + printf(" Operation %s \n", (res ? "is successful:" : "has failed.")); + res= lpaGetConfigParameter("deviceInfoTlv",LPA_PARAMETER_TYPE_STRING,ParamValue,131); + if(res) printf(" deviceInfoTlv set to %s\n", ParamValue); +} + +void SampleLPA_SetRefreshParameter(bool inputParamValue) +{ + bool res; + bool ParamValue; + res = lpaGetConfigParameter("profileRefreshFlag",LPA_PARAMETER_TYPE_BOOL,&ParamValue,1); + if(res) printf("profileRefreshFlag is currently set to %s\n", (ParamValue ? "true" : "false")); + printf("Setting profileRefreshFlag to %s...\n",(inputParamValue ? "true" : "false")); + res = lpaSetConfigParameter("profileRefreshFlag",LPA_PARAMETER_TYPE_BOOL,&inputParamValue); + printf(" Operation %s \n", (res ? "is successful:" : "has failed.")); + res = lpaGetConfigParameter("profileRefreshFlag",LPA_PARAMETER_TYPE_BOOL,&ParamValue,1); + if(res) printf(" profileRefreshFlag set to %s\n", (ParamValue ? "true" : "false")); +} + + +void lpaEventValueNotificationFunction(const void * ptrAppParameter, size_t eventType, size_t valueMin, size_t currentValue, size_t valueMax) +{ + printf("Evt progress value = %u %u %u %u\n",eventType,valueMin,currentValue,valueMax); +} + +void lpaEventTextNotificationFunction(const void * ptrAppParameter, size_t eventType, const char* ptrText) +{ + if(ptrText != NULL) + printf("Evt progress text = %s\n",ptrText); +} + +void lpaEventExecutionErrorNotificationFunction(const void* ptrAppParameter, const LPA_EVENT_EXECUTION_ERROR_INFO* ptrEventExecutionErrorInfo) +{ + printf("Execution error:\n"); + //printf("\t executionErrorType: %d\n",ptrEventExecutionErrorInfo->executionErrorType); + printf("\t Error type: "); + switch(ptrEventExecutionErrorInfo->executionErrorType) + { + case LPA_EVENT_EXECUTION_SERVER_ERROR_TYPE: + printf("Error sent by server\n"); + break; + case LPA_EVENT_EXECUTION_HTTP_ERROR_TYPE: + printf("HTTP error during communication with server\n"); + break; + case LPA_EVENT_EXECUTION_CURL_ERROR_TYPE: + printf("Curl error\n"); + break; + case LPA_EVENT_EXECUTION_SEMEDIA_DRIVER_ERROR_TYPE: + printf("SEMEDIA_DRIVER error\n"); + break; + } + //printf("\t detailErrorMask: 0x%04X\n",ptrEventExecutionErrorInfo->detailErrorMask); + if(ptrEventExecutionErrorInfo->detailErrorMask & LPA_EVENT_EXECUTION_ERROR_SUBJECT_CODE_MASK) + printf("\t Error Subject Code: %s\n",ptrEventExecutionErrorInfo->ptrErrorSubjectCode); + if(ptrEventExecutionErrorInfo->detailErrorMask & LPA_EVENT_EXECUTION_ERROR_REASON_CODE_MASK) + printf("\t Error Reason Code: %s\n",ptrEventExecutionErrorInfo->ptrErrorReasonCode); + if(ptrEventExecutionErrorInfo->detailErrorMask & LPA_EVENT_EXECUTION_ERROR_EXTRA_INFO_MASK) + printf("\t Error Extra Info: %s\n",ptrEventExecutionErrorInfo->ptrErrorExtraInfo); +} + +bool lpaEventRequestConfirmationCodeFunction(const void * ptrAppParameter, LPA_REQUEST_CONFIRMATION_CODE* ptrRequestConfirmationCode) +{ + printf("\n\tThis is the lpaEventCallback._lpaEventRequestConfirmationCode function!\n"); + printf("\tPlease enter confirmation code : "); + +#if !SIFAR_PLATFORM_ICATCH + scanf("%s",ptrRequestConfirmationCode->confirmationCode); +#else + sf_scanf(0, (UINT8 *)ptrRequestConfirmationCode->confirmationCode); +#endif + //printf("\n\tRecorded confirmation code is : "); + //for (size_t index = 0; index < LPA_CONFIRMATION_CODE_MAX_SIZE ; index++) + // printf("0x%02X ",ptrRequestConfirmationCode->confirmationCode[index]); + printf("\n\tRecorded confirmation code is : \"%s\"",ptrRequestConfirmationCode->confirmationCode); + printf("\n\n"); + if(ptrRequestConfirmationCode->confirmationCode[0] == 0x00) ptrRequestConfirmationCode->reasonCodeNoCC = LPA_CANCEL_SESSION_POSTPONED; + return(true); +} + +bool lpaEventRequestUserConsentFunction(const void * ptrAppParameter, LPA_REQUEST_USER_CONSENT_FOR_LOADING_PROFILE* ptrRequestUserConsentForLoadingProfile) +{ + //int trials = 5; + char choice; + + printf("\n\tThis is the lpaEventCallback._lpaEventRequestUserConsentForLoadingProfile function!\n"); + if(ptrRequestUserConsentForLoadingProfile->userCallBackType == LPA_USR_CONSENT_NO_PPR) + { + printf("\tUser consent is LPA_USR_CONSENT_NO_PPR\n"); + } + else + { + if((ptrRequestUserConsentForLoadingProfile->userCallBackType & LPA_USR_CONSENT_PPR1) == LPA_USR_CONSENT_PPR1) + printf("\tUser consent: LPA_USR_CONSENT_PPR1\n"); + if((ptrRequestUserConsentForLoadingProfile->userCallBackType & LPA_USR_CONSENT_PPR2) == LPA_USR_CONSENT_PPR2) + printf("\tUser consent: LPA_USR_CONSENT_PPR2\n"); + if((ptrRequestUserConsentForLoadingProfile->userCallBackType & LPA_USR_CONSENT_PROFILE_WITH_PPR1_ENABLED_PRESENT) == LPA_USR_CONSENT_PROFILE_WITH_PPR1_ENABLED_PRESENT) + printf("\tUser consent: LPA_USR_CONSENT_PROFILE_WITH_PPR1_ENABLED_PRESENT\n"); + } + printf("\tDo you confirm that you want to load new profile \"%s\" ?\n",ptrRequestUserConsentForLoadingProfile->profileName); + choice = 'y'; +#if 0 +#if SIFAR_PLATFORM_ICATCH + while(sf_getchar() != '\n'); + + for(trials = 5; choice!='y' && choice!='Y' && choice!='n' && choice!='N' && choice!='p' && choice!='P' && choice!='t' && choice!='T' && trials>0 ; trials--) + { + printf("\tPlease reply with 'y' (yes) or 'n' (no) or 'p' (postpone) or 't' (timeoout):"); + choice = sf_getchar(); + while(sf_getchar() != '\n'); + } +#else + while(getchar() != '\n'); + for(trials = 5; choice!='y' && choice!='Y' && choice!='n' && choice!='N' && choice!='p' && choice!='P' && choice!='t' && choice!='T' && trials>0 ; trials--) + { + printf("\tPlease reply with 'y' (yes) or 'n' (no) or 'p' (postpone) or 't' (timeoout):"); + choice = getchar(); + while(getchar() != '\n'); + } +#endif +#endif + + + switch(choice) + { + case 'y': + case 'Y': + ptrRequestUserConsentForLoadingProfile->downloadAllowed = true; + break; + + case 'n': + case 'N': + ptrRequestUserConsentForLoadingProfile->downloadAllowed = false; + ptrRequestUserConsentForLoadingProfile->cancelSessionReason = LPA_CANCEL_SESSION_END_USER_REJECTION; + break; + + case 'p': + case 'P': + ptrRequestUserConsentForLoadingProfile->downloadAllowed = false; + ptrRequestUserConsentForLoadingProfile->cancelSessionReason = LPA_CANCEL_SESSION_POSTPONED; + break; + + case 't': + case 'T': + default: + ptrRequestUserConsentForLoadingProfile->downloadAllowed = false; + ptrRequestUserConsentForLoadingProfile->cancelSessionReason = LPA_CANCEL_SESSION_TIME_OUT; + break; + } + if(ptrRequestUserConsentForLoadingProfile->downloadAllowed == true) + { + printf("\t -> Download is allowed\n\n"); + } + else + { + printf("\t -> Download is not allowed\n"); + printf("\t -> Cancel Session Reason = "); + switch(ptrRequestUserConsentForLoadingProfile->cancelSessionReason) + { + case LPA_CANCEL_SESSION_END_USER_REJECTION: + printf("End User Rejection\n\n"); + break; + + case LPA_CANCEL_SESSION_POSTPONED: + printf("Postponed\n\n"); + break; + + case LPA_CANCEL_SESSION_TIME_OUT: + printf("Timeout\n\n"); + break; + + default: + printf("This should never be displayed !\n\n"); + break; + } + } + return(true); +} + +void lpaEventDisplayIncomingProfileInformationFunction(const void * ptrAppParameter, size_t eventType, LPA_EVENT_INCOMING_PROFILE_INFORMATION* ptrIncomingProfileInformation) +{ + ssize_t indexIcon = 0; + unsigned char iccidStr[2*LPA_PROFILE_ICCID_BUFFER_MAX_SIZE+1] = {0}; + + printf("\nInformation from lpaEventCallback._lpaEventDisplayIncomingProfileInformation function:\n"); + + if(ptrIncomingProfileInformation->profileMetadataAvailable == true) + { + SampleLPA_GetIccidStr(iccidStr, ptrIncomingProfileInformation->iccid, ptrIncomingProfileInformation->iccidSize); + sf_lpa_set_download_profile_iccid((SINT8 *)iccidStr); + printf("\ticcidSize = %u\n",ptrIncomingProfileInformation->iccidSize); + printf("\ticcid = %s\n", iccidStr); + + printf("\tprofileName = \"%s\"\n",ptrIncomingProfileInformation->profileName); + + printf("\tserviceProviderName = \"%s\"\n",ptrIncomingProfileInformation->serviceProviderName); + + printf("\tprofileIconSize = %u\n",ptrIncomingProfileInformation->profileIconSize); + if(ptrIncomingProfileInformation->profileIconSize != 0) + { + printf("\tprofileIconType = %d\n",ptrIncomingProfileInformation->profileIconType); + printf("\tprofileIcon = "); + for (indexIcon = 0; indexIcon < ptrIncomingProfileInformation->profileIconSize; indexIcon++) + printf("%02X",ptrIncomingProfileInformation->profileIcon[indexIcon]); + printf("\n"); + } + + if(ptrIncomingProfileInformation->profilePPR != 0) + { + printf("\tprofilePPR = %04X\n",ptrIncomingProfileInformation->profilePPR); + } + } + else + { + printf("\tSM-DP+ didn't send Metadata\n"); + } + + printf("\n"); +} + + +LPA_API_ERROR SampleLPA_DownloadProfile(const char* ActivationCodeStr) +{ + LPA_DOWNLOAD_PROFILE_RESULT downloadProfileResult; + LPA_EventCallback lpaEventCallback; + char ActivationCode[255] = {0}; + LPA_API_ERROR errCode = LPA_NO_ERROR; + + strcpy(ActivationCode,ActivationCodeStr); + + memset(&lpaEventCallback,0x00,sizeof(LPA_EventCallback)); + //lpaEventCallback._appParameter = NULL; + lpaEventCallback._lpaEventProgressValue = lpaEventValueNotificationFunction; + lpaEventCallback._lpaEventProgressText = lpaEventTextNotificationFunction; + lpaEventCallback._lpaEventExecutionError = lpaEventExecutionErrorNotificationFunction; + lpaEventCallback._lpaEventRequestConfirmationCode = lpaEventRequestConfirmationCodeFunction; + lpaEventCallback._lpaEventRequestUserConsentForLoadingProfile= lpaEventRequestUserConsentFunction; + lpaEventCallback._lpaEventDisplayIncomingProfileInformation = lpaEventDisplayIncomingProfileInformationFunction; + + printf("\nStarting Profile Download\n"); + printf("ActivationCode = %s\n",ActivationCode); + //sp5kSystemCfgSet(SP5K_SYS_VFP_ENABLE, 1); + bool res = lpaDownloadProfile(ActivationCode, &lpaEventCallback, &downloadProfileResult); + //sp5kSystemCfgSet(SP5K_SYS_VFP_ENABLE, 0); + printf("lpaDownloadProfile API returned %s\n", (res ? "true" : "false")); + + if(!res) + { + errCode = lpaGetErrorCode(); + printf("=> Error code: %s\n", lpaGetErrorCodeDescription(errCode)); + } + + printf("Nb of installed profile(s) during operation : %u\n",downloadProfileResult.countProfileInstalled); + + return(errCode); +} + + +bool SampleLPA_DownloadProfile_SMDS() +{ + LPA_DOWNLOAD_PROFILE_RESULT downloadProfileResult; + LPA_EventCallback lpaEventCallback; + + memset(&lpaEventCallback,0x00,sizeof(LPA_EventCallback)); + //lpaEventCallback._appParameter = NULL; + lpaEventCallback._lpaEventProgressValue = lpaEventValueNotificationFunction; + lpaEventCallback._lpaEventProgressText = lpaEventTextNotificationFunction; + lpaEventCallback._lpaEventExecutionError = lpaEventExecutionErrorNotificationFunction; + lpaEventCallback._lpaEventRequestConfirmationCode = (LPA_EVENT_REQUEST_CONFIRMATION_CODE)lpaEventRequestConfirmationCodeFunction; + //lpaEventCallback._lpaEventRequestUserConsentForLoadingProfile= NULL; + lpaEventCallback._lpaEventDisplayIncomingProfileInformation = lpaEventDisplayIncomingProfileInformationFunction; + + printf("\nStarting Profile Download using the discovery mechanism (SM-DS)\n"); + bool res = lpaDownloadProfileWithSMDSAddress(&lpaEventCallback, &downloadProfileResult); + printf("lpaDownloadProfileWithSMDSAddress API returned %s\n", (res ? "true" : "false")); + + if(!res) + { + printf("=> Error code: %s\n", lpaGetErrorCodeDescription(lpaGetErrorCode())); + } + + printf("Nb of installed profile(s) during operation : %u out of %u from list retrieved on SM-DS\n",downloadProfileResult.countProfileInstalled,downloadProfileResult.countProfileTotal); + + return(res); +} + +bool SampleLPA_DownloadProfile_defaultSMDP() +{ + LPA_DOWNLOAD_PROFILE_RESULT downloadProfileResult; + LPA_EventCallback lpaEventCallback; + + memset(&lpaEventCallback,0x00,sizeof(LPA_EventCallback)); + //lpaEventCallback._appParameter = NULL; + lpaEventCallback._lpaEventProgressValue = lpaEventValueNotificationFunction; + lpaEventCallback._lpaEventProgressText = lpaEventTextNotificationFunction; + lpaEventCallback._lpaEventExecutionError = lpaEventExecutionErrorNotificationFunction; + lpaEventCallback._lpaEventRequestConfirmationCode = (LPA_EVENT_REQUEST_CONFIRMATION_CODE)lpaEventRequestConfirmationCodeFunction; + //lpaEventCallback._lpaEventRequestUserConsentForLoadingProfile= NULL; + lpaEventCallback._lpaEventDisplayIncomingProfileInformation = lpaEventDisplayIncomingProfileInformationFunction; + + printf("\nStarting Profile Download using the default SM-DP+\n"); + bool res = lpaDownloadProfileWithDefaultSMDPAddress(&lpaEventCallback, &downloadProfileResult); + printf("lpaDownloadProfileWithDefaultSMDPAddress API returned %s\n", (res ? "true" : "false")); + + if(!res) + { + printf("=> Error code: %s\n", lpaGetErrorCodeDescription(lpaGetErrorCode())); + } + + printf("Nb of installed profile(s) during operation : %u\n",downloadProfileResult.countProfileInstalled); + + return(res); +} + +bool SampleLPA_GetProfilesInfo(LPA_GET_PROFILES_INFO* getProfilesInfo) +{ + size_t NbOfProfilesForMemAlloc; + size_t ActualNbOfProfiles; + bool res_1; + bool res_2; + + res_1 = lpaGetProfilesNumber( &ActualNbOfProfiles ); + printf("\nlpaGetProfilesNumber API returned %s\n", (res_1 ? "true" : "false")); + + res_2 = res_1; + + if(res_1) + { + getProfilesInfo->countProfileInfo = 0; + getProfilesInfo->numberProfileInfoFound = ActualNbOfProfiles; + + // Try to allocate memory for Nb of profiles = ActualNbOfProfiles (or less if not possible) + NbOfProfilesForMemAlloc = ActualNbOfProfiles; + if(getProfilesInfo->profileInfoList != NULL) + { + free(getProfilesInfo->profileInfoList); + getProfilesInfo->profileInfoList = NULL; + } + while(getProfilesInfo->profileInfoList == NULL && NbOfProfilesForMemAlloc > 0) + { + getProfilesInfo->profileInfoList = malloc(sizeof(LPA_PROFILE_INFO)*NbOfProfilesForMemAlloc); + getProfilesInfo->maxNumberProfileInfo = NbOfProfilesForMemAlloc; + NbOfProfilesForMemAlloc--; + } + + // Call lpaGetProfilesInfo only if memory has been allocated + if(getProfilesInfo->profileInfoList != NULL) + { + res_2 = lpaGetProfilesInfo(getProfilesInfo); + printf("lpaGetrofilesInfo API returned %s\n", (res_2 ? "true" : "false")); + } + } + + if(res_2) + { + printf("\tcountProfileInfo= %u\n",getProfilesInfo->countProfileInfo); + printf("\tnumberProfileInfoFound= %u\n",getProfilesInfo->numberProfileInfoFound); + } + else + { + getProfilesInfo->countProfileInfo = 0; + printf("=> Error code: %s\n", lpaGetErrorCodeDescription(lpaGetErrorCode())); + } + + printf("\n"); + return(res_2); +} + +void SampleLPA_DisplayProfilesInfoFull(LPA_GET_PROFILES_INFO getProfilesInfo) +{ + size_t indexProfile = 0; + size_t indexRaw = 0; + size_t indexState = 0; + size_t indexSPN = 0; + size_t indexName = 0; + size_t indexClass = 0; + size_t indexNickname = 0; + size_t indexIcon = 0; + size_t indexIconType = 0; + size_t indexPolicyRules = 0; + LPA_PROFILE_INFO *profileData = (LPA_PROFILE_INFO*) getProfilesInfo.profileInfoList; + unsigned char iccidStr[2*LPA_PROFILE_ICCID_BUFFER_MAX_SIZE+1] = {0}; + + for (indexProfile = 0; indexProfile < getProfilesInfo.countProfileInfo; indexProfile ++) + { + printf("Profile %u :\n",indexProfile); + printf("\tProfile[%d].rawDataSize = %u\n",indexProfile, profileData[indexProfile].rawDataSize); + printf("\tProfile[%d].rawData = ",indexProfile); + for (indexRaw = 0; indexRaw < profileData[indexProfile].rawDataSize; indexRaw++) + printf("%02X",profileData[indexProfile].rawData[indexRaw]); + printf("\n"); + + printf("\tProfile[%u].iccidSize = %u\n",indexProfile, profileData[indexProfile].iccidSize); + SampleLPA_GetIccidStr(iccidStr,profileData[indexProfile].iccid, profileData[indexProfile].iccidSize); + printf("\tProfile[%u].iccid = %s\n",indexProfile, iccidStr); + + printf("\tProfile[%u].profileStateSize = %u\n",indexProfile, profileData[indexProfile].profileStateSize); + printf("\tProfile[%u].profileState = ",indexProfile); + for (indexState = 0; indexState < profileData[indexProfile].profileStateSize; indexState++) + printf("%02X",profileData[indexProfile].profileState[indexState]); + printf("\n"); + + printf("\tProfile[%u].serviceProviderNameSize = %u\n",indexProfile, profileData[indexProfile].serviceProviderNameSize); + printf("\tProfile[%u].serviceProviderName = ",indexProfile); + for (indexSPN = 0; indexSPN < profileData[indexProfile].serviceProviderNameSize; indexSPN++) + printf("%02X",profileData[indexProfile].serviceProviderName[indexSPN]); + printf("\n\t => SPN = "); + for (indexSPN = 0; indexSPN < profileData[indexProfile].serviceProviderNameSize; indexSPN++) + printf("%c",profileData[indexProfile].serviceProviderName[indexSPN]); + printf("\n"); + + printf("\tProfile[%u].profileNameSize = %u\n",indexProfile, profileData[indexProfile].profileNameSize); + printf("\tprofileInfoList[%u].profileName = ",indexProfile); + for (indexName = 0; indexName < profileData[indexProfile].profileNameSize; indexName++) + printf("%02X",profileData[indexProfile].profileName[indexName]); + printf("\n\t => Profile Name = "); + for (indexName = 0; indexName < profileData[indexProfile].profileNameSize; indexName++) + printf("%c",profileData[indexProfile].profileName[indexName]); + printf("\n"); + + printf("\tProfile[%u].profileClassSize = %u\n",indexProfile, profileData[indexProfile].profileClassSize); + printf("\tProfile[%u].profileClass = ",indexProfile); + for (indexClass = 0; indexClass < profileData[indexProfile].profileClassSize; indexClass++) + printf("%02X",profileData[indexProfile].profileClass[indexClass]); + printf("\n"); + + printf("\tProfile[%u].profileNicknameSize = %u\n",indexProfile, profileData[indexProfile].profileNicknameSize); + printf("\tProfile[%u].profileNickname = ",indexProfile); + for (indexNickname = 0; indexNickname < profileData[indexProfile].profileNicknameSize; indexNickname++) + printf("%02X",profileData[indexProfile].profileNickname[indexNickname]); + printf("\n\t => Nickname = "); + for (indexNickname = 0; indexNickname < profileData[indexProfile].profileNicknameSize; indexNickname++) + printf("%c",profileData[indexProfile].profileNickname[indexNickname]); + printf("\n"); + + printf("\tProfile[%u].profileIconSize = %u\n",indexProfile, profileData[indexProfile].profileIconSize); + printf("\tProfile[%u].profileIcon = ",indexProfile); + for (indexIcon = 0; indexIcon < profileData[indexProfile].profileIconSize; indexIcon++) + printf("%02X",profileData[indexProfile].profileIcon[indexIcon]); + printf("\n"); + + printf("\tProfile[%u].profileIconTypeSize = %u\n",indexProfile, profileData[indexProfile].profileIconTypeSize); + printf("\tProfile[%u].profileIconType = ",indexProfile); + for (indexIconType = 0; indexIconType < profileData[indexProfile].profileIconTypeSize; indexIconType++) + printf("%02X",profileData[indexProfile].profileIconType[indexIconType]); + printf("\n"); + + printf("\tProfile[%u].profilePolicyRulesSize = %u\n",indexProfile, profileData[indexProfile].profilePolicyRulesSize); + printf("\tProfile[%u].profilePolicyRules = ",indexProfile); + for (indexPolicyRules = 0; indexPolicyRules < profileData[indexProfile].profilePolicyRulesSize; indexPolicyRules++) + printf("%02X",profileData[indexProfile].profilePolicyRules[indexPolicyRules]); + printf("\n"); + + } + printf("\n"); +} + +void SampleLPA_DisplayProfilesInfoSimplified(LPA_GET_PROFILES_INFO getProfilesInfo) +{ + size_t indexProfile = 0; + size_t indexName = 0; + size_t indexNickname = 0; + size_t indexPolicyRules = 0; + unsigned char iccidStr[2*LPA_PROFILE_ICCID_BUFFER_MAX_SIZE+1]; + + LPA_PROFILE_INFO *profileData = (LPA_PROFILE_INFO*) getProfilesInfo.profileInfoList; + + for (indexProfile = 0; indexProfile < getProfilesInfo.countProfileInfo; indexProfile ++) + { + printf("Profile %u :\n",indexProfile); + SampleLPA_GetIccidStr(iccidStr,profileData[indexProfile].iccid, profileData[indexProfile].iccidSize); + printf("\ticcid = %s\n", iccidStr); + + printf("\tprofileState = "); + switch(profileData[indexProfile].profileState[0]) + { + case PROFILE_STATE_DISABLED: + printf("disabled\n"); + break; + case PROFILE_STATE_ENABLED: + printf("enabled\n"); + break; + default: + printf("UNEXPECTED VALUE\n"); + break; + } + + printf("\tprofileName = "); + for (indexName = 0; indexName < profileData[indexProfile].profileNameSize; indexName++) + printf("%c",profileData[indexProfile].profileName[indexName]); + printf("\n"); + + printf("\tprofileNickname = "); + for (indexNickname = 0; indexNickname < profileData[indexProfile].profileNicknameSize; indexNickname++) + printf("%c",profileData[indexProfile].profileNickname[indexNickname]); + printf("\n"); + + printf("\tprofileClass = "); + switch(profileData[indexProfile].profileClass[0]) + { + case PROFILE_CLASS_TEST: + printf("test\n"); + break; + case PROFILE_CLASS_PROVISIONING: + printf("provisioning\n"); + break; + case PROFILE_CLASS_OPERATIONAL: + printf("operational\n"); + break; + default: + printf("UNEXPECTED VALUE\n"); + break; + } + + if(profileData[indexProfile].profilePolicyRulesSize >0) + { + printf("\tprofilePolicyRules = "); + for (indexPolicyRules = 0; indexPolicyRules < profileData[indexProfile].profilePolicyRulesSize; indexPolicyRules++) + printf("%02X",profileData[indexProfile].profilePolicyRules[indexPolicyRules]); + printf("\n"); + } + } + printf("\n"); +} + +bool SampleLPA_EnableProfile(unsigned char* ProfileIdByteArray, size_t ProfileIdByteArraySize) +{ + unsigned char IccidStr[2*LPA_PROFILE_ICCID_BUFFER_MAX_SIZE+1] = {0}; + + SampleLPA_GetIccidStr(IccidStr,ProfileIdByteArray,ProfileIdByteArraySize); + + printf("\nEnabling Profile %s...\n",IccidStr); + bool res = lpaEnableProfileByIccid(ProfileIdByteArray,ProfileIdByteArraySize); + printf("Operation for enabling profile %s.\n", (res ? "is successful" : "has failed")); + if(!res) printf("=> Error code: %s\n", lpaGetErrorCodeDescription(lpaGetErrorCode())); + return(res); +} + + +bool SampleLPA_DisableProfile(unsigned char* ProfileIdByteArray, size_t ProfileIdByteArraySize) +{ + unsigned char IccidStr[2*LPA_PROFILE_ICCID_BUFFER_MAX_SIZE+1] = {0}; + + SampleLPA_GetIccidStr(IccidStr,ProfileIdByteArray,ProfileIdByteArraySize); + + printf("\nDisabling Profile %s...\n",IccidStr); + bool res = lpaDisableProfileByIccid(ProfileIdByteArray,ProfileIdByteArraySize); + printf("Operation for disabling profile %s.\n", (res ? "is successful" : "has failed")); + if(!res) printf("=> Error code: %s\n", lpaGetErrorCodeDescription(lpaGetErrorCode())); + return(res); +} + + +bool SampleLPA_DeleteProfile(unsigned char* ProfileIdByteArray, size_t ProfileIdByteArraySize) +{ + unsigned char IccidStr[2*LPA_PROFILE_ICCID_BUFFER_MAX_SIZE+1] = {0}; + + SampleLPA_GetIccidStr(IccidStr,ProfileIdByteArray,ProfileIdByteArraySize); + + printf("\nDeleting Profile %s...\n",IccidStr); + bool res = lpaDeleteProfileByIccid(ProfileIdByteArray,ProfileIdByteArraySize); + printf("Profile deletion %s.\n", (res ? "is successful" : "has failed")); + if(!res) printf("=> Error code: %s\n", lpaGetErrorCodeDescription(lpaGetErrorCode())); + return(res); +} + +void SampleLPA_SetNickname(unsigned char* ProfileIdByteArray, size_t ProfileIdByteArraySize) +{ + unsigned char IccidStr[2*LPA_PROFILE_ICCID_BUFFER_MAX_SIZE+1] = {0}; + unsigned char Nickname[LPA_PROFILE_NICKNAME_MAX_SIZE+1] = {0}; + + SampleLPA_GetIccidStr(IccidStr,ProfileIdByteArray,ProfileIdByteArraySize); + + printf("\nEnter the nickname for %s:\n",IccidStr); + +#if SIFAR_PLATFORM_ICATCH + sf_scanf(0, Nickname); + printf("Nickname:%s\n", Nickname); +#else + int c=0; + while(c!='\n') c=getchar(); + fgets(Nickname,sizeof(Nickname),stdin); + if(strstr(Nickname,"\n") != NULL) + { + *strstr(Nickname,"\n")='\0'; + } + else + { + c=0; + while(c!='\n') c=getchar(); + } +#endif + bool res = lpaSetNicknameByIccid(ProfileIdByteArray,ProfileIdByteArraySize,Nickname,strlen((const char *)Nickname)); + printf("Call to lpaSetNicknameByIccid() %s.\n", (res ? "was successful" : "has failed")); + if(!res) printf("=> Error code: %s\n", lpaGetErrorCodeDescription(lpaGetErrorCode())); +} + + +LPA_API_ERROR SampleLPA_SendPendingNotifications(void) +{ + LPA_SENDING_NOTIFICATION_RESULT sendingNotificationResult; + LPA_EventCallback lpaEventCallback; + LPA_API_ERROR errCode = LPA_NO_ERROR; + + //sp5kSystemCfgSet(SP5K_SYS_VFP_ENABLE, 1); + memset(&lpaEventCallback,0x00,sizeof(LPA_EventCallback)); + //lpaEventCallback._appParameter = NULL; + lpaEventCallback._lpaEventProgressText = lpaEventTextNotificationFunction; + lpaEventCallback._lpaEventProgressValue = lpaEventValueNotificationFunction; + lpaEventCallback._lpaEventExecutionError = lpaEventExecutionErrorNotificationFunction; + + #ifdef SAMPLE__GENERIC_MODEM + Modem_WaitForModemReady_EID(); + #endif //SAMPLE__GENERIC_MODEM + + printf("\nStarting sending pending notifications\n"); +// system("date +%H:%M:%S:%N"); + bool res = lpaSendPendingNotification(&lpaEventCallback, &sendingNotificationResult); +// system("date +%H:%M:%S:%N"); + printf("lpaSendPendingNotification API returned %s\n", (res ? "true" : "false")); + if(res) + { + printf("Notification(s) detected = %u\n",sendingNotificationResult.countNotificationDetected); + printf("Notification(s) sent = %u\n",sendingNotificationResult.countNotificationSend); + } + + errCode = lpaGetErrorCode(); + if(errCode != LPA_NO_ERROR) + { + printf("=> Error code: %s\n", lpaGetErrorCodeDescription(errCode)); + } + + //sp5kSystemCfgSet(SP5K_SYS_VFP_ENABLE, 0); + + return errCode; +} + + + +bool SampleLPA_MemoryReset() +{ + const unsigned char memoryResetOptionParameter[] = {0x05,0xE0}; + + printf("\nStarting Memory Reset\n"); + bool res = lpaMemoryReset(memoryResetOptionParameter,sizeof(memoryResetOptionParameter)); + printf("lpaMemoryReset API returned %s\n", (res ? "true" : "false")); + if(!res) printf("=> Error code: %s\n", lpaGetErrorCodeDescription(lpaGetErrorCode())); + return(res); +} + +#if SF_LPA_SDK +SF_BOOL sf_get_eid(UINT8 *eidStr) +{ + if(eidStr== NULL) + return FALSE; + + if(SimEid[0] == '\0') + return FALSE; + + SF_STRCPY(eidStr, SimEid); + + return TRUE; +} + + +UINT32 sf_get_profile_total(void) +{ + return getProfilesInfo.countProfileInfo; +} + +UINT32 sf_get_profile_item(UINT8 index, LPA_PROFILE_INFO *profileInfo) +{ + size_t indexProfile = 0; + LPA_PROFILE_INFO *profileData = (LPA_PROFILE_INFO*) getProfilesInfo.profileInfoList; + + indexProfile = (size_t)index; + + if((profileInfo == NULL) || (indexProfile >= getProfilesInfo.countProfileInfo)) + { + printf("%s(%d)input para err\n",__FUNCTION__,__LINE__); + return FAIL; + } + + memcpy(profileInfo, &profileData[indexProfile], sizeof(LPA_PROFILE_INFO)); + + return SUCCESS; +} + +UINT32 sf_is_profile_index_enable(UINT8 index) +{ + LPA_PROFILE_INFO *profileData = (LPA_PROFILE_INFO*) getProfilesInfo.profileInfoList; + + if(index >= getProfilesInfo.countProfileInfo) + return FALSE; + + if(profileData[index].profileState[0] == PROFILE_STATE_ENABLED) + return TRUE; + + return FALSE; +} + + +UINT32 sf_get_profile_active(LPA_GET_PROFILES_INFO getProfilesInfo, LPA_PROFILE_INFO *profileActive) +{ + size_t indexProfile = 0; + size_t indexIccid = 0; + size_t indexName = 0; + size_t indexNickname = 0; + size_t indexPolicyRules = 0; + unsigned char digit_left = 0; + unsigned char digit_right = 0; + + LPA_PROFILE_INFO *profileData = (LPA_PROFILE_INFO*) getProfilesInfo.profileInfoList; + + printf("active profile :\n"); + + for (indexProfile = 0; indexProfile < getProfilesInfo.countProfileInfo; indexProfile ++) + { + if(profileData[indexProfile].profileState[0] == PROFILE_STATE_ENABLED) + { + memcpy(profileActive, &profileData[indexProfile], sizeof(LPA_PROFILE_INFO)); + + printf("Profile %u :\n",indexProfile); + printf("\ticcid = "); + for (indexIccid = 0; indexIccid < profileData[indexProfile].iccidSize; indexIccid++) + { + digit_left = (profileData[indexProfile].iccid[indexIccid] & 0xF0)>>4; + digit_right = (profileData[indexProfile].iccid[indexIccid] & 0x0F); + + //printf("%02X",profileData[indexProfile].iccid[indexIccid]); + printf("%c", digit_right == 0x0F ? 'F' : '0' + digit_right); + printf("%c", digit_left == 0x0F ? 'F' : '0' + digit_left); + + } + printf("\n"); + printf("\tprofileState = enabled\n"); + printf("\tprofileName = "); + for (indexName = 0; indexName < profileData[indexProfile].profileNameSize; indexName++) + printf("%c",profileData[indexProfile].profileName[indexName]); + printf("\n"); + + printf("\tprofileNickname = "); + for (indexNickname = 0; indexNickname < profileData[indexProfile].profileNicknameSize; indexNickname++) + printf("%c",profileData[indexProfile].profileNickname[indexNickname]); + printf("\n"); + + printf("\tprofileClass = "); + switch(profileData[indexProfile].profileClass[0]) + { + case PROFILE_CLASS_TEST: + printf("test\n"); + break; + case PROFILE_CLASS_PROVISIONING: + printf("provisioning\n"); + break; + case PROFILE_CLASS_OPERATIONAL: + printf("operational\n"); + break; + default: + printf("UNEXPECTED VALUE\n"); + break; + } + + if(profileData[indexProfile].profilePolicyRulesSize >0) + { + printf("\tprofilePolicyRules = "); + for (indexPolicyRules = 0; indexPolicyRules < profileData[indexProfile].profilePolicyRulesSize; indexPolicyRules++) + printf("%02X",profileData[indexProfile].profilePolicyRules[indexPolicyRules]); + printf("\n"); + } + + return SUCCESS; + } + } + + return FAIL; +} + +UINT32 sf_profile_active_change(LPA_GET_PROFILES_INFO getProfilesInfo) +{ + bool res = 0; + size_t indexProfile = 0; + unsigned char IccidStr[2*LPA_PROFILE_ICCID_BUFFER_MAX_SIZE+1] = {0}; + LPA_PROFILE_INFO *profileData = (LPA_PROFILE_INFO*) getProfilesInfo.profileInfoList; + + for (indexProfile = 0; indexProfile < getProfilesInfo.countProfileInfo; indexProfile++) + { + if(profileData[indexProfile].profileState[0] == PROFILE_STATE_ENABLED) + { + SampleLPA_GetIccidStr(IccidStr, profileData[indexProfile].iccid, profileData[indexProfile].iccidSize); + printf("\nDisabling Profile %s...\n",IccidStr); + + res = lpaDisableProfileByIccid(profileData[indexProfile].iccid, profileData[indexProfile].iccidSize); + + if(!res) + { + printf("Operation for disabling profile has failed.\n"); + printf("=> Error code: %s\n", lpaGetErrorCodeDescription(lpaGetErrorCode())); + } + else + { + printf("Operation for disabling profile is successful.\n"); + } + + break; + } + } + + usleep(2000000); + + indexProfile = (indexProfile + 1) % getProfilesInfo.countProfileInfo; + + SampleLPA_GetIccidStr(IccidStr, profileData[indexProfile].iccid, profileData[indexProfile].iccidSize); + + printf("\nEnabling Profile %s...\n",IccidStr); + res = lpaEnableProfileByIccid(profileData[indexProfile].iccid, profileData[indexProfile].iccidSize); + + if(!res) + { + printf("Operation for enabling profile has failed.\n"); + printf("=> Error code: %s\n", lpaGetErrorCodeDescription(lpaGetErrorCode())); + + return SF_LPA_FAIL; + } + + printf("Operation for enabling profile is successful.\n"); + usleep(2000000); + + return SF_LPA_SUCCESS; +} + +UINT32 sf_profile_name_paired(UINT8 *profileName, UINT8 *operatorName) +{ +#if 0 + if(SF_STRSTR(profileName, operatorName)) + return SUCCESS; + + if(SF_STRSTR(profileName, "TestProfile1") && SF_STRSTR(operatorName, "CHINA MOBILE")) + { + return SUCCESS; + } + else if(SF_STRSTR(profileName, "TestProfile2") && SF_STRSTR(operatorName, "CHN-UNICOM")) + { + return SUCCESS; + } + else if(SF_STRSTR(profileName, "TestProfile2") && SF_STRSTR(operatorName, "CHN-CT")) + { + return SUCCESS; + } + else +#endif + if(SF_STRSTR(profileName, "Verizon") && SF_STRSTR(operatorName, "Verizon")) + { + return SUCCESS; + } + else if(SF_STRSTR(profileName, "ATT") && SF_STRSTR(operatorName, "AT&T")) + { + return SUCCESS; + } + + return FAIL; +} + + +UINT32 sf_get_profile_index(LPA_GET_PROFILES_INFO getProfilesInfo, UINT8 *operatorName, size_t *index) +{ + size_t indexProfile = 0; + + LPA_PROFILE_INFO *profileData = (LPA_PROFILE_INFO*) getProfilesInfo.profileInfoList; + + for (indexProfile = 0; indexProfile < getProfilesInfo.countProfileInfo; indexProfile ++) + { + if(sf_profile_name_paired(profileData[indexProfile].profileName, operatorName) == SUCCESS) + { + *index = indexProfile; + + return SUCCESS; + } + } + + return FAIL; +} + +UINT32 sf_get_profile_active_index(UINT8 *index) +{ + UINT8 indexProfile = 0; + + for (indexProfile = 0; indexProfile < getProfilesInfo.countProfileInfo; indexProfile++) + { + if(ProfileData[indexProfile].profileState[0] == PROFILE_STATE_ENABLED) + { + *index = indexProfile; + + return SUCCESS; + } + } + + return FAIL; +} + + +LPA_API_ERROR sf_enable_profile(UINT8 indexProfiles) +{ + unsigned char IccidStr[2*LPA_PROFILE_ICCID_BUFFER_MAX_SIZE+1]; + bool res = 0; + LPA_API_ERROR errCode = LPA_NO_ERROR; + + if(indexProfiles < getProfilesInfo.countProfileInfo) + { + SampleLPA_GetIccidStr(IccidStr, ProfileData[indexProfiles].iccid, ProfileData[indexProfiles].iccidSize); + + printf("\nEnabling Profile %s...\n",IccidStr); + res = lpaEnableProfileByIccid(ProfileData[indexProfiles].iccid, ProfileData[indexProfiles].iccidSize); + + if(!res) + { + printf("Operation for enabling profile has failed.\n"); + + errCode = lpaGetErrorCode(); + printf("=> Error code: %s\n", lpaGetErrorCodeDescription(errCode)); + + return errCode; + } + + printf("Operation for enabling profile is successful.\n"); + + return LPA_NO_ERROR; + } + + return errCode; +} + + +LPA_API_ERROR sf_lpa_enable_profile_from_iccid(const SINT8* iccid) +{ + UINT8 iccidStr[2 * LPA_PROFILE_ICCID_BUFFER_MAX_SIZE + 1] = {0}; + LPA_API_ERROR errCode = SF_LPA_CUSTOM_ERROR_INVALID_ICCID; + UINT8 indexProfile = 0; + UINT8 retry = 6; + bool res = 0; + + printf("enable profile from ICCID\n"); + + for (indexProfile = 0; indexProfile < getProfilesInfo.countProfileInfo; indexProfile++) + { + SampleLPA_GetIccidStr(iccidStr, ProfileData[indexProfile].iccid, ProfileData[indexProfile].iccidSize); + + if(SF_STRCMP(iccidStr, iccid) == 0) + { + if(ProfileData[indexProfile].profileState[0] == PROFILE_STATE_ENABLED) + { + printf("profile is enabled\n"); + return SF_LPA_CUSTOM_ERROR_PROFILE_ENABLED; + } + else + { + printf("\nEnabling Profile %s...\n",iccidStr); + + while(retry--) + { + res = lpaEnableProfileByIccid(ProfileData[indexProfile].iccid, ProfileData[indexProfile].iccidSize); + + if(!res) + { + printf("Operation for enabling profile has failed.\n"); + errCode = lpaGetErrorCode(); + printf("=> Error code: %s\n", lpaGetErrorCodeDescription(errCode)); + + if(errCode == LPA_ERROR_LOCAL_PROFILE_CAT_BUSY) + { + sleep(10); + printf("retry %d\n", retry); + } + else + { + break; + } + } + else + { + errCode = LPA_NO_ERROR; + + break; + } + } + + if(errCode == LPA_NO_ERROR) + { + printf("Operation for enabling profile is successful.\n"); + } + + return errCode; + } + } + } + + printf("INVALID ICCID\n"); + + return errCode; +} + + +LPA_API_ERROR sf_lpa_delete_profile_from_iccid(const SINT8* iccid) +{ + UINT8 iccidStr[2 * LPA_PROFILE_ICCID_BUFFER_MAX_SIZE + 1] = {0}; + LPA_API_ERROR errCode = SF_LPA_CUSTOM_ERROR_INVALID_ICCID; + UINT8 indexProfile = 0; + bool res = 0; + + printf("delete profile from ICCID\n"); + + for (indexProfile = 2; indexProfile < getProfilesInfo.countProfileInfo; indexProfile++) + { + SampleLPA_GetIccidStr(iccidStr, ProfileData[indexProfile].iccid, ProfileData[indexProfile].iccidSize); + + if(SF_STRCMP(iccidStr, iccid) == 0) + { + if(ProfileData[indexProfile].profileState[0] == PROFILE_STATE_ENABLED) + { + printf("profile is enabled\n"); + return SF_LPA_CUSTOM_ERROR_PROFILE_ENABLED; + } + else + { + printf("\nDeleting Profile %s...\n",iccidStr); + //sp5kSystemCfgSet(SP5K_SYS_VFP_ENABLE, 1); + res = lpaDeleteProfileByIccid(ProfileData[indexProfile].iccid, ProfileData[indexProfile].iccidSize); + //sp5kSystemCfgSet(SP5K_SYS_VFP_ENABLE, 0); + printf("Profile deletion %s.\n", (res ? "is successful" : "has failed")); + + if(!res) + { + errCode = lpaGetErrorCode(); + printf("=> Error code: %s\n", lpaGetErrorCodeDescription(errCode)); + + return errCode; + } + else + { + return LPA_NO_ERROR; + } + } + } + } + + printf("INVALID ICCID\n"); + + return errCode; +} + +LPA_API_ERROR sf_lpa_download_profile(const SINT8* activationCodeStr) +{ + return SampleLPA_DownloadProfile((const char*)activationCodeStr); +} + +LPA_API_ERROR sf_lpa_set_smdp_addr(const char* smdpAddr) +{ + LPA_API_ERROR errCode = LPA_NO_ERROR; + + bool res = lpaSetDefaultSMDPAddress(smdpAddr); + printf("lpaSetDefaultSMDPAddress API returned %s\n", (res ? "true" : "false")); + + if(res) + { + printf(" SMDP Address (hex) = %s\n", smdpAddr); + } + else + { + errCode = lpaGetErrorCode(); + printf("=> Error code: %s\n", lpaGetErrorCodeDescription(errCode)); + } + + return errCode; +} + +LPA_API_ERROR sf_lpa_send_pending_notifications(void) +{ + return SampleLPA_SendPendingNotifications(); +} + +SINT32 sf_lpa_get_all_iccid(SINT8* allIccid) +{ + UINT8 iccidStr[2 * LPA_PROFILE_ICCID_BUFFER_MAX_SIZE + 1] = {0}; + UINT8 indexProfile = 0; + + if(allIccid == NULL) + { + return SF_FAILURE; + } + + for (indexProfile = 0; indexProfile < getProfilesInfo.countProfileInfo; indexProfile++) + { + if(ProfileData[indexProfile].profileState[0] == PROFILE_STATE_ENABLED) + { + SampleLPA_GetIccidStr(iccidStr, ProfileData[indexProfile].iccid, ProfileData[indexProfile].iccidSize); + SF_STRCPY(allIccid, iccidStr); + } + } + + for (indexProfile = 0; indexProfile < getProfilesInfo.countProfileInfo; indexProfile++) + { + if(ProfileData[indexProfile].profileState[0] != PROFILE_STATE_ENABLED) + { + SampleLPA_GetIccidStr(iccidStr, ProfileData[indexProfile].iccid, ProfileData[indexProfile].iccidSize); + SF_STRCAT(allIccid, "-"); + SF_STRCAT(allIccid, iccidStr); + } + } + + //printf("allIccid:%s\n", allIccid); + + return SF_SUCCESS; +} + +SINT32 sf_lpa_get_active_profile_iccid(SINT8* iccid) +{ + UINT8 indexProfile = 0; + + for (indexProfile = 0; indexProfile < getProfilesInfo.countProfileInfo; indexProfile++) + { + if(ProfileData[indexProfile].profileState[0] == PROFILE_STATE_ENABLED) + { + SampleLPA_GetIccidStr((unsigned char*)iccid, (unsigned char*)ProfileData[indexProfile].iccid, ProfileData[indexProfile].iccidSize); + printf("active iccid:%s\n", iccid); + + return SF_SUCCESS; + } + } + + return SF_FAILURE; +} + + +SINT32 sf_lpa_get_download_profile_iccid(SINT8* iccid) +{ + if(iccid == NULL) + { + return SF_FAILURE; + } + + SF_STRNCPY(iccid, DownLoadProfileIccid, 2*LPA_PROFILE_ICCID_BUFFER_MAX_SIZE); + printf("download profile iccid:%s\n", iccid); + + return SF_SUCCESS; +} + + + + + +static UINT8 g_esim_flag=0; //adjust insert esim or not +void sf_set_esim_card(UINT8 flag) +{ + g_esim_flag = flag; +} + +UINT8 sf_is_esim_card() +{ + return g_esim_flag; +} + + + +static UINT8 g_esim_init_finish_flag=0; //adjust the esim card is init. +void sf_set_esim_init_finish(UINT8 flag) +{ + g_esim_init_finish_flag = flag; +} +UINT8 sf_is_esim_init_finish() +{ + return g_esim_init_finish_flag; +} + +void sf_lpa_profile_info_refresh(void) +{ + bool ret = false; + + memset(&ProfileActive, 0, sizeof(LPA_PROFILE_INFO)); + memset(&getProfilesInfo, 0, sizeof(LPA_GET_PROFILES_INFO)); + + ret = SampleLPA_GetProfilesInfo(&getProfilesInfo); + + if(ret == false) + { + sleep(1); + ret = SampleLPA_GetProfilesInfo(&getProfilesInfo); + } + + if(ret == true) + { + ProfileData = (LPA_PROFILE_INFO*) getProfilesInfo.profileInfoList; + SampleLPA_DisplayProfilesInfoSimplified(getProfilesInfo); + } + + if(sf_get_profile_active(getProfilesInfo, &ProfileActive) == FAIL) + { + printf("Profile no active\n"); + } +} + + +/************/ +/** **/ +/** Main **/ +/** **/ +/************/ + + + +void sf_sample_lpa_thread() +{ + bool res; + const LPA_API_VERSION* lpaApiVersion; + + char* ActivationCodeStr_local_default="1$smdp-plus.test.gsma.com$default"; + char* ActivationCodeStr_local_OP1="1$smdp-plus.test.gsma.com$GTO_PROFILE_OPERATIONAL1_8929901012345678905.ppp"; + char* ActivationCodeStr_local_OP2="1$smdp-plus.test.gsma.com$GTO_PROFILE_OPERATIONAL2_8929901023456789019.ppp"; + char* ActivationCodeStr_local_TEST1="1$smdp-plus.test.gsma.com$GTO_PROFILE_TEST1_89299010023456780024.ppp"; + char* ActivationCodeStr_local_OP4_PPR1="1$smdp-plus.test.gsma.com$GTO_PROFILE_OPERATIONAL4_8929901045678901239.ppp"; + char* ActivationCodeStr_local_OP51_PPR1_PPR2="1$smdp-plus.test.gsma.com$GTO_PROFILE_OPERATIONAL5.1_8929901056789012345.ppp"; + //char* ActivationCodeStr_local_OP11_PPR2="1$smdp-plus.test.gsma.com$GTO_PROFILE_OPERATIONAL1.1_8929901012345678905.ppp"; + char* ActivationCodeStr_local_OP11_PPR2="1$thales1-livelab.prod.ondemandconnectivity.com$CFF8F7C0697AF20CD99B0E53E10C9C4494FA7AD1672D69E7AC14A7975D230967"; + + + #define NB_OF_AVAILABLE_CODES 7 + char* ActivationCodeStr[NB_OF_AVAILABLE_CODES]; + ActivationCodeStr[0] = ActivationCodeStr_local_default; + ActivationCodeStr[1] = ActivationCodeStr_local_OP1; + ActivationCodeStr[2] = ActivationCodeStr_local_OP2; + ActivationCodeStr[3] = ActivationCodeStr_local_TEST1; + ActivationCodeStr[4] = ActivationCodeStr_local_OP4_PPR1; + ActivationCodeStr[5] = ActivationCodeStr_local_OP51_PPR1_PPR2; + ActivationCodeStr[6] = ActivationCodeStr_local_OP11_PPR2; + + + size_t index_ActivationCode; + size_t index_Profiles; + + memset(&ProfileActive, 0, sizeof(LPA_PROFILE_INFO)); + memset(&getProfilesInfo, 0, sizeof(LPA_GET_PROFILES_INFO)); + + //LPA_GET_PROFILES_INFO getProfilesInfo; + //getProfilesInfo.profileInfoList = NULL; + //LPA_PROFILE_INFO *ProfileData = NULL; + + printf("\n --- Starting sample execution ---\n"); + #ifdef SAMPLE__GENERIC_MODEM + printf(" --- compiled for MODEM ---\n\n"); + Modem_WaitForModemIsDetected(); + Modem_WaitForModemReady_AT(); + #else + printf(" --- not compiled for MODEM ---\n\n"); + #endif + + SampleLPA_Initialize(); + + lpaApiVersion = lpaGetApiVersion(); + printf("LPA API version : %d.%d\n\n", lpaApiVersion->major, lpaApiVersion->minor); + + SampleLPA_GetAndSetReader(); + + res = SampleLPA_GetEID(SimEid); + + if(res) + { + sf_set_esim_card(1); + + #if 1 + SampleLPA_GetSMDPAddress(); + + SampleLPA_GetSMDSAddress(); + + SampleLPA_SetCurlParameters(); + + //SampleLPA_SetParameter_CertPath("CI-cert_NIST.crt"); + + #endif + + SampleLPA_SetParameter_deviceInfoTlv(); + + #ifdef SAMPLE__GENERIC_MODEM + SampleLPA_SetRefreshParameter(true); + #else + SampleLPA_SetRefreshParameter(false); + #endif //SAMPLE__GENERIC_MODEM + + //SampleLPA_SendPendingNotifications(); + + if(SampleLPA_GetProfilesInfo(&getProfilesInfo)) + { + ProfileData = (LPA_PROFILE_INFO*) getProfilesInfo.profileInfoList; + //SampleLPA_DisplayProfilesInfoFull(getProfilesInfo); + SampleLPA_DisplayProfilesInfoSimplified(getProfilesInfo); + } + + if(sf_get_profile_active(getProfilesInfo, &ProfileActive) == FAIL) + { + printf("Profile no active\n"); + } + + //ESIM Init finished + sf_set_esim_init_finish(1); + + char choice[SCANF_MAX_LEN]; + choice[0]= '0'; + while( choice[0] != 'x') + { + printf("\n------------------------------------------------------------\n"); + printf("L - List activation codes\n"); + printf("logx - Log level:#x (0:UNKNOWN 1:PROFLOG 2:VERBOSE 3:DEBUG 4:INFO 5:WARNING 6:ERROR 7:SYSTEM)\n"); + printf("Ax - download profile using Activation code #x\n"); + printf("Ex - Enable profile #x\n"); + printf("Dx - Disable profile #x\n"); + printf("Rx - delete (Remove) profile #x\n"); + printf("Sx - Set nickname for profile #x\n\n"); + printf("G - Get EID\n"); + printf("I - get and display profiles Info (simplified)\n"); + printf("IF - get and display profiles Info (Full)\n"); + printf("UI - get eUicc Info\n"); + printf("N - send Notifications\n"); + printf("MR - Memory Reset\n"); + printf("US - download profile Using sm-dS address\n"); + printf("UP - download profile Using default sm-dP+ address\n"); + printf("b - get default sm-dP+ address\n"); + printf("X - eXit\n"); + #ifdef SAMPLE__USE_MODEM_CONNECTIVITY + printf("\n"); + printf("+ - Connect celluar data\n"); + printf("- - Disconnect cellular data\n"); + printf("/ - Toggle cellular auto connect (currently %s)\n",cellularAutoConnect ? "enabled" : "disabled"); + #endif //SAMPLE__USE_MODEM_CONNECTIVITY + printf("\n------------------------------------------------------------"); + printf("\nChoice : \n"); + + choice[1]= '\0'; + choice[2]= '\0'; + + sf_scanf(0, (UINT8 *)choice); + + index_ActivationCode = NB_OF_AVAILABLE_CODES; // set index to out of range value + index_Profiles = getProfilesInfo.countProfileInfo; // set index to out of range value + + if((choice[1] >= '0') && (choice[1] <='9')) + { + index_Profiles = choice[1]-'0'; + if((choice[2] >= '0') && (choice[2] <='9')) + { + index_Profiles = index_Profiles*10; + index_Profiles += choice[2]-'0'; + } + index_ActivationCode = index_Profiles; + } + + switch(choice[0]) + { + case 'l': + if(choice[1] == 'o' && choice[2] == 'g') + { + if((choice[3] >= '0') && (choice[3] <= '9')) + { + lpaSetLogLevel(choice[3] - '0'); + } + else + { + printf("\nlog level %c error.\n", choice[3]); + } + } + else + { + printf("\nCommand is not recognized.\n"); + } + break; + case 'L': + for(index_ActivationCode=0; index_ActivationCode < NB_OF_AVAILABLE_CODES; index_ActivationCode++) + { + printf("\tActivation Code #%d : %s\n",index_ActivationCode,ActivationCodeStr[index_ActivationCode]); + } + break; + + case 'a': + case 'A': + if(index_ActivationCode Result for lpaUninitialize is %s\n", (res ? "\"true\"" : "\"false\"")); + return; + + #ifdef SAMPLE__USE_MODEM_CONNECTIVITY + case '+': + External_ConnectCellular(); + break; + case '-': + External_DisconnectCellular(); + break; + case '/': + ToggleCellularAutoConnect(); + break; + #endif //SAMPLE__USE_MODEM_CONNECTIVITY + + default: + printf("\nCommand is not recognized.\n"); + break; + } + + } + printf("LPA end.\n"); + } + else + { + //not esim + sf_set_esim_card(0); + + lpaUninitialize(); + //ESIM Init finished + sf_set_esim_init_finish(1); + } +} + + +static SF_THREAD_S SfLpaTskParam = +{ + .IsRun = 0, + .TskId = -1, +}; + +void sf_sample_lpa_init(void) +{ + + if(!SfLpaTskParam.IsRun) + { + pthread_create(&SfLpaTskParam.TskId, NULL, sf_sample_lpa_thread, NULL); + SfLpaTskParam.IsRun = 1; + } +} + +void sf_profile_active_change_thread(ULONG tmp) +{ + sf_profile_active_change(getProfilesInfo); + if(SampleLPA_GetProfilesInfo(&getProfilesInfo)) + { + ProfileData = (LPA_PROFILE_INFO*) getProfilesInfo.profileInfoList; + //SampleLPA_DisplayProfilesInfoFull(getProfilesInfo); + SampleLPA_DisplayProfilesInfoSimplified(getProfilesInfo); + } + + usleep(1000000); + sf_power_off(); +} + + +void sf_lpa_profile_active_change(void) +{ + pthread_t tLpaProfileActiveTask; + pthread_create(&tLpaProfileActiveTask,NULL,sf_profile_active_change_thread,(void *)NULL); +} + + + + +void sf_lpa_cmds(UINT32 argc, char *arg[], UINT32 v[]) +{ + UINT32 i = 0, paraNum = argc-1; + char *cmd = arg[0]; + + printf("----%d--%s---%s\n", argc , arg[0], arg[1]); + if(!strcmp(cmd, "sample")) + { + sf_sample_lpa_init(); + } + else if(!strcmp(cmd, "scanf")) + { + for(i = 0; i < paraNum; i++) + { + sprintf((char *)&ScanfStr[i][0], "%s", arg[i+1]); + ScanfVal[i] = v[i+1]; + + printf("ScanfStr[%d]=%s\n", i, ScanfStr[i]); + printf("ScanfVal[%d]=%d\n", i, ScanfVal[i]); + } + } + else if(!strcmp(cmd, "actprofile")) + { + if(sf_get_profile_active(getProfilesInfo, &ProfileActive) == FAIL) + { + printf("Profile no active\n"); + } + } + + +} + + +typedef struct +{ + UINT8 operatorId; /*operator ID*/ + UINT8 operatorName[16]; /* operator name string: AT&T or Verizon or other*/ + UINT8 signalVal; /*operator signal val: db */ +}Operator_Info_T; + +typedef struct +{ + UINT8 profileId; /*profile ID*/ + UINT8 profileName[16]; /* profile name string: ATT or Verizon or other*/ +}Profile_Info_T; + +SF_OPERATORS_LIST_T *pOperatorListHead = NULL; +static UINT8 FirstScan = 1; + + + +uint32_t sf_fgets(char **src, char *dst) +{ + char *pStr = *src; + char *pDst = dst; + + while(*pStr != '\0') + { + //printf("*pStr=%02x\n", *pStr); + if ((*pStr == 0x0d) || (*pStr == 0x0a)) + { + *dst = '\0'; + + break; + } + + *dst = *pStr; + + pStr++; + dst++; + } + + if (((*pStr == 0x0d) || (*pStr == 0x0a)) && ((*(pStr + 1) == 0x0d) || (*(pStr + 1) == 0x0a))) + *src = pStr + 2; + else if(*pStr != '\0') + *src = pStr + 1; + else + *src = pStr; + + //printf("*src=%s\n", *src); + + return (uint32_t)dst - (uint32_t)pDst; +} + +/************************************************* + Function: sf_operator_list_print + Description: printf operator list + Input: N/A + Output: N/A + Return: N/A + Others: N/A +*************************************************/ +void sf_operator_list_print(void) +{ + //UINT8 i = 0; + SF_OPERATORS_LIST_T *pList = pOperatorListHead; + printf("print list:\n"); + while(pList != NULL) + { + printf("Operator%d:%s %s %s\n", pList->Index, pList->OperatorNameLong, pList->OperatorNameShort, pList->OperatorNum); + printf("net:%dG signal:%d\n", pList->NetType, pList->SignalVal); + pList = pList->pNext; + } +} + +/************************************************* + Function: sf_get_operator_total + Description: get operator total + Input: N/A + Output: N/A + Return: total + Others: N/A +*************************************************/ +UINT8 sf_get_operator_total(void) +{ + UINT8 total = 0; + SF_OPERATORS_LIST_T *pList = pOperatorListHead; + + while(pList != NULL) + { + total = pList->Index; + pList = pList->pNext; + + if(total == 0xFF) + total = 0; + else + total++; + } + + return total; +} + +/************************************************* + Function: sf_get_operator_item + Description: get operator item + Input: N/A + Output: N/A + Return: N/A + Others: N/A +*************************************************/ +UINT32 sf_get_operator_item(UINT8 index, SF_OPERATORS_LIST_T *pOperatorInfo) +{ + SF_OPERATORS_LIST_T *pList = pOperatorListHead; + + while(pList != NULL) + { + if (pList->Index == index) + { + memcpy(pOperatorInfo, pList, sizeof(SF_OPERATORS_LIST_T)); + printf("Operator%d:%s %s %s\n", pOperatorInfo->Index, pOperatorInfo->OperatorNameLong, pOperatorInfo->OperatorNameShort, pOperatorInfo->OperatorNum); + printf("net:%dG signal:%d\n", pOperatorInfo->NetType, pOperatorInfo->SignalVal); + return SUCCESS; + } + + pList = pList->pNext; + } + + return FAIL; +} + +/************************************************* + Function: sf_get_operator_total + Description: get operator total + Input: N/A + Output: N/A + Return: total + Others: N/A +*************************************************/ +void sf_operator_delete_to_list(void) +{ + SF_OPERATORS_LIST_T *pList = pOperatorListHead; + SF_OPERATORS_LIST_T *qList = NULL; + + while(pList != NULL) + { + qList = pList->pNext; + free(pList); + pList = qList; + } + + pOperatorListHead = NULL; +} +#if 0 + +/************************************************* + Function: sf_operator_add_to_list + Description: add operator to list + Input: AT response buff + Output: N/A + Return: N/A + Others: N/A +*************************************************/ +#define SF_OPERATOR_LIST_FILENAME SF_DCF_SD_ROOT "operator_list.txt" +void sf_operator_add_to_list(UINT8 *operatorInfo, UINT8 saveFlg) +{ + SF_OPERATORS_LIST_T *currList = pOperatorListHead; + SF_OPERATORS_LIST_T *preList = NULL; + UINT8 *pStr1 = NULL; + UINT8 *pOperatorNameLongStr = NULL; + UINT8 *pOperatorNameShortStr = NULL; + UINT8 *pOperatorNumStr = NULL; + UINT8 *pOperatorRsrpStr = NULL; + UINT8 *pNetTypeStr = NULL; + UINT8 operatorStr[100] = {0}; + UINT8 OperatorRsrp = 0; + UINT8 OperatorBestRsrp = 0; + UINT8 OperatorType = 0; + UINT8 OperatorBestType = 0; + UINT8 ingoreOperator = 0; + UIMenuStoreInfo *sim_info_t2 = sf_app_ui_para_get(); + pStr1 = SF_STRSTR(operatorInfo, "+QOPS:"); + + if(pStr1 == NULL) + { + printf("no operator\n"); + + return; + } + + if(saveFlg) + { + sf_save_file(SF_OPERATOR_LIST_FILENAME, pStr1, SF_STRLEN(pStr1)); + } + + if(pOperatorListHead == NULL) + { + pOperatorListHead = (SF_OPERATORS_LIST_T *)malloc(sizeof(SF_OPERATORS_LIST_T)); + memset(pOperatorListHead, 0, sizeof(SF_OPERATORS_LIST_T)); + pOperatorListHead->Index = 0xFF; //init 0xff, operator null + currList = pOperatorListHead; + } + + while(1) + { + memset(operatorStr, '\0', sizeof(operatorStr)); + + if(sf_fgets((char **)&pStr1, (char *)operatorStr) == 0) + break; + + //printf("operatorStr=%s\n", operatorStr); + + if(SF_STRSTR(operatorStr, "+QOPS:")) + { + if (SF_STRSTR(operatorStr, "+QOPS: \"AT&T\",\"AT&T\",") || SF_STRSTR(operatorStr, "+QOPS: \"Verizon\",\"Verizon\",")) + { + ingoreOperator = 0; + } + else if(SF_STRSTR(operatorStr, "+QOPS: \"\",\"\",")) //unknow operator + { + + ingoreOperator = 1; + } + else + { + if(sim_info_t2->NetworkTestSwitch) + ingoreOperator = 0; + else + ingoreOperator = 1; + } + } + + if(ingoreOperator) + { + continue; + } + + if(SF_STRSTR(operatorStr, "+QOPS:")) + { + pOperatorNameLongStr = SF_STRTOK(operatorStr, "\""); + pOperatorNameLongStr = pOperatorNameLongStr; //build warning + pOperatorNameLongStr = SF_STRTOK(NULL, "\",\""); + pOperatorNameShortStr = SF_STRTOK(NULL, "\",\""); + pOperatorNumStr = SF_STRTOK(NULL, ",\""); + + //printf("\r\nOperator: %s %s %s\n", pOperatorNameLongStr, pOperatorNameShortStr, pOperatorNumStr); + + if(currList == NULL) + { + currList = (SF_OPERATORS_LIST_T *)malloc(sizeof(SF_OPERATORS_LIST_T)); + memset(currList, 0, sizeof(SF_OPERATORS_LIST_T)); + } + + SF_STRCPY(currList->OperatorNameLong, pOperatorNameLongStr); + SF_STRCPY(currList->OperatorNameShort, pOperatorNameShortStr); + SF_STRCPY(currList->OperatorNum, pOperatorNumStr); + currList->pPre = preList; + + if(currList->pPre != NULL) + { + currList->Index = currList->pPre->Index + 1; + currList->pPre->pNext = currList; + } + else + { + currList->Index = 0; + } + + preList = currList; + currList = currList->pNext; + OperatorBestType = 0; + OperatorBestRsrp = 0; + } + else if(SF_STRSTR(operatorStr, "2G") || SF_STRSTR(operatorStr, "3G") || SF_STRSTR(operatorStr, "4G")) + { + pNetTypeStr = SF_STRTOK(operatorStr, "\""); + pNetTypeStr = pNetTypeStr; + pNetTypeStr = SF_STRTOK(NULL, "\","); + + if(SF_STRSTR(pNetTypeStr, "4G")) + { + pOperatorRsrpStr = SF_STRTOK(NULL, ","); + pOperatorRsrpStr = pOperatorRsrpStr; + pOperatorRsrpStr = SF_STRTOK(NULL, ","); + pOperatorRsrpStr = pOperatorRsrpStr; + pOperatorRsrpStr = SF_STRTOK(NULL, ","); + pOperatorRsrpStr = pOperatorRsrpStr; + pOperatorRsrpStr = SF_STRTOK(NULL, ","); + pOperatorRsrpStr = pOperatorRsrpStr; + pOperatorRsrpStr = SF_STRTOK(NULL, ","); + //pOperatorRsrpStr = pOperatorRsrpStr; + //pOperatorRsrpStr = SF_STRTOK(NULL, ","); + //pOperatorRsrpStr = pOperatorRsrpStr; + //pOperatorRsrpStr = SF_STRTOK(NULL, ","); + } + + //printf("NET str: %s RSRP:%s\n", pNetTypeStr, pOperatorRsrpStr); + OperatorType = (UINT8)atoi((const char *)pNetTypeStr); + OperatorRsrp = (UINT8)0 - atoi((const char *)pOperatorRsrpStr); + //printf("NET: %dG RSRP:-%d\n", OperatorType, OperatorRsrp); + + if(OperatorRsrp != 0) + { + if(OperatorBestType < OperatorType) + { + OperatorBestType = OperatorType; + OperatorBestRsrp = OperatorRsrp; + } + else if (OperatorBestType == OperatorType) + { + if((OperatorBestRsrp != 0) && (OperatorBestRsrp > OperatorRsrp)) + OperatorBestRsrp = OperatorRsrp; + } + + preList->NetType = OperatorBestType; + preList->SignalVal = OperatorBestRsrp; + //printf("Best NET: %dG Rsrp:-%d\n", OperatorBestType, OperatorBestRsrp); + } + } + else //if(SF_STRSTR(operatorStr, "OK")) + { + break; + } + } + + sf_operator_list_print(); +} + + +void sf_operator_list_load(void) +{ + UINT32 fd = 0, fSize = 0; + UINT8 buff[2048] = {0}; + + printf("%s(%d) load operator network\n",__FUNCTION__,__LINE__); + + fd = fopen(SF_OPERATOR_LIST_FILENAME, "r"); + + if(fd) + { + + fread(buff, 2048, 1, fd); + sf_operator_add_to_list(buff, 0); + + fclose(fd); + } +} + +#endif +UINT8 sf_check_network_status(void) +{ + UINT8 errCode = CMD_SUCCESS; + + if(sf_get_sim_insert() == 0)//(!sf_get_sim_card_status_by_gpio()) + { + errCode = NETWORK_NO_SIM; + } + + //NetworkScan = TRUE; + while(!sf_get_simcard_ready()) + { + usleep(100*1000); + } + + if(sf_get_simcard_ready() == 2) + { + errCode = NETWORK_NO_SIM; + return errCode; + } + + while(!sf_is_esim_init_finish()) + { + usleep(100*1000); + } + + /*adjust the module is not reset status*/ + while(sf_get_module_reset_flag()) + { + usleep(100*1000); + } + + if(!sf_is_esim_card()) + errCode = NETWORK_SIM_NOT_SUPPORTED; + + if(sf_get_lpa_switch_flag()) + errCode = NETWORK_PROFILE_SELECT_BUSY; + + return errCode; +} + + +void sf_operator_scan_thread(UINT32 *tmp) +{ + printf("scan network.\n"); + + UINT8 totalOperator = 0; + UINT8 totalProfile = 0; + UINT8 i = 0; + UINT8 errCode = CMD_SUCCESS; + UINT8 mode = (UINT8)*tmp; + UINT8 *sendBuff = NULL; + UINT16 sendBuffLen = 0; + APP_SVR_PACKET_T *pMsgParse = NULL; + SF_OPERATORS_LIST_T operatorInfo; + Operator_Info_T *pOperatorInfo = NULL; + Profile_Info_T *pProfileInfo = NULL; + LPA_PROFILE_INFO profileItem; + UINT16 profileListBase = 0; + UINT8 OperatorNameL[20] = {0}; + + memset((void *)&profileItem, 0, sizeof(LPA_PROFILE_INFO)); + memset((void *)&operatorInfo, 0, sizeof(SF_OPERATORS_LIST_T)); + + printf("mode=%d\n", mode); + + errCode = sf_check_network_status(); + + if(errCode == CMD_SUCCESS) + { + totalOperator = sf_get_operator_total(); + + if(mode == 0) //scan + { + errCode = NETWORK_CMD_NOT_SUPPORT; +#if 0 + sf_operator_delete_to_list(); + sf_operator_scan(); + totalOperator = sf_get_operator_total(); +#endif + } + else if(mode == 1) //not scan and return esim info + { + + } + else if(mode == 2) //stop scan + { + errCode = NETWORK_CMD_NOT_SUPPORT; + } + else + { + errCode = NETWORK_CMD_NOT_SUPPORT; + } + + totalProfile = sf_get_profile_total(); + } + + + + int fd = sf_get_wifi_socket(); + UINT8 currentCmd = sf_get_wifi_cmd(); + + if(fd > 0) + { + sendBuffLen = 10/*Magic+MsgLen+CMD+ACK+EndFlag*/ + 5/*Operator/Profile Total,ID*/ + totalOperator * sizeof(Operator_Info_T) + totalProfile * sizeof(Profile_Info_T); + printf("sendBuffLen=%d totalOperator=%d totalProfile=%d\n", sendBuffLen, totalOperator, totalProfile); + sendBuff = malloc(sendBuffLen); + memset((void *)sendBuff, 0, sendBuffLen); + pMsgParse = (APP_SVR_PACKET_T *)sendBuff; + pMsgParse->magicNum = htons(MSG_PRE_FIX); + pMsgParse->cmd = htons(currentCmd); + pMsgParse->rsp = htons(MSG_WIFI_2_APP); + pMsgParse->msglen = htons(sendBuffLen - 2*sizeof(UINT16)); + pMsgParse->msgBuf.rctrlNetworkScan.cmdRet = errCode; + + pMsgParse->msgBuf.rctrlNetworkScan.buff[0] = totalOperator; + pMsgParse->msgBuf.rctrlNetworkScan.buff[1] = 0xff; + pOperatorInfo = (Operator_Info_T *)&(pMsgParse->msgBuf.rctrlNetworkScan.buff[2]); + + sf_get_operatorname(OperatorNameL); + + for(i = 0; i < totalOperator; i++) + { + if(sf_get_operator_item(i, &operatorInfo) == SUCCESS) + { + pOperatorInfo[i].operatorId = operatorInfo.Index; + SF_STRNCPY(&(pOperatorInfo[i].operatorName), &(operatorInfo.OperatorNameLong), 16); + pOperatorInfo[i].signalVal = operatorInfo.SignalVal; + + if(SF_STRNCMP(operatorInfo.OperatorNameLong, OperatorNameL, sizeof(operatorInfo.OperatorNameLong)) == 0) + { + pMsgParse->msgBuf.rctrlNetworkScan.buff[1] = operatorInfo.Index; + } + } + } + + profileListBase = 2 + totalOperator * sizeof(Operator_Info_T); + printf("profileListBase=%d\n", profileListBase); + pMsgParse->msgBuf.rctrlNetworkScan.buff[profileListBase] = totalProfile; //htons(totalProfile); + pMsgParse->msgBuf.rctrlNetworkScan.buff[profileListBase + 1] = 0xff; + pProfileInfo = (Profile_Info_T *)&(pMsgParse->msgBuf.rctrlNetworkScan.buff[profileListBase + 2]); + + for(i = 0; i < totalProfile; i++) + { + if(sf_get_profile_item(i, &profileItem) == SUCCESS) + { + pProfileInfo[i].profileId = i; + SF_STRNCPY(&pProfileInfo[i].profileName, profileItem.profileName, 16); + + if(profileItem.profileState[0] == PROFILE_STATE_ENABLED) + { + pMsgParse->msgBuf.rctrlNetworkScan.buff[profileListBase + 1] = i; + } + } + } + + sendBuff[sendBuffLen - 2] = 0xff; + sendBuff[sendBuffLen - 1] = 0xee; + + //memdump(sendBuff, sendBuffLen); + send(fd,(void *)sendBuff, sendBuffLen, 0); + free(sendBuff); + + } + else + { + printf("%s(%d)socket error\n",__FUNCTION__,__LINE__); + } + + +} + + + + +void sf_4g_operator_scan(UINT8 mode) +{ + pthread_t tOperScanTask; + + pthread_create(&tOperScanTask,NULL,sf_operator_scan_thread,(void *)&mode); +} + +UINT8 sf_wifi_server_network_select_finish(UINT8 errCode) +{ + APP_SVR_PACKET_T msgParse; + UINT32 tmp = 0; + + memset((void *)&msgParse, 0, sizeof(msgParse)); + + int fd = sf_get_wifi_socket(); + UINT8 currentCmd = sf_get_wifi_cmd(); + + if(fd > 0) + { + msgParse.msgBuf.rctrlNetworkSelect.cmdRet = errCode; + msgParse.msgBuf.rctrlNetworkSelect.suffix = htons(MSG_END_FIX); + msgParse.msglen = htons(sizeof(MSG_DEV_NetworkSelect_Ctrl_Rsp_T) + 2*sizeof(UINT16)); + /* used for response */ + msgParse.magicNum = htons(MSG_PRE_FIX); + msgParse.cmd = htons(currentCmd); + msgParse.rsp = htons(MSG_WIFI_2_APP); + /* add the magic + len total 2*2 bytes; */ + tmp=ntohs(msgParse.msglen); + send( fd,(void *)(&msgParse), (tmp + sizeof(UINT16)*2), 0); +#if 0 + printf("[app_agent]:send msg OK, msg_len[%d],data_len:[%d],cmd:[0x%x],rsp[0x%x]\n", + (tmp+4), tmp, ntohs(msgParse.cmd), ntohs(msgParse.rsp) ); +#endif + } + + return 0; +} + +SF_BOOL sf_get_active_profile_next_index(UINT8 *index) +{ + UINT32 totalProfile = 0; + UINT8 i = 0; + LPA_PROFILE_INFO profileItem; + + totalProfile = sf_get_profile_total(); + + if(totalProfile == 0) + return FALSE; + + memset((void *)&profileItem, 0, sizeof(LPA_PROFILE_INFO)); + + for(i = 0; i < totalProfile; i++) + { + if(sf_get_profile_item(i, &profileItem) == SUCCESS) + { + if(profileItem.profileState[0] == PROFILE_STATE_ENABLED) + { + i++; + + break; + } + } + } + + *index = (UINT8)(i % totalProfile); + + return TRUE; +} + +void sf_network_select_thread(UINT32 * tmp) +{ + printf("select network.\n"); + UINT32 ret = SF_LPA_SUCCESS; + UINT32 sts = 0; + UINT32 retryTime=0; + UINT8 errCode = CMD_SUCCESS; + UINT8 profileId = (UINT8)*tmp; + UINT8 curActiveProfileId = 0; + UINT32 totalProfile = 0; + LPA_API_ERROR lpaErrCode = LPA_NO_ERROR; + + errCode = sf_check_network_status(); + + if(errCode == CMD_SUCCESS) + { + + + sf_get_profile_active_index(&curActiveProfileId); + + printf("Cur id: %d select id:%d\n", curActiveProfileId, profileId); + //LOG_DM_RS("Cur id: %d select id:%d\n", curActiveProfileId, profileId); + + if(curActiveProfileId == profileId) + { + printf("No need Switch!\n"); + errCode = NETWORK_NOT_NEED_SET; + } + else + { + //LOG_DM_RS("Swich Profile:%d\n", profileId); + totalProfile = sf_get_profile_total(); + if(profileId >= totalProfile) + { + errCode = NETWORK_PROFILE_NOT_FOUND; + } + else + { + //set lpa switch flag. + sf_set_lpa_switch_flag(1); + + while(sts==0) + { + lpaErrCode = sf_enable_profile(profileId); + + printf("switch ret:%d\n", lpaErrCode); + //LOG_DM_RS("Swich Result:0x%02x\n", lpaErrCode); + + if(lpaErrCode == LPA_NO_ERROR) + { + sf_lpa_profile_info_refresh(); + errCode = CMD_SUCCESS; + sts = 1; + } + else if (lpaErrCode == LPA_ERROR_LOCAL_PROFILE_CAT_BUSY) + { + retryTime++; + if(retryTime>6) + { + errCode = NETWORK_PROFILE_SELECT_BUSY; + sts = 1; + } + sleep(10); + continue; + } + else if (lpaErrCode == SF_LPA_ERROR_MEDIA_READER_CONNECTION) + { + retryTime++; + if(retryTime>6) + { + errCode = NETWORK_PROFILE_SELECT_BUSY; + sts = 1; + } + sleep(10); + continue; + } + else + { + if(lpaErrCode == SF_LPA_ERROR_PROFILE_NOT_FOUND) + { + printf("status:PROFILE_NOT_FOUND\n"); + errCode = NETWORK_PROFILE_NOT_FOUND; + } + else if(lpaErrCode == SF_LPA_ERROR_PROFILE_IS_ENABLE) + { + printf("status:PROFILE_IS_ENABLE\n"); + errCode = NETWORK_NOT_NEED_SET; + } + else + { + printf("status:SELECT_FAILED\n"); + errCode = NETWORK_PROFILE_SELECT_FAILED; + } + sts = 1; + } + } + + if(lpaErrCode == LPA_ERROR_LOCAL_PROFILE_CAT_BUSY) + { + sf_sms_lpa_command_log(NULL, SF_SMS_LPA_CMD_FAIL, lpaErrCode, SF_SMS_LPA_CMD_ERROR_SOURCE_ESIM); + ret = SF_LPA_ERROR_PROFILE_CAT_BUSY; + } + else if(lpaErrCode == LPA_NO_ERROR) + { + sf_lpa_profile_info_refresh(); + sf_sms_lpa_command_log(NULL, SF_SMS_LPA_CMD_SUCCESS, lpaErrCode, SF_SMS_LPA_CMD_ERROR_SOURCE_OTHER); + ret = SF_LPA_SUCCESS; + } + else + { + sf_sms_lpa_command_log(NULL, SF_SMS_LPA_CMD_FAIL, lpaErrCode, SF_SMS_LPA_CMD_ERROR_SOURCE_ESIM); + ret = SF_LPA_FAIL; + } + + //clear lpa switch flag. + sf_set_lpa_switch_flag(0); + + if(errCode == CMD_SUCCESS) + { + SLOGE("Reboot module,try again!\n"); + int retryTime = 0; + int rebootTime=0; + //SF_PDT_PARAM_CFG_S *sim_info_t = sf_get_sifar_param(); + + app_RegisterNet_stop(); + + sf_set_module_reset_flag(1); + sf_mcu_reg_set(SF_MCU_RESET_MODULE, 0); + sleep(SF_MODULE_RESET_WAIT_TIME); + sf_set_module_reset_flag(0); + + #if 0 + while(sf_get_ttyfd() < 0) + { + sf_ttyfd_init_tryother(); + } + + if(sf_get_ttyfd() < 0) + { + sf_set_module_reset_flag(1); + sf_reset_ttyfd(); + sf_mcu_module_reset(1); + sleep(SF_MODULE_RESET_WAIT_TIME); + sf_set_module_reset_flag(0); + sf_ttyfd_init_tryother(); + } + #endif + + //if(sf_get_ttyfd() < 0) + { + errCode = NETWORK_CMD_READ_SIM_FAIL; + } + + } + else + { + //sf_set_4g_status(SF_4G_FAIL); + } + +#if 0 + + SampleLPA_GetAndSetReader(); + + bool res = SampleLPA_GetEID(); + + if(res) + { + + SampleLPA_SetParameter_deviceInfoTlv(); + + + SampleLPA_SetRefreshParameter(false); + + + if(SampleLPA_GetProfilesInfo(&getProfilesInfo)) + { + ProfileData = (LPA_PROFILE_INFO*) getProfilesInfo.profileInfoList; + //SampleLPA_DisplayProfilesInfoFull(getProfilesInfo); + SampleLPA_DisplayProfilesInfoSimplified(getProfilesInfo); + } + + if(sf_get_profile_active(getProfilesInfo, &ProfileActive) == FAIL) + { + printf("Profile no active\n"); + } + + + + } + + sf_set_esim_init_finish(1); +#endif + + } + } + + + } + + sf_wifi_server_network_select_finish(errCode); + +#if ((!SF_IQ_DEBUG)&&(!SF_4G_TEST)) + if(errCode == CMD_SUCCESS) + { + sf_clear_operatorname(); + sf_set_simcard_ready(0); + app_RegisterNet_start(); + } + +#endif + +#if 0 + if((errCode == CMD_SUCCESS) || (errCode == NETWORK_PROFILE_SELECT_FAILED)) + { + sleep(3); + sf_send_poweroff_msg(); + printf("[power off] %s(%d)\n",__FUNCTION__,__LINE__); + } + +#endif + +} + +void sf_network_select(UINT8 profileId) +{ + pthread_t tNetWorkSeclectTask; + pthread_create(&tNetWorkSeclectTask,NULL,sf_network_select_thread,(void *)&profileId); +} + + +void sf_network_switch_thread() +{ + printf("switch network.\n"); + UINT32 ret = SF_LPA_SUCCESS; + UINT32 sts = 0; + UINT32 retryTime=0; + UINT8 errCode = CMD_SUCCESS; + UINT8 profileId = 0; + UINT8 curActiveProfileId = 0; + LPA_API_ERROR lpaErrCode = LPA_NO_ERROR; + + errCode = sf_check_network_status(); + + if(errCode == CMD_SUCCESS) + { + + if(sf_get_active_profile_next_index(&profileId) == FALSE) + { + profileId = 0; + } + + printf("Cur id: %d select id:%d\n", curActiveProfileId, profileId); + //LOG_DM_RS("Cur id: %d select id:%d\n", curActiveProfileId, profileId); + + //LOG_DM_RS("Swich Profile:%d\n", profileId); + + //set lpa switch flag. + sf_set_lpa_switch_flag(1); + + while(sts==0) + { + lpaErrCode = sf_enable_profile(profileId); + + printf("switch ret:%d\n", lpaErrCode); + //LOG_DM_RS("Swich Result:0x%02x\n", lpaErrCode); + + if(lpaErrCode == LPA_NO_ERROR) + { + sf_lpa_profile_info_refresh(); + errCode = CMD_SUCCESS; + sts = 1; + } + else if (lpaErrCode == LPA_ERROR_LOCAL_PROFILE_CAT_BUSY) + { + retryTime++; + if(retryTime>6) + { + errCode = NETWORK_PROFILE_SELECT_BUSY; + sts = 1; + } + sleep(10); + continue; + } + else if (lpaErrCode == SF_LPA_ERROR_MEDIA_READER_CONNECTION) + { + retryTime++; + if(retryTime>6) + { + errCode = NETWORK_PROFILE_SELECT_BUSY; + sts = 1; + } + sleep(10); + continue; + } + else + { + if(lpaErrCode == SF_LPA_ERROR_PROFILE_NOT_FOUND) + { + printf("status:PROFILE_NOT_FOUND\n"); + errCode = NETWORK_PROFILE_NOT_FOUND; + } + else if(lpaErrCode == SF_LPA_ERROR_PROFILE_IS_ENABLE) + { + printf("status:PROFILE_IS_ENABLE\n"); + errCode = NETWORK_NOT_NEED_SET; + } + else + { + printf("status:SELECT_FAILED\n"); + errCode = NETWORK_PROFILE_SELECT_FAILED; + } + sts = 1; + } + } + + if(lpaErrCode == LPA_ERROR_LOCAL_PROFILE_CAT_BUSY) + { + sf_sms_lpa_command_log(NULL, SF_SMS_LPA_CMD_FAIL, lpaErrCode, SF_SMS_LPA_CMD_ERROR_SOURCE_ESIM); + ret = SF_LPA_ERROR_PROFILE_CAT_BUSY; + } + else if(lpaErrCode == LPA_NO_ERROR) + { + sf_lpa_profile_info_refresh(); + sf_sms_lpa_command_log(NULL, SF_SMS_LPA_CMD_SUCCESS, lpaErrCode, SF_SMS_LPA_CMD_ERROR_SOURCE_OTHER); + ret = SF_LPA_SUCCESS; + } + else + { + sf_sms_lpa_command_log(NULL, SF_SMS_LPA_CMD_FAIL, lpaErrCode, SF_SMS_LPA_CMD_ERROR_SOURCE_ESIM); + ret = SF_LPA_FAIL; + } + //clear lpa switch flag. + sf_set_lpa_switch_flag(0); + + if(errCode == CMD_SUCCESS) + { + + if(profileId == 0) + { + sf_sys_status_led_set(SF_SIM_SWITCH_VERIZON_PROFILE); + sleep(3); + sf_led_set(SF_LED_SIG3, SF_LED_STATE_OFF); + + } + else if(profileId == 1) + { + sf_sys_status_led_set(SF_SIM_SWITCH_ATT_PROFILE); + sleep(3); + sf_led_set(SF_LED_SIG2, SF_LED_STATE_OFF); + } + else + { + sf_sys_status_led_set(SF_SIM_SWITCH_OTHER_PROFILE); + sleep(3); + sf_led_set(SF_LED_SIG4, SF_LED_STATE_OFF); + } + + //LOG_DM_RS("Reboot Camera...!\n"); + sf_mcu_rebootall(0); + } + else + { + SLOGE("Switch Profile Failed.Err:0x%x!\n", errCode); + sf_sys_status_led_set(SF_SIM_ERROR_SWITCH_PROFILE); + } + + } + else + { + printf("Can not switch Profile. Err:0x%x\n", errCode); + sf_sys_status_led_set(SF_SIM_ERROR_SWITCH_PROFILE); + } + + +} + +void sf_network_switch(void) +{ + pthread_t tNetWorkSeclectTask; + pthread_create(&tNetWorkSeclectTask,NULL,sf_network_switch_thread,NULL); +} + + +#endif + + + diff --git a/code/application/source/sf_app/code/source/4gMng/sf_eg91_sim.c b/code/application/source/sf_app/code/source/4gMng/sf_eg91_sim.c index 42ea7be92..29df43c1d 100755 --- a/code/application/source/sf_app/code/source/4gMng/sf_eg91_sim.c +++ b/code/application/source/sf_app/code/source/4gMng/sf_eg91_sim.c @@ -14,7 +14,7 @@ extern "C" { #include "sf_hal_ttyusb.h" #include "sf_systemMng.h" - +#include "sf_commu_mcu_reg.h" #include "sf_opera_adapt.h" #include "sf_eg91_sim.h" #include "sf_param_common.h" @@ -94,6 +94,85 @@ void eg91_mark_time_set(unsigned long int MarkTime) LocateTime = MarkTime; } +static UINT8 gSIMCardReady = 0; /*0: Init Status, 1: Ready, 2: No SIM Card*/ +void sf_set_simcard_ready(UINT8 readyFlag) +{ + gSIMCardReady = readyFlag; +} + +UINT8 sf_get_simcard_ready() +{ + return gSIMCardReady; +} + +static int gModuleResetFlag = 0; + +int sf_get_module_reset_flag() +{ + return gModuleResetFlag; +} + +void sf_set_module_reset_flag(int flag) +{ + gModuleResetFlag= flag; +} + + +void sf_module_reset() +{ + gModuleResetFlag = 1; + sf_hal_ttyusb2_deinit(); + sf_mcu_reg_set(SF_MCU_RESET_MODULE, 0); + sleep(SF_MODULE_RESET_WAIT_TIME); + gModuleResetFlag = 0; +} + + +#define SF_OPERATORS_NAME_LEN 20 + +static UINT8 g_OperatorNameL[SF_OPERATORS_NAME_LEN] = {0}; +void sf_set_operatorname( const char *src) +{ + + if(NULL != src) + { + if(strlen(src) < SF_OPERATORS_NAME_LEN) + { + strcpy(g_OperatorNameL, src); + } + } +} + +int sf_get_operatorname(char *strname) +{ + if(NULL != strname) + { + strncpy(strname, g_OperatorNameL, SF_OPERATORS_NAME_LEN - 1); + strname[SF_OPERATORS_NAME_LEN - 1] = '\0'; + return strlen(g_OperatorNameL); + } + + return -1; + +} + +void sf_clear_operatorname() +{ + memset(g_OperatorNameL, 0, sizeof(g_OperatorNameL)); +} + +static int gLpaSwitchFlag=0; +int sf_get_lpa_switch_flag() +{ + return gLpaSwitchFlag; +} + +void sf_set_lpa_switch_flag(int flag) +{ + gLpaSwitchFlag= flag; +} + + static void eg91_parse_module_version_detail(SF_CHAR* pTemp, SF_CHAR *pT1, SF_CHAR *pT2, SF_CHAR *pT4, SF_CHAR *version) { UIMenuStoreInfo *sim_info_t = sf_app_ui_para_get(); @@ -2037,6 +2116,7 @@ SINT32 eg91_register_net_manual(SF_FN_PARAM_S *pfnParam) pStr = strtok(NULL, "\""); if(pStr != NULL) { + sf_set_operatorname(pStr); strcpy(pStaticParam->ServiceProvider, pStr); printf("cops1 is %s\r\n", pStr); printf("cops2 is %s\r\n", pStaticParam->ServiceProvider); @@ -5155,7 +5235,6 @@ SINT32 sf_add_cimi_id(char *cimi) return ret; } - #ifdef __cplusplus #if __cplusplus } diff --git a/code/application/source/sf_app/code/source/app/sf_common.c b/code/application/source/sf_app/code/source/app/sf_common.c index b60b6c69d..42d13e61e 100755 --- a/code/application/source/sf_app/code/source/app/sf_common.c +++ b/code/application/source/sf_app/code/source/app/sf_common.c @@ -411,6 +411,10 @@ static SINT32 process_cmd_longclick(SF_MESSAGE_BUF_S *pMessageBuf) break; case SF_KEY_PIN_SYNC: +#if SF_LPA_SDK + SLOGD("[Long]KEY_TEST.\n"); + sf_network_switch(); +#endif // if(upgrade_ota_file_IsExsit(SF_OTA_UPGRADE_FILE_PATH) == SF_FALSE) // break; // diff --git a/code/application/source/sf_app/code/source/app/sf_service.c b/code/application/source/sf_app/code/source/app/sf_service.c index b142fc090..7bc7a57d5 100755 --- a/code/application/source/sf_app/code/source/app/sf_service.c +++ b/code/application/source/sf_app/code/source/app/sf_service.c @@ -119,12 +119,16 @@ SINT32 app_ttyusb_IsOpen(void) { return s32ret; } -SINT32 sf_ttyusb_restart(void) { +SINT32 sf_ttyusb_restart(void) +{ SINT32 ret = 0; ret = sf_hal_ttyusb2_deinit(); - if (ret != 0) { + if (ret != 0) + { MLOGE("-------ttyUSB deinit fail!\n"); - } else { + } + else + { sf_mcu_reg_set(SF_MCU_RESET_MODULE, 0); sleep(5); ret = app_ttyusb_IsOpen(); @@ -163,43 +167,53 @@ static SINT16 app_Qlog_procress(void) { return s32ret; } #endif -SINT32 sf_USB_net_init(void) { +SINT32 sf_USB_net_init(void) +{ //SF_CHAR cmdStr[128] = {0}; //char cmdtmp[20] = {0}; UINT8 i = 0; int ret = SF_SUCCESS; + static U16 flag = 0; UIMenuStoreInfo *puiPara = sf_app_ui_para_get(); - if (ret == SF_SUCCESS) { - if(AT_MANAGER_SUCCEED != at_usbnet_init()){ + if (flag == 0) + { + flag = 1; + if(AT_MANAGER_SUCCEED != at_usbnet_init()) + { MLOGE("usb net err %d\n", AT_MANAGER_SUCCEED); - }else { - for (i = 0; i < 20; i++) { - if(strncmp(puiPara->ModuleVer, GPRS_MODULE_TYPE_EG915Q, 6) == 0){ + } + else + { + for (i = 0; i < 20; i++) + { + if(strncmp(puiPara->ModuleVer, GPRS_MODULE_TYPE_EG915Q, 6) == 0) + { ret = sf_check_usb0(); - }else{ + } + else + { ret = sf_check_eth0(); } - if (SUCCESS == ret) { + if (SUCCESS == ret) + { ret = SF_SUCCESS; MLOGI("usb net ip up\r\n"); break; - } else { + } + else + { sleep(1); } } } - /*if (sf_poweron_type_get() == SF_MCU_STARTUP_RING) { - sleep(2); - } else { - sleep(5); - }*/ + return ret; } printf("usb net ko no exist!\r\n"); return ret; - } +} SINT32 app_gps_map_update(SF_FN_PARAM_S *pfnParam) { SINT16 ret = SF_SUCCESS; @@ -1239,327 +1253,461 @@ static SINT32 app_Register_Net_Error_return_server(SF_FN_PARAM_S *pfnParam, sf_4G_status_set(SF_4G_FREE); return SF_SUCCESS; } -static SINT32 app_Register_Net_startup_mode(SF_FN_PARAM_S *pfnParam) { - SINT32 s32ret = 0; - // UINT8 timeCnt = 0; - // UINT8 bIsKeepConnect = 0; - // SF_CHAR version[12] = {0}; - // SF_MESSAGE_BUF_S stMessageBuf = {0}; - // SF_PDT_PARAM_CFG_S *pCustomerParam = pfnParam->pstParam; - // SF_PDT_PARAM_STATISTICS_S *pStaticParam = pfnParam->pstaticParam; - UIMenuStoreInfo *pCustomerParam = sf_app_ui_para_get(); - sf_log_Level_set(SF_LOG_LEVEL_DEBUG); +static SINT32 app_Register_Net_startup_mode(SF_FN_PARAM_S *pfnParam) +{ + SINT32 s32ret = 0; + SF_CHAR simICCID[24] = { 0 }; + SF_CHAR eid[40] = {0}; + SF_CHAR sim4gApn[40] = {0}; + UIMenuStoreInfo *pCustomerParam = sf_app_ui_para_get(); - if (sf_usb_IsInsert()) - return SF_SUCCESS; + sf_log_Level_set(SF_LOG_LEVEL_DEBUG); - sf_4G_status_set(SF_4G_SEARCHING); + if (sf_usb_IsInsert()) + return SF_SUCCESS; - switch (sf_poweron_type_get()) { - case SF_MCU_STARTUP_OFF: - break; + sf_4G_status_set(SF_4G_SEARCHING); - case SF_MCU_STARTUP_ONKEY: + switch (sf_poweron_type_get()) { + case SF_MCU_STARTUP_OFF: + break; + + case SF_MCU_STARTUP_ONKEY: #ifdef SF_HARDWARE_TEST - break; + break; #endif #ifdef SF_GPS_TEST - sf_commu_set_mcu(19, 1); - sf_commu_set_mcu(20, 1); - sf_commu_set_mcu(84, 1); + sf_commu_set_mcu(19, 1); + sf_commu_set_mcu(20, 1); + sf_commu_set_mcu(84, 1); #endif - app_led_net_reg_start(); + app_led_net_reg_start(); - s32ret = app_ttyusb_IsOpen(); - SF_APPCOMM_CHECK_RETURN(s32ret, s32ret); + s32ret = app_ttyusb_IsOpen(); + SF_APPCOMM_CHECK_RETURN(s32ret, s32ret); #if SF_QLOG_ENABLE - if (pCustomerParam->QLogSwitch == 1) - app_Qlog_procress(); + if (pCustomerParam->QLogSwitch == 1) + app_Qlog_procress(); #endif - s32ret = sf_4G_sim_init(pfnParam); - SF_APPCOMM_CHECK_RETURN(s32ret, s32ret); + s32ret = sf_4G_sim_init(pfnParam); + SF_APPCOMM_CHECK_RETURN(s32ret, s32ret); - // sf_sys_software_version_get(version); - // s32ret = sf_qrcode_create(pStaticParam->IMEI,pStaticParam->SimID - //,version); +#if SF_LPA_SDK - s32ret = sf_4G_register_net_manual(pfnParam); - //sf_share_mem_customer_down(1); - SF_APPCOMM_CHECK_RETURN(s32ret, s32ret); + sf_sample_lpa_init(); + + while(!sf_is_esim_init_finish()) + { + usleep(100*1000); + } + + if(!sf_is_esim_card() || pCustomerParam->UpdateFlg) + { + if(pCustomerParam->UpdateFlg) + { + pCustomerParam->UpdateFlg = 0; + //sf_set_param_save_flag(); + } + + sf_sms_lpa_delete_lpa_log(); + } + + if(sf_is_esim_card()) + { + sf_get_eid(eid); + printf("pPara->EsimEid=%s\n", pCustomerParam->EsimEid); + printf("pPara->eid=%s\n", eid); + if((pCustomerParam->EsimEid[0] != '\0') && (SF_STRCMP(pCustomerParam->EsimEid, eid) != 0)) + { + sf_sms_lpa_delete_lpa_log(); + } + + SF_STRCPY(pCustomerParam->EsimEid, eid); + sf_sms_lpa_load_profile_apn((const SINT8 *)simICCID, (SINT8 *)sim4gApn); + if(sim4gApn[0] != '\0') + { + SF_STRCPY(pCustomerParam->Sim4gApn, sim4gApn); + SF_STRCPY(pCustomerParam->Sim4gPwd, "\0"); + SF_STRCPY(pCustomerParam->Sim4gUsr, "\0"); + #if 0 + SF_STRCPY(sim_info_t->MmsMmsc, "\0"); + SF_STRCPY(sim_info_t->MmsApn, "\0"); + SF_STRCPY(sim_info_t->MmsProxy, "\0"); + SF_STRCPY(sim_info_t->MmsPort, "\0"); + SF_STRCPY(sim_info_t->MmsUserName, "\0"); + SF_STRCPY(sim_info_t->MmsPassword, "\0"); + #endif + printf("set profile Sim4gApn=%s\n", pCustomerParam->Sim4gApn); + } + + } +#endif + + s32ret = sf_4G_register_net_manual(pfnParam); + //sf_share_mem_customer_down(1); + SF_APPCOMM_CHECK_RETURN(s32ret, s32ret); #ifdef SF_GPS_TEST - s32ret = app_gps_map_update(pfnParam); - SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_NO_SUPPOET); + s32ret = app_gps_map_update(pfnParam); + SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_NO_SUPPOET); - s32ret = app_gps_info_get(pfnParam); - SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_NO_SUPPOET); + s32ret = app_gps_info_get(pfnParam); + SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_NO_SUPPOET); - break; + break; #endif - s32ret = sf_get_utc(); - if ((s32ret == SF_SIM_ERROR_UTC) && (SF_ON != pCustomerParam->GpsSwitch)) { - SF_PARA_TIME_S current_time = { 0, 0, 0, 0, 0, 0}; - s32ret = sf_get_ntp(s32ret, ¤t_time); - } - sf_4G_usb_net_apn_cfg(pfnParam); - sf_USB_net_init(); - if ((SF_ON == pCustomerParam->GpsSwitch)) { - s32ret = open_gps(s32ret); - serach_gps_onkey_start(); - } + s32ret = sf_get_utc(); + if ((s32ret == SF_SIM_ERROR_UTC) && (SF_ON != pCustomerParam->GpsSwitch)) { + SF_PARA_TIME_S current_time = { 0, 0, 0, 0, 0, 0}; + s32ret = sf_get_ntp(s32ret, ¤t_time); + } + sf_4G_usb_net_apn_cfg(pfnParam); + sf_USB_net_init(); + if ((SF_ON == pCustomerParam->GpsSwitch)) { + s32ret = open_gps(s32ret); + serach_gps_onkey_start(); + } - if(sf_get_signal_ready()){ - if(SUCCESS != sf_connect_ftps_server()){ - printf("[%s:%d]open ftps fail, reconnect\n", __FUNCTION__, __LINE__); - if(SUCCESS != sf_connect_ftps_server()){ - printf("[%s:%d]re open ftps fail, reconnect\n", __FUNCTION__, __LINE__); - } - } - } - SF_APPCOMM_CHECK_RETURN(s32ret, s32ret); + if(sf_get_signal_ready()){ + if(SUCCESS != sf_connect_ftps_server()){ + printf("[%s:%d]open ftps fail, reconnect\n", __FUNCTION__, __LINE__); + if(SUCCESS != sf_connect_ftps_server()){ + printf("[%s:%d]re open ftps fail, reconnect\n", __FUNCTION__, __LINE__); + } + } + } + SF_APPCOMM_CHECK_RETURN(s32ret, s32ret); - break; + break; - case SF_MCU_STARTUP_NORMAL: - break; + case SF_MCU_STARTUP_NORMAL: + break; - case SF_MCU_STARTUP_RING: + case SF_MCU_STARTUP_RING: - s32ret = sf_4G_sim_IsInsert(); - if (!s32ret) { - SF_APPCOMM_CHECK_RETURN(SF_FAILURE, SF_APP_ERROR_REQUEST); - } + s32ret = sf_4G_sim_IsInsert(); + if (!s32ret) { + SF_APPCOMM_CHECK_RETURN(SF_FAILURE, SF_APP_ERROR_REQUEST); + } - s32ret = app_ttyusb_IsOpen(); - SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); + s32ret = app_ttyusb_IsOpen(); + SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); #if SF_QLOG_ENABLE - if (pCustomerParam->QLogSwitch == 1) - app_Qlog_procress(); + if (pCustomerParam->QLogSwitch == 1) + app_Qlog_procress(); #endif - s32ret = sf_4G_sim_init(pfnParam); - SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); + s32ret = sf_4G_sim_init(pfnParam); + SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); - s32ret = sf_4G_register_net_auto(pfnParam); - //sf_share_mem_customer_down(1); - SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); - sf_4G_usb_net_apn_cfg(pfnParam); - sf_USB_net_init(); + s32ret = sf_4G_register_net_auto(pfnParam); + //sf_share_mem_customer_down(1); + SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); + sf_4G_usb_net_apn_cfg(pfnParam); + sf_USB_net_init(); - s32ret = sf_read_message(); - SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); - if (sf_get_pic()) { - s32ret = sf_app_to_cardv_capture(); - } - else if(sf_get_send_hd()){ - s32ret = sf_app_to_cardv_hd_ture(); - } - else if(sf_get_send_video()){ - s32ret = sf_video_ftp_send(); - } - break; + s32ret = sf_read_message(); + SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); + if (sf_get_pic()) { + s32ret = sf_app_to_cardv_capture(); + } + else if(sf_get_send_hd()){ + s32ret = sf_app_to_cardv_hd_ture(); + } + else if(sf_get_send_video()){ + s32ret = sf_video_ftp_send(); + } + break; - case SF_MCU_STARTUP_TIMELAPSE: - case SF_MCU_STARTUP_PIR: - if (pCustomerParam->SendType != 0) { - break; - } + case SF_MCU_STARTUP_TIMELAPSE: + case SF_MCU_STARTUP_PIR: + if (pCustomerParam->SendType != 0) { + break; + } - case SF_MCU_STARTUP_BATCH_SEND: + case SF_MCU_STARTUP_BATCH_SEND: #ifdef SF_HARDWARE_TEST - app_system_poweroff(SF_POWEROFF_NOT); - break; + app_system_poweroff(SF_POWEROFF_NOT); + break; #endif - s32ret = sf_4G_sim_IsInsert(); - if (!s32ret) { - SF_APPCOMM_CHECK_RETURN(SF_FAILURE, SF_APP_ERROR_REQUEST); - } + s32ret = sf_4G_sim_IsInsert(); + if (!s32ret) { + SF_APPCOMM_CHECK_RETURN(SF_FAILURE, SF_APP_ERROR_REQUEST); + } - s32ret = app_ttyusb_IsOpen(); - SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); + s32ret = app_ttyusb_IsOpen(); + SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); #if SF_QLOG_ENABLE - if (pCustomerParam->QLogSwitch == 1) - app_Qlog_procress(); + if (pCustomerParam->QLogSwitch == 1) + app_Qlog_procress(); #endif - s32ret = sf_4G_sim_init(pfnParam); - SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); + s32ret = sf_4G_sim_init(pfnParam); + SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); - s32ret = sf_4G_register_net_auto(pfnParam); - if (s32ret != SF_SUCCESS) { - sf_set_signal_ready_flag(TRUE); - } - //sf_share_mem_customer_down(1); - SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); - sf_4G_usb_net_apn_cfg(pfnParam); - sf_USB_net_init(); + s32ret = sf_4G_register_net_auto(pfnParam); + if (s32ret != SF_SUCCESS) { + sf_set_signal_ready_flag(TRUE); + } + //sf_share_mem_customer_down(1); + SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); + sf_4G_usb_net_apn_cfg(pfnParam); + sf_USB_net_init(); - s32ret = sf_file_send_auto(); - SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); + s32ret = sf_file_send_auto(); + SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); - break; - case SF_MCU_STARTUP_WARNING: + break; + case SF_MCU_STARTUP_WARNING: - break; - case SF_MCU_STARTUP_SERVER: + break; + case SF_MCU_STARTUP_SERVER: - break; - case SF_MCU_STARTUP_DP: + break; + case SF_MCU_STARTUP_DP: - s32ret = app_ttyusb_IsOpen(); - SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); + s32ret = app_ttyusb_IsOpen(); + SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); #if SF_QLOG_ENABLE - if (pCustomerParam->QLogSwitch == 1) - app_Qlog_procress(); + if (pCustomerParam->QLogSwitch == 1) + app_Qlog_procress(); #endif - s32ret = sf_4G_sim_init(pfnParam); - SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); + s32ret = sf_4G_sim_init(pfnParam); + SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); - s32ret = sf_4G_register_net_manual(pfnParam); - if (s32ret != SF_SUCCESS) { - sf_set_signal_ready_flag(TRUE); - } - - if (0 != sf_get_cq_signal()) { - pCustomerParam->NeedTimeSyncStartUp = 1; - } - if (pCustomerParam->DailyReportSwitch) { - pCustomerParam->GpsSendFlag = 1; // indicate need send dp file in b power on. - } + s32ret = sf_4G_register_net_manual(pfnParam); + if (s32ret != SF_SUCCESS) { + sf_set_signal_ready_flag(TRUE); + } - SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); - sf_4G_usb_net_apn_cfg(pfnParam); - sf_USB_net_init(); + if (0 != sf_get_cq_signal()) { + pCustomerParam->NeedTimeSyncStartUp = 1; + } + if (pCustomerParam->DailyReportSwitch) { + pCustomerParam->GpsSendFlag = 1; // indicate need send dp file in b power on. + } - s32ret = sf_get_utc(); - if ((s32ret == SF_SIM_ERROR_UTC) && (SF_ON != pCustomerParam->GpsSwitch)) { - SF_PARA_TIME_S current_time = { 0, 0, 0, 0, 0, 0}; - s32ret = sf_get_ntp(s32ret, ¤t_time); - } - if ((SF_ON == pCustomerParam->GpsSwitch)) { - s32ret = open_gps(s32ret); - } - if (1 == pCustomerParam->NeedTimeSyncStartUp) { - printf("[%s:%d]8 between A and B,no reg net again,no reset time sync.\n", - __FUNCTION__, __LINE__); - sf_set_dr_reset_time_sys_flag(1); - } - //sf_dailyReport_set(); - //sf_share_mem_customer_down(1); + SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); + sf_4G_usb_net_apn_cfg(pfnParam); + sf_USB_net_init(); - break; - case SF_MCU_STARTUP_USB: + s32ret = sf_get_utc(); + if ((s32ret == SF_SIM_ERROR_UTC) && (SF_ON != pCustomerParam->GpsSwitch)) { + SF_PARA_TIME_S current_time = { 0, 0, 0, 0, 0, 0}; + s32ret = sf_get_ntp(s32ret, ¤t_time); + } + if ((SF_ON == pCustomerParam->GpsSwitch)) { + s32ret = open_gps(s32ret); + } + if (1 == pCustomerParam->NeedTimeSyncStartUp) { + printf("[%s:%d]8 between A and B,no reg net again,no reset time sync.\n", + __FUNCTION__, __LINE__); + sf_set_dr_reset_time_sys_flag(1); + } + //sf_dailyReport_set(); + //sf_share_mem_customer_down(1); - break; - case SF_MCU_STARTUP_RESET: + break; + case SF_MCU_STARTUP_USB: - s32ret = app_ttyusb_IsOpen(); - SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); + break; + case SF_MCU_STARTUP_RESET: + + s32ret = app_ttyusb_IsOpen(); + SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); #if SF_QLOG_ENABLE - if (pCustomerParam->QLogSwitch == 1) - app_Qlog_procress(); + if (pCustomerParam->QLogSwitch == 1) + app_Qlog_procress(); #endif - s32ret = sf_4G_sim_init(pfnParam); - SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); + s32ret = sf_4G_sim_init(pfnParam); + SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); - s32ret = sf_4G_register_net_manual(pfnParam); - if (s32ret != SF_SUCCESS) { - sf_set_signal_ready_flag(TRUE); - } - if (0 != sf_get_cq_signal()) { - pCustomerParam->GpsSendFlag = 1; - pCustomerParam->NeedTimeSyncStartUp = 1; - // avoid always A mode power on - pCustomerParam->NetWorkNeedSearch = 0; - } - SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); - sf_4G_usb_net_apn_cfg(pfnParam); - sf_USB_net_init(); + #if SF_LPA_SDK - s32ret = sf_get_utc(); - if ((s32ret == SF_SIM_ERROR_UTC) && (SF_ON != pCustomerParam->GpsSwitch)) { - SF_PARA_TIME_S current_time = { 0, 0, 0, 0, 0, 0}; - s32ret = sf_get_ntp(s32ret, ¤t_time); - } - if ((SF_ON == pCustomerParam->GpsSwitch)) { - s32ret = open_gps(s32ret); - } - if (0 != sf_get_cq_signal()) { + sf_sample_lpa_init(); - if(SUCCESS != sf_connect_ftps_server()){ - printf("[%s:%d]open ftps fail, reconnect\n", __FUNCTION__, __LINE__); - if(SUCCESS != sf_connect_ftps_server()){ - printf("[%s:%d]re open ftps fail, reconnect\n", __FUNCTION__, __LINE__); - } - } - } - //sf_share_mem_customer_down(1); - break; - case SF_MCU_STARTUP_SYN_PARAM: + while(!sf_is_esim_init_finish()) + { + usleep(100*1000); + } - s32ret = app_ttyusb_IsOpen(); - SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); + if(!sf_is_esim_card() || pCustomerParam->UpdateFlg) + { + if(pCustomerParam->UpdateFlg) + { + pCustomerParam->UpdateFlg = 0; + //sf_set_param_save_flag(); + } + + sf_sms_lpa_delete_lpa_log(); + } + + if(sf_is_esim_card()) + { + sf_get_eid(eid); + printf("pPara->EsimEid=%s\n", pCustomerParam->EsimEid); + printf("pPara->eid=%s\n", eid); + if((pCustomerParam->EsimEid[0] != '\0') && (SF_STRCMP(pCustomerParam->EsimEid, eid) != 0)) + { + sf_sms_lpa_delete_lpa_log(); + } + + SF_STRCPY(pCustomerParam->EsimEid, eid); + sf_sms_lpa_load_profile_apn((const SINT8 *)simICCID, (SINT8 *)sim4gApn); + if(sim4gApn[0] != '\0') + { + SF_STRCPY(pCustomerParam->Sim4gApn, sim4gApn); + SF_STRCPY(pCustomerParam->Sim4gPwd, "\0"); + SF_STRCPY(pCustomerParam->Sim4gUsr, "\0"); + #if 0 + SF_STRCPY(sim_info_t->MmsMmsc, "\0"); + SF_STRCPY(sim_info_t->MmsApn, "\0"); + SF_STRCPY(sim_info_t->MmsProxy, "\0"); + SF_STRCPY(sim_info_t->MmsPort, "\0"); + SF_STRCPY(sim_info_t->MmsUserName, "\0"); + SF_STRCPY(sim_info_t->MmsPassword, "\0"); + #endif + printf("set profile Sim4gApn=%s\n", pCustomerParam->Sim4gApn); + } + + } + + if(pCustomerParam->ProfileSwitchFlg) + { + pCustomerParam->ProfileSwitchFlg = 0; + + if(ret == SF_SIM_ERROR_REG_NET_REFUSE) + { + sf_sms_lpa_command_recombination_log(SF_SMS_LPA_CMD_FAIL, SF_LPA_CUSTOM_ERROR_NETWORK_REJECTED); + + if(pCustomerParam->PreActiveProfileIccid != '\0') + { + sf_sms_lpa_profile_rool_back((const SINT8 *)pCustomerParam->PreActiveProfileIccid); + memset(pCustomerParam->PreActiveProfileIccid, '\0', sizeof(pCustomerParam->PreActiveProfileIccid)); + if(sf_sms_lpa_is_need_profile_switch_reboot()) + pCustomerParam->NetWorkNeedSearch = 1; + else + pCustomerParam->NetWorkNeedSearch = 0; //rool back fail, not need reboot + } + else + { + // switch prlfile reboot in A reg net, reg 0,3 reboot in A again + // when reboot in a, reg still reg 0,3; not need reboot again + pCustomerParam->NetWorkNeedSearch = 0; + } + } + else + { + sf_sms_lpa_command_recombination_log(SF_SMS_LPA_CMD_SUCCESS, LPA_NO_ERROR); + memset(pCustomerParam->PreActiveProfileIccid, '\0', sizeof(pCustomerParam->PreActiveProfileIccid)); + if(ret == SF_SUCCESS) + sf_sms_lpa_set_send_lpa_log_flg(1); + + // switch prlfile reboot in A reg net, reg 0,1 or reg 0,2, not need reboot again + pCustomerParam->NetWorkNeedSearch = 0; + } + } +#endif + + s32ret = sf_4G_register_net_manual(pfnParam); + if (s32ret != SF_SUCCESS) { + sf_set_signal_ready_flag(TRUE); + } + if (0 != sf_get_cq_signal()) { + pCustomerParam->GpsSendFlag = 1; + pCustomerParam->NeedTimeSyncStartUp = 1; + // avoid always A mode power on + pCustomerParam->NetWorkNeedSearch = 0; + } + SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); + sf_4G_usb_net_apn_cfg(pfnParam); + sf_USB_net_init(); + + s32ret = sf_get_utc(); + if ((s32ret == SF_SIM_ERROR_UTC) && (SF_ON != pCustomerParam->GpsSwitch)) { + SF_PARA_TIME_S current_time = { 0, 0, 0, 0, 0, 0}; + s32ret = sf_get_ntp(s32ret, ¤t_time); + } + if ((SF_ON == pCustomerParam->GpsSwitch)) { + s32ret = open_gps(s32ret); + } + if (0 != sf_get_cq_signal()) { + + if(SUCCESS != sf_connect_ftps_server()){ + printf("[%s:%d]open ftps fail, reconnect\n", __FUNCTION__, __LINE__); + if(SUCCESS != sf_connect_ftps_server()){ + printf("[%s:%d]re open ftps fail, reconnect\n", __FUNCTION__, __LINE__); + } + } + } + //sf_share_mem_customer_down(1); + break; + case SF_MCU_STARTUP_SYN_PARAM: + + s32ret = app_ttyusb_IsOpen(); + SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); #if SF_QLOG_ENABLE - if (pCustomerParam->QLogSwitch == 1) - app_Qlog_procress(); + if (pCustomerParam->QLogSwitch == 1) + app_Qlog_procress(); #endif - s32ret = sf_4G_sim_init(pfnParam); - SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); + s32ret = sf_4G_sim_init(pfnParam); + SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); - s32ret = sf_4G_register_net_auto(pfnParam); - SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); - sf_4G_usb_net_apn_cfg(pfnParam); - sf_USB_net_init(); + s32ret = sf_4G_register_net_auto(pfnParam); + SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); + sf_4G_usb_net_apn_cfg(pfnParam); + sf_USB_net_init(); - if ((SF_ON == pCustomerParam->GpsSwitch)) { - const int KEEP_SERACHING_TIMEOUT_MS = 2000; - const int KEEP_SERACHING_PERIOD_MS = 200; - // keep_seraching_gps_location(KEEP_SERACHING_TIMEOUT_S); - SF_GPS_PARAM gps_param = { - .timeout_ms = KEEP_SERACHING_TIMEOUT_MS, - .period_ms = KEEP_SERACHING_PERIOD_MS, - }; - keep_get_gps_location(gps_param); - gps_close(); - } + if ((SF_ON == pCustomerParam->GpsSwitch)) { + const int KEEP_SERACHING_TIMEOUT_MS = 2000; + const int KEEP_SERACHING_PERIOD_MS = 200; + // keep_seraching_gps_location(KEEP_SERACHING_TIMEOUT_S); + SF_GPS_PARAM gps_param = { + .timeout_ms = KEEP_SERACHING_TIMEOUT_MS, + .period_ms = KEEP_SERACHING_PERIOD_MS, + }; + keep_get_gps_location(gps_param); + gps_close(); + } - s32ret = sf_read_message(); - SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); + s32ret = sf_read_message(); + SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); - pCustomerParam->NetWorkNeedSearch = 0; - pCustomerParam->NeedTimeSyncStartUp = 0; + pCustomerParam->NetWorkNeedSearch = 0; + pCustomerParam->NeedTimeSyncStartUp = 0; - s32ret = sf_file_send_auto(); - SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); + s32ret = sf_file_send_auto(); + SF_APPCOMM_CHECK_RETURN(s32ret, SF_APP_ERROR_REQUEST); - if (sf_get_pic()) { - s32ret = sf_app_to_cardv_capture(); - } - else if(sf_get_send_hd()){ - s32ret = sf_app_to_cardv_hd_ture(); - } - else if(sf_get_send_video()){ - s32ret = sf_video_ftp_send(); - } - //sf_share_mem_customer_down(1); - break; + if (sf_get_pic()) { + s32ret = sf_app_to_cardv_capture(); + } + else if(sf_get_send_hd()){ + s32ret = sf_app_to_cardv_hd_ture(); + } + else if(sf_get_send_video()){ + s32ret = sf_video_ftp_send(); + } + //sf_share_mem_customer_down(1); + break; - default: - break; - } + default: + break; + } - return s32ret; + return s32ret; } + void app_Register_Net_thread(void) { SINT32 s32ret = 0; SF_FN_PARAM_S stpfncallback = {0}; @@ -1600,10 +1748,21 @@ SINT32 app_RegisterNet_start(void) { pthread_create(&RegisterNetTskParam.TskId, NULL, (void *)app_Register_Net_thread, NULL); RegisterNetTskParam.IsRun = 1; - SF_MUTEX_INIT_LOCK(RegisterNetTskParam.mutexLock); + //SF_MUTEX_INIT_LOCK(RegisterNetTskParam.mutexLock); } return SF_SUCCESS; } + +void app_RegisterNet_stop() +{ + printf("RegisterNetTskParam.IsRun:%d\n", RegisterNetTskParam.IsRun); + if(RegisterNetTskParam.IsRun) + { + pthread_cancel(RegisterNetTskParam.TskId); + RegisterNetTskParam.IsRun = 0; + } +} + SINT32 app_t110(void) { SINT8 halvalue = 0; diff --git a/code/application/source/sf_app/code/source/devMng/sf_ledmng.c b/code/application/source/sf_app/code/source/devMng/sf_ledmng.c index 22268ff59..0d59e9f13 100755 --- a/code/application/source/sf_app/code/source/devMng/sf_ledmng.c +++ b/code/application/source/sf_app/code/source/devMng/sf_ledmng.c @@ -22,6 +22,8 @@ #include "sf_hal_ttyusb.h" #include "sf_common.h" #include "sf_device.h" +#include "sf_eg91_sim.h" + #ifdef __cplusplus #if __cplusplus extern "C" { @@ -899,6 +901,27 @@ void sf_sys_status_led_set(LedSysState_t ledSysStateId) sf_led_set(SF_LED_BAT4, SF_LED_STATE_OFF); break; + case SF_SIM_ERROR_SWITCH_PROFILE: + //sf_set_4g_status(SF_4G_FAIL); + sf_led_set(SF_LED_SIG1_R, SF_LED_STATE_ON); + sf_led_set(SF_LED_SIG1_G, SF_LED_STATE_ON); + break; + + case SF_SIM_SWITCH_ATT_PROFILE: + //sf_set_4g_status(SF_4G_FAIL); + sf_led_set(SF_LED_SIG2, SF_LED_STATE_SLOW_FLASHING); + break; + + case SF_SIM_SWITCH_VERIZON_PROFILE: + //sf_set_4g_status(SF_4G_FAIL); + sf_led_set(SF_LED_SIG3, SF_LED_STATE_SLOW_FLASHING); + break; + + case SF_SIM_SWITCH_OTHER_PROFILE: + //sf_set_4g_status(SF_4G_FAIL); + sf_led_set(SF_LED_SIG4, SF_LED_STATE_SLOW_FLASHING); + break; + default: break; } diff --git a/code/application/source/sf_app/code/source/sf_lpa/Extra/base64/LICENSE.txt b/code/application/source/sf_app/code/source/sf_lpa/Extra/base64/LICENSE.txt new file mode 100755 index 000000000..973d540ac --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/Extra/base64/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 Joe DF (joedf@ahkscript.org) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/code/application/source/sf_app/code/source/sf_lpa/Extra/base64/base64.c b/code/application/source/sf_app/code/source/sf_lpa/Extra/base64/base64.c new file mode 100755 index 000000000..06929dbed --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/Extra/base64/base64.c @@ -0,0 +1,204 @@ +/* + base64.c - by Joe DF (joedf@ahkscript.org) + Released under the MIT License + + See "base64.h", for more information. + + Thank you for inspiration: + http://www.codeproject.com/Tips/813146/Fast-base-functions-for-encode-decode +*/ + +#include "base64.h" + +//Base64 char table - used internally for encoding +unsigned char b64_chr[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +unsigned int b64_int(unsigned int ch) { + + // ASCII to base64_int + // 65-90 Upper Case >> 0-25 + // 97-122 Lower Case >> 26-51 + // 48-57 Numbers >> 52-61 + // 43 Plus (+) >> 62 + // 47 Slash (/) >> 63 + // 61 Equal (=) >> 64~ + if (ch==43) + return 62; + if (ch==47) + return 63; + if (ch==61) + return 64; + if ((ch>47) && (ch<58)) + return ch + 4; + if ((ch>64) && (ch<91)) + return ch - 'A'; + if ((ch>96) && (ch<123)) + return (ch - 'a') + 26; + return 0; +} + +unsigned int b64e_size(unsigned int in_size) { + + // size equals 4*floor((1/3)*(in_size+2)); + int i, j = 0; + for (i=0;i>2 ]; + out[k+1] = b64_chr[ ((s[0]&0x03)<<4)+((s[1]&0xF0)>>4) ]; + out[k+2] = b64_chr[ ((s[1]&0x0F)<<2)+((s[2]&0xC0)>>6) ]; + out[k+3] = b64_chr[ s[2]&0x3F ]; + j=0; k+=4; + } + } + + if (j) { + if (j==1) + s[1] = 0; + out[k+0] = b64_chr[ (s[0]&255)>>2 ]; + out[k+1] = b64_chr[ ((s[0]&0x03)<<4)+((s[1]&0xF0)>>4) ]; + if (j==2) + out[k+2] = b64_chr[ ((s[1]&0x0F)<<2) ]; + else + out[k+2] = '='; + out[k+3] = '='; + k+=4; + } + + out[k] = '\0'; + + return k; +} + +unsigned int b64_decode(const unsigned char* in, unsigned int in_len, unsigned char* out) { + + unsigned int i=0, j=0, k=0, s[4]; + + for (i=0;i>4); + if (s[2]!=64) { + out[k+1] = ((s[1]&0x0F)<<4)+((s[2]&0x3C)>>2); + if ((s[3]!=64)) { + out[k+2] = ((s[2]&0x03)<<6)+(s[3]); k+=3; + } else { + k+=2; + } + } else { + k+=1; + } + j=0; + } + } + + return k; +} + +unsigned int b64_encodef(char *InFile, char *OutFile) { + + FILE *pInFile = fopen(InFile,"rb"); + FILE *pOutFile = fopen(OutFile,"wb"); + + unsigned int i=0; + unsigned int j=0; + unsigned int c=0; + unsigned int s[4]; + + if ((pInFile==NULL) || (pOutFile==NULL) ) { + if (pInFile!=NULL){fclose(pInFile);} + if (pOutFile!=NULL){fclose(pOutFile);} + return 0; + } + + while(c!=EOF) { + c=fgetc(pInFile); + if (c==EOF) + break; + s[j++]=c; + if (j==3) { + fputc(b64_chr[ (s[0]&255)>>2 ],pOutFile); + fputc(b64_chr[ ((s[0]&0x03)<<4)+((s[1]&0xF0)>>4) ],pOutFile); + fputc(b64_chr[ ((s[1]&0x0F)<<2)+((s[2]&0xC0)>>6) ],pOutFile); + fputc(b64_chr[ s[2]&0x3F ],pOutFile); + j=0; i+=4; + } + } + + if (j) { + if (j==1) + s[1] = 0; + fputc(b64_chr[ (s[0]&255)>>2 ],pOutFile); + fputc(b64_chr[ ((s[0]&0x03)<<4)+((s[1]&0xF0)>>4) ],pOutFile); + if (j==2) + fputc(b64_chr[ ((s[1]&0x0F)<<2) ],pOutFile); + else + fputc('=',pOutFile); + fputc('=',pOutFile); + i+=4; + } + + fclose(pInFile); + fclose(pOutFile); + + return i; +} + +unsigned int b64_decodef(char *InFile, char *OutFile) { + + FILE *pInFile = fopen(InFile,"rb"); + FILE *pOutFile = fopen(OutFile,"wb"); + + unsigned int c=0; + unsigned int j=0; + unsigned int k=0; + unsigned int s[4]; + + if ((pInFile==NULL) || (pOutFile==NULL) ) { + if (pInFile!=NULL){fclose(pInFile);} + if (pOutFile!=NULL){fclose(pOutFile);} + return 0; + } + + while(c!=EOF) { + c=fgetc(pInFile); + if (c==EOF) + break; + s[j++]=b64_int(c); + if (j==4) { + fputc(((s[0]&255)<<2)+((s[1]&0x30)>>4),pOutFile); + if (s[2]!=64) { + fputc(((s[1]&0x0F)<<4)+((s[2]&0x3C)>>2),pOutFile); + if ((s[3]!=64)) { + fputc(((s[2]&0x03)<<6)+(s[3]),pOutFile); k+=3; + } else { + k+=2; + } + } else { + k+=1; + } + j=0; + } + } + + fclose(pInFile); + fclose(pOutFile); + + return k; +} diff --git a/code/application/source/sf_app/code/source/sf_lpa/Extra/base64/base64.h b/code/application/source/sf_app/code/source/sf_lpa/Extra/base64/base64.h new file mode 100755 index 000000000..c700c7f67 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/Extra/base64/base64.h @@ -0,0 +1,44 @@ +/* + base64.c - by Joe DF (joedf@ahkscript.org) + Released under the MIT License + + Revision: 2015-06-12 01:26:51 + + Thank you for inspiration: + http://www.codeproject.com/Tips/813146/Fast-base-functions-for-encode-decode +*/ + +#include + +//Base64 char table function - used internally for decoding +unsigned int b64_int(unsigned int ch); + +// in_size : the number bytes to be encoded. +// Returns the recommended memory size to be allocated for the output buffer excluding the null byte +unsigned int b64e_size(unsigned int in_size); + +// in_size : the number bytes to be decoded. +// Returns the recommended memory size to be allocated for the output buffer +unsigned int b64d_size(unsigned int in_size); + +// in : buffer of "raw" binary to be encoded. +// in_len : number of bytes to be encoded. +// out : pointer to buffer with enough memory, user is responsible for memory allocation, receives null-terminated string +// returns size of output including null byte +unsigned int b64_encode(const unsigned char* in, unsigned int in_len, unsigned char* out); + +// in : buffer of base64 string to be decoded. +// in_len : number of bytes to be decoded. +// out : pointer to buffer with enough memory, user is responsible for memory allocation, receives "raw" binary +// returns size of output excluding null byte +unsigned int b64_decode(const unsigned char* in, unsigned int in_len, unsigned char* out); + +// file-version b64_encode +// Input : filenames +// returns size of output +unsigned int b64_encodef(char *InFile, char *OutFile); + +// file-version b64_decode +// Input : filenames +// returns size of output +unsigned int b64_decodef(char *InFile, char *OutFile); \ No newline at end of file diff --git a/code/application/source/sf_app/code/source/sf_lpa/Extra/cJSON/cJSON.c b/code/application/source/sf_app/code/source/sf_lpa/Extra/cJSON/cJSON.c new file mode 100755 index 000000000..ec16ce99f --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/Extra/cJSON/cJSON.c @@ -0,0 +1,2934 @@ +/* +Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/* cJSON */ +/* JSON parser in C. */ + +/* disable warnings about old C89 functions in MSVC */ +#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) +#define _CRT_SECURE_NO_DEPRECATE +#endif + +#ifdef __GNUC__ +#pragma GCC visibility push(default) +#endif +#if defined(_MSC_VER) +#pragma warning (push) +/* disable warning about single line comments in system headers */ +#pragma warning (disable : 4001) +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef ENABLE_LOCALES +#include +#endif + +#if defined(_MSC_VER) +#pragma warning (pop) +#endif +#ifdef __GNUC__ +#pragma GCC visibility pop +#endif + +#include "cJSON.h" + +/* define our own boolean type */ +#define true ((cJSON_bool)1) +#define false ((cJSON_bool)0) + +typedef struct { + const unsigned char *json; + size_t position; +} error; +static error global_error = { NULL, 0 }; + +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) +{ + return (const char*)(global_error.json + global_error.position); +} + +CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) { + if (!cJSON_IsString(item)) { + return NULL; + } + + return item->valuestring; +} + +/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 10) +#error cJSON.h and cJSON.c have different versions. Make sure that both have the same. +#endif + +CJSON_PUBLIC(const char*) cJSON_Version(void) +{ + static char version[15]; + sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); + + return version; +} + +/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ +static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) +{ + if ((string1 == NULL) || (string2 == NULL)) + { + return 1; + } + + if (string1 == string2) + { + return 0; + } + + for (; tolower(*string1) == tolower(*string2); (void)string1++, string2++) + { + if (*string1 == '\0') + { + return 0; + } + } + + return tolower(*string1) - tolower(*string2); +} + +typedef struct internal_hooks +{ + void *(CJSON_CDECL *allocate)(size_t size); + void (CJSON_CDECL *deallocate)(void *pointer); + void *(CJSON_CDECL *reallocate)(void *pointer, size_t size); +} internal_hooks; + +#if defined(_MSC_VER) +/* work around MSVC error C2322: '...' address of dillimport '...' is not static */ +static void * CJSON_CDECL internal_malloc(size_t size) +{ + return malloc(size); +} +static void CJSON_CDECL internal_free(void *pointer) +{ + free(pointer); +} +static void * CJSON_CDECL internal_realloc(void *pointer, size_t size) +{ + return realloc(pointer, size); +} +#else +#define internal_malloc malloc +#define internal_free free +#define internal_realloc realloc +#endif + +static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc }; + +static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) +{ + size_t length = 0; + unsigned char *copy = NULL; + + if (string == NULL) + { + return NULL; + } + + length = strlen((const char*)string) + sizeof(""); + copy = (unsigned char*)hooks->allocate(length); + if (copy == NULL) + { + return NULL; + } + memcpy(copy, string, length); + + return copy; +} + +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) +{ + if (hooks == NULL) + { + /* Reset hooks */ + global_hooks.allocate = malloc; + global_hooks.deallocate = free; + global_hooks.reallocate = realloc; + return; + } + + global_hooks.allocate = malloc; + if (hooks->malloc_fn != NULL) + { + global_hooks.allocate = hooks->malloc_fn; + } + + global_hooks.deallocate = free; + if (hooks->free_fn != NULL) + { + global_hooks.deallocate = hooks->free_fn; + } + + /* use realloc only if both free and malloc are used */ + global_hooks.reallocate = NULL; + if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) + { + global_hooks.reallocate = realloc; + } +} + +/* Internal constructor. */ +static cJSON *cJSON_New_Item(const internal_hooks * const hooks) +{ + cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON)); + if (node) + { + memset(node, '\0', sizeof(cJSON)); + } + + return node; +} + +/* Delete a cJSON structure. */ +CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) +{ + cJSON *next = NULL; + while (item != NULL) + { + next = item->next; + if (!(item->type & cJSON_IsReference) && (item->child != NULL)) + { + cJSON_Delete(item->child); + } + if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) + { + global_hooks.deallocate(item->valuestring); + } + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { + global_hooks.deallocate(item->string); + } + global_hooks.deallocate(item); + item = next; + } +} + +/* get the decimal point character of the current locale */ +static unsigned char get_decimal_point(void) +{ +#ifdef ENABLE_LOCALES + struct lconv *lconv = localeconv(); + return (unsigned char)lconv->decimal_point[0]; +#else + return '.'; +#endif +} + +typedef struct +{ + const unsigned char *content; + size_t length; + size_t offset; + size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ + internal_hooks hooks; +} parse_buffer; + +/* check if the given size is left to read in a given parse buffer (starting with 1) */ +#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) +/* check if the buffer can be accessed at the given index (starting with 0) */ +#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) +#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) +/* get a pointer to the buffer at the position */ +#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) + +/* Parse the input text to generate a number, and populate the result into item. */ +static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer) +{ + double number = 0; + unsigned char *after_end = NULL; + unsigned char number_c_string[64]; + unsigned char decimal_point = get_decimal_point(); + size_t i = 0; + + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { + return false; + } + + /* copy the number into a temporary buffer and replace '.' with the decimal point + * of the current locale (for strtod) + * This also takes care of '\0' not necessarily being available for marking the end of the input */ + for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) + { + switch (buffer_at_offset(input_buffer)[i]) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '+': + case '-': + case 'e': + case 'E': + number_c_string[i] = buffer_at_offset(input_buffer)[i]; + break; + + case '.': + number_c_string[i] = decimal_point; + break; + + default: + goto loop_end; + } + } +loop_end: + number_c_string[i] = '\0'; + + number = strtod((const char*)number_c_string, (char**)&after_end); + if (number_c_string == after_end) + { + return false; /* parse_error */ + } + + item->valuedouble = number; + + /* use saturation in case of overflow */ + if (number >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (number <= (double)INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)number; + } + + item->type = cJSON_Number; + + input_buffer->offset += (size_t)(after_end - number_c_string); + return true; +} + +/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) +{ + if (number >= INT_MAX) + { + object->valueint = INT_MAX; + } + else if (number <= (double)INT_MIN) + { + object->valueint = INT_MIN; + } + else + { + object->valueint = (int)number; + } + + return object->valuedouble = number; +} + +typedef struct +{ + unsigned char *buffer; + size_t length; + size_t offset; + size_t depth; /* current nesting depth (for formatted printing) */ + cJSON_bool noalloc; + cJSON_bool format; /* is this print a formatted print */ + internal_hooks hooks; +} printbuffer; + +/* realloc printbuffer if necessary to have at least "needed" bytes more */ +static unsigned char* ensure(printbuffer * const p, size_t needed) +{ + unsigned char *newbuffer = NULL; + size_t newsize = 0; + + if ((p == NULL) || (p->buffer == NULL)) + { + return NULL; + } + + if ((p->length > 0) && (p->offset >= p->length)) + { + /* make sure that offset is valid */ + return NULL; + } + + if (needed > INT_MAX) + { + /* sizes bigger than INT_MAX are currently not supported */ + return NULL; + } + + needed += p->offset + 1; + if (needed <= p->length) + { + return p->buffer + p->offset; + } + + if (p->noalloc) { + return NULL; + } + + /* calculate new buffer size */ + if (needed > (INT_MAX / 2)) + { + /* overflow of int, use INT_MAX if possible */ + if (needed <= INT_MAX) + { + newsize = INT_MAX; + } + else + { + return NULL; + } + } + else + { + newsize = needed * 2; + } + + if (p->hooks.reallocate != NULL) + { + /* reallocate with realloc if available */ + newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize); + if (newbuffer == NULL) + { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + } + else + { + /* otherwise reallocate manually */ + newbuffer = (unsigned char*)p->hooks.allocate(newsize); + if (!newbuffer) + { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + if (newbuffer) + { + memcpy(newbuffer, p->buffer, p->offset + 1); + } + p->hooks.deallocate(p->buffer); + } + p->length = newsize; + p->buffer = newbuffer; + + return newbuffer + p->offset; +} + +/* calculate the new length of the string in a printbuffer and update the offset */ +static void update_offset(printbuffer * const buffer) +{ + const unsigned char *buffer_pointer = NULL; + if ((buffer == NULL) || (buffer->buffer == NULL)) + { + return; + } + buffer_pointer = buffer->buffer + buffer->offset; + + buffer->offset += strlen((const char*)buffer_pointer); +} + +/* Render the number nicely from the given item into a string. */ +static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + double d = item->valuedouble; + int length = 0; + size_t i = 0; + unsigned char number_buffer[26]; /* temporary buffer to print the number into */ + unsigned char decimal_point = get_decimal_point(); + double test; + + if (output_buffer == NULL) + { + return false; + } + + /* This checks for NaN and Infinity */ + if ((d * 0) != 0) + { + length = sprintf((char*)number_buffer, "null"); + } + else + { + /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ + length = sprintf((char*)number_buffer, "%1.15g", d); + + /* Check whether the original double can be recovered */ + if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || ((double)test != d)) + { + /* If not, print with 17 decimal places of precision */ + length = sprintf((char*)number_buffer, "%1.17g", d); + } + } + + /* sprintf failed or buffer overrun occured */ + if ((length < 0) || (length >(int)(sizeof(number_buffer) - 1))) + { + return false; + } + + /* reserve appropriate space in the output */ + output_pointer = ensure(output_buffer, (size_t)length + sizeof("")); + if (output_pointer == NULL) + { + return false; + } + + /* copy the printed number to the output and replace locale + * dependent decimal point with '.' */ + for (i = 0; i < ((size_t)length); i++) + { + if (number_buffer[i] == decimal_point) + { + output_pointer[i] = '.'; + continue; + } + + output_pointer[i] = number_buffer[i]; + } + output_pointer[i] = '\0'; + + output_buffer->offset += (size_t)length; + + return true; +} + +/* parse 4 digit hexadecimal number */ +static unsigned parse_hex4(const unsigned char * const input) +{ + unsigned int h = 0; + size_t i = 0; + + for (i = 0; i < 4; i++) + { + /* parse digit */ + if ((input[i] >= '0') && (input[i] <= '9')) + { + h += (unsigned int)input[i] - '0'; + } + else if ((input[i] >= 'A') && (input[i] <= 'F')) + { + h += (unsigned int)10 + input[i] - 'A'; + } + else if ((input[i] >= 'a') && (input[i] <= 'f')) + { + h += (unsigned int)10 + input[i] - 'a'; + } + else /* invalid */ + { + return 0; + } + + if (i < 3) + { + /* shift left to make place for the next nibble */ + h = h << 4; + } + } + + return h; +} + +/* converts a UTF-16 literal to UTF-8 +* A literal can be one or two sequences of the form \uXXXX */ +static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) +{ + long unsigned int codepoint = 0; + unsigned int first_code = 0; + const unsigned char *first_sequence = input_pointer; + unsigned char utf8_length = 0; + unsigned char utf8_position = 0; + unsigned char sequence_length = 0; + unsigned char first_byte_mark = 0; + + if ((input_end - first_sequence) < 6) + { + /* input ends unexpectedly */ + goto fail; + } + + /* get the first utf16 sequence */ + first_code = parse_hex4(first_sequence + 2); + + /* check that the code is valid */ + if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) + { + goto fail; + } + + /* UTF16 surrogate pair */ + if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) + { + const unsigned char *second_sequence = first_sequence + 6; + unsigned int second_code = 0; + sequence_length = 12; /* \uXXXX\uXXXX */ + + if ((input_end - second_sequence) < 6) + { + /* input ends unexpectedly */ + goto fail; + } + + if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) + { + /* missing second half of the surrogate pair */ + goto fail; + } + + /* get the second utf16 sequence */ + second_code = parse_hex4(second_sequence + 2); + /* check that the code is valid */ + if ((second_code < 0xDC00) || (second_code > 0xDFFF)) + { + /* invalid second half of the surrogate pair */ + goto fail; + } + + + /* calculate the unicode codepoint from the surrogate pair */ + codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); + } + else + { + sequence_length = 6; /* \uXXXX */ + codepoint = first_code; + } + + /* encode as UTF-8 + * takes at maximum 4 bytes to encode: + * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + if (codepoint < 0x80) + { + /* normal ascii, encoding 0xxxxxxx */ + utf8_length = 1; + } + else if (codepoint < 0x800) + { + /* two bytes, encoding 110xxxxx 10xxxxxx */ + utf8_length = 2; + first_byte_mark = 0xC0; /* 11000000 */ + } + else if (codepoint < 0x10000) + { + /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ + utf8_length = 3; + first_byte_mark = 0xE0; /* 11100000 */ + } + else if (codepoint <= 0x10FFFF) + { + /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + utf8_length = 4; + first_byte_mark = 0xF0; /* 11110000 */ + } + else + { + /* invalid unicode codepoint */ + goto fail; + } + + /* encode as utf8 */ + for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) + { + /* 10xxxxxx */ + (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); + codepoint >>= 6; + } + /* encode first byte */ + if (utf8_length > 1) + { + (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); + } + else + { + (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); + } + + *output_pointer += utf8_length; + + return sequence_length; + +fail: + return 0; +} + +/* Parse the input text into an unescaped cinput, and populate item. */ +static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer) +{ + const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; + const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; + unsigned char *output_pointer = NULL; + unsigned char *output = NULL; + + /* not a string */ + if (buffer_at_offset(input_buffer)[0] != '\"') + { + goto fail; + } + + { + /* calculate approximate size of the output (overestimate) */ + size_t allocation_length = 0; + size_t skipped_bytes = 0; + while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) + { + /* is escape sequence */ + if (input_end[0] == '\\') + { + if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) + { + /* prevent buffer overflow when last input character is a backslash */ + goto fail; + } + skipped_bytes++; + input_end++; + } + input_end++; + } + if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) + { + goto fail; /* string ended unexpectedly */ + } + + /* This is at most how much we need for the output */ + allocation_length = (size_t)(input_end - buffer_at_offset(input_buffer)) - skipped_bytes; + output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof("")); + if (output == NULL) + { + goto fail; /* allocation failure */ + } + } + + output_pointer = output; + /* loop through the string literal */ + while (input_pointer < input_end) + { + if (*input_pointer != '\\') + { + *output_pointer++ = *input_pointer++; + } + /* escape sequence */ + else + { + unsigned char sequence_length = 2; + if ((input_end - input_pointer) < 1) + { + goto fail; + } + + switch (input_pointer[1]) + { + case 'b': + *output_pointer++ = '\b'; + break; + case 'f': + *output_pointer++ = '\f'; + break; + case 'n': + *output_pointer++ = '\n'; + break; + case 'r': + *output_pointer++ = '\r'; + break; + case 't': + *output_pointer++ = '\t'; + break; + case '\"': + case '\\': + case '/': + *output_pointer++ = input_pointer[1]; + break; + + /* UTF-16 literal */ + case 'u': + sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); + if (sequence_length == 0) + { + /* failed to convert UTF16-literal to UTF-8 */ + goto fail; + } + break; + + default: + goto fail; + } + input_pointer += sequence_length; + } + } + + /* zero terminate the output */ + *output_pointer = '\0'; + + item->type = cJSON_String; + item->valuestring = (char*)output; + + input_buffer->offset = (size_t)(input_end - input_buffer->content); + input_buffer->offset++; + + return true; + +fail: + if (output != NULL) + { + input_buffer->hooks.deallocate(output); + } + + if (input_pointer != NULL) + { + input_buffer->offset = (size_t)(input_pointer - input_buffer->content); + } + + return false; +} + +/* Render the cstring provided to an escaped version that can be printed. */ +static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) +{ + const unsigned char *input_pointer = NULL; + unsigned char *output = NULL; + unsigned char *output_pointer = NULL; + size_t output_length = 0; + /* numbers of additional characters needed for escaping */ + size_t escape_characters = 0; + + if (output_buffer == NULL) + { + return false; + } + + /* empty string */ + if (input == NULL) + { + output = ensure(output_buffer, sizeof("\"\"")); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "\"\""); + + return true; + } + + /* set "flag" to 1 if something needs to be escaped */ + for (input_pointer = input; *input_pointer; input_pointer++) + { + switch (*input_pointer) + { + case '\"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + /* one character escape sequence */ + escape_characters++; + break; + default: + if (*input_pointer < 32) + { + /* UTF-16 escape sequence uXXXX */ + escape_characters += 5; + } + break; + } + } + output_length = (size_t)(input_pointer - input) + escape_characters; + + output = ensure(output_buffer, output_length + sizeof("\"\"")); + if (output == NULL) + { + return false; + } + + /* no characters have to be escaped */ + if (escape_characters == 0) + { + output[0] = '\"'; + memcpy(output + 1, input, output_length); + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; + } + + output[0] = '\"'; + output_pointer = output + 1; + /* copy the string */ + for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) + { + if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) + { + /* normal character, copy */ + *output_pointer = *input_pointer; + } + else + { + /* character needs to be escaped */ + *output_pointer++ = '\\'; + switch (*input_pointer) + { + case '\\': + *output_pointer = '\\'; + break; + case '\"': + *output_pointer = '\"'; + break; + case '\b': + *output_pointer = 'b'; + break; + case '\f': + *output_pointer = 'f'; + break; + case '\n': + *output_pointer = 'n'; + break; + case '\r': + *output_pointer = 'r'; + break; + case '\t': + *output_pointer = 't'; + break; + default: + /* escape and print as unicode codepoint */ + sprintf((char*)output_pointer, "u%04x", *input_pointer); + output_pointer += 4; + break; + } + } + } + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; +} + +/* Invoke print_string_ptr (which is useful) on an item. */ +static cJSON_bool print_string(const cJSON * const item, printbuffer * const p) +{ + return print_string_ptr((unsigned char*)item->valuestring, p); +} + +/* Predeclare these prototypes. */ +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer); + +/* Utility to jump whitespace and cr/lf */ +static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL)) + { + return NULL; + } + + while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) + { + buffer->offset++; + } + + if (buffer->offset == buffer->length) + { + buffer->offset--; + } + + return buffer; +} + +/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ +static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) + { + return NULL; + } + + if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) + { + buffer->offset += 3; + } + + return buffer; +} + +/* Parse an object - create a new root, and populate. */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) +{ + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + cJSON *item = NULL; + + /* reset error position */ + global_error.json = NULL; + global_error.position = 0; + + if (value == NULL) + { + goto fail; + } + + buffer.content = (const unsigned char*)value; + buffer.length = strlen((const char*)value) + sizeof(""); + buffer.offset = 0; + buffer.hooks = global_hooks; + + item = cJSON_New_Item(&global_hooks); + if (item == NULL) /* memory fail */ + { + goto fail; + } + + if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) + { + /* parse failure. ep is set. */ + goto fail; + } + + /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ + if (require_null_terminated) + { + buffer_skip_whitespace(&buffer); + if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') + { + goto fail; + } + } + if (return_parse_end) + { + *return_parse_end = (const char*)buffer_at_offset(&buffer); + } + + return item; + +fail: + if (item != NULL) + { + cJSON_Delete(item); + } + + if (value != NULL) + { + error local_error; + local_error.json = (const unsigned char*)value; + local_error.position = 0; + + if (buffer.offset < buffer.length) + { + local_error.position = buffer.offset; + } + else if (buffer.length > 0) + { + local_error.position = buffer.length - 1; + } + + if (return_parse_end != NULL) + { + *return_parse_end = (const char*)local_error.json + local_error.position; + } + + global_error = local_error; + } + + return NULL; +} + +/* Default options for cJSON_Parse */ +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) +{ + return cJSON_ParseWithOpts(value, 0, 0); +} + +#define cjson_min(a, b) ((a < b) ? a : b) + +static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) +{ + static const size_t default_buffer_size = 256; + printbuffer buffer[1]; + unsigned char *printed = NULL; + + memset(buffer, 0, sizeof(buffer)); + + /* create buffer */ + buffer->buffer = (unsigned char*)hooks->allocate(default_buffer_size); + buffer->length = default_buffer_size; + buffer->format = format; + buffer->hooks = *hooks; + if (buffer->buffer == NULL) + { + goto fail; + } + + /* print the value */ + if (!print_value(item, buffer)) + { + goto fail; + } + update_offset(buffer); + + /* check if reallocate is available */ + if (hooks->reallocate != NULL) + { + printed = (unsigned char*)hooks->reallocate(buffer->buffer, buffer->offset + 1); + if (printed == NULL) { + goto fail; + } + buffer->buffer = NULL; + } + else /* otherwise copy the JSON over to a new buffer */ + { + printed = (unsigned char*)hooks->allocate(buffer->offset + 1); + if (printed == NULL) + { + goto fail; + } + memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); + printed[buffer->offset] = '\0'; /* just to be sure */ + + /* free the buffer */ + hooks->deallocate(buffer->buffer); + } + + return printed; + +fail: + if (buffer->buffer != NULL) + { + hooks->deallocate(buffer->buffer); + } + + if (printed != NULL) + { + hooks->deallocate(printed); + } + + return NULL; +} + +/* Render a cJSON item/entity/structure to text. */ +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) +{ + return (char*)print(item, true, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) +{ + return (char*)print(item, false, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if (prebuffer < 0) + { + return NULL; + } + + p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); + if (!p.buffer) + { + return NULL; + } + + p.length = (size_t)prebuffer; + p.offset = 0; + p.noalloc = false; + p.format = fmt; + p.hooks = global_hooks; + + if (!print_value(item, &p)) + { + global_hooks.deallocate(p.buffer); + return NULL; + } + + return (char*)p.buffer; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cJSON_bool fmt) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if ((len < 0) || (buf == NULL)) + { + return false; + } + + p.buffer = (unsigned char*)buf; + p.length = (size_t)len; + p.offset = 0; + p.noalloc = true; + p.format = fmt; + p.hooks = global_hooks; + + return print_value(item, &p); +} + +/* Parser core - when encountering text, process appropriately. */ +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer) +{ + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { + return false; /* no input */ + } + + /* parse the different types of values */ + /* null */ + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0)) + { + item->type = cJSON_NULL; + input_buffer->offset += 4; + return true; + } + /* false */ + if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0)) + { + item->type = cJSON_False; + input_buffer->offset += 5; + return true; + } + /* true */ + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0)) + { + item->type = cJSON_True; + item->valueint = 1; + input_buffer->offset += 4; + return true; + } + /* string */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) + { + return parse_string(item, input_buffer); + } + /* number */ + if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) + { + return parse_number(item, input_buffer); + } + /* array */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) + { + return parse_array(item, input_buffer); + } + /* object */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) + { + return parse_object(item, input_buffer); + } + + return false; +} + +/* Render a value to text. */ +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output = NULL; + + if ((item == NULL) || (output_buffer == NULL)) + { + return false; + } + + switch ((item->type) & 0xFF) + { + case cJSON_NULL: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "null"); + return true; + + case cJSON_False: + output = ensure(output_buffer, 6); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "false"); + return true; + + case cJSON_True: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "true"); + return true; + + case cJSON_Number: + return print_number(item, output_buffer); + + case cJSON_Raw: + { + size_t raw_length = 0; + if (item->valuestring == NULL) + { + return false; + } + + raw_length = strlen(item->valuestring) + sizeof(""); + output = ensure(output_buffer, raw_length); + if (output == NULL) + { + return false; + } + memcpy(output, item->valuestring, raw_length); + return true; + } + + case cJSON_String: + return print_string(item, output_buffer); + + case cJSON_Array: + return print_array(item, output_buffer); + + case cJSON_Object: + return print_object(item, output_buffer); + + default: + return false; + } +} + +/* Build an array from input text. */ +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer) +{ + cJSON *head = NULL; /* head of the linked list */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) + { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (buffer_at_offset(input_buffer)[0] != '[') + { + /* not an array */ + goto fail; + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) + { + /* empty array */ + goto success; + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse next value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) + { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') + { + goto fail; /* expected end of array */ + } + +success: + input_buffer->depth--; + + item->type = cJSON_Array; + item->child = head; + + input_buffer->offset++; + + return true; + +fail: + if (head != NULL) + { + cJSON_Delete(head); + } + + return false; +} + +/* Render an array to text */ +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_element = item->child; + + if (output_buffer == NULL) + { + return false; + } + + /* Compose the output array. */ + /* opening square bracket */ + output_pointer = ensure(output_buffer, 1); + if (output_pointer == NULL) + { + return false; + } + + *output_pointer = '['; + output_buffer->offset++; + output_buffer->depth++; + + while (current_element != NULL) + { + if (!print_value(current_element, output_buffer)) + { + return false; + } + update_offset(output_buffer); + if (current_element->next) + { + length = (size_t)(output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ','; + if (output_buffer->format) + { + *output_pointer++ = ' '; + } + *output_pointer = '\0'; + output_buffer->offset += length; + } + current_element = current_element->next; + } + + output_pointer = ensure(output_buffer, 2); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ']'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Build an object from the text. */ +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer) +{ + cJSON *head = NULL; /* linked list head */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) + { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) + { + goto fail; /* not an object */ + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) + { + goto success; /* empty object */ + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse the name of the child */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_string(current_item, input_buffer)) + { + goto fail; /* faile to parse name */ + } + buffer_skip_whitespace(input_buffer); + + /* swap valuestring and string, because we parsed the name */ + current_item->string = current_item->valuestring; + current_item->valuestring = NULL; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) + { + goto fail; /* invalid object */ + } + + /* parse the value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) + { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) + { + goto fail; /* expected end of object */ + } + +success: + input_buffer->depth--; + + item->type = cJSON_Object; + item->child = head; + + input_buffer->offset++; + return true; + +fail: + if (head != NULL) + { + cJSON_Delete(head); + } + + return false; +} + +/* Render an object to text. */ +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_item = item->child; + + if (output_buffer == NULL) + { + return false; + } + + /* Compose the output: */ + length = (size_t)(output_buffer->format ? 2 : 1); /* fmt: {\n */ + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + + *output_pointer++ = '{'; + output_buffer->depth++; + if (output_buffer->format) + { + *output_pointer++ = '\n'; + } + output_buffer->offset += length; + + while (current_item) + { + if (output_buffer->format) + { + size_t i; + output_pointer = ensure(output_buffer, output_buffer->depth); + if (output_pointer == NULL) + { + return false; + } + for (i = 0; i < output_buffer->depth; i++) + { + *output_pointer++ = '\t'; + } + output_buffer->offset += output_buffer->depth; + } + + /* print key */ + if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) + { + return false; + } + update_offset(output_buffer); + + length = (size_t)(output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ':'; + if (output_buffer->format) + { + *output_pointer++ = '\t'; + } + output_buffer->offset += length; + + /* print value */ + if (!print_value(current_item, output_buffer)) + { + return false; + } + update_offset(output_buffer); + + /* print comma if not last */ + length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0)); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + if (current_item->next) + { + *output_pointer++ = ','; + } + + if (output_buffer->format) + { + *output_pointer++ = '\n'; + } + *output_pointer = '\0'; + output_buffer->offset += length; + + current_item = current_item->next; + } + + output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); + if (output_pointer == NULL) + { + return false; + } + if (output_buffer->format) + { + size_t i; + for (i = 0; i < (output_buffer->depth - 1); i++) + { + *output_pointer++ = '\t'; + } + } + *output_pointer++ = '}'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Get Array size/item / object item. */ +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) +{ + cJSON *child = NULL; + size_t size = 0; + + if (array == NULL) + { + return 0; + } + + child = array->child; + + while (child != NULL) + { + size++; + child = child->next; + } + + /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ + + return (int)size; +} + +static cJSON* get_array_item(const cJSON *array, size_t index) +{ + cJSON *current_child = NULL; + + if (array == NULL) + { + return NULL; + } + + current_child = array->child; + while ((current_child != NULL) && (index > 0)) + { + index--; + current_child = current_child->next; + } + + return current_child; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) +{ + if (index < 0) + { + return NULL; + } + + return get_array_item(array, (size_t)index); +} + +static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) +{ + cJSON *current_element = NULL; + + if ((object == NULL) || (name == NULL)) + { + return NULL; + } + + current_element = object->child; + if (case_sensitive) + { + while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0)) + { + current_element = current_element->next; + } + } + else + { + while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) + { + current_element = current_element->next; + } + } + + if ((current_element == NULL) || (current_element->string == NULL)) { + return NULL; + } + + return current_element; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, false); +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, true); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) +{ + return cJSON_GetObjectItem(object, string) ? 1 : 0; +} + +/* Utility for array list handling. */ +static void suffix_object(cJSON *prev, cJSON *item) +{ + prev->next = item; + item->prev = prev; +} + +/* Utility for handling references. */ +static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) +{ + cJSON *reference = NULL; + if (item == NULL) + { + return NULL; + } + + reference = cJSON_New_Item(hooks); + if (reference == NULL) + { + return NULL; + } + + memcpy(reference, item, sizeof(cJSON)); + reference->string = NULL; + reference->type |= cJSON_IsReference; + reference->next = reference->prev = NULL; + return reference; +} + +static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) +{ + cJSON *child = NULL; + + if ((item == NULL) || (array == NULL)) + { + return false; + } + + child = array->child; + + if (child == NULL) + { + /* list is empty, start new one */ + array->child = item; + } + else + { + /* append to the end */ + while (child->next) + { + child = child->next; + } + suffix_object(child, item); + } + + return true; +} + +/* Add item to array/object. */ +CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item) +{ + add_item_to_array(array, item); +} + +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) +#pragma GCC diagnostic push +#endif +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif +/* helper function to cast away const */ +static void* cast_away_const(const void* string) +{ + return (void*)string; +} +#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) +#pragma GCC diagnostic pop +#endif + + +static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key) +{ + char *new_key = NULL; + int new_type = cJSON_Invalid; + + if ((object == NULL) || (string == NULL) || (item == NULL)) + { + return false; + } + + if (constant_key) + { + new_key = (char*)cast_away_const(string); + new_type = item->type | cJSON_StringIsConst; + } + else + { + new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks); + if (new_key == NULL) + { + return false; + } + + new_type = item->type & ~cJSON_StringIsConst; + } + + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { + hooks->deallocate(item->string); + } + + item->string = new_key; + item->type = new_type; + + return add_item_to_array(object, item); +} + +CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) +{ + add_item_to_object(object, string, item, &global_hooks, false); +} + +/* Add an item to an object with constant string as key */ +CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) +{ + add_item_to_object(object, string, item, &global_hooks, true); +} + +CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) +{ + if (array == NULL) + { + return; + } + + add_item_to_array(array, create_reference(item, &global_hooks)); +} + +CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) +{ + if ((object == NULL) || (string == NULL)) + { + return; + } + + add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); +} + +CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name) +{ + cJSON *null = cJSON_CreateNull(); + if (add_item_to_object(object, name, null, &global_hooks, false)) + { + return null; + } + + cJSON_Delete(null); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name) +{ + cJSON *true_item = cJSON_CreateTrue(); + if (add_item_to_object(object, name, true_item, &global_hooks, false)) + { + return true_item; + } + + cJSON_Delete(true_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name) +{ + cJSON *false_item = cJSON_CreateFalse(); + if (add_item_to_object(object, name, false_item, &global_hooks, false)) + { + return false_item; + } + + cJSON_Delete(false_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean) +{ + cJSON *bool_item = cJSON_CreateBool(boolean); + if (add_item_to_object(object, name, bool_item, &global_hooks, false)) + { + return bool_item; + } + + cJSON_Delete(bool_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) +{ + cJSON *number_item = cJSON_CreateNumber(number); + if (add_item_to_object(object, name, number_item, &global_hooks, false)) + { + return number_item; + } + + cJSON_Delete(number_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string) +{ + cJSON *string_item = cJSON_CreateString(string); + if (add_item_to_object(object, name, string_item, &global_hooks, false)) + { + return string_item; + } + + cJSON_Delete(string_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw) +{ + cJSON *raw_item = cJSON_CreateRaw(raw); + if (add_item_to_object(object, name, raw_item, &global_hooks, false)) + { + return raw_item; + } + + cJSON_Delete(raw_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name) +{ + cJSON *object_item = cJSON_CreateObject(); + if (add_item_to_object(object, name, object_item, &global_hooks, false)) + { + return object_item; + } + + cJSON_Delete(object_item); + return NULL; +} + +CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name) +{ + cJSON *array = cJSON_CreateArray(); + if (add_item_to_object(object, name, array, &global_hooks, false)) + { + return array; + } + + cJSON_Delete(array); + return NULL; +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) +{ + if ((parent == NULL) || (item == NULL)) + { + return NULL; + } + + if (item->prev != NULL) + { + /* not the first element */ + item->prev->next = item->next; + } + if (item->next != NULL) + { + /* not the last element */ + item->next->prev = item->prev; + } + + if (item == parent->child) + { + /* first element */ + parent->child = item->next; + } + /* make sure the detached item doesn't point anywhere anymore */ + item->prev = NULL; + item->next = NULL; + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) +{ + if (which < 0) + { + return NULL; + } + + return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) +{ + cJSON_Delete(cJSON_DetachItemFromArray(array, which)); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItem(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObject(object, string)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); +} + +/* Replace array/object items with new ones. */ +CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) +{ + cJSON *after_inserted = NULL; + + if (which < 0) + { + return; + } + + after_inserted = get_array_item(array, (size_t)which); + if (after_inserted == NULL) + { + add_item_to_array(array, newitem); + return; + } + + newitem->next = after_inserted; + newitem->prev = after_inserted->prev; + after_inserted->prev = newitem; + if (after_inserted == array->child) + { + array->child = newitem; + } + else + { + newitem->prev->next = newitem; + } +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) +{ + if ((parent == NULL) || (replacement == NULL) || (item == NULL)) + { + return false; + } + + if (replacement == item) + { + return true; + } + + replacement->next = item->next; + replacement->prev = item->prev; + + if (replacement->next != NULL) + { + replacement->next->prev = replacement; + } + if (replacement->prev != NULL) + { + replacement->prev->next = replacement; + } + if (parent->child == item) + { + parent->child = replacement; + } + + item->next = NULL; + item->prev = NULL; + cJSON_Delete(item); + + return true; +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) +{ + if (which < 0) + { + return; + } + + cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); +} + +static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) +{ + if ((replacement == NULL) || (string == NULL)) + { + return false; + } + + /* replace the name in the replacement */ + if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL)) + { + cJSON_free(replacement->string); + } + replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + replacement->type &= ~cJSON_StringIsConst; + + cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); + + return true; +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) +{ + replace_item_in_object(object, string, newitem, false); +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) +{ + replace_item_in_object(object, string, newitem, true); +} + +/* Create basic types: */ +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) + { + item->type = cJSON_NULL; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) + { + item->type = cJSON_True; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) + { + item->type = cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool b) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) + { + item->type = b ? cJSON_True : cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) + { + item->type = cJSON_Number; + item->valuedouble = num; + + /* use saturation in case of overflow */ + if (num >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (num <= (double)INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)num; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) + { + item->type = cJSON_String; + item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + if (!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) + { + item->type = cJSON_String | cJSON_IsReference; + item->valuestring = (char*)cast_away_const(string); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Object | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { + cJSON *item = cJSON_New_Item(&global_hooks); + if (item != NULL) { + item->type = cJSON_Array | cJSON_IsReference; + item->child = (cJSON*)cast_away_const(child); + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) + { + item->type = cJSON_Raw; + item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); + if (!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) + { + item->type = cJSON_Array; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) + { + item->type = cJSON_Object; + } + + return item; +} + +/* Create Arrays: */ +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + for (i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if (!n) + { + cJSON_Delete(a); + return NULL; + } + if (!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for (i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber((double)numbers[i]); + if (!n) + { + cJSON_Delete(a); + return NULL; + } + if (!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for (i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if (!n) + { + cJSON_Delete(a); + return NULL; + } + if (!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (strings == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for (i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateString(strings[i]); + if (!n) + { + cJSON_Delete(a); + return NULL; + } + if (!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +/* Duplication */ +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) +{ + cJSON *newitem = NULL; + cJSON *child = NULL; + cJSON *next = NULL; + cJSON *newchild = NULL; + + /* Bail on bad ptr */ + if (!item) + { + goto fail; + } + /* Create new item */ + newitem = cJSON_New_Item(&global_hooks); + if (!newitem) + { + goto fail; + } + /* Copy over all vars */ + newitem->type = item->type & (~cJSON_IsReference); + newitem->valueint = item->valueint; + newitem->valuedouble = item->valuedouble; + if (item->valuestring) + { + newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); + if (!newitem->valuestring) + { + goto fail; + } + } + if (item->string) + { + newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); + if (!newitem->string) + { + goto fail; + } + } + /* If non-recursive, then we're done! */ + if (!recurse) + { + return newitem; + } + /* Walk the ->next chain for the child. */ + child = item->child; + while (child != NULL) + { + newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ + if (!newchild) + { + goto fail; + } + if (next != NULL) + { + /* If newitem->child already set, then crosswire ->prev and ->next and move on */ + next->next = newchild; + newchild->prev = next; + next = newchild; + } + else + { + /* Set newitem->child and move to it */ + newitem->child = newchild; + next = newchild; + } + child = child->next; + } + + return newitem; + +fail: + if (newitem != NULL) + { + cJSON_Delete(newitem); + } + + return NULL; +} + +CJSON_PUBLIC(void) cJSON_Minify(char *json) +{ + unsigned char *into = (unsigned char*)json; + + if (json == NULL) + { + return; + } + + while (*json) + { + if (*json == ' ') + { + json++; + } + else if (*json == '\t') + { + /* Whitespace characters. */ + json++; + } + else if (*json == '\r') + { + json++; + } + else if (*json == '\n') + { + json++; + } + else if ((*json == '/') && (json[1] == '/')) + { + /* double-slash comments, to end of line. */ + while (*json && (*json != '\n')) + { + json++; + } + } + else if ((*json == '/') && (json[1] == '*')) + { + /* multiline comments. */ + while (*json && !((*json == '*') && (json[1] == '/'))) + { + json++; + } + json += 2; + } + else if (*json == '\"') + { + /* string literals, which are \" sensitive. */ + *into++ = (unsigned char)*json++; + while (*json && (*json != '\"')) + { + if (*json == '\\') + { + *into++ = (unsigned char)*json++; + } + *into++ = (unsigned char)*json++; + } + *into++ = (unsigned char)*json++; + } + else + { + /* All other characters. */ + *into++ = (unsigned char)*json++; + } + } + + /* and null-terminate. */ + *into = '\0'; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Invalid; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_False; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xff) == cJSON_True; +} + + +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & (cJSON_True | cJSON_False)) != 0; +} +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_NULL; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Number; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_String; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Array; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Object; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Raw; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) +{ + if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) + { + return false; + } + + /* check if type is valid */ + switch (a->type & 0xFF) + { + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + case cJSON_Number: + case cJSON_String: + case cJSON_Raw: + case cJSON_Array: + case cJSON_Object: + break; + + default: + return false; + } + + /* identical objects are equal */ + if (a == b) + { + return true; + } + + switch (a->type & 0xFF) + { + /* in these cases and equal type is enough */ + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + return true; + + case cJSON_Number: + if (a->valuedouble == b->valuedouble) + { + return true; + } + return false; + + case cJSON_String: + case cJSON_Raw: + if ((a->valuestring == NULL) || (b->valuestring == NULL)) + { + return false; + } + if (strcmp(a->valuestring, b->valuestring) == 0) + { + return true; + } + + return false; + + case cJSON_Array: + { + cJSON *a_element = a->child; + cJSON *b_element = b->child; + + for (; (a_element != NULL) && (b_element != NULL);) + { + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return false; + } + + a_element = a_element->next; + b_element = b_element->next; + } + + /* one of the arrays is longer than the other */ + if (a_element != b_element) { + return false; + } + + return true; + } + + case cJSON_Object: + { + cJSON *a_element = NULL; + cJSON *b_element = NULL; + cJSON_ArrayForEach(a_element, a) + { + /* TODO This has O(n^2) runtime, which is horrible! */ + b_element = get_object_item(b, a_element->string, case_sensitive); + if (b_element == NULL) + { + return false; + } + + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return false; + } + } + + /* doing this twice, once on a and b to prevent true comparison if a subset of b + * TODO: Do this the proper way, this is just a fix for now */ + cJSON_ArrayForEach(b_element, b) + { + a_element = get_object_item(a, b_element->string, case_sensitive); + if (a_element == NULL) + { + return false; + } + + if (!cJSON_Compare(b_element, a_element, case_sensitive)) + { + return false; + } + } + + return true; + } + + default: + return false; + } +} + +CJSON_PUBLIC(void *) cJSON_malloc(size_t size) +{ + return global_hooks.allocate(size); +} + +CJSON_PUBLIC(void) cJSON_free(void *object) +{ + global_hooks.deallocate(object); +} diff --git a/code/application/source/sf_app/code/source/sf_lpa/Extra/cJSON/cJSON.h b/code/application/source/sf_app/code/source/sf_lpa/Extra/cJSON/cJSON.h new file mode 100755 index 000000000..eaee3ef68 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/Extra/cJSON/cJSON.h @@ -0,0 +1,285 @@ +/* +Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef cJSON__h +#define cJSON__h + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) +#define __WINDOWS__ +#endif + +#ifdef __WINDOWS__ + + /* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options: + + CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols + CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) + CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol + + For *nix builds that support visibility attribute, you can define similar behavior by + + setting default visibility to hidden by adding + -fvisibility=hidden (for gcc) + or + -xldscope=hidden (for sun cc) + to CFLAGS + + then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does + + */ + +#define CJSON_CDECL __cdecl +#define CJSON_STDCALL __stdcall + + /* export symbols by default, this is necessary for copy pasting the C and header file */ +#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_EXPORT_SYMBOLS +#endif + +#if defined(CJSON_HIDE_SYMBOLS) +#define CJSON_PUBLIC(type) type CJSON_STDCALL +#elif defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL +#elif defined(CJSON_IMPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL +#endif +#else /* !__WINDOWS__ */ +#define CJSON_CDECL +#define CJSON_STDCALL + +#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) +#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type +#else +#define CJSON_PUBLIC(type) type +#endif +#endif + + /* project version */ +#define CJSON_VERSION_MAJOR 1 +#define CJSON_VERSION_MINOR 7 +#define CJSON_VERSION_PATCH 10 + +#include + + /* cJSON Types: */ +#define cJSON_Invalid (0) +#define cJSON_False (1 << 0) +#define cJSON_True (1 << 1) +#define cJSON_NULL (1 << 2) +#define cJSON_Number (1 << 3) +#define cJSON_String (1 << 4) +#define cJSON_Array (1 << 5) +#define cJSON_Object (1 << 6) +#define cJSON_Raw (1 << 7) /* raw json */ + +#define cJSON_IsReference 256 +#define cJSON_StringIsConst 512 + + /* The cJSON structure: */ + typedef struct cJSON + { + /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *next; + struct cJSON *prev; + /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ + struct cJSON *child; + + /* The type of the item, as above. */ + int type; + + /* The item's string, if type==cJSON_String and type == cJSON_Raw */ + char *valuestring; + /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ + int valueint; + /* The item's number, if type==cJSON_Number */ + double valuedouble; + + /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ + char *string; + } cJSON; + + typedef struct cJSON_Hooks + { + /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ + void *(CJSON_CDECL *malloc_fn)(size_t sz); + void (CJSON_CDECL *free_fn)(void *ptr); + } cJSON_Hooks; + + typedef int cJSON_bool; + + /* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. + * This is to prevent stack overflows. */ +#ifndef CJSON_NESTING_LIMIT +#define CJSON_NESTING_LIMIT 1000 +#endif + + /* returns the version of cJSON as a string */ + CJSON_PUBLIC(const char*) cJSON_Version(void); + + /* Supply malloc, realloc and free functions to cJSON */ + CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); + + /* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ + /* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ + CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); + /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ + /* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ + CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); + + /* Render a cJSON entity to text for transfer/storage. */ + CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); + /* Render a cJSON entity to text for transfer/storage without any formatting. */ + CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); + /* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ + CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); + /* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ + /* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ + CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); + /* Delete a cJSON entity and all subentities. */ + CJSON_PUBLIC(void) cJSON_Delete(cJSON *c); + + /* Returns the number of items in an array (or object). */ + CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); + /* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ + CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); + /* Get item "string" from object. Case insensitive. */ + CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); + CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); + CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); + /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ + CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); + + /* Check if the item is a string and return its valuestring */ + CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item); + + /* These functions check the type of an item */ + CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); + CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); + CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); + CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); + CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); + CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); + CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); + CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); + CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); + CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); + + /* These calls create a cJSON item of the appropriate type. */ + CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); + CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); + CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); + CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); + CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); + CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); + /* raw json */ + CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); + CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); + CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); + + /* Create a string where valuestring references a string so + * it will not be freed by cJSON_Delete */ + CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); + /* Create an object/arrray that only references it's elements so + * they will not be freed by cJSON_Delete */ + CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); + CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); + + /* These utilities create an Array of count items. */ + CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); + CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); + CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); + CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count); + + /* Append item to the specified array/object. */ + CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item); + CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); + /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. + * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before + * writing to `item->string` */ + CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); + /* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ + CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); + CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); + + /* Remove/Detatch items from Arrays/Objects. */ + CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); + CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); + CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); + CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); + CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); + CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); + CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); + + /* Update array items. */ + CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ + CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); + CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); + CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem); + CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem); + + /* Duplicate a cJSON item */ + CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); + /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will + need to be released. With recurse!=0, it will duplicate any children connected to the item. + The item->next and ->prev pointers are always zero on return from Duplicate. */ + /* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. + * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ + CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); + + + CJSON_PUBLIC(void) cJSON_Minify(char *json); + + /* Helper functions for creating and adding items to an object at the same time. + * They return the added item or NULL on failure. */ + CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); + CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); + CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); + CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); + CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); + CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); + CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); + CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); + CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name); + + /* When assigning an integer value, it needs to be propagated to valuedouble too. */ +#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) + /* helper for the cJSON_SetNumberValue macro */ + CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); +#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) + + /* Macro for iterating over an array or object */ +#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) + + /* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ + CJSON_PUBLIC(void *) cJSON_malloc(size_t size); + CJSON_PUBLIC(void) cJSON_free(void *object); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/code/application/source/sf_app/code/source/sf_lpa/Extra/sha256/sha-256.c b/code/application/source/sf_app/code/source/sf_lpa/Extra/sha256/sha-256.c new file mode 100755 index 000000000..0f3149fb9 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/Extra/sha256/sha-256.c @@ -0,0 +1,242 @@ + +// Source code from https://github.com/amosnier/sha-2 +// License : https://github.com/amosnier/sha-2/blob/master/LICENSE + +/* +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to +*/ + + +#include +#include + +#include "sha-256.h" + +#define CHUNK_SIZE 64 +#define TOTAL_LEN_LEN 8 + +/* + * ABOUT bool: this file does not use bool in order to be as pre-C99 compatible as possible. + */ + +/* + * Comments from pseudo-code at https://en.wikipedia.org/wiki/SHA-2 are reproduced here. + * When useful for clarification, portions of the pseudo-code are reproduced here too. + */ + +/* + * Initialize array of round constants: + * (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311): + */ +static const uint32_t k[] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +struct buffer_state { + const uint8_t * p; + size_t len; + size_t total_len; + int single_one_delivered; /* bool */ + int total_len_delivered; /* bool */ +}; + +static /*inline*/ uint32_t right_rot(uint32_t value, unsigned int count) +{ + /* + * Defined behaviour in standard C for all count where 0 < count < 32, + * which is what we need here. + */ + return value >> count | value << (32 - count); +} + +static void init_buf_state(struct buffer_state * state, const void * input, size_t len) +{ + state->p = input; + state->len = len; + state->total_len = len; + state->single_one_delivered = 0; + state->total_len_delivered = 0; +} + +/* Return value: bool */ +static int calc_chunk(uint8_t chunk[CHUNK_SIZE], struct buffer_state * state) +{ + size_t space_in_chunk; + + if (state->total_len_delivered) { + return 0; + } + + if (state->len >= CHUNK_SIZE) { + memcpy(chunk, state->p, CHUNK_SIZE); + state->p += CHUNK_SIZE; + state->len -= CHUNK_SIZE; + return 1; + } + + memcpy(chunk, state->p, state->len); + chunk += state->len; + space_in_chunk = CHUNK_SIZE - state->len; + state->p += state->len; + state->len = 0; + + /* If we are here, space_in_chunk is one at minimum. */ + if (!state->single_one_delivered) { + *chunk++ = 0x80; + space_in_chunk -= 1; + state->single_one_delivered = 1; + } + + /* + * Now: + * - either there is enough space left for the total length, and we can conclude, + * - or there is too little space left, and we have to pad the rest of this chunk with zeroes. + * In the latter case, we will conclude at the next invokation of this function. + */ + if (space_in_chunk >= TOTAL_LEN_LEN) { + const size_t left = space_in_chunk - TOTAL_LEN_LEN; + size_t len = state->total_len; + int i; + memset(chunk, 0x00, left); + chunk += left; + + /* Storing of len * 8 as a big endian 64-bit without overflow. */ + chunk[7] = (uint8_t) (len << 3); + len >>= 5; + for (i = 6; i >= 0; i--) { + chunk[i] = (uint8_t) len; + len >>= 8; + } + state->total_len_delivered = 1; + } else { + memset(chunk, 0x00, space_in_chunk); + } + + return 1; +} + +/* + * Limitations: + * - Since input is a pointer in RAM, the data to hash should be in RAM, which could be a problem + * for large data sizes. + * - SHA algorithms theoretically operate on bit strings. However, this implementation has no support + * for bit string lengths that are not multiples of eight, and it really operates on arrays of bytes. + * In particular, the len parameter is a number of bytes. + */ +void calc_sha_256(uint8_t hash[32], const void * input, size_t len) +{ + /* + * Note 1: All integers (expect indexes) are 32-bit unsigned integers and addition is calculated modulo 2^32. + * Note 2: For each round, there is one round constant k[i] and one entry in the message schedule array w[i], 0 = i = 63 + * Note 3: The compression function uses 8 working variables, a through h + * Note 4: Big-endian convention is used when expressing the constants in this pseudocode, + * and when parsing message block data from bytes to words, for example, + * the first word of the input message "abc" after padding is 0x61626380 + */ + + /* + * Initialize hash values: + * (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19): + */ + uint32_t h[] = { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 }; + int i, j; + + /* 512-bit chunks is what we will operate on. */ + uint8_t chunk[64]; + + struct buffer_state state; + + init_buf_state(&state, input, len); + + while (calc_chunk(chunk, &state)) { + uint32_t ah[8]; + + /* + * create a 64-entry message schedule array w[0..63] of 32-bit words + * (The initial values in w[0..63] don't matter, so many implementations zero them here) + * copy chunk into first 16 words w[0..15] of the message schedule array + */ + uint32_t w[64]; + const uint8_t *p = chunk; + + memset(w, 0x00, sizeof w); + for (i = 0; i < 16; i++) { + w[i] = (uint32_t) p[0] << 24 | (uint32_t) p[1] << 16 | + (uint32_t) p[2] << 8 | (uint32_t) p[3]; + p += 4; + } + + /* Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array: */ + for (i = 16; i < 64; i++) { + const uint32_t s0 = right_rot(w[i - 15], 7) ^ right_rot(w[i - 15], 18) ^ (w[i - 15] >> 3); + const uint32_t s1 = right_rot(w[i - 2], 17) ^ right_rot(w[i - 2], 19) ^ (w[i - 2] >> 10); + w[i] = w[i - 16] + s0 + w[i - 7] + s1; + } + + /* Initialize working variables to current hash value: */ + for (i = 0; i < 8; i++) + ah[i] = h[i]; + + /* Compression function main loop: */ + for (i = 0; i < 64; i++) { + const uint32_t s1 = right_rot(ah[4], 6) ^ right_rot(ah[4], 11) ^ right_rot(ah[4], 25); + const uint32_t ch = (ah[4] & ah[5]) ^ (~ah[4] & ah[6]); + const uint32_t temp1 = ah[7] + s1 + ch + k[i] + w[i]; + const uint32_t s0 = right_rot(ah[0], 2) ^ right_rot(ah[0], 13) ^ right_rot(ah[0], 22); + const uint32_t maj = (ah[0] & ah[1]) ^ (ah[0] & ah[2]) ^ (ah[1] & ah[2]); + const uint32_t temp2 = s0 + maj; + + ah[7] = ah[6]; + ah[6] = ah[5]; + ah[5] = ah[4]; + ah[4] = ah[3] + temp1; + ah[3] = ah[2]; + ah[2] = ah[1]; + ah[1] = ah[0]; + ah[0] = temp1 + temp2; + } + + /* Add the compressed chunk to the current hash value: */ + for (i = 0; i < 8; i++) + h[i] += ah[i]; + } + + /* Produce the final hash value (big-endian): */ + for (i = 0, j = 0; i < 8; i++) + { + hash[j++] = (uint8_t) (h[i] >> 24); + hash[j++] = (uint8_t) (h[i] >> 16); + hash[j++] = (uint8_t) (h[i] >> 8); + hash[j++] = (uint8_t) h[i]; + } +} diff --git a/code/application/source/sf_app/code/source/sf_lpa/Extra/sha256/sha-256.h b/code/application/source/sf_app/code/source/sf_lpa/Extra/sha256/sha-256.h new file mode 100755 index 000000000..546079241 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/Extra/sha256/sha-256.h @@ -0,0 +1,31 @@ +// Source code from https://github.com/amosnier/sha-2 +// License : https://github.com/amosnier/sha-2/blob/master/LICENSE + +/* +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to +*/ + +void calc_sha_256(uint8_t hash[32], const void *input, size_t len); \ No newline at end of file diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/base64/base64.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/base64/base64.h new file mode 100755 index 000000000..c700c7f67 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/base64/base64.h @@ -0,0 +1,44 @@ +/* + base64.c - by Joe DF (joedf@ahkscript.org) + Released under the MIT License + + Revision: 2015-06-12 01:26:51 + + Thank you for inspiration: + http://www.codeproject.com/Tips/813146/Fast-base-functions-for-encode-decode +*/ + +#include + +//Base64 char table function - used internally for decoding +unsigned int b64_int(unsigned int ch); + +// in_size : the number bytes to be encoded. +// Returns the recommended memory size to be allocated for the output buffer excluding the null byte +unsigned int b64e_size(unsigned int in_size); + +// in_size : the number bytes to be decoded. +// Returns the recommended memory size to be allocated for the output buffer +unsigned int b64d_size(unsigned int in_size); + +// in : buffer of "raw" binary to be encoded. +// in_len : number of bytes to be encoded. +// out : pointer to buffer with enough memory, user is responsible for memory allocation, receives null-terminated string +// returns size of output including null byte +unsigned int b64_encode(const unsigned char* in, unsigned int in_len, unsigned char* out); + +// in : buffer of base64 string to be decoded. +// in_len : number of bytes to be decoded. +// out : pointer to buffer with enough memory, user is responsible for memory allocation, receives "raw" binary +// returns size of output excluding null byte +unsigned int b64_decode(const unsigned char* in, unsigned int in_len, unsigned char* out); + +// file-version b64_encode +// Input : filenames +// returns size of output +unsigned int b64_encodef(char *InFile, char *OutFile); + +// file-version b64_decode +// Input : filenames +// returns size of output +unsigned int b64_decodef(char *InFile, char *OutFile); \ No newline at end of file diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/cJSON/cJSON.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/cJSON/cJSON.h new file mode 100755 index 000000000..eaee3ef68 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/cJSON/cJSON.h @@ -0,0 +1,285 @@ +/* +Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef cJSON__h +#define cJSON__h + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) +#define __WINDOWS__ +#endif + +#ifdef __WINDOWS__ + + /* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options: + + CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols + CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) + CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol + + For *nix builds that support visibility attribute, you can define similar behavior by + + setting default visibility to hidden by adding + -fvisibility=hidden (for gcc) + or + -xldscope=hidden (for sun cc) + to CFLAGS + + then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does + + */ + +#define CJSON_CDECL __cdecl +#define CJSON_STDCALL __stdcall + + /* export symbols by default, this is necessary for copy pasting the C and header file */ +#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_EXPORT_SYMBOLS +#endif + +#if defined(CJSON_HIDE_SYMBOLS) +#define CJSON_PUBLIC(type) type CJSON_STDCALL +#elif defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL +#elif defined(CJSON_IMPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL +#endif +#else /* !__WINDOWS__ */ +#define CJSON_CDECL +#define CJSON_STDCALL + +#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) +#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type +#else +#define CJSON_PUBLIC(type) type +#endif +#endif + + /* project version */ +#define CJSON_VERSION_MAJOR 1 +#define CJSON_VERSION_MINOR 7 +#define CJSON_VERSION_PATCH 10 + +#include + + /* cJSON Types: */ +#define cJSON_Invalid (0) +#define cJSON_False (1 << 0) +#define cJSON_True (1 << 1) +#define cJSON_NULL (1 << 2) +#define cJSON_Number (1 << 3) +#define cJSON_String (1 << 4) +#define cJSON_Array (1 << 5) +#define cJSON_Object (1 << 6) +#define cJSON_Raw (1 << 7) /* raw json */ + +#define cJSON_IsReference 256 +#define cJSON_StringIsConst 512 + + /* The cJSON structure: */ + typedef struct cJSON + { + /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *next; + struct cJSON *prev; + /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ + struct cJSON *child; + + /* The type of the item, as above. */ + int type; + + /* The item's string, if type==cJSON_String and type == cJSON_Raw */ + char *valuestring; + /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ + int valueint; + /* The item's number, if type==cJSON_Number */ + double valuedouble; + + /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ + char *string; + } cJSON; + + typedef struct cJSON_Hooks + { + /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ + void *(CJSON_CDECL *malloc_fn)(size_t sz); + void (CJSON_CDECL *free_fn)(void *ptr); + } cJSON_Hooks; + + typedef int cJSON_bool; + + /* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. + * This is to prevent stack overflows. */ +#ifndef CJSON_NESTING_LIMIT +#define CJSON_NESTING_LIMIT 1000 +#endif + + /* returns the version of cJSON as a string */ + CJSON_PUBLIC(const char*) cJSON_Version(void); + + /* Supply malloc, realloc and free functions to cJSON */ + CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); + + /* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ + /* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ + CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); + /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ + /* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ + CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); + + /* Render a cJSON entity to text for transfer/storage. */ + CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); + /* Render a cJSON entity to text for transfer/storage without any formatting. */ + CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); + /* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ + CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); + /* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ + /* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ + CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); + /* Delete a cJSON entity and all subentities. */ + CJSON_PUBLIC(void) cJSON_Delete(cJSON *c); + + /* Returns the number of items in an array (or object). */ + CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); + /* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ + CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); + /* Get item "string" from object. Case insensitive. */ + CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); + CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); + CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); + /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ + CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); + + /* Check if the item is a string and return its valuestring */ + CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item); + + /* These functions check the type of an item */ + CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); + CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); + CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); + CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); + CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); + CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); + CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); + CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); + CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); + CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); + + /* These calls create a cJSON item of the appropriate type. */ + CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); + CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); + CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); + CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); + CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); + CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); + /* raw json */ + CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); + CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); + CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); + + /* Create a string where valuestring references a string so + * it will not be freed by cJSON_Delete */ + CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); + /* Create an object/arrray that only references it's elements so + * they will not be freed by cJSON_Delete */ + CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); + CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); + + /* These utilities create an Array of count items. */ + CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); + CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); + CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); + CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count); + + /* Append item to the specified array/object. */ + CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item); + CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); + /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. + * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before + * writing to `item->string` */ + CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); + /* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ + CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); + CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); + + /* Remove/Detatch items from Arrays/Objects. */ + CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); + CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); + CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); + CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); + CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); + CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); + CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); + + /* Update array items. */ + CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ + CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); + CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); + CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem); + CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem); + + /* Duplicate a cJSON item */ + CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); + /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will + need to be released. With recurse!=0, it will duplicate any children connected to the item. + The item->next and ->prev pointers are always zero on return from Duplicate. */ + /* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. + * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ + CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); + + + CJSON_PUBLIC(void) cJSON_Minify(char *json); + + /* Helper functions for creating and adding items to an object at the same time. + * They return the added item or NULL on failure. */ + CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); + CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); + CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); + CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); + CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); + CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); + CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); + CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); + CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name); + + /* When assigning an integer value, it needs to be propagated to valuedouble too. */ +#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) + /* helper for the cJSON_SetNumberValue macro */ + CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); +#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) + + /* Macro for iterating over an array or object */ +#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) + + /* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ + CJSON_PUBLIC(void *) cJSON_malloc(size_t size); + CJSON_PUBLIC(void) cJSON_free(void *object); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/curl/curl.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/curl/curl.h new file mode 100755 index 000000000..88e1f39e8 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/curl/curl.h @@ -0,0 +1,2839 @@ +#ifndef __CURL_CURL_H +#define __CURL_CURL_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * If you have libcurl problems, all docs and details are found here: + * https://curl.haxx.se/libcurl/ + * + * curl-library mailing list subscription and unsubscription web interface: + * https://cool.haxx.se/mailman/listinfo/curl-library/ + */ + +#ifdef CURL_NO_OLDIES +#define CURL_STRICTER +#endif + +#include "curlver.h" /* libcurl version defines */ +#include "system.h" /* determine things run-time */ + +/* + * Define WIN32 when build target is Win32 API + */ + +#if (defined(_WIN32) || defined(__WIN32__)) && \ + !defined(WIN32) && !defined(__SYMBIAN32__) +#define WIN32 +#endif + +#include +#include + +#if defined(__FreeBSD__) && (__FreeBSD__ >= 2) +/* Needed for __FreeBSD_version symbol definition */ +#include +#endif + +/* The include stuff here below is mainly for time_t! */ +#include +#include + +#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__) +#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || \ + defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)) +/* The check above prevents the winsock2 inclusion if winsock.h already was + included, since they can't co-exist without problems */ +#include +#include +#endif +#endif + +/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish + libc5-based Linux systems. Only include it on systems that are known to + require it! */ +#if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \ + defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \ + defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \ + defined(__CYGWIN__) || \ + (defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) +#include +#endif + +#if !defined(WIN32) && !defined(_WIN32_WCE) +#include +#endif + +#if !defined(WIN32) && !defined(__WATCOMC__) && !defined(__VXWORKS__) +#include +#endif + +#ifdef __BEOS__ +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) +typedef struct Curl_easy CURL; +typedef struct Curl_share CURLSH; +#else +typedef void CURL; +typedef void CURLSH; +#endif + +/* + * libcurl external API function linkage decorations. + */ + +#ifdef CURL_STATICLIB +# define CURL_EXTERN +#elif defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__) +# if defined(BUILDING_LIBCURL) +# define CURL_EXTERN __declspec(dllexport) +# else +# define CURL_EXTERN __declspec(dllimport) +# endif +#elif defined(BUILDING_LIBCURL) && defined(CURL_HIDDEN_SYMBOLS) +# define CURL_EXTERN CURL_EXTERN_SYMBOL +#else +# define CURL_EXTERN +#endif + +#ifndef curl_socket_typedef +/* socket typedef */ +#if defined(WIN32) && !defined(__LWIP_OPT_H__) && !defined(LWIP_HDR_OPT_H) +typedef SOCKET curl_socket_t; +#define CURL_SOCKET_BAD INVALID_SOCKET +#else +typedef int curl_socket_t; +#define CURL_SOCKET_BAD -1 +#endif +#define curl_socket_typedef +#endif /* curl_socket_typedef */ + +/* enum for the different supported SSL backends */ +typedef enum { + CURLSSLBACKEND_NONE = 0, + CURLSSLBACKEND_OPENSSL = 1, + CURLSSLBACKEND_GNUTLS = 2, + CURLSSLBACKEND_NSS = 3, + CURLSSLBACKEND_OBSOLETE4 = 4, /* Was QSOSSL. */ + CURLSSLBACKEND_GSKIT = 5, + CURLSSLBACKEND_POLARSSL = 6, + CURLSSLBACKEND_WOLFSSL = 7, + CURLSSLBACKEND_SCHANNEL = 8, + CURLSSLBACKEND_DARWINSSL = 9, + CURLSSLBACKEND_AXTLS = 10, /* never used since 7.63.0 */ + CURLSSLBACKEND_MBEDTLS = 11, + CURLSSLBACKEND_MESALINK = 12 +} curl_sslbackend; + +/* aliases for library clones and renames */ +#define CURLSSLBACKEND_LIBRESSL CURLSSLBACKEND_OPENSSL +#define CURLSSLBACKEND_BORINGSSL CURLSSLBACKEND_OPENSSL +#define CURLSSLBACKEND_CYASSL CURLSSLBACKEND_WOLFSSL + +struct curl_httppost { + struct curl_httppost *next; /* next entry in the list */ + char *name; /* pointer to allocated name */ + long namelength; /* length of name length */ + char *contents; /* pointer to allocated data contents */ + long contentslength; /* length of contents field, see also + CURL_HTTPPOST_LARGE */ + char *buffer; /* pointer to allocated buffer contents */ + long bufferlength; /* length of buffer field */ + char *contenttype; /* Content-Type */ + struct curl_slist *contentheader; /* list of extra headers for this form */ + struct curl_httppost *more; /* if one field name has more than one + file, this link should link to following + files */ + long flags; /* as defined below */ + +/* specified content is a file name */ +#define CURL_HTTPPOST_FILENAME (1<<0) +/* specified content is a file name */ +#define CURL_HTTPPOST_READFILE (1<<1) +/* name is only stored pointer do not free in formfree */ +#define CURL_HTTPPOST_PTRNAME (1<<2) +/* contents is only stored pointer do not free in formfree */ +#define CURL_HTTPPOST_PTRCONTENTS (1<<3) +/* upload file from buffer */ +#define CURL_HTTPPOST_BUFFER (1<<4) +/* upload file from pointer contents */ +#define CURL_HTTPPOST_PTRBUFFER (1<<5) +/* upload file contents by using the regular read callback to get the data and + pass the given pointer as custom pointer */ +#define CURL_HTTPPOST_CALLBACK (1<<6) +/* use size in 'contentlen', added in 7.46.0 */ +#define CURL_HTTPPOST_LARGE (1<<7) + + char *showfilename; /* The file name to show. If not set, the + actual file name will be used (if this + is a file part) */ + void *userp; /* custom pointer used for + HTTPPOST_CALLBACK posts */ + curl_off_t contentlen; /* alternative length of contents + field. Used if CURL_HTTPPOST_LARGE is + set. Added in 7.46.0 */ +}; + +/* This is the CURLOPT_PROGRESSFUNCTION callback proto. It is now considered + deprecated but was the only choice up until 7.31.0 */ +typedef int (*curl_progress_callback)(void *clientp, + double dltotal, + double dlnow, + double ultotal, + double ulnow); + +/* This is the CURLOPT_XFERINFOFUNCTION callback proto. It was introduced in + 7.32.0, it avoids floating point and provides more detailed information. */ +typedef int (*curl_xferinfo_callback)(void *clientp, + curl_off_t dltotal, + curl_off_t dlnow, + curl_off_t ultotal, + curl_off_t ulnow); + +#ifndef CURL_MAX_READ_SIZE + /* The maximum receive buffer size configurable via CURLOPT_BUFFERSIZE. */ +#define CURL_MAX_READ_SIZE 524288 +#endif + +#ifndef CURL_MAX_WRITE_SIZE + /* Tests have proven that 20K is a very bad buffer size for uploads on + Windows, while 16K for some odd reason performed a lot better. + We do the ifndef check to allow this value to easier be changed at build + time for those who feel adventurous. The practical minimum is about + 400 bytes since libcurl uses a buffer of this size as a scratch area + (unrelated to network send operations). */ +#define CURL_MAX_WRITE_SIZE 16384 +#endif + +#ifndef CURL_MAX_HTTP_HEADER +/* The only reason to have a max limit for this is to avoid the risk of a bad + server feeding libcurl with a never-ending header that will cause reallocs + infinitely */ +#define CURL_MAX_HTTP_HEADER (100*1024) +#endif + +/* This is a magic return code for the write callback that, when returned, + will signal libcurl to pause receiving on the current transfer. */ +#define CURL_WRITEFUNC_PAUSE 0x10000001 + +typedef size_t (*curl_write_callback)(char *buffer, + size_t size, + size_t nitems, + void *outstream); + +/* This callback will be called when a new resolver request is made */ +typedef int (*curl_resolver_start_callback)(void *resolver_state, + void *reserved, void *userdata); + +/* enumeration of file types */ +typedef enum { + CURLFILETYPE_FILE = 0, + CURLFILETYPE_DIRECTORY, + CURLFILETYPE_SYMLINK, + CURLFILETYPE_DEVICE_BLOCK, + CURLFILETYPE_DEVICE_CHAR, + CURLFILETYPE_NAMEDPIPE, + CURLFILETYPE_SOCKET, + CURLFILETYPE_DOOR, /* is possible only on Sun Solaris now */ + + CURLFILETYPE_UNKNOWN /* should never occur */ +} curlfiletype; + +#define CURLFINFOFLAG_KNOWN_FILENAME (1<<0) +#define CURLFINFOFLAG_KNOWN_FILETYPE (1<<1) +#define CURLFINFOFLAG_KNOWN_TIME (1<<2) +#define CURLFINFOFLAG_KNOWN_PERM (1<<3) +#define CURLFINFOFLAG_KNOWN_UID (1<<4) +#define CURLFINFOFLAG_KNOWN_GID (1<<5) +#define CURLFINFOFLAG_KNOWN_SIZE (1<<6) +#define CURLFINFOFLAG_KNOWN_HLINKCOUNT (1<<7) + +/* Content of this structure depends on information which is known and is + achievable (e.g. by FTP LIST parsing). Please see the url_easy_setopt(3) man + page for callbacks returning this structure -- some fields are mandatory, + some others are optional. The FLAG field has special meaning. */ +struct curl_fileinfo { + char *filename; + curlfiletype filetype; + time_t time; + unsigned int perm; + int uid; + int gid; + curl_off_t size; + long int hardlinks; + + struct { + /* If some of these fields is not NULL, it is a pointer to b_data. */ + char *time; + char *perm; + char *user; + char *group; + char *target; /* pointer to the target filename of a symlink */ + } strings; + + unsigned int flags; + + /* used internally */ + char *b_data; + size_t b_size; + size_t b_used; +}; + +/* return codes for CURLOPT_CHUNK_BGN_FUNCTION */ +#define CURL_CHUNK_BGN_FUNC_OK 0 +#define CURL_CHUNK_BGN_FUNC_FAIL 1 /* tell the lib to end the task */ +#define CURL_CHUNK_BGN_FUNC_SKIP 2 /* skip this chunk over */ + +/* if splitting of data transfer is enabled, this callback is called before + download of an individual chunk started. Note that parameter "remains" works + only for FTP wildcard downloading (for now), otherwise is not used */ +typedef long (*curl_chunk_bgn_callback)(const void *transfer_info, + void *ptr, + int remains); + +/* return codes for CURLOPT_CHUNK_END_FUNCTION */ +#define CURL_CHUNK_END_FUNC_OK 0 +#define CURL_CHUNK_END_FUNC_FAIL 1 /* tell the lib to end the task */ + +/* If splitting of data transfer is enabled this callback is called after + download of an individual chunk finished. + Note! After this callback was set then it have to be called FOR ALL chunks. + Even if downloading of this chunk was skipped in CHUNK_BGN_FUNC. + This is the reason why we don't need "transfer_info" parameter in this + callback and we are not interested in "remains" parameter too. */ +typedef long (*curl_chunk_end_callback)(void *ptr); + +/* return codes for FNMATCHFUNCTION */ +#define CURL_FNMATCHFUNC_MATCH 0 /* string corresponds to the pattern */ +#define CURL_FNMATCHFUNC_NOMATCH 1 /* pattern doesn't match the string */ +#define CURL_FNMATCHFUNC_FAIL 2 /* an error occurred */ + +/* callback type for wildcard downloading pattern matching. If the + string matches the pattern, return CURL_FNMATCHFUNC_MATCH value, etc. */ +typedef int (*curl_fnmatch_callback)(void *ptr, + const char *pattern, + const char *string); + +/* These are the return codes for the seek callbacks */ +#define CURL_SEEKFUNC_OK 0 +#define CURL_SEEKFUNC_FAIL 1 /* fail the entire transfer */ +#define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking can't be done, so + libcurl might try other means instead */ +typedef int (*curl_seek_callback)(void *instream, + curl_off_t offset, + int origin); /* 'whence' */ + +/* This is a return code for the read callback that, when returned, will + signal libcurl to immediately abort the current transfer. */ +#define CURL_READFUNC_ABORT 0x10000000 +/* This is a return code for the read callback that, when returned, will + signal libcurl to pause sending data on the current transfer. */ +#define CURL_READFUNC_PAUSE 0x10000001 + +/* Return code for when the trailing headers' callback has terminated + without any errors*/ +#define CURL_TRAILERFUNC_OK 0 +/* Return code for when was an error in the trailing header's list and we + want to abort the request */ +#define CURL_TRAILERFUNC_ABORT 1 + +typedef size_t (*curl_read_callback)(char *buffer, + size_t size, + size_t nitems, + void *instream); + +typedef int (*curl_trailer_callback)(struct curl_slist **list, + void *userdata); + +typedef enum { + CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */ + CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */ + CURLSOCKTYPE_LAST /* never use */ +} curlsocktype; + +/* The return code from the sockopt_callback can signal information back + to libcurl: */ +#define CURL_SOCKOPT_OK 0 +#define CURL_SOCKOPT_ERROR 1 /* causes libcurl to abort and return + CURLE_ABORTED_BY_CALLBACK */ +#define CURL_SOCKOPT_ALREADY_CONNECTED 2 + +typedef int (*curl_sockopt_callback)(void *clientp, + curl_socket_t curlfd, + curlsocktype purpose); + +struct curl_sockaddr { + int family; + int socktype; + int protocol; + unsigned int addrlen; /* addrlen was a socklen_t type before 7.18.0 but it + turned really ugly and painful on the systems that + lack this type */ + struct sockaddr addr; +}; + +typedef curl_socket_t +(*curl_opensocket_callback)(void *clientp, + curlsocktype purpose, + struct curl_sockaddr *address); + +typedef int +(*curl_closesocket_callback)(void *clientp, curl_socket_t item); + +typedef enum { + CURLIOE_OK, /* I/O operation successful */ + CURLIOE_UNKNOWNCMD, /* command was unknown to callback */ + CURLIOE_FAILRESTART, /* failed to restart the read */ + CURLIOE_LAST /* never use */ +} curlioerr; + +typedef enum { + CURLIOCMD_NOP, /* no operation */ + CURLIOCMD_RESTARTREAD, /* restart the read stream from start */ + CURLIOCMD_LAST /* never use */ +} curliocmd; + +typedef curlioerr (*curl_ioctl_callback)(CURL *handle, + int cmd, + void *clientp); + +#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS +/* + * The following typedef's are signatures of malloc, free, realloc, strdup and + * calloc respectively. Function pointers of these types can be passed to the + * curl_global_init_mem() function to set user defined memory management + * callback routines. + */ +typedef void *(*curl_malloc_callback)(size_t size); +typedef void (*curl_free_callback)(void *ptr); +typedef void *(*curl_realloc_callback)(void *ptr, size_t size); +typedef char *(*curl_strdup_callback)(const char *str); +typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); + +#define CURL_DID_MEMORY_FUNC_TYPEDEFS +#endif + +/* the kind of data that is passed to information_callback*/ +typedef enum { + CURLINFO_TEXT = 0, + CURLINFO_HEADER_IN, /* 1 */ + CURLINFO_HEADER_OUT, /* 2 */ + CURLINFO_DATA_IN, /* 3 */ + CURLINFO_DATA_OUT, /* 4 */ + CURLINFO_SSL_DATA_IN, /* 5 */ + CURLINFO_SSL_DATA_OUT, /* 6 */ + CURLINFO_END +} curl_infotype; + +typedef int (*curl_debug_callback) + (CURL *handle, /* the handle/transfer this concerns */ + curl_infotype type, /* what kind of data */ + char *data, /* points to the data */ + size_t size, /* size of the data pointed to */ + void *userptr); /* whatever the user please */ + +/* All possible error codes from all sorts of curl functions. Future versions + may return other values, stay prepared. + + Always add new return codes last. Never *EVER* remove any. The return + codes must remain the same! + */ + +typedef enum { + CURLE_OK = 0, + CURLE_UNSUPPORTED_PROTOCOL, /* 1 */ + CURLE_FAILED_INIT, /* 2 */ + CURLE_URL_MALFORMAT, /* 3 */ + CURLE_NOT_BUILT_IN, /* 4 - [was obsoleted in August 2007 for + 7.17.0, reused in April 2011 for 7.21.5] */ + CURLE_COULDNT_RESOLVE_PROXY, /* 5 */ + CURLE_COULDNT_RESOLVE_HOST, /* 6 */ + CURLE_COULDNT_CONNECT, /* 7 */ + CURLE_WEIRD_SERVER_REPLY, /* 8 */ + CURLE_REMOTE_ACCESS_DENIED, /* 9 a service was denied by the server + due to lack of access - when login fails + this is not returned. */ + CURLE_FTP_ACCEPT_FAILED, /* 10 - [was obsoleted in April 2006 for + 7.15.4, reused in Dec 2011 for 7.24.0]*/ + CURLE_FTP_WEIRD_PASS_REPLY, /* 11 */ + CURLE_FTP_ACCEPT_TIMEOUT, /* 12 - timeout occurred accepting server + [was obsoleted in August 2007 for 7.17.0, + reused in Dec 2011 for 7.24.0]*/ + CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */ + CURLE_FTP_WEIRD_227_FORMAT, /* 14 */ + CURLE_FTP_CANT_GET_HOST, /* 15 */ + CURLE_HTTP2, /* 16 - A problem in the http2 framing layer. + [was obsoleted in August 2007 for 7.17.0, + reused in July 2014 for 7.38.0] */ + CURLE_FTP_COULDNT_SET_TYPE, /* 17 */ + CURLE_PARTIAL_FILE, /* 18 */ + CURLE_FTP_COULDNT_RETR_FILE, /* 19 */ + CURLE_OBSOLETE20, /* 20 - NOT USED */ + CURLE_QUOTE_ERROR, /* 21 - quote command failure */ + CURLE_HTTP_RETURNED_ERROR, /* 22 */ + CURLE_WRITE_ERROR, /* 23 */ + CURLE_OBSOLETE24, /* 24 - NOT USED */ + CURLE_UPLOAD_FAILED, /* 25 - failed upload "command" */ + CURLE_READ_ERROR, /* 26 - couldn't open/read from file */ + CURLE_OUT_OF_MEMORY, /* 27 */ + /* Note: CURLE_OUT_OF_MEMORY may sometimes indicate a conversion error + instead of a memory allocation error if CURL_DOES_CONVERSIONS + is defined + */ + CURLE_OPERATION_TIMEDOUT, /* 28 - the timeout time was reached */ + CURLE_OBSOLETE29, /* 29 - NOT USED */ + CURLE_FTP_PORT_FAILED, /* 30 - FTP PORT operation failed */ + CURLE_FTP_COULDNT_USE_REST, /* 31 - the REST command failed */ + CURLE_OBSOLETE32, /* 32 - NOT USED */ + CURLE_RANGE_ERROR, /* 33 - RANGE "command" didn't work */ + CURLE_HTTP_POST_ERROR, /* 34 */ + CURLE_SSL_CONNECT_ERROR, /* 35 - wrong when connecting with SSL */ + CURLE_BAD_DOWNLOAD_RESUME, /* 36 - couldn't resume download */ + CURLE_FILE_COULDNT_READ_FILE, /* 37 */ + CURLE_LDAP_CANNOT_BIND, /* 38 */ + CURLE_LDAP_SEARCH_FAILED, /* 39 */ + CURLE_OBSOLETE40, /* 40 - NOT USED */ + CURLE_FUNCTION_NOT_FOUND, /* 41 - NOT USED starting with 7.53.0 */ + CURLE_ABORTED_BY_CALLBACK, /* 42 */ + CURLE_BAD_FUNCTION_ARGUMENT, /* 43 */ + CURLE_OBSOLETE44, /* 44 - NOT USED */ + CURLE_INTERFACE_FAILED, /* 45 - CURLOPT_INTERFACE failed */ + CURLE_OBSOLETE46, /* 46 - NOT USED */ + CURLE_TOO_MANY_REDIRECTS, /* 47 - catch endless re-direct loops */ + CURLE_UNKNOWN_OPTION, /* 48 - User specified an unknown option */ + CURLE_TELNET_OPTION_SYNTAX, /* 49 - Malformed telnet option */ + CURLE_OBSOLETE50, /* 50 - NOT USED */ + CURLE_OBSOLETE51, /* 51 - NOT USED */ + CURLE_GOT_NOTHING, /* 52 - when this is a specific error */ + CURLE_SSL_ENGINE_NOTFOUND, /* 53 - SSL crypto engine not found */ + CURLE_SSL_ENGINE_SETFAILED, /* 54 - can not set SSL crypto engine as + default */ + CURLE_SEND_ERROR, /* 55 - failed sending network data */ + CURLE_RECV_ERROR, /* 56 - failure in receiving network data */ + CURLE_OBSOLETE57, /* 57 - NOT IN USE */ + CURLE_SSL_CERTPROBLEM, /* 58 - problem with the local certificate */ + CURLE_SSL_CIPHER, /* 59 - couldn't use specified cipher */ + CURLE_PEER_FAILED_VERIFICATION, /* 60 - peer's certificate or fingerprint + wasn't verified fine */ + CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized/bad encoding */ + CURLE_LDAP_INVALID_URL, /* 62 - Invalid LDAP URL */ + CURLE_FILESIZE_EXCEEDED, /* 63 - Maximum file size exceeded */ + CURLE_USE_SSL_FAILED, /* 64 - Requested FTP SSL level failed */ + CURLE_SEND_FAIL_REWIND, /* 65 - Sending the data requires a rewind + that failed */ + CURLE_SSL_ENGINE_INITFAILED, /* 66 - failed to initialise ENGINE */ + CURLE_LOGIN_DENIED, /* 67 - user, password or similar was not + accepted and we failed to login */ + CURLE_TFTP_NOTFOUND, /* 68 - file not found on server */ + CURLE_TFTP_PERM, /* 69 - permission problem on server */ + CURLE_REMOTE_DISK_FULL, /* 70 - out of disk space on server */ + CURLE_TFTP_ILLEGAL, /* 71 - Illegal TFTP operation */ + CURLE_TFTP_UNKNOWNID, /* 72 - Unknown transfer ID */ + CURLE_REMOTE_FILE_EXISTS, /* 73 - File already exists */ + CURLE_TFTP_NOSUCHUSER, /* 74 - No such user */ + CURLE_CONV_FAILED, /* 75 - conversion failed */ + CURLE_CONV_REQD, /* 76 - caller must register conversion + callbacks using curl_easy_setopt options + CURLOPT_CONV_FROM_NETWORK_FUNCTION, + CURLOPT_CONV_TO_NETWORK_FUNCTION, and + CURLOPT_CONV_FROM_UTF8_FUNCTION */ + CURLE_SSL_CACERT_BADFILE, /* 77 - could not load CACERT file, missing + or wrong format */ + CURLE_REMOTE_FILE_NOT_FOUND, /* 78 - remote file not found */ + CURLE_SSH, /* 79 - error from the SSH layer, somewhat + generic so the error message will be of + interest when this has happened */ + + CURLE_SSL_SHUTDOWN_FAILED, /* 80 - Failed to shut down the SSL + connection */ + CURLE_AGAIN, /* 81 - socket is not ready for send/recv, + wait till it's ready and try again (Added + in 7.18.2) */ + CURLE_SSL_CRL_BADFILE, /* 82 - could not load CRL file, missing or + wrong format (Added in 7.19.0) */ + CURLE_SSL_ISSUER_ERROR, /* 83 - Issuer check failed. (Added in + 7.19.0) */ + CURLE_FTP_PRET_FAILED, /* 84 - a PRET command failed */ + CURLE_RTSP_CSEQ_ERROR, /* 85 - mismatch of RTSP CSeq numbers */ + CURLE_RTSP_SESSION_ERROR, /* 86 - mismatch of RTSP Session Ids */ + CURLE_FTP_BAD_FILE_LIST, /* 87 - unable to parse FTP file list */ + CURLE_CHUNK_FAILED, /* 88 - chunk callback reported error */ + CURLE_NO_CONNECTION_AVAILABLE, /* 89 - No connection available, the + session will be queued */ + CURLE_SSL_PINNEDPUBKEYNOTMATCH, /* 90 - specified pinned public key did not + match */ + CURLE_SSL_INVALIDCERTSTATUS, /* 91 - invalid certificate status */ + CURLE_HTTP2_STREAM, /* 92 - stream error in HTTP/2 framing layer + */ + CURLE_RECURSIVE_API_CALL, /* 93 - an api function was called from + inside a callback */ + CURL_LAST /* never use! */ +} CURLcode; + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Previously obsolete error code re-used in 7.38.0 */ +#define CURLE_OBSOLETE16 CURLE_HTTP2 + +/* Previously obsolete error codes re-used in 7.24.0 */ +#define CURLE_OBSOLETE10 CURLE_FTP_ACCEPT_FAILED +#define CURLE_OBSOLETE12 CURLE_FTP_ACCEPT_TIMEOUT + +/* compatibility with older names */ +#define CURLOPT_ENCODING CURLOPT_ACCEPT_ENCODING +#define CURLE_FTP_WEIRD_SERVER_REPLY CURLE_WEIRD_SERVER_REPLY + +/* The following were added in 7.62.0 */ +#define CURLE_SSL_CACERT CURLE_PEER_FAILED_VERIFICATION + +/* The following were added in 7.21.5, April 2011 */ +#define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION + +/* The following were added in 7.17.1 */ +/* These are scheduled to disappear by 2009 */ +#define CURLE_SSL_PEER_CERTIFICATE CURLE_PEER_FAILED_VERIFICATION + +/* The following were added in 7.17.0 */ +/* These are scheduled to disappear by 2009 */ +#define CURLE_OBSOLETE CURLE_OBSOLETE50 /* no one should be using this! */ +#define CURLE_BAD_PASSWORD_ENTERED CURLE_OBSOLETE46 +#define CURLE_BAD_CALLING_ORDER CURLE_OBSOLETE44 +#define CURLE_FTP_USER_PASSWORD_INCORRECT CURLE_OBSOLETE10 +#define CURLE_FTP_CANT_RECONNECT CURLE_OBSOLETE16 +#define CURLE_FTP_COULDNT_GET_SIZE CURLE_OBSOLETE32 +#define CURLE_FTP_COULDNT_SET_ASCII CURLE_OBSOLETE29 +#define CURLE_FTP_WEIRD_USER_REPLY CURLE_OBSOLETE12 +#define CURLE_FTP_WRITE_ERROR CURLE_OBSOLETE20 +#define CURLE_LIBRARY_NOT_FOUND CURLE_OBSOLETE40 +#define CURLE_MALFORMAT_USER CURLE_OBSOLETE24 +#define CURLE_SHARE_IN_USE CURLE_OBSOLETE57 +#define CURLE_URL_MALFORMAT_USER CURLE_NOT_BUILT_IN + +#define CURLE_FTP_ACCESS_DENIED CURLE_REMOTE_ACCESS_DENIED +#define CURLE_FTP_COULDNT_SET_BINARY CURLE_FTP_COULDNT_SET_TYPE +#define CURLE_FTP_QUOTE_ERROR CURLE_QUOTE_ERROR +#define CURLE_TFTP_DISKFULL CURLE_REMOTE_DISK_FULL +#define CURLE_TFTP_EXISTS CURLE_REMOTE_FILE_EXISTS +#define CURLE_HTTP_RANGE_ERROR CURLE_RANGE_ERROR +#define CURLE_FTP_SSL_FAILED CURLE_USE_SSL_FAILED + +/* The following were added earlier */ + +#define CURLE_OPERATION_TIMEOUTED CURLE_OPERATION_TIMEDOUT + +#define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR +#define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED +#define CURLE_FTP_COULDNT_STOR_FILE CURLE_UPLOAD_FAILED + +#define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE +#define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME + +/* This was the error code 50 in 7.7.3 and a few earlier versions, this + is no longer used by libcurl but is instead #defined here only to not + make programs break */ +#define CURLE_ALREADY_COMPLETE 99999 + +/* Provide defines for really old option names */ +#define CURLOPT_FILE CURLOPT_WRITEDATA /* name changed in 7.9.7 */ +#define CURLOPT_INFILE CURLOPT_READDATA /* name changed in 7.9.7 */ +#define CURLOPT_WRITEHEADER CURLOPT_HEADERDATA + +/* Since long deprecated options with no code in the lib that does anything + with them. */ +#define CURLOPT_WRITEINFO CURLOPT_OBSOLETE40 +#define CURLOPT_CLOSEPOLICY CURLOPT_OBSOLETE72 + +#endif /*!CURL_NO_OLDIES*/ + +/* This prototype applies to all conversion callbacks */ +typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length); + +typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl, /* easy handle */ + void *ssl_ctx, /* actually an + OpenSSL SSL_CTX */ + void *userptr); + +typedef enum { + CURLPROXY_HTTP = 0, /* added in 7.10, new in 7.19.4 default is to use + CONNECT HTTP/1.1 */ + CURLPROXY_HTTP_1_0 = 1, /* added in 7.19.4, force to use CONNECT + HTTP/1.0 */ + CURLPROXY_HTTPS = 2, /* added in 7.52.0 */ + CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already + in 7.10 */ + CURLPROXY_SOCKS5 = 5, /* added in 7.10 */ + CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */ + CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the + host name rather than the IP address. added + in 7.18.0 */ +} curl_proxytype; /* this enum was added in 7.10 */ + +/* + * Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options: + * + * CURLAUTH_NONE - No HTTP authentication + * CURLAUTH_BASIC - HTTP Basic authentication (default) + * CURLAUTH_DIGEST - HTTP Digest authentication + * CURLAUTH_NEGOTIATE - HTTP Negotiate (SPNEGO) authentication + * CURLAUTH_GSSNEGOTIATE - Alias for CURLAUTH_NEGOTIATE (deprecated) + * CURLAUTH_NTLM - HTTP NTLM authentication + * CURLAUTH_DIGEST_IE - HTTP Digest authentication with IE flavour + * CURLAUTH_NTLM_WB - HTTP NTLM authentication delegated to winbind helper + * CURLAUTH_BEARER - HTTP Bearer token authentication + * CURLAUTH_ONLY - Use together with a single other type to force no + * authentication or just that single type + * CURLAUTH_ANY - All fine types set + * CURLAUTH_ANYSAFE - All fine types except Basic + */ + +#define CURLAUTH_NONE ((unsigned long)0) +#define CURLAUTH_BASIC (((unsigned long)1)<<0) +#define CURLAUTH_DIGEST (((unsigned long)1)<<1) +#define CURLAUTH_NEGOTIATE (((unsigned long)1)<<2) +/* Deprecated since the advent of CURLAUTH_NEGOTIATE */ +#define CURLAUTH_GSSNEGOTIATE CURLAUTH_NEGOTIATE +/* Used for CURLOPT_SOCKS5_AUTH to stay terminologically correct */ +#define CURLAUTH_GSSAPI CURLAUTH_NEGOTIATE +#define CURLAUTH_NTLM (((unsigned long)1)<<3) +#define CURLAUTH_DIGEST_IE (((unsigned long)1)<<4) +#define CURLAUTH_NTLM_WB (((unsigned long)1)<<5) +#define CURLAUTH_BEARER (((unsigned long)1)<<6) +#define CURLAUTH_ONLY (((unsigned long)1)<<31) +#define CURLAUTH_ANY (~CURLAUTH_DIGEST_IE) +#define CURLAUTH_ANYSAFE (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE)) + +#define CURLSSH_AUTH_ANY ~0 /* all types supported by the server */ +#define CURLSSH_AUTH_NONE 0 /* none allowed, silly but complete */ +#define CURLSSH_AUTH_PUBLICKEY (1<<0) /* public/private key files */ +#define CURLSSH_AUTH_PASSWORD (1<<1) /* password */ +#define CURLSSH_AUTH_HOST (1<<2) /* host key files */ +#define CURLSSH_AUTH_KEYBOARD (1<<3) /* keyboard interactive */ +#define CURLSSH_AUTH_AGENT (1<<4) /* agent (ssh-agent, pageant...) */ +#define CURLSSH_AUTH_GSSAPI (1<<5) /* gssapi (kerberos, ...) */ +#define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY + +#define CURLGSSAPI_DELEGATION_NONE 0 /* no delegation (default) */ +#define CURLGSSAPI_DELEGATION_POLICY_FLAG (1<<0) /* if permitted by policy */ +#define CURLGSSAPI_DELEGATION_FLAG (1<<1) /* delegate always */ + +#define CURL_ERROR_SIZE 256 + +enum curl_khtype { + CURLKHTYPE_UNKNOWN, + CURLKHTYPE_RSA1, + CURLKHTYPE_RSA, + CURLKHTYPE_DSS, + CURLKHTYPE_ECDSA, + CURLKHTYPE_ED25519 +}; + +struct curl_khkey { + const char *key; /* points to a zero-terminated string encoded with base64 + if len is zero, otherwise to the "raw" data */ + size_t len; + enum curl_khtype keytype; +}; + +/* this is the set of return values expected from the curl_sshkeycallback + callback */ +enum curl_khstat { + CURLKHSTAT_FINE_ADD_TO_FILE, + CURLKHSTAT_FINE, + CURLKHSTAT_REJECT, /* reject the connection, return an error */ + CURLKHSTAT_DEFER, /* do not accept it, but we can't answer right now so + this causes a CURLE_DEFER error but otherwise the + connection will be left intact etc */ + CURLKHSTAT_LAST /* not for use, only a marker for last-in-list */ +}; + +/* this is the set of status codes pass in to the callback */ +enum curl_khmatch { + CURLKHMATCH_OK, /* match */ + CURLKHMATCH_MISMATCH, /* host found, key mismatch! */ + CURLKHMATCH_MISSING, /* no matching host/key found */ + CURLKHMATCH_LAST /* not for use, only a marker for last-in-list */ +}; + +typedef int + (*curl_sshkeycallback) (CURL *easy, /* easy handle */ + const struct curl_khkey *knownkey, /* known */ + const struct curl_khkey *foundkey, /* found */ + enum curl_khmatch, /* libcurl's view on the keys */ + void *clientp); /* custom pointer passed from app */ + +/* parameter for the CURLOPT_USE_SSL option */ +typedef enum { + CURLUSESSL_NONE, /* do not attempt to use SSL */ + CURLUSESSL_TRY, /* try using SSL, proceed anyway otherwise */ + CURLUSESSL_CONTROL, /* SSL for the control connection or fail */ + CURLUSESSL_ALL, /* SSL for all communication or fail */ + CURLUSESSL_LAST /* not an option, never use */ +} curl_usessl; + +/* Definition of bits for the CURLOPT_SSL_OPTIONS argument: */ + +/* - ALLOW_BEAST tells libcurl to allow the BEAST SSL vulnerability in the + name of improving interoperability with older servers. Some SSL libraries + have introduced work-arounds for this flaw but those work-arounds sometimes + make the SSL communication fail. To regain functionality with those broken + servers, a user can this way allow the vulnerability back. */ +#define CURLSSLOPT_ALLOW_BEAST (1<<0) + +/* - NO_REVOKE tells libcurl to disable certificate revocation checks for those + SSL backends where such behavior is present. */ +#define CURLSSLOPT_NO_REVOKE (1<<1) + +/* The default connection attempt delay in milliseconds for happy eyeballs. + CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.3 and happy-eyeballs-timeout-ms.d document + this value, keep them in sync. */ +#define CURL_HET_DEFAULT 200L + +/* The default connection upkeep interval in milliseconds. */ +#define CURL_UPKEEP_INTERVAL_DEFAULT 60000L + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Backwards compatibility with older names */ +/* These are scheduled to disappear by 2009 */ + +#define CURLFTPSSL_NONE CURLUSESSL_NONE +#define CURLFTPSSL_TRY CURLUSESSL_TRY +#define CURLFTPSSL_CONTROL CURLUSESSL_CONTROL +#define CURLFTPSSL_ALL CURLUSESSL_ALL +#define CURLFTPSSL_LAST CURLUSESSL_LAST +#define curl_ftpssl curl_usessl +#endif /*!CURL_NO_OLDIES*/ + +/* parameter for the CURLOPT_FTP_SSL_CCC option */ +typedef enum { + CURLFTPSSL_CCC_NONE, /* do not send CCC */ + CURLFTPSSL_CCC_PASSIVE, /* Let the server initiate the shutdown */ + CURLFTPSSL_CCC_ACTIVE, /* Initiate the shutdown */ + CURLFTPSSL_CCC_LAST /* not an option, never use */ +} curl_ftpccc; + +/* parameter for the CURLOPT_FTPSSLAUTH option */ +typedef enum { + CURLFTPAUTH_DEFAULT, /* let libcurl decide */ + CURLFTPAUTH_SSL, /* use "AUTH SSL" */ + CURLFTPAUTH_TLS, /* use "AUTH TLS" */ + CURLFTPAUTH_LAST /* not an option, never use */ +} curl_ftpauth; + +/* parameter for the CURLOPT_FTP_CREATE_MISSING_DIRS option */ +typedef enum { + CURLFTP_CREATE_DIR_NONE, /* do NOT create missing dirs! */ + CURLFTP_CREATE_DIR, /* (FTP/SFTP) if CWD fails, try MKD and then CWD + again if MKD succeeded, for SFTP this does + similar magic */ + CURLFTP_CREATE_DIR_RETRY, /* (FTP only) if CWD fails, try MKD and then CWD + again even if MKD failed! */ + CURLFTP_CREATE_DIR_LAST /* not an option, never use */ +} curl_ftpcreatedir; + +/* parameter for the CURLOPT_FTP_FILEMETHOD option */ +typedef enum { + CURLFTPMETHOD_DEFAULT, /* let libcurl pick */ + CURLFTPMETHOD_MULTICWD, /* single CWD operation for each path part */ + CURLFTPMETHOD_NOCWD, /* no CWD at all */ + CURLFTPMETHOD_SINGLECWD, /* one CWD to full dir, then work on file */ + CURLFTPMETHOD_LAST /* not an option, never use */ +} curl_ftpmethod; + +/* bitmask defines for CURLOPT_HEADEROPT */ +#define CURLHEADER_UNIFIED 0 +#define CURLHEADER_SEPARATE (1<<0) + +/* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */ +#define CURLPROTO_HTTP (1<<0) +#define CURLPROTO_HTTPS (1<<1) +#define CURLPROTO_FTP (1<<2) +#define CURLPROTO_FTPS (1<<3) +#define CURLPROTO_SCP (1<<4) +#define CURLPROTO_SFTP (1<<5) +#define CURLPROTO_TELNET (1<<6) +#define CURLPROTO_LDAP (1<<7) +#define CURLPROTO_LDAPS (1<<8) +#define CURLPROTO_DICT (1<<9) +#define CURLPROTO_FILE (1<<10) +#define CURLPROTO_TFTP (1<<11) +#define CURLPROTO_IMAP (1<<12) +#define CURLPROTO_IMAPS (1<<13) +#define CURLPROTO_POP3 (1<<14) +#define CURLPROTO_POP3S (1<<15) +#define CURLPROTO_SMTP (1<<16) +#define CURLPROTO_SMTPS (1<<17) +#define CURLPROTO_RTSP (1<<18) +#define CURLPROTO_RTMP (1<<19) +#define CURLPROTO_RTMPT (1<<20) +#define CURLPROTO_RTMPE (1<<21) +#define CURLPROTO_RTMPTE (1<<22) +#define CURLPROTO_RTMPS (1<<23) +#define CURLPROTO_RTMPTS (1<<24) +#define CURLPROTO_GOPHER (1<<25) +#define CURLPROTO_SMB (1<<26) +#define CURLPROTO_SMBS (1<<27) +#define CURLPROTO_ALL (~0) /* enable everything */ + +/* long may be 32 or 64 bits, but we should never depend on anything else + but 32 */ +#define CURLOPTTYPE_LONG 0 +#define CURLOPTTYPE_OBJECTPOINT 10000 +#define CURLOPTTYPE_STRINGPOINT 10000 +#define CURLOPTTYPE_FUNCTIONPOINT 20000 +#define CURLOPTTYPE_OFF_T 30000 + +/* *STRINGPOINT is an alias for OBJECTPOINT to allow tools to extract the + string options from the header file */ + +/* name is uppercase CURLOPT_, + type is one of the defined CURLOPTTYPE_ + number is unique identifier */ +#ifdef CINIT +#undef CINIT +#endif + +#ifdef CURL_ISOCPP +#define CINIT(na,t,nu) CURLOPT_ ## na = CURLOPTTYPE_ ## t + nu +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define LONG CURLOPTTYPE_LONG +#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT +#define STRINGPOINT CURLOPTTYPE_OBJECTPOINT +#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT +#define OFF_T CURLOPTTYPE_OFF_T +#define CINIT(name,type,number) CURLOPT_/**/name = type + number +#endif + +/* + * This macro-mania below setups the CURLOPT_[what] enum, to be used with + * curl_easy_setopt(). The first argument in the CINIT() macro is the [what] + * word. + */ + +typedef enum { + /* This is the FILE * or void * the regular output should be written to. */ + CINIT(WRITEDATA, OBJECTPOINT, 1), + + /* The full URL to get/put */ + CINIT(URL, STRINGPOINT, 2), + + /* Port number to connect to, if other than default. */ + CINIT(PORT, LONG, 3), + + /* Name of proxy to use. */ + CINIT(PROXY, STRINGPOINT, 4), + + /* "user:password;options" to use when fetching. */ + CINIT(USERPWD, STRINGPOINT, 5), + + /* "user:password" to use with proxy. */ + CINIT(PROXYUSERPWD, STRINGPOINT, 6), + + /* Range to get, specified as an ASCII string. */ + CINIT(RANGE, STRINGPOINT, 7), + + /* not used */ + + /* Specified file stream to upload from (use as input): */ + CINIT(READDATA, OBJECTPOINT, 9), + + /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE + * bytes big. */ + CINIT(ERRORBUFFER, OBJECTPOINT, 10), + + /* Function that will be called to store the output (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CINIT(WRITEFUNCTION, FUNCTIONPOINT, 11), + + /* Function that will be called to read the input (instead of fread). The + * parameters will use fread() syntax, make sure to follow them. */ + CINIT(READFUNCTION, FUNCTIONPOINT, 12), + + /* Time-out the read operation after this amount of seconds */ + CINIT(TIMEOUT, LONG, 13), + + /* If the CURLOPT_INFILE is used, this can be used to inform libcurl about + * how large the file being sent really is. That allows better error + * checking and better verifies that the upload was successful. -1 means + * unknown size. + * + * For large file support, there is also a _LARGE version of the key + * which takes an off_t type, allowing platforms with larger off_t + * sizes to handle larger files. See below for INFILESIZE_LARGE. + */ + CINIT(INFILESIZE, LONG, 14), + + /* POST static input fields. */ + CINIT(POSTFIELDS, OBJECTPOINT, 15), + + /* Set the referrer page (needed by some CGIs) */ + CINIT(REFERER, STRINGPOINT, 16), + + /* Set the FTP PORT string (interface name, named or numerical IP address) + Use i.e '-' to use default address. */ + CINIT(FTPPORT, STRINGPOINT, 17), + + /* Set the User-Agent string (examined by some CGIs) */ + CINIT(USERAGENT, STRINGPOINT, 18), + + /* If the download receives less than "low speed limit" bytes/second + * during "low speed time" seconds, the operations is aborted. + * You could i.e if you have a pretty high speed connection, abort if + * it is less than 2000 bytes/sec during 20 seconds. + */ + + /* Set the "low speed limit" */ + CINIT(LOW_SPEED_LIMIT, LONG, 19), + + /* Set the "low speed time" */ + CINIT(LOW_SPEED_TIME, LONG, 20), + + /* Set the continuation offset. + * + * Note there is also a _LARGE version of this key which uses + * off_t types, allowing for large file offsets on platforms which + * use larger-than-32-bit off_t's. Look below for RESUME_FROM_LARGE. + */ + CINIT(RESUME_FROM, LONG, 21), + + /* Set cookie in request: */ + CINIT(COOKIE, STRINGPOINT, 22), + + /* This points to a linked list of headers, struct curl_slist kind. This + list is also used for RTSP (in spite of its name) */ + CINIT(HTTPHEADER, OBJECTPOINT, 23), + + /* This points to a linked list of post entries, struct curl_httppost */ + CINIT(HTTPPOST, OBJECTPOINT, 24), + + /* name of the file keeping your private SSL-certificate */ + CINIT(SSLCERT, STRINGPOINT, 25), + + /* password for the SSL or SSH private key */ + CINIT(KEYPASSWD, STRINGPOINT, 26), + + /* send TYPE parameter? */ + CINIT(CRLF, LONG, 27), + + /* send linked-list of QUOTE commands */ + CINIT(QUOTE, OBJECTPOINT, 28), + + /* send FILE * or void * to store headers to, if you use a callback it + is simply passed to the callback unmodified */ + CINIT(HEADERDATA, OBJECTPOINT, 29), + + /* point to a file to read the initial cookies from, also enables + "cookie awareness" */ + CINIT(COOKIEFILE, STRINGPOINT, 31), + + /* What version to specifically try to use. + See CURL_SSLVERSION defines below. */ + CINIT(SSLVERSION, LONG, 32), + + /* What kind of HTTP time condition to use, see defines */ + CINIT(TIMECONDITION, LONG, 33), + + /* Time to use with the above condition. Specified in number of seconds + since 1 Jan 1970 */ + CINIT(TIMEVALUE, LONG, 34), + + /* 35 = OBSOLETE */ + + /* Custom request, for customizing the get command like + HTTP: DELETE, TRACE and others + FTP: to use a different list command + */ + CINIT(CUSTOMREQUEST, STRINGPOINT, 36), + + /* FILE handle to use instead of stderr */ + CINIT(STDERR, OBJECTPOINT, 37), + + /* 38 is not used */ + + /* send linked-list of post-transfer QUOTE commands */ + CINIT(POSTQUOTE, OBJECTPOINT, 39), + + CINIT(OBSOLETE40, OBJECTPOINT, 40), /* OBSOLETE, do not use! */ + + CINIT(VERBOSE, LONG, 41), /* talk a lot */ + CINIT(HEADER, LONG, 42), /* throw the header out too */ + CINIT(NOPROGRESS, LONG, 43), /* shut off the progress meter */ + CINIT(NOBODY, LONG, 44), /* use HEAD to get http document */ + CINIT(FAILONERROR, LONG, 45), /* no output on http error codes >= 400 */ + CINIT(UPLOAD, LONG, 46), /* this is an upload */ + CINIT(POST, LONG, 47), /* HTTP POST method */ + CINIT(DIRLISTONLY, LONG, 48), /* bare names when listing directories */ + + CINIT(APPEND, LONG, 50), /* Append instead of overwrite on upload! */ + + /* Specify whether to read the user+password from the .netrc or the URL. + * This must be one of the CURL_NETRC_* enums below. */ + CINIT(NETRC, LONG, 51), + + CINIT(FOLLOWLOCATION, LONG, 52), /* use Location: Luke! */ + + CINIT(TRANSFERTEXT, LONG, 53), /* transfer data in text/ASCII format */ + CINIT(PUT, LONG, 54), /* HTTP PUT */ + + /* 55 = OBSOLETE */ + + /* DEPRECATED + * Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_progress_callback + * prototype defines. */ + CINIT(PROGRESSFUNCTION, FUNCTIONPOINT, 56), + + /* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION + callbacks */ + CINIT(PROGRESSDATA, OBJECTPOINT, 57), +#define CURLOPT_XFERINFODATA CURLOPT_PROGRESSDATA + + /* We want the referrer field set automatically when following locations */ + CINIT(AUTOREFERER, LONG, 58), + + /* Port of the proxy, can be set in the proxy string as well with: + "[host]:[port]" */ + CINIT(PROXYPORT, LONG, 59), + + /* size of the POST input data, if strlen() is not good to use */ + CINIT(POSTFIELDSIZE, LONG, 60), + + /* tunnel non-http operations through a HTTP proxy */ + CINIT(HTTPPROXYTUNNEL, LONG, 61), + + /* Set the interface string to use as outgoing network interface */ + CINIT(INTERFACE, STRINGPOINT, 62), + + /* Set the krb4/5 security level, this also enables krb4/5 awareness. This + * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string + * is set but doesn't match one of these, 'private' will be used. */ + CINIT(KRBLEVEL, STRINGPOINT, 63), + + /* Set if we should verify the peer in ssl handshake, set 1 to verify. */ + CINIT(SSL_VERIFYPEER, LONG, 64), + + /* The CApath or CAfile used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ + CINIT(CAINFO, STRINGPOINT, 65), + + /* 66 = OBSOLETE */ + /* 67 = OBSOLETE */ + + /* Maximum number of http redirects to follow */ + CINIT(MAXREDIRS, LONG, 68), + + /* Pass a long set to 1 to get the date of the requested document (if + possible)! Pass a zero to shut it off. */ + CINIT(FILETIME, LONG, 69), + + /* This points to a linked list of telnet options */ + CINIT(TELNETOPTIONS, OBJECTPOINT, 70), + + /* Max amount of cached alive connections */ + CINIT(MAXCONNECTS, LONG, 71), + + CINIT(OBSOLETE72, LONG, 72), /* OBSOLETE, do not use! */ + + /* 73 = OBSOLETE */ + + /* Set to explicitly use a new connection for the upcoming transfer. + Do not use this unless you're absolutely sure of this, as it makes the + operation slower and is less friendly for the network. */ + CINIT(FRESH_CONNECT, LONG, 74), + + /* Set to explicitly forbid the upcoming transfer's connection to be re-used + when done. Do not use this unless you're absolutely sure of this, as it + makes the operation slower and is less friendly for the network. */ + CINIT(FORBID_REUSE, LONG, 75), + + /* Set to a file name that contains random data for libcurl to use to + seed the random engine when doing SSL connects. */ + CINIT(RANDOM_FILE, STRINGPOINT, 76), + + /* Set to the Entropy Gathering Daemon socket pathname */ + CINIT(EGDSOCKET, STRINGPOINT, 77), + + /* Time-out connect operations after this amount of seconds, if connects are + OK within this time, then fine... This only aborts the connect phase. */ + CINIT(CONNECTTIMEOUT, LONG, 78), + + /* Function that will be called to store headers (instead of fwrite). The + * parameters will use fwrite() syntax, make sure to follow them. */ + CINIT(HEADERFUNCTION, FUNCTIONPOINT, 79), + + /* Set this to force the HTTP request to get back to GET. Only really usable + if POST, PUT or a custom request have been used first. + */ + CINIT(HTTPGET, LONG, 80), + + /* Set if we should verify the Common name from the peer certificate in ssl + * handshake, set 1 to check existence, 2 to ensure that it matches the + * provided hostname. */ + CINIT(SSL_VERIFYHOST, LONG, 81), + + /* Specify which file name to write all known cookies in after completed + operation. Set file name to "-" (dash) to make it go to stdout. */ + CINIT(COOKIEJAR, STRINGPOINT, 82), + + /* Specify which SSL ciphers to use */ + CINIT(SSL_CIPHER_LIST, STRINGPOINT, 83), + + /* Specify which HTTP version to use! This must be set to one of the + CURL_HTTP_VERSION* enums set below. */ + CINIT(HTTP_VERSION, LONG, 84), + + /* Specifically switch on or off the FTP engine's use of the EPSV command. By + default, that one will always be attempted before the more traditional + PASV command. */ + CINIT(FTP_USE_EPSV, LONG, 85), + + /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */ + CINIT(SSLCERTTYPE, STRINGPOINT, 86), + + /* name of the file keeping your private SSL-key */ + CINIT(SSLKEY, STRINGPOINT, 87), + + /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */ + CINIT(SSLKEYTYPE, STRINGPOINT, 88), + + /* crypto engine for the SSL-sub system */ + CINIT(SSLENGINE, STRINGPOINT, 89), + + /* set the crypto engine for the SSL-sub system as default + the param has no meaning... + */ + CINIT(SSLENGINE_DEFAULT, LONG, 90), + + /* Non-zero value means to use the global dns cache */ + CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* DEPRECATED, do not use! */ + + /* DNS cache timeout */ + CINIT(DNS_CACHE_TIMEOUT, LONG, 92), + + /* send linked-list of pre-transfer QUOTE commands */ + CINIT(PREQUOTE, OBJECTPOINT, 93), + + /* set the debug function */ + CINIT(DEBUGFUNCTION, FUNCTIONPOINT, 94), + + /* set the data for the debug function */ + CINIT(DEBUGDATA, OBJECTPOINT, 95), + + /* mark this as start of a cookie session */ + CINIT(COOKIESESSION, LONG, 96), + + /* The CApath directory used to validate the peer certificate + this option is used only if SSL_VERIFYPEER is true */ + CINIT(CAPATH, STRINGPOINT, 97), + + /* Instruct libcurl to use a smaller receive buffer */ + CINIT(BUFFERSIZE, LONG, 98), + + /* Instruct libcurl to not use any signal/alarm handlers, even when using + timeouts. This option is useful for multi-threaded applications. + See libcurl-the-guide for more background information. */ + CINIT(NOSIGNAL, LONG, 99), + + /* Provide a CURLShare for mutexing non-ts data */ + CINIT(SHARE, OBJECTPOINT, 100), + + /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default), + CURLPROXY_HTTPS, CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and + CURLPROXY_SOCKS5. */ + CINIT(PROXYTYPE, LONG, 101), + + /* Set the Accept-Encoding string. Use this to tell a server you would like + the response to be compressed. Before 7.21.6, this was known as + CURLOPT_ENCODING */ + CINIT(ACCEPT_ENCODING, STRINGPOINT, 102), + + /* Set pointer to private data */ + CINIT(PRIVATE, OBJECTPOINT, 103), + + /* Set aliases for HTTP 200 in the HTTP Response header */ + CINIT(HTTP200ALIASES, OBJECTPOINT, 104), + + /* Continue to send authentication (user+password) when following locations, + even when hostname changed. This can potentially send off the name + and password to whatever host the server decides. */ + CINIT(UNRESTRICTED_AUTH, LONG, 105), + + /* Specifically switch on or off the FTP engine's use of the EPRT command ( + it also disables the LPRT attempt). By default, those ones will always be + attempted before the good old traditional PORT command. */ + CINIT(FTP_USE_EPRT, LONG, 106), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_USERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CINIT(HTTPAUTH, LONG, 107), + + /* Set the ssl context callback function, currently only for OpenSSL ssl_ctx + in second argument. The function must be matching the + curl_ssl_ctx_callback proto. */ + CINIT(SSL_CTX_FUNCTION, FUNCTIONPOINT, 108), + + /* Set the userdata for the ssl context callback function's third + argument */ + CINIT(SSL_CTX_DATA, OBJECTPOINT, 109), + + /* FTP Option that causes missing dirs to be created on the remote server. + In 7.19.4 we introduced the convenience enums for this option using the + CURLFTP_CREATE_DIR prefix. + */ + CINIT(FTP_CREATE_MISSING_DIRS, LONG, 110), + + /* Set this to a bitmask value to enable the particular authentications + methods you like. Use this in combination with CURLOPT_PROXYUSERPWD. + Note that setting multiple bits may cause extra network round-trips. */ + CINIT(PROXYAUTH, LONG, 111), + + /* FTP option that changes the timeout, in seconds, associated with + getting a response. This is different from transfer timeout time and + essentially places a demand on the FTP server to acknowledge commands + in a timely manner. */ + CINIT(FTP_RESPONSE_TIMEOUT, LONG, 112), +#define CURLOPT_SERVER_RESPONSE_TIMEOUT CURLOPT_FTP_RESPONSE_TIMEOUT + + /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to + tell libcurl to resolve names to those IP versions only. This only has + affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */ + CINIT(IPRESOLVE, LONG, 113), + + /* Set this option to limit the size of a file that will be downloaded from + an HTTP or FTP server. + + Note there is also _LARGE version which adds large file support for + platforms which have larger off_t sizes. See MAXFILESIZE_LARGE below. */ + CINIT(MAXFILESIZE, LONG, 114), + + /* See the comment for INFILESIZE above, but in short, specifies + * the size of the file being uploaded. -1 means unknown. + */ + CINIT(INFILESIZE_LARGE, OFF_T, 115), + + /* Sets the continuation offset. There is also a LONG version of this; + * look above for RESUME_FROM. + */ + CINIT(RESUME_FROM_LARGE, OFF_T, 116), + + /* Sets the maximum size of data that will be downloaded from + * an HTTP or FTP server. See MAXFILESIZE above for the LONG version. + */ + CINIT(MAXFILESIZE_LARGE, OFF_T, 117), + + /* Set this option to the file name of your .netrc file you want libcurl + to parse (using the CURLOPT_NETRC option). If not set, libcurl will do + a poor attempt to find the user's home directory and check for a .netrc + file in there. */ + CINIT(NETRC_FILE, STRINGPOINT, 118), + + /* Enable SSL/TLS for FTP, pick one of: + CURLUSESSL_TRY - try using SSL, proceed anyway otherwise + CURLUSESSL_CONTROL - SSL for the control connection or fail + CURLUSESSL_ALL - SSL for all communication or fail + */ + CINIT(USE_SSL, LONG, 119), + + /* The _LARGE version of the standard POSTFIELDSIZE option */ + CINIT(POSTFIELDSIZE_LARGE, OFF_T, 120), + + /* Enable/disable the TCP Nagle algorithm */ + CINIT(TCP_NODELAY, LONG, 121), + + /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 123 OBSOLETE. Gone in 7.16.0 */ + /* 124 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 125 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 126 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ + /* 127 OBSOLETE. Gone in 7.16.0 */ + /* 128 OBSOLETE. Gone in 7.16.0 */ + + /* When FTP over SSL/TLS is selected (with CURLOPT_USE_SSL), this option + can be used to change libcurl's default action which is to first try + "AUTH SSL" and then "AUTH TLS" in this order, and proceed when a OK + response has been received. + + Available parameters are: + CURLFTPAUTH_DEFAULT - let libcurl decide + CURLFTPAUTH_SSL - try "AUTH SSL" first, then TLS + CURLFTPAUTH_TLS - try "AUTH TLS" first, then SSL + */ + CINIT(FTPSSLAUTH, LONG, 129), + + CINIT(IOCTLFUNCTION, FUNCTIONPOINT, 130), + CINIT(IOCTLDATA, OBJECTPOINT, 131), + + /* 132 OBSOLETE. Gone in 7.16.0 */ + /* 133 OBSOLETE. Gone in 7.16.0 */ + + /* zero terminated string for pass on to the FTP server when asked for + "account" info */ + CINIT(FTP_ACCOUNT, STRINGPOINT, 134), + + /* feed cookie into cookie engine */ + CINIT(COOKIELIST, STRINGPOINT, 135), + + /* ignore Content-Length */ + CINIT(IGNORE_CONTENT_LENGTH, LONG, 136), + + /* Set to non-zero to skip the IP address received in a 227 PASV FTP server + response. Typically used for FTP-SSL purposes but is not restricted to + that. libcurl will then instead use the same IP address it used for the + control connection. */ + CINIT(FTP_SKIP_PASV_IP, LONG, 137), + + /* Select "file method" to use when doing FTP, see the curl_ftpmethod + above. */ + CINIT(FTP_FILEMETHOD, LONG, 138), + + /* Local port number to bind the socket to */ + CINIT(LOCALPORT, LONG, 139), + + /* Number of ports to try, including the first one set with LOCALPORT. + Thus, setting it to 1 will make no additional attempts but the first. + */ + CINIT(LOCALPORTRANGE, LONG, 140), + + /* no transfer, set up connection and let application use the socket by + extracting it with CURLINFO_LASTSOCKET */ + CINIT(CONNECT_ONLY, LONG, 141), + + /* Function that will be called to convert from the + network encoding (instead of using the iconv calls in libcurl) */ + CINIT(CONV_FROM_NETWORK_FUNCTION, FUNCTIONPOINT, 142), + + /* Function that will be called to convert to the + network encoding (instead of using the iconv calls in libcurl) */ + CINIT(CONV_TO_NETWORK_FUNCTION, FUNCTIONPOINT, 143), + + /* Function that will be called to convert from UTF8 + (instead of using the iconv calls in libcurl) + Note that this is used only for SSL certificate processing */ + CINIT(CONV_FROM_UTF8_FUNCTION, FUNCTIONPOINT, 144), + + /* if the connection proceeds too quickly then need to slow it down */ + /* limit-rate: maximum number of bytes per second to send or receive */ + CINIT(MAX_SEND_SPEED_LARGE, OFF_T, 145), + CINIT(MAX_RECV_SPEED_LARGE, OFF_T, 146), + + /* Pointer to command string to send if USER/PASS fails. */ + CINIT(FTP_ALTERNATIVE_TO_USER, STRINGPOINT, 147), + + /* callback function for setting socket options */ + CINIT(SOCKOPTFUNCTION, FUNCTIONPOINT, 148), + CINIT(SOCKOPTDATA, OBJECTPOINT, 149), + + /* set to 0 to disable session ID re-use for this transfer, default is + enabled (== 1) */ + CINIT(SSL_SESSIONID_CACHE, LONG, 150), + + /* allowed SSH authentication methods */ + CINIT(SSH_AUTH_TYPES, LONG, 151), + + /* Used by scp/sftp to do public/private key authentication */ + CINIT(SSH_PUBLIC_KEYFILE, STRINGPOINT, 152), + CINIT(SSH_PRIVATE_KEYFILE, STRINGPOINT, 153), + + /* Send CCC (Clear Command Channel) after authentication */ + CINIT(FTP_SSL_CCC, LONG, 154), + + /* Same as TIMEOUT and CONNECTTIMEOUT, but with ms resolution */ + CINIT(TIMEOUT_MS, LONG, 155), + CINIT(CONNECTTIMEOUT_MS, LONG, 156), + + /* set to zero to disable the libcurl's decoding and thus pass the raw body + data to the application even when it is encoded/compressed */ + CINIT(HTTP_TRANSFER_DECODING, LONG, 157), + CINIT(HTTP_CONTENT_DECODING, LONG, 158), + + /* Permission used when creating new files and directories on the remote + server for protocols that support it, SFTP/SCP/FILE */ + CINIT(NEW_FILE_PERMS, LONG, 159), + CINIT(NEW_DIRECTORY_PERMS, LONG, 160), + + /* Set the behaviour of POST when redirecting. Values must be set to one + of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */ + CINIT(POSTREDIR, LONG, 161), + + /* used by scp/sftp to verify the host's public key */ + CINIT(SSH_HOST_PUBLIC_KEY_MD5, STRINGPOINT, 162), + + /* Callback function for opening socket (instead of socket(2)). Optionally, + callback is able change the address or refuse to connect returning + CURL_SOCKET_BAD. The callback should have type + curl_opensocket_callback */ + CINIT(OPENSOCKETFUNCTION, FUNCTIONPOINT, 163), + CINIT(OPENSOCKETDATA, OBJECTPOINT, 164), + + /* POST volatile input fields. */ + CINIT(COPYPOSTFIELDS, OBJECTPOINT, 165), + + /* set transfer mode (;type=) when doing FTP via an HTTP proxy */ + CINIT(PROXY_TRANSFER_MODE, LONG, 166), + + /* Callback function for seeking in the input stream */ + CINIT(SEEKFUNCTION, FUNCTIONPOINT, 167), + CINIT(SEEKDATA, OBJECTPOINT, 168), + + /* CRL file */ + CINIT(CRLFILE, STRINGPOINT, 169), + + /* Issuer certificate */ + CINIT(ISSUERCERT, STRINGPOINT, 170), + + /* (IPv6) Address scope */ + CINIT(ADDRESS_SCOPE, LONG, 171), + + /* Collect certificate chain info and allow it to get retrievable with + CURLINFO_CERTINFO after the transfer is complete. */ + CINIT(CERTINFO, LONG, 172), + + /* "name" and "pwd" to use when fetching. */ + CINIT(USERNAME, STRINGPOINT, 173), + CINIT(PASSWORD, STRINGPOINT, 174), + + /* "name" and "pwd" to use with Proxy when fetching. */ + CINIT(PROXYUSERNAME, STRINGPOINT, 175), + CINIT(PROXYPASSWORD, STRINGPOINT, 176), + + /* Comma separated list of hostnames defining no-proxy zones. These should + match both hostnames directly, and hostnames within a domain. For + example, local.com will match local.com and www.local.com, but NOT + notlocal.com or www.notlocal.com. For compatibility with other + implementations of this, .local.com will be considered to be the same as + local.com. A single * is the only valid wildcard, and effectively + disables the use of proxy. */ + CINIT(NOPROXY, STRINGPOINT, 177), + + /* block size for TFTP transfers */ + CINIT(TFTP_BLKSIZE, LONG, 178), + + /* Socks Service */ + CINIT(SOCKS5_GSSAPI_SERVICE, STRINGPOINT, 179), /* DEPRECATED, do not use! */ + + /* Socks Service */ + CINIT(SOCKS5_GSSAPI_NEC, LONG, 180), + + /* set the bitmask for the protocols that are allowed to be used for the + transfer, which thus helps the app which takes URLs from users or other + external inputs and want to restrict what protocol(s) to deal + with. Defaults to CURLPROTO_ALL. */ + CINIT(PROTOCOLS, LONG, 181), + + /* set the bitmask for the protocols that libcurl is allowed to follow to, + as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs + to be set in both bitmasks to be allowed to get redirected to. Defaults + to all protocols except FILE and SCP. */ + CINIT(REDIR_PROTOCOLS, LONG, 182), + + /* set the SSH knownhost file name to use */ + CINIT(SSH_KNOWNHOSTS, STRINGPOINT, 183), + + /* set the SSH host key callback, must point to a curl_sshkeycallback + function */ + CINIT(SSH_KEYFUNCTION, FUNCTIONPOINT, 184), + + /* set the SSH host key callback custom pointer */ + CINIT(SSH_KEYDATA, OBJECTPOINT, 185), + + /* set the SMTP mail originator */ + CINIT(MAIL_FROM, STRINGPOINT, 186), + + /* set the list of SMTP mail receiver(s) */ + CINIT(MAIL_RCPT, OBJECTPOINT, 187), + + /* FTP: send PRET before PASV */ + CINIT(FTP_USE_PRET, LONG, 188), + + /* RTSP request method (OPTIONS, SETUP, PLAY, etc...) */ + CINIT(RTSP_REQUEST, LONG, 189), + + /* The RTSP session identifier */ + CINIT(RTSP_SESSION_ID, STRINGPOINT, 190), + + /* The RTSP stream URI */ + CINIT(RTSP_STREAM_URI, STRINGPOINT, 191), + + /* The Transport: header to use in RTSP requests */ + CINIT(RTSP_TRANSPORT, STRINGPOINT, 192), + + /* Manually initialize the client RTSP CSeq for this handle */ + CINIT(RTSP_CLIENT_CSEQ, LONG, 193), + + /* Manually initialize the server RTSP CSeq for this handle */ + CINIT(RTSP_SERVER_CSEQ, LONG, 194), + + /* The stream to pass to INTERLEAVEFUNCTION. */ + CINIT(INTERLEAVEDATA, OBJECTPOINT, 195), + + /* Let the application define a custom write method for RTP data */ + CINIT(INTERLEAVEFUNCTION, FUNCTIONPOINT, 196), + + /* Turn on wildcard matching */ + CINIT(WILDCARDMATCH, LONG, 197), + + /* Directory matching callback called before downloading of an + individual file (chunk) started */ + CINIT(CHUNK_BGN_FUNCTION, FUNCTIONPOINT, 198), + + /* Directory matching callback called after the file (chunk) + was downloaded, or skipped */ + CINIT(CHUNK_END_FUNCTION, FUNCTIONPOINT, 199), + + /* Change match (fnmatch-like) callback for wildcard matching */ + CINIT(FNMATCH_FUNCTION, FUNCTIONPOINT, 200), + + /* Let the application define custom chunk data pointer */ + CINIT(CHUNK_DATA, OBJECTPOINT, 201), + + /* FNMATCH_FUNCTION user pointer */ + CINIT(FNMATCH_DATA, OBJECTPOINT, 202), + + /* send linked-list of name:port:address sets */ + CINIT(RESOLVE, OBJECTPOINT, 203), + + /* Set a username for authenticated TLS */ + CINIT(TLSAUTH_USERNAME, STRINGPOINT, 204), + + /* Set a password for authenticated TLS */ + CINIT(TLSAUTH_PASSWORD, STRINGPOINT, 205), + + /* Set authentication type for authenticated TLS */ + CINIT(TLSAUTH_TYPE, STRINGPOINT, 206), + + /* Set to 1 to enable the "TE:" header in HTTP requests to ask for + compressed transfer-encoded responses. Set to 0 to disable the use of TE: + in outgoing requests. The current default is 0, but it might change in a + future libcurl release. + + libcurl will ask for the compressed methods it knows of, and if that + isn't any, it will not ask for transfer-encoding at all even if this + option is set to 1. + + */ + CINIT(TRANSFER_ENCODING, LONG, 207), + + /* Callback function for closing socket (instead of close(2)). The callback + should have type curl_closesocket_callback */ + CINIT(CLOSESOCKETFUNCTION, FUNCTIONPOINT, 208), + CINIT(CLOSESOCKETDATA, OBJECTPOINT, 209), + + /* allow GSSAPI credential delegation */ + CINIT(GSSAPI_DELEGATION, LONG, 210), + + /* Set the name servers to use for DNS resolution */ + CINIT(DNS_SERVERS, STRINGPOINT, 211), + + /* Time-out accept operations (currently for FTP only) after this amount + of milliseconds. */ + CINIT(ACCEPTTIMEOUT_MS, LONG, 212), + + /* Set TCP keepalive */ + CINIT(TCP_KEEPALIVE, LONG, 213), + + /* non-universal keepalive knobs (Linux, AIX, HP-UX, more) */ + CINIT(TCP_KEEPIDLE, LONG, 214), + CINIT(TCP_KEEPINTVL, LONG, 215), + + /* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */ + CINIT(SSL_OPTIONS, LONG, 216), + + /* Set the SMTP auth originator */ + CINIT(MAIL_AUTH, STRINGPOINT, 217), + + /* Enable/disable SASL initial response */ + CINIT(SASL_IR, LONG, 218), + + /* Function that will be called instead of the internal progress display + * function. This function should be defined as the curl_xferinfo_callback + * prototype defines. (Deprecates CURLOPT_PROGRESSFUNCTION) */ + CINIT(XFERINFOFUNCTION, FUNCTIONPOINT, 219), + + /* The XOAUTH2 bearer token */ + CINIT(XOAUTH2_BEARER, STRINGPOINT, 220), + + /* Set the interface string to use as outgoing network + * interface for DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_INTERFACE, STRINGPOINT, 221), + + /* Set the local IPv4 address to use for outgoing DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_LOCAL_IP4, STRINGPOINT, 222), + + /* Set the local IPv6 address to use for outgoing DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_LOCAL_IP6, STRINGPOINT, 223), + + /* Set authentication options directly */ + CINIT(LOGIN_OPTIONS, STRINGPOINT, 224), + + /* Enable/disable TLS NPN extension (http2 over ssl might fail without) */ + CINIT(SSL_ENABLE_NPN, LONG, 225), + + /* Enable/disable TLS ALPN extension (http2 over ssl might fail without) */ + CINIT(SSL_ENABLE_ALPN, LONG, 226), + + /* Time to wait for a response to a HTTP request containing an + * Expect: 100-continue header before sending the data anyway. */ + CINIT(EXPECT_100_TIMEOUT_MS, LONG, 227), + + /* This points to a linked list of headers used for proxy requests only, + struct curl_slist kind */ + CINIT(PROXYHEADER, OBJECTPOINT, 228), + + /* Pass in a bitmask of "header options" */ + CINIT(HEADEROPT, LONG, 229), + + /* The public key in DER form used to validate the peer public key + this option is used only if SSL_VERIFYPEER is true */ + CINIT(PINNEDPUBLICKEY, STRINGPOINT, 230), + + /* Path to Unix domain socket */ + CINIT(UNIX_SOCKET_PATH, STRINGPOINT, 231), + + /* Set if we should verify the certificate status. */ + CINIT(SSL_VERIFYSTATUS, LONG, 232), + + /* Set if we should enable TLS false start. */ + CINIT(SSL_FALSESTART, LONG, 233), + + /* Do not squash dot-dot sequences */ + CINIT(PATH_AS_IS, LONG, 234), + + /* Proxy Service Name */ + CINIT(PROXY_SERVICE_NAME, STRINGPOINT, 235), + + /* Service Name */ + CINIT(SERVICE_NAME, STRINGPOINT, 236), + + /* Wait/don't wait for pipe/mutex to clarify */ + CINIT(PIPEWAIT, LONG, 237), + + /* Set the protocol used when curl is given a URL without a protocol */ + CINIT(DEFAULT_PROTOCOL, STRINGPOINT, 238), + + /* Set stream weight, 1 - 256 (default is 16) */ + CINIT(STREAM_WEIGHT, LONG, 239), + + /* Set stream dependency on another CURL handle */ + CINIT(STREAM_DEPENDS, OBJECTPOINT, 240), + + /* Set E-xclusive stream dependency on another CURL handle */ + CINIT(STREAM_DEPENDS_E, OBJECTPOINT, 241), + + /* Do not send any tftp option requests to the server */ + CINIT(TFTP_NO_OPTIONS, LONG, 242), + + /* Linked-list of host:port:connect-to-host:connect-to-port, + overrides the URL's host:port (only for the network layer) */ + CINIT(CONNECT_TO, OBJECTPOINT, 243), + + /* Set TCP Fast Open */ + CINIT(TCP_FASTOPEN, LONG, 244), + + /* Continue to send data if the server responds early with an + * HTTP status code >= 300 */ + CINIT(KEEP_SENDING_ON_ERROR, LONG, 245), + + /* The CApath or CAfile used to validate the proxy certificate + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CINIT(PROXY_CAINFO, STRINGPOINT, 246), + + /* The CApath directory used to validate the proxy certificate + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CINIT(PROXY_CAPATH, STRINGPOINT, 247), + + /* Set if we should verify the proxy in ssl handshake, + set 1 to verify. */ + CINIT(PROXY_SSL_VERIFYPEER, LONG, 248), + + /* Set if we should verify the Common name from the proxy certificate in ssl + * handshake, set 1 to check existence, 2 to ensure that it matches + * the provided hostname. */ + CINIT(PROXY_SSL_VERIFYHOST, LONG, 249), + + /* What version to specifically try to use for proxy. + See CURL_SSLVERSION defines below. */ + CINIT(PROXY_SSLVERSION, LONG, 250), + + /* Set a username for authenticated TLS for proxy */ + CINIT(PROXY_TLSAUTH_USERNAME, STRINGPOINT, 251), + + /* Set a password for authenticated TLS for proxy */ + CINIT(PROXY_TLSAUTH_PASSWORD, STRINGPOINT, 252), + + /* Set authentication type for authenticated TLS for proxy */ + CINIT(PROXY_TLSAUTH_TYPE, STRINGPOINT, 253), + + /* name of the file keeping your private SSL-certificate for proxy */ + CINIT(PROXY_SSLCERT, STRINGPOINT, 254), + + /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") for + proxy */ + CINIT(PROXY_SSLCERTTYPE, STRINGPOINT, 255), + + /* name of the file keeping your private SSL-key for proxy */ + CINIT(PROXY_SSLKEY, STRINGPOINT, 256), + + /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") for + proxy */ + CINIT(PROXY_SSLKEYTYPE, STRINGPOINT, 257), + + /* password for the SSL private key for proxy */ + CINIT(PROXY_KEYPASSWD, STRINGPOINT, 258), + + /* Specify which SSL ciphers to use for proxy */ + CINIT(PROXY_SSL_CIPHER_LIST, STRINGPOINT, 259), + + /* CRL file for proxy */ + CINIT(PROXY_CRLFILE, STRINGPOINT, 260), + + /* Enable/disable specific SSL features with a bitmask for proxy, see + CURLSSLOPT_* */ + CINIT(PROXY_SSL_OPTIONS, LONG, 261), + + /* Name of pre proxy to use. */ + CINIT(PRE_PROXY, STRINGPOINT, 262), + + /* The public key in DER form used to validate the proxy public key + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CINIT(PROXY_PINNEDPUBLICKEY, STRINGPOINT, 263), + + /* Path to an abstract Unix domain socket */ + CINIT(ABSTRACT_UNIX_SOCKET, STRINGPOINT, 264), + + /* Suppress proxy CONNECT response headers from user callbacks */ + CINIT(SUPPRESS_CONNECT_HEADERS, LONG, 265), + + /* The request target, instead of extracted from the URL */ + CINIT(REQUEST_TARGET, STRINGPOINT, 266), + + /* bitmask of allowed auth methods for connections to SOCKS5 proxies */ + CINIT(SOCKS5_AUTH, LONG, 267), + + /* Enable/disable SSH compression */ + CINIT(SSH_COMPRESSION, LONG, 268), + + /* Post MIME data. */ + CINIT(MIMEPOST, OBJECTPOINT, 269), + + /* Time to use with the CURLOPT_TIMECONDITION. Specified in number of + seconds since 1 Jan 1970. */ + CINIT(TIMEVALUE_LARGE, OFF_T, 270), + + /* Head start in milliseconds to give happy eyeballs. */ + CINIT(HAPPY_EYEBALLS_TIMEOUT_MS, LONG, 271), + + /* Function that will be called before a resolver request is made */ + CINIT(RESOLVER_START_FUNCTION, FUNCTIONPOINT, 272), + + /* User data to pass to the resolver start callback. */ + CINIT(RESOLVER_START_DATA, OBJECTPOINT, 273), + + /* send HAProxy PROXY protocol header? */ + CINIT(HAPROXYPROTOCOL, LONG, 274), + + /* shuffle addresses before use when DNS returns multiple */ + CINIT(DNS_SHUFFLE_ADDRESSES, LONG, 275), + + /* Specify which TLS 1.3 ciphers suites to use */ + CINIT(TLS13_CIPHERS, STRINGPOINT, 276), + CINIT(PROXY_TLS13_CIPHERS, STRINGPOINT, 277), + + /* Disallow specifying username/login in URL. */ + CINIT(DISALLOW_USERNAME_IN_URL, LONG, 278), + + /* DNS-over-HTTPS URL */ + CINIT(DOH_URL, STRINGPOINT, 279), + + /* Preferred buffer size to use for uploads */ + CINIT(UPLOAD_BUFFERSIZE, LONG, 280), + + /* Time in ms between connection upkeep calls for long-lived connections. */ + CINIT(UPKEEP_INTERVAL_MS, LONG, 281), + + /* Specify URL using CURL URL API. */ + CINIT(CURLU, OBJECTPOINT, 282), + + /* add trailing data just after no more data is available */ + CINIT(TRAILERFUNCTION, FUNCTIONPOINT, 283), + + /* pointer to be passed to HTTP_TRAILER_FUNCTION */ + CINIT(TRAILERDATA, OBJECTPOINT, 284), + + /* set this to 1L to allow HTTP/0.9 responses or 0L to disallow */ + CINIT(HTTP09_ALLOWED, LONG, 285), + + CURLOPT_LASTENTRY /* the last unused */ +} CURLoption; + +#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all + the obsolete stuff removed! */ + +/* Backwards compatibility with older names */ +/* These are scheduled to disappear by 2011 */ + +/* This was added in version 7.19.1 */ +#define CURLOPT_POST301 CURLOPT_POSTREDIR + +/* These are scheduled to disappear by 2009 */ + +/* The following were added in 7.17.0 */ +#define CURLOPT_SSLKEYPASSWD CURLOPT_KEYPASSWD +#define CURLOPT_FTPAPPEND CURLOPT_APPEND +#define CURLOPT_FTPLISTONLY CURLOPT_DIRLISTONLY +#define CURLOPT_FTP_SSL CURLOPT_USE_SSL + +/* The following were added earlier */ + +#define CURLOPT_SSLCERTPASSWD CURLOPT_KEYPASSWD +#define CURLOPT_KRB4LEVEL CURLOPT_KRBLEVEL + +#else +/* This is set if CURL_NO_OLDIES is defined at compile-time */ +#undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */ +#endif + + + /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host + name resolves addresses using more than one IP protocol version, this + option might be handy to force libcurl to use a specific IP version. */ +#define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP + versions that your system allows */ +#define CURL_IPRESOLVE_V4 1 /* resolve to IPv4 addresses */ +#define CURL_IPRESOLVE_V6 2 /* resolve to IPv6 addresses */ + + /* three convenient "aliases" that follow the name scheme better */ +#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER + + /* These enums are for use with the CURLOPT_HTTP_VERSION option. */ +enum { + CURL_HTTP_VERSION_NONE, /* setting this means we don't care, and that we'd + like the library to choose the best possible + for us! */ + CURL_HTTP_VERSION_1_0, /* please use HTTP 1.0 in the request */ + CURL_HTTP_VERSION_1_1, /* please use HTTP 1.1 in the request */ + CURL_HTTP_VERSION_2_0, /* please use HTTP 2 in the request */ + CURL_HTTP_VERSION_2TLS, /* use version 2 for HTTPS, version 1.1 for HTTP */ + CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE, /* please use HTTP 2 without HTTP/1.1 + Upgrade */ + + CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */ +}; + +/* Convenience definition simple because the name of the version is HTTP/2 and + not 2.0. The 2_0 version of the enum name was set while the version was + still planned to be 2.0 and we stick to it for compatibility. */ +#define CURL_HTTP_VERSION_2 CURL_HTTP_VERSION_2_0 + +/* + * Public API enums for RTSP requests + */ +enum { + CURL_RTSPREQ_NONE, /* first in list */ + CURL_RTSPREQ_OPTIONS, + CURL_RTSPREQ_DESCRIBE, + CURL_RTSPREQ_ANNOUNCE, + CURL_RTSPREQ_SETUP, + CURL_RTSPREQ_PLAY, + CURL_RTSPREQ_PAUSE, + CURL_RTSPREQ_TEARDOWN, + CURL_RTSPREQ_GET_PARAMETER, + CURL_RTSPREQ_SET_PARAMETER, + CURL_RTSPREQ_RECORD, + CURL_RTSPREQ_RECEIVE, + CURL_RTSPREQ_LAST /* last in list */ +}; + + /* These enums are for use with the CURLOPT_NETRC option. */ +enum CURL_NETRC_OPTION { + CURL_NETRC_IGNORED, /* The .netrc will never be read. + * This is the default. */ + CURL_NETRC_OPTIONAL, /* A user:password in the URL will be preferred + * to one in the .netrc. */ + CURL_NETRC_REQUIRED, /* A user:password in the URL will be ignored. + * Unless one is set programmatically, the .netrc + * will be queried. */ + CURL_NETRC_LAST +}; + +enum { + CURL_SSLVERSION_DEFAULT, + CURL_SSLVERSION_TLSv1, /* TLS 1.x */ + CURL_SSLVERSION_SSLv2, + CURL_SSLVERSION_SSLv3, + CURL_SSLVERSION_TLSv1_0, + CURL_SSLVERSION_TLSv1_1, + CURL_SSLVERSION_TLSv1_2, + CURL_SSLVERSION_TLSv1_3, + + CURL_SSLVERSION_LAST /* never use, keep last */ +}; + +enum { + CURL_SSLVERSION_MAX_NONE = 0, + CURL_SSLVERSION_MAX_DEFAULT = (CURL_SSLVERSION_TLSv1 << 16), + CURL_SSLVERSION_MAX_TLSv1_0 = (CURL_SSLVERSION_TLSv1_0 << 16), + CURL_SSLVERSION_MAX_TLSv1_1 = (CURL_SSLVERSION_TLSv1_1 << 16), + CURL_SSLVERSION_MAX_TLSv1_2 = (CURL_SSLVERSION_TLSv1_2 << 16), + CURL_SSLVERSION_MAX_TLSv1_3 = (CURL_SSLVERSION_TLSv1_3 << 16), + + /* never use, keep last */ + CURL_SSLVERSION_MAX_LAST = (CURL_SSLVERSION_LAST << 16) +}; + +enum CURL_TLSAUTH { + CURL_TLSAUTH_NONE, + CURL_TLSAUTH_SRP, + CURL_TLSAUTH_LAST /* never use, keep last */ +}; + +/* symbols to use with CURLOPT_POSTREDIR. + CURL_REDIR_POST_301, CURL_REDIR_POST_302 and CURL_REDIR_POST_303 + can be bitwise ORed so that CURL_REDIR_POST_301 | CURL_REDIR_POST_302 + | CURL_REDIR_POST_303 == CURL_REDIR_POST_ALL */ + +#define CURL_REDIR_GET_ALL 0 +#define CURL_REDIR_POST_301 1 +#define CURL_REDIR_POST_302 2 +#define CURL_REDIR_POST_303 4 +#define CURL_REDIR_POST_ALL \ + (CURL_REDIR_POST_301|CURL_REDIR_POST_302|CURL_REDIR_POST_303) + +typedef enum { + CURL_TIMECOND_NONE, + + CURL_TIMECOND_IFMODSINCE, + CURL_TIMECOND_IFUNMODSINCE, + CURL_TIMECOND_LASTMOD, + + CURL_TIMECOND_LAST +} curl_TimeCond; + +/* Special size_t value signaling a zero-terminated string. */ +#define CURL_ZERO_TERMINATED ((size_t) -1) + +/* curl_strequal() and curl_strnequal() are subject for removal in a future + release */ +CURL_EXTERN int curl_strequal(const char *s1, const char *s2); +CURL_EXTERN int curl_strnequal(const char *s1, const char *s2, size_t n); + +/* Mime/form handling support. */ +typedef struct curl_mime_s curl_mime; /* Mime context. */ +typedef struct curl_mimepart_s curl_mimepart; /* Mime part context. */ + +/* + * NAME curl_mime_init() + * + * DESCRIPTION + * + * Create a mime context and return its handle. The easy parameter is the + * target handle. + */ +CURL_EXTERN curl_mime *curl_mime_init(CURL *easy); + +/* + * NAME curl_mime_free() + * + * DESCRIPTION + * + * release a mime handle and its substructures. + */ +CURL_EXTERN void curl_mime_free(curl_mime *mime); + +/* + * NAME curl_mime_addpart() + * + * DESCRIPTION + * + * Append a new empty part to the given mime context and return a handle to + * the created part. + */ +CURL_EXTERN curl_mimepart *curl_mime_addpart(curl_mime *mime); + +/* + * NAME curl_mime_name() + * + * DESCRIPTION + * + * Set mime/form part name. + */ +CURL_EXTERN CURLcode curl_mime_name(curl_mimepart *part, const char *name); + +/* + * NAME curl_mime_filename() + * + * DESCRIPTION + * + * Set mime part remote file name. + */ +CURL_EXTERN CURLcode curl_mime_filename(curl_mimepart *part, + const char *filename); + +/* + * NAME curl_mime_type() + * + * DESCRIPTION + * + * Set mime part type. + */ +CURL_EXTERN CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype); + +/* + * NAME curl_mime_encoder() + * + * DESCRIPTION + * + * Set mime data transfer encoder. + */ +CURL_EXTERN CURLcode curl_mime_encoder(curl_mimepart *part, + const char *encoding); + +/* + * NAME curl_mime_data() + * + * DESCRIPTION + * + * Set mime part data source from memory data, + */ +CURL_EXTERN CURLcode curl_mime_data(curl_mimepart *part, + const char *data, size_t datasize); + +/* + * NAME curl_mime_filedata() + * + * DESCRIPTION + * + * Set mime part data source from named file. + */ +CURL_EXTERN CURLcode curl_mime_filedata(curl_mimepart *part, + const char *filename); + +/* + * NAME curl_mime_data_cb() + * + * DESCRIPTION + * + * Set mime part data source from callback function. + */ +CURL_EXTERN CURLcode curl_mime_data_cb(curl_mimepart *part, + curl_off_t datasize, + curl_read_callback readfunc, + curl_seek_callback seekfunc, + curl_free_callback freefunc, + void *arg); + +/* + * NAME curl_mime_subparts() + * + * DESCRIPTION + * + * Set mime part data source from subparts. + */ +CURL_EXTERN CURLcode curl_mime_subparts(curl_mimepart *part, + curl_mime *subparts); +/* + * NAME curl_mime_headers() + * + * DESCRIPTION + * + * Set mime part headers. + */ +CURL_EXTERN CURLcode curl_mime_headers(curl_mimepart *part, + struct curl_slist *headers, + int take_ownership); + +/* Old form API. */ +/* name is uppercase CURLFORM_ */ +#ifdef CFINIT +#undef CFINIT +#endif + +#ifdef CURL_ISOCPP +#define CFINIT(name) CURLFORM_ ## name +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define CFINIT(name) CURLFORM_/**/name +#endif + +typedef enum { + CFINIT(NOTHING), /********* the first one is unused ************/ + + /* */ + CFINIT(COPYNAME), + CFINIT(PTRNAME), + CFINIT(NAMELENGTH), + CFINIT(COPYCONTENTS), + CFINIT(PTRCONTENTS), + CFINIT(CONTENTSLENGTH), + CFINIT(FILECONTENT), + CFINIT(ARRAY), + CFINIT(OBSOLETE), + CFINIT(FILE), + + CFINIT(BUFFER), + CFINIT(BUFFERPTR), + CFINIT(BUFFERLENGTH), + + CFINIT(CONTENTTYPE), + CFINIT(CONTENTHEADER), + CFINIT(FILENAME), + CFINIT(END), + CFINIT(OBSOLETE2), + + CFINIT(STREAM), + CFINIT(CONTENTLEN), /* added in 7.46.0, provide a curl_off_t length */ + + CURLFORM_LASTENTRY /* the last unused */ +} CURLformoption; + +#undef CFINIT /* done */ + +/* structure to be used as parameter for CURLFORM_ARRAY */ +struct curl_forms { + CURLformoption option; + const char *value; +}; + +/* use this for multipart formpost building */ +/* Returns code for curl_formadd() + * + * Returns: + * CURL_FORMADD_OK on success + * CURL_FORMADD_MEMORY if the FormInfo allocation fails + * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form + * CURL_FORMADD_NULL if a null pointer was given for a char + * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed + * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used + * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error) + * CURL_FORMADD_MEMORY if a curl_httppost struct cannot be allocated + * CURL_FORMADD_MEMORY if some allocation for string copying failed. + * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array + * + ***************************************************************************/ +typedef enum { + CURL_FORMADD_OK, /* first, no error */ + + CURL_FORMADD_MEMORY, + CURL_FORMADD_OPTION_TWICE, + CURL_FORMADD_NULL, + CURL_FORMADD_UNKNOWN_OPTION, + CURL_FORMADD_INCOMPLETE, + CURL_FORMADD_ILLEGAL_ARRAY, + CURL_FORMADD_DISABLED, /* libcurl was built with this disabled */ + + CURL_FORMADD_LAST /* last */ +} CURLFORMcode; + +/* + * NAME curl_formadd() + * + * DESCRIPTION + * + * Pretty advanced function for building multi-part formposts. Each invoke + * adds one part that together construct a full post. Then use + * CURLOPT_HTTPPOST to send it off to libcurl. + */ +CURL_EXTERN CURLFORMcode curl_formadd(struct curl_httppost **httppost, + struct curl_httppost **last_post, + ...); + +/* + * callback function for curl_formget() + * The void *arg pointer will be the one passed as second argument to + * curl_formget(). + * The character buffer passed to it must not be freed. + * Should return the buffer length passed to it as the argument "len" on + * success. + */ +typedef size_t (*curl_formget_callback)(void *arg, const char *buf, + size_t len); + +/* + * NAME curl_formget() + * + * DESCRIPTION + * + * Serialize a curl_httppost struct built with curl_formadd(). + * Accepts a void pointer as second argument which will be passed to + * the curl_formget_callback function. + * Returns 0 on success. + */ +CURL_EXTERN int curl_formget(struct curl_httppost *form, void *arg, + curl_formget_callback append); +/* + * NAME curl_formfree() + * + * DESCRIPTION + * + * Free a multipart formpost previously built with curl_formadd(). + */ +CURL_EXTERN void curl_formfree(struct curl_httppost *form); + +/* + * NAME curl_getenv() + * + * DESCRIPTION + * + * Returns a malloc()'ed string that MUST be curl_free()ed after usage is + * complete. DEPRECATED - see lib/README.curlx + */ +CURL_EXTERN char *curl_getenv(const char *variable); + +/* + * NAME curl_version() + * + * DESCRIPTION + * + * Returns a static ascii string of the libcurl version. + */ +CURL_EXTERN char *curl_version(void); + +/* + * NAME curl_easy_escape() + * + * DESCRIPTION + * + * Escapes URL strings (converts all letters consider illegal in URLs to their + * %XX versions). This function returns a new allocated string or NULL if an + * error occurred. + */ +CURL_EXTERN char *curl_easy_escape(CURL *handle, + const char *string, + int length); + +/* the previous version: */ +CURL_EXTERN char *curl_escape(const char *string, + int length); + + +/* + * NAME curl_easy_unescape() + * + * DESCRIPTION + * + * Unescapes URL encoding in strings (converts all %XX codes to their 8bit + * versions). This function returns a new allocated string or NULL if an error + * occurred. + * Conversion Note: On non-ASCII platforms the ASCII %XX codes are + * converted into the host encoding. + */ +CURL_EXTERN char *curl_easy_unescape(CURL *handle, + const char *string, + int length, + int *outlength); + +/* the previous version */ +CURL_EXTERN char *curl_unescape(const char *string, + int length); + +/* + * NAME curl_free() + * + * DESCRIPTION + * + * Provided for de-allocation in the same translation unit that did the + * allocation. Added in libcurl 7.10 + */ +CURL_EXTERN void curl_free(void *p); + +/* + * NAME curl_global_init() + * + * DESCRIPTION + * + * curl_global_init() should be invoked exactly once for each application that + * uses libcurl and before any call of other libcurl functions. + * + * This function is not thread-safe! + */ +CURL_EXTERN CURLcode curl_global_init(long flags); + +/* + * NAME curl_global_init_mem() + * + * DESCRIPTION + * + * curl_global_init() or curl_global_init_mem() should be invoked exactly once + * for each application that uses libcurl. This function can be used to + * initialize libcurl and set user defined memory management callback + * functions. Users can implement memory management routines to check for + * memory leaks, check for mis-use of the curl library etc. User registered + * callback routines with be invoked by this library instead of the system + * memory management routines like malloc, free etc. + */ +CURL_EXTERN CURLcode curl_global_init_mem(long flags, + curl_malloc_callback m, + curl_free_callback f, + curl_realloc_callback r, + curl_strdup_callback s, + curl_calloc_callback c); + +/* + * NAME curl_global_cleanup() + * + * DESCRIPTION + * + * curl_global_cleanup() should be invoked exactly once for each application + * that uses libcurl + */ +CURL_EXTERN void curl_global_cleanup(void); + +/* linked-list structure for the CURLOPT_QUOTE option (and other) */ +struct curl_slist { + char *data; + struct curl_slist *next; +}; + +/* + * NAME curl_global_sslset() + * + * DESCRIPTION + * + * When built with multiple SSL backends, curl_global_sslset() allows to + * choose one. This function can only be called once, and it must be called + * *before* curl_global_init(). + * + * The backend can be identified by the id (e.g. CURLSSLBACKEND_OPENSSL). The + * backend can also be specified via the name parameter (passing -1 as id). + * If both id and name are specified, the name will be ignored. If neither id + * nor name are specified, the function will fail with + * CURLSSLSET_UNKNOWN_BACKEND and set the "avail" pointer to the + * NULL-terminated list of available backends. + * + * Upon success, the function returns CURLSSLSET_OK. + * + * If the specified SSL backend is not available, the function returns + * CURLSSLSET_UNKNOWN_BACKEND and sets the "avail" pointer to a NULL-terminated + * list of available SSL backends. + * + * The SSL backend can be set only once. If it has already been set, a + * subsequent attempt to change it will result in a CURLSSLSET_TOO_LATE. + */ + +typedef struct { + curl_sslbackend id; + const char *name; +} curl_ssl_backend; + +typedef enum { + CURLSSLSET_OK = 0, + CURLSSLSET_UNKNOWN_BACKEND, + CURLSSLSET_TOO_LATE, + CURLSSLSET_NO_BACKENDS /* libcurl was built without any SSL support */ +} CURLsslset; + +CURL_EXTERN CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, + const curl_ssl_backend ***avail); + +/* + * NAME curl_slist_append() + * + * DESCRIPTION + * + * Appends a string to a linked list. If no list exists, it will be created + * first. Returns the new list, after appending. + */ +CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *, + const char *); + +/* + * NAME curl_slist_free_all() + * + * DESCRIPTION + * + * free a previously built curl_slist. + */ +CURL_EXTERN void curl_slist_free_all(struct curl_slist *); + +/* + * NAME curl_getdate() + * + * DESCRIPTION + * + * Returns the time, in seconds since 1 Jan 1970 of the time string given in + * the first argument. The time argument in the second parameter is unused + * and should be set to NULL. + */ +CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused); + +/* info about the certificate chain, only for OpenSSL builds. Asked + for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */ +struct curl_certinfo { + int num_of_certs; /* number of certificates with information */ + struct curl_slist **certinfo; /* for each index in this array, there's a + linked list with textual information in the + format "name: value" */ +}; + +/* Information about the SSL library used and the respective internal SSL + handle, which can be used to obtain further information regarding the + connection. Asked for with CURLINFO_TLS_SSL_PTR or CURLINFO_TLS_SESSION. */ +struct curl_tlssessioninfo { + curl_sslbackend backend; + void *internals; +}; + +#define CURLINFO_STRING 0x100000 +#define CURLINFO_LONG 0x200000 +#define CURLINFO_DOUBLE 0x300000 +#define CURLINFO_SLIST 0x400000 +#define CURLINFO_PTR 0x400000 /* same as SLIST */ +#define CURLINFO_SOCKET 0x500000 +#define CURLINFO_OFF_T 0x600000 +#define CURLINFO_MASK 0x0fffff +#define CURLINFO_TYPEMASK 0xf00000 + +typedef enum { + CURLINFO_NONE, /* first, never use this */ + CURLINFO_EFFECTIVE_URL = CURLINFO_STRING + 1, + CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2, + CURLINFO_TOTAL_TIME = CURLINFO_DOUBLE + 3, + CURLINFO_NAMELOOKUP_TIME = CURLINFO_DOUBLE + 4, + CURLINFO_CONNECT_TIME = CURLINFO_DOUBLE + 5, + CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6, + CURLINFO_SIZE_UPLOAD = CURLINFO_DOUBLE + 7, + CURLINFO_SIZE_UPLOAD_T = CURLINFO_OFF_T + 7, + CURLINFO_SIZE_DOWNLOAD = CURLINFO_DOUBLE + 8, + CURLINFO_SIZE_DOWNLOAD_T = CURLINFO_OFF_T + 8, + CURLINFO_SPEED_DOWNLOAD = CURLINFO_DOUBLE + 9, + CURLINFO_SPEED_DOWNLOAD_T = CURLINFO_OFF_T + 9, + CURLINFO_SPEED_UPLOAD = CURLINFO_DOUBLE + 10, + CURLINFO_SPEED_UPLOAD_T = CURLINFO_OFF_T + 10, + CURLINFO_HEADER_SIZE = CURLINFO_LONG + 11, + CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12, + CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13, + CURLINFO_FILETIME = CURLINFO_LONG + 14, + CURLINFO_FILETIME_T = CURLINFO_OFF_T + 14, + CURLINFO_CONTENT_LENGTH_DOWNLOAD = CURLINFO_DOUBLE + 15, + CURLINFO_CONTENT_LENGTH_DOWNLOAD_T = CURLINFO_OFF_T + 15, + CURLINFO_CONTENT_LENGTH_UPLOAD = CURLINFO_DOUBLE + 16, + CURLINFO_CONTENT_LENGTH_UPLOAD_T = CURLINFO_OFF_T + 16, + CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17, + CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18, + CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19, + CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20, + CURLINFO_PRIVATE = CURLINFO_STRING + 21, + CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG + 22, + CURLINFO_HTTPAUTH_AVAIL = CURLINFO_LONG + 23, + CURLINFO_PROXYAUTH_AVAIL = CURLINFO_LONG + 24, + CURLINFO_OS_ERRNO = CURLINFO_LONG + 25, + CURLINFO_NUM_CONNECTS = CURLINFO_LONG + 26, + CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27, + CURLINFO_COOKIELIST = CURLINFO_SLIST + 28, + CURLINFO_LASTSOCKET = CURLINFO_LONG + 29, + CURLINFO_FTP_ENTRY_PATH = CURLINFO_STRING + 30, + CURLINFO_REDIRECT_URL = CURLINFO_STRING + 31, + CURLINFO_PRIMARY_IP = CURLINFO_STRING + 32, + CURLINFO_APPCONNECT_TIME = CURLINFO_DOUBLE + 33, + CURLINFO_CERTINFO = CURLINFO_PTR + 34, + CURLINFO_CONDITION_UNMET = CURLINFO_LONG + 35, + CURLINFO_RTSP_SESSION_ID = CURLINFO_STRING + 36, + CURLINFO_RTSP_CLIENT_CSEQ = CURLINFO_LONG + 37, + CURLINFO_RTSP_SERVER_CSEQ = CURLINFO_LONG + 38, + CURLINFO_RTSP_CSEQ_RECV = CURLINFO_LONG + 39, + CURLINFO_PRIMARY_PORT = CURLINFO_LONG + 40, + CURLINFO_LOCAL_IP = CURLINFO_STRING + 41, + CURLINFO_LOCAL_PORT = CURLINFO_LONG + 42, + CURLINFO_TLS_SESSION = CURLINFO_PTR + 43, + CURLINFO_ACTIVESOCKET = CURLINFO_SOCKET + 44, + CURLINFO_TLS_SSL_PTR = CURLINFO_PTR + 45, + CURLINFO_HTTP_VERSION = CURLINFO_LONG + 46, + CURLINFO_PROXY_SSL_VERIFYRESULT = CURLINFO_LONG + 47, + CURLINFO_PROTOCOL = CURLINFO_LONG + 48, + CURLINFO_SCHEME = CURLINFO_STRING + 49, + /* Fill in new entries below here! */ + + /* Preferably these would be defined conditionally based on the + sizeof curl_off_t being 64-bits */ + CURLINFO_TOTAL_TIME_T = CURLINFO_OFF_T + 50, + CURLINFO_NAMELOOKUP_TIME_T = CURLINFO_OFF_T + 51, + CURLINFO_CONNECT_TIME_T = CURLINFO_OFF_T + 52, + CURLINFO_PRETRANSFER_TIME_T = CURLINFO_OFF_T + 53, + CURLINFO_STARTTRANSFER_TIME_T = CURLINFO_OFF_T + 54, + CURLINFO_REDIRECT_TIME_T = CURLINFO_OFF_T + 55, + CURLINFO_APPCONNECT_TIME_T = CURLINFO_OFF_T + 56, + + CURLINFO_LASTONE = 56 +} CURLINFO; + +/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as + CURLINFO_HTTP_CODE */ +#define CURLINFO_HTTP_CODE CURLINFO_RESPONSE_CODE + +typedef enum { + CURLCLOSEPOLICY_NONE, /* first, never use this */ + + CURLCLOSEPOLICY_OLDEST, + CURLCLOSEPOLICY_LEAST_RECENTLY_USED, + CURLCLOSEPOLICY_LEAST_TRAFFIC, + CURLCLOSEPOLICY_SLOWEST, + CURLCLOSEPOLICY_CALLBACK, + + CURLCLOSEPOLICY_LAST /* last, never use this */ +} curl_closepolicy; + +#define CURL_GLOBAL_SSL (1<<0) /* no purpose since since 7.57.0 */ +#define CURL_GLOBAL_WIN32 (1<<1) +#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) +#define CURL_GLOBAL_NOTHING 0 +#define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL +#define CURL_GLOBAL_ACK_EINTR (1<<2) + + +/***************************************************************************** + * Setup defines, protos etc for the sharing stuff. + */ + +/* Different data locks for a single share */ +typedef enum { + CURL_LOCK_DATA_NONE = 0, + /* CURL_LOCK_DATA_SHARE is used internally to say that + * the locking is just made to change the internal state of the share + * itself. + */ + CURL_LOCK_DATA_SHARE, + CURL_LOCK_DATA_COOKIE, + CURL_LOCK_DATA_DNS, + CURL_LOCK_DATA_SSL_SESSION, + CURL_LOCK_DATA_CONNECT, + CURL_LOCK_DATA_PSL, + CURL_LOCK_DATA_LAST +} curl_lock_data; + +/* Different lock access types */ +typedef enum { + CURL_LOCK_ACCESS_NONE = 0, /* unspecified action */ + CURL_LOCK_ACCESS_SHARED = 1, /* for read perhaps */ + CURL_LOCK_ACCESS_SINGLE = 2, /* for write perhaps */ + CURL_LOCK_ACCESS_LAST /* never use */ +} curl_lock_access; + +typedef void (*curl_lock_function)(CURL *handle, + curl_lock_data data, + curl_lock_access locktype, + void *userptr); +typedef void (*curl_unlock_function)(CURL *handle, + curl_lock_data data, + void *userptr); + + +typedef enum { + CURLSHE_OK, /* all is fine */ + CURLSHE_BAD_OPTION, /* 1 */ + CURLSHE_IN_USE, /* 2 */ + CURLSHE_INVALID, /* 3 */ + CURLSHE_NOMEM, /* 4 out of memory */ + CURLSHE_NOT_BUILT_IN, /* 5 feature not present in lib */ + CURLSHE_LAST /* never use */ +} CURLSHcode; + +typedef enum { + CURLSHOPT_NONE, /* don't use */ + CURLSHOPT_SHARE, /* specify a data type to share */ + CURLSHOPT_UNSHARE, /* specify which data type to stop sharing */ + CURLSHOPT_LOCKFUNC, /* pass in a 'curl_lock_function' pointer */ + CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */ + CURLSHOPT_USERDATA, /* pass in a user data pointer used in the lock/unlock + callback functions */ + CURLSHOPT_LAST /* never use */ +} CURLSHoption; + +CURL_EXTERN CURLSH *curl_share_init(void); +CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...); +CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *); + +/**************************************************************************** + * Structures for querying information about the curl library at runtime. + */ + +typedef enum { + CURLVERSION_FIRST, + CURLVERSION_SECOND, + CURLVERSION_THIRD, + CURLVERSION_FOURTH, + CURLVERSION_FIFTH, + CURLVERSION_LAST /* never actually use this */ +} CURLversion; + +/* The 'CURLVERSION_NOW' is the symbolic name meant to be used by + basically all programs ever that want to get version information. It is + meant to be a built-in version number for what kind of struct the caller + expects. If the struct ever changes, we redefine the NOW to another enum + from above. */ +#define CURLVERSION_NOW CURLVERSION_FIFTH + +typedef struct { + CURLversion age; /* age of the returned struct */ + const char *version; /* LIBCURL_VERSION */ + unsigned int version_num; /* LIBCURL_VERSION_NUM */ + const char *host; /* OS/host/cpu/machine when configured */ + int features; /* bitmask, see defines below */ + const char *ssl_version; /* human readable string */ + long ssl_version_num; /* not used anymore, always 0 */ + const char *libz_version; /* human readable string */ + /* protocols is terminated by an entry with a NULL protoname */ + const char * const *protocols; + + /* The fields below this were added in CURLVERSION_SECOND */ + const char *ares; + int ares_num; + + /* This field was added in CURLVERSION_THIRD */ + const char *libidn; + + /* These field were added in CURLVERSION_FOURTH */ + + /* Same as '_libiconv_version' if built with HAVE_ICONV */ + int iconv_ver_num; + + const char *libssh_version; /* human readable string */ + + /* These fields were added in CURLVERSION_FIFTH */ + + unsigned int brotli_ver_num; /* Numeric Brotli version + (MAJOR << 24) | (MINOR << 12) | PATCH */ + const char *brotli_version; /* human readable string. */ + +} curl_version_info_data; + +#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */ +#define CURL_VERSION_KERBEROS4 (1<<1) /* Kerberos V4 auth is supported + (deprecated) */ +#define CURL_VERSION_SSL (1<<2) /* SSL options are present */ +#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */ +#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */ +#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth is supported + (deprecated) */ +#define CURL_VERSION_DEBUG (1<<6) /* Built with debug capabilities */ +#define CURL_VERSION_ASYNCHDNS (1<<7) /* Asynchronous DNS resolves */ +#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth is supported */ +#define CURL_VERSION_LARGEFILE (1<<9) /* Supports files larger than 2GB */ +#define CURL_VERSION_IDN (1<<10) /* Internationized Domain Names are + supported */ +#define CURL_VERSION_SSPI (1<<11) /* Built against Windows SSPI */ +#define CURL_VERSION_CONV (1<<12) /* Character conversions supported */ +#define CURL_VERSION_CURLDEBUG (1<<13) /* Debug memory tracking supported */ +#define CURL_VERSION_TLSAUTH_SRP (1<<14) /* TLS-SRP auth is supported */ +#define CURL_VERSION_NTLM_WB (1<<15) /* NTLM delegation to winbind helper + is supported */ +#define CURL_VERSION_HTTP2 (1<<16) /* HTTP2 support built-in */ +#define CURL_VERSION_GSSAPI (1<<17) /* Built against a GSS-API library */ +#define CURL_VERSION_KERBEROS5 (1<<18) /* Kerberos V5 auth is supported */ +#define CURL_VERSION_UNIX_SOCKETS (1<<19) /* Unix domain sockets support */ +#define CURL_VERSION_PSL (1<<20) /* Mozilla's Public Suffix List, used + for cookie domain verification */ +#define CURL_VERSION_HTTPS_PROXY (1<<21) /* HTTPS-proxy support built-in */ +#define CURL_VERSION_MULTI_SSL (1<<22) /* Multiple SSL backends available */ +#define CURL_VERSION_BROTLI (1<<23) /* Brotli features are present. */ + + /* + * NAME curl_version_info() + * + * DESCRIPTION + * + * This function returns a pointer to a static copy of the version info + * struct. See above. + */ +CURL_EXTERN curl_version_info_data *curl_version_info(CURLversion); + +/* + * NAME curl_easy_strerror() + * + * DESCRIPTION + * + * The curl_easy_strerror function may be used to turn a CURLcode value + * into the equivalent human readable error string. This is useful + * for printing meaningful error messages. + */ +CURL_EXTERN const char *curl_easy_strerror(CURLcode); + +/* + * NAME curl_share_strerror() + * + * DESCRIPTION + * + * The curl_share_strerror function may be used to turn a CURLSHcode value + * into the equivalent human readable error string. This is useful + * for printing meaningful error messages. + */ +CURL_EXTERN const char *curl_share_strerror(CURLSHcode); + +/* + * NAME curl_easy_pause() + * + * DESCRIPTION + * + * The curl_easy_pause function pauses or unpauses transfers. Select the new + * state by setting the bitmask, use the convenience defines below. + * + */ +CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask); + +#define CURLPAUSE_RECV (1<<0) +#define CURLPAUSE_RECV_CONT (0) + +#define CURLPAUSE_SEND (1<<2) +#define CURLPAUSE_SEND_CONT (0) + +#define CURLPAUSE_ALL (CURLPAUSE_RECV|CURLPAUSE_SEND) +#define CURLPAUSE_CONT (CURLPAUSE_RECV_CONT|CURLPAUSE_SEND_CONT) + +#ifdef __cplusplus +} +#endif + +/* unfortunately, the easy.h and multi.h include files need options and info + stuff before they can be included! */ +#include "easy.h" /* nothing in curl is fun without the easy stuff */ +#include "multi.h" +#include "urlapi.h" + +/* the typechecker doesn't work in C++ (yet) */ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \ + ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && \ + !defined(__cplusplus) && !defined(CURL_DISABLE_TYPECHECK) +#include "typecheck-gcc.h" +#else +#if defined(__STDC__) && (__STDC__ >= 1) +/* This preprocessor magic that replaces a call with the exact same call is + only done to make sure application authors pass exactly three arguments + to these functions. */ +#define curl_easy_setopt(handle,opt,param) curl_easy_setopt(handle,opt,param) +#define curl_easy_getinfo(handle,info,arg) curl_easy_getinfo(handle,info,arg) +#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) +#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) +#endif /* __STDC__ >= 1 */ +#endif /* gcc >= 4.3 && !__cplusplus */ + +#endif /* __CURL_CURL_H */ diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/curl/curlver.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/curl/curlver.h new file mode 100755 index 000000000..3b043345d --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/curl/curlver.h @@ -0,0 +1,77 @@ +#ifndef __CURL_CURLVER_H +#define __CURL_CURLVER_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* This header file contains nothing but libcurl version info, generated by + a script at release-time. This was made its own header file in 7.11.2 */ + +/* This is the global package copyright */ +#define LIBCURL_COPYRIGHT "1996 - 2018 Daniel Stenberg, ." + +/* This is the version number of the libcurl package from which this header + file origins: */ +#define LIBCURL_VERSION "7.64.0" + +/* The numeric version number is also available "in parts" by using these + defines: */ +#define LIBCURL_VERSION_MAJOR 7 +#define LIBCURL_VERSION_MINOR 64 +#define LIBCURL_VERSION_PATCH 0 + +/* This is the numeric version of the libcurl version number, meant for easier + parsing and comparions by programs. The LIBCURL_VERSION_NUM define will + always follow this syntax: + + 0xXXYYZZ + + Where XX, YY and ZZ are the main version, release and patch numbers in + hexadecimal (using 8 bits each). All three numbers are always represented + using two digits. 1.2 would appear as "0x010200" while version 9.11.7 + appears as "0x090b07". + + This 6-digit (24 bits) hexadecimal number does not show pre-release number, + and it is always a greater number in a more recent release. It makes + comparisons with greater than and less than work. + + Note: This define is the full hex number and _does not_ use the + CURL_VERSION_BITS() macro since curl's own configure script greps for it + and needs it to contain the full number. +*/ +#define LIBCURL_VERSION_NUM 0x074000 + +/* + * This is the date and time when the full source package was created. The + * timestamp is not stored in git, as the timestamp is properly set in the + * tarballs by the maketgz script. + * + * The format of the date follows this template: + * + * "2007-11-23" + */ +#define LIBCURL_TIMESTAMP "2019-02-06" + +#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|z) +#define CURL_AT_LEAST_VERSION(x,y,z) \ + (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z)) + +#endif /* __CURL_CURLVER_H */ diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/curl/easy.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/curl/easy.h new file mode 100755 index 000000000..f42a8a969 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/curl/easy.h @@ -0,0 +1,112 @@ +#ifndef __CURL_EASY_H +#define __CURL_EASY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +CURL_EXTERN CURL *curl_easy_init(void); +CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); +CURL_EXTERN CURLcode curl_easy_perform(CURL *curl); +CURL_EXTERN void curl_easy_cleanup(CURL *curl); + +/* + * NAME curl_easy_getinfo() + * + * DESCRIPTION + * + * Request internal information from the curl session with this function. The + * third argument MUST be a pointer to a long, a pointer to a char * or a + * pointer to a double (as the documentation describes elsewhere). The data + * pointed to will be filled in accordingly and can be relied upon only if the + * function returns CURLE_OK. This function is intended to get used *AFTER* a + * performed transfer, all results from this function are undefined until the + * transfer is completed. + */ +CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...); + + +/* + * NAME curl_easy_duphandle() + * + * DESCRIPTION + * + * Creates a new curl session handle with the same options set for the handle + * passed in. Duplicating a handle could only be a matter of cloning data and + * options, internal state info and things like persistent connections cannot + * be transferred. It is useful in multithreaded applications when you can run + * curl_easy_duphandle() for each new thread to avoid a series of identical + * curl_easy_setopt() invokes in every thread. + */ +CURL_EXTERN CURL *curl_easy_duphandle(CURL *curl); + +/* + * NAME curl_easy_reset() + * + * DESCRIPTION + * + * Re-initializes a CURL handle to the default values. This puts back the + * handle to the same state as it was in when it was just created. + * + * It does keep: live connections, the Session ID cache, the DNS cache and the + * cookies. + */ +CURL_EXTERN void curl_easy_reset(CURL *curl); + +/* + * NAME curl_easy_recv() + * + * DESCRIPTION + * + * Receives data from the connected socket. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURL_EXTERN CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, + size_t *n); + +/* + * NAME curl_easy_send() + * + * DESCRIPTION + * + * Sends data over the connected socket. Use after successful + * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. + */ +CURL_EXTERN CURLcode curl_easy_send(CURL *curl, const void *buffer, + size_t buflen, size_t *n); + + +/* + * NAME curl_easy_upkeep() + * + * DESCRIPTION + * + * Performs connection upkeep for the given session handle. + */ +CURL_EXTERN CURLcode curl_easy_upkeep(CURL *curl); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/curl/mprintf.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/curl/mprintf.h new file mode 100755 index 000000000..e20f546e1 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/curl/mprintf.h @@ -0,0 +1,50 @@ +#ifndef __CURL_MPRINTF_H +#define __CURL_MPRINTF_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include +#include /* needed for FILE */ +#include "curl.h" /* for CURL_EXTERN */ + +#ifdef __cplusplus +extern "C" { +#endif + +CURL_EXTERN int curl_mprintf(const char *format, ...); +CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...); +CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...); +CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength, + const char *format, ...); +CURL_EXTERN int curl_mvprintf(const char *format, va_list args); +CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args); +CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args); +CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength, + const char *format, va_list args); +CURL_EXTERN char *curl_maprintf(const char *format, ...); +CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args); + +#ifdef __cplusplus +} +#endif + +#endif /* __CURL_MPRINTF_H */ diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/curl/multi.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/curl/multi.h new file mode 100755 index 000000000..b19dbaf79 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/curl/multi.h @@ -0,0 +1,441 @@ +#ifndef __CURL_MULTI_H +#define __CURL_MULTI_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +/* + This is an "external" header file. Don't give away any internals here! + + GOALS + + o Enable a "pull" interface. The application that uses libcurl decides where + and when to ask libcurl to get/send data. + + o Enable multiple simultaneous transfers in the same thread without making it + complicated for the application. + + o Enable the application to select() on its own file descriptors and curl's + file descriptors simultaneous easily. + +*/ + +/* + * This header file should not really need to include "curl.h" since curl.h + * itself includes this file and we expect user applications to do #include + * without the need for especially including multi.h. + * + * For some reason we added this include here at one point, and rather than to + * break existing (wrongly written) libcurl applications, we leave it as-is + * but with this warning attached. + */ +#include "curl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) +typedef struct Curl_multi CURLM; +#else +typedef void CURLM; +#endif + +typedef enum { + CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or + curl_multi_socket*() soon */ + CURLM_OK, + CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */ + CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */ + CURLM_OUT_OF_MEMORY, /* if you ever get this, you're in deep sh*t */ + CURLM_INTERNAL_ERROR, /* this is a libcurl bug */ + CURLM_BAD_SOCKET, /* the passed in socket argument did not match */ + CURLM_UNKNOWN_OPTION, /* curl_multi_setopt() with unsupported option */ + CURLM_ADDED_ALREADY, /* an easy handle already added to a multi handle was + attempted to get added - again */ + CURLM_RECURSIVE_API_CALL, /* an api function was called from inside a + callback */ + CURLM_LAST +} CURLMcode; + +/* just to make code nicer when using curl_multi_socket() you can now check + for CURLM_CALL_MULTI_SOCKET too in the same style it works for + curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */ +#define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM + +/* bitmask bits for CURLMOPT_PIPELINING */ +#define CURLPIPE_NOTHING 0L +#define CURLPIPE_HTTP1 1L +#define CURLPIPE_MULTIPLEX 2L + +typedef enum { + CURLMSG_NONE, /* first, not used */ + CURLMSG_DONE, /* This easy handle has completed. 'result' contains + the CURLcode of the transfer */ + CURLMSG_LAST /* last, not used */ +} CURLMSG; + +struct CURLMsg { + CURLMSG msg; /* what this message means */ + CURL *easy_handle; /* the handle it concerns */ + union { + void *whatever; /* message-specific data */ + CURLcode result; /* return code for transfer */ + } data; +}; +typedef struct CURLMsg CURLMsg; + +/* Based on poll(2) structure and values. + * We don't use pollfd and POLL* constants explicitly + * to cover platforms without poll(). */ +#define CURL_WAIT_POLLIN 0x0001 +#define CURL_WAIT_POLLPRI 0x0002 +#define CURL_WAIT_POLLOUT 0x0004 + +struct curl_waitfd { + curl_socket_t fd; + short events; + short revents; /* not supported yet */ +}; + +/* + * Name: curl_multi_init() + * + * Desc: inititalize multi-style curl usage + * + * Returns: a new CURLM handle to use in all 'curl_multi' functions. + */ +CURL_EXTERN CURLM *curl_multi_init(void); + +/* + * Name: curl_multi_add_handle() + * + * Desc: add a standard curl handle to the multi stack + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_add_handle(CURLM *multi_handle, + CURL *curl_handle); + + /* + * Name: curl_multi_remove_handle() + * + * Desc: removes a curl handle from the multi stack again + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle, + CURL *curl_handle); + + /* + * Name: curl_multi_fdset() + * + * Desc: Ask curl for its fd_set sets. The app can use these to select() or + * poll() on. We want curl_multi_perform() called as soon as one of + * them are ready. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle, + fd_set *read_fd_set, + fd_set *write_fd_set, + fd_set *exc_fd_set, + int *max_fd); + +/* + * Name: curl_multi_wait() + * + * Desc: Poll on all fds within a CURLM set as well as any + * additional fds passed to the function. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_wait(CURLM *multi_handle, + struct curl_waitfd extra_fds[], + unsigned int extra_nfds, + int timeout_ms, + int *ret); + + /* + * Name: curl_multi_perform() + * + * Desc: When the app thinks there's data available for curl it calls this + * function to read/write whatever there is right now. This returns + * as soon as the reads and writes are done. This function does not + * require that there actually is data available for reading or that + * data can be written, it can be called just in case. It returns + * the number of handles that still transfer data in the second + * argument's integer-pointer. + * + * Returns: CURLMcode type, general multi error code. *NOTE* that this only + * returns errors etc regarding the whole multi stack. There might + * still have occurred problems on individual transfers even when + * this returns OK. + */ +CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle, + int *running_handles); + + /* + * Name: curl_multi_cleanup() + * + * Desc: Cleans up and removes a whole multi stack. It does not free or + * touch any individual easy handles in any way. We need to define + * in what state those handles will be if this function is called + * in the middle of a transfer. + * + * Returns: CURLMcode type, general multi error code. + */ +CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle); + +/* + * Name: curl_multi_info_read() + * + * Desc: Ask the multi handle if there's any messages/informationals from + * the individual transfers. Messages include informationals such as + * error code from the transfer or just the fact that a transfer is + * completed. More details on these should be written down as well. + * + * Repeated calls to this function will return a new struct each + * time, until a special "end of msgs" struct is returned as a signal + * that there is no more to get at this point. + * + * The data the returned pointer points to will not survive calling + * curl_multi_cleanup(). + * + * The 'CURLMsg' struct is meant to be very simple and only contain + * very basic information. If more involved information is wanted, + * we will provide the particular "transfer handle" in that struct + * and that should/could/would be used in subsequent + * curl_easy_getinfo() calls (or similar). The point being that we + * must never expose complex structs to applications, as then we'll + * undoubtably get backwards compatibility problems in the future. + * + * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out + * of structs. It also writes the number of messages left in the + * queue (after this read) in the integer the second argument points + * to. + */ +CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle, + int *msgs_in_queue); + +/* + * Name: curl_multi_strerror() + * + * Desc: The curl_multi_strerror function may be used to turn a CURLMcode + * value into the equivalent human readable error string. This is + * useful for printing meaningful error messages. + * + * Returns: A pointer to a zero-terminated error message. + */ +CURL_EXTERN const char *curl_multi_strerror(CURLMcode); + +/* + * Name: curl_multi_socket() and + * curl_multi_socket_all() + * + * Desc: An alternative version of curl_multi_perform() that allows the + * application to pass in one of the file descriptors that have been + * detected to have "action" on them and let libcurl perform. + * See man page for details. + */ +#define CURL_POLL_NONE 0 +#define CURL_POLL_IN 1 +#define CURL_POLL_OUT 2 +#define CURL_POLL_INOUT 3 +#define CURL_POLL_REMOVE 4 + +#define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD + +#define CURL_CSELECT_IN 0x01 +#define CURL_CSELECT_OUT 0x02 +#define CURL_CSELECT_ERR 0x04 + +typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */ + curl_socket_t s, /* socket */ + int what, /* see above */ + void *userp, /* private callback + pointer */ + void *socketp); /* private socket + pointer */ +/* + * Name: curl_multi_timer_callback + * + * Desc: Called by libcurl whenever the library detects a change in the + * maximum number of milliseconds the app is allowed to wait before + * curl_multi_socket() or curl_multi_perform() must be called + * (to allow libcurl's timed events to take place). + * + * Returns: The callback should return zero. + */ +typedef int (*curl_multi_timer_callback)(CURLM *multi, /* multi handle */ + long timeout_ms, /* see above */ + void *userp); /* private callback + pointer */ + +CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s, + int *running_handles); + +CURL_EXTERN CURLMcode curl_multi_socket_action(CURLM *multi_handle, + curl_socket_t s, + int ev_bitmask, + int *running_handles); + +CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle, + int *running_handles); + +#ifndef CURL_ALLOW_OLD_MULTI_SOCKET +/* This macro below was added in 7.16.3 to push users who recompile to use + the new curl_multi_socket_action() instead of the old curl_multi_socket() +*/ +#define curl_multi_socket(x,y,z) curl_multi_socket_action(x,y,0,z) +#endif + +/* + * Name: curl_multi_timeout() + * + * Desc: Returns the maximum number of milliseconds the app is allowed to + * wait before curl_multi_socket() or curl_multi_perform() must be + * called (to allow libcurl's timed events to take place). + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle, + long *milliseconds); + +#undef CINIT /* re-using the same name as in curl.h */ + +#ifdef CURL_ISOCPP +#define CINIT(name,type,num) CURLMOPT_ ## name = CURLOPTTYPE_ ## type + num +#else +/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */ +#define LONG CURLOPTTYPE_LONG +#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT +#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT +#define OFF_T CURLOPTTYPE_OFF_T +#define CINIT(name,type,number) CURLMOPT_/**/name = type + number +#endif + +typedef enum { + /* This is the socket callback function pointer */ + CINIT(SOCKETFUNCTION, FUNCTIONPOINT, 1), + + /* This is the argument passed to the socket callback */ + CINIT(SOCKETDATA, OBJECTPOINT, 2), + + /* set to 1 to enable pipelining for this multi handle */ + CINIT(PIPELINING, LONG, 3), + + /* This is the timer callback function pointer */ + CINIT(TIMERFUNCTION, FUNCTIONPOINT, 4), + + /* This is the argument passed to the timer callback */ + CINIT(TIMERDATA, OBJECTPOINT, 5), + + /* maximum number of entries in the connection cache */ + CINIT(MAXCONNECTS, LONG, 6), + + /* maximum number of (pipelining) connections to one host */ + CINIT(MAX_HOST_CONNECTIONS, LONG, 7), + + /* maximum number of requests in a pipeline */ + CINIT(MAX_PIPELINE_LENGTH, LONG, 8), + + /* a connection with a content-length longer than this + will not be considered for pipelining */ + CINIT(CONTENT_LENGTH_PENALTY_SIZE, OFF_T, 9), + + /* a connection with a chunk length longer than this + will not be considered for pipelining */ + CINIT(CHUNK_LENGTH_PENALTY_SIZE, OFF_T, 10), + + /* a list of site names(+port) that are blacklisted from + pipelining */ + CINIT(PIPELINING_SITE_BL, OBJECTPOINT, 11), + + /* a list of server types that are blacklisted from + pipelining */ + CINIT(PIPELINING_SERVER_BL, OBJECTPOINT, 12), + + /* maximum number of open connections in total */ + CINIT(MAX_TOTAL_CONNECTIONS, LONG, 13), + + /* This is the server push callback function pointer */ + CINIT(PUSHFUNCTION, FUNCTIONPOINT, 14), + + /* This is the argument passed to the server push callback */ + CINIT(PUSHDATA, OBJECTPOINT, 15), + + CURLMOPT_LASTENTRY /* the last unused */ +} CURLMoption; + + +/* + * Name: curl_multi_setopt() + * + * Desc: Sets options for the multi handle. + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle, + CURLMoption option, ...); + + +/* + * Name: curl_multi_assign() + * + * Desc: This function sets an association in the multi handle between the + * given socket and a private pointer of the application. This is + * (only) useful for curl_multi_socket uses. + * + * Returns: CURLM error code. + */ +CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle, + curl_socket_t sockfd, void *sockp); + + +/* + * Name: curl_push_callback + * + * Desc: This callback gets called when a new stream is being pushed by the + * server. It approves or denies the new stream. + * + * Returns: CURL_PUSH_OK or CURL_PUSH_DENY. + */ +#define CURL_PUSH_OK 0 +#define CURL_PUSH_DENY 1 + +struct curl_pushheaders; /* forward declaration only */ + +CURL_EXTERN char *curl_pushheader_bynum(struct curl_pushheaders *h, + size_t num); +CURL_EXTERN char *curl_pushheader_byname(struct curl_pushheaders *h, + const char *name); + +typedef int (*curl_push_callback)(CURL *parent, + CURL *easy, + size_t num_headers, + struct curl_pushheaders *headers, + void *userp); + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/curl/stdcheaders.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/curl/stdcheaders.h new file mode 100755 index 000000000..027b6f421 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/curl/stdcheaders.h @@ -0,0 +1,33 @@ +#ifndef __STDC_HEADERS_H +#define __STDC_HEADERS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include + +size_t fread(void *, size_t, size_t, FILE *); +size_t fwrite(const void *, size_t, size_t, FILE *); + +int strcasecmp(const char *, const char *); +int strncasecmp(const char *, const char *, size_t); + +#endif /* __STDC_HEADERS_H */ diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/curl/system.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/curl/system.h new file mode 100755 index 000000000..1e555ec19 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/curl/system.h @@ -0,0 +1,493 @@ +#ifndef __CURL_SYSTEM_H +#define __CURL_SYSTEM_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* + * Try to keep one section per platform, compiler and architecture, otherwise, + * if an existing section is reused for a different one and later on the + * original is adjusted, probably the piggybacking one can be adversely + * changed. + * + * In order to differentiate between platforms/compilers/architectures use + * only compiler built in predefined preprocessor symbols. + * + * curl_off_t + * ---------- + * + * For any given platform/compiler curl_off_t must be typedef'ed to a 64-bit + * wide signed integral data type. The width of this data type must remain + * constant and independent of any possible large file support settings. + * + * As an exception to the above, curl_off_t shall be typedef'ed to a 32-bit + * wide signed integral data type if there is no 64-bit type. + * + * As a general rule, curl_off_t shall not be mapped to off_t. This rule shall + * only be violated if off_t is the only 64-bit data type available and the + * size of off_t is independent of large file support settings. Keep your + * build on the safe side avoiding an off_t gating. If you have a 64-bit + * off_t then take for sure that another 64-bit data type exists, dig deeper + * and you will find it. + * + */ + +#if defined(__DJGPP__) || defined(__GO32__) +# if defined(__DJGPP__) && (__DJGPP__ > 1) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__SALFORDC__) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__BORLANDC__) +# if (__BORLANDC__ < 0x520) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__TURBOC__) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__WATCOMC__) +# if defined(__386__) +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__POCC__) +# if (__POCC__ < 280) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# elif defined(_MSC_VER) +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# else +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__LCC__) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__SYMBIAN32__) +# if defined(__EABI__) /* Treat all ARM compilers equally */ +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__CW32__) +# pragma longlong on +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__VC32__) +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int + +#elif defined(__MWERKS__) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(_WIN32_WCE) +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__MINGW32__) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_WS2TCPIP_H 1 + +#elif defined(__VMS) +# if defined(__VAX) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int + +#elif defined(__OS400__) +# if defined(__ILEC400__) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 +# endif + +#elif defined(__MVS__) +# if defined(__IBMC__) || defined(__IBMCPP__) +# if defined(_ILP32) +# elif defined(_LP64) +# endif +# if defined(_LONG_LONG) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(_LP64) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 +# endif + +#elif defined(__370__) +# if defined(__IBMC__) || defined(__IBMCPP__) +# if defined(_ILP32) +# elif defined(_LP64) +# endif +# if defined(_LONG_LONG) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(_LP64) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 +# endif + +#elif defined(TPF) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +#elif defined(__TINYC__) /* also known as tcc */ + +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 + +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) /* Oracle Solaris Studio */ +# if !defined(__LP64) && (defined(__ILP32) || \ + defined(__i386) || \ + defined(__sparcv8) || \ + defined(__sparcv8plus)) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__LP64) || \ + defined(__amd64) || defined(__sparcv9) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 + +#elif defined(__xlc__) /* IBM xlc compiler */ +# if !defined(_LP64) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 + +/* ===================================== */ +/* KEEP MSVC THE PENULTIMATE ENTRY */ +/* ===================================== */ + +#elif defined(_MSC_VER) +# if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) +# define CURL_TYPEOF_CURL_OFF_T __int64 +# define CURL_FORMAT_CURL_OFF_T "I64d" +# define CURL_FORMAT_CURL_OFF_TU "I64u" +# define CURL_SUFFIX_CURL_OFF_T i64 +# define CURL_SUFFIX_CURL_OFF_TU ui64 +# else +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T int + +/* ===================================== */ +/* KEEP GENERIC GCC THE LAST ENTRY */ +/* ===================================== */ + +#elif defined(__GNUC__) && !defined(_SCO_DS) +# if !defined(__LP64__) && \ + (defined(__ILP32__) || defined(__i386__) || defined(__hppa__) || \ + defined(__ppc__) || defined(__powerpc__) || defined(__arm__) || \ + defined(__sparc__) || defined(__mips__) || defined(__sh__) || \ + defined(__XTENSA__) || \ + (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 4) || \ + (defined(__LONG_MAX__) && __LONG_MAX__ == 2147483647L)) +# define CURL_TYPEOF_CURL_OFF_T long long +# define CURL_FORMAT_CURL_OFF_T "lld" +# define CURL_FORMAT_CURL_OFF_TU "llu" +# define CURL_SUFFIX_CURL_OFF_T LL +# define CURL_SUFFIX_CURL_OFF_TU ULL +# elif defined(__LP64__) || \ + defined(__x86_64__) || defined(__ppc64__) || defined(__sparc64__) || \ + (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 8) || \ + (defined(__LONG_MAX__) && __LONG_MAX__ == 9223372036854775807L) +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# endif +# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t +# define CURL_PULL_SYS_TYPES_H 1 +# define CURL_PULL_SYS_SOCKET_H 1 + +#else +/* generic "safe guess" on old 32 bit style */ +# define CURL_TYPEOF_CURL_OFF_T long +# define CURL_FORMAT_CURL_OFF_T "ld" +# define CURL_FORMAT_CURL_OFF_TU "lu" +# define CURL_SUFFIX_CURL_OFF_T L +# define CURL_SUFFIX_CURL_OFF_TU UL +# define CURL_TYPEOF_CURL_SOCKLEN_T int +#endif + +#ifdef _AIX +/* AIX needs */ +#define CURL_PULL_SYS_POLL_H +#endif + + +/* CURL_PULL_WS2TCPIP_H is defined above when inclusion of header file */ +/* ws2tcpip.h is required here to properly make type definitions below. */ +#ifdef CURL_PULL_WS2TCPIP_H +# include +# include +# include +#endif + +/* CURL_PULL_SYS_TYPES_H is defined above when inclusion of header file */ +/* sys/types.h is required here to properly make type definitions below. */ +#ifdef CURL_PULL_SYS_TYPES_H +# include +#endif + +/* CURL_PULL_SYS_SOCKET_H is defined above when inclusion of header file */ +/* sys/socket.h is required here to properly make type definitions below. */ +#ifdef CURL_PULL_SYS_SOCKET_H +# include +#endif + +/* CURL_PULL_SYS_POLL_H is defined above when inclusion of header file */ +/* sys/poll.h is required here to properly make type definitions below. */ +#ifdef CURL_PULL_SYS_POLL_H +# include +#endif + +/* Data type definition of curl_socklen_t. */ +#ifdef CURL_TYPEOF_CURL_SOCKLEN_T + typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; +#endif + +/* Data type definition of curl_off_t. */ + +#ifdef CURL_TYPEOF_CURL_OFF_T + typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; +#endif + +/* + * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow + * these to be visible and exported by the external libcurl interface API, + * while also making them visible to the library internals, simply including + * curl_setup.h, without actually needing to include curl.h internally. + * If some day this section would grow big enough, all this should be moved + * to its own header file. + */ + +/* + * Figure out if we can use the ## preprocessor operator, which is supported + * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__ + * or __cplusplus so we need to carefully check for them too. + */ + +#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \ + defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \ + defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \ + defined(__ILEC400__) + /* This compiler is believed to have an ISO compatible preprocessor */ +#define CURL_ISOCPP +#else + /* This compiler is believed NOT to have an ISO compatible preprocessor */ +#undef CURL_ISOCPP +#endif + +/* + * Macros for minimum-width signed and unsigned curl_off_t integer constants. + */ + +#if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551) +# define __CURL_OFF_T_C_HLPR2(x) x +# define __CURL_OFF_T_C_HLPR1(x) __CURL_OFF_T_C_HLPR2(x) +# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ + __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T) +# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \ + __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU) +#else +# ifdef CURL_ISOCPP +# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix +# else +# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix +# endif +# define __CURL_OFF_T_C_HLPR1(Val,Suffix) __CURL_OFF_T_C_HLPR2(Val,Suffix) +# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T) +# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU) +#endif + +#endif /* __CURL_SYSTEM_H */ diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/curl/typecheck-gcc.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/curl/typecheck-gcc.h new file mode 100755 index 000000000..01df7b15f --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/curl/typecheck-gcc.h @@ -0,0 +1,699 @@ +#ifndef __CURL_TYPECHECK_GCC_H +#define __CURL_TYPECHECK_GCC_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +/* wraps curl_easy_setopt() with typechecking */ + +/* To add a new kind of warning, add an + * if(_curl_is_sometype_option(_curl_opt)) + * if(!_curl_is_sometype(value)) + * _curl_easy_setopt_err_sometype(); + * block and define _curl_is_sometype_option, _curl_is_sometype and + * _curl_easy_setopt_err_sometype below + * + * NOTE: We use two nested 'if' statements here instead of the && operator, in + * order to work around gcc bug #32061. It affects only gcc 4.3.x/4.4.x + * when compiling with -Wlogical-op. + * + * To add an option that uses the same type as an existing option, you'll just + * need to extend the appropriate _curl_*_option macro + */ +#define curl_easy_setopt(handle, option, value) \ +__extension__ ({ \ + __typeof__(option) _curl_opt = option; \ + if(__builtin_constant_p(_curl_opt)) { \ + if(_curl_is_long_option(_curl_opt)) \ + if(!_curl_is_long(value)) \ + _curl_easy_setopt_err_long(); \ + if(_curl_is_off_t_option(_curl_opt)) \ + if(!_curl_is_off_t(value)) \ + _curl_easy_setopt_err_curl_off_t(); \ + if(_curl_is_string_option(_curl_opt)) \ + if(!_curl_is_string(value)) \ + _curl_easy_setopt_err_string(); \ + if(_curl_is_write_cb_option(_curl_opt)) \ + if(!_curl_is_write_cb(value)) \ + _curl_easy_setopt_err_write_callback(); \ + if((_curl_opt) == CURLOPT_RESOLVER_START_FUNCTION) \ + if(!_curl_is_resolver_start_callback(value)) \ + _curl_easy_setopt_err_resolver_start_callback(); \ + if((_curl_opt) == CURLOPT_READFUNCTION) \ + if(!_curl_is_read_cb(value)) \ + _curl_easy_setopt_err_read_cb(); \ + if((_curl_opt) == CURLOPT_IOCTLFUNCTION) \ + if(!_curl_is_ioctl_cb(value)) \ + _curl_easy_setopt_err_ioctl_cb(); \ + if((_curl_opt) == CURLOPT_SOCKOPTFUNCTION) \ + if(!_curl_is_sockopt_cb(value)) \ + _curl_easy_setopt_err_sockopt_cb(); \ + if((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION) \ + if(!_curl_is_opensocket_cb(value)) \ + _curl_easy_setopt_err_opensocket_cb(); \ + if((_curl_opt) == CURLOPT_PROGRESSFUNCTION) \ + if(!_curl_is_progress_cb(value)) \ + _curl_easy_setopt_err_progress_cb(); \ + if((_curl_opt) == CURLOPT_DEBUGFUNCTION) \ + if(!_curl_is_debug_cb(value)) \ + _curl_easy_setopt_err_debug_cb(); \ + if((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION) \ + if(!_curl_is_ssl_ctx_cb(value)) \ + _curl_easy_setopt_err_ssl_ctx_cb(); \ + if(_curl_is_conv_cb_option(_curl_opt)) \ + if(!_curl_is_conv_cb(value)) \ + _curl_easy_setopt_err_conv_cb(); \ + if((_curl_opt) == CURLOPT_SEEKFUNCTION) \ + if(!_curl_is_seek_cb(value)) \ + _curl_easy_setopt_err_seek_cb(); \ + if(_curl_is_cb_data_option(_curl_opt)) \ + if(!_curl_is_cb_data(value)) \ + _curl_easy_setopt_err_cb_data(); \ + if((_curl_opt) == CURLOPT_ERRORBUFFER) \ + if(!_curl_is_error_buffer(value)) \ + _curl_easy_setopt_err_error_buffer(); \ + if((_curl_opt) == CURLOPT_STDERR) \ + if(!_curl_is_FILE(value)) \ + _curl_easy_setopt_err_FILE(); \ + if(_curl_is_postfields_option(_curl_opt)) \ + if(!_curl_is_postfields(value)) \ + _curl_easy_setopt_err_postfields(); \ + if((_curl_opt) == CURLOPT_HTTPPOST) \ + if(!_curl_is_arr((value), struct curl_httppost)) \ + _curl_easy_setopt_err_curl_httpost(); \ + if((_curl_opt) == CURLOPT_MIMEPOST) \ + if(!_curl_is_ptr((value), curl_mime)) \ + _curl_easy_setopt_err_curl_mimepost(); \ + if(_curl_is_slist_option(_curl_opt)) \ + if(!_curl_is_arr((value), struct curl_slist)) \ + _curl_easy_setopt_err_curl_slist(); \ + if((_curl_opt) == CURLOPT_SHARE) \ + if(!_curl_is_ptr((value), CURLSH)) \ + _curl_easy_setopt_err_CURLSH(); \ + } \ + curl_easy_setopt(handle, _curl_opt, value); \ +}) + +/* wraps curl_easy_getinfo() with typechecking */ +/* FIXME: don't allow const pointers */ +#define curl_easy_getinfo(handle, info, arg) \ +__extension__ ({ \ + __typeof__(info) _curl_info = info; \ + if(__builtin_constant_p(_curl_info)) { \ + if(_curl_is_string_info(_curl_info)) \ + if(!_curl_is_arr((arg), char *)) \ + _curl_easy_getinfo_err_string(); \ + if(_curl_is_long_info(_curl_info)) \ + if(!_curl_is_arr((arg), long)) \ + _curl_easy_getinfo_err_long(); \ + if(_curl_is_double_info(_curl_info)) \ + if(!_curl_is_arr((arg), double)) \ + _curl_easy_getinfo_err_double(); \ + if(_curl_is_slist_info(_curl_info)) \ + if(!_curl_is_arr((arg), struct curl_slist *)) \ + _curl_easy_getinfo_err_curl_slist(); \ + if(_curl_is_tlssessioninfo_info(_curl_info)) \ + if(!_curl_is_arr((arg), struct curl_tlssessioninfo *)) \ + _curl_easy_getinfo_err_curl_tlssesssioninfo(); \ + if(_curl_is_certinfo_info(_curl_info)) \ + if(!_curl_is_arr((arg), struct curl_certinfo *)) \ + _curl_easy_getinfo_err_curl_certinfo(); \ + if(_curl_is_socket_info(_curl_info)) \ + if(!_curl_is_arr((arg), curl_socket_t)) \ + _curl_easy_getinfo_err_curl_socket(); \ + if(_curl_is_off_t_info(_curl_info)) \ + if(!_curl_is_arr((arg), curl_off_t)) \ + _curl_easy_getinfo_err_curl_off_t(); \ + } \ + curl_easy_getinfo(handle, _curl_info, arg); \ +}) + +/* TODO: typechecking for curl_share_setopt() and curl_multi_setopt(), + * for now just make sure that the functions are called with three + * arguments + */ +#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) +#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) + + +/* the actual warnings, triggered by calling the _curl_easy_setopt_err* + * functions */ + +/* To define a new warning, use _CURL_WARNING(identifier, "message") */ +#define _CURL_WARNING(id, message) \ + static void __attribute__((__warning__(message))) \ + __attribute__((__unused__)) __attribute__((__noinline__)) \ + id(void) { __asm__(""); } + +_CURL_WARNING(_curl_easy_setopt_err_long, + "curl_easy_setopt expects a long argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_off_t, + "curl_easy_setopt expects a curl_off_t argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_string, + "curl_easy_setopt expects a " + "string ('char *' or char[]) argument for this option" + ) +_CURL_WARNING(_curl_easy_setopt_err_write_callback, + "curl_easy_setopt expects a curl_write_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_resolver_start_callback, + "curl_easy_setopt expects a " + "curl_resolver_start_callback argument for this option" + ) +_CURL_WARNING(_curl_easy_setopt_err_read_cb, + "curl_easy_setopt expects a curl_read_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_ioctl_cb, + "curl_easy_setopt expects a curl_ioctl_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_sockopt_cb, + "curl_easy_setopt expects a curl_sockopt_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_opensocket_cb, + "curl_easy_setopt expects a " + "curl_opensocket_callback argument for this option" + ) +_CURL_WARNING(_curl_easy_setopt_err_progress_cb, + "curl_easy_setopt expects a curl_progress_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_debug_cb, + "curl_easy_setopt expects a curl_debug_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_ssl_ctx_cb, + "curl_easy_setopt expects a curl_ssl_ctx_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_conv_cb, + "curl_easy_setopt expects a curl_conv_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_seek_cb, + "curl_easy_setopt expects a curl_seek_callback argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_cb_data, + "curl_easy_setopt expects a " + "private data pointer as argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_error_buffer, + "curl_easy_setopt expects a " + "char buffer of CURL_ERROR_SIZE as argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_FILE, + "curl_easy_setopt expects a 'FILE *' argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_postfields, + "curl_easy_setopt expects a 'void *' or 'char *' argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_httpost, + "curl_easy_setopt expects a 'struct curl_httppost *' " + "argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_mimepost, + "curl_easy_setopt expects a 'curl_mime *' " + "argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_curl_slist, + "curl_easy_setopt expects a 'struct curl_slist *' argument for this option") +_CURL_WARNING(_curl_easy_setopt_err_CURLSH, + "curl_easy_setopt expects a CURLSH* argument for this option") + +_CURL_WARNING(_curl_easy_getinfo_err_string, + "curl_easy_getinfo expects a pointer to 'char *' for this info") +_CURL_WARNING(_curl_easy_getinfo_err_long, + "curl_easy_getinfo expects a pointer to long for this info") +_CURL_WARNING(_curl_easy_getinfo_err_double, + "curl_easy_getinfo expects a pointer to double for this info") +_CURL_WARNING(_curl_easy_getinfo_err_curl_slist, + "curl_easy_getinfo expects a pointer to 'struct curl_slist *' for this info") +_CURL_WARNING(_curl_easy_getinfo_err_curl_tlssesssioninfo, + "curl_easy_getinfo expects a pointer to " + "'struct curl_tlssessioninfo *' for this info") +_CURL_WARNING(_curl_easy_getinfo_err_curl_certinfo, + "curl_easy_getinfo expects a pointer to " + "'struct curl_certinfo *' for this info") +_CURL_WARNING(_curl_easy_getinfo_err_curl_socket, + "curl_easy_getinfo expects a pointer to curl_socket_t for this info") +_CURL_WARNING(_curl_easy_getinfo_err_curl_off_t, + "curl_easy_getinfo expects a pointer to curl_off_t for this info") + +/* groups of curl_easy_setops options that take the same type of argument */ + +/* To add a new option to one of the groups, just add + * (option) == CURLOPT_SOMETHING + * to the or-expression. If the option takes a long or curl_off_t, you don't + * have to do anything + */ + +/* evaluates to true if option takes a long argument */ +#define _curl_is_long_option(option) \ + (0 < (option) && (option) < CURLOPTTYPE_OBJECTPOINT) + +#define _curl_is_off_t_option(option) \ + ((option) > CURLOPTTYPE_OFF_T) + +/* evaluates to true if option takes a char* argument */ +#define _curl_is_string_option(option) \ + ((option) == CURLOPT_ABSTRACT_UNIX_SOCKET || \ + (option) == CURLOPT_ACCEPT_ENCODING || \ + (option) == CURLOPT_CAINFO || \ + (option) == CURLOPT_CAPATH || \ + (option) == CURLOPT_COOKIE || \ + (option) == CURLOPT_COOKIEFILE || \ + (option) == CURLOPT_COOKIEJAR || \ + (option) == CURLOPT_COOKIELIST || \ + (option) == CURLOPT_CRLFILE || \ + (option) == CURLOPT_CUSTOMREQUEST || \ + (option) == CURLOPT_DEFAULT_PROTOCOL || \ + (option) == CURLOPT_DNS_INTERFACE || \ + (option) == CURLOPT_DNS_LOCAL_IP4 || \ + (option) == CURLOPT_DNS_LOCAL_IP6 || \ + (option) == CURLOPT_DNS_SERVERS || \ + (option) == CURLOPT_DOH_URL || \ + (option) == CURLOPT_EGDSOCKET || \ + (option) == CURLOPT_FTPPORT || \ + (option) == CURLOPT_FTP_ACCOUNT || \ + (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \ + (option) == CURLOPT_INTERFACE || \ + (option) == CURLOPT_ISSUERCERT || \ + (option) == CURLOPT_KEYPASSWD || \ + (option) == CURLOPT_KRBLEVEL || \ + (option) == CURLOPT_LOGIN_OPTIONS || \ + (option) == CURLOPT_MAIL_AUTH || \ + (option) == CURLOPT_MAIL_FROM || \ + (option) == CURLOPT_NETRC_FILE || \ + (option) == CURLOPT_NOPROXY || \ + (option) == CURLOPT_PASSWORD || \ + (option) == CURLOPT_PINNEDPUBLICKEY || \ + (option) == CURLOPT_PRE_PROXY || \ + (option) == CURLOPT_PROXY || \ + (option) == CURLOPT_PROXYPASSWORD || \ + (option) == CURLOPT_PROXYUSERNAME || \ + (option) == CURLOPT_PROXYUSERPWD || \ + (option) == CURLOPT_PROXY_CAINFO || \ + (option) == CURLOPT_PROXY_CAPATH || \ + (option) == CURLOPT_PROXY_CRLFILE || \ + (option) == CURLOPT_PROXY_KEYPASSWD || \ + (option) == CURLOPT_PROXY_PINNEDPUBLICKEY || \ + (option) == CURLOPT_PROXY_SERVICE_NAME || \ + (option) == CURLOPT_PROXY_SSLCERT || \ + (option) == CURLOPT_PROXY_SSLCERTTYPE || \ + (option) == CURLOPT_PROXY_SSLKEY || \ + (option) == CURLOPT_PROXY_SSLKEYTYPE || \ + (option) == CURLOPT_PROXY_SSL_CIPHER_LIST || \ + (option) == CURLOPT_PROXY_TLSAUTH_PASSWORD || \ + (option) == CURLOPT_PROXY_TLSAUTH_USERNAME || \ + (option) == CURLOPT_PROXY_TLSAUTH_TYPE || \ + (option) == CURLOPT_RANDOM_FILE || \ + (option) == CURLOPT_RANGE || \ + (option) == CURLOPT_REFERER || \ + (option) == CURLOPT_RTSP_SESSION_ID || \ + (option) == CURLOPT_RTSP_STREAM_URI || \ + (option) == CURLOPT_RTSP_TRANSPORT || \ + (option) == CURLOPT_SERVICE_NAME || \ + (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \ + (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \ + (option) == CURLOPT_SSH_KNOWNHOSTS || \ + (option) == CURLOPT_SSH_PRIVATE_KEYFILE || \ + (option) == CURLOPT_SSH_PUBLIC_KEYFILE || \ + (option) == CURLOPT_SSLCERT || \ + (option) == CURLOPT_SSLCERTTYPE || \ + (option) == CURLOPT_SSLENGINE || \ + (option) == CURLOPT_SSLKEY || \ + (option) == CURLOPT_SSLKEYTYPE || \ + (option) == CURLOPT_SSL_CIPHER_LIST || \ + (option) == CURLOPT_TLSAUTH_PASSWORD || \ + (option) == CURLOPT_TLSAUTH_TYPE || \ + (option) == CURLOPT_TLSAUTH_USERNAME || \ + (option) == CURLOPT_UNIX_SOCKET_PATH || \ + (option) == CURLOPT_URL || \ + (option) == CURLOPT_USERAGENT || \ + (option) == CURLOPT_USERNAME || \ + (option) == CURLOPT_USERPWD || \ + (option) == CURLOPT_XOAUTH2_BEARER || \ + 0) + +/* evaluates to true if option takes a curl_write_callback argument */ +#define _curl_is_write_cb_option(option) \ + ((option) == CURLOPT_HEADERFUNCTION || \ + (option) == CURLOPT_WRITEFUNCTION) + +/* evaluates to true if option takes a curl_conv_callback argument */ +#define _curl_is_conv_cb_option(option) \ + ((option) == CURLOPT_CONV_TO_NETWORK_FUNCTION || \ + (option) == CURLOPT_CONV_FROM_NETWORK_FUNCTION || \ + (option) == CURLOPT_CONV_FROM_UTF8_FUNCTION) + +/* evaluates to true if option takes a data argument to pass to a callback */ +#define _curl_is_cb_data_option(option) \ + ((option) == CURLOPT_CHUNK_DATA || \ + (option) == CURLOPT_CLOSESOCKETDATA || \ + (option) == CURLOPT_DEBUGDATA || \ + (option) == CURLOPT_FNMATCH_DATA || \ + (option) == CURLOPT_HEADERDATA || \ + (option) == CURLOPT_INTERLEAVEDATA || \ + (option) == CURLOPT_IOCTLDATA || \ + (option) == CURLOPT_OPENSOCKETDATA || \ + (option) == CURLOPT_PRIVATE || \ + (option) == CURLOPT_PROGRESSDATA || \ + (option) == CURLOPT_READDATA || \ + (option) == CURLOPT_SEEKDATA || \ + (option) == CURLOPT_SOCKOPTDATA || \ + (option) == CURLOPT_SSH_KEYDATA || \ + (option) == CURLOPT_SSL_CTX_DATA || \ + (option) == CURLOPT_WRITEDATA || \ + (option) == CURLOPT_RESOLVER_START_DATA || \ + (option) == CURLOPT_CURLU || \ + 0) + +/* evaluates to true if option takes a POST data argument (void* or char*) */ +#define _curl_is_postfields_option(option) \ + ((option) == CURLOPT_POSTFIELDS || \ + (option) == CURLOPT_COPYPOSTFIELDS || \ + 0) + +/* evaluates to true if option takes a struct curl_slist * argument */ +#define _curl_is_slist_option(option) \ + ((option) == CURLOPT_HTTP200ALIASES || \ + (option) == CURLOPT_HTTPHEADER || \ + (option) == CURLOPT_MAIL_RCPT || \ + (option) == CURLOPT_POSTQUOTE || \ + (option) == CURLOPT_PREQUOTE || \ + (option) == CURLOPT_PROXYHEADER || \ + (option) == CURLOPT_QUOTE || \ + (option) == CURLOPT_RESOLVE || \ + (option) == CURLOPT_TELNETOPTIONS || \ + 0) + +/* groups of curl_easy_getinfo infos that take the same type of argument */ + +/* evaluates to true if info expects a pointer to char * argument */ +#define _curl_is_string_info(info) \ + (CURLINFO_STRING < (info) && (info) < CURLINFO_LONG) + +/* evaluates to true if info expects a pointer to long argument */ +#define _curl_is_long_info(info) \ + (CURLINFO_LONG < (info) && (info) < CURLINFO_DOUBLE) + +/* evaluates to true if info expects a pointer to double argument */ +#define _curl_is_double_info(info) \ + (CURLINFO_DOUBLE < (info) && (info) < CURLINFO_SLIST) + +/* true if info expects a pointer to struct curl_slist * argument */ +#define _curl_is_slist_info(info) \ + (((info) == CURLINFO_SSL_ENGINES) || ((info) == CURLINFO_COOKIELIST)) + +/* true if info expects a pointer to struct curl_tlssessioninfo * argument */ +#define _curl_is_tlssessioninfo_info(info) \ + (((info) == CURLINFO_TLS_SSL_PTR) || ((info) == CURLINFO_TLS_SESSION)) + +/* true if info expects a pointer to struct curl_certinfo * argument */ +#define _curl_is_certinfo_info(info) ((info) == CURLINFO_CERTINFO) + +/* true if info expects a pointer to struct curl_socket_t argument */ +#define _curl_is_socket_info(info) \ + (CURLINFO_SOCKET < (info) && (info) < CURLINFO_OFF_T) + +/* true if info expects a pointer to curl_off_t argument */ +#define _curl_is_off_t_info(info) \ + (CURLINFO_OFF_T < (info)) + + +/* typecheck helpers -- check whether given expression has requested type*/ + +/* For pointers, you can use the _curl_is_ptr/_curl_is_arr macros, + * otherwise define a new macro. Search for __builtin_types_compatible_p + * in the GCC manual. + * NOTE: these macros MUST NOT EVALUATE their arguments! The argument is + * the actual expression passed to the curl_easy_setopt macro. This + * means that you can only apply the sizeof and __typeof__ operators, no + * == or whatsoever. + */ + +/* XXX: should evaluate to true if expr is a pointer */ +#define _curl_is_any_ptr(expr) \ + (sizeof(expr) == sizeof(void *)) + +/* evaluates to true if expr is NULL */ +/* XXX: must not evaluate expr, so this check is not accurate */ +#define _curl_is_NULL(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), __typeof__(NULL))) + +/* evaluates to true if expr is type*, const type* or NULL */ +#define _curl_is_ptr(expr, type) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), type *) || \ + __builtin_types_compatible_p(__typeof__(expr), const type *)) + +/* evaluates to true if expr is one of type[], type*, NULL or const type* */ +#define _curl_is_arr(expr, type) \ + (_curl_is_ptr((expr), type) || \ + __builtin_types_compatible_p(__typeof__(expr), type [])) + +/* evaluates to true if expr is a string */ +#define _curl_is_string(expr) \ + (_curl_is_arr((expr), char) || \ + _curl_is_arr((expr), signed char) || \ + _curl_is_arr((expr), unsigned char)) + +/* evaluates to true if expr is a long (no matter the signedness) + * XXX: for now, int is also accepted (and therefore short and char, which + * are promoted to int when passed to a variadic function) */ +#define _curl_is_long(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), long) || \ + __builtin_types_compatible_p(__typeof__(expr), signed long) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned long) || \ + __builtin_types_compatible_p(__typeof__(expr), int) || \ + __builtin_types_compatible_p(__typeof__(expr), signed int) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned int) || \ + __builtin_types_compatible_p(__typeof__(expr), short) || \ + __builtin_types_compatible_p(__typeof__(expr), signed short) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned short) || \ + __builtin_types_compatible_p(__typeof__(expr), char) || \ + __builtin_types_compatible_p(__typeof__(expr), signed char) || \ + __builtin_types_compatible_p(__typeof__(expr), unsigned char)) + +/* evaluates to true if expr is of type curl_off_t */ +#define _curl_is_off_t(expr) \ + (__builtin_types_compatible_p(__typeof__(expr), curl_off_t)) + +/* evaluates to true if expr is abuffer suitable for CURLOPT_ERRORBUFFER */ +/* XXX: also check size of an char[] array? */ +#define _curl_is_error_buffer(expr) \ + (_curl_is_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), char *) || \ + __builtin_types_compatible_p(__typeof__(expr), char[])) + +/* evaluates to true if expr is of type (const) void* or (const) FILE* */ +#if 0 +#define _curl_is_cb_data(expr) \ + (_curl_is_ptr((expr), void) || \ + _curl_is_ptr((expr), FILE)) +#else /* be less strict */ +#define _curl_is_cb_data(expr) \ + _curl_is_any_ptr(expr) +#endif + +/* evaluates to true if expr is of type FILE* */ +#define _curl_is_FILE(expr) \ + (_curl_is_NULL(expr) || \ + (__builtin_types_compatible_p(__typeof__(expr), FILE *))) + +/* evaluates to true if expr can be passed as POST data (void* or char*) */ +#define _curl_is_postfields(expr) \ + (_curl_is_ptr((expr), void) || \ + _curl_is_arr((expr), char) || \ + _curl_is_arr((expr), unsigned char)) + +/* FIXME: the whole callback checking is messy... + * The idea is to tolerate char vs. void and const vs. not const + * pointers in arguments at least + */ +/* helper: __builtin_types_compatible_p distinguishes between functions and + * function pointers, hide it */ +#define _curl_callback_compatible(func, type) \ + (__builtin_types_compatible_p(__typeof__(func), type) || \ + __builtin_types_compatible_p(__typeof__(func) *, type)) + +/* evaluates to true if expr is of type curl_resolver_start_callback */ +#define _curl_is_resolver_start_callback(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_resolver_start_callback)) + +/* evaluates to true if expr is of type curl_read_callback or "similar" */ +#define _curl_is_read_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), __typeof__(fread) *) || \ + _curl_callback_compatible((expr), curl_read_callback) || \ + _curl_callback_compatible((expr), _curl_read_callback1) || \ + _curl_callback_compatible((expr), _curl_read_callback2) || \ + _curl_callback_compatible((expr), _curl_read_callback3) || \ + _curl_callback_compatible((expr), _curl_read_callback4) || \ + _curl_callback_compatible((expr), _curl_read_callback5) || \ + _curl_callback_compatible((expr), _curl_read_callback6)) +typedef size_t (*_curl_read_callback1)(char *, size_t, size_t, void *); +typedef size_t (*_curl_read_callback2)(char *, size_t, size_t, const void *); +typedef size_t (*_curl_read_callback3)(char *, size_t, size_t, FILE *); +typedef size_t (*_curl_read_callback4)(void *, size_t, size_t, void *); +typedef size_t (*_curl_read_callback5)(void *, size_t, size_t, const void *); +typedef size_t (*_curl_read_callback6)(void *, size_t, size_t, FILE *); + +/* evaluates to true if expr is of type curl_write_callback or "similar" */ +#define _curl_is_write_cb(expr) \ + (_curl_is_read_cb(expr) || \ + _curl_callback_compatible((expr), __typeof__(fwrite) *) || \ + _curl_callback_compatible((expr), curl_write_callback) || \ + _curl_callback_compatible((expr), _curl_write_callback1) || \ + _curl_callback_compatible((expr), _curl_write_callback2) || \ + _curl_callback_compatible((expr), _curl_write_callback3) || \ + _curl_callback_compatible((expr), _curl_write_callback4) || \ + _curl_callback_compatible((expr), _curl_write_callback5) || \ + _curl_callback_compatible((expr), _curl_write_callback6)) +typedef size_t (*_curl_write_callback1)(const char *, size_t, size_t, void *); +typedef size_t (*_curl_write_callback2)(const char *, size_t, size_t, + const void *); +typedef size_t (*_curl_write_callback3)(const char *, size_t, size_t, FILE *); +typedef size_t (*_curl_write_callback4)(const void *, size_t, size_t, void *); +typedef size_t (*_curl_write_callback5)(const void *, size_t, size_t, + const void *); +typedef size_t (*_curl_write_callback6)(const void *, size_t, size_t, FILE *); + +/* evaluates to true if expr is of type curl_ioctl_callback or "similar" */ +#define _curl_is_ioctl_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_ioctl_callback) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback1) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback2) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback3) || \ + _curl_callback_compatible((expr), _curl_ioctl_callback4)) +typedef curlioerr (*_curl_ioctl_callback1)(CURL *, int, void *); +typedef curlioerr (*_curl_ioctl_callback2)(CURL *, int, const void *); +typedef curlioerr (*_curl_ioctl_callback3)(CURL *, curliocmd, void *); +typedef curlioerr (*_curl_ioctl_callback4)(CURL *, curliocmd, const void *); + +/* evaluates to true if expr is of type curl_sockopt_callback or "similar" */ +#define _curl_is_sockopt_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_sockopt_callback) || \ + _curl_callback_compatible((expr), _curl_sockopt_callback1) || \ + _curl_callback_compatible((expr), _curl_sockopt_callback2)) +typedef int (*_curl_sockopt_callback1)(void *, curl_socket_t, curlsocktype); +typedef int (*_curl_sockopt_callback2)(const void *, curl_socket_t, + curlsocktype); + +/* evaluates to true if expr is of type curl_opensocket_callback or + "similar" */ +#define _curl_is_opensocket_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_opensocket_callback) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback1) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback2) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback3) || \ + _curl_callback_compatible((expr), _curl_opensocket_callback4)) +typedef curl_socket_t (*_curl_opensocket_callback1) + (void *, curlsocktype, struct curl_sockaddr *); +typedef curl_socket_t (*_curl_opensocket_callback2) + (void *, curlsocktype, const struct curl_sockaddr *); +typedef curl_socket_t (*_curl_opensocket_callback3) + (const void *, curlsocktype, struct curl_sockaddr *); +typedef curl_socket_t (*_curl_opensocket_callback4) + (const void *, curlsocktype, const struct curl_sockaddr *); + +/* evaluates to true if expr is of type curl_progress_callback or "similar" */ +#define _curl_is_progress_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_progress_callback) || \ + _curl_callback_compatible((expr), _curl_progress_callback1) || \ + _curl_callback_compatible((expr), _curl_progress_callback2)) +typedef int (*_curl_progress_callback1)(void *, + double, double, double, double); +typedef int (*_curl_progress_callback2)(const void *, + double, double, double, double); + +/* evaluates to true if expr is of type curl_debug_callback or "similar" */ +#define _curl_is_debug_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_debug_callback) || \ + _curl_callback_compatible((expr), _curl_debug_callback1) || \ + _curl_callback_compatible((expr), _curl_debug_callback2) || \ + _curl_callback_compatible((expr), _curl_debug_callback3) || \ + _curl_callback_compatible((expr), _curl_debug_callback4) || \ + _curl_callback_compatible((expr), _curl_debug_callback5) || \ + _curl_callback_compatible((expr), _curl_debug_callback6) || \ + _curl_callback_compatible((expr), _curl_debug_callback7) || \ + _curl_callback_compatible((expr), _curl_debug_callback8)) +typedef int (*_curl_debug_callback1) (CURL *, + curl_infotype, char *, size_t, void *); +typedef int (*_curl_debug_callback2) (CURL *, + curl_infotype, char *, size_t, const void *); +typedef int (*_curl_debug_callback3) (CURL *, + curl_infotype, const char *, size_t, void *); +typedef int (*_curl_debug_callback4) (CURL *, + curl_infotype, const char *, size_t, const void *); +typedef int (*_curl_debug_callback5) (CURL *, + curl_infotype, unsigned char *, size_t, void *); +typedef int (*_curl_debug_callback6) (CURL *, + curl_infotype, unsigned char *, size_t, const void *); +typedef int (*_curl_debug_callback7) (CURL *, + curl_infotype, const unsigned char *, size_t, void *); +typedef int (*_curl_debug_callback8) (CURL *, + curl_infotype, const unsigned char *, size_t, const void *); + +/* evaluates to true if expr is of type curl_ssl_ctx_callback or "similar" */ +/* this is getting even messier... */ +#define _curl_is_ssl_ctx_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_ssl_ctx_callback) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback1) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback2) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback3) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback4) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback5) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback6) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback7) || \ + _curl_callback_compatible((expr), _curl_ssl_ctx_callback8)) +typedef CURLcode (*_curl_ssl_ctx_callback1)(CURL *, void *, void *); +typedef CURLcode (*_curl_ssl_ctx_callback2)(CURL *, void *, const void *); +typedef CURLcode (*_curl_ssl_ctx_callback3)(CURL *, const void *, void *); +typedef CURLcode (*_curl_ssl_ctx_callback4)(CURL *, const void *, + const void *); +#ifdef HEADER_SSL_H +/* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX + * this will of course break if we're included before OpenSSL headers... + */ +typedef CURLcode (*_curl_ssl_ctx_callback5)(CURL *, SSL_CTX, void *); +typedef CURLcode (*_curl_ssl_ctx_callback6)(CURL *, SSL_CTX, const void *); +typedef CURLcode (*_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX, void *); +typedef CURLcode (*_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX, + const void *); +#else +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback5; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback6; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback7; +typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback8; +#endif + +/* evaluates to true if expr is of type curl_conv_callback or "similar" */ +#define _curl_is_conv_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_conv_callback) || \ + _curl_callback_compatible((expr), _curl_conv_callback1) || \ + _curl_callback_compatible((expr), _curl_conv_callback2) || \ + _curl_callback_compatible((expr), _curl_conv_callback3) || \ + _curl_callback_compatible((expr), _curl_conv_callback4)) +typedef CURLcode (*_curl_conv_callback1)(char *, size_t length); +typedef CURLcode (*_curl_conv_callback2)(const char *, size_t length); +typedef CURLcode (*_curl_conv_callback3)(void *, size_t length); +typedef CURLcode (*_curl_conv_callback4)(const void *, size_t length); + +/* evaluates to true if expr is of type curl_seek_callback or "similar" */ +#define _curl_is_seek_cb(expr) \ + (_curl_is_NULL(expr) || \ + _curl_callback_compatible((expr), curl_seek_callback) || \ + _curl_callback_compatible((expr), _curl_seek_callback1) || \ + _curl_callback_compatible((expr), _curl_seek_callback2)) +typedef CURLcode (*_curl_seek_callback1)(void *, curl_off_t, int); +typedef CURLcode (*_curl_seek_callback2)(const void *, curl_off_t, int); + + +#endif /* __CURL_TYPECHECK_GCC_H */ diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/curl/urlapi.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/curl/urlapi.h new file mode 100755 index 000000000..850faa97a --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/curl/urlapi.h @@ -0,0 +1,122 @@ +#ifndef __CURL_URLAPI_H +#define __CURL_URLAPI_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2018 - 2019, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* the error codes for the URL API */ +typedef enum { + CURLUE_OK, + CURLUE_BAD_HANDLE, /* 1 */ + CURLUE_BAD_PARTPOINTER, /* 2 */ + CURLUE_MALFORMED_INPUT, /* 3 */ + CURLUE_BAD_PORT_NUMBER, /* 4 */ + CURLUE_UNSUPPORTED_SCHEME, /* 5 */ + CURLUE_URLDECODE, /* 6 */ + CURLUE_OUT_OF_MEMORY, /* 7 */ + CURLUE_USER_NOT_ALLOWED, /* 8 */ + CURLUE_UNKNOWN_PART, /* 9 */ + CURLUE_NO_SCHEME, /* 10 */ + CURLUE_NO_USER, /* 11 */ + CURLUE_NO_PASSWORD, /* 12 */ + CURLUE_NO_OPTIONS, /* 13 */ + CURLUE_NO_HOST, /* 14 */ + CURLUE_NO_PORT, /* 15 */ + CURLUE_NO_QUERY, /* 16 */ + CURLUE_NO_FRAGMENT /* 17 */ +} CURLUcode; + +typedef enum { + CURLUPART_URL, + CURLUPART_SCHEME, + CURLUPART_USER, + CURLUPART_PASSWORD, + CURLUPART_OPTIONS, + CURLUPART_HOST, + CURLUPART_PORT, + CURLUPART_PATH, + CURLUPART_QUERY, + CURLUPART_FRAGMENT +} CURLUPart; + +#define CURLU_DEFAULT_PORT (1<<0) /* return default port number */ +#define CURLU_NO_DEFAULT_PORT (1<<1) /* act as if no port number was set, + if the port number matches the + default for the scheme */ +#define CURLU_DEFAULT_SCHEME (1<<2) /* return default scheme if + missing */ +#define CURLU_NON_SUPPORT_SCHEME (1<<3) /* allow non-supported scheme */ +#define CURLU_PATH_AS_IS (1<<4) /* leave dot sequences */ +#define CURLU_DISALLOW_USER (1<<5) /* no user+password allowed */ +#define CURLU_URLDECODE (1<<6) /* URL decode on get */ +#define CURLU_URLENCODE (1<<7) /* URL encode on set */ +#define CURLU_APPENDQUERY (1<<8) /* append a form style part */ +#define CURLU_GUESS_SCHEME (1<<9) /* legacy curl-style guessing */ + +typedef struct Curl_URL CURLU; + +/* + * curl_url() creates a new CURLU handle and returns a pointer to it. + * Must be freed with curl_url_cleanup(). + */ +CURL_EXTERN CURLU *curl_url(void); + +/* + * curl_url_cleanup() frees the CURLU handle and related resources used for + * the URL parsing. It will not free strings previously returned with the URL + * API. + */ +CURL_EXTERN void curl_url_cleanup(CURLU *handle); + +/* + * curl_url_dup() duplicates a CURLU handle and returns a new copy. The new + * handle must also be freed with curl_url_cleanup(). + */ +CURL_EXTERN CURLU *curl_url_dup(CURLU *in); + +/* + * curl_url_get() extracts a specific part of the URL from a CURLU + * handle. Returns error code. The returned pointer MUST be freed with + * curl_free() afterwards. + */ +CURL_EXTERN CURLUcode curl_url_get(CURLU *handle, CURLUPart what, + char **part, unsigned int flags); + +/* + * curl_url_set() sets a specific part of the URL in a CURLU handle. Returns + * error code. The passed in string will be copied. Passing a NULL instead of + * a part string, clears that part. + */ +CURL_EXTERN CURLUcode curl_url_set(CURLU *handle, CURLUPart what, + const char *part, unsigned int flags); + + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/api/lpasdk_api.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/api/lpasdk_api.h new file mode 100755 index 000000000..e85121128 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/api/lpasdk_api.h @@ -0,0 +1,758 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + + +#ifndef LPA_SDK__CORE_API_H +#define LPA_SDK__CORE_API_H + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include +#include +#include +#include + +#include "lpasdk/api/semedia/semedia.h" + +///////////////////////////////// +// API versionning +///////////////////////////////// + +#define LPA_API_MAJOR_VERSION 1 +#define LPA_API_MINOR_VERSION 9 + +typedef struct +{ + int major; // Update it when API compatibility is not "supported" + int minor; // Update it when function added without impact on API compatibility +}LPA_API_VERSION; + +///////////////////////////////// +// LPA Type +///////////////////////////////// + +typedef int16_t LPA_Integer; +typedef char* LPA_StringPtr; + +///////////////////////////////// +// API definition +///////////////////////////////// + + + +#define LPA_CFG_DEVICE_INFO_TLV_MAX_SIZE 385 // 384 + CR +#define LPA_CFG_DEVICE_INFO_TLV_BYTE_ARRAY_MAX_SIZE ((LPA_CFG_DEVICE_INFO_TLV_MAX_SIZE >> 1) + 1) + +#define LPA_CFG_CERT_PATH_MAX_SIZE LPA_MAX_PATH + +#define LPA_CFG_LINE_ENTRY_MAX_SIZE 1024 + +/* +Maximum profile info size retrieved from eUICC (Max length used): + Tag/size bytes + max data lengths +Header tag E3 5 bytes +iccid tag 5A 2 + 10 = 12 bytes +profileState tag 9F70 3 + 1 = 4 bytes +profileNickName tag 90 2 + 64 = 66 bytes +serviceProviderName tag 91 2 + 32 = 34 bytes +profileName tag 92 2 + 64 = 66 bytes +iconType tag 93 2 + 1 = 3 bytes +icon tag 94 4 + 1024 = 1028 bytes +profileClass tag 95 2 + 1 = 3 bytes +profilePolicyRules tag 99 2 + 2 = 4 bytes + +TOTAL -------------------------------------- 1225 bytes - Set at 1300 for rounding / security +Note: Other tags (4F, B6, B7 & B8) not requested in current request, so not taken in account +*/ +#define LPA_PROFILE_INFO_BUFFER_MAX_SIZE 1300 // Size of profile raw data +#define LPA_MAX_EVENT_RECORD 16 + +// All profile fields limits match maximum defined in SGP.22 +// LPA_PROFILE_STATE_MAX_SIZE, LPA_PROFILE_CLASS_MAX_SIZE, LPA_PROFILE_ICON_TYPE_MAX_SIZE defined as ASN1 'INTEGER' +#define LPA_ASN1_INTEGER_MAX_SIZE 2 +#define LPA_PROFILE_ICCID_BUFFER_MAX_SIZE 10 +#define LPA_PROFILE_STATE_MAX_SIZE LPA_ASN1_INTEGER_MAX_SIZE +#define LPA_PROFILE_SERVICE_PROVIDER_NAME_MAX_SIZE 32 +#define LPA_PROFILE_NAME_MAX_SIZE 64 +#define LPA_PROFILE_CLASS_MAX_SIZE LPA_ASN1_INTEGER_MAX_SIZE +#define LPA_PROFILE_ICON_MAX_SIZE 1024 +#define LPA_PROFILE_ICON_TYPE_MAX_SIZE LPA_ASN1_INTEGER_MAX_SIZE +#define LPA_PROFILE_NICKNAME_MAX_SIZE 64 +#define LPA_PROFILE_POLICY_RULES_MAX_SIZE 2 + +#define LPA_GET_EID_BUFFER_SIZE 20 // Previously 64, 16 is the typical size, set 20 to keep a security +#define LPA_GET_EUICC_BUFFER_MAX_SIZE 900 //255 then 384 previously + +/* Size calculation to evaluate EUICCInfo2. Some fields of list size have no limit defined, so decisions have been taken here: + Note: TL = Tag Length +Size ASN1 object + Explanation +5 EUICCInfo2 Main Tag BF22, length coded on 3 bytes considering total data size => 5 bytes +5 profileVersion [1] "VersionType" object, 3 bytes value, 5 with TL +5 svn [2] "VersionType" object, 3 bytes value, 5 with TL +5 euiccFirmwareVer [3] "VersionType" object, 3 bytes value, 5 with TL +16 extCardResource [4] "Extended Card Resource Information according to ETSI TS 102 226" (Chapter 8.2.1.7.2) - 3 concatenated TLV, first refer "application number", typical 1 byte, 2 others are free memory status, typically coded on 4 bytes. Total typical size = 16 +6 uiccCapability [5] BITSTRING object, max 6 bytes with TL +5 ts102241Version [6] "VersionType" object, 3 bytes value, 5 with TL +5 globalplatformVersion [7] "VersionType" object, 3 bytes value, 5 with TL +4 rspCapability [8] BITSTRING object, 4 bytes with TL +3 euiccCiPKIdListForVerification [9] List of "SubjectKeyIdentifier", fixed to up to 6 elements (Typical use in Asia 5 elements): TL + Size coded on 2 bytes (132 bytes data) => 3 bytes +132 6x > SubjectKeyIdentifier "CI Public Key Identifier" => 20 bytes + 2 bytes TL => 22 bytes +3 euiccCiPKIdListForSigning [10] List of "SubjectKeyIdentifier", fixed to up to 6 elements (Typical use in Asia 5 elements): TL + Size coded on 2 bytes (132 bytes data) => 3 bytes +132 6x > SubjectKeyIdentifier "CI Public Key Identifier" => 20 bytes + 2 bytes TL => 22 bytes +3 euiccCategory [11] Integer, typically 1 byte value, 3 with TL +4 forbiddenProfilePolicyRules [25] BITSTRING object, 4 bytes with TL +5 ppVersion "VersionType" object, 3 bytes value, 5 with TL +66 sasAcreditationNumber String, limited to 64 characters max, 66 with TL +4 certificationDataObject [12] List of 2 strings, length coded on 3 bytes considering data size => 4 bytes +102 > platformLabel Coded on form "/", example "1.2.840.114283/My_Platform_Label_1a" - Considering real label size, set at 100 characters max + 2 bytes TL => 102 bytes +258 > discoveryBaseURL Based on the fact that some URL like Activation Code SM-DP address are limited to 255 characters, we will use the same limit => 258 bytes with TL +4 treProperties [13] BITSTRING object, 4 bytes with TL +52 treProductReference [14] String, "unique reference of the Integrated TRE product that the eUICC is based upon" - Set at 50 characters considering references actually used => 52 bytes with TL +2 additionalEuiccProfilePackageVersions [15] List of "VersionType" fixed to up to 12 elements: TL + Size coded on 1 byte (60 bytes data) => 2 bytes - "List higher major versions including associated highest minor version number of additional eUICC Profile Package specification(s) supported by eUICC +60 12x > VersionType "VersionType" object, 3 bytes value, 5 with TL +TOTAL 886 bytes + +*/ + +#define LPA_CANCEL_SESSION_RESPONSE_BUFFER_SIZE 160 + +// For memory: Full Activation Code is 1$lpa_SM-Dx_address$matchingId$oid_object$ccRequiredFlag +#define LPA_ACTIVATION_CODE_MAX_SIZE (2 + LPA_SMDP_ADDRESS_SIZE + 1 + LPA_MATCHING_ID_SIZE + 1 + LPA_OID_SIZE + 1 + LPA_CC_REQUIRED_FLAG_SIZE) +#define LPA_ACTIVATION_CODE_MAX_STRING_BUFFER_SIZE ( LPA_ACTIVATION_CODE_MAX_SIZE + 1 ) // Adding 1 bytes to End of String + +#define LPA_SMDP_ADDRESS_SIZE 128 // Max 127 characters with End Of String +#define LPA_SMDS_ADDRESS_SIZE LPA_SMDP_ADDRESS_SIZE +#define LPA_ADDRESS_MAX_SIZE 255 +#define LPA_MATCHING_ID_SIZE 255 +#define LPA_OID_SIZE 128 +#define LPA_CC_REQUIRED_FLAG_SIZE 2 // Include end of string + +#define LPA_MAX_PROFILE_NOTIFICATION_LIST_ELEMENT 16 +#define LPA_MAX_NOTIFICATION_ADDRESS_RAW_DATA_SIZE 128 + +// Managing Confirmation Code during downloadProfile +#define LPA_CONFIRMATION_CODE_MAX_SIZE 50 + +// Maximum number of parameters for parameter list generation +// ! CAUTION: Have to take care that list is long enough to store all parameters and element size long enough to fit longest parameters names +#define LPA_MAX_PARAMETERS_LIST 25 +#define LPA_MAX_PARAMETERS_LIST_ELEMENT_SIZE 40 + +typedef struct +{ + int major; + int minor; + int patch; + int build; +}LPA_VERSION; + + +// Support of Notification Error during a download profile +// Application owner should manage LPA_EVENT_REQUEST_CONFIRMATION_CODE callback +typedef enum +{ + LPA_EVENT_EXECUTION_SERVER_ERROR_TYPE = 1, // Error send by server + LPA_EVENT_EXECUTION_HTTP_ERROR_TYPE = 2, // HTTP error during communication with server + LPA_EVENT_EXECUTION_CURL_ERROR_TYPE = 3, // Curl error + LPA_EVENT_EXECUTION_SEMEDIA_DRIVER_ERROR_TYPE = 4 // SEMEDIA_DRIVER error +}LPA_EVENT_EXECUTION_ERROR_TYPE; + +typedef enum +{ + LPA_EVENT_EXECUTION_ERROR_NO_DETAIL_MASK = 0x0000, // 0b00000000 + + LPA_EVENT_EXECUTION_ERROR_SUBJECT_CODE_MASK = 0x0001, // 0b00000001 + LPA_EVENT_EXECUTION_ERROR_REASON_CODE_MASK = 0x0002, // 0b00000010 + LPA_EVENT_EXECUTION_ERROR_EXTRA_INFO_MASK = 0x0004, // 0b00000100 +}LPA_EVENT_EXECUTION_ERROR_DETAIL_MASK; + +typedef struct +{ + LPA_EVENT_EXECUTION_ERROR_TYPE executionErrorType; + LPA_EVENT_EXECUTION_ERROR_DETAIL_MASK detailErrorMask; + const char* ptrErrorSubjectCode; + const char* ptrErrorReasonCode; + const char* ptrErrorExtraInfo; +} LPA_EVENT_EXECUTION_ERROR_INFO; + + +// Support of Confirmation Code requested by LPA SDK +// Application owner should manage LPA_EVENT_EXECUTION_ERROR callback + +typedef struct +{ + // Confirmation code value updated by application + char confirmationCode[LPA_CONFIRMATION_CODE_MAX_SIZE]; + + // Size of CC buffer (with final '\0') + size_t confirmationCodeMaxBufferSize; + + // Updated by LPA Application + unsigned int reasonCodeNoCC; // used if no Confirmation Code +} LPA_REQUEST_CONFIRMATION_CODE; + +// @Since LPASDK API 1.6 +typedef struct +{ + unsigned char userCallBackType; // Set information(s) to display. Values masks defined in LPA_USER_CONSENT_TYPES enum. Each bit set an info to display. + char profileName[LPA_PROFILE_NAME_MAX_SIZE + 2]; // Profile name that may be displayed. String coded. +1 byte for EOS, +1 byte for security + bool downloadAllowed; // Confirm user accepted download (True) or refused (False) + unsigned int cancelSessionReason; // Values defined in LPA_CANCEL_SESSION_REASON enum. Value has no importance if downloadAllowed returned "true" +}LPA_REQUEST_USER_CONSENT_FOR_LOADING_PROFILE; + +// Since LPASDK API 1.8 +typedef struct +{ + bool profileMetadataAvailable; // Set to true if SM-DP server returned profile Metadata, else false + unsigned char iccid[LPA_PROFILE_ICCID_BUFFER_MAX_SIZE]; // ICCID. Raw bytes + size_t iccidSize; // ICCID size. Given as confirmation but shall be always equal to 0x0A + char profileName[LPA_PROFILE_NAME_MAX_SIZE + 2]; // Profile name. String coded. +1 byte for EOS, +1 byte for security + char serviceProviderName[LPA_PROFILE_SERVICE_PROVIDER_NAME_MAX_SIZE + 2]; // Service provider name. String coded. +1 byte for EOS, +1 byte for security + unsigned char profileIcon[LPA_PROFILE_ICON_MAX_SIZE]; // Icon. Raw bytes + size_t profileIconSize; // Icon size. If equal 0 the 2 other icon fields have no meaning + unsigned char profileIconType; // Icon type value + unsigned int profilePPR; // PPR value (ASN1 bitstring value). If equal 0 the PPR is not defined (Or empty or set to 0 but this shall not happen) +}LPA_EVENT_INCOMING_PROFILE_INFORMATION; + +// LPA Event mechanism +// eventType is dependant of LPA SDK API used. Mainly give equivalent of progression order +// Zero, some or all LPA Event functions can be registered + +// Function is used to manage a Progress Value +typedef void (*LPA_EVENT_PROGRESS_VALUE) (const void* ptrAppParameter, size_t eventType, size_t valueMin, size_t currentValue, size_t valueMax); + +// Function is used to communicate a text message to the application +typedef void(*LPA_EVENT_PROGRESS_TEXT) (const void* ptrAppParameter, size_t eventType, const char* ptrText); + +// Function is used to communicate a text message to the application +// Return true if CC entered correctly, otherwise return false and update reasonCodeNoCC field +typedef bool(*LPA_EVENT_REQUEST_CONFIRMATION_CODE) (const void* ptrAppParameter, LPA_REQUEST_CONFIRMATION_CODE* ptrRequestConfirmationCode); + +// Function is used to communicate some execution error information (subjectCode, reasonCode...) to the application +typedef void(*LPA_EVENT_EXECUTION_ERROR) (const void* ptrAppParameter, const LPA_EVENT_EXECUTION_ERROR_INFO* ptrEventExecutionErrorInfo); + +// Function is used to request a User Consent before loading a profile by Activation Code +// Since LPASDK API 1.6 +// Since LPASDK API 1.9, systematically called on each download +typedef bool(*LPA_EVENT_REQUEST_USER_CONSENT_FOR_LOADING_PROFILE) (const void* ptrAppParameter, LPA_REQUEST_USER_CONSENT_FOR_LOADING_PROFILE* ptrRequestUserConsentForLoadingProfile); + +// Function is used to display informations about profile currently downloaded +// Since LPASDK API 1.8 +typedef void(*LPA_EVENT_DISPLAY_INCOMING_PROFILE_INFORMATION) (const void* ptrAppParameter, size_t eventType, LPA_EVENT_INCOMING_PROFILE_INFORMATION* ptrIncomingProfileInformation); + +typedef struct +{ + // LPA SDK event parameter + void* _appParameter; // NULL if not used, otherwise specific application parameter (using it at first parameter value of event function + // In C++ application, could be instance of a class + + // LPA SDK Event callback functions - Must be initialized to NULL if not used. + LPA_EVENT_PROGRESS_VALUE _lpaEventProgressValue; + LPA_EVENT_PROGRESS_TEXT _lpaEventProgressText; + LPA_EVENT_EXECUTION_ERROR _lpaEventExecutionError; + + // When LPA SDK request a Confirmation Code during a DownloadProfile + LPA_EVENT_REQUEST_CONFIRMATION_CODE _lpaEventRequestConfirmationCode; + + // Event for managing User Consent before loading profile + LPA_EVENT_REQUEST_USER_CONSENT_FOR_LOADING_PROFILE _lpaEventRequestUserConsentForLoadingProfile; + + // Displaying of incoming profile information during download + LPA_EVENT_DISPLAY_INCOMING_PROFILE_INFORMATION _lpaEventDisplayIncomingProfileInformation; +}LPA_EventCallback; + +typedef struct +{ + // Profile Info Record + unsigned char rawData[LPA_PROFILE_INFO_BUFFER_MAX_SIZE]; + size_t rawDataSize; + + unsigned char iccid[LPA_PROFILE_ICCID_BUFFER_MAX_SIZE]; + size_t iccidSize; + + unsigned char profileState[LPA_PROFILE_STATE_MAX_SIZE]; + size_t profileStateSize; + + unsigned char serviceProviderName[LPA_PROFILE_SERVICE_PROVIDER_NAME_MAX_SIZE]; + size_t serviceProviderNameSize; + + unsigned char profileName[LPA_PROFILE_NAME_MAX_SIZE]; + size_t profileNameSize; + + unsigned char profileClass[LPA_PROFILE_CLASS_MAX_SIZE]; + size_t profileClassSize; + + unsigned char profileNickname[LPA_PROFILE_NICKNAME_MAX_SIZE]; + size_t profileNicknameSize; + + unsigned char profileIcon[LPA_PROFILE_ICON_MAX_SIZE]; + size_t profileIconSize; + + unsigned char profileIconType[LPA_PROFILE_ICON_TYPE_MAX_SIZE]; + size_t profileIconTypeSize; + + unsigned char profilePolicyRules[LPA_PROFILE_POLICY_RULES_MAX_SIZE]; + size_t profilePolicyRulesSize; +}LPA_PROFILE_INFO; + +typedef struct +{ + // Get Profile Info All + size_t countProfileInfo; // Number of profiles effectively retrieved and available in profileInfoList + size_t numberProfileInfoFound; // Number of profiles found in eUICC. Can be higher than value returned in "countProfileInfo" + size_t maxNumberProfileInfo; // Maximum number of profiles that can be stored in profileInfoList + unsigned char * profileInfoList; // Data area storing profiles information list. Must be allocated with (maxNumberProfileInfo * sizeof(LPA_PROFILE_INFO)) size. +}LPA_GET_PROFILES_INFO; + +typedef struct +{ + // EID + unsigned char EID_Data[LPA_GET_EID_BUFFER_SIZE]; + size_t EID_DataSize; +}LPA_GET_EID; + +typedef struct +{ + // EUICC Info + unsigned char EUICC_Info_Data[LPA_GET_EUICC_BUFFER_MAX_SIZE]; + size_t EUICC_Info_DataSize; +}LPA_GET_EUICC_INFO; + +typedef struct +{ + size_t countProfileInstalled; + size_t countProfileTotal; +} LPA_DOWNLOAD_PROFILE_RESULT; + +typedef struct +{ + size_t countNotificationDetected; // Before sending + size_t countNotificationSend; // really send +} LPA_SENDING_NOTIFICATION_RESULT; + +typedef enum +{ + LPA_NOTIFICATION_INSTALL = 0, + LPA_NOTIFICATION_ENABLE = 1, + LPA_NOTIFICATION_DISABLE = 2, + LPA_NOTIFICATION_DELETE = 3, + LPA_NOTIFICATION_UNKNOWN = 0xFF +} LPA_NOTIFICATION_EVENT; + + + + +typedef struct { + bool resultOK; + unsigned char cancelSessionResponse_RawData[LPA_CANCEL_SESSION_RESPONSE_BUFFER_SIZE]; + size_t cancelSessionResponse_RawDataSize; +}CANCEL_SESSION_RESPONSE; + +typedef struct +{ + // SMDP Address + char smdxAddr[LPA_SMDP_ADDRESS_SIZE]; + // activation code + char matchingId[LPA_MATCHING_ID_SIZE]; + // OID + char oid[LPA_OID_SIZE]; + // Confirmation Code Required Flag + char ccRequiredFlag[LPA_CC_REQUIRED_FLAG_SIZE]; +} ACTIVATION_CODE; + +typedef struct { + char eventId[LPA_MATCHING_ID_SIZE]; + char rspServerAddress[LPA_SMDP_ADDRESS_SIZE]; + unsigned char EID_RawData[LPA_GET_EID_BUFFER_SIZE]; + bool forwardingIndicator; +}LPA_EVENT_RECORD; + +typedef struct { + size_t countEvent; + LPA_EVENT_RECORD eventRecordList[LPA_MAX_EVENT_RECORD]; +}EVENT_RECORD_LIST; + +typedef struct { + char address_Data[LPA_SMDP_ADDRESS_SIZE]; + size_t address_DataSize; +}ADDRESS_DATA; + +typedef enum +{ + LPA_DELETE_NOTIFICATION_OK = 0, + LPA_DELETE_NOTIFICATION_NOTHING_TO_DELETE = 1, + LPA_DELETE_NOTIFICATION_UNDEFINED_ERROR = 127, + LPA_DELETE_NOTIFICATION_UNKNOWN = 0xFF +}LPA_DELETE_NOTIFICATION_STATUS; + +typedef struct +{ + uint16_t seqNumber; + LPA_NOTIFICATION_EVENT profileManagementOperation; + unsigned char notificationAddressRawData[LPA_MAX_NOTIFICATION_ADDRESS_RAW_DATA_SIZE]; + size_t notificationAddressRawDataSize; +}LPA_PROFILE_NOTIFICATION_METADATA; + + +typedef struct +{ + size_t countNotification; + LPA_PROFILE_NOTIFICATION_METADATA notificationMetadataList[LPA_MAX_PROFILE_NOTIFICATION_LIST_ELEMENT]; +} LPA_PROFILE_NOTIFICATION_LIST; + +typedef enum +{ + LPA_MEMORY_RESET_OK = 0, + LPA_MEMORY_RESET_NOTHING_TO_DELETE = 1, + LPA_MEMORY_RESET_CAT_BUSY = 5, + LPA_MEMORY_RESET_UNDEFINED_ERROR = 127, + LPA_MEMORY_RESET_UNKNOWN = 0xFF +}LPA_MEMORY_RESET_STATUS; + +// Cancel Session codes +typedef enum +{ + LPA_CANCEL_SESSION_END_USER_REJECTION = 0, + LPA_CANCEL_SESSION_POSTPONED = 1, + LPA_CANCEL_SESSION_TIME_OUT = 2, + LPA_CANCEL_SESSION_PPR_NOT_ALLOWED = 3, + LPA_CANCEL_SESSION_METADATA_MISMATCH = 4, + LPA_CANCEL_SESSION_LOAD_BPP_EXECUTION_ERROR = 5, + LPA_CANCEL_SESSION_UNDEFINED_REASON = 127 +}LPA_CANCEL_SESSION_REASON; + +static const unsigned int LPA_ALLOWED_CANCEL_SESSION_CODE_LIST[] = {0, 1, 2, 3, 4, 5, 127}; +#define LPA_ALLOWED_CANCEL_SESSION_CODE_LIST_SIZE 7 + +// User consent type for Callback. These are binary mask, they can be mixed together or checked individually. +typedef enum +{ + LPA_USR_CONSENT_NO_PPR = 0x00, + LPA_USR_CONSENT_PPR1 = 0x01, + LPA_USR_CONSENT_PPR2 = 0x02, + LPA_USR_CONSENT_PROFILE_WITH_PPR1_ENABLED_PRESENT = 0x04 +}LPA_USER_CONSENT_TYPES; + +// Management of retry for chained GetResponse issue with modems (0x6D00 issue, other SW may be discovered) through LPA_SDK__NUMBER_OF_RETRY_FOR_CHAINED_GET_RESPONSE +// If not defined or minus than 1 retry mechanism will be disabled +#ifndef LPA_SDK__NUMBER_OF_RETRY_FOR_CHAINED_GET_RESPONSE + #define LPA_RETRY_CHAINED_GET_RESPONSE_MGT false // Do not modify this value! + #define LPA_LOOP_NUMBER_FOR_CHAINED_GET_RESPONSE 1 // Do not modify this value ! Must be AT LEAST value "1" else commands will be NOT played. +#elif LPA_SDK__NUMBER_OF_RETRY_FOR_CHAINED_GET_RESPONSE < 1 + #define LPA_RETRY_CHAINED_GET_RESPONSE_MGT false // Do not modify this value! + #define LPA_LOOP_NUMBER_FOR_CHAINED_GET_RESPONSE 1 // Do not modify this value! Must be AT LEAST value "1" else commands will be NOT played. +#else + #define LPA_RETRY_CHAINED_GET_RESPONSE_MGT true // Do not modify this value! + #define LPA_LOOP_NUMBER_FOR_CHAINED_GET_RESPONSE LPA_SDK__NUMBER_OF_RETRY_FOR_CHAINED_GET_RESPONSE + 1 // Do not modify this expression ! Must be +1 to include initial command run to retries. +#endif // defined LPA_SDK__NUMBER_OF_RETRY_FOR_CHAINED_GET_RESPONSE + + +// Management of maximum size of data send through APDU. Need to limit size due to some modems not supporting 261 bytes (So 522 characters) in case 4 APDU +// If not defined default value of 0xFF will be used. +// If out of bounds will issue an error and stop compilation. If #error ignored by compiler used, value will be set to 0xFF to show that something is wrong. +// Boundaries for usable limits shall not be changed. +// Minimum size is fixed to 0x52 (82) due to eUICC limitations that does not support chained Store Data for some commands. 1 byte has been reserved for security. +// - Set Nickname: 0x51 (81) bytes minimum needed +// - Enable / Disable / Delete profile: 0x14 (20) bytes minimum needed +// - Any download command, Set default DP, Send Notification: Tested OK with 10 bytes size limitation +#ifndef LPA_SDK__MAX_SIZE_OF_DATA_IN_STORE_DATA_APDU + #define LPA_STORE_DATA_APDU_DATA_SIZE_MAX 0xFF +#elif LPA_SDK__MAX_SIZE_OF_DATA_IN_STORE_DATA_APDU < 0x52 // Lower limit given by Set Nickname + #define LPA_STORE_DATA_APDU_DATA_SIZE_MAX 0xFF + #error LPA_SDK__MAX_SIZE_OF_DATA_IN_STORE_DATA_APDU is out of authorized range ( decimal: [82,255 ] , hexa: [0x52,0xFF] ). +#elif LPA_SDK__MAX_SIZE_OF_DATA_IN_STORE_DATA_APDU > 0xFF // Upper limit, max possible in an APDU + #define LPA_STORE_DATA_APDU_DATA_SIZE_MAX 0xFF + #error LPA_SDK__MAX_SIZE_OF_DATA_IN_STORE_DATA_APDU is out of authorized range ( decimal: [82,255 ] , hexa: [0x52,0xFF] ). +#else + #define LPA_STORE_DATA_APDU_DATA_SIZE_MAX LPA_SDK__MAX_SIZE_OF_DATA_IN_STORE_DATA_APDU +#endif + +// List of tags allowed in deviceCapabilities object when extensibility is not supported +static const unsigned char LPA_LIST_ALLOWED_DEVICE_TAGS_NO_EXTENSIBILITY_SUPPORT[] = {0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87}; +#define LPA_LIST_ALLOWED_DEVICE_TAGS_NO_EXTENSIBILITY_SUPPORT_SIZE 8 + + +///////////////////////////////// +// API ERROR +///////////////////////////////// + +typedef enum { + LPA_NO_ERROR = 0, + + // 0x0001 - 0x0999 => Sifar custom error + SF_LPA_CUSTOM_ERROR_CMD_UNKNOWN = 0x0001, //Unknow command + SF_LPA_CUSTOM_ERROR_MEMORY, //Memory error + SF_LPA_CUSTOM_ERROR_USBNET, //Network error + SF_LPA_CUSTOM_ERROR_LPA_ERROR, //LPA initialization failed + SF_LPA_CUSTOM_ERROR_SIM_NOT_SUPPORTED, //SIM not supported + SF_LPA_CUSTOM_ERROR_SIM_EID, //SIM EID error + SF_LPA_CUSTOM_ERROR_HASH, //LPA command hash error + SF_LPA_CUSTOM_ERROR_ACTIVATION_CODE, //LPA sms command activation code error + SF_LPA_CUSTOM_ERROR_INVALID_ICCID, //LPA sms command invalid ICCID + SF_LPA_CUSTOM_ERROR_PROFILE_ENABLED, //The profile has been enabled + SF_LPA_CUSTOM_ERROR_NETWORK_REJECTED, //Network rejected + + + // 0x1001 - 0x1999 => Configuration error + LPA_NOT_INITIALIZED = 0x1001, + + // 0x2001 - 0x2FFF => Common error + LPA_ERROR_INVALID_PARAMETER = 0x2001, + LPA_ERROR_INSUFFICIENT_BUFFER, + LPA_ERROR_INVALID_SW, + LPA_ERROR_ISDR_NOT_SELECTED, + LPA_ERROR_ISDR_ALREADY_SELECTED, + LPA_ERROR_SE_MEDIA_NOT_INITIALIZED, + LPA_ERROR_SE_MEDIA_CONTEXT_NOT_ESTABLISHED, + LPA_ERROR_SE_MEDIA_READER_CONNECTION, + LPA_ERROR_SE_MEDIA_CONTEXT_NOT_RELEASED, + LPA_ERROR_SE_MEDIA_READER_NOT_DISCONNECTED, + LPA_ERROR_SE_MEDIA_UNABLE_TO_SELECT_ISDR, + LPA_ERROR_INVALID_GET_PROFILES_INFO_EXCHANGE, + LPA_ERROR_INVALID_GET_EID_EXCHANGE, + LPA_ERROR_INVALID_GET_EUICC_ADDRESS, + LPA_ERROR_INVALID_MEMORY_RESET_EXCHANGE, + LPA_ERROR_INVALID_SET_DEFAULT_SMDP_ADDRESS, + LPA_ERROR_INVALID_GET_SMDP_ADDRESS, + LPA_ERROR_INVALID_GET_SMDS_ADDRESS, + LPA_ERROR_PARAMETER_NOT_AUTHORIZED, + LPA_ERROR_UNKNOWN_PARAMETER, + LPA_ERROR_INVALID_PARAMETER_TYPE, + LPA_ERROR_INCORRECT_PARAMETER_TYPE, + LPA_ERROR_PARAMETER_INTERNAL_ERROR, + LPA_ERROR_UNABLE_TO_INIT_LOG, + LPA_ERROR_MISSING_CONFIG_FILE, // 23/12/2019 No longer used + LPA_ERROR_UNABLE_TO_LOAD_CONFIG_FILE, // 23/12/2019 No longer used + LPA_ERROR_CONFIG_FILE_MISSING_MANDATORY_KEY, // 06/06/2019 No longer used + LPA_ERROR_CONFIG_FILE_INCORRECT_KEY_VALUE, + LPA_ERROR_UNABLE_TO_INITIALIZE_LPA_MANAGER, + LPA_ERROR_UNABLE_TO_INITIALIZE_HTTP_MEDIA, + LPA_ERROR_EXTENDED_API_UNAVAILABLE, + LPA_ERROR_PROCESSING_ERROR, + + // Local Profile Management + LPA_ERROR_LOCAL_PROFILE_NOT_FOUND = 0x2101, + LPA_ERROR_LOCAL_PROFILE_INCORRECT_STATE, + LPA_ERROR_LOCAL_PROFILE_CAT_BUSY, + LPA_ERROR_LOCAL_PROFILE_INCORRECT_CARD_RESPONSE, + LPA_ERROR_LOCAL_PROFILE_UNKNOWN_ERROR, + LPA_ERROR_LOCAL_PROFILE_NOTHING_TO_DELETE, + LPA_ERROR_LOCAL_PROFILE_UNDEFINED_ERROR, + LPA_ERROR_LOCAL_PROFILE_UNABLE_TO_EXTRACT_DATA, + + LPA_ERROR_LOCAL_PROFILE_ICCID_OR_AID_NOT_FOUND, // enableResult => iccidOrAidNotFound + LPA_ERROR_LOCAL_PROFILE_NOT_IN_DISABLE_STATE, // enableResult => profileNotInDisabledState + LPA_ERROR_LOCAL_PROFILE_DISALLOWED_BY_POLICY, // enableResult => disallowedByPolicy + LPA_ERROR_LOCAL_PROFILE_WRONG_PROFILE_REENABLING, // enableResult => wrongProfileReenabling + LPA_ERROR_LOCAL_PROFILE_NOT_IN_ENABLE_STATE, // disableResult => profileNotInEnabledState + + LPA_ERROR_LOCAL_PROFILE_INVALID_DATA_EXCHANGE, + + // Notification management + LPA_ERROR_NOTIFICATION_INCORRECT_CARD_RESPONSE = 0x2201, + LPA_ERROR_NOTIFICATION_NOTHING_TO_DELETE, + LPA_ERROR_NOTIFICATION_UNDEFINED_ERROR, + LPA_ERROR_NOTIFICATION_UNKNOWN_ERROR, + LPA_ERROR_NOTIFICATION_INVALID_CARD_DATA, + + // Download Profile management + LPA_ERROR_DOWNLOAD_PROFILE_PARAMETER_ERROR = 0x2301, + LPA_ERROR_INVALID_GET_EUICC_INFO, + LPA_ERROR_INVALID_GET_UICC_CHALLENGE, + LPA_ERROR_INVALID_SERVER_ADDRESS, + LPA_ERROR_FAILED_INITIAL_AUTHENTICATION, + LPA_ERROR_FAILED_AUTHENTICATE_SERVER, + LPA_ERROR_FAILED_AUTHENTICATE_CLIENT, + LPA_ERROR_AUTHENTICATE_CLIENT_EXCHANGE, + LPA_ERROR_FAILED_PREPARE_DOWNLOAD, + LPA_ERROR_INVALID_ACTIVATION_CODE, + LPA_ERROR_INVALID_CTX_PARAM, + LPA_ERROR_INVALID_TRANSACTIONID, + LPA_ERROR_INVALID_AUTHENTICATE_SERVER_RESPONSE, + LPA_ERROR_INVALID_PREPARE_DOWNLOAD_RESPONSE, + LPA_ERROR_INVALID_MATCHINGID_OR_DEVICE_INFO_TLV, // 03/09/2020 Confirmed not used anymore + LPA_ERROR_INVALID_DEVICE_INFO_TLV, + LPA_ERROR_FAILED_GET_BOUND_PROFILE_PACKAGE, + LPA_ERROR_FAILED_LOAD_BPP, + LPA_ERROR_FAILED_INITIAL_SECURITY_CHANNEL, + LPA_ERROR_FAILED_CONFIGURE_ISDP, + LPA_ERROR_FAILED_STORE_META_DATA, + LPA_ERROR_FAILED_REPLACE_SESSION_KEY, + LPA_ERROR_FAILED_LOAD_PROFILE_ELEMENTS, + LPA_ERROR_FAILED_GET_DATA_FROM_ACTIVATION_CODE, + LPA_ERROR_INVALID_PIR_RESPONSE, + LPA_ERROR_GET_INTERNAL_SERVER_ERROR, + LPA_ERROR_CJSON_PARSE_FAILURE, + LPA_ERROR_FAILED_SEND_NOTIFICATION_OR_NOT_GET_STATUS_CODE, + LPA_ERROR_SERVER_COMMUNICATION_ISSUE, + LPA_ERROR_INVALID_EVENT_ID, + LPA_ERROR_INVALID_RSP_SERVER_ADDRESS, + LPA_ERROR_INVALID_EVENT_ENTRIES, + LPA_ERROR_NO_EVENT_RECORD_FOUND, // This error code is now obsolete since V1.6 + LPA_ERROR_CONFIRMATION_CODE_MISSING_OR_EMPTY, + LPA_ERROR_SERVER_RETURN_404_STATUS_CODE, + LPA_ERROR_SERVER_RETURN_500_STATUS_CODE, + LPA_ERROR_SE_MEDIA_UNABLE_TO_UNSELECT_ISDR, + LPA_ERROR_INVALID_SERVERSIGNED1, + LPA_ERROR_INVALID_SERVERSIGNATURE1, + LPA_ERROR_INVALID_EUICCCIPKIDTOBEUSED, + LPA_ERROR_INVALID_SERVERCERTIFICATE, + LPA_ERROR_INVALID_SERVER_RESPONSE, + LPA_ERROR_FAILED_CANCEL_SESSION, + LPA_ERROR_INVALID_PROFILE_METADATA, + LPA_ERROR_INVALID_GET_RAT, + LPA_ERROR_PPR_NOT_ALLOWED, + LPA_ERROR_DOWNLOAD_SESSION_CANCELED_BY_USER, + LPA_ERROR_OID_MISMATCH, + LPA_ERROR_INVALID_BPP_DATA, + LPA_ERROR_SERVER_RETURN_ERROR_STATUS, // This apply when server return an error, in JSON code for example + + // 0x8000 - 0x9999 => SE Media error + SE_MEDIA_ERROR_BROKEN_PIPE = 0x8000, + SE_MEDIA_E_CANCELLED, + SE_MEDIA_E_CANT_DISPOSE, + SE_MEDIA_E_CARD_UNSUPPORTED, + SE_MEDIA_E_DUPLICATE_READER, + SE_MEDIA_E_FILE_NOT_FOUND, + SE_MEDIA_E_INSUFFICIENT_BUFFER, + SE_MEDIA_E_INVALID_ATR, + SE_MEDIA_E_INVALID_HANDLE, + SE_MEDIA_E_INVALID_PARAMETER, + SE_MEDIA_E_INVALID_TARGET, + SE_MEDIA_E_INVALID_VALUE, + SE_MEDIA_E_NO_MEMORY, + SE_MEDIA_E_NO_READERS_AVAILABLE, + SE_MEDIA_E_NO_SMARTCARD, + SE_MEDIA_E_NOT_READY, + SE_MEDIA_E_PROTO_MISMATCH, + SE_MEDIA_E_READER_UNAVAILABLE, + SE_MEDIA_E_READER_UNSUPPORTED, + SE_MEDIA_E_SERVER_TOO_BUSY, + SE_MEDIA_E_SERVICE_STOPPED, + SE_MEDIA_E_SHARING_VIOLATION, + SE_MEDIA_E_SYSTEM_CANCELLED, + SE_MEDIA_E_TIMEOUT, + SE_MEDIA_E_UNEXPECTED, + SE_MEDIA_E_UNKNOWN_CARD, + SE_MEDIA_E_UNKNOWN_READER, + SE_MEDIA_W_REMOVED_CARD, + SE_MEDIA_W_RESET_CARD, + SE_MEDIA_W_UNSUPPORTED_CARD, + SE_MEDIA_E_CHAINING_GET_RESPONSE, // Can be issued only if LPA_SDK__DEACTIVATE_RETRY_FOR_CHAINED_GET_RESPONSE is not defined + +} LPA_API_ERROR; + +typedef enum +{ + LPA_PARAMETER_TYPE_BOOL, // bool + LPA_PARAMETER_TYPE_LONG, // long + LPA_PARAMETER_TYPE_STRING, // char* + + LPA_PARAMETER_TYPE_UNKNOWN = 1664, // Unknown type; Must be the latest on the enum +} LPA_PARAMETER_TYPE; + +// List of settable parameters. Memory contain initialization is done by lpaManagerGetFullParametersList() +// Size constants are fixed in lpasdk_api.h, shall fit all available parameters. +typedef struct +{ + size_t parametersCount; + char parametersList[LPA_MAX_PARAMETERS_LIST][LPA_MAX_PARAMETERS_LIST_ELEMENT_SIZE]; + LPA_PARAMETER_TYPE parametersTypeList[LPA_MAX_PARAMETERS_LIST]; +}LPA_PARAMETERS_LIST; + +typedef struct +{ + LPA_API_ERROR apiErrorCode; + char* ptrApiErrorDescription; +} LPA_API_ERROR_DESCRIPTION; + +#if defined (LPA_SDK__PLATFORM_WIN) || defined (LPA_SDK__PLATFORM_CYGWIN) +#define EXPORT_DLL __declspec(dllexport) +#else +// to add default visibility on LINUX +//#define EXPORT_DLL __attribute__ ((visibility ("default") )) +#define EXPORT_DLL + +#endif + +// LPA SDK API versionning +EXPORT_DLL const LPA_API_VERSION* lpaGetApiVersion(); + +// LPA SDK Initialization +EXPORT_DLL bool lpaInitialize(const char* ptrLpaFolder); +// @Since: API 1.6 +EXPORT_DLL bool lpaInitializeWithInputOutputFolder(const char* ptrLpaInputFolder, const char* ptrLpaOutputFolder); + +// Manage LPA SDK versionning +EXPORT_DLL bool lpaGetVersion(LPA_VERSION* ptrLpaVersion); + +// LPA SDK Uninitialization +EXPORT_DLL bool lpaUninitialize(); + +// LPA SDK IS initialized +EXPORT_DLL bool lpaIsInitialized(); + +// LPA SDK => GetErrorCode +EXPORT_DLL LPA_API_ERROR lpaGetErrorCode(); +EXPORT_DLL const char* lpaGetErrorCodeDescription(LPA_API_ERROR apiError); + +// LPA SDK Configuration +EXPORT_DLL bool lpaSetConfigParameter(const char* ptrParameterName, LPA_PARAMETER_TYPE parameterType, const void* ptrParameterValue); +EXPORT_DLL bool lpaGetConfigParameter(const char* ptrParameterName, LPA_PARAMETER_TYPE parameterType, void* ptrParameterValue, size_t parameterValueMaxSize); +EXPORT_DLL bool lpaIsConfigParameterExist(const char* ptrParameterName, LPA_PARAMETER_TYPE* ptrParameterType, bool* ptrIsExist); + +// LPA SDK Reader +EXPORT_DLL bool lpaGetReaderList(LPA_SE_MEDIA_READER_NAME_INFO * readerNameInfoList, size_t readerNameInfoMax, size_t* countReader); + + +EXPORT_DLL bool lpaGetProfilesInfo(LPA_GET_PROFILES_INFO*); +EXPORT_DLL bool lpaGetProfilesNumber(size_t*); +EXPORT_DLL bool lpaGetEID(LPA_GET_EID*); +EXPORT_DLL bool lpaGetEUICCInfo(LPA_GET_EUICC_INFO* ptrGetEUICCInfo); +EXPORT_DLL bool lpaMemoryReset(const unsigned char* memoryResetOptionParameter, const size_t memoryResetOptionSize); +EXPORT_DLL bool lpaSendPendingNotification(LPA_EventCallback* ptrLpaEventCallback, LPA_SENDING_NOTIFICATION_RESULT* ptrSendingNotificationResult); + +EXPORT_DLL bool lpaEnableProfileByIccid(const unsigned char* ptrProfileId, size_t profileIdSize); +EXPORT_DLL bool lpaDisableProfileByIccid(const unsigned char* ptrProfileId, size_t profileIdSize); +EXPORT_DLL bool lpaDeleteProfileByIccid(const unsigned char* ptrProfileId, size_t profileIdSize); + +EXPORT_DLL bool lpaSetDefaultSMDPAddress(const char* ptrSMDPAddr); +EXPORT_DLL bool lpaGetSMDPAddress(ADDRESS_DATA* ptrAddressData); +EXPORT_DLL bool lpaGetSMDSAddress(ADDRESS_DATA* ptrAddressData); + +EXPORT_DLL bool lpaDownloadProfile(const char * ptrActivationCodeStr, const LPA_EventCallback* ptrLpaEventCallback, LPA_DOWNLOAD_PROFILE_RESULT* ptrDownloadProfileResult); +EXPORT_DLL bool lpaDownloadProfileWithConfirmationCode(const char * ptrActivationCodeStr, const char * ptrConfirmationCodeStr, const LPA_EventCallback* ptrLpaEventCallback, LPA_DOWNLOAD_PROFILE_RESULT* ptrDownloadProfileResult); +EXPORT_DLL bool lpaDownloadProfileWithDefaultSMDPAddress(const LPA_EventCallback* ptrLpaEventCallback, LPA_DOWNLOAD_PROFILE_RESULT* ptrDownloadProfileResult); +EXPORT_DLL bool lpaDownloadProfileWithSMDSAddress( const LPA_EventCallback* ptrLpaEventCallback, LPA_DOWNLOAD_PROFILE_RESULT* ptrDownloadProfileResult); + +EXPORT_DLL bool lpaSetNicknameByIccid(const unsigned char* ptrProfileId, size_t profileIdSize, const unsigned char* ptrNickname, size_t nickNameSize); + +EXPORT_DLL void lpaSetLogLevel(unsigned char logLevel); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif // LPA_SDK__CORE_API_H diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/api/lpasdk_ex_api.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/api/lpasdk_ex_api.h new file mode 100755 index 000000000..609b2015b --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/api/lpasdk_ex_api.h @@ -0,0 +1,73 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + + +#ifndef LPA_SDK__CORE_EX_API_H +#define LPA_SDK__CORE_EX_API_H + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "lpasdk/api/lpasdk_api.h" +#include + + +typedef struct +{ + long countMemoryAllocCall; + long countMemoryFreeCall; + long currentMemoryBlockAllocated; + + long currentMemoryAllocated; + long totalMemoryAllocated; + + long maxMemoryAllocated; + long maxMemoryBlockAllocated; +}LPA_MEMORY_STATUS; + +// Extented API +///////////////////////////////////////////// + +EXPORT_DLL bool lpaExGetExtraVersion(char* ptrVersionBuffer, size_t versionBufferMaxSize); + +// Since LPASDK 1.5, moved on Extended API +EXPORT_DLL bool lpaExGetFullParametersList(LPA_PARAMETERS_LIST * ptrLpaParametersList); + +// LPA SDK SE Media Card Reset +EXPORT_DLL bool lpaExCardReset(); + +EXPORT_DLL bool lpaExGetProfileNotificationList(LPA_PROFILE_NOTIFICATION_LIST* ptrProfileNotificationList); +EXPORT_DLL bool lpaExClearProfileNotification(uint16_t sequenceNumber); + +EXPORT_DLL bool lpaExWriteMemoryStatusDumpToLog(); +EXPORT_DLL bool lpaExGetMemoryStatus(LPA_MEMORY_STATUS* prtMemoryStatus); +EXPORT_DLL bool lpaExCheckMemoryAllocated(); + +EXPORT_DLL LPA_API_ERROR_DESCRIPTION* lpaExGetListErrorCodeDescription(); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif // LPA_SDK__CORE_EX_API_H \ No newline at end of file diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/api/semedia/semedia.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/api/semedia/semedia.h new file mode 100755 index 000000000..6d742ca44 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/api/semedia/semedia.h @@ -0,0 +1,59 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#ifndef LPA_SDK__API_SE_MEDIA_H +#define LPA_SDK__API_SE_MEDIA_H + +// Increase size of Reader Name buffer in Debug mode to allow more space for test command when Windows test driver DLL is used +#if defined(_DEBUG) && defined(LPA_SDK__PLATFORM_WIN) && defined(LPA_SDK__SEMEDIA_DRIVER_EXTERNAL) +#define LPA_CFG_READER_NAME_MAX_SIZE 255 +#else +#define LPA_CFG_READER_NAME_MAX_SIZE 100 +#endif // _DEBUG & LPA_SDK__PLATFORM_WIN & LPA_SDK__SEMEDIA_DRIVER_EXTERNAL + +typedef struct +{ + char readerName[LPA_CFG_READER_NAME_MAX_SIZE]; +} LPA_SE_MEDIA_READER_NAME_INFO; + +typedef enum seMediaCardStatus +{ + SE_MEDIA_STATUS_SCARD_UNKNOWN = 0x0001, + SE_MEDIA_STATUS_SCARD_ABSENT = 0x0002, // There is no card in the reader. + SE_MEDIA_STATUS_SCARD_PRESENT = 0x0004, // There is a card in the reader, but it has not been moved into position for use. + SE_MEDIA_STATUS_SCARD_SWALLOWED = 0x0008, // There is a card in the reader in position for use.The card is not powered. + SE_MEDIA_STATUS_SCARD_POWERED = 0x0010, // Power is being provided to the card, but the reader driver is unaware of the mode of the card. + SE_MEDIA_STATUS_SCARD_NEGOTIABLE = 0x0020, // The card has been reset and is awaiting PTS negotiation. + SE_MEDIA_STATUS_SCARD_SPECIFIC = 0x0040, // The card has been reset and specific communication protocols have been established. + + + SE_MEDIA_STATUS_REMOVED_CARD = 0x80001, // The smart card has been removed(SCARD_W_REMOVED_CARD) + SE_MEDIA_RESET_CARD, // The smart card has been reset(SCARD_W_RESET_CARD) +}SE_MEDIA_CARD_STATUS; + +typedef enum seMediaDisconnectCardParam +{ + SE_MEDIA_DISCONNECT_LEAVE_CARD = 0, // Don't do anything special on close + SE_MEDIA_DISCONNECT_RESET_CARD, // Reset the card on close + SE_MEDIA_DISCONNECT_UNPOWER_CARD, // Power down the card on close +}SE_MEDIA_DISCONNECT_CARD_PARAM; + +#endif // LPA_SDK__API_SE_MEDIA_H \ No newline at end of file diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/bertlv_object.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/bertlv_object.h new file mode 100755 index 000000000..47d789230 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/bertlv_object.h @@ -0,0 +1,71 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#ifndef LPA_SDK__CORE_BERTLV_H +#define LPA_SDK__CORE_BERTLV_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "lpasdk/core/lpa_core.h" +#include "lpasdk/core/rawdata_object.h" + +typedef struct +{ + uint16_t tag; + uint32_t length; + unsigned char* value; +}BeerTLV, *PtrBeerTLV; + +//typedef struct BerTLVList BerTLVList; +typedef struct BerTLVList +{ + uint16_t index; + BeerTLV* berTLV; + struct BerTLVList* ptrNext; +} BerTLVList; + +UT_EXPORT_DLL BeerTLV* berTLV_create(uint16_t tag, uint32_t length, const unsigned char* ptrValue); +UT_EXPORT_DLL BeerTLV* berTLV_extractTagUInt8(uint8_t tag, const unsigned char* ptrRawData, uint32_t rawDataSize, bool* ptrIsTagFound); +UT_EXPORT_DLL BeerTLV* berTLV_extractTagUInt16(uint16_t tag, const unsigned char* ptrRawData, uint32_t rawDataSize, bool* ptrIsTagFound); +UT_EXPORT_DLL BerTLVList* berTLV_extractList(const unsigned char* ptrRawData, uint32_t rawDataSize, uint8_t* ptrCountTLVFound); + +UT_EXPORT_DLL RawDataObject* berTLV_buildRawDataObject(const BeerTLV* ptrBerTlv); +UT_EXPORT_DLL RawDataObject* berTLV_createAndBuildRawDataObject(uint16_t tag, uint32_t length, const unsigned char* ptrValue); + +UT_EXPORT_DLL bool berTLV_freeBerTLV(BeerTLV* ptrBerTLV); +UT_EXPORT_DLL bool berTLV_freeBerTLVList(BerTLVList* ptrBerTLVList); + + +// Some macro to help memory cleanup +#define ERASE_BERTLV(_ptr) if ((_ptr) != NULL) { berTLV_freeBerTLV( (_ptr) ); (_ptr) = NULL;} +#define ERASE_BERTLV_LIST(_ptr) if ((_ptr) != NULL) { berTLV_freeBerTLVList( (_ptr) ); (_ptr) = NULL;} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif // LPA_SDK__CORE_BERTLV_H \ No newline at end of file diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/httpmedia_base.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/httpmedia_base.h new file mode 100755 index 000000000..97acb2d63 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/httpmedia_base.h @@ -0,0 +1,51 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#ifndef HTTPMEDIA_BASE_H +#define HTTPMEDIA_BASE_H + +#include +#include "lpasdk/core/httpmedia_option_type.h" +#include "lpasdk/api/lpasdk_api.h" + + typedef struct THTTPMedia { + void* _childStruct; + bool (*httpMediaHttpExecuteInit) (const struct THTTPMedia*); + bool (*httpMediaPost) (const struct THTTPMedia*, const char* ptrCertificatePath, const char* ptrTargetURL, const char* ptrPostdata, long* ptrHttpCode); + + void (*httpMediaHttpExecuteCleanup) (const struct THTTPMedia*); + char* (*httpMediaGetBufferResponse) (const struct THTTPMedia*); + bool (*httpMediaSetBooleanOption) (const struct THTTPMedia*, HttpMediaOptionType optionType, bool enabled); + bool (*httpMediaGetBooleanOption) (const struct THTTPMedia*, HttpMediaOptionType optionType, bool* ptrEnabled); + + bool (*httpMediaSetLongOption) (const struct THTTPMedia*, HttpMediaOptionType optionType, long value); + bool (*httpMediaGetLongOption) (const struct THTTPMedia*, HttpMediaOptionType optionType, long* ptrValue); + + // EventErrorCallback support + bool(*httpMediaSetCallbackEventExecutionError) (const struct THTTPMedia*, LPA_EVENT_EXECUTION_ERROR lpaEventExecutionErrorCallback); + } THTTPMedia; + + THTTPMedia* New_HTTPMediaBase(); + + + +#endif /* HTTPMEDIA_BASE_H */ + diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/httpmedia_manager.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/httpmedia_manager.h new file mode 100755 index 000000000..51047d839 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/httpmedia_manager.h @@ -0,0 +1,66 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#ifndef HTTPMEDIAMANAGER_H +#define HTTPMEDIAMANAGER_H +#include + +#include "lpasdk/core/httpmedia_option_type.h" +#include "lpasdk/core/lpa_core.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +UT_EXPORT_DLL bool httpMediaManagerInitialize(); +UT_EXPORT_DLL bool httpMediaManagerIsInitialized(); +UT_EXPORT_DLL bool httpMediaManagerDelete(); + +bool httpMediaManagerConfigure(); + +bool httpMediaManagerSetBooleanOption(HttpMediaOptionType optionType, bool enabled); +bool httpMediaManagerGetBooleanOption(HttpMediaOptionType optionType, bool* ptrEnabled); + +bool httpMediaManagerSetLongOption(HttpMediaOptionType optionType, long value); +bool httpMediaManagerGetLongOption(HttpMediaOptionType optionType, long* ptrValue); + +bool httpMediaManagerSetCallbackEventExecutionError(LPA_EVENT_EXECUTION_ERROR lpaEventExecutionErrorCallback); + +char* httpMediaManagerPost(const char* ptrCertificatePath, const char* ptrTargetURL, const char* ptrPostdata, bool* ptrIsSuccess, long* ptrHttpCode); +char* httpMediaManagerHTTPExecutePost(bool* ptrIsSuccess, long* ptrHttpCode); + +bool httpMediaManagerSetTargetUrl( char* ptrTargetURL); +bool httpMediaManagerSetCertificatePath( char* ptrCertificatePath); + +bool httpMediaManagerSetPostData( char* ptrPostdata); +bool httpMediaManagerSetHeaders(); + +bool httpMediaManagerSetCallback(); +bool httpMediaManagerSetWriteData(); +bool httpMediaManagerHttpExecuteInit(); +bool httpMediaManagerHttpExecuteCleanup(); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* HTTPMEDIAMANAGER_H */ + diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/httpmedia_option_type.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/httpmedia_option_type.h new file mode 100755 index 000000000..b0c1533c3 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/httpmedia_option_type.h @@ -0,0 +1,35 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#ifndef LPA_SDK__HTTP_MEDIA_OPTION_TYPE_H +#define LPA_SDK__HTTP_MEDIA_OPTION_TYPE_H + +typedef enum +{ + // CURL option + HTTP_MEDIA_OPTION_TYPE_CURL_SSL_VERIFYPEER, + HTTP_MEDIA_OPTION_TYPE_CURL_SSL_VERIFYHOST, + HTTP_MEDIA_OPTION_TYPE_CURL_VERBOSE, + HTTP_MEDIA_OPTION_TYPE_CURL_CONNECT_TIMEOUT, + HTTP_MEDIA_OPTION_TYPE_CURL_TIMEOUT +} HttpMediaOptionType; + +#endif // LPA_SDK__HTTP_MEDIA_OPTION_TYPE_H \ No newline at end of file diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/isdr_applet_manager.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/isdr_applet_manager.h new file mode 100755 index 000000000..847360aa4 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/isdr_applet_manager.h @@ -0,0 +1,32 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#ifndef LPA_SDK__ISDR_APPLET_MANAGER_H +#define LPA_SDK__ISDR_APPLET_MANAGER_H + +#include + +bool selectISDRApplet(); +bool isISDRAppletSelected(); +bool unselectISDRApplet(); + +#endif // LPA_SDK__ISDR_APPLET_MANAGER_H + diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_config_file.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_config_file.h new file mode 100755 index 000000000..77127a71e --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_config_file.h @@ -0,0 +1,43 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#ifndef LPA_SDK__CONFIG_FILE_H +#define LPA_SDK__CONFIG_FILE_H + +#include +#include + +#include "lpasdk/core/lpa_core.h" +#include "lpasdk/api/lpasdk_api.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + #include "lpasdk/core/lpa_config_interface.h" + + bool lpaConfigFileLoad(const char* ptrConfigFileName, bool* ptrConfigFilePresent); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif // LPA_SDK__CONFIG_H diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_config_interface.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_config_interface.h new file mode 100755 index 000000000..8b7f50ddb --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_config_interface.h @@ -0,0 +1,48 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#ifndef LPA_SDK__CONFIG_INTERFACE_H +#define LPA_SDK__CONFIG_INTERFACE_H + +#include +#include +#include + +#include "lpasdk/core/lpa_log_interface.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + + typedef struct LPA_CONFIG_INTERFACE LPA_CONFIG_INTERFACE; + struct LPA_CONFIG_INTERFACE + { + bool (*setLog)(const LPA_LOG_INTERFACE* ptrLogInterface); + bool (*setConfigFileName)(const char*ptrConfigFileName); + bool (*load) (); +}; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif // LPA_SDK__CONFIG_INTERFACE_H diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_core.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_core.h new file mode 100755 index 000000000..0ba1d5b2b --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_core.h @@ -0,0 +1,64 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#ifndef LPA_SDK__LPA_CORE_H +#define LPA_SDK__LPA_CORE_H + +#define LPA_SDK__PLATFORM_RASPBIAN + +#ifdef LPA_SDK__PLATFORM_WIN +#include "lpasdk/core/win/lpa_core.h" +#endif // + +#ifdef LPA_SDK__PLATFORM_CYGWIN +#include "lpasdk/core/cygwin/lpa_core.h" +#endif //LPA_SDK__PLATFORM_CYGWIN + +#ifdef LPA_SDK__PLATFORM_RASPBIAN +#include "lpasdk/core/raspbian/lpa_core.h" +#endif //LPA_SDK__PLATFORM_RASPBIAN + +// Define generic MACRO & Constant +/////////////////////////////////////// + +#define LPA_RES_TRUE_STRING "true" +#define LPA_RES_FALSE_STRING "false" + +// Check that macro exits for specific platform +/////////////////////////////////////// + +#ifndef UT_EXPORT_DLL +#error "UT_EXPORT_DLL not defined for current platform" +//#define UT_EXPORT_DLL // Nothing specific for this platform + +#endif // UT_EXPORT_DLL + +#ifndef LPA_SDK_INLINE_FUNCTION +#error "LPA_SDK_INLINE_FUNCTION not defined for current platform" +//#define LPA_SDK_INLINE_FUNCTION // Nothing specific for this platform + +#endif // LPA_SDK_INLINE_FUNCTION + + + +#endif // LPA_SDK__LPA_CORE_H + + diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_log.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_log.h new file mode 100755 index 000000000..a2cac9f5e --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_log.h @@ -0,0 +1,65 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#ifndef LPA_SDK__CORE_LOG_H +#define LPA_SDK__CORE_LOG_H + +#include +#include + +#include "lpasdk/core/lpa_core.h" +#include "lpasdk/core/lpa_log_interface.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +UT_EXPORT_DLL bool lpaCoreLogInit(); +UT_EXPORT_DLL bool lpaCoreLogInitEx(LPA_LOG_INTERFACE* lpaLogInterface); +UT_EXPORT_DLL bool lpaCoreLogIsInitialized(); +UT_EXPORT_DLL bool lpaCoreLogRelease(); + +UT_EXPORT_DLL void lpaCoreLogOpen(const char* ptrFileName, const char* prtBackupFileName); +UT_EXPORT_DLL void lpaCoreLogFlush(); +UT_EXPORT_DLL void lpaCoreLogClose(); +UT_EXPORT_DLL bool lpaCoreLogIsOpen(); + +UT_EXPORT_DLL void lpaCoreActivateLogLimitation(bool activated); + +UT_EXPORT_DLL void lpaCoreSetLogLevel(LpaLogLevel logLevel); +UT_EXPORT_DLL LpaLogLevel lpaCoreGetLogLevel(void); + +UT_EXPORT_DLL bool lpaCoreSetLogMaxSize(long logMaxSize); +UT_EXPORT_DLL long lpaCoreGetLogMaxSize(); + +UT_EXPORT_DLL const char* lpaCoreGetLogLevelName(LpaLogLevel logLevel, bool* ptrIsFound); + +UT_EXPORT_DLL bool lpaCoreSetLogLevelString(const char* logLevelString); + +UT_EXPORT_DLL void lpaCoreLogAppend(LpaLogLevel logLevel, const char* ptrMessage, ...); +UT_EXPORT_DLL void lpaCoreLogAppendLongText(LpaLogLevel logLevel, const char* ptrHeaderMessage, const char* ptrLongTextToLog, const size_t LongTextToLogSize); +UT_EXPORT_DLL void lpaCoreLogAppendByteArray(LpaLogLevel logLevel, const char* ptrMessage, const char* ptrByteArrayName, unsigned char* ptrByteArray, size_t byteArraySize); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif // LPA_SDK__CORE_LOG_H \ No newline at end of file diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_log_interface.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_log_interface.h new file mode 100755 index 000000000..eea778d76 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_log_interface.h @@ -0,0 +1,71 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#ifndef LPA_SDK__CORE_LOG_INTERFACE_H +#define LPA_SDK__CORE_LOG_INTERFACE_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef enum +{ + SDK_LOG_LEVEL_UNKNOWN, + + SDK_LOG_LEVEL_VERBOSE, + SDK_LOG_LEVEL_DEBUG, + SDK_LOG_LEVEL_INFO, + SDK_LOG_LEVEL_WARNING, + SDK_LOG_LEVEL_ERROR, + SDK_LOG_LEVEL_SYSTEM // Use only internally +} LpaLogLevel; + +typedef struct LPA_LOG_INTERFACE LPA_LOG_INTERFACE; +struct LPA_LOG_INTERFACE +{ + void (*openLog) (const char* ptrFileName, const char* prtBackupFileName); + void (*flushLog)(); + bool (*isLogOpened)(); + void(*closeLog)(); + + void (*activateLogLimitation) (bool activated); + + void (*setLogLevel) (LpaLogLevel logLevel); + LpaLogLevel (*getLogLevel)(void); + + bool (*setLogMaxSize)(long logMaxSize); + long (*getLogMaxSize)(); + + void (*appendToLog)(LpaLogLevel logLevel, const char* ptrMessage, va_list argptr); + void (*appendLongTextToLog)(LpaLogLevel logLevel, const char* ptrHeaderMessage, const char* ptrLongTextToLog, const size_t LongTextToLogSize); + void (*appendByteArrayToLog)(LpaLogLevel logLevel, const char* ptrMessage, const char* ptrByteArrayName, unsigned char* ptrByteArray, size_t byteArraySize); +}; + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif // LPA_SDK__CORE_LOG_INTERFACE_H diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_manager.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_manager.h new file mode 100755 index 000000000..e68b88615 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_manager.h @@ -0,0 +1,106 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#ifndef LPA_SDK__LPA_MANAGER_H +#define LPA_SDK__LPA_MANAGER_H + +#include "lpasdk/api/lpasdk_api.h" +#include "lpasdk/lpasdk_internal_api.h" + +#ifdef LPA_SDK__USING_EX_API +//#include "lpasdk/lpasdk_ex_api.h" +#endif // LPA_SDK__USING_EX_API + +#include "lpasdk/core/lpa_core.h" + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define MAX_LPA_MANAGER_APDU_BUFFER_SIZE 8192 + +bool lpaManagerInitialize(const char* ptrLpaFolder); +bool lpaManagerInitializeSEMedia(); +bool lpaManagerInitializeHttpMedia(); + +bool lpaManagerSetConfigParameter(const char* ptrParameterName, LPA_PARAMETER_TYPE parameterType, const void* ptrParameterValue, bool internalCall); +bool lpaManagerGetConfigParameter(const char* ptrParameterName, LPA_PARAMETER_TYPE parameterType, void* ptrParameterValue, size_t parameterValueMaxSize); +bool lpaManagerIsConfigParameterExist(const char* ptrParameterName, LPA_PARAMETER_TYPE* ptrParameterType, bool* ptrIsExist, bool* ptrAccessGranted); +bool lpaManagerGetFullParametersList(LPA_PARAMETERS_LIST * ptrLpaParametersList); + +// SEMedia manager redirections through lpa_manager.c +bool lpaManagerSEMediaManagerIsInitialized(); +bool lpaManagerSEMediaManagerUninitialize(); +// Reconnect SEMedia +bool lpaManagerSEMediaCardReset(); + +// httpMedia manager redirections through lpa_manager.c +bool lpaManagerHttpMediaManagerIsInitialized(); +bool lpaManagerHttpMediaManagerDelete(); + + +// Exchange with ISDR applet +bool lpaManagerGetReaderList(LPA_SE_MEDIA_READER_NAME_INFO * ptrReaderNameInfoList, size_t readerNameInfoMax, size_t* ptrCountReader); +bool lpaManagerGetProfilesInfo(LPA_GET_PROFILES_INFO* ); +bool lpaManagerGetProfilesNumber(size_t* ); +bool lpaManagerGetEID(LPA_GET_EID* ); +bool lpaManagerGetEUICCInfo2(LPA_GET_EUICC_INFO* ptrGetEUICCInfo); +bool lpaManagerMemoryReset(const unsigned char* memoryResetOptionParameter, const size_t memoryResetOptionSize); +bool lpaManagerSendPendingNotification(LPA_EventCallback* ptrLpaEventCallback, LPA_SENDING_NOTIFICATION_RESULT* ptrSendingNotificationResult); + + +// Manage Enable/Disable/Delete Profile +bool lpaManagerEnableProfileByIccid(const unsigned char* ptrProfileId, size_t profileIdSize); +bool lpaManagerDisableProfileByIccid(const unsigned char* ptrProfileId, size_t profileIdSize); +bool lpaManagerDeleteProfileByIccid(const unsigned char* ptrProfileId, size_t profileIdSize); + +// Manage notification list +bool lpaManagerGetProfileNotificationList(LPA_PROFILE_NOTIFICATION_LIST* ptrProfileNotificationList); +bool lpaManagerClearProfileNotification(uint16_t sequenceNumber); + +bool lpaManagerSetDefaultSMDPAddress(const char* ptrSMDPAddr); +bool lpaManagerGetSMDPAddress(ADDRESS_DATA* ptrAddressData); +bool lpaManagerGetSMDSAddress(ADDRESS_DATA* ptrAddressData); + +bool lpaManagerDownloadProfile(const char * ptrActivationCodeStr, const LPA_EventCallback* ptrLpaEventCallback, LPA_DOWNLOAD_PROFILE_RESULT* ptrDownloadProfileResult); +bool lpaManagerDownloadProfileWithConfirmationCode(const char * ptrActivationCodeStr, const char * ptrConfirmationCodeStr, const LPA_EventCallback* ptrLpaEventCallback, LPA_DOWNLOAD_PROFILE_RESULT* ptrDownloadProfileResult); +bool lpaManagerDownloadProfileWithDefaultSMDPAddress(const LPA_EventCallback* ptrLpaEventCallback, LPA_DOWNLOAD_PROFILE_RESULT* ptrDownloadProfileResult); +bool lpaManagerDownloadProfileWithSMDSAddress( const LPA_EventCallback* ptrLpaEventCallback, LPA_DOWNLOAD_PROFILE_RESULT* ptrDownloadProfileResult); + +bool lpaManagerGetProfileNotificationList(LPA_PROFILE_NOTIFICATION_LIST* ptrProfileNotificationList); +bool lpaManagerClearProfileNotification(uint16_t sequenceNumber); + +// Nickname management +bool lpaManagerSetNickname(const unsigned char* ptrProfileId, size_t profileIdSize, const unsigned char* ptrNickname, size_t nickNameSize); + +bool lpaManagerConnectReaderAndSelectISDR(); +bool lpaManagerUnselectISDRAndDisconnectReader(); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif // LPA_SDK__LPA_MANAGER_H \ No newline at end of file diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_manager_api.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_manager_api.h new file mode 100755 index 000000000..e666d45a4 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_manager_api.h @@ -0,0 +1,123 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#ifndef LPA_SDK__LPA_MANAGER_API_H +#define LPA_SDK__LPA_MANAGER_API_H + +#include "lpasdk/api/lpasdk_api.h" +#include "lpasdk/lpasdk_internal_api.h" + +#ifdef LPA_SDK__USING_EX_API +#include "lpasdk/api/lpasdk_ex_api.h" +#endif // LPA_SDK__USING_EX_API + +#include "lpasdk/core/lpa_core.h" + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +// PARAMETER KEY NAMES +// Parameter list itself is defined in lpa_manager.c + +#define LPA_SDK_CONFIG_PARAM_READER_NAME "readerName" +#define LPA_SDK_CONFIG_PARAM_DEVICE_INFO_TLV "deviceInfoTlv" +#define LPA_SDK_CONFIG_PARAM_CERT_PATH "certPath" + + +#define LPA_SDK_CONFIG_PARAM_SEND_PIR_DURING_DOWNLOAD_PROFILE "sendPIRDuringDownloadProfile" +#define LPA_SDK_CONFIG_PARAM_USING_HTTPS_REQUEST "usingHTTPSRequest" +#define LPA_SDK_CONFIG_PARAM_ACTIVATE_CURL_DEBUG_MODE "activateCURLDebugMode" +#define LPA_SDK_CONFIG_PARAM_ADD_LE_TO_APDU_CASE_4 "addLeToApduCase4" +#define LPA_SDK_CONFIG_PARAM_LOG_LEVEL "logLevel" +#define LPA_SDK_CONFIG_PARAM_LOG_MAX_SIZE "logMaxSize" +#define LPA_SDK_CONFIG_PARAM_PROFILE_REFRESH_FLAG "profileRefreshFlag" + +#define LPA_SDK_CONFIG_PARAM_CURL_SSL_SSL_VERIFYPEER "CURL_SSL_VERIFYPEER" +#define LPA_SDK_CONFIG_PARAM_CURL_SSL_SSL_VERIFYHOST "CURL_SSL_VERIFYHOST" + +#define LPA_SDK_CONFIG_PARAM_CURL_CONNECT_TIMEOUT "CURL_CONNECT_TIMEOUT" +#define LPA_SDK_CONFIG_PARAM_CURL_TIMEOUT "CURL_TIMEOUT" + +#define LPA_SDK_CONFIG_PARAM_DEVICE_CAPABILITIES_FILTERING "deviceCapabilitiesFiltering" + +#define LPA_SDK_CONFIG_PARAM_DEVICE_SMDS_ADDRESS "deviceSMDSAddress" +#define LPA_SDK_CONFIG_PARAM_DEVICE_DEFAULT_SMDP_ADDRESS "deviceDefaultSMDPAddress" + +#define LPA_SDK_CONFIG_PARAM_BYPASS_DEFAULT_USER_CONSENT_WITH_NO_PPR "bypassDefaultUserConsentWithNoPPR" +#define LPA_SDK_CONFIG_PARAM_SUPPORT_DOWLOAD_PROFILES_WITH_PPR "supportDownloadOfProfilesWithPPR" + +UT_EXPORT_DLL bool lpaManagerApiInitialize(const char* ptrLpaFolder); + +UT_EXPORT_DLL bool lpaManagerApiSetConfigParameter(const char* ptrParameterName, LPA_PARAMETER_TYPE parameterType, const void* ptrParameterValue, bool internalCall); +UT_EXPORT_DLL bool lpaManagerApiGetConfigParameter(const char* ptrParameterName, LPA_PARAMETER_TYPE parameterType, void* ptrParameterValue, size_t parameterValueMaxSize); +UT_EXPORT_DLL bool lpaManagerApiIsConfigParameterExist(const char* ptrParameterName, LPA_PARAMETER_TYPE* ptrParameterType, bool* ptrIsExist); +UT_EXPORT_DLL bool lpaManagerApiGetFullParametersList(LPA_PARAMETERS_LIST * ptrLpaParametersList); + +// Reconnect SEMedia +UT_EXPORT_DLL bool lpaManagerApiSEMediaCardReset(); + + +// Exchange with ISDR applet +UT_EXPORT_DLL bool lpaManagerApiGetReaderList(LPA_SE_MEDIA_READER_NAME_INFO * ptrReaderNameInfoList, size_t readerNameInfoMax, size_t* ptrCountReader); +UT_EXPORT_DLL bool lpaManagerApiGetProfilesInfo(LPA_GET_PROFILES_INFO*); +UT_EXPORT_DLL bool lpaManagerApiGetProfilesNumber(size_t*); +UT_EXPORT_DLL bool lpaManagerApiGetEID(LPA_GET_EID*); +UT_EXPORT_DLL bool lpaManagerApiGetEUICCInfo(LPA_GET_EUICC_INFO* ptrGetEUICCInfo); +UT_EXPORT_DLL bool lpaManagerApiMemoryReset(const unsigned char* memoryResetOptionParameter, const size_t memoryResetOptionSize); +UT_EXPORT_DLL bool lpaManagerApiSendPendingNotification(LPA_EventCallback* ptrLpaEventCallback, LPA_SENDING_NOTIFICATION_RESULT* ptrSendingNotificationResult); + + +// Manage Enable/Disable/Delete Profile +UT_EXPORT_DLL bool lpaManagerApiEnableProfileByIccid(const unsigned char* ptrProfileId, size_t profileIdSize); +UT_EXPORT_DLL bool lpaManagerApiDisableProfileByIccid(const unsigned char* ptrProfileId, size_t profileIdSize); +UT_EXPORT_DLL bool lpaManagerApiDeleteProfileByIccid(const unsigned char* ptrProfileId, size_t profileIdSize); + +// Manage notification list +UT_EXPORT_DLL bool lpaManagerApiGetProfileNotificationList(LPA_PROFILE_NOTIFICATION_LIST* ptrProfileNotificationList); +UT_EXPORT_DLL bool lpaManagerApiClearProfileNotification(uint16_t sequenceNumber); + +UT_EXPORT_DLL bool lpaManagerApiSetDefaultSMDPAddress(const char* ptrSMDPAddr); +UT_EXPORT_DLL bool lpaManagerApiGetSMDPAddress(ADDRESS_DATA* ptrAddressData); +UT_EXPORT_DLL bool lpaManagerApiGetSMDSAddress(ADDRESS_DATA* ptrAddressData); + +UT_EXPORT_DLL bool lpaManagerApiDownloadProfile(const char * ptrActivationCodeStr, const LPA_EventCallback* ptrLpaEventCallback, LPA_DOWNLOAD_PROFILE_RESULT* ptrDownloadProfileResult); +UT_EXPORT_DLL bool lpaManagerApiDownloadProfileWithConfirmationCode(const char * ptrActivationCodeStr, const char * ptrConfirmationCodeStr, const LPA_EventCallback* ptrLpaEventCallback, LPA_DOWNLOAD_PROFILE_RESULT* ptrDownloadProfileResult); +UT_EXPORT_DLL bool lpaManagerApiDownloadProfileWithDefaultSMDPAddress(const LPA_EventCallback* ptrLpaEventCallback, LPA_DOWNLOAD_PROFILE_RESULT* ptrDownloadProfileResult); +UT_EXPORT_DLL bool lpaManagerApiDownloadProfileWithSMDSAddress(const LPA_EventCallback* ptrLpaEventCallback, LPA_DOWNLOAD_PROFILE_RESULT* ptrDownloadProfileResult); + +UT_EXPORT_DLL bool lpaManagerApiSetNickname(const unsigned char* ptrProfileId, size_t profileIdSize, const unsigned char* ptrNickname, size_t nickNameSize); + +UT_EXPORT_DLL bool lpaManagerApiSEMediaManagerIsInitialized(); +UT_EXPORT_DLL bool lpaManagerApiSEMediaManagerUninitialize(); +UT_EXPORT_DLL bool lpaManagerApiHttpMediaManagerIsInitialized(); +UT_EXPORT_DLL bool lpaManagerApiHttpMediaManagerDelete(); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif // LPA_SDK__LPA_MANAGER_API_H \ No newline at end of file diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_manager_es10b.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_manager_es10b.h new file mode 100755 index 000000000..69d4d3036 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_manager_es10b.h @@ -0,0 +1,50 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#ifndef LPA_SDK__LPA_MANAGER_ES10B_H +#define LPA_SDK__LPA_MANAGER_ES10B_H + +#include +#include +#include + +#include "lpasdk/api/lpasdk_api.h" +#include "lpasdk/lpasdk_internal_api.h" + +#include "lpasdk/core/rawdata_object.h" + +typedef struct +{ + RawDataObject* ptrRawDataObjectTLV_transactionId; + RawDataObject* ptrRawDataObjectTLV_ccRequiredFlag; + RawDataObject* ptrRawDataObjectTLV_bppEuiccOtpk; +} SMDP_SIGNED2_DATA; + + +bool lpaManagerES10b_PrepareDownload(ptr_serverData, const LPA_EventCallback* ptrLpaEventCallback, const char * ptrStringHashCC, PREPARE_DOWNLOAD_RESPONSE*); +bool lpaManagerES10b_LoadBoundProfilePackage(ptr_serverData p_serverData, PROFILE_INSTALLATION_RESULT *pir, bool * cancelForBPPerrors); +bool lpaManagerES10b_GetEuiccChallenge(LPA_GET_EUICC* ptrGetEUICC); +bool lpaManagerES10b_GetEuiccInfo(const unsigned short eUICCinfoTag, LPA_GET_EUICC* ptrGetEUICC); +bool lpaManagerES10b_AuthenticateServer(ptr_serverData p_serverData, const LPA_EventCallback* ptrLpaEventCallback, RawDataObject * ptrCtxParam, AUTHENTICATE_SERVER_RESPONSE* ptrAnthServerResp); +bool lpaManagerES10b_CancelSession(const char * transactionID, const unsigned int p_reasonCode, CANCEL_SESSION_RESPONSE * ptrCancelSessionResp); +bool lpaManagerES10b_GetRAT(RawDataObject ** ptrGetRAT); + +#endif // LPA_SDK__LPA_MANAGER_ES10C_H diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_manager_es10c.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_manager_es10c.h new file mode 100755 index 000000000..1d977710c --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_manager_es10c.h @@ -0,0 +1,44 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#ifndef LPA_SDK__LPA_MANAGER_ES10C_H +#define LPA_SDK__LPA_MANAGER_ES10C_H + +#include "lpasdk/api/lpasdk_api.h" + +#include +#include +#include + +void lpaManagerES10c_SetRefreshFlag(bool refreshFlagActivated); +bool lpaManagerES10c_IsRefreshFlag(); + +bool lpaManagerES10c_GetProfilesInfo(LPA_GET_PROFILES_INFO* ptrLpaGetProfilesInfo, bool * continueRetry, bool requestForPPRmanagement); +bool lpaManagerES10c_GetProfilesNumber(size_t*); +bool lpaManagerES10c_EnableProfileByIccid(const unsigned char* ptrProfileId, size_t profileIdSize); +bool lpaManagerES10c_DisableProfileByIccid(const unsigned char* ptrProfileId, size_t profileIdSize); +bool lpaManagerES10c_DeleteProfileByIccid(const unsigned char* ptrProfileId, size_t profileIdSize); +bool lpaManagerES10c_MemoryReset(const unsigned char* memoryResetOptionParameter, const size_t memoryResetOptionSize); +bool lpaManagerES10c_GetEID(LPA_GET_EID*); +bool lpaManagerES10c_SetNickname(const unsigned char* ptrProfileId, size_t profileIdSize, const unsigned char* ptrNickname, size_t nickNameSize); + +#endif // LPA_SDK__LPA_MANAGER_ES10C_H + diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_manager_es9plus.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_manager_es9plus.h new file mode 100755 index 000000000..f7e2b3f0e --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_manager_es9plus.h @@ -0,0 +1,50 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#ifndef LPA_SDK__LPA_MANAGER_ES9_PLUS_H +#define LPA_SDK__LPA_MANAGER_ES9_PLUS_H + +#include +#include +#include + +#include "lpasdk/api/lpasdk_api.h" +#include "lpasdk/lpasdk_internal_api.h" + +bool lpaManagerES9Plus_InitiateAuthentication(ptr_serverData p_serverData, const LPA_EventCallback* ptrLpaEventCallback, const char * ptrEuiccChallenge, const char * ptrEuiccInfo1, const char* ptrSmdpAddress); +bool lpaManagerES9Plus_GetBoundProfilePackage(ptr_serverData p_serverData, const LPA_EventCallback* ptrLpaEventCallback, const char* ptrSmdpAddress, const unsigned char* ptrPrepareDownloadResponse, bool * cancelForBPPerrors); +bool lpaManagerES9Plus_AuthenticateClient(ptr_serverData p_serverData, const LPA_EventCallback* ptrLpaEventCallback, const char* ptrSmdpAddress, const unsigned char* ptrAuthenticateServerResponse); + +bool lpaManagerES9Plus_HandleNotification(const char* ptrSmdpAddr, size_t smdpAddrSize, const unsigned char* ptrPendingNotification, const LPA_EventCallback* ptrLpaEventCallback, bool * ptrNormalAcknowledge); +bool lpaManagerES9Plus_EventRetrieval(const char* ptrTransactionId, const LPA_EventCallback* ptrLpaEventCallback, const char* ptrSmdsAddress, const unsigned char* ptrAuthenticateServerResponse, EVENT_RECORD_LIST* ptrEventRecordList); + +bool lpaManagerES9plus_CancelSession(const char * transactionID, CANCEL_SESSION_RESPONSE * ptrCancelSessionResp, const char* ptrSmdpAddress, const LPA_EventCallback* ptrLpaEventCallback); + +// From lpa_manager.c +char* lpaManagerES9Plus_ExecutePost(const char * ptrTargetURL, const char * ptrJsonRequest, bool* ptrIsSuccess, long *ptrHttpCode, const LPA_EventCallback* ptrLpaEventCallback); + +// certPath support +void lpaManagerES9Plus_Init(const char * defaultCertPath); +bool lpaManagerES9Plus_setCertPath(const char* ptrCertPath); +size_t lpaManagerES9Plus_getCertPathSize(); +bool lpaManagerES9Plus_getCertPath(char*ptrCertPath, size_t ptrCertPathMaxSize); + +#endif // LPA_SDK__LPA_MANAGER_ES9_PLUS_H \ No newline at end of file diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_manager_helper.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_manager_helper.h new file mode 100755 index 000000000..acfc46fe3 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_manager_helper.h @@ -0,0 +1,43 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#ifndef LPA_SDK__LPA_MANAGER_HELPER_H +#define LPA_SDK__LPA_MANAGER_HELPER_H + +#include +#include +#include + +#include "lpasdk/core/bertlv_object.h" + +void lpaManagerHelperSetLeToAddApduCase4(bool enable); +bool lpaManagerHelperIsLeAddedToApduCase4(); + +bool buildAndSendStoreDataCase3WithoutResponseData(const RawDataObject* ptrRawDataObject, uint16_t *ptrSW); +bool buildAndSendStoreDataCase3(const RawDataObject* ptrRawDataObject, uint16_t *ptrSW, unsigned char *ptrResponseApduData, size_t responseApduDataMaxSize, size_t *ptrResponseApduDataSize); + +bool buildAndSendStoreDataCase4WithoutResponseData(const RawDataObject* ptrRawDataObject, uint16_t *ptrSW); +bool buildAndSendStoreDataCase4(const RawDataObject* ptrRawDataObject, uint16_t *ptrSW, unsigned char *ptrResponseApduData, size_t responseApduDataMaxSize, size_t *ptrResponseApduDataSize); +bool buildAndSendApduCase4(const RawDataObject* ptrRawDataObject, uint16_t *ptrSW, unsigned char *ptrResponseApduData, size_t responseApduDataMaxSize, size_t *ptrResponseApduDataSize); +bool buildAndSendApduCase4Ex(const unsigned char* ptrApduC, uint16_t apduCSize, uint16_t *ptrSW, unsigned char *ptrResponseApduData, size_t responseApduDataMaxSize, size_t *ptrResponseApduDataSize); + +#endif // LPA_SDK__LPA_MANAGER_HELPER_H + diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_memory.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_memory.h new file mode 100755 index 000000000..8dee01e50 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/lpa_memory.h @@ -0,0 +1,103 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#ifndef LPA_SDK__CORE_MEMORY_H +#define LPA_SDK__CORE_MEMORY_H + +#include +#include + +#include +#include + +#ifdef LPA_SDK__USING_EX_API +#include "lpasdk/api/lpasdk_ex_api.h" +#endif // LPA_SDK__USING_EX_API + +#include "lpasdk/core/lpa_core.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +UT_EXPORT_DLL void lpaCoreMemoryInitialize(); + +#ifdef LPA_SDK__MEMORY + +#define LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_COUNTER_EQ 1 +#define LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_COUNTER_GT 2 +#define LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_COUNTER_GE 3 + +#define LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_SIZE_REQUESTED_EQ 4 +#define LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_SIZE_REQUESTED_GT 5 +#define LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_SIZE_REQUESTED_GE 6 + +UT_EXPORT_DLL void lpaCoreMemoryResetParamGenerateErr(); +UT_EXPORT_DLL bool lpaCoreMemorySetParamGenerateErr(uint8_t param, long value); +UT_EXPORT_DLL bool lpaCoreMemoryGetParamGenerateErr(uint8_t param, long* ptrValue); + + +#ifndef LPA_SDK__MEMORY_MONITORING + +// Allocate memory +void* lpaCoreMemoryAlloc(size_t size); +void* lpaCoreMemoryCalloc(size_t count, size_t size); +void* lpaCoreMemoryRealloc(void* ptrMemoryBlock, size_t newSize); + +// free memory +void lpaCoreMemoryFree(void* ptrMemoryBlock); + +#else // LPA_SDK__MEMORY_MONITORING + +UT_EXPORT_DLL void* lpaCoreMemoryMonitorAlloc(char* ptrFilename, int line, size_t size); +UT_EXPORT_DLL void* lpaCoreMemoryMonitorCalloc(char* ptrFilename, int line, size_t count, size_t size); +UT_EXPORT_DLL void* lpaCoreMemoryMonitorRealloc(char* ptrFilename, int line, void* ptrMemoryBlock, size_t newSize); +UT_EXPORT_DLL void lpaCoreMemoryMonitorFree(char* ptrFilename, int line, void* mem); + +// Wrapper to monitor memory API call +#define lpaCoreMemoryAlloc(size) lpaCoreMemoryMonitorAlloc(__FILE__, __LINE__, size) +#define lpaCoreMemoryCalloc(count, size) lpaCoreMemoryMonitorCalloc(__FILE__, __LINE__,count,size) +#define lpaCoreMemoryRealloc(ptrMemoryBlock, newSize) lpaCoreMemoryMonitorRealloc(__FILE__, __LINE__,ptrMemoryBlock,newSize) +#define lpaCoreMemoryFree(mem) lpaCoreMemoryMonitorFree(__FILE__, __LINE__, mem) + +#endif // LPA_SDK__MEMORY_MONITORING +#else // LPA_SDK__MEMORY + + //Not using owner memory mecanism +#define lpaCoreMemoryAlloc(size) malloc(size) +#define lpaCoreMemoryCalloc(count, size) calloc(count,size) +#define lpaCoreMemoryRealloc(ptrMemoryBlock, newSize) realloc(ptrMemoryBlock,newSize) +#define lpaCoreMemoryFree(mem) free(mem) + +#endif // LPA_SDK__MEMORY + +#ifdef LPA_SDK__USING_EX_API +UT_EXPORT_DLL bool lpaCoreGetMemoryStatus(LPA_MEMORY_STATUS* prtMemoryStatus); +#endif // LPA_SDK__USING_EX_API + +void lpaCoreMemoryDumpStatusIntoLog(); +void lpaCoreMemoryCheckMemoryAllocated(); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif // LPA_SDK__CORE_MEMORY_H \ No newline at end of file diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/raspbian/lpa_core.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/raspbian/lpa_core.h new file mode 100755 index 000000000..394e1ee57 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/raspbian/lpa_core.h @@ -0,0 +1,38 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#ifndef LPA_SDK__CORE_RASPBIAN__LPA_CORE_H +#define LPA_SDK__CORE_RASPBIAN__LPA_CORE_H + +#ifndef LPA_SDK__PLATFORM_RASPBIAN +#error "Incorrect usage of lpasdk/core/raspbian/lpa_core.h (PLATFORM_RASPBIAN not defined)" +#endif + + +#define LPA_MAX_PATH 260 //MAX_PATH +#define LPA_PATH_SEPARATOR "/" + +// Declare LPA MACRO & Constant (platform) +#define LPA_SDK_INLINE_FUNCTION static inline +#define UT_EXPORT_DLL // Nothing specific for this platform + + +#endif // LPA_SDK__CORE_RASPBIAN__LPA_CORE_H \ No newline at end of file diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/rawdata_object.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/rawdata_object.h new file mode 100755 index 000000000..5979e556d --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/rawdata_object.h @@ -0,0 +1,61 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#ifndef LPA_SDK__CORE_RAW_DATA_OBJECT_H +#define LPA_SDK__CORE_RAW_DATA_OBJECT_H + +#include +#include +#include + +#include "lpasdk/core/lpa_core.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct +{ + unsigned char* rawData; + size_t rawDataSize; +}RawDataObject, *PtrRawDataObject; + +UT_EXPORT_DLL RawDataObject* rawDataObject_allocate(); +UT_EXPORT_DLL RawDataObject* rawDataObject_create(const unsigned char* ptrRawData, size_t rawDataSize); +UT_EXPORT_DLL RawDataObject* rawDataObject_createAsLV(const unsigned char* ptrRawData, size_t rawDataSize); +UT_EXPORT_DLL RawDataObject* rawDataObject_createFromBase64(const char* ptrBase64Data, const size_t base64DataSize, const size_t maximumRawdataSize); +UT_EXPORT_DLL RawDataObject* rawDataObject_concat(const RawDataObject* ptrRawDataObject1, const RawDataObject*ptrRawDataObject2); +UT_EXPORT_DLL RawDataObject* rawDataObject_concatRawDataArray(const RawDataObject* ptrRawDataObject1, const unsigned char* ptrRawData2, size_t rawDataSize2); +UT_EXPORT_DLL RawDataObject* rawDataObject_concatPartially(const RawDataObject* ptrRawDataObject1, const RawDataObject*ptrRawDataObject2, size_t offset, size_t length); +UT_EXPORT_DLL bool rawDataObject_appendRawDataArray(RawDataObject* ptrRawDataObjectSource, const unsigned char* ptrRawDataAppend, size_t rawDataSizeAppend); + +UT_EXPORT_DLL bool rawDataObject_update(RawDataObject* ptrRawDataObject, const unsigned char* ptrRawData, size_t rawDataSize); +UT_EXPORT_DLL void rawDataObject_clear(RawDataObject* ptrRawDataObject); +UT_EXPORT_DLL void rawDataObject_free(RawDataObject* ptrRawDataObject); + +// Some macro to help memory cleanup +#define ERASE_RAWDATAOBJECT(_ptr) if ((_ptr) != NULL) { rawDataObject_free( (_ptr) ); (_ptr) = NULL;} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif // LPA_SDK__CORE_RAW_DATA_OBJECT_H diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/semedia_base.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/semedia_base.h new file mode 100755 index 000000000..62d46f389 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/semedia_base.h @@ -0,0 +1,62 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#ifndef LPA_SDK__CORE_SEMEDIA_BASE_H +#define LPA_SDK__CORE_SEMEDIA_BASE_H + +#include +#include + +#include "lpasdk/api/lpasdk_api.h" +#include "lpasdk/api/semedia/semedia.h" + + +typedef struct TSEMedia +{ + // parameter part + ///////////////////////// + + void* _childStruct; + + // function part + ///////////////////////// + + bool (*seMediaEstablishContext) (const struct TSEMedia*); + bool (*seMediaReleaseContext) (const struct TSEMedia*); + bool (*seMediaIsValidContext) (const struct TSEMedia*); + bool (*seMediaIsContextEstablished) (const struct TSEMedia*); + + bool (*seMediaSetCallbackEventExecutionError) (const struct TSEMedia*, LPA_EVENT_EXECUTION_ERROR lpaEventExecutionErrorCallback); + + bool (*seMediaListReader) (const struct TSEMedia*, LPA_SE_MEDIA_READER_NAME_INFO * ptrReaderNameInfoList, size_t readerNameInfoMax, size_t* ptrCountReader); + bool (*seMediaConnect) (const struct TSEMedia*, const char *ptrReaderName); + bool (*seMediaIsConnected) (const struct TSEMedia*); + bool (*seMediaTransmitApdu) (const struct TSEMedia*, const unsigned char* ptrApduCommandBytes, size_t apduCommandSize, unsigned char* ptrApduResponseBytes, size_t* ptrApduResponseMaxSize); + bool (*seMediaDisconnect) (const struct TSEMedia*); + bool (*seMediaDisconnectWithReset) (const struct TSEMedia*); + + bool (*seMediaGetStatus) (const struct TSEMedia*, SE_MEDIA_CARD_STATUS* ptrStatus); + +} TSEMedia; + +TSEMedia* New_SEMediaBase(); + +#endif // LPA_SDK__CORE_SEMEDIA_BASE_H \ No newline at end of file diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/semedia_manager.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/semedia_manager.h new file mode 100755 index 000000000..04b544d82 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/semedia_manager.h @@ -0,0 +1,60 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#ifndef LPA_SDK__CORE_SEMEDIA_MANAGER_H +#define LPA_SDK__CORE_SEMEDIA_MANAGER_H + +#include +#include + +#include "lpasdk/api/lpasdk_api.h" +#include "lpasdk/core/lpa_core.h" +#include "lpasdk/core/semedia_base.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +UT_EXPORT_DLL bool seMediaManagerInitialize(); +UT_EXPORT_DLL bool seMediaManagerIsInitialized(); +UT_EXPORT_DLL bool seMediaManagerUninitialize(); + +UT_EXPORT_DLL bool seMediaManagerSetCallbackEventExecutionError(LPA_EVENT_EXECUTION_ERROR lpaEventExecutionErrorCallback); + +bool seMediaManagerEstablishContext(); +bool seMediaManagerReleaseContext(); + +bool seMediaManagerIsContextEstablished(); +bool seMediaManagerIsValidContext(); + +bool seMediaManagerListReader(LPA_SE_MEDIA_READER_NAME_INFO * readerNameInfoList, size_t readerNameInfoMax, size_t* countReader); +bool seMediaManagerIsConnected(); +bool seMediaManagerConnect(const char* readerName); +bool seMediaManagerTransmitApdu(const unsigned char* apduCommandBytes, size_t apduCommandSize, unsigned char* apduResponseBytes, size_t* apduResponseMaxSize); + +bool seMediaManagerDisconnect(); +bool seMediaManagerDisconnectWithReset(); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif // LPA_SDK__CORE_SEMEDIA_MANAGER_H \ No newline at end of file diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/util.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/util.h new file mode 100755 index 000000000..2a3addbc6 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/core/util.h @@ -0,0 +1,54 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#ifndef LPA_SDK__CORE_UTIL_H +#define LPA_SDK__CORE_UTIL_H + +#include +#include +#include + +int formatBytesToHexaString(const unsigned char *ptrDataBytes, size_t dataSize, char* ptrBuffer, size_t bufferMaxSize); +bool writeIntegerValueToByteArray(uint16_t integerValue, unsigned char *ptrByteArray, size_t byteArrayMaxSize, size_t* byteArraySize ); +bool extractIntegerFromByteArray(const unsigned char *ptrByteArray, size_t byteArraySize, uint16_t* ptrIntegerValue); +bool hexStr2ByteArray(const unsigned char * inHexString,int inLen, unsigned char * outHex, int* outLen); +bool encodeLength(int length, unsigned char* lengthTLV, const size_t lengthTLVsize, size_t * attributeLength); +bool generateLength(int length, unsigned char* lengthHex, const size_t lengthHexsize, size_t * attributeLength); +int oneHexCharToHex(char h); +bool split(char *src,const char *separator,char **dest,int *num); +bool findSubstr(char* source, char* target); +int countCharOccurencesInString(const char * pString, const char c); +bool isElementPresentInArrayUInt(const unsigned int *pReferenceArray, const size_t pArraySize, const unsigned int pValue); +bool isElementPresentInArrayByte(const unsigned char *pReferenceArray, const size_t pArraySize, const unsigned char pValue); +bool compareEqualStringIgnoringCase(const char * pString1, const char * pString2); +bool convertStringToBoolean(const char* ptrParameterValue, bool *ptrBooleanValue); +bool convertStringToLong(const char* ptrParameterValue, long *ptrLongValue); +bool convertStringToLower(const char * ptrSourceString, char * ptrDestString, size_t ptrDestStringSize); +bool extractOIDfromCertificate(const unsigned char * ptrCertificate, const size_t certificateLength, unsigned char * ptrOID, size_t * ptrOIDsize, const size_t oidSizeMax); +bool convertASN1_OIDtoText(const unsigned char * ptrOID, const size_t OIDsize, char * OIDtext, const size_t OIDtextMaxSize); +bool parseDataWithVLQnodes(const unsigned char * ptrSource, const size_t sourceLength, unsigned char * ptrExtractData, size_t * ptrExtractDatalength, const size_t extractDataMaxSize); +bool decodeVLQvalue(const unsigned char * ptrVLQvalue, const size_t VLQvalueSize, unsigned long long * ptrOutputValue); +bool base64_encode(const unsigned char *indata, size_t inlen, char *outdata, size_t *outlen, size_t maxSize); +bool base64_decode(const char *indata, size_t inlen, unsigned char *outdata, size_t *outlen, size_t destSize); +bool extractBitsSetListInStaticASN1BitString(const unsigned char * ptrASN1BitString, const size_t ASN1BitStringLength, unsigned char * ptrBitsSetList, const size_t maxBitsSetListSize, size_t * ptrNbBitsSetFound); +bool checkBitSetInStaticASN1BitString(const unsigned char * ptrASN1BitString, const size_t ASN1BitStringLength, const unsigned char bitToCheck, bool * ptrIsPresent); + +#endif // LPA_SDK__CORE_UTIL_H \ No newline at end of file diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/driver/httpmedia_curl.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/driver/httpmedia_curl.h new file mode 100755 index 000000000..1901aa82c --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/driver/httpmedia_curl.h @@ -0,0 +1,56 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#include +#ifndef HTTPMEDIA_CURL_H +#define HTTPMEDIA_CURL_H + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct RespStruct { + char *resp; + size_t size; + } RespStruct; + + typedef struct { + // Base part + ///////////////////////// + THTTPMedia* _base; + + // Specific part + ///////////////////////// + CURL *_curl; + struct curl_slist *_headers; + struct RespStruct _respdata; + } THTTPMediaCURL; + + THTTPMedia* New_HTTPMediaCurl(); + void Delete_HTTPMediaCurl(THTTPMedia* httpMedia); + + +#ifdef __cplusplus +} +#endif + +#endif /* HTTPMEDIA_CURL_H */ + diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/driver/semedia_genericmodem.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/driver/semedia_genericmodem.h new file mode 100755 index 000000000..d2a931299 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/driver/semedia_genericmodem.h @@ -0,0 +1,65 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#ifndef LPA_SDK__DRIVER_SEMEDIA_GENERIC_MODEM_H +#define LPA_SDK__DRIVER_SEMEDIA_GENERIC_MODEM_H + +// This driver is compiled only if LPA_SDK__SEMEDIA_DRIVER_GENERIC_MODEM build option exist +#ifdef LPA_SDK__SEMEDIA_DRIVER_GENERIC_MODEM + +#if defined(LPA_SDK__PLATFORM_WIN) || defined(LPA_SDK__PLATFORM_CYGWIN) || defined(LPA_SDK__PLATFORM_RASPBIAN) + +#include + +#include "lpasdk/core/semedia_manager.h" +#include "lpasdk/core/semedia_base.h" + +typedef struct +{ + // Base part + ///////////////////////// + TSEMedia* _ptrBase; + + // Specific part + ///////////////////////// +#ifdef LPA_SDK__PLATFORM_WIN + HANDLE _modemHandle; +#else + int _modemFD; +#endif // LPA_SDK__PLATFORM_WIN + + uint8_t _apduChannel; + char _apduChannelString[3]; + bool _contextEstablished; +} TSEMediaGenericModem; + +// Simulate object constructor +TSEMedia* New_SEMediaGenericModem(); + +// Simulate object destructor +void Delete_SEMediaGenericModem(TSEMedia* ptrTSEMedia); + +#endif //def LPA_SDK__PLATFORM_WIN || LPA_SDK__PLATFORM_CYGWIN ||LPA_SDK__PLATFORM_RASPBIAN + +#endif // LPA_SDK__SEMEDIA_DRIVER_GENERIC_MODEM + +#endif // LPA_SDK__DRIVER_SEMEDIA_GENERIC_MODEM_H + diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/driver/semedia_winscard.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/driver/semedia_winscard.h new file mode 100755 index 000000000..575bd33b7 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/driver/semedia_winscard.h @@ -0,0 +1,105 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#ifndef LPA_SDK__DRIVER_SEMEDIA_WINSCARD_H +#define LPA_SDK__DRIVER_SEMEDIA_WINSCARD_H + +#ifdef LPA_SDK__SEMEDIA_DRIVER_WINSCARD + +#if defined(LPA_SDK__PLATFORM_WIN) || defined(LPA_SDK__PLATFORM_CYGWIN) || defined(LPA_SDK__PLATFORM_RASPBIAN) + +#include + +#ifdef LPA_SDK__PLATFORM_WIN +// Only available under Windows platform +#include +#else + #ifdef LPA_SDK__PLATFORM_CYGWIN + // Only available under Cygwin platform + #include + #else // LPA_SDK__PLATFORM_RASPBIAN + // Raspbian + + #define TEXT(quote) __TEXT(quote) // r_winnt + #define __TEXT(quote) quote // r_winnt + // MessageId: ERROR_BROKEN_PIPE + // + // MessageText: + // + // The pipe has been ended. + // + #define ERROR_BROKEN_PIPE 109L + #define SCARD_AUTOALLOCATE (DWORD)(-1) + #define SCARD_SCOPE_USER 0 // The context is a user context, and any + // database operations are performed within the + // domain of the user. + #define SCARD_SCOPE_TERMINAL 1 // The context is that of the current terminal, + // and any database operations are performed + // within the domain of that terminal. (The + // calling application must have appropriate + // access permissions for any database actions.) + #define SCARD_SCOPE_SYSTEM 2 // The context is the system context, and any + // database operations are performed within the + // domain of the system. (The calling + // application must have appropriate access + // permissions for any database actions.) + #define SCARD_ALL_READERS TEXT("SCard$AllReaders\000") + #define SCARD_DEFAULT_READERS TEXT("SCard$DefaultReaders\000") + #define SCARD_LOCAL_READERS TEXT("SCard$LocalReaders\000") + #define SCARD_SYSTEM_READERS TEXT("SCard$SystemReaders\000") + + #include + #include + #endif // LPA_SDK__PLATFORM_CYGWIN +#endif //LPA_SDK__PLATFORM_WIN + +#include "lpasdk/core/semedia_manager.h" +#include "lpasdk/core/semedia_base.h" + +typedef struct +{ + // Base part + ///////////////////////// + TSEMedia* _ptrBase; + + // Specific part + ///////////////////////// + SCARDCONTEXT _scardContext; + SCARDHANDLE _scardHandle; + bool _contextEstablished; + uint8_t _apduChannel; + + SE_MEDIA_DISCONNECT_CARD_PARAM _disconnectParam; + DWORD _connectSharedMode; + +} TSEMediaWinSCard; + +// Simulate object constructor +TSEMedia* New_SEMediaWinSCard(); + +// Simulate object destructor +void Delete_SEMediaWinSCard(TSEMedia* ptrTSEMedia); + +#endif //def LPA_SDK__PLATFORM_WIN || LPA_SDK__PLATFORM_CYGWIN + +#endif // LPA_SDK__SEMEDIA_DRIVER_WINSCARD + +#endif // LPA_SDK__DRIVER_SEMEDIA_WINSCARD_H \ No newline at end of file diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/lpasdk_internal_api.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/lpasdk_internal_api.h new file mode 100755 index 000000000..9177b0844 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/lpasdk_internal_api.h @@ -0,0 +1,207 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + + +#ifndef LPA_SDK__CORE_INTERNAL_API_H +#define LPA_SDK__CORE_INTERNAL_API_H + +#include +#include +#include + +#include "lpasdk/api/lpasdk_api.h" +#include "lpasdk/core/rawdata_object.h" +#include "lpasdk/core/bertlv_object.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/////////////////////////////////// +// MACRO PART +/////////////////////////////////// + +// Actually not used but can be still useful to free memory not reserved by lpaCoreMemoryAlloc() +#define FREEIF(ptr) do{\ + if(ptr) free(ptr);\ + ptr=NULL;\ +}while(0) + +/////////////////////////////////// +// DEFINE PART +/////////////////////////////////// + +#define LPA_GET_EUICC_CHALLENGE_MAX_SIZE 30 // Shall not be grater than 23 bytes (Including SW), but keep some margin +#define LPA_AUTHENTICATE_SERVER_MAX_SIZE 4500 +#define LPA_PIR_BUFFER_MAX_SIZE 400 + +//max size for the server data +#define LPA_TRANSACTION_ID_MAX_SIZE 40 // For both binary and string format +#define LPA_INITIAL_AUTHENTICATE_SERVER_SIGNED1_MAX_SIZE 350 +#define LPA_INITIAL_AUTHENTICATE_SERVER_SIGNATURE1_MAX_SIZE 100 +#define LPA_INITIAL_AUTHENTICATE_EUICC_CIPKID_TO_BE_USED_MAX_SIZE 40 +#define LPA_INITIAL_AUTHENTICATE_SERVER_CERTIFICATE_MAX_SIZE 1536 +#define LPA_AUTHENTICATE_CLIENT_SMDP_CERTIFICATE_MAX_SIZE 1536 +#define LPA_AUTHENTICATE_CLIENT_SMDP_SIGNATURE2_MAX_SIZE 100 +#define LPA_AUTHENTICATE_CLIENT_SMDP_SIGNED2_MAX_SIZE 350 +#define LPA_AUTHENTICATE_CLIENT_PROFILE_METADATA_MAX_SIZE 2048 +#define LPA_GET_BOUND_PROFILE_MAX_SIZE 135168 // 132 Kb + +#define GET_EUICC_INFO1_DGI_TAG 0xBF20 +#define GET_EUICC_INFO2_DGI_TAG 0xBF22 + +/////////////////////////////////// +// STRUCTURE PART +/////////////////////////////////// + +typedef struct LPA_SERVER_DATA { + RawDataObject * _transactionId; + + // Initiate Authentication objects + RawDataObject * _serverSigned1; + RawDataObject * _serverSignature1; + RawDataObject * _euiccCiPKIdToBeUsed; + RawDataObject * _serverCertificate; + + // Authenticate Client objects + RawDataObject * _smdpCertificate; + RawDataObject * _smdpSignature2; + RawDataObject * _smdpSigned2; + RawDataObject * _profileMetadata; + + BerTLVList * _boundProfilePackage; + size_t _boundProfilePackageLength; + uint8_t _boundProfilePackageContainerCount; +} LPA_SERVER_DATA, *ptr_serverData; + +typedef struct { + // MatchingId + deviceInfoTLV + RawDataObject * ptrAuthenticateServerResponse; + RawDataObject * ptrAuthenticateServerResponse_Base64; +} AUTHENTICATE_SERVER_RESPONSE; + +typedef struct { + // UICC challenge or UICC info + RawDataObject * ptrEUICC; + RawDataObject * prtEUICC_Base64; +} LPA_GET_EUICC; + +typedef struct { + RawDataObject * ptrPrepareDownloadResponse; + RawDataObject * ptrPrepareDownloadResponse_Base64; +} PREPARE_DOWNLOAD_RESPONSE; + +typedef struct { + bool hasResult; + RawDataObject * ptrProfileInstallationResultTlv; + RawDataObject * ptrProfileInstallationResultTlv_Base64; +} PROFILE_INSTALLATION_RESULT; + +// PPR ASN1 bitstring values (PprIds object) +// Note: PPRUC means PprUpdateControl bit defined in PprIds ASN1 object and related to ES6 features +typedef enum +{ + LPA_PPRDEF_PPR2 = 0x0520, + LPA_PPRDEF_PPR1_PPR2 = 0x0560, + LPA_PPRDEF_PPRUC_PPR2 = 0x05A0, + LPA_PPRDEF_PPRUC_PPR1_PPR2 = 0x05E0, + LPA_PPRDEF_PPR1 = 0x0640, + LPA_PPRDEF_PPRUC_PPR1 = 0x06C0, + LPA_PPRDEF_PPRUC = 0x0780 +}LPA_PPR_ASN1_BIT_STRING_VALUES; + +// Fields extracted from profile Metadata for PPR check +#define LPA_GID_MAX_SIZE 10 // TBC if bigger size can be encountered. Not fixed in 31.102. Saw at 4 bytes in SGP.23 examples. + +typedef struct +{ + unsigned int profilePPR; // Will store ASN1 coding of profile PPR. If value = 0 No PPR in profile + bool hasPPR1; // True if PPR1 is enabled + bool hasPPR2; // True if PPR2 is enabled + unsigned char mccMnc[3]; + unsigned char gid1[LPA_GID_MAX_SIZE]; + size_t gid1Size; + bool gid1Defined; // Allow to know if field exists, even if length = 0 (Used in PPR conditions) + unsigned char gid2[LPA_GID_MAX_SIZE]; + size_t gid2Size; + bool gid2Defined; // Allow to know if field exists, even if length = 0 (Used in PPR conditions) + char profileName[LPA_PROFILE_NAME_MAX_SIZE + 2]; // Profile name that may be displayed to user. String coded. +1 byte for EOS, +1 byte for security + unsigned char userCallBackType; // Set information(s) to display to user. Values masks defined in LPA_USER_CONSENT_TYPES enum. Each bit set an info. + bool performCancelSession; // If true download is not allowed (PPR1 vs profile, RAT...) and Cancel Session will be performed + unsigned int cancelSessionReason; // Values defined in LPA_CANCEL_SESSION_REASON enum. Value has no importance while performCancelSession is not set +}LPA_DOWNLOADED_PROFILE_DATA_FOR_PPR; + +typedef struct +{ + unsigned char iccid[LPA_PROFILE_ICCID_BUFFER_MAX_SIZE]; + size_t iccidSize; + + unsigned char profileState[LPA_PROFILE_STATE_MAX_SIZE]; + size_t profileStateSize; + + unsigned char profileClass[LPA_PROFILE_CLASS_MAX_SIZE]; + size_t profileClassSize; + + unsigned char profilePolicyRules[LPA_PROFILE_POLICY_RULES_MAX_SIZE]; + size_t profilePolicyRulesSize; +}LPA_PROFILE_INFO_FOR_PPR; + +/* +Maximum profile info size retrieved from eUICC for PPR (Max length used): + Tag/size bytes + max data lengths +Header tag E3 5 bytes +iccid tag 5A 2 + 10 = 12 bytes +profileState tag 9F70 3 + 1 = 4 bytes +profileClass tag 95 2 + 1 = 3 bytes +profilePolicyRules tag 99 2 + 2 = 4 bytes + +TOTAL -------------------------------------- 28 bytes - Set at 30 for rounding / security +*/ +#define LPA_PROFILE_INFO_BUFFER_MAX_SIZE_FOR_PPR 30 // Size of profile raw data for PPR request + +#define LPA_RAT_MAXIMUM_SIZE 1024 // Arbitrary fixed to 1024 bytes + +// Structure used for PPR analysis, one for each PPR +typedef struct +{ + bool pprValidated; // If true, means this PPR has been validated one time + int matchLevelMCC_MNC; // Match level for MCC / MNC digits: From 0 (Most generic) to 6 (Most accurate). Most accurate = Highest priority + bool matchedGID1; // If true an exact matching has been found for GID1 (Same or not defined). Has most priority than wildcard (Defined in rule with L = 0). + bool matchedGID2; // If true an exact matching has been found for GID2 (Same or not defined). Has most priority than wildcard (Defined in rule with L = 0). + int matchLevelGID; // Match level for GID: From 0 (No match, both accepted in rule with L = 0) to 2 (Both same value or not defined). + bool userConsentRequired; // If true user consent is required. Has most priority than no consent required +}LPA_PPR_RAT_ANALYSIS_FLAGS; + +/////////////////////////////////// +// FUNCTION PART +/////////////////////////////////// +void lpaResetErrorCode(); +LPA_API_ERROR lpaGetErrorCodeNoClear(); +bool lpaIsError(); +void lpaSetErrorCode(LPA_API_ERROR errorCode); +void lpaWriteErrorMessageOnLog(LPA_API_ERROR errorCode); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif // LPA_SDK__CORE_API_H \ No newline at end of file diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/lpasdk_version.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/lpasdk_version.h new file mode 100755 index 000000000..6bd7ab791 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/lpasdk/lpasdk_version.h @@ -0,0 +1,33 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#ifndef LPA_SDK__VERSION_H +#define LPA_SDK__VERSION_H + +#define LPA_SDK_VERSION_MAJOR 1 +#define LPA_SDK_VERSION_MINOR 8 +#define LPA_SDK_VERSION_PATCH 0 +#define LPA_SDK_VERSION_BUILD 1 // 0 For a dev version (dev branch) + +// Must be lower than 64 bytes +#define LPA_SDK_EXTRA_VERSION "1.8.0-Build01" + +#endif // LPA_SDK__VERSION_H diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/sha256/sha-256.h b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/sha256/sha-256.h new file mode 100755 index 000000000..546079241 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/include/sha256/sha-256.h @@ -0,0 +1,31 @@ +// Source code from https://github.com/amosnier/sha-2 +// License : https://github.com/amosnier/sha-2/blob/master/LICENSE + +/* +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to +*/ + +void calc_sha_256(uint8_t hash[32], const void *input, size_t len); \ No newline at end of file diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/bertlv_object.c b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/bertlv_object.c new file mode 100755 index 000000000..df29c1554 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/bertlv_object.c @@ -0,0 +1,693 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#include "lpasdk/core/bertlv_object.h" +#include "lpasdk/core/lpa_memory.h" +#include "lpasdk/core/lpa_log.h" + +#include +#include + +//#include + +void _berTLV_freeRawDataBuffer(unsigned char* ptrRawData); +unsigned char* _berTLV_createRawDataBuffer(const BeerTLV* ptrBerTlv, size_t* ptrRawDataSize); + +////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////// + +/** + * Build BERTLV object (BeerTLV type) from raw data field, but only if specified Tag is found and its structure seems correct + * @param tag TLV tag to be found, uint8_t format + * @param ptrRawData Raw data field to analyze, bytes format + * @param rawDataSize Size of given raw data field + * @param ptrIsTagFound Boolean flag address, will be set to True if tag found and object has correct structure. If address = NULL will be ignored / not updated + * @return Pointer on BERTLV object (BeerTLV type) extracted from raw data bytes field. + */ +UT_EXPORT_DLL BeerTLV* berTLV_extractTagUInt8(uint8_t tag, const unsigned char* ptrRawData, uint32_t rawDataSize, bool* ptrIsTagFound) +{ + BeerTLV* berTLV = NULL; + + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "berTLV_extractTagUInt8(0x%02X,...)", tag); + + if (ptrRawData != NULL && rawDataSize >= 2) + { + uint16_t tag16 = (uint16_t)tag & 0x00FF; + berTLV = berTLV_extractTagUInt16(tag16, ptrRawData, rawDataSize, ptrIsTagFound); + } + + return berTLV; +} + +////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////// + +/** + * Build BERTLV object (BeerTLV type) from raw data field, but only if specified Tag is found and its structure seems correct + * @param tag TLV tag to be found, uint16_t format + * @param ptrRawData Raw data field to analyze, bytes format + * @param rawDataSize Size of given raw data field + * @param ptrIsTagFound Boolean flag address, will be set to True if tag found and object has correct structure. If address = NULL will be ignored / not updated + * @return Pointer on BERTLV object (BeerTLV type) extracted from raw data bytes field. + */ +UT_EXPORT_DLL BeerTLV* berTLV_extractTagUInt16(uint16_t tag, const unsigned char* ptrRawData, uint32_t rawDataSize, bool* ptrIsTagFound) +{ + BeerTLV* berTLV = NULL; + bool isTagFound = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "berTLV_extractTagUInt16(0x%04X,...)", tag); + + // ptrIsTagFound is now optionnal + if (ptrRawData != NULL && rawDataSize >= 2) + { + size_t offsetRawData = 0; + uint16_t currentTag = 0x00; + uint32_t currentLength = 0x00; + bool invalidRawData = false; + + while ((isTagFound == false) && (!invalidRawData) && (offsetRawData < rawDataSize)) + { + currentTag = 0x00; + currentLength = 0x00; + + // Read Tag + //////////////////// + + currentTag = ptrRawData[offsetRawData]; + if (currentTag == 0xFF || currentTag == 0x9F || currentTag == 0xdf || currentTag == 0x5f || currentTag == 0xbf) + { + // Tag size: 2 bytes + if ((offsetRawData + 1) < rawDataSize) + { + currentTag <<= 8; + currentTag |= ptrRawData[offsetRawData + 1]; + + offsetRawData += 2; + } + else + { + invalidRawData = true; + break; // Incorrect size + } + } + else + { + // Tag size: 1 byte + offsetRawData += 1; + } + + if (invalidRawData) + break; + + // Read + //////////////////// + if (offsetRawData < rawDataSize) + { + if (ptrRawData[offsetRawData] <= 0x7F) + { + currentLength = ptrRawData[offsetRawData]; + offsetRawData++; + } + else + { + switch (ptrRawData[offsetRawData]) + { + case 0x81: + { + if (offsetRawData + 1 < rawDataSize) + { + currentLength = ptrRawData[offsetRawData + 1]; + offsetRawData += 2; + } + else + invalidRawData = true; + } + break; + + case 0x82: + { + if (offsetRawData + 2 < rawDataSize) + { + currentLength = (ptrRawData[offsetRawData+1] << 8) | ptrRawData[offsetRawData + 2]; + offsetRawData += 3; + } + else + invalidRawData = true; + } + break; + + case 0x83: + { + if (offsetRawData + 3 < rawDataSize) + { + currentLength = (ptrRawData[offsetRawData + 1] << 16) | (ptrRawData[offsetRawData + 2] << 8) | ptrRawData[offsetRawData + 3] ; + offsetRawData += 4; + } + else + invalidRawData = true; + } + break; + + default: + invalidRawData = true; + break; + } + } + } + else + { + invalidRawData = true; + break; // Incorrect size + } + + if (invalidRawData) + break; + + // check if Tag expected + if (currentTag == tag) + { + // Tag is found + isTagFound = true; + + if (offsetRawData + currentLength <= rawDataSize) + berTLV = berTLV_create(tag, currentLength, &ptrRawData[offsetRawData]); + else + invalidRawData = true; + } + else + { + // No correct tag => go to next tag + offsetRawData += currentLength; + } + } + } + + // Update ptrIsTagFound if defined + if (ptrIsTagFound != NULL) + (*ptrIsTagFound) = isTagFound; + + return berTLV; +} + +////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////// + +/** + * Extract BERTLV objects list (At same encapsulation level) from raw bytes field. + * This list is a chained list, next list element is another BerTLVList object that can be reached by "ptrNext" attribute + * Warning: Keep pointer of first element to be able to free generated list from memory + * @param ptrRawData Raw data field to analyze, bytes format + * @param rawDataSize Size of given raw data field + * @param ptrCountTLVFound Return number of TLV objects found at this level + * @return First element of BERTLV objects list, BerTLVList format + */ +UT_EXPORT_DLL BerTLVList* berTLV_extractList(const unsigned char* ptrRawData, uint32_t rawDataSize, uint8_t* ptrCountTLVFound) +{ + BerTLVList* berTLVFirstElement = NULL; + BerTLVList* berTLVLastElement = NULL; + uint8_t countTLVFound = 0; + + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "berTLV_extractList(...)"); + + if (ptrRawData != NULL && rawDataSize >= 2) + { + size_t offsetRawData = 0; + uint16_t currentTag = 0x00; + uint32_t currentLength = 0x00; + bool invalidRawData = false; + + while ( (!invalidRawData) && (offsetRawData < rawDataSize)) + { + currentTag = 0x00; + currentLength = 0x00; + + // Read Tag + //////////////////// + + currentTag = ptrRawData[offsetRawData]; + if (currentTag == 0xFF || currentTag == 0x9F || currentTag == 0xdf || currentTag == 0x5f || currentTag == 0xbf) + { + // Tag size: 2 bytes + if ((offsetRawData + 1) < rawDataSize) + { + currentTag <<= 8; + currentTag |= ptrRawData[offsetRawData + 1]; + + offsetRawData += 2; + } + else + { + invalidRawData = true; + break; // Incorrect size + } + } + else + { + // Tag size: 1 byte + offsetRawData += 1; + } + + if (invalidRawData) + break; + + // Read + //////////////////// + if (offsetRawData < rawDataSize) + { + if (ptrRawData[offsetRawData] <= 0x7F) + { + currentLength = ptrRawData[offsetRawData]; + offsetRawData++; + } + else + { + switch (ptrRawData[offsetRawData]) + { + case 0x81: + if (offsetRawData + 1 < rawDataSize) + { + currentLength = ptrRawData[offsetRawData+1]; + offsetRawData += 2; + } + else + invalidRawData = true; + break; + + case 0x82: + if (offsetRawData + 2 < rawDataSize) + { + currentLength = (ptrRawData[offsetRawData+1] << 8) | ptrRawData[offsetRawData+2]; + offsetRawData += 3; + } + else + invalidRawData = true; + break; + + case 0x83: + { + if (offsetRawData + 3 < rawDataSize) + { + currentLength = (ptrRawData[offsetRawData + 1] << 16) | (ptrRawData[offsetRawData + 2] << 8) | ptrRawData[offsetRawData + 3]; + offsetRawData += 4; + } + else + invalidRawData = true; + } + break; + + default: + invalidRawData = true; + break; + } + } + } + else + { + invalidRawData = true; + break; // Incorrect size + } + + if (invalidRawData) + break; + + // create TLV item + BerTLVList* ptrBerTLVList = lpaCoreMemoryAlloc(sizeof(BerTLVList)); + if (ptrBerTLVList != NULL) + { + memset(ptrBerTLVList, 0x00, sizeof(BerTLVList)); + + ptrBerTLVList->index = countTLVFound; + ptrBerTLVList->berTLV = berTLV_create(currentTag, currentLength, &ptrRawData[offsetRawData]); + ptrBerTLVList->ptrNext = NULL; + + if (ptrBerTLVList->berTLV != NULL) + { + // Add it to the list + if (berTLVFirstElement == NULL) + berTLVFirstElement = berTLVLastElement = ptrBerTLVList; + else + { + berTLVLastElement->ptrNext = ptrBerTLVList; + berTLVLastElement = ptrBerTLVList; + } + + countTLVFound++; + } + else + { + // Memory issue => release list created, release new item and return NULL + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "berTLV_extractList(...) => memory issue!"); + if (berTLVFirstElement != NULL) + { + berTLV_freeBerTLVList(berTLVFirstElement); + berTLVFirstElement = NULL; + } + + lpaCoreMemoryFree(ptrBerTLVList); + ptrBerTLVList = NULL; + + break; + } + } + else + { + // Memory issue => clear list created and return NULL + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "berTLV_extractList(...) => memory issue!"); + if (berTLVFirstElement != NULL) + { + berTLV_freeBerTLVList(berTLVFirstElement); + berTLVFirstElement = NULL; + } + + break; + } + + // go to next tag + offsetRawData += currentLength; + } + } + + if (ptrCountTLVFound != NULL) + *ptrCountTLVFound = countTLVFound; + + return berTLVFirstElement; +} + +////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////// + +/** + * Free BERTLV object (BeerTLV) from memory + * @param ptrBerTLV Pointer on BeerTLV object to free + * @return + */ +UT_EXPORT_DLL bool berTLV_freeBerTLV(BeerTLV* ptrBerTLV) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "berTLV_freeBerTLV(...)" ); + + if (ptrBerTLV != NULL) + { + if (ptrBerTLV->value != NULL) + { + lpaCoreMemoryFree(ptrBerTLV->value); + } + lpaCoreMemoryFree(ptrBerTLV); + ptrBerTLV = NULL; + } + + return true; +} + +////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////// + +/** + * Free BERTLV list object (BerTLVList) from memory + * @param ptrBerTLVList Pointer on first element of the BERTLV list to free + * @return + */ +UT_EXPORT_DLL bool berTLV_freeBerTLVList(BerTLVList* ptrBerTLVList) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "berTLV_freeBerTLVList(...)"); + + if (ptrBerTLVList != NULL) + { + BerTLVList* ptrCurrentBerTLVList = ptrBerTLVList; + while (ptrCurrentBerTLVList != NULL) + { + BerTLVList* ptrNextBertTLVList = ptrCurrentBerTLVList->ptrNext; + if (ptrCurrentBerTLVList->berTLV != NULL) + { + berTLV_freeBerTLV(ptrCurrentBerTLVList->berTLV); + ptrCurrentBerTLVList->berTLV = NULL; + } + lpaCoreMemoryFree(ptrCurrentBerTLVList); + ptrCurrentBerTLVList = ptrNextBertTLVList; + } + + ptrBerTLVList = NULL; + } + + return true; +} + +////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////// + +/** + * Create BERTLV object from separate elements (Tag, size and data) + * @param tag Tag of BERTLV object, uint16_t format + * @param length Length of BERTLV, uint32_t format + * @param ptrValue Data to be stored in BERTLV object, char array + * @return Pointer on created BERTLV object, else NULL if failed + */ +UT_EXPORT_DLL BeerTLV* berTLV_create(uint16_t tag, uint32_t length, const unsigned char* ptrValue) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "berTLV_create(tag:0x%04X)", tag); + + BeerTLV* ptrBerTLV = lpaCoreMemoryAlloc(sizeof(BeerTLV)); + if (ptrBerTLV != NULL) + { + memset(ptrBerTLV, 0x00, sizeof(BeerTLV)); + + ptrBerTLV->tag = tag; + ptrBerTLV->length = 0; + ptrBerTLV->value = NULL; + + if (length > 0 && ptrValue != NULL ) + { + ptrBerTLV->value = lpaCoreMemoryAlloc(length); + if (ptrBerTLV->value != NULL) + { + memcpy(ptrBerTLV->value, ptrValue, length); + ptrBerTLV->length = length; + } + else + { + // If no memory for data, ptrBerTLV must be NULL (and release allocated memory) + lpaCoreMemoryFree(ptrBerTLV); + ptrBerTLV = NULL; + } + } + } + + return ptrBerTLV; +} + +////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////// + +/** + * Will create a raw data array storing image (Tag, encoded length and data) of BERTLV object stored in a BeerTLV variable / object + * @param ptrBerTlv Pointer on BERTLV variable / object to store, BeerTLV type + * @param ptrRawDataSize Will store size of array storing BERTLV object image, size_t type + * @return Pointer on raw data array storing BERTLV image, else NULL if failed + */ +unsigned char* _berTLV_createRawDataBuffer(const BeerTLV* ptrBerTlv, size_t* ptrRawDataSize) +{ + unsigned char* ptrRawData = NULL; + + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "_berTLV_createRawDataBuffer(...)"); + + if (ptrRawDataSize != NULL && ptrBerTlv != NULL) + { + *ptrRawDataSize = 0; // default raw data size + + uint32_t tlvTagSize = 0; + uint32_t tlvLengthSize = 0; + uint32_t tlvDataSize = 0; + uint32_t tlvTotalSize = 0; + + // detect tag size + tlvTagSize = ((ptrBerTlv->tag & 0xFF00) != 0x00) ? 2 : 1; + tlvLengthSize = ptrBerTlv->length <= 0x7F ? 1 : (ptrBerTlv->length <= 0xFF ? 2 : (ptrBerTlv->length <= 0xFFFF ? 3 : 4 ) ); + tlvDataSize = ptrBerTlv->length; + + tlvTotalSize = tlvTagSize + tlvLengthSize + tlvDataSize; + + // Allocate buffer + if (tlvTotalSize > 0) + { + size_t offestRawData = 0; + ptrRawData = lpaCoreMemoryAlloc(tlvTotalSize); + if (ptrRawData != NULL) + { + switch (tlvTagSize) + { + case 1: + ptrRawData[offestRawData] = ptrBerTlv->tag & 0xFF; + offestRawData++; + break; + + case 2: + ptrRawData[offestRawData] = (ptrBerTlv->tag >> 8) & 0xFF; + offestRawData++; + + ptrRawData[offestRawData] = ptrBerTlv->tag & 0x00FF; + offestRawData++; + break; + } + + switch (tlvLengthSize) + { + case 1: + ptrRawData[offestRawData] = (unsigned char) ptrBerTlv->length; + offestRawData++; + break; + + case 2: + ptrRawData[offestRawData] = 0x81; + offestRawData++; + + ptrRawData[offestRawData] = (unsigned char) ptrBerTlv->length; + offestRawData++; + break; + + case 3: + ptrRawData[offestRawData] = 0x82; + offestRawData++; + + ptrRawData[offestRawData] = (ptrBerTlv->length >> 8) & 0xFF; + offestRawData++; + + ptrRawData[offestRawData] = ptrBerTlv->length & 0x00FF; + offestRawData++; + break; + + case 4: + ptrRawData[offestRawData] = 0x83; + offestRawData++; + + ptrRawData[offestRawData] = (ptrBerTlv->length >> 16) & 0xFF; + offestRawData++; + + ptrRawData[offestRawData] = (ptrBerTlv->length >> 8) & 0xFF; + offestRawData++; + + ptrRawData[offestRawData] = ptrBerTlv->length & 0x00FF; + offestRawData++; + break; + } + + // And now, add TLV Value part + if (tlvDataSize > 0) + memcpy(&ptrRawData[offestRawData], ptrBerTlv->value, tlvDataSize); + + *ptrRawDataSize = tlvTotalSize; + } + } + + } + + return ptrRawData; +} + +////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////// + +/** + * Free BERTLV raw data array image created by _berTLV_createRawDataBuffer() + * @param ptrRawData + */ +void _berTLV_freeRawDataBuffer(unsigned char* ptrRawData) +{ + if (ptrRawData != NULL) + { + lpaCoreMemoryFree(ptrRawData); + ptrRawData = NULL; + } +} + +////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////// + +/** + * Build a TLV object in a raw data data chain (RawDataObject type) + * @param tag Tag of TLV object + * @param length Length of TLV object + * @param ptrValue Value of TLV object + * @return TLV object raw data in RawDataObject type + */ +RawDataObject* berTLV_createAndBuildRawDataObject(uint16_t tag, uint32_t length, const unsigned char* ptrValue) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "berTLV_createAndBuildRawDataObject(...)"); + + RawDataObject* ptrRawDataObject = NULL; + BeerTLV* ptrBerTLV = berTLV_create(tag, length, ptrValue); + if (ptrBerTLV != NULL) + { + ptrRawDataObject = berTLV_buildRawDataObject(ptrBerTLV); + berTLV_freeBerTLV(ptrBerTLV); + ptrBerTLV = NULL; + } + + return ptrRawDataObject; +} + +////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////// + +/** + * Create raw data image of BERTLV object (BeerTLV type) and store it in a RawDataObject object + * @param ptrBerTlv Pointer on BERTLV variable / object to store, BeerTLV type + * @return Pointer on RawDataObject storing raw data image of BeerTLV object, else NULL if failed + */ +UT_EXPORT_DLL RawDataObject* berTLV_buildRawDataObject(const BeerTLV* ptrBerTlv) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "berTLV_buildRawDataObject(...)"); + + RawDataObject* ptrRawDataObject = NULL; + if (ptrBerTlv != NULL) + { + ptrRawDataObject = rawDataObject_allocate(); + if (ptrRawDataObject != NULL) + { + size_t rawDataSize = 0; + ptrRawDataObject->rawData = _berTLV_createRawDataBuffer(ptrBerTlv, &rawDataSize); + if (ptrRawDataObject->rawData != NULL) + { + ptrRawDataObject->rawDataSize = rawDataSize; + } + else + { + // Memory allocation issue => release ptrRawDataObject and return NULL + rawDataObject_free(ptrRawDataObject); + ptrRawDataObject = NULL; + } + } + } + return ptrRawDataObject; +} + +////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////// + diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/httpmedia_base.c b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/httpmedia_base.c new file mode 100755 index 000000000..3e950f24a --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/httpmedia_base.c @@ -0,0 +1,38 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#include "lpasdk/core/lpa_memory.h" +#include "lpasdk/core/httpmedia_base.h" +#include "lpasdk/core/lpa_log.h" + +THTTPMedia* New_HTTPMediaBase() +{ + THTTPMedia* ptrHttpMediaBase = NULL; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++New_HTTPMediaBase"); + + ptrHttpMediaBase = lpaCoreMemoryAlloc(sizeof(THTTPMedia)); + + if(ptrHttpMediaBase != NULL) + memset(ptrHttpMediaBase, 0, sizeof(THTTPMedia)); + + return ptrHttpMediaBase; +} \ No newline at end of file diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/httpmedia_manager.c b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/httpmedia_manager.c new file mode 100755 index 000000000..ce112d690 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/httpmedia_manager.c @@ -0,0 +1,244 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#include +#include +#include +#include +#include "curl/curl.h" + +#include "lpasdk/core/httpmedia_base.h" +#include "lpasdk/core/httpmedia_manager.h" +#include "lpasdk/driver/httpmedia_curl.h" +#include "lpasdk/core/lpa_log.h" +#include "lpasdk/core/lpa_memory.h" + + +static THTTPMedia* _httpMedia = NULL; + +UT_EXPORT_DLL bool httpMediaManagerInitialize() +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+httpMediaManagerInitialize()"); + + if (_httpMedia == NULL) + { + _httpMedia = New_HTTPMediaCurl(); + if (_httpMedia != NULL ) + res = true; + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "httpMediaManagerInitialize(): Unable to create _httpMedia!"); + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-httpMediaManagerInitialize()"); + + return res; +} + +UT_EXPORT_DLL bool httpMediaManagerIsInitialized() +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+httpMediaManagerIsInitialized()"); + + return (_httpMedia != NULL); +} + +UT_EXPORT_DLL bool httpMediaManagerDelete() +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+httpMediaManagerDelete()"); + + if (_httpMedia != NULL) + { + Delete_HTTPMediaCurl(_httpMedia); + _httpMedia = NULL; + res = true; + } + + return res; +} + +bool httpMediaManagerSetBooleanOption(HttpMediaOptionType optionType, bool enabled) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+httpMediaManagerSetBooleanOption()"); + + if (_httpMedia != NULL) { + res = _httpMedia->httpMediaSetBooleanOption(_httpMedia, optionType, enabled); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "_httpMedia is not created!"); + + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- httpMediaManagerSetBooleanOption() return %s", (res ? "true" : "false")); + return res; +} + +bool httpMediaManagerGetBooleanOption(HttpMediaOptionType optionType, bool* ptrEnabled) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+httpMediaManagerGetBooleanOption()"); + + if (_httpMedia != NULL && ptrEnabled != NULL) { + res = _httpMedia->httpMediaGetBooleanOption(_httpMedia, optionType, ptrEnabled); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "_httpMedia is not created!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- httpMediaManagerGetBooleanOption() return %s", (res ? "true" : "false")); + return res; +} + +bool httpMediaManagerSetLongOption(HttpMediaOptionType optionType, long value) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+httpMediaManagerSetLongOption()"); + + if (_httpMedia != NULL) + { + res = _httpMedia->httpMediaSetLongOption(_httpMedia, optionType, value); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "_httpMedia is not created!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- httpMediaManagerSetLongOption() return %s", (res ? "true" : "false")); + return res; +} + +bool httpMediaManagerGetLongOption(HttpMediaOptionType optionType, long* ptrValue) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+httpMediaManagerGetLongOption()"); + + if (_httpMedia != NULL) { + + if(ptrValue != NULL ) + res = _httpMedia->httpMediaGetLongOption(_httpMedia, optionType, ptrValue); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "_httpMedia is not created!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- httpMediaManagerGetLongOption() return %s", (res ? "true" : "false")); + return res; +} + +bool httpMediaManagerSetCallbackEventExecutionError(LPA_EVENT_EXECUTION_ERROR lpaEventExecutionErrorCallback) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+httpMediaManagerSetCallbackEventExecutionError()"); + + if (_httpMedia != NULL ) + res = _httpMedia->httpMediaSetCallbackEventExecutionError(_httpMedia, lpaEventExecutionErrorCallback); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "_httpMedia is not created!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- httpMediaManagerSetCallbackEventExecutionError() return %s", (res ? "true" : "false")); + return res; +} + +char* httpMediaManagerPost(const char* ptrCertificatePath, const char* ptrTargetURL, const char* ptrPostdata, bool* ptrIsSuccess, long* ptrHttpCode) +{ + char* resp = NULL; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+httpMediaManagerPost()"); + if (_httpMedia != NULL ) + { + if( ptrIsSuccess != NULL && ptrCertificatePath != NULL && ptrTargetURL != NULL && ptrPostdata != NULL && ptrHttpCode != NULL) + { + *ptrIsSuccess = false; + + bool res = _httpMedia->httpMediaPost(_httpMedia, ptrCertificatePath, ptrTargetURL, ptrPostdata, ptrHttpCode); + if (res) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "httpMediaPost() execute success"); + + // Check Http Code + int httpCode = *ptrHttpCode; + + if (httpCode >= 200 && httpCode < 300) + { + if (httpCode == 204) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "HTTP Code 204 => no data expected (calling httpMediaGetBufferResponse() is ignored)"); + *ptrIsSuccess = true; + } + else + { + resp = _httpMedia->httpMediaGetBufferResponse(_httpMedia); + if (resp != NULL) + *ptrIsSuccess = true; + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "httpMediaGetBufferResponse() return NULL"); + } + } + else + { + // Not a 2XX code , normally no data available + *ptrIsSuccess = true; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Not HTTP Code 2xx => data not managed (if present)"); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "httpMediaPost() failed"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "_httpMedia is not created!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- httpMediaManagerHTTPExecutePost() return res %s", (resp != NULL ? "not NULL" : "NULL")); + + return resp; +} + + + +bool httpMediaManagerHttpExecuteInit() { + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+httpMediaManagerHttpExecuteInit()"); + + if (_httpMedia != NULL) { + res = _httpMedia->httpMediaHttpExecuteInit(_httpMedia); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "_httpMedia is not created!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- httpMediaManagerHttpExecuteInit() return %s", (res ? "true" : "false")); + + return res; +} + +bool httpMediaManagerHttpExecuteCleanup() +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+httpMediaHttpExecuteCleanup()"); + bool res = false; + + if (_httpMedia != NULL) { + _httpMedia->httpMediaHttpExecuteCleanup(_httpMedia); + res = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "_httpMedia is not created!"); + + return res; +} \ No newline at end of file diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/isdr_applet_manager.c b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/isdr_applet_manager.c new file mode 100755 index 000000000..1f01af470 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/isdr_applet_manager.c @@ -0,0 +1,83 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#include "lpasdk/lpasdk_internal_api.h" + +#include "lpasdk/core/isdr_applet_manager.h" +#include "lpasdk/core/lpa_log.h" +#include "lpasdk/core/lpa_manager_helper.h" + +static bool _isSelectedISDR = false; +static unsigned char _apduCommandSelectISDR[] = { 0x00, 0xA4, 0x04, 0x00, 0x10, 0xA0, 0x00, 0x00, 0x05, 0x59, 0x10, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0x89, 0x00, 0x00, 0x01, 0x00 }; + +bool selectISDRApplet() +{ + if (!_isSelectedISDR) + { + unsigned char apduResponseBytes[256]; // Max APDU response size when Selecting ISDR + size_t apduResponseSize = 0; + uint16_t sw = 0x00; + + if (buildAndSendApduCase4Ex(_apduCommandSelectISDR, sizeof(_apduCommandSelectISDR), &sw, apduResponseBytes, sizeof(apduResponseBytes), &apduResponseSize)) + { + if (apduResponseSize >= 2) + { + if (sw == (uint16_t)0x9000 || ((sw & (uint16_t)0x9100) == (uint16_t)0x9100) || ((sw & (uint16_t)0x6100) == (uint16_t)0x6100) ) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "ISDR applet selected successfully"); + _isSelectedISDR = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Incorrect SW received!"); + lpaSetErrorCode(LPA_ERROR_SE_MEDIA_UNABLE_TO_SELECT_ISDR); + } + } + else + { + // SW is empty / incomplete or incorrect data (Too short to be a SW, can be data corruption or error detected at lower layer) + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Incorrect data or invalid SW or error! (Too short response < 2)"); + lpaSetErrorCode(LPA_ERROR_SE_MEDIA_UNABLE_TO_SELECT_ISDR); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Unable to send successfully APDU command!"); + lpaSetErrorCode(LPA_ERROR_SE_MEDIA_UNABLE_TO_SELECT_ISDR); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "ISDR applet already selected"); + + return _isSelectedISDR; +} + +bool isISDRAppletSelected() +{ + return _isSelectedISDR; +} + +bool unselectISDRApplet() +{ + _isSelectedISDR = false; + + return true; +} diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/lpa_config_file.c b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/lpa_config_file.c new file mode 100755 index 000000000..6b681d414 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/lpa_config_file.c @@ -0,0 +1,244 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#include "lpasdk/core/lpa_config_file.h" +#include "lpasdk/core/lpa_manager.h" + +#include "lpasdk/core/lpa_log.h" + +#include +#include +#include + +static bool _isLoaded = false; + +void _trimString(char* ptrString); +void _removeQuotes(char* ptrString); +bool _manageConfigLineEntry(char* ptrString); +bool _isEmptyOrCommentedLine(const char* ptrString); + +bool lpaConfigFileLoad(const char* ptrConfigFileName, bool* ptrConfigFileOpened) +{ + FILE *ptrFileConfig = NULL; + + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "lpaConfigFileLoad()..."); + + if (!_isLoaded) + { + if (ptrConfigFileName != NULL && ptrConfigFileOpened != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "Opening '%s' configuration file...", ptrConfigFileName); + + ptrFileConfig = fopen(ptrConfigFileName, "r"); + if (ptrFileConfig != NULL) + { + char bufferReadFile[LPA_CFG_LINE_ENTRY_MAX_SIZE]; + int16_t lineCounter = 0; + + *ptrConfigFileOpened = true; + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "Loading '%s' configuration file...", ptrConfigFileName); + + + // Read line by line (parsing error on one line do not stop parsing loop) + while ( !feof(ptrFileConfig)) + { + if (fgets(bufferReadFile, 1024, ptrFileConfig) == NULL) + break; + lineCounter++; + + _trimString(bufferReadFile); + if (!_isEmptyOrCommentedLine(bufferReadFile)) + { + if (!_manageConfigLineEntry(bufferReadFile)) + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "Unable to parse successfully line number %d!", lineCounter); + } + } + + if(lineCounter == 0) + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "No line processed, configuration file seems empty"); + + _isLoaded = true; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Closing configuration file..." ); + + fclose(ptrFileConfig); + ptrFileConfig = NULL; + } + else + { + int save_errno = errno; // Immediately save errno macro value else can be affected by other operations + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "Unable to open configuration file, errno = %d \"%s\"", save_errno, strerror(save_errno)); + *ptrConfigFileOpened = false; + } + } + } + else + { + // Configuration file already loaded + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "Configuration file already loaded"); + + if ( ptrConfigFileOpened != NULL) + *ptrConfigFileOpened = true; + } + + return _isLoaded; +} + +bool _isEmptyOrCommentedLine(const char* ptrLine) +{ + bool isEmptyOrCommentedLine = false; + + if (NULL == ptrLine || strlen(ptrLine) == 0) + isEmptyOrCommentedLine = true; + else + { + if (ptrLine[0] == '#' || ptrLine[0] == '/' || ptrLine[0] == ';') + isEmptyOrCommentedLine = true; + } + + return isEmptyOrCommentedLine; +} + +bool _manageConfigLineEntry(char* ptrLine) +{ + bool res = true; + + if (NULL != ptrLine && strlen(ptrLine) > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Parsing configuration entry '%s'...", ptrLine); + size_t posEqual = strcspn(ptrLine, "="); + if (posEqual < strlen(ptrLine)) + { + // Split the line into 2 parts : Key <-> Value + ptrLine[posEqual] = 0x00; + + char* ptrParameterKeyName = ptrLine; + char* ptrParameterKeyValue = &ptrLine[posEqual + 1]; + + _trimString(ptrParameterKeyName); + _trimString(ptrParameterKeyValue); + _removeQuotes(ptrParameterKeyName); + _removeQuotes(ptrParameterKeyValue); + + // Note: Empty ptrParameterKeyValue is now accepted, allow to replace a default string parameter value by an empty string if needed + // Value data compatibility checking for other types of parameters will be done by parameter setter. + if (strlen(ptrParameterKeyName) > 0) + { + LPA_PARAMETER_TYPE parameterType = LPA_PARAMETER_TYPE_UNKNOWN; + bool isParameterExist = false; + bool isAccessGranted = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "managing LPA parameter: '%s'='%s'", ptrParameterKeyName, ptrParameterKeyValue); + + if (lpaManagerIsConfigParameterExist(ptrParameterKeyName, ¶meterType, &isParameterExist, &isAccessGranted) && isParameterExist ) + { + if(isAccessGranted) + { + // Internal call to lpaManagerSetConfigParameter() function + if (lpaManagerSetConfigParameter(ptrParameterKeyName, LPA_PARAMETER_TYPE_STRING, ptrParameterKeyValue, true)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "LPA parameter '%s' configured successfully with value '%s'", ptrParameterKeyName, ptrParameterKeyValue); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Unable to set LPA parameter '%s' with value '%s'!", ptrParameterKeyName, ptrParameterKeyValue); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "No access right to update LPA parameter '%s' with value '%s'!", ptrParameterKeyName, ptrParameterKeyValue); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "parameter '%s' not exit or not supported", ptrParameterKeyName); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid configuration entry!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Separator not found on Configuration entry!"); + } + + return res; +} + +void _trimString(char* ptrString) +{ + if (ptrString != NULL && strlen(ptrString) > 0 ) + { + char* ptrBeginString = ptrString; + + size_t posSlash = strcspn(ptrBeginString, "\r\n"); + if (posSlash != strlen(ptrBeginString)) + ptrBeginString[posSlash] = 0x00; + + if (strlen(ptrString) > 0) + { + // Step1: Remove all space before first digit + if (isspace((unsigned char)(ptrBeginString[0]))) + { + // One or more space at begin + size_t countSpace = 0; + while (isspace( (unsigned char) (ptrBeginString[countSpace]))) + countSpace++; + + // Now remove it (or them) + size_t remainingString = strlen(ptrBeginString) - countSpace; + if (remainingString > 0) + { + for (size_t idx = 0; idx < remainingString; idx++) + ptrBeginString[idx] = ptrBeginString[idx + countSpace]; + ptrBeginString[remainingString] = 0x0; + } + else + ptrBeginString[0] = 0x0; + } + + // Step2: Remove all spaces after last digit + while((isspace( (unsigned char) (ptrString[strlen(ptrString) - 1]))) && (strlen(ptrString) > 0)) + ptrString[strlen(ptrString) - 1] = 0x00; + } + } +} + +/** + * Remove quotes '"' or ''' from parameter string only if it begin and ends by these characters + * Note: The parameter string has already been cleaned from extra spaces before and after by _trimString() + * @param ptrString + */ +void _removeQuotes(char* ptrString) +{ + size_t strLengthMinus1 = 0; + size_t idx = 0; + + // At least 2 characters must be present, minimum is "" that defines an empty string + if (ptrString != NULL && strlen(ptrString) > 1 ) + { + strLengthMinus1 = strlen(ptrString) - 1; + + if((ptrString[0] == '"' && ptrString[strLengthMinus1] == '"') || (ptrString[0] == '\'' && ptrString[strLengthMinus1] == '\'')) + { + // Remove first and last character + // Note: If 2 characters long it is an empty string, so copy loop will not start, and strlen -1 -1 will equal 0, so OK for end of string + for(idx = 0; idx < (strLengthMinus1 - 1); idx++) + { + ptrString[idx] = ptrString[idx + 1]; + } + // Set new end of string + ptrString[strLengthMinus1 - 1] = 0x00; + } + } +} diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/lpa_log.c b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/lpa_log.c new file mode 100755 index 000000000..b83881d65 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/lpa_log.c @@ -0,0 +1,774 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#include "lpasdk/core/lpa_log.h" +#include "lpasdk/core/lpa_memory.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +static LpaLogLevel _logLevel = SDK_LOG_LEVEL_DEBUG; + +static LPA_LOG_INTERFACE _lpaLogInterface; +static bool _lpaLogInitialized = false; +static bool _logLimitationActivated = false; + +#define LOG_NORMAL_MESSAGE_LINE_SIZE 1024 +#define LOG_MAXIMUM_MESSAGE_LINE_SIZE 8192 + +static char _bufferTimeFormatting[96]; +static char _bufferMessageFormatting[LOG_NORMAL_MESSAGE_LINE_SIZE]; // No static buffer > 1024 bytes (except if allocated dynamically) + +// Managing log max size +#define MIN_LOG_MAX_SIZE 64 * 1024 // 64 Ko + +#ifdef _DEBUG + #define LOG_FILE_MAX_SIZE_DEFAULT 16*1024*1024 // 16 Mo +#else + #define LOG_FILE_MAX_SIZE_DEFAULT 1024 * 1024 // 1 Mo +#endif // + +#ifdef LPA_SDK__LOG_MAX_SIZE + #undef LOG_FILE_MAX_SIZE_DEFAULT + #define LOG_FILE_MAX_SIZE_DEFAULT LPA_SDK__LOG_MAX_SIZE +#endif + +static long _lpaLogFileMaxSize = LOG_FILE_MAX_SIZE_DEFAULT; + +#define LOG_LEVEL_VERBOSE_STRING "VER" +#define LOG_LEVEL_DEBUG_STRING "DEB" +#define LOG_LEVEL_INFO_STRING "INF" +#define LOG_LEVEL_WARNING_STRING "WAR" +#define LOG_LEVEL_ERROR_STRING "ERR" +#define LOG_LEVEL_SYSTEM_STRING "SYS" + +typedef struct +{ + LpaLogLevel logLevel; + char* logLevelName; + bool selectable; +}LOG_LEVEL_INFO; + +static LOG_LEVEL_INFO _logLevelInfoList [] = +{ + { SDK_LOG_LEVEL_VERBOSE, LOG_LEVEL_VERBOSE_STRING, true }, + { SDK_LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_STRING, true }, + { SDK_LOG_LEVEL_INFO, LOG_LEVEL_INFO_STRING, true }, + { SDK_LOG_LEVEL_WARNING, LOG_LEVEL_WARNING_STRING, true }, + { SDK_LOG_LEVEL_ERROR, LOG_LEVEL_ERROR_STRING, true }, + + { SDK_LOG_LEVEL_SYSTEM, LOG_LEVEL_SYSTEM_STRING, false }, + // Latest entry: do not remove/update + {0, NULL} +}; + +static FILE* _logFile = NULL; +static char _logFileName[LPA_MAX_PATH]; +static char _backupLogFileName[LPA_MAX_PATH]; + +// Default implementation definition +/////////////////////////////////////////// +void _lpaCoreSetLogLevel(LpaLogLevel logLevel); +LpaLogLevel _lpaCoreGetLogLevel(void); + +bool _lpaCoreSetLogMaxSize(long logMaxSize); +long _lpaCoreGetLogMaxSize(); + +void _lpaCoreLogOpen(const char* ptrFileName, const char* prtBackupFileName); +void _lpaCoreLogFlush(); +bool _lpaCoreLogIsOpened(); +void _lpaCoreLogClose(); + +void _lpaCoreLogAppend(LpaLogLevel logLevel, const char* ptrMessage, va_list argptr); +void _lpaCoreLogAppendLongText(LpaLogLevel logLevel, const char* ptrHeaderMessage, const char* ptrLongTextToLog, const size_t LongTextToLogSize); +void _lpaCoreLogAppendByteArray(LpaLogLevel logLevel, const char* ptrMessage, const char* ptrByteArrayName, unsigned char* ptrByteArray, size_t byteArraySize); + +void _lpaCoreActivateLogLimitation(bool activated); + +// Internal functions +/////////////////////////////////////////// + +bool _isLogLevelMatching(const char* ptrLogLevel, const char* ptrLogLevelRef); +const char* _lpaCoreGetLogLevelName(LpaLogLevel logLevel, bool* ptrIsFound); + +/** + * Initialize log component with default implementation. + * @return True if log component successfully initialized, otherwise return false + */ + +bool lpaCoreLogInit() +{ + bool initDoneSuccessfully = false; + + if (!_lpaLogInitialized) + { + memset(&_lpaLogInterface, 0x00, sizeof(LPA_LOG_INTERFACE)); + + _lpaLogInterface.openLog = _lpaCoreLogOpen; + _lpaLogInterface.flushLog = _lpaCoreLogFlush; + _lpaLogInterface.isLogOpened = _lpaCoreLogIsOpened; + _lpaLogInterface.closeLog = _lpaCoreLogClose; + + _lpaLogInterface.appendToLog = _lpaCoreLogAppend; + _lpaLogInterface.appendLongTextToLog = _lpaCoreLogAppendLongText; + _lpaLogInterface.appendByteArrayToLog = _lpaCoreLogAppendByteArray; + + _lpaLogInterface.activateLogLimitation = _lpaCoreActivateLogLimitation; + + _lpaLogInterface.setLogLevel = _lpaCoreSetLogLevel; + _lpaLogInterface.getLogLevel = _lpaCoreGetLogLevel; + + _lpaLogInterface.setLogMaxSize = _lpaCoreSetLogMaxSize; + _lpaLogInterface.getLogMaxSize = _lpaCoreGetLogMaxSize; + + _lpaLogInitialized = true; + initDoneSuccessfully = true; + + // Log limitation mecanism deactivated at startup + _lpaLogInterface.activateLogLimitation(false); + } + + return initDoneSuccessfully; +} + +UT_EXPORT_DLL bool lpaCoreLogInitEx(LPA_LOG_INTERFACE* ptrLpaLogInterface) +{ + bool initDoneSuccessfully = false; + + if (!_lpaLogInitialized && ptrLpaLogInterface != NULL ) + { + memset( &_lpaLogInterface, 0x00, sizeof(LPA_LOG_INTERFACE)); + + _lpaLogInterface.openLog = ptrLpaLogInterface->openLog; + _lpaLogInterface.flushLog = ptrLpaLogInterface->flushLog; + _lpaLogInterface.closeLog = ptrLpaLogInterface->closeLog; + + _lpaLogInterface.activateLogLimitation = ptrLpaLogInterface->activateLogLimitation; + + _lpaLogInterface.setLogLevel = ptrLpaLogInterface->setLogLevel; + _lpaLogInterface.getLogLevel = ptrLpaLogInterface->getLogLevel; + + _lpaLogInterface.setLogMaxSize = ptrLpaLogInterface->setLogMaxSize; + _lpaLogInterface.getLogMaxSize = ptrLpaLogInterface->getLogMaxSize; + + _lpaLogInterface.appendToLog = ptrLpaLogInterface->appendToLog; + _lpaLogInterface.appendLongTextToLog = ptrLpaLogInterface->appendLongTextToLog; + _lpaLogInterface.appendByteArrayToLog = ptrLpaLogInterface->appendByteArrayToLog; + + _lpaLogInitialized = true; + initDoneSuccessfully = true; + + // Log limitation mecanism deactivated at startup + if(_lpaLogInterface.activateLogLimitation != NULL ) + _lpaLogInterface.activateLogLimitation(false); + } + + return initDoneSuccessfully; +} + +UT_EXPORT_DLL bool lpaCoreLogIsInitialized() +{ + return _lpaLogInitialized; +} + +UT_EXPORT_DLL bool lpaCoreLogRelease() +{ + bool releaseDoneSuccessfully = false; + + if (_lpaLogInitialized) + { + memset(&_lpaLogInterface, 0x00, sizeof(LPA_LOG_INTERFACE)); + + _lpaLogInitialized = false; + releaseDoneSuccessfully = false; + } + return releaseDoneSuccessfully; +} + +const LPA_LOG_INTERFACE* getLpaLogObject() +{ + return (_lpaLogInitialized ? &_lpaLogInterface : NULL); +} + +////////////////////////////////////////////// +// Log Manager part +////////////////////////////////////////////// + +UT_EXPORT_DLL void lpaCoreSetLogLevel(LpaLogLevel logLevel) +{ + if (_lpaLogInitialized && _lpaLogInterface.setLogLevel != NULL) + { + _lpaLogInterface.setLogLevel(logLevel); + } +} + +UT_EXPORT_DLL LpaLogLevel lpaCoreGetLogLevel(void) +{ + LpaLogLevel logLevel = SDK_LOG_LEVEL_UNKNOWN; + + if (_lpaLogInitialized && _lpaLogInterface.setLogLevel != NULL) + logLevel = _lpaLogInterface.getLogLevel(); + + return logLevel; +} + +UT_EXPORT_DLL bool lpaCoreSetLogMaxSize(long logMaxSize) +{ + bool res = false; + + if (_lpaLogInitialized && _lpaLogInterface.setLogMaxSize != NULL) + res = _lpaLogInterface.setLogMaxSize(logMaxSize); + + return res; +} + +UT_EXPORT_DLL long lpaCoreGetLogMaxSize() +{ + long logMaxSize = 0L; + + if (_lpaLogInitialized && _lpaLogInterface.getLogMaxSize != NULL) + logMaxSize = _lpaLogInterface.getLogMaxSize(); + + return logMaxSize; +} + +UT_EXPORT_DLL void lpaCoreActivateLogLimitation(bool activated) +{ + if (_lpaLogInitialized && _lpaLogInterface.activateLogLimitation != NULL) + _lpaLogInterface.activateLogLimitation(activated); +} + +UT_EXPORT_DLL void lpaCoreLogOpen(const char* ptrFileName, const char* prtBackupFileName) +{ + if (_lpaLogInitialized && _lpaLogInterface.openLog != NULL) + _lpaLogInterface.openLog(ptrFileName, prtBackupFileName); +} + +UT_EXPORT_DLL void lpaCoreLogFlush() +{ + if (_lpaLogInitialized && _lpaLogInterface.flushLog != NULL) + _lpaLogInterface.flushLog(); +} + +UT_EXPORT_DLL void lpaCoreLogClose() +{ + if (_lpaLogInitialized && _lpaLogInterface.closeLog != NULL) + _lpaLogInterface.closeLog(); +} + +UT_EXPORT_DLL bool lpaCoreLogIsOpen() +{ + bool isOpened = false; + + if (_lpaLogInitialized && _lpaLogInterface.isLogOpened != NULL) + isOpened = _lpaLogInterface.isLogOpened(); + + return isOpened; +} + +UT_EXPORT_DLL void lpaCoreLogAppend(LpaLogLevel logLevel, const char* ptrMessage, ...) +{ + if (_lpaLogInitialized && _lpaLogInterface.appendToLog != NULL) + { + va_list argptr; + va_start(argptr, ptrMessage); + + _lpaLogInterface.appendToLog(logLevel, ptrMessage, argptr); + + va_end(argptr); + } +} + +UT_EXPORT_DLL void lpaCoreLogAppendLongText(LpaLogLevel logLevel, const char* ptrHeaderMessage, const char* ptrLongTextToLog, const size_t LongTextToLogSize) +{ + if (_lpaLogInitialized && _lpaLogInterface.appendLongTextToLog != NULL) + { + _lpaLogInterface.appendLongTextToLog(logLevel, ptrHeaderMessage, ptrLongTextToLog,LongTextToLogSize); + } +} + +UT_EXPORT_DLL void lpaCoreLogAppendByteArray(LpaLogLevel logLevel, const char* ptrMessage, const char* ptrByteArrayName, unsigned char* ptrByteArray, size_t byteArraySize) +{ + if (_lpaLogInitialized && _lpaLogInterface.appendByteArrayToLog != NULL) + { + _lpaLogInterface.appendByteArrayToLog(logLevel, ptrMessage, ptrByteArrayName, ptrByteArray, byteArraySize); + } +} + + +UT_EXPORT_DLL const char* lpaCoreGetLogLevelName(LpaLogLevel logLevel, bool* ptrIsFound) +{ + return _lpaCoreGetLogLevelName(logLevel, ptrIsFound); +} + + +////////////////////////////////////////////// +// Default implementation +////////////////////////////////////////////// + +void _lpaCoreSetLogLevel(LpaLogLevel logLevel) +{ + _logLevel = logLevel; +} + +LpaLogLevel _lpaCoreGetLogLevel(void) +{ + return _logLevel; +} + +bool _lpaCoreSetLogMaxSize(long logMaxSize) +{ + bool res = false; + + if (logMaxSize > MIN_LOG_MAX_SIZE) + { + _lpaLogFileMaxSize = logMaxSize; + res = true; + } + + return res; +} + +long _lpaCoreGetLogMaxSize() +{ + return _lpaLogFileMaxSize; +} + +void _lpaCoreActivateLogLimitation(bool activated) +{ + _logLimitationActivated = activated; +} + +void _lpaCoreManageLogFileSize() +{ + if (_logFile != NULL && _logLimitationActivated) + { + static size_t checkCounter = 0; + + checkCounter++; + if (checkCounter > 5) + { + // do check all 5 call + checkCounter = 0; + + // Check file size + struct stat statLogFile; + memset(&statLogFile, 0x00, sizeof(struct stat)); + + bool getFileSize = false; + +#ifdef LPA_SDK__PLATFORM_WIN + + int descriptorFile = _fileno(_logFile); + + if (descriptorFile != -1 && fstat(descriptorFile, &statLogFile) >= 0) + getFileSize = true; +#else + // Special code for Linux (Warning: fileno() is POSIX, not C99!! +#if defined(__POSIX_VISIBLE) && (__POSIX_VISIBLE > 0) + if (fstat(fileno(_logFile), &statLogFile) >= 0) + getFileSize = true; +#else + // Works fine under Cygwin, TBV for other platforms + if (stat(_logFileName, &statLogFile) >= 0) + getFileSize = true; + +#endif // __POSIX_VISIBLE +#endif // LPA_SDK__PLATFORM_WIN + + if (getFileSize) + { + // File exist => check size + if (statLogFile.st_size > _lpaLogFileMaxSize) + { + fclose(_logFile); + _logFile = NULL; + + if (stat(_backupLogFileName, &statLogFile) >= 0) + { + remove(_backupLogFileName); + } + + if (rename(_logFileName, _backupLogFileName) != 0) + { + fprintf(stderr, "Unable to rename log file (errno=%d)!", errno); + + // Unable to rename file => reopen it but content is lost + _logFile = fopen(_logFileName, "wt"); + } + else + { + // log file renamed successfully + _logFile = fopen(_logFileName, "at"); + } + } + } + } + } +} + +void _lpaCoreLogOpen( const char* ptrFileName, const char* prtBackupFileName) +{ + if( _logFile == NULL ) + { + if (ptrFileName != NULL && prtBackupFileName != NULL && strlen(ptrFileName) < LPA_MAX_PATH && strlen(ptrFileName) < LPA_MAX_PATH) + { + // Save log file name & backup log file name + snprintf(_logFileName, LPA_MAX_PATH, "%s", ptrFileName); + snprintf(_backupLogFileName, LPA_MAX_PATH, "%s", prtBackupFileName); + + // Check file size + struct stat statLogFile; + + if (_logLimitationActivated && stat(ptrFileName, &statLogFile) >= 0) + { + // File exist => check size + if (statLogFile.st_size > _lpaLogFileMaxSize) + { + if (stat(prtBackupFileName, &statLogFile) >= 0) + { + remove(prtBackupFileName); + } + + if (rename(ptrFileName, prtBackupFileName) != 0) + fprintf(stderr, "Unable to rename log file (errno=%d)!", errno); + } + } + + _logFile = fopen(ptrFileName, "at"); + } + } + else + { + // Log file already opened + } +} + +bool _lpaCoreLogIsOpened() +{ + return (_logFile != NULL); +} + +void _lpaCoreLogFlush() +{ + if( _logFile != NULL ) + fflush(_logFile); +} + +void _lpaCoreLogAppend(LpaLogLevel logLevel, const char* ptrMessage, va_list argptr) +{ + bool not_big_logging = true; + + if (_logFile != NULL && logLevel >= _logLevel && ptrMessage != NULL) + { + time_t rawTime; + struct tm *infoTime = NULL; + int formattedStringSize = 0; + va_list argptrClone; + + // Buffers reset + memset(_bufferTimeFormatting, 0, sizeof(_bufferTimeFormatting)); + memset(_bufferMessageFormatting, 0, sizeof(_bufferMessageFormatting)); + + // Manage header message + ///////////////////////////// + + // manage time formatting + time(&rawTime); + infoTime = localtime(&rawTime); + strftime(_bufferTimeFormatting, sizeof(_bufferTimeFormatting), "%d/%m/%Y %H:%M:%S", infoTime); + + // Manage message formatting + ///////////////////////////// + + va_copy(argptrClone, argptr); + formattedStringSize = vsnprintf(_bufferMessageFormatting, sizeof(_bufferMessageFormatting) - 1, ptrMessage, argptrClone); + va_end(argptrClone); + + // Check if line to log exceeds normal buffer. If yes try to allocate a bigger buffer and retrieve log inside + if(formattedStringSize > (LOG_NORMAL_MESSAGE_LINE_SIZE - 1)) + { + int bigFormattedStringSize = formattedStringSize + 1; // + End of string + + // Check not exceed maximum allowed + if(bigFormattedStringSize > LOG_MAXIMUM_MESSAGE_LINE_SIZE) + bigFormattedStringSize = LOG_MAXIMUM_MESSAGE_LINE_SIZE; + + char * bigBufferMessageFormatting = lpaCoreMemoryAlloc(bigFormattedStringSize); + + // If data buffer cannot be allocated, will return to log on one truncated line, size limited to LOG_NORMAL_MESSAGE_LINE_SIZE + if(bigBufferMessageFormatting != NULL) + { + not_big_logging = false; + + // Write header part - Done here to avoid log interleave with Memory allocation log + fprintf(_logFile, "%s | %s", _bufferTimeFormatting, _lpaCoreGetLogLevelName(logLevel, NULL)); + + // Manage message formatting + formattedStringSize = vsnprintf(bigBufferMessageFormatting, bigFormattedStringSize, ptrMessage, argptr); + + if (formattedStringSize > 0 ) + fprintf(_logFile, " | %s\n", bigBufferMessageFormatting); + else + fprintf(_logFile, " | ---Unable to format message --- \n"); + + // Big buffer cleanup + lpaCoreMemoryFree(bigBufferMessageFormatting); + bigBufferMessageFormatting = NULL; + } + } + + // Perform logging of normal buffer if not been done by big one due to memory problem + if(not_big_logging) + { + // Write header part - Done here to avoid log interleave with Memory allocation log + fprintf(_logFile, "%s | %s", _bufferTimeFormatting, _lpaCoreGetLogLevelName(logLevel, NULL)); + + if (formattedStringSize > 0 ) + fprintf(_logFile, " | %s\n", _bufferMessageFormatting); + else + fprintf(_logFile, " | ---Unable to format message --- \n"); + } + + // In first release, flush automatically each log entry + fflush(_logFile); + + _lpaCoreManageLogFileSize(); + } +} + + +/** + * Log text in log file, in multiple lines - This functions does not support formatting characters + * @param logLevel Log level to apply on log item + * @param ptrHeaderMessage Message header to write in log + * @param ptrLongTextToLog Pointer on long text to log in log file + * @param LongTextToLogSize Long text to log size + */ + +void _lpaCoreLogAppendLongText(LpaLogLevel logLevel, const char* ptrHeaderMessage, const char* ptrLongTextToLog, const size_t LongTextToLogSize) +{ + if (_logFile != NULL && logLevel >= _logLevel && ptrHeaderMessage != NULL && ptrLongTextToLog != NULL && LongTextToLogSize > 0) + { + const char* logLevelName = _lpaCoreGetLogLevelName(logLevel, NULL); + + time_t rawTime; + struct tm *infoTime = NULL; + + // manage time formatting + time(&rawTime); + infoTime = localtime(&rawTime); + strftime(_bufferTimeFormatting, sizeof(_bufferTimeFormatting), "%d/%m/%Y %H:%M:%S", infoTime); + + // Log Header + fprintf(_logFile, "%s | %s | %s\n", _bufferTimeFormatting, logLevelName, ptrHeaderMessage); + + size_t currentPositionInText = 0; + size_t currentPositionInLine = 0; + + while(currentPositionInText < LongTextToLogSize) + { + // Start a new line, print new line header + if(currentPositionInLine == 0) + { + fprintf(_logFile, "%s | %s | ", _bufferTimeFormatting, logLevelName); + } + + // Print text character in current log line + fprintf(_logFile, "%c", *(ptrLongTextToLog + currentPositionInText)); + + currentPositionInText++; + currentPositionInLine++; + + // Check end of log line reached, if yes go to the next line and flush current line + if(currentPositionInLine > LOG_NORMAL_MESSAGE_LINE_SIZE) + { + fprintf(_logFile, "\n"); + currentPositionInLine = 0; + + fflush(_logFile); + } + } + + // Terminate last line, only if not already done + if(currentPositionInLine > 0) + fprintf(_logFile, "\n"); + + fflush(_logFile); + _lpaCoreManageLogFileSize(); + } +} + + +void _lpaCoreLogAppendByteArray(LpaLogLevel logLevel, const char* ptrMessage, const char* ptrByteArrayName, unsigned char* ptrByteArray, size_t byteArraySize) +{ + if (_logFile != NULL && logLevel >= _logLevel) + { + if (ptrMessage != NULL) + { + // Write message in first + lpaCoreLogAppend(logLevel, ptrMessage); + } + + if (ptrByteArray != NULL && byteArraySize > 0 && ptrByteArrayName != NULL ) + { + + // Write Byte array (one or more bloc) + size_t maxBytesByBlocK = sizeof(_bufferMessageFormatting) / 4; + size_t offsetByteArray = 0; + + time_t rawTime; + struct tm *infoTime = NULL; + const char* logLevelName = _lpaCoreGetLogLevelName(logLevel, NULL); + + while (offsetByteArray < byteArraySize) + { + size_t currentBlockSize = ((offsetByteArray + maxBytesByBlocK) < byteArraySize ? maxBytesByBlocK : (byteArraySize - offsetByteArray)); + + // manage time formatting + time(&rawTime); + infoTime = localtime(&rawTime); + strftime(_bufferTimeFormatting, sizeof(_bufferTimeFormatting), "%d/%m/%Y %H:%M:%S", infoTime); + + if (currentBlockSize > 1) + { + snprintf(_bufferMessageFormatting, sizeof(_bufferMessageFormatting), "%s [%llu-%llu]: ", ptrByteArrayName, (long long unsigned)offsetByteArray, (long long unsigned)(offsetByteArray + currentBlockSize - 1)); + fprintf(_logFile, "%s | %s | %s", _bufferTimeFormatting, logLevelName, _bufferMessageFormatting); + + + // Manage data + for (size_t offset = 0; offset < currentBlockSize; offset++) + fprintf(_logFile, " %02X", ptrByteArray[offsetByteArray + offset]); + + fprintf(_logFile, "\n"); + } + else + { + snprintf(_bufferMessageFormatting, sizeof(_bufferMessageFormatting), "%s [%llu]: %02X", ptrByteArrayName, (long long unsigned)offsetByteArray, ptrByteArray[offsetByteArray]); + fprintf(_logFile, "%s | %s | %s \n", _bufferTimeFormatting, logLevelName, _bufferMessageFormatting); + } + + fflush(_logFile); + + offsetByteArray += currentBlockSize; + } + + _lpaCoreManageLogFileSize(); + } + } +} + +void _lpaCoreLogClose() +{ + if( _logFile != NULL ) + { + fclose(_logFile); + _logFile = NULL; + } +} + +bool lpaCoreSetLogLevelString(const char* logLevelString) +{ + bool res = false; + + if (logLevelString != NULL) + { + size_t index = 0; + + while ( !res && _logLevelInfoList[index].logLevelName != NULL) + { + if ( _isLogLevelMatching(logLevelString, _logLevelInfoList[index].logLevelName)) + { + if (_logLevelInfoList[index].selectable) + { + if (_logLevel != _logLevelInfoList[index].logLevel) + { + + lpaCoreLogAppend(SDK_LOG_LEVEL_SYSTEM, "Updating log level to '%s' ( '%s' previously)", + _lpaCoreGetLogLevelName(_logLevelInfoList[index].logLevel, NULL), + _lpaCoreGetLogLevelName(_logLevel, NULL)); + _logLevel = _logLevelInfoList[index].logLevel; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_SYSTEM, "Log level already to '%s'", _lpaCoreGetLogLevelName(_logLevel, NULL)); + + res = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_SYSTEM, "Unable to select '%s' log level (internal usage only)", + _lpaCoreGetLogLevelName(_logLevelInfoList[index].logLevel, NULL)); + break; + } + else + index++; + } + } + + return res; +} + + +const char* _lpaCoreGetLogLevelName(LpaLogLevel logLevel, bool* ptrIsFound) +{ + char* ptrLogLevelName = "??"; + bool isFound = false; + size_t index = 0; + + while (!isFound && _logLevelInfoList[index].logLevelName != NULL) + { + if (logLevel == _logLevelInfoList[index].logLevel) + { + ptrLogLevelName = _logLevelInfoList[index].logLevelName; + isFound = true; + break; + } + else + index++; + } + + if (ptrIsFound != NULL) + *ptrIsFound = isFound; + + return ptrLogLevelName; +} + +bool _isLogLevelMatching(const char* ptrLogLevel, const char* ptrLogLevelRef ) +{ + if (ptrLogLevel == NULL || ptrLogLevelRef == NULL || strlen(ptrLogLevel) < strlen(ptrLogLevelRef)) + return false; + + size_t stringSize = strlen(ptrLogLevelRef); + for (size_t index = 0; index < stringSize; index++) + { + if (tolower(ptrLogLevel[index]) != tolower(ptrLogLevelRef[index])) + return false; + } + return true; +} + + + diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/lpa_manager.c b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/lpa_manager.c new file mode 100755 index 000000000..799e1813c --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/lpa_manager.c @@ -0,0 +1,8064 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#include "lpasdk/lpasdk_internal_api.h" + +#include "lpasdk/core/lpa_manager_api.h" // For main API +#include "lpasdk/core/lpa_manager.h" // For main API +#include "lpasdk/core/isdr_applet_manager.h" + +#include "lpasdk/core/lpa_log.h" +#include "lpasdk/core/lpa_memory.h" +#include "lpasdk/core/semedia_manager.h" +#include "lpasdk/core/httpmedia_manager.h" +#include "lpasdk/core/bertlv_object.h" +#include "lpasdk/core/util.h" +#include "lpasdk/core/lpa_core.h" +#include "lpasdk/core/lpa_manager_helper.h" + +#include "lpasdk/core/lpa_manager_es9plus.h" +#include "lpasdk/core/lpa_manager_es10b.h" +#include "lpasdk/core/lpa_manager_es10c.h" + +#include "cJSON/cJSON.h" +#include "sha256/sha-256.h" + +#include +#include + +#define DEFAULT_SE_MEDIA_READER_NAME "" +#define DEFAULT_CERTIFICATE_NAME "/sdcard/mmcblk0p1/GSMA_CE_LIVE_CI.crt" +#define DEFAULT_DEVICE_SMDS_ADDRESS "" +#define DEFAULT_DEVICE_DEFAULT_SMDP_ADDRESS "" +#define BYPASS_DEFAULT_USER_CONSENT_WITH_NO_PPR false // If set to true bypass default user consent when no PPR involved +#define SUPPORT_DOWNLOAD_OF_PROFILES_WITH_PPR true // If set to false download of profiles with PPR will be not allowed + +#define DER_ATTRIBUTE_TAG 0x80 +#define SEQUENCE_TAG 0xA0 +#define NOTIFICATION_METADATA_TAG 0xBF2F + +#define ASN1_PRIMITIVE_ATTRIBUTE_TAG 0x80 +#define ASN1_CONSTRUCTED_ATTRIBUTE_TAG 0xA0 + +#define ASN1_SMDPSIGNED2_TAG 0x30 +#define ASN1_CCREQUIREDFLAG_TAG 0x01 + +#define LIST_NOTIFICATION_TAG 0xBF28 +#define REMOVE_NOTIFICATION_FROM_LIST_TAG 0xBF30 +#define RETRIEVE_NOTIFICATIONS_LIST_TAG 0xBF2B + +#define PROFILE_METADATA_TAG 0xBF25 +#define EUICC_RAT_TAG 0xBF43 + + +// Memory stress parameters +#define LPA_SDK_CONFIG_PARAM_MEM_ERR_IF_MEM_COUNTER_EQ "MEM_ERR_IF_MEM_COUNTER_EQ" +#define LPA_SDK_CONFIG_PARAM_MEM_ERR_IF_MEM_COUNTER_GT "MEM_ERR_IF_MEM_COUNTER_GT" +#define LPA_SDK_CONFIG_PARAM_MEM_ERR_IF_MEM_COUNTER_GE "MEM_ERR_IF_MEM_COUNTER_GE" + +#define LPA_SDK_CONFIG_PARAM_MEM_ERR_IF_SIZE_REQUESTED_EQ "MEM_ERR_IF_SIZE_REQUESTED_EQ" +#define LPA_SDK_CONFIG_PARAM_MEM_ERR_IF_SIZE_REQUESTED_GT "MEM_ERR_IF_SIZE_REQUESTED_GT" +#define LPA_SDK_CONFIG_PARAM_MEM_ERR_IF_SIZE_REQUESTED_GE "MEM_ERR_IF_SIZE_REQUESTED_GE" + + +// SE Media +static char _seMediaReaderName[LPA_CFG_READER_NAME_MAX_SIZE]; + +// Device information +static char _deviceInfo[LPA_CFG_DEVICE_INFO_TLV_MAX_SIZE]; +static unsigned char _deviceInfoByteArray[LPA_CFG_DEVICE_INFO_TLV_BYTE_ARRAY_MAX_SIZE]; +static size_t _deviceInfoByteArraySize = 0; +static bool _deviceCapabilitiesFilter = true; // true = filtering enabled + +static bool _initializeDone = false; +static char _bufferFormatLogMessage[1024]; // 1Ko is enough (to increase it, use dynamic memory allocation) +static char _lpaFolder[LPA_MAX_PATH]; + +#define LPA_MANAGER_DATA_BUFFER_MAX_SIZE MAX_LPA_MANAGER_APDU_BUFFER_SIZE +static unsigned char _dataBuffer[LPA_MANAGER_DATA_BUFFER_MAX_SIZE]; // For managing data from/to SE Media + +static bool _sendPIRDuringDownloadProfileOperation = true; + +// Definition alternate SM-DP+ and SM-DS address. Constant used for max size also include end of string. +static char _deviceSMDSaddress[LPA_SMDS_ADDRESS_SIZE]; +static char _deviceDefaultSMDPaddress[LPA_SMDP_ADDRESS_SIZE]; + +static bool _bypassDefaultUserConsentWithNoPPR = BYPASS_DEFAULT_USER_CONSENT_WITH_NO_PPR; // If set to true bypass default user consent when no PPR involved +static bool _supportDownloadOfProfilesWithPPR = SUPPORT_DOWNLOAD_OF_PROFILES_WITH_PPR; // If set to false download of profiles with PPR will be not allowed + +// for sending Event to Application +//////////////////////////////////////////// + +typedef struct +{ + // LPA SDK event parameter + void* _appParameter; + LPA_EVENT_EXECUTION_ERROR _lpaEventExecutionError; +} APP_EVENT_EXECUTION_ERROR_CALLBACK; + +static APP_EVENT_EXECUTION_ERROR_CALLBACK _appEventExecutionErrorCallback; + +void _registerAppEventExecutionCallback(const LPA_EventCallback* ptrEventCallback); +void _unregisterAppEventExecutionCallback(); + +#ifdef LPA_SDK__USING_EX_API +static bool _isExtendedApiActivated = true; +#else +static bool _isExtendedApiActivated = false; +#endif + +// PARAMETERS LIST DEFINITIONS +typedef enum +{ + PARAM_ID_READER_NAME = 1, + PARAM_ID_SEND_PIR_DURING_DOWNLOAD_PROFILE, + PARAM_ID_ADD_LE_TO_APDU_CASE_4, + PARAM_ID_LOG_LEVEL, + PARAM_ID_LOG_MAX_SIZE, + + // Profile Mangement + PARAM_ID_PROFILE_REFRESH_FLAG, + + // CURL part (httpMedia) + PARAM_ID_ACTIVATE_CURL_DEBUG_MODE, + PARAM_ID_CURL_SSL_SSL_VERIFYPEER, + PARAM_ID_CURL_SSL_SSL_VERIFYHOST, + PARAM_ID_CURL_CONNECT_TIMEOUT, + PARAM_ID_CURL_TIMEOUT, + + PARAM_ID_CERT_PATH, + PARAM_ID_CONFIG_DEVICE_INFO_TLV, + + + // Memory stress parameters + PARAM_ID_MEM_ERR_IF_MEM_COUNTER_EQ, + PARAM_ID_MEM_ERR_IF_MEM_COUNTER_GT, + PARAM_ID_MEM_ERR_IF_MEM_COUNTER_GE, + + PARAM_ID_MEM_ERR_IF_SIZE_REQUESTED_EQ, + PARAM_ID_MEM_ERR_IF_SIZE_REQUESTED_GT, + PARAM_ID_MEM_ERR_IF_SIZE_REQUESTED_GE, + + PARAM_ID_DEVICE_CAPABILITIES_FILTERING, + + PARAM_ID_DEVICE_SMDS_ADDRESS, + PARAM_ID_DEVICE_DEFAULT_SMDP_ADDRESS, + + PARAM_ID_BYPASS_USER_CONSENT_WITH_NO_PPR, + PARAM_ID_SUPPORT_DOWNLOAD_PROFILES_WITH_PPR, + + // Latest entry + PARAM_ID_NONE = 999 +} LPA_PARAMETER_ID; + +typedef struct +{ + LPA_PARAMETER_ID parameterId; + char* parameterName; + LPA_PARAMETER_TYPE parameterType; + bool isRestricted; // If yes, only available when using LPA_SDK__USING_EX_API build option +} LPA_PARAMETER_DEFINITION; + +// PARAMETERS LIST BUILD +// NOTES: String constants defining names of parameters in second position are located in lpa_manager_api.h +// true / false flag at the end defines a restriction mode. If true this parameter will be only usable when compiled / running in Extended API Mode +static LPA_PARAMETER_DEFINITION _lpaParameterDefinitionList[] = +{ + { PARAM_ID_READER_NAME, LPA_SDK_CONFIG_PARAM_READER_NAME, LPA_PARAMETER_TYPE_STRING, false }, + { PARAM_ID_SEND_PIR_DURING_DOWNLOAD_PROFILE, LPA_SDK_CONFIG_PARAM_SEND_PIR_DURING_DOWNLOAD_PROFILE, LPA_PARAMETER_TYPE_BOOL, true }, + + { PARAM_ID_ACTIVATE_CURL_DEBUG_MODE, LPA_SDK_CONFIG_PARAM_ACTIVATE_CURL_DEBUG_MODE, LPA_PARAMETER_TYPE_BOOL, true }, + { PARAM_ID_CURL_SSL_SSL_VERIFYPEER, LPA_SDK_CONFIG_PARAM_CURL_SSL_SSL_VERIFYPEER, LPA_PARAMETER_TYPE_BOOL, true }, + { PARAM_ID_CURL_SSL_SSL_VERIFYHOST, LPA_SDK_CONFIG_PARAM_CURL_SSL_SSL_VERIFYHOST, LPA_PARAMETER_TYPE_BOOL, true }, + { PARAM_ID_ADD_LE_TO_APDU_CASE_4, LPA_SDK_CONFIG_PARAM_ADD_LE_TO_APDU_CASE_4, LPA_PARAMETER_TYPE_BOOL, false }, + + { PARAM_ID_LOG_LEVEL, LPA_SDK_CONFIG_PARAM_LOG_LEVEL, LPA_PARAMETER_TYPE_STRING, false }, + { PARAM_ID_LOG_MAX_SIZE, LPA_SDK_CONFIG_PARAM_LOG_MAX_SIZE, LPA_PARAMETER_TYPE_LONG, false }, + { PARAM_ID_PROFILE_REFRESH_FLAG, LPA_SDK_CONFIG_PARAM_PROFILE_REFRESH_FLAG, LPA_PARAMETER_TYPE_BOOL, false }, + + { PARAM_ID_CURL_CONNECT_TIMEOUT, LPA_SDK_CONFIG_PARAM_CURL_CONNECT_TIMEOUT, LPA_PARAMETER_TYPE_LONG, false }, + { PARAM_ID_CURL_TIMEOUT, LPA_SDK_CONFIG_PARAM_CURL_TIMEOUT, LPA_PARAMETER_TYPE_LONG, false }, + + { PARAM_ID_CERT_PATH, LPA_SDK_CONFIG_PARAM_CERT_PATH, LPA_PARAMETER_TYPE_STRING, false }, + { PARAM_ID_CONFIG_DEVICE_INFO_TLV, LPA_SDK_CONFIG_PARAM_DEVICE_INFO_TLV, LPA_PARAMETER_TYPE_STRING, false }, + { PARAM_ID_DEVICE_CAPABILITIES_FILTERING, LPA_SDK_CONFIG_PARAM_DEVICE_CAPABILITIES_FILTERING, LPA_PARAMETER_TYPE_BOOL, false }, + + { PARAM_ID_DEVICE_SMDS_ADDRESS, LPA_SDK_CONFIG_PARAM_DEVICE_SMDS_ADDRESS, LPA_PARAMETER_TYPE_STRING, false }, + { PARAM_ID_DEVICE_DEFAULT_SMDP_ADDRESS, LPA_SDK_CONFIG_PARAM_DEVICE_DEFAULT_SMDP_ADDRESS, LPA_PARAMETER_TYPE_STRING, false }, + + { PARAM_ID_BYPASS_USER_CONSENT_WITH_NO_PPR, LPA_SDK_CONFIG_PARAM_BYPASS_DEFAULT_USER_CONSENT_WITH_NO_PPR, LPA_PARAMETER_TYPE_BOOL, false }, + { PARAM_ID_SUPPORT_DOWNLOAD_PROFILES_WITH_PPR, LPA_SDK_CONFIG_PARAM_SUPPORT_DOWLOAD_PROFILES_WITH_PPR, LPA_PARAMETER_TYPE_BOOL, false }, + + // Memory stress parameters. Not restricted to allow to use them also out of Extended mode. Access not authorized if LPA_SDK__MEMORY is not set. + { PARAM_ID_MEM_ERR_IF_MEM_COUNTER_EQ, LPA_SDK_CONFIG_PARAM_MEM_ERR_IF_MEM_COUNTER_EQ, LPA_PARAMETER_TYPE_LONG, false }, + { PARAM_ID_MEM_ERR_IF_MEM_COUNTER_GT, LPA_SDK_CONFIG_PARAM_MEM_ERR_IF_MEM_COUNTER_GT, LPA_PARAMETER_TYPE_LONG, false }, + { PARAM_ID_MEM_ERR_IF_MEM_COUNTER_GE, LPA_SDK_CONFIG_PARAM_MEM_ERR_IF_MEM_COUNTER_GE, LPA_PARAMETER_TYPE_LONG, false }, + + { PARAM_ID_MEM_ERR_IF_SIZE_REQUESTED_EQ, LPA_SDK_CONFIG_PARAM_MEM_ERR_IF_SIZE_REQUESTED_EQ, LPA_PARAMETER_TYPE_LONG, false }, + { PARAM_ID_MEM_ERR_IF_SIZE_REQUESTED_GT, LPA_SDK_CONFIG_PARAM_MEM_ERR_IF_SIZE_REQUESTED_GT, LPA_PARAMETER_TYPE_LONG, false }, + { PARAM_ID_MEM_ERR_IF_SIZE_REQUESTED_GE, LPA_SDK_CONFIG_PARAM_MEM_ERR_IF_SIZE_REQUESTED_GE, LPA_PARAMETER_TYPE_LONG, false }, + + // Latest entry : do not remove it!!!! + { PARAM_ID_NONE, NULL, LPA_PARAMETER_TYPE_BOOL, false } +}; + +bool _lpaManagerGetBooleanParameterValue(LPA_PARAMETER_ID parameterId, bool* ptrParameterValue); +bool _lpaManagerSetBooleanParameterValue(const LPA_PARAMETER_DEFINITION * ptrParameterDefinition, bool parameterValue); + +bool _lpaManagerGetLongParameterValue(LPA_PARAMETER_ID parameterId, long* ptrParameterValue); +bool _lpaManagerSetLongParameterValue(const LPA_PARAMETER_DEFINITION * ptrParameterDefinition, long parameterValue); + +bool _lpaManagerGetStringParameterValue(LPA_PARAMETER_ID parameterId, char* ptrParameterValue, size_t parameterValueMaxSize); +bool _lpaManagerSetStringParameterValue(const LPA_PARAMETER_DEFINITION * ptrParameterDefinition, const char* ptrParameterValue); + +#ifdef LPA_SDK__MEMORY +bool _lpaManagerGetLongMemoryErrorParameterValue(LPA_PARAMETER_ID parameterId, long* ptrParameterValue); +bool _lpaManagerSetLongMemoryErrorParameterValue(const LPA_PARAMETER_DEFINITION * ptrParameterDefinition, long parameterValue); +#endif // LPA_SDK__MEMORY + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool _doExtractMetadataForGetProfileNotificationList(LPA_PROFILE_NOTIFICATION_LIST* ptrProfileNotificationList, unsigned char *ptrData, size_t dataSize); +LPA_DELETE_NOTIFICATION_STATUS _doExtractClearProfileNotificationResponse(unsigned char *ptrData, size_t dataSize); +LPA_NOTIFICATION_EVENT _doExtractNotificationEventValue(unsigned char* ptrDataValue, size_t dataLength); +bool _retrieveNotificationData(uint16_t sequenceNumber, RawDataObject* ptrRawDataNotification); +bool _sendNotificationToServer(const LPA_PROFILE_NOTIFICATION_METADATA* ptrProfileNotificationMetadata, const RawDataObject* ptrRawDataNotification, const LPA_EventCallback* ptrLpaEventCallback); +bool _extractNotificationData(const unsigned char* ptrDataBuffer, size_t dataBufferSize, RawDataObject* ptrRawDataNotification); +bool _sortNotificationList(LPA_PROFILE_NOTIFICATION_LIST * ptrNotificationList); +bool _copyNotificationListElement(LPA_PROFILE_NOTIFICATION_METADATA * ptrSource, LPA_PROFILE_NOTIFICATION_METADATA * ptrDestination); +bool _decodeActivationCodeStr(const char* ptrActivationCodeStr, ACTIVATION_CODE* ptrActivationCode); + +bool _processGetSMserverAddress(ADDRESS_DATA* ptrAddressData, bool isSMDPserver); +bool _getEUICCconfiguredAddresses(RawDataObject* ptrRawDataEuiccAddr); +LPA_PARAMETER_DEFINITION* _getParameterDefinition(const char* ptrParameterName); +void _sendEventCallbackProgressText(const LPA_EventCallback*, size_t eventType, const char* ptrText); +void _sendEventCallbackProgressValue(LPA_EventCallback*, size_t eventType, size_t valueMin, size_t currentValue, size_t valueMax); +bool _verifySMDPAddress(const char* ptrSmdpAddress, const char* ptrServerSignedTLV, size_t serverSignedTLVSize); +bool _handleNotification(const char* ptrSmdpAddr, size_t smdpAddrSize, const unsigned char* ptrPendingNotification, const LPA_EventCallback* ptrLpaEventCallback, bool* ptrNormalNotifAcknowledge); + +void _notifyAppliOwnerCancelResult(const LPA_EventCallback* ptrLpaEventCallback, const bool cancelResult, size_t callbackEventType); +static bool _manageDownloadProfile(const char * ptrActivationCodeStr, const char * ptrConfirmationCodeStr, const int confirmationCodeLength, + const LPA_EventCallback* ptrLpaEventCallback, LPA_DOWNLOAD_PROFILE_RESULT* ptrDownloadProfileResult, bool * retryRequested); +bool _performProfileDownloadFromDefaultAddress(const LPA_EventCallback* ptrLpaEventCallback, const char* pSmdpAddr, const size_t pSmdpAddrSize, + const char* pEventID, LPA_DOWNLOAD_PROFILE_RESULT* ptrDownloadProfileResult, const bool requestFromDefaultSMDPload, bool * retryRequested); + +//work with server +bool _lpaManagerAuthenticateClient(ptr_serverData p_serverData, const LPA_EventCallback* ptrLpaEventCallback, const char* ptrSmdpAddress, const unsigned char* ptrAuthenticateServerResponse); +bool _lpaManagerInitiateAuthentication(ptr_serverData p_serverData, const LPA_EventCallback* ptrLpaEventCallback, const char * ptrEuiccChallenge, const char * ptrEuiccInfo1, const char* ptrSmdpAddress); +bool _lpaManagerGetBoundProfilePackage(ptr_serverData p_serverData, const LPA_EventCallback* ptrLpaEventCallback, const char* ptrSmdpAddress, const unsigned char* ptrPrepareDownloadResponse, bool * cancelForBPPerrors); + +bool _lpaManagerGetEuiccChallenge(LPA_GET_EUICC*); +bool _lpaManagerGetEuiccInfoWithRetry(const unsigned short eUICCinfoTag, LPA_GET_EUICC* ptrGetEUICC); +bool _lpaManagerGetFlag_deviceInfoExtensibilitySupport(const LPA_GET_EUICC* ptrEUICCInfo2, bool* ptrDeviceInfoExtensibilitySupport); +bool _lpaManagerFilterDeviceCapabitilitiesInformation(const unsigned char * ptrRawDeviceInfo, const size_t rawDeviceInfoSize, + unsigned char * ptrFilteredDeviceInfo, size_t * ptrFilteredDeviceInfoSize, const size_t maxFilteredDeviceInfoSize, const bool deviceInfoExtensibilitySupport, + const bool deviceInfoFilteringEnabled); +bool _lpaManagerAuthenticateServer(ptr_serverData, const LPA_EventCallback* ptrLpaEventCallback, RawDataObject *, AUTHENTICATE_SERVER_RESPONSE*); +bool _lpaManagerPrepareDownload(ptr_serverData, const LPA_EventCallback* ptrLpaEventCallback, const char * ptrStringHashCC, PREPARE_DOWNLOAD_RESPONSE*); + +//matching id+deviceinfoTlv +bool _lpaManagerPrepareCtxParam(const char* ptrMatchingId, const unsigned char* ptrDeviceInfoTlv, size_t deviceInfoTlvSize, RawDataObject **); +bool _lpaManagerCancelSession(const char * transactionID, const unsigned int p_reasonCode, const char* ptrSmdpAddress, const LPA_EventCallback* ptrLpaEventCallback); + +bool _lpaManagerInitServerData(ptr_serverData p_serverData, bool initTransactionID); +bool _lpaManagerFreeServerData(ptr_serverData p_serverData, bool clearTransactionID); + +bool _extractFieldsFromProfileMetadata(const unsigned char * ptrProfileMetadata, const size_t profileMetadataSize, + LPA_DOWNLOADED_PROFILE_DATA_FOR_PPR * ptrProfileFieldsForPPR, LPA_EVENT_INCOMING_PROFILE_INFORMATION * ptrProfileFieldsForInfo); +bool _getProfilesInfoForPPR(LPA_GET_PROFILES_INFO* ptrLpaGetProfilesInfo); +bool _isPPR1definedInPPRflag(const unsigned int pprFlag); +bool _isPPR2definedInPPRflag(const unsigned int pprFlag); +bool _lpaManagerGetRAT(RawDataObject ** ptrGetRAT); +bool _checkIncomingProfilePPRconditionVersusInstalledProfiles(LPA_DOWNLOADED_PROFILE_DATA_FOR_PPR* ptrIncomingProfileData, + const LPA_GET_PROFILES_INFO * ptrCurrentlyInstalledProfiles); +bool _checkIncomingProfilePPRattributesVersusRAT(LPA_DOWNLOADED_PROFILE_DATA_FOR_PPR* ptrIncomingProfileData, const RawDataObject* ptrRATrules); +bool _analysePPARversusProfileAttribute(BeerTLV * ptrPPARrule, LPA_DOWNLOADED_PROFILE_DATA_FOR_PPR * ptrIncomingProfileData, LPA_PPR_RAT_ANALYSIS_FLAGS * ptrCheckPPR1, + LPA_PPR_RAT_ANALYSIS_FLAGS * ptrCheckPPR2); +bool _analysePPARallowedOperatorVersusProfile(LPA_DOWNLOADED_PROFILE_DATA_FOR_PPR * ptrIncomingProfileData, LPA_PPR_RAT_ANALYSIS_FLAGS * ptrCheckPPR, + BeerTLV * berAllowedOperators, const bool consentRequiredFlag); +bool _comparePPARallowedOperator_MCC_MNC(const unsigned char * ptrAllowOpMCCMNC, const unsigned char * ptrProfileMCCMNC, bool * ptrMatchingFlag, int * ptrMatchinglevel); + +void* _hookForJSONAlloc(size_t size); +void _hookForJSONFree(void* ptrMemoryBlock); + +// register EventError callback +void _lpaManagerEventExecutionErrorCallback(const void* ptrAppParameter, const LPA_EVENT_EXECUTION_ERROR_INFO* ptrEventExecutionErrorInfo); + +void* _hookForJSONAlloc(size_t size) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "CJSON Alloc(%llu bytes)", (unsigned long long)size); + + return lpaCoreMemoryAlloc(size); +} + +void _hookForJSONFree(void* ptrMemoryBlock) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "CJSON Free(%08lX)", ptrMemoryBlock); + lpaCoreMemoryFree(ptrMemoryBlock); +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool lpaManagerInitialize(const char* ptrLpaFolder) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaManagerInitialize(...)"); + + if (!_initializeDone) + { + if (ptrLpaFolder != NULL) + { + // Update default seMediaReaderName and save lpaFolder + if (snprintf(_seMediaReaderName, sizeof(_seMediaReaderName), "%s", DEFAULT_SE_MEDIA_READER_NAME) < sizeof(_seMediaReaderName) && + snprintf(_lpaFolder, sizeof(_lpaFolder), "%s", ptrLpaFolder) < sizeof(_lpaFolder)) + { + _initializeDone = true; + } + + // Device info + memset(_deviceInfo, 0, sizeof(_deviceInfo)); + memset(_deviceInfoByteArray, 0, sizeof(_deviceInfoByteArray)); + _deviceInfoByteArraySize = 0; + + // Alternate SM-DP+ and SM-DS address - For memories value returned by snprintf() does not include EOS + // If values defined in DEFAULT_DEVICE_SMDS_ADDRESS or DEFAULT_DEVICE_DEFAULT_SMDP_ADDRESS are too long, empty value will be used + if (snprintf(_deviceSMDSaddress, sizeof(_deviceSMDSaddress), "%s", DEFAULT_DEVICE_SMDS_ADDRESS) >= sizeof(_deviceSMDSaddress)) + memset(_deviceSMDSaddress, 0, sizeof(_deviceSMDSaddress)); + if (snprintf(_deviceDefaultSMDPaddress, sizeof(_deviceDefaultSMDPaddress), "%s", DEFAULT_DEVICE_DEFAULT_SMDP_ADDRESS) >= sizeof(_deviceDefaultSMDPaddress)) + memset(_deviceDefaultSMDPaddress, 0, sizeof(_deviceDefaultSMDPaddress)); + + lpaManagerES9Plus_Init(DEFAULT_CERTIFICATE_NAME); // To initialize certPath + } + + // use cJSON Hook for using lpaMemory mechanism + cJSON_Hooks jsonHook; + jsonHook.malloc_fn = _hookForJSONAlloc; + jsonHook.free_fn = _hookForJSONFree; + cJSON_InitHooks(&jsonHook); + + // register EventError callback + _appEventExecutionErrorCallback._appParameter = NULL; + _appEventExecutionErrorCallback._lpaEventExecutionError = NULL; + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaManagerInitialize(...)"); + + return _initializeDone; +} + +//////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////// + +bool lpaManagerInitializeHttpMedia() +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaManagerInitializeHttpMedia(...)"); + + res = httpMediaManagerInitialize(); + if ( res ) + res = httpMediaManagerSetCallbackEventExecutionError(_lpaManagerEventExecutionErrorCallback); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaManagerInitializeHttpMedia(...)"); + + return res; +} + +//////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////// + +bool lpaManagerInitializeSEMedia() +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaManagerInitializeSEMedia(...)"); + + res = seMediaManagerInitialize(); + if (res) + res = seMediaManagerSetCallbackEventExecutionError(_lpaManagerEventExecutionErrorCallback); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaManagerInitializeSEMedia(...)"); + + return res; +} + +//////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////// + +bool lpaManagerSetConfigParameter(const char* ptrParameterName, LPA_PARAMETER_TYPE parameterType, const void* ptrParameterValue, bool internalCall) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaManagerSetConfigParameter(...)"); + + if (ptrParameterName != NULL && ptrParameterValue != NULL) + { + if (internalCall ) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Internal call to this function"); + + // Logging of parameter name / type / value + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Parameter key name : %s", ptrParameterName); + switch(parameterType) + { + case LPA_PARAMETER_TYPE_BOOL: + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Parameter type given : LPA_PARAMETER_TYPE_BOOL"); + // No warranty that displaying will be correct because cannot effectively check parameter value type passed as void* + const bool* ptrLogBooleanValue = ptrParameterValue; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Parameter value (Type match cannot be checked): %s", (*ptrLogBooleanValue)?"true":"false"); + } + break; + + case LPA_PARAMETER_TYPE_LONG: + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Parameter type given : LPA_PARAMETER_TYPE_LONG"); + // No warranty that displaying will be correct because cannot effectively check parameter value type passed as void* + const long* ptrLogLongValue = ptrParameterValue; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Parameter value (Type match cannot be checked): %ld", *ptrLogLongValue); + } + break; + + case LPA_PARAMETER_TYPE_STRING: + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Parameter type given : LPA_PARAMETER_TYPE_STRING"); + // No warranty that displaying will be correct because cannot effectively check parameter value type passed as void* + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Parameter value (Type match cannot be checked): %s", (const char *)ptrParameterValue); + } + break; + + default: + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Parameter type given not managed. Value will be not logged!"); + break; + } + + LPA_PARAMETER_DEFINITION *ptrParameterDefinition = _getParameterDefinition(ptrParameterName); + if (ptrParameterDefinition != NULL) + { + if (ptrParameterDefinition->isRestricted && !_isExtendedApiActivated) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Parameter key not authorized!"); + lpaSetErrorCode(LPA_ERROR_PARAMETER_NOT_AUTHORIZED); // this parameter is only available for Extended API + } + else + { + switch (ptrParameterDefinition->parameterType) + { + case LPA_PARAMETER_TYPE_BOOL: + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Parameter key identified, default type : LPA_PARAMETER_TYPE_BOOL"); + + if (parameterType == LPA_PARAMETER_TYPE_BOOL) + { + const bool* ptrParameterBooleanValue = ptrParameterValue; + res = _lpaManagerSetBooleanParameterValue(ptrParameterDefinition, *ptrParameterBooleanValue); + } + else + { + bool parameterBooleanValue = false; + if (parameterType == LPA_PARAMETER_TYPE_STRING && convertStringToBoolean((const char*)ptrParameterValue, ¶meterBooleanValue)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Conversion from STRING to BOOL performed."); + res = _lpaManagerSetBooleanParameterValue(ptrParameterDefinition, parameterBooleanValue); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Parameter type / value given is not compatible with parameter key!"); + lpaSetErrorCode(LPA_ERROR_INCORRECT_PARAMETER_TYPE); + } + } + } + break; + + case LPA_PARAMETER_TYPE_LONG: + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Parameter key identified, default type : LPA_PARAMETER_TYPE_LONG"); + + if (parameterType == LPA_PARAMETER_TYPE_LONG) + { + const long* ptrParameterLongValue = ptrParameterValue; + res = _lpaManagerSetLongParameterValue(ptrParameterDefinition, *ptrParameterLongValue); + } + else + { + long parameterLongValue = 0L; + // Added checking of length of value string, it was strange that an empty string can be converted to value zero + if (parameterType == LPA_PARAMETER_TYPE_STRING && strlen(ptrParameterValue) > 0 && convertStringToLong((const char*)ptrParameterValue, ¶meterLongValue)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Conversion from STRING to LONG performed."); + res = _lpaManagerSetLongParameterValue(ptrParameterDefinition, parameterLongValue); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Parameter type / value given is not compatible with parameter key!"); + lpaSetErrorCode(LPA_ERROR_INCORRECT_PARAMETER_TYPE); + } + } + } + break; + + case LPA_PARAMETER_TYPE_STRING: + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Parameter key identified, default type : LPA_PARAMETER_TYPE_STRING"); + + if (parameterType == LPA_PARAMETER_TYPE_STRING) + res = _lpaManagerSetStringParameterValue(ptrParameterDefinition, ptrParameterValue); + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Parameter type / value given is not compatible with parameter key!"); + lpaSetErrorCode(LPA_ERROR_INCORRECT_PARAMETER_TYPE); + } + } + break; + + default: + { + // This case shall never occurs normally, except for memory / data corruption issue + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Unknown parameter type returned from parameter list! DATA CORRUPTION ERROR CASE"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER_TYPE); + } + break; + } + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Parameter key name not identified!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + } + else + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaManagerSetConfigParameter() return %s", (res ? "true" : "false")); + return res; +} + +bool lpaManagerGetConfigParameter(const char* ptrParameterName, LPA_PARAMETER_TYPE parameterType, void* ptrParameterValue, size_t parameterValueMaxSize) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaManagerGetConfigParameter(...)"); + + if (ptrParameterName != NULL && ptrParameterValue != NULL && parameterValueMaxSize > 0) + { + // Logging of parameter name / type / value + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Parameter key name : %s", ptrParameterName); + switch(parameterType) + { + case LPA_PARAMETER_TYPE_BOOL: + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Parameter type given : LPA_PARAMETER_TYPE_BOOL"); + break; + + case LPA_PARAMETER_TYPE_LONG: + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Parameter type given : LPA_PARAMETER_TYPE_LONG"); + break; + + case LPA_PARAMETER_TYPE_STRING: + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Parameter type given : LPA_PARAMETER_TYPE_STRING"); + break; + + default: + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Parameter type given not managed, will be not displayed!"); + break; + } + + LPA_PARAMETER_DEFINITION *ptrParameterDefinition = _getParameterDefinition(ptrParameterName); + if (ptrParameterDefinition != NULL) + { + if (ptrParameterDefinition->isRestricted && !_isExtendedApiActivated) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Parameter key not authorized!"); + lpaSetErrorCode(LPA_ERROR_PARAMETER_NOT_AUTHORIZED); // this parameter is only available for Extended API + } + else + { + if (parameterType != ptrParameterDefinition->parameterType) + { + switch(ptrParameterDefinition->parameterType) + { + case LPA_PARAMETER_TYPE_BOOL: + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Parameter type given does not match parameter key default type (LPA_PARAMETER_TYPE_BOOL)"); + break; + + case LPA_PARAMETER_TYPE_LONG: + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Parameter type given does not match parameter key default type (LPA_PARAMETER_TYPE_LONG)"); + break; + + case LPA_PARAMETER_TYPE_STRING: + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Parameter type given does not match parameter key default type (LPA_PARAMETER_TYPE_STRING)"); + break; + + default: + // This case shall never occurs normally, except for memory / data corruption issue + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Unknown parameter type returned from parameter list! DATA CORRUPTION ERROR CASE"); + break; + } + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER_TYPE); + } + else + { + switch (parameterType) + { + case LPA_PARAMETER_TYPE_BOOL: + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Parameter key identified, default type : LPA_PARAMETER_TYPE_BOOL"); + + if (sizeof(bool) == parameterValueMaxSize) + res = _lpaManagerGetBooleanParameterValue(ptrParameterDefinition->parameterId, ptrParameterValue); + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Size of variable receiving value does not match value type!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER_TYPE); + } + + } + break; + + case LPA_PARAMETER_TYPE_STRING: + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Parameter key identified, default type : LPA_PARAMETER_TYPE_STRING"); + + res = _lpaManagerGetStringParameterValue(ptrParameterDefinition->parameterId, ptrParameterValue, parameterValueMaxSize); + } + break; + + case LPA_PARAMETER_TYPE_LONG: + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Parameter key identified, default type : LPA_PARAMETER_TYPE_LONG"); + + if (sizeof(long) == parameterValueMaxSize) + res = _lpaManagerGetLongParameterValue(ptrParameterDefinition->parameterId, ptrParameterValue); + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Size of variable receiving value does not match value type!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER_TYPE); + } + } + break; + + default: + { + // Normally we shall never arrive here, but leaved as security + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER_TYPE); + } + break; + } + } + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Parameter key name not identified!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + } + else + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaManagerGetConfigParameter() return %s", (res ? "true" : "false")); + return res; +} + +/** + * Check if parameter exists in parameter list, if yes return parameter type and if access is allowed out of Extended Mode + * @param ptrParameterName Pointer on parameter name to check, string type + * @param ptrParameterType Pointer on parameter type to return, LPA_PARAMETER_TYPE type + * @param ptrIsExist Pointer on boolean flag returning if parameter exists, if yes return true + * @param ptrAccessGranted Pointer on boolean flag returning true if parameter use is allowed out of Extended Mode + * @return True if no error occurred during check + */ +bool lpaManagerIsConfigParameterExist(const char* ptrParameterName, LPA_PARAMETER_TYPE* ptrParameterType, bool* ptrIsExist, bool* ptrAccessGranted) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaManagerIsConfigParameterExist(...)"); + + if (ptrParameterName != NULL && ptrParameterType != NULL && ptrIsExist != NULL) + { + *ptrIsExist = false; + *ptrParameterType = LPA_PARAMETER_TYPE_UNKNOWN; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Searching parameter key '%s'", ptrParameterName); + + LPA_PARAMETER_DEFINITION *ptrParameterDefinition = _getParameterDefinition(ptrParameterName); + if (ptrParameterDefinition != NULL) + { + *ptrIsExist = true; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Parameter key exists (isRestricted:%s)", (ptrParameterDefinition->isRestricted ? "yes" : "no")); + + *ptrParameterType = ptrParameterDefinition->parameterType; + + if (NULL != ptrAccessGranted) + *ptrAccessGranted = (!ptrParameterDefinition->isRestricted || _isExtendedApiActivated); + + res = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Parameter key does not exist."); + res = true; // Return true (Correct execution but parameter not found) + } + } + else + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaManagerIsConfigParameterExist() return %s", (res ? "true" : "false")); + + return res; +} + + +/** + * Return list of settable parameters + * @param ptrLpaParametersList List of parameters with type, LPA_PARAMETERS_LIST type. + * @return true if operation successful + */ +bool lpaManagerGetFullParametersList(LPA_PARAMETERS_LIST * ptrLpaParametersList) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaGetFullParametersList(...)"); + + if (ptrLpaParametersList != NULL) + { + memset(ptrLpaParametersList, 0, sizeof(LPA_PARAMETERS_LIST)); + ptrLpaParametersList->parametersCount = 0; + +// Re-activate code block below in case of return of this function in Normal Mode +// Deactivated because generate a warning in compiler, syntax of use of #pragma is environment dependant +/* + bool usingExtentedAPI = false; +#ifdef LPA_SDK__USING_EX_API + usingExtentedAPI = true; +#endif //LPA_SDK__USING_EX_API +*/ + + int parametersIndex = 0; + int listIndex = 0; + + // Last test on parametersIndex is to avoid eventual infinite loop reading memory + while((_lpaParameterDefinitionList[parametersIndex].parameterName != NULL) && (listIndex < LPA_MAX_PARAMETERS_LIST) && (parametersIndex < (LPA_MAX_PARAMETERS_LIST + 10))) + { + // Copy restricted parameters only if Extended API used mode ON + // NOTE: Condition bypassed due to moving in Extended Mode. But kept here in case of returning of feature in Normal Mode + //if(usingExtentedAPI || !_lpaParameterDefinitionList[parametersIndex].isRestricted) + if(true) + { + // If LPA_MAX_PARAMETERS_LIST_ELEMENT_SIZE has been incorrectly set, parameters list elements will appear truncated + strncpy(ptrLpaParametersList->parametersList[listIndex], _lpaParameterDefinitionList[parametersIndex].parameterName, (LPA_MAX_PARAMETERS_LIST_ELEMENT_SIZE - 1)); + ptrLpaParametersList->parametersTypeList[listIndex] = _lpaParameterDefinitionList[parametersIndex].parameterType; + listIndex++; + } + + parametersIndex++; + } + + // Validated OK while list does not exceed parameters list array capacity. If empty list will return OK but no elements to display (parameterCount = 0) + if(listIndex < LPA_MAX_PARAMETERS_LIST) + { + ptrLpaParametersList->parametersCount = listIndex; + res = true; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "lpaGetFullParametersList() - Invalid NULL parameter!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaGetFullParametersList() return %s", (res ? "true" : "false")); + return res; +} + + +LPA_PARAMETER_DEFINITION* _getParameterDefinition(const char* ptrParameterName) +{ + LPA_PARAMETER_DEFINITION *ptrParameterDefinition = NULL; + if (ptrParameterName != NULL) + { + int index = 0; + while (ptrParameterDefinition == NULL) + { + if (_lpaParameterDefinitionList[index].parameterName == NULL) + break; // End of list : Entry not found + + if (compareEqualStringIgnoringCase(ptrParameterName, _lpaParameterDefinitionList[index].parameterName)) + ptrParameterDefinition = &_lpaParameterDefinitionList[index]; // Entry found + else + index++; + } + } + + return ptrParameterDefinition; +} + + +bool _lpaManagerGetBooleanParameterValue(LPA_PARAMETER_ID parameterId, bool* ptrParameterValue) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ _lpaManagerGetBooleanParameterValue(parameterId=%d)", parameterId); + + if (ptrParameterValue != NULL) + { + switch (parameterId) + { + + case PARAM_ID_SEND_PIR_DURING_DOWNLOAD_PROFILE: + *ptrParameterValue = _sendPIRDuringDownloadProfileOperation; + res = true; + break; + + case PARAM_ID_PROFILE_REFRESH_FLAG: + *ptrParameterValue = lpaManagerES10c_IsRefreshFlag(); + res = true; + break; + + // CURL part (httpMedia) + case PARAM_ID_ACTIVATE_CURL_DEBUG_MODE: + res = httpMediaManagerGetBooleanOption(HTTP_MEDIA_OPTION_TYPE_CURL_VERBOSE, ptrParameterValue); + break; + + case PARAM_ID_CURL_SSL_SSL_VERIFYPEER: + res = httpMediaManagerGetBooleanOption(HTTP_MEDIA_OPTION_TYPE_CURL_SSL_VERIFYPEER, ptrParameterValue); + break; + + case PARAM_ID_CURL_SSL_SSL_VERIFYHOST: + res = httpMediaManagerGetBooleanOption(HTTP_MEDIA_OPTION_TYPE_CURL_SSL_VERIFYHOST, ptrParameterValue); + break; + + // lpaManager Helper + case PARAM_ID_ADD_LE_TO_APDU_CASE_4: + *ptrParameterValue = lpaManagerHelperIsLeAddedToApduCase4(); + res = true; + break; + + case PARAM_ID_DEVICE_CAPABILITIES_FILTERING: + *ptrParameterValue = _deviceCapabilitiesFilter; + res = true; + break; + + case PARAM_ID_BYPASS_USER_CONSENT_WITH_NO_PPR: + *ptrParameterValue = _bypassDefaultUserConsentWithNoPPR; + res = true; + break; + + case PARAM_ID_SUPPORT_DOWNLOAD_PROFILES_WITH_PPR: + *ptrParameterValue = _supportDownloadOfProfilesWithPPR; + res = true; + break; + + default: + lpaSetErrorCode(LPA_ERROR_UNKNOWN_PARAMETER); + break; + } + + if (res) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Parameter value : %s", (*ptrParameterValue ? "true" : "false")); + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- _lpaManagerGetBooleanParameterValue() return %s", (res ? "true" : "false")); + return res; +} + +bool _lpaManagerSetBooleanParameterValue(const LPA_PARAMETER_DEFINITION * ptrParameterDefinition, bool parameterValue) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ _lpaManagerSetBooleanParameterValue(...)"); + + if(ptrParameterDefinition != NULL) + { + switch (ptrParameterDefinition->parameterId) + { + case PARAM_ID_SEND_PIR_DURING_DOWNLOAD_PROFILE: + _sendPIRDuringDownloadProfileOperation = parameterValue; + res = true; + break; + + case PARAM_ID_PROFILE_REFRESH_FLAG: + lpaManagerES10c_SetRefreshFlag(parameterValue); + res = true; + break; + + // CURL part (httpMedia) + case PARAM_ID_ACTIVATE_CURL_DEBUG_MODE: + res = httpMediaManagerSetBooleanOption(HTTP_MEDIA_OPTION_TYPE_CURL_VERBOSE, parameterValue); + break; + + case PARAM_ID_CURL_SSL_SSL_VERIFYPEER: + res = httpMediaManagerSetBooleanOption(HTTP_MEDIA_OPTION_TYPE_CURL_SSL_VERIFYPEER, parameterValue); + break; + + case PARAM_ID_CURL_SSL_SSL_VERIFYHOST: + res = httpMediaManagerSetBooleanOption(HTTP_MEDIA_OPTION_TYPE_CURL_SSL_VERIFYHOST, parameterValue); + break; + + // SEMedia + case PARAM_ID_ADD_LE_TO_APDU_CASE_4: + lpaManagerHelperSetLeToAddApduCase4(parameterValue); + res = true; + break; + + case PARAM_ID_DEVICE_CAPABILITIES_FILTERING: + _deviceCapabilitiesFilter = parameterValue; + res = true; + break; + + case PARAM_ID_BYPASS_USER_CONSENT_WITH_NO_PPR: + _bypassDefaultUserConsentWithNoPPR = parameterValue; + res = true; + break; + + case PARAM_ID_SUPPORT_DOWNLOAD_PROFILES_WITH_PPR: + _supportDownloadOfProfilesWithPPR = parameterValue; + res = true; + break; + default: + lpaSetErrorCode(LPA_ERROR_UNKNOWN_PARAMETER); + break; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerSetBooleanParameterValue(): NULL parameter! Operation canceled."); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- _lpaManagerSetBooleanParameterValue() return %s", (res ? "true" : "false")); + return res; +} + +bool _lpaManagerSetLongParameterValue(const LPA_PARAMETER_DEFINITION * ptrParameterDefinition, long parameterValue) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ _lpaManagerSetLongParameterValue(...)"); + + if(ptrParameterDefinition != NULL) + { + switch (ptrParameterDefinition->parameterId) + { + // Log max size + case PARAM_ID_LOG_MAX_SIZE: + res = lpaCoreSetLogMaxSize(parameterValue); + break; + + // CURL part (httpMedia) + case PARAM_ID_CURL_CONNECT_TIMEOUT: + res = httpMediaManagerSetLongOption(HTTP_MEDIA_OPTION_TYPE_CURL_CONNECT_TIMEOUT, parameterValue); + break; + + case PARAM_ID_CURL_TIMEOUT: + res = httpMediaManagerSetLongOption(HTTP_MEDIA_OPTION_TYPE_CURL_TIMEOUT, parameterValue); + break; + + // Memory stress parameters + case PARAM_ID_MEM_ERR_IF_MEM_COUNTER_EQ: + case PARAM_ID_MEM_ERR_IF_MEM_COUNTER_GT: + case PARAM_ID_MEM_ERR_IF_MEM_COUNTER_GE: + case PARAM_ID_MEM_ERR_IF_SIZE_REQUESTED_EQ: + case PARAM_ID_MEM_ERR_IF_SIZE_REQUESTED_GT: + case PARAM_ID_MEM_ERR_IF_SIZE_REQUESTED_GE: +#ifdef LPA_SDK__MEMORY + res = _lpaManagerSetLongMemoryErrorParameterValue(ptrParameterDefinition, parameterValue); +#else + lpaSetErrorCode(LPA_ERROR_PARAMETER_NOT_AUTHORIZED); +#endif //LPA_SDK__MEMORY + break; + + default: + lpaSetErrorCode(LPA_ERROR_UNKNOWN_PARAMETER); + break; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerSetLongParameterValue(): NULL parameter! Operation canceled."); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- _lpaManagerSetLongParameterValue() return %s", (res ? "true" : "false")); + return res; +} + +#ifdef LPA_SDK__MEMORY +bool _lpaManagerSetLongMemoryErrorParameterValue(const LPA_PARAMETER_DEFINITION * ptrParameterDefinition, long parameterValue) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ _lpaManagerSetLongMemoryErrorParameterValue(...)"); + + if(ptrParameterDefinition != NULL) + { + switch (ptrParameterDefinition->parameterId) + { + case PARAM_ID_MEM_ERR_IF_MEM_COUNTER_EQ: + res = lpaCoreMemorySetParamGenerateErr(LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_COUNTER_EQ, parameterValue); + break; + + case PARAM_ID_MEM_ERR_IF_MEM_COUNTER_GT: + res = lpaCoreMemorySetParamGenerateErr(LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_COUNTER_GT, parameterValue); + break; + + case PARAM_ID_MEM_ERR_IF_MEM_COUNTER_GE: + res = lpaCoreMemorySetParamGenerateErr(LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_COUNTER_GE, parameterValue); + break; + + case PARAM_ID_MEM_ERR_IF_SIZE_REQUESTED_EQ: + res = lpaCoreMemorySetParamGenerateErr(LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_SIZE_REQUESTED_EQ, parameterValue); + break; + + case PARAM_ID_MEM_ERR_IF_SIZE_REQUESTED_GT: + res = lpaCoreMemorySetParamGenerateErr(LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_SIZE_REQUESTED_GT, parameterValue); + break; + + case PARAM_ID_MEM_ERR_IF_SIZE_REQUESTED_GE: + res = lpaCoreMemorySetParamGenerateErr(LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_SIZE_REQUESTED_GE, parameterValue); + break; + + default: + break; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerSetLongMemoryErrorParameterValue(): NULL parameter! Operation canceled."); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- _lpaManagerSetLongMemoryErrorParameterValue() return %s", (res ? "true" : "false")); + return res; +} +#endif //LPA_SDK__MEMORY + +bool _lpaManagerGetLongParameterValue(LPA_PARAMETER_ID parameterId, long* ptrParameterValue) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ _lpaManagerGetLongParameterValue(parameterId=%d)", parameterId); + + if (ptrParameterValue != NULL) + { + switch (parameterId) + { + // Log max size + case PARAM_ID_LOG_MAX_SIZE: + if (NULL != ptrParameterValue) + { + long logMaxSize = lpaCoreGetLogMaxSize(); + (*ptrParameterValue) = logMaxSize; + res = true; + } + break; + + // CURL part (httpMedia) + case PARAM_ID_CURL_CONNECT_TIMEOUT: + res = httpMediaManagerGetLongOption(HTTP_MEDIA_OPTION_TYPE_CURL_CONNECT_TIMEOUT, ptrParameterValue); + break; + + case PARAM_ID_CURL_TIMEOUT: + res = httpMediaManagerGetLongOption(HTTP_MEDIA_OPTION_TYPE_CURL_TIMEOUT, ptrParameterValue); + break; + + // Memory stress parameters + case PARAM_ID_MEM_ERR_IF_MEM_COUNTER_EQ: + case PARAM_ID_MEM_ERR_IF_MEM_COUNTER_GT: + case PARAM_ID_MEM_ERR_IF_MEM_COUNTER_GE: + case PARAM_ID_MEM_ERR_IF_SIZE_REQUESTED_EQ: + case PARAM_ID_MEM_ERR_IF_SIZE_REQUESTED_GT: + case PARAM_ID_MEM_ERR_IF_SIZE_REQUESTED_GE: +#ifdef LPA_SDK__MEMORY + res = _lpaManagerGetLongMemoryErrorParameterValue(parameterId, ptrParameterValue); +#else + lpaSetErrorCode(LPA_ERROR_PARAMETER_NOT_AUTHORIZED); +#endif //LPA_SDK__MEMORY + break; + + default: + lpaSetErrorCode(LPA_ERROR_UNKNOWN_PARAMETER); + break; + } + + if (res) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Parameter value : %ld", *ptrParameterValue); + } + else + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- _lpaManagerGetLongParameterValue() return %s", (res ? "true" : "false")); + + return res; +} + +#ifdef LPA_SDK__MEMORY +bool _lpaManagerGetLongMemoryErrorParameterValue(LPA_PARAMETER_ID parameterId, long* ptrParameterValue) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ _lpaManagerGetLongMemoryErrorParameterValue(parameterId=%d)", parameterId); + + if (ptrParameterValue != NULL) + { + switch (parameterId) + { + case PARAM_ID_MEM_ERR_IF_MEM_COUNTER_EQ: + res = lpaCoreMemoryGetParamGenerateErr(LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_COUNTER_EQ, ptrParameterValue); + break; + + case PARAM_ID_MEM_ERR_IF_MEM_COUNTER_GT: + res = lpaCoreMemoryGetParamGenerateErr(LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_COUNTER_GT, ptrParameterValue); + break; + + case PARAM_ID_MEM_ERR_IF_MEM_COUNTER_GE: + res = lpaCoreMemoryGetParamGenerateErr(LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_COUNTER_GE, ptrParameterValue); + break; + + case PARAM_ID_MEM_ERR_IF_SIZE_REQUESTED_EQ: + res = lpaCoreMemoryGetParamGenerateErr(LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_SIZE_REQUESTED_EQ, ptrParameterValue); + break; + + case PARAM_ID_MEM_ERR_IF_SIZE_REQUESTED_GT: + res = lpaCoreMemoryGetParamGenerateErr(LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_SIZE_REQUESTED_GT, ptrParameterValue); + break; + + case PARAM_ID_MEM_ERR_IF_SIZE_REQUESTED_GE: + res = lpaCoreMemoryGetParamGenerateErr(LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_SIZE_REQUESTED_GE, ptrParameterValue); + break; + + default: + lpaSetErrorCode(LPA_ERROR_UNKNOWN_PARAMETER); + break; + } + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- _lpaManagerGetLongMemoryErrorParameterValue() return %s", (res ? "true" : "false")); + return res; +} +#endif //LPA_SDK__MEMORY + +bool _lpaManagerSetStringParameterValue(const LPA_PARAMETER_DEFINITION * ptrParameterDefinition, const char* ptrParameterValue) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ _lpaManagerSetStringParameterValue(...)"); + + if(ptrParameterDefinition != NULL && ptrParameterValue != NULL) + { + switch (ptrParameterDefinition->parameterId) + { + case PARAM_ID_READER_NAME: + if (strlen(ptrParameterValue) < sizeof(_seMediaReaderName)) + { + snprintf(_seMediaReaderName, sizeof(_seMediaReaderName),"%s", ptrParameterValue); + res = true; + } + else + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + break; + + case PARAM_ID_LOG_LEVEL: + { + res = lpaCoreSetLogLevelString(ptrParameterValue); + } + break; + + case PARAM_ID_CERT_PATH: + { + if (strlen(ptrParameterValue) < LPA_CFG_CERT_PATH_MAX_SIZE) + { + res = lpaManagerES9Plus_setCertPath(ptrParameterValue); + } + else + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + break; + + case PARAM_ID_CONFIG_DEVICE_INFO_TLV: + { + if (strlen(ptrParameterValue) < LPA_CFG_DEVICE_INFO_TLV_MAX_SIZE) + { + int deviceInfoByteArraySize = LPA_CFG_DEVICE_INFO_TLV_BYTE_ARRAY_MAX_SIZE; + _deviceInfoByteArraySize = 0; + if (hexStr2ByteArray((const unsigned char *)ptrParameterValue, strlen(ptrParameterValue), _deviceInfoByteArray, &deviceInfoByteArraySize) && deviceInfoByteArraySize > 0) + { + _deviceInfoByteArraySize = deviceInfoByteArraySize; + snprintf(_deviceInfo, sizeof(_deviceInfo), "%s", ptrParameterValue); + res = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "-- Unable to convert DeviceInfoTLV element as ByteArray!!"); + memset(_deviceInfo, 0, sizeof(_deviceInfo)); + memset(_deviceInfoByteArray, 0, sizeof(_deviceInfoByteArray)); + } + } + else + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + break; + + case PARAM_ID_DEVICE_DEFAULT_SMDP_ADDRESS: + if (strlen(ptrParameterValue) < sizeof(_deviceDefaultSMDPaddress)) + { + snprintf(_deviceDefaultSMDPaddress, sizeof(_deviceDefaultSMDPaddress), "%s", ptrParameterValue); + res = true; + } + else + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + break; + + case PARAM_ID_DEVICE_SMDS_ADDRESS: + if (strlen(ptrParameterValue) < sizeof(_deviceSMDSaddress)) + { + snprintf(_deviceSMDSaddress, sizeof(_deviceSMDSaddress), "%s", ptrParameterValue); + res = true; + } + else + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + break; + + default: + lpaSetErrorCode(LPA_ERROR_UNKNOWN_PARAMETER); + break; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerSetStringParameterValue(): NULL parameter! Operation canceled."); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- _lpaManagerSetStringParameterValue() return %s", (res ? "true" : "false")); + return res; +} + +bool _lpaManagerGetStringParameterValue(LPA_PARAMETER_ID parameterId, char* ptrParameterValue, size_t parameterValueMaxSize) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ _lpaManagerGetStringParameterValue(parameterId=%d)", parameterId); + + if (ptrParameterValue != NULL && parameterValueMaxSize > 0) + { + switch (parameterId) + { + case PARAM_ID_READER_NAME: + if (strlen(_seMediaReaderName) < parameterValueMaxSize) + { + snprintf(ptrParameterValue, parameterValueMaxSize, "%s", _seMediaReaderName); + res = true; + } + else + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + break; + + case PARAM_ID_CERT_PATH: + { + if (lpaManagerES9Plus_getCertPathSize() < parameterValueMaxSize) + res = lpaManagerES9Plus_getCertPath(ptrParameterValue, parameterValueMaxSize); + else + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + break; + + case PARAM_ID_CONFIG_DEVICE_INFO_TLV: + { + if (strlen(_deviceInfo) < parameterValueMaxSize) + { + snprintf(ptrParameterValue, parameterValueMaxSize, "%s", _deviceInfo); + res = true; + } + else + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + break; + + case PARAM_ID_LOG_LEVEL: + { + LpaLogLevel logLevel = lpaCoreGetLogLevel(); + bool isLogLevelExist = false; + const char* logLevelString = lpaCoreGetLogLevelName(logLevel, &isLogLevelExist); + if (logLevelString != NULL && isLogLevelExist) + { + if (strlen(logLevelString) < parameterValueMaxSize) + { + snprintf(ptrParameterValue, parameterValueMaxSize, "%s", logLevelString); + res = true; + } + else + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + else + lpaSetErrorCode(LPA_ERROR_PARAMETER_INTERNAL_ERROR); + } + break; + + case PARAM_ID_DEVICE_DEFAULT_SMDP_ADDRESS: + if (strlen(_deviceDefaultSMDPaddress) < parameterValueMaxSize) + { + snprintf(ptrParameterValue, parameterValueMaxSize, "%s", _deviceDefaultSMDPaddress); + res = true; + } + else + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + break; + + case PARAM_ID_DEVICE_SMDS_ADDRESS: + if (strlen(_deviceSMDSaddress) < parameterValueMaxSize) + { + snprintf(ptrParameterValue, parameterValueMaxSize, "%s", _deviceSMDSaddress); + res = true; + } + else + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + break; + + default: + lpaSetErrorCode(LPA_ERROR_UNKNOWN_PARAMETER); + break; + } + + if (res) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Parameter value : %s", ptrParameterValue); + } + else + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- _lpaManagerGetStringParameterValue() return %s", (res ? "true" : "false")); + return res; +} + + +bool lpaManagerGetReaderList(LPA_SE_MEDIA_READER_NAME_INFO * ptrReaderNameInfoList, size_t readerNameInfoMax, size_t* ptrCountReader) +{ + return seMediaManagerListReader(ptrReaderNameInfoList, readerNameInfoMax, ptrCountReader); +} + +// ES10c part +////////////////////////////////////////////// + +bool lpaManagerGetProfilesInfo(LPA_GET_PROFILES_INFO* ptrLpaGetProfilesInfo) +{ + bool res = true; + int nbExecGetResp = LPA_LOOP_NUMBER_FOR_CHAINED_GET_RESPONSE; // If retry deactivated, will be performed only one time + bool continueRetry = true; // Allow to know if have to give up performing GetResponse retry (Case of permanent issue for retrieve number of profile in eUICC). true = continue retrying + + // Execution / retry management + while(nbExecGetResp > 0 && continueRetry) + { + res = lpaManagerES10c_GetProfilesInfo(ptrLpaGetProfilesInfo, &continueRetry, false); + + if(lpaGetErrorCodeNoClear() != SE_MEDIA_E_CHAINING_GET_RESPONSE) + { + // No chaining error detected, end execution loop + nbExecGetResp = 0; + } + else + { + // Chaining error detected, continue on execution loop + nbExecGetResp--; + // If last loop not reached, clear error code to execute another attempt + // Else stay on error SE_MEDIA_E_CHAINING_GET_RESPONSE + if(nbExecGetResp > 0 && continueRetry) + { + lpaResetErrorCode(); + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "lpaManagerGetProfilesInfo: GetResponse chaining issue detected, try another time, nbExecGetResp = %d", nbExecGetResp); + } + } + } + + return res; +} + + +bool lpaManagerGetProfilesNumber(size_t * ptrNumberOfProfiles) +{ + bool res = true; + int nbExecGetResp = LPA_LOOP_NUMBER_FOR_CHAINED_GET_RESPONSE; // If retry deactivated, will be performed only one time + + // Execution / retry management + while(nbExecGetResp > 0) + { + res = lpaManagerES10c_GetProfilesNumber(ptrNumberOfProfiles); + + if(lpaGetErrorCodeNoClear() != SE_MEDIA_E_CHAINING_GET_RESPONSE) + { + // No chaining error detected, end execution loop + nbExecGetResp = 0; + } + else + { + // Chaining error detected, continue on execution loop + nbExecGetResp--; + // If last loop not reached, clear error code to execute another attempt + // Else stay on error SE_MEDIA_E_CHAINING_GET_RESPONSE + if(nbExecGetResp > 0) + { + lpaResetErrorCode(); + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "lpaManagerGetProfilesNumber: GetResponse chaining issue detected, try another time, nbExecGetResp = %d", nbExecGetResp); + } + } + } + + return res; +} + +/** + * Retrieve profile info for PPR processing + * Note: This is for internal use, so memory allocation for ptrLpaGetProfilesInfo->profileInfoList will be performed here, so pointer should be NULL (De-allocated after if not) + * @param ptrLpaGetProfilesInfo - Pointer on profile info structure. + * @return true if retrieve operation is successful + */ +bool _getProfilesInfoForPPR(LPA_GET_PROFILES_INFO* ptrLpaGetProfilesInfo) +{ + bool res = true; + int nbExecGetResp = LPA_LOOP_NUMBER_FOR_CHAINED_GET_RESPONSE; // If retry deactivated, will be performed only one time + bool continueRetry = true; // Allow to know if have to give up performing GetResponse retry (Case of permanent issue for retrieve number of profile in eUICC). true = continue retrying + + if(ptrLpaGetProfilesInfo != NULL) + { + ptrLpaGetProfilesInfo->countProfileInfo = 0; + ptrLpaGetProfilesInfo->numberProfileInfoFound = 0; + + // Execution / retry management + while(nbExecGetResp > 0 && continueRetry) + { + res = lpaManagerES10c_GetProfilesInfo(ptrLpaGetProfilesInfo, &continueRetry, true); + + if(lpaGetErrorCodeNoClear() != SE_MEDIA_E_CHAINING_GET_RESPONSE) + { + // No chaining error detected, end execution loop + nbExecGetResp = 0; + } + else + { + // Chaining error detected, continue on execution loop + nbExecGetResp--; + // If last loop not reached, clear error code to execute another attempt + // Else stay on error SE_MEDIA_E_CHAINING_GET_RESPONSE + if(nbExecGetResp > 0 && continueRetry) + { + lpaResetErrorCode(); + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "_getProfilesInfoForPPR: GetResponse chaining issue detected, try another time, nbExecGetResp = %d", nbExecGetResp); + } + } + } + } + else + { + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_getProfilesInfoForPPR: NULL parameter!"); + } + + return res; +} + + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool lpaManagerGetEID(LPA_GET_EID* ptrGetEID) +{ + return lpaManagerES10c_GetEID(ptrGetEID); +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** + * Get EUICCinfo2 for external API interface + * @param ptrGetEUICCInfo Pointer on LPA_GET_EUICC_INFO object + * @return True if retrieve is correct, else false + */ +bool lpaManagerGetEUICCInfo2(LPA_GET_EUICC_INFO* ptrGetEUICCInfo) +{ + bool res = false; + LPA_GET_EUICC getEuiccInfo2; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaManagerGetEUICCInfo2(...)"); + + if(ptrGetEUICCInfo != NULL) + { + getEuiccInfo2.ptrEUICC = NULL; + getEuiccInfo2.prtEUICC_Base64 = NULL; + ptrGetEUICCInfo->EUICC_Info_DataSize = 0; + + res = _lpaManagerGetEuiccInfoWithRetry(GET_EUICC_INFO2_DGI_TAG, &getEuiccInfo2); // Get with retry mechanism management + + if(res && getEuiccInfo2.ptrEUICC != NULL && getEuiccInfo2.ptrEUICC->rawDataSize > 0) + { + memcpy(ptrGetEUICCInfo->EUICC_Info_Data, getEuiccInfo2.ptrEUICC->rawData, getEuiccInfo2.ptrEUICC->rawDataSize); + ptrGetEUICCInfo->EUICC_Info_DataSize = getEuiccInfo2.ptrEUICC->rawDataSize; + } + else + { + res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Problem while retrieving EUICCInfo2 or returned data empty"); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_EUICC_INFO); + } + + // Memory cleanup + ERASE_RAWDATAOBJECT(getEuiccInfo2.ptrEUICC); + ERASE_RAWDATAOBJECT(getEuiccInfo2.prtEUICC_Base64); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter(s)!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaManagerGetEUICCInfo2()"); + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool lpaManagerMemoryReset(const unsigned char* memoryResetOptionParameter, const size_t memoryResetOptionSize) +{ + return lpaManagerES10c_MemoryReset(memoryResetOptionParameter, memoryResetOptionSize); +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool lpaManagerEnableProfileByIccid(const unsigned char* ptrProfileId, size_t profileIdSize) +{ + return lpaManagerES10c_EnableProfileByIccid(ptrProfileId, profileIdSize); +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool lpaManagerDisableProfileByIccid(const unsigned char* ptrProfileId, size_t profileIdSize) +{ + return lpaManagerES10c_DisableProfileByIccid(ptrProfileId, profileIdSize); +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool lpaManagerDeleteProfileByIccid(const unsigned char* ptrProfileId, size_t profileIdSize) +{ + return lpaManagerES10c_DeleteProfileByIccid(ptrProfileId, profileIdSize); +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool lpaManagerSendPendingNotification(LPA_EventCallback* ptrLpaEventCallback, LPA_SENDING_NOTIFICATION_RESULT* ptrSendingNotificationResult) +{ + bool res = false; + bool sendItSuccessfully = false; + size_t notificationManaged = 0; + int nbExecGetResp = LPA_LOOP_NUMBER_FOR_CHAINED_GET_RESPONSE; // If Retry deactivated, will be performed only one time + + // For address successfully send checking + ADDRESS_DATA listOfFailedServers[LPA_MAX_PROFILE_NOTIFICATION_LIST_ELEMENT]; + size_t idx = 0; + bool smdpAddressNotFailed = true; + + LPA_API_ERROR firstEncounteredErrorCode = LPA_NO_ERROR; // To store first encountered error code if GetResponse Retry mechanism enabled + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaManagerSendPendingNotification(...)"); + + // Registering LPA_EVENT_EXECUTION_ERROR (if configured) for this call only + _registerAppEventExecutionCallback(ptrLpaEventCallback); + + // ptrLpaEventCallback NULL managed in another function + if (ptrSendingNotificationResult != NULL) + { + ptrSendingNotificationResult->countNotificationDetected = 0; + ptrSendingNotificationResult->countNotificationSend = 0; + + // Init / clear list of failed servers + for(idx = 0; idx < LPA_MAX_PROFILE_NOTIFICATION_LIST_ELEMENT; idx++) + memset(&listOfFailedServers[idx], 0, sizeof(ADDRESS_DATA)); + + // Step 1: get Pending notification list + LPA_PROFILE_NOTIFICATION_LIST profileNotificationList; + _sendEventCallbackProgressText(ptrLpaEventCallback, 0, "Read pending notifications..."); + + // If Retry enabled and failed during notification list retrieve, will return false so operation will end with SE_MEDIA_E_CHAINING_GET_RESPONSE error + res = lpaManagerGetProfileNotificationList(&profileNotificationList); + if (res) + { + if (profileNotificationList.countNotification > 0) + { + char bufferFormattingNotificationEventMessage[128]; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "<%llu> pending notification(s) detected", (long long unsigned)profileNotificationList.countNotification); + + snprintf(bufferFormattingNotificationEventMessage, sizeof(bufferFormattingNotificationEventMessage), "<%llu> pending notification(s) detected", (long long unsigned)profileNotificationList.countNotification); + _sendEventCallbackProgressText(ptrLpaEventCallback, 0, bufferFormattingNotificationEventMessage); + + ptrSendingNotificationResult->countNotificationDetected = profileNotificationList.countNotification; + + // Sort list of notification by sequence numbers, ascending order + if(_sortNotificationList(&profileNotificationList)) + { + notificationManaged = 0; + + RawDataObject* ptrRawDataNotification = rawDataObject_allocate(); + if (ptrRawDataNotification != NULL) + { + // Step 2: for each notification entry, get notification data and send them to the server + while (notificationManaged < profileNotificationList.countNotification) + { + sendItSuccessfully = false; + nbExecGetResp = LPA_LOOP_NUMBER_FOR_CHAINED_GET_RESPONSE; + + // Try to send notification to the server + uint16_t notificationSequenceNumber = profileNotificationList.notificationMetadataList[notificationManaged].seqNumber; + rawDataObject_clear(ptrRawDataNotification); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Processing notification #%llu <%u>...", (long long unsigned)(notificationManaged + 1), notificationSequenceNumber); + snprintf(bufferFormattingNotificationEventMessage, sizeof(bufferFormattingNotificationEventMessage), "Processing notification #%llu <%u>", + (long long unsigned)(notificationManaged + 1), notificationSequenceNumber); + _sendEventCallbackProgressText(ptrLpaEventCallback, 0, bufferFormattingNotificationEventMessage); + + // Check if SM-DP+ address has not already failed in this session + smdpAddressNotFailed = true; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Check if current notification address has not already failed in this session"); + for(idx = 0; idx < LPA_MAX_PROFILE_NOTIFICATION_LIST_ELEMENT; idx++) + { + // Check no empty entry detected in failed servers addresses list array + if(listOfFailedServers[idx].address_DataSize > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Compare address with failed servers list element #%llu", (long long unsigned)idx); + // Compare failed server address list element with current notification address + if(listOfFailedServers[idx].address_DataSize == profileNotificationList.notificationMetadataList[notificationManaged].notificationAddressRawDataSize) + { + if(memcmp(listOfFailedServers[idx].address_Data, + profileNotificationList.notificationMetadataList[notificationManaged].notificationAddressRawData, + listOfFailedServers[idx].address_DataSize) == 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "Already failed to exchange with this SM-DP+ server during this session, skipping notification"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 0, "Already failed to exchange with this SM-DP+ server during this session, skipping notification"); + smdpAddressNotFailed = false; + break; + } + } + } + else + { + // Failed addresses are stored from the beginning of array, so when empty entry is found there is nothing more to check + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Failed servers list element #%llu: No more server address to evaluate", (long long unsigned)idx); + break; + } + } + + if(smdpAddressNotFailed) + { + // Execution / retry management for notification data retrieval + while(nbExecGetResp > 0) + { + if (_retrieveNotificationData(notificationSequenceNumber, ptrRawDataNotification)) + { + // No chaining error detected, end execution loop + nbExecGetResp = 0; + + sendItSuccessfully = _sendNotificationToServer(&profileNotificationList.notificationMetadataList[notificationManaged], ptrRawDataNotification, ptrLpaEventCallback); + } + else + { + // Decrease execution loop. If Retry not enabled, will reach 0 so no retry + nbExecGetResp--; + + // Retry management + if(lpaGetErrorCodeNoClear() == SE_MEDIA_E_CHAINING_GET_RESPONSE && LPA_RETRY_CHAINED_GET_RESPONSE_MGT) + { + // If last loop not reached, clear error code to execute another attempt + // Else stay on error SE_MEDIA_E_CHAINING_GET_RESPONSE + if(nbExecGetResp > 0) + { + lpaResetErrorCode(); + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "lpaManagerSendPendingNotification: GetResponse chaining issue detected, try another time, nbExecGetResp = %d", nbExecGetResp); + + rawDataObject_clear(ptrRawDataNotification); + } + } + } + } + + if (sendItSuccessfully) + { + if(lpaManagerClearProfileNotification(notificationSequenceNumber)) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Notification <%u> successfully cleared", notificationSequenceNumber); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to clear notification <%u>", notificationSequenceNumber); + + ptrSendingNotificationResult->countNotificationSend++; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Notification <%u> successfully sent", notificationSequenceNumber); + + snprintf(bufferFormattingNotificationEventMessage, sizeof(bufferFormattingNotificationEventMessage), "Notification <%u> successfully sent", notificationSequenceNumber); + _sendEventCallbackProgressText(ptrLpaEventCallback, 0, bufferFormattingNotificationEventMessage); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to send notification <%u>", notificationSequenceNumber); + + snprintf(bufferFormattingNotificationEventMessage, sizeof(bufferFormattingNotificationEventMessage), "Failed to send notification <%u>", notificationSequenceNumber); + _sendEventCallbackProgressText(ptrLpaEventCallback, 0, bufferFormattingNotificationEventMessage); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Store notification address in failed servers address list"); + + for(idx = 0; idx < LPA_MAX_PROFILE_NOTIFICATION_LIST_ELEMENT; idx++) + { + // Check if array element is empty, else go to next one + if(listOfFailedServers[idx].address_DataSize < 1) + { + // Store current notification address in failed servers address list + if(profileNotificationList.notificationMetadataList[notificationManaged].notificationAddressRawDataSize < sizeof(_bufferFormatLogMessage)) + { + memcpy(_bufferFormatLogMessage, + profileNotificationList.notificationMetadataList[notificationManaged].notificationAddressRawData, + profileNotificationList.notificationMetadataList[notificationManaged].notificationAddressRawDataSize); + _bufferFormatLogMessage[profileNotificationList.notificationMetadataList[notificationManaged].notificationAddressRawDataSize] = '\0'; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Store \"%s\" at list position #%llu", _bufferFormatLogMessage, (long long unsigned)idx); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Store SM-DP+ address at list position #%llu", (long long unsigned)idx); + + memcpy(listOfFailedServers[idx].address_Data, + profileNotificationList.notificationMetadataList[notificationManaged].notificationAddressRawData, + profileNotificationList.notificationMetadataList[notificationManaged].notificationAddressRawDataSize); + listOfFailedServers[idx].address_DataSize = profileNotificationList.notificationMetadataList[notificationManaged].notificationAddressRawDataSize; + break; + } + } + + // Has a VERY few chances to happen, but in this case stop process to avoid risk of desynchronize notifications reception by server + if(idx >= LPA_MAX_PROFILE_NOTIFICATION_LIST_ELEMENT) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed servers address list full, cannot store notification address, process aborted!"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 0, "Failed servers address list full, cannot store notification address, process aborted"); + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + res = false; + break; + } + } + } + + notificationManaged++; + + // Management of error code. Need to clear it at each notification read if GetResponse Retry mechanism is enabled + // So keep the first one encountered to deliver it at the end like previously + if(LPA_RETRY_CHAINED_GET_RESPONSE_MGT) + { + if(lpaGetErrorCodeNoClear() != LPA_NO_ERROR && firstEncounteredErrorCode == LPA_NO_ERROR) + { + firstEncounteredErrorCode = lpaGetErrorCodeNoClear(); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerSendPendingNotification(): First encountered Error Code: 0x%06X", firstEncounteredErrorCode); + } + + lpaResetErrorCode(); + } + } + + // Cleanup memory + ERASE_RAWDATAOBJECT(ptrRawDataNotification); + } + else + { + res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Unable to allocate memory for ptrByteArrayNotificationData!"); + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + } + else + { + res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to sort list of notifications"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 0, "Failed to sort list of notifications"); + lpaSetErrorCode(LPA_ERROR_PROCESSING_ERROR); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "No pending notification found"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 0, "No pending notification found"); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to retrieve list of notifications!"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 0, "Failed to retrieve list of notifications"); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter(s)!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + // And unregistering LPA_EVENT_EXECUTION_ERROR callback + _unregisterAppEventExecutionCallback(); + + // Management of error code if GetResponse Retry mechanism enabled + // If any error encountered while sending notification(s), restore it (First occurrence only) + if(LPA_RETRY_CHAINED_GET_RESPONSE_MGT) + { + if(firstEncounteredErrorCode != LPA_NO_ERROR) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerSendPendingNotification(): Restore first Error Code encountered: 0x%06X", firstEncounteredErrorCode); + lpaResetErrorCode(); + lpaSetErrorCode(firstEncounteredErrorCode); + } + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaManagerSendPendingNotification()"); + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** + * Sort notification list in ascending order + * @param ptrNotificationList Pointer on notification list to sort, LPA_PROFILE_NOTIFICATION_LIST type + * @return True if no error during sorting + */ +bool _sortNotificationList(LPA_PROFILE_NOTIFICATION_LIST * ptrNotificationList) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_sortNotificationList()..."); + + if(ptrNotificationList != NULL) + { + if(ptrNotificationList->countNotification > 1) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_sortNotificationList(): Start sorting notification list..."); + + // Declare here save heap operations if no need to sort + int maxIterations = ptrNotificationList->countNotification - 1; // Up to N-1 iterations will be needed + int i = 0; + int j = 0; + bool swapPerformed = false; + LPA_PROFILE_NOTIFICATION_METADATA listElementSwap; + + // Final status will be invalidated only if problem is detected + res = true; + + for(i = 0; i < maxIterations; i++) + { + swapPerformed = false; + for(j = 0; j < maxIterations; j++) + { + // Sequence number of current notification is greater -> Perform swap of notifications in list + if(ptrNotificationList->notificationMetadataList[j].seqNumber > ptrNotificationList->notificationMetadataList[j+1].seqNumber) + { + swapPerformed = true; + res = _copyNotificationListElement(&ptrNotificationList->notificationMetadataList[j+1], &listElementSwap); + if(res) + res = _copyNotificationListElement(&ptrNotificationList->notificationMetadataList[j], &ptrNotificationList->notificationMetadataList[j+1]); + if(res) + res = _copyNotificationListElement(&listElementSwap, &ptrNotificationList->notificationMetadataList[j]); + } + + // If problem detected stop this loop + if(! res) break; + } + + // No more swap performed => no need to perform more iterations, the list is sorted + // Also exit in case of error + if(! swapPerformed || ! res) break; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_sortNotificationList(): Less than 2 elements reported in list, sorting is useless."); + res = true; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_sortNotificationList(): Invalid NULL parameter!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_sortNotificationList() return %s", (res ? "true" : "false")); + return res; +} + +/** + * Copy notification list element from source to destination data structure + * @param ptrSource Pointer on source element, LPA_PROFILE_NOTIFICATION_METADATA type + * @param ptrDestination Pointer on destination element, LPA_PROFILE_NOTIFICATION_METADATA type + * @return True if no error during copy + */ +bool _copyNotificationListElement(LPA_PROFILE_NOTIFICATION_METADATA * ptrSource, LPA_PROFILE_NOTIFICATION_METADATA * ptrDestination) +{ + bool res = false; + + if(ptrSource != NULL && ptrDestination != NULL) + { + ptrDestination->seqNumber = ptrSource->seqNumber; + ptrDestination->profileManagementOperation = ptrSource->profileManagementOperation; + ptrDestination->notificationAddressRawDataSize = ptrSource->notificationAddressRawDataSize; + memcpy(ptrDestination->notificationAddressRawData, ptrSource->notificationAddressRawData, LPA_MAX_NOTIFICATION_ADDRESS_RAW_DATA_SIZE); + + res = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_copyNotificationListElement(): Invalid NULL parameter(s)!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool _retrieveNotificationData(uint16_t sequenceNumber, RawDataObject* ptrRawDataNotification) +{ + bool res = false; + unsigned char byteArraySequenceNumber[16]; + size_t byteArraySequenceNumberSize = 0; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_retrieveNotificationData(sequenceNumber=%u)...", sequenceNumber); + + if(ptrRawDataNotification != NULL) + { + if (writeIntegerValueToByteArray(sequenceNumber, byteArraySequenceNumber, sizeof(byteArraySequenceNumber), &byteArraySequenceNumberSize)) + { + RawDataObject* rawDataObjectSequenceNumber = NULL; + RawDataObject* rawDataObjectAttribute = NULL; + RawDataObject* rawDataObjectRetrieveNotificationsList = NULL; + + rawDataObjectSequenceNumber = berTLV_createAndBuildRawDataObject(ASN1_PRIMITIVE_ATTRIBUTE_TAG, byteArraySequenceNumberSize, byteArraySequenceNumber); + + if (rawDataObjectSequenceNumber != NULL) + rawDataObjectAttribute = berTLV_createAndBuildRawDataObject(ASN1_CONSTRUCTED_ATTRIBUTE_TAG, rawDataObjectSequenceNumber->rawDataSize, rawDataObjectSequenceNumber->rawData); + + if (rawDataObjectAttribute != NULL) + rawDataObjectRetrieveNotificationsList = berTLV_createAndBuildRawDataObject(RETRIEVE_NOTIFICATIONS_LIST_TAG, rawDataObjectAttribute->rawDataSize, rawDataObjectAttribute->rawData); + + if (rawDataObjectRetrieveNotificationsList != NULL) + { + // build and Send APDU + uint16_t apduSW = 0x0000; + size_t dataBufferSize = 0; + + // Will be failed if unattended SW or GetResponse chaining issue is encountered + if (buildAndSendStoreDataCase4(rawDataObjectRetrieveNotificationsList, &apduSW, _dataBuffer, sizeof(_dataBuffer), &dataBufferSize)) + { + // Check SW = 90.00 or 91.xx + if((apduSW == 0x9000) || ((apduSW & 0xFF00) == 0x9100)) + { + res = _extractNotificationData(_dataBuffer, dataBufferSize, ptrRawDataNotification); + if (res) + { + snprintf(_bufferFormatLogMessage, sizeof(_bufferFormatLogMessage), "Notification rawData found, %llu bytes:", (long long unsigned)ptrRawDataNotification->rawDataSize); + lpaCoreLogAppendByteArray(SDK_LOG_LEVEL_DEBUG, _bufferFormatLogMessage, "Notification Data", ptrRawDataNotification->rawData, ptrRawDataNotification->rawDataSize); + } + } + else + lpaSetErrorCode(LPA_ERROR_INVALID_SW); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Problem encountered when trying to retrieve notification data: APDU execution failed!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "rawDataObjectRetrieveNotificationsList is NULL!"); + + // Do memory cleanup + ERASE_RAWDATAOBJECT(rawDataObjectSequenceNumber); + ERASE_RAWDATAOBJECT(rawDataObjectAttribute); + ERASE_RAWDATAOBJECT(rawDataObjectRetrieveNotificationsList); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Unable to write sequenceNumber into byte array!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_retrieveNotificationData() return %s", (res ? "true" : "false")); + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool _extractNotificationData(const unsigned char* ptrDataBuffer, size_t dataBufferSize, RawDataObject* ptrRawDataNotification) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_extractNotificationData()..."); + + if (ptrDataBuffer != NULL && dataBufferSize > 0 && ptrRawDataNotification != NULL) + { + bool tagFound = false; + BeerTLV* berTLVRetrieveNotificationsList = NULL; + BeerTLV* berTLVConstructedAttribute = NULL; + + berTLVRetrieveNotificationsList = berTLV_extractTagUInt16(RETRIEVE_NOTIFICATIONS_LIST_TAG, ptrDataBuffer, dataBufferSize, &tagFound); + if (berTLVRetrieveNotificationsList != NULL) + { + berTLVConstructedAttribute = berTLV_extractTagUInt8(ASN1_CONSTRUCTED_ATTRIBUTE_TAG, berTLVRetrieveNotificationsList->value, berTLVRetrieveNotificationsList->length, &tagFound); + if (berTLVConstructedAttribute != NULL) + { + rawDataObject_update(ptrRawDataNotification, berTLVConstructedAttribute->value, berTLVConstructedAttribute->length); + res = true; + } + } + + // Cleanup memory + ERASE_BERTLV(berTLVRetrieveNotificationsList); + ERASE_BERTLV(berTLVConstructedAttribute); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter(s)!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_extractNotificationData() return %s", (res ? "true" : "false")); + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool _sendNotificationToServer(const LPA_PROFILE_NOTIFICATION_METADATA* ptrProfileNotificationMetadata, const RawDataObject* ptrRawDataNotification, const LPA_EventCallback* ptrLpaEventCallback) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_sendNotificationToServer(...) ..."); + bool normalNotifAcknowledge = false; + + if (ptrProfileNotificationMetadata != NULL && ptrRawDataNotification != NULL) + { + char * tmpInfo = NULL; + size_t convBuffSize = ptrRawDataNotification->rawDataSize + (ptrRawDataNotification->rawDataSize / 2); // 150 % greater. A bit more than 137 % commonly described + tmpInfo = lpaCoreMemoryAlloc(convBuffSize); + + if(tmpInfo != NULL) + { + size_t outlen = 0; + memset(tmpInfo, 0, convBuffSize); + + if (base64_encode(ptrRawDataNotification->rawData, ptrRawDataNotification->rawDataSize, tmpInfo, &outlen, convBuffSize)) + { + if (_handleNotification((const char*)ptrProfileNotificationMetadata->notificationAddressRawData, ptrProfileNotificationMetadata->notificationAddressRawDataSize, (const unsigned char*)tmpInfo, ptrLpaEventCallback, &normalNotifAcknowledge)) + { + // Even if server returned an error, it means that it has received the notification data so sending is successful + if(normalNotifAcknowledge) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Success to send notification data to server!"); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "Success to send notification data to server, but get error status returned"); + + res = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to send notification data to server!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Cannot convert Notification data in Base64!"); + + lpaCoreMemoryFree(tmpInfo); + tmpInfo = NULL; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Cannot allocate %llu bytes for conversion buffer tmpInfo!", (long long unsigned)convBuffSize); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter(s)!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_sendNotificationToServer() return %s", (res ? "true" : "false")); + return res; +} + +////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////// + + +bool lpaManagerGetProfileNotificationList(LPA_PROFILE_NOTIFICATION_LIST* ptrProfileNotificationList) +{ + bool res = false; + int nbExecGetResp = LPA_LOOP_NUMBER_FOR_CHAINED_GET_RESPONSE; // If retry deactivated, will be performed only one time + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaManagerGetProfileNotificationList(...)"); + + if (ptrProfileNotificationList != NULL) + { + RawDataObject* rawDataObjectGetProfileNotificationList = NULL; + + ptrProfileNotificationList->countNotification = 0; + + rawDataObjectGetProfileNotificationList = berTLV_createAndBuildRawDataObject(LIST_NOTIFICATION_TAG, 0, NULL); + if (rawDataObjectGetProfileNotificationList != NULL) + { + // build and Send APDU + uint16_t apduSW = 0x0000; + size_t dataBufferSize = 0; + + // Execution / retry management + while(nbExecGetResp > 0) + { + // In case of retry, better to re-initialize these values + apduSW = 0x0000; + dataBufferSize = 0; + + if (buildAndSendStoreDataCase4(rawDataObjectGetProfileNotificationList, &apduSW, _dataBuffer, sizeof(_dataBuffer), &dataBufferSize)) + { + // No chaining error detected, end execution loop + nbExecGetResp = 0; + + // Check SW = 90.00 or 91.xx + if((apduSW == 0x9000) || ((apduSW & 0xFF00) == 0x9100)) + { + // APDU successfully sent + if (dataBufferSize == 0) + { + res = true; // no data + } + else + { + if (_doExtractMetadataForGetProfileNotificationList(ptrProfileNotificationList, _dataBuffer, dataBufferSize)) + res = true; + else + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_UNABLE_TO_EXTRACT_DATA); + } + } + else + lpaSetErrorCode(LPA_ERROR_INVALID_SW); + } + else + { + // Decrease execution loop. If Retry not enabled, will reach 0 so no retry + nbExecGetResp--; + + // Retry management + if(lpaGetErrorCodeNoClear() == SE_MEDIA_E_CHAINING_GET_RESPONSE && LPA_RETRY_CHAINED_GET_RESPONSE_MGT) + { + // If last loop not reached, clear error code to execute another attempt + // Else stay on error SE_MEDIA_E_CHAINING_GET_RESPONSE + if(nbExecGetResp > 0) + { + lpaResetErrorCode(); + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "lpaManagerGetProfileNotificationList: GetResponse chaining issue detected, try another time, nbExecGetResp = %d", nbExecGetResp); + } + } + else + lpaSetErrorCode(LPA_ERROR_NOTIFICATION_INCORRECT_CARD_RESPONSE); + + } + } + + // Do memory cleanup + ERASE_RAWDATAOBJECT(rawDataObjectGetProfileNotificationList); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Cannot build Notification List raw data object!"); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter(s)!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaManagerGetProfileNotificationList() return %s", (res ? "true" : "false")); + return res; +} + +bool _doExtractMetadataForGetProfileNotificationList(LPA_PROFILE_NOTIFICATION_LIST* ptrProfileNotificationList, unsigned char *ptrData, size_t dataSize) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ _doExtractMetadataForGetProfileNotificationList(...)"); + + if (ptrProfileNotificationList != NULL && ptrData != NULL && dataSize > 0) + { + bool tagFound = false; + BeerTLV* berTLVListNotificationTag = NULL; + BeerTLV* berTLVSequenceTag = NULL; + BerTLVList* tlvListInsideSequenceTag = NULL; + + ptrProfileNotificationList->countNotification = 0; + + berTLVListNotificationTag = berTLV_extractTagUInt16(LIST_NOTIFICATION_TAG, ptrData, dataSize, &tagFound); + if (berTLVListNotificationTag != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "BerTLV tag <%X> found", LIST_NOTIFICATION_TAG); + + berTLVSequenceTag = berTLV_extractTagUInt8(SEQUENCE_TAG, berTLVListNotificationTag->value, berTLVListNotificationTag->length, &tagFound); + } + + if (berTLVSequenceTag != NULL) + { + uint8_t countTLVFound = 0; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "BerTLV tag <%X> found (data size:%lu)", SEQUENCE_TAG, (long unsigned)berTLVSequenceTag->length); + if (berTLVSequenceTag->length > 0) + { + tlvListInsideSequenceTag = berTLV_extractList(berTLVSequenceTag->value, berTLVSequenceTag->length, &countTLVFound); + + if (countTLVFound > 0 && tlvListInsideSequenceTag != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "%u tag found inside BERTLV object", countTLVFound); + + BerTLVList* berTLVCurrentInsideSequenceTag = tlvListInsideSequenceTag; + while (berTLVCurrentInsideSequenceTag != NULL) + { + if (berTLVCurrentInsideSequenceTag->berTLV != NULL && berTLVCurrentInsideSequenceTag->berTLV->tag == NOTIFICATION_METADATA_TAG) + { + bool tag80Found = false, tag81Found = false, tag0CFound = false; + BeerTLV *ptrNotificationTag80 = NULL, *ptrNotificationTag81 = NULL, *ptrNotificationTag0C = NULL; + bool isSequenceError = false; + + if (formatBytesToHexaString(berTLVCurrentInsideSequenceTag->berTLV->value, berTLVCurrentInsideSequenceTag->berTLV->length, _bufferFormatLogMessage, sizeof(_bufferFormatLogMessage)) > 0) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "NOTIFICATION_METADATA_TAG found: %s", _bufferFormatLogMessage); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "NOTIFICATION_METADATA_TAG found: ..."); + + + // extract metadata for current notification + ptrNotificationTag80 = berTLV_extractTagUInt8(0x80, berTLVCurrentInsideSequenceTag->berTLV->value, berTLVCurrentInsideSequenceTag->berTLV->length, &tag80Found); + ptrNotificationTag81 = berTLV_extractTagUInt8(0x81, berTLVCurrentInsideSequenceTag->berTLV->value, berTLVCurrentInsideSequenceTag->berTLV->length, &tag81Found); + ptrNotificationTag0C = berTLV_extractTagUInt8(0x0C, berTLVCurrentInsideSequenceTag->berTLV->value, berTLVCurrentInsideSequenceTag->berTLV->length, &tag0CFound); + + // Actually, only Tags 80,81 & 0C mandatory and used + if (ptrNotificationTag80 != NULL && ptrNotificationTag81 != NULL && ptrNotificationTag0C != NULL) + { + uint16_t seqNumber = 0; + + if (formatBytesToHexaString(ptrNotificationTag80->value, ptrNotificationTag80->length, _bufferFormatLogMessage, sizeof(_bufferFormatLogMessage)) > 0) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "TAG <80> found: %s", _bufferFormatLogMessage); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "TAG <80> found: ..."); + + if (formatBytesToHexaString(ptrNotificationTag81->value, ptrNotificationTag81->length, _bufferFormatLogMessage, sizeof(_bufferFormatLogMessage)) > 0) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "TAG <81> found: %s", _bufferFormatLogMessage); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "TAG <81> found: ..."); + + if (formatBytesToHexaString(ptrNotificationTag0C->value, ptrNotificationTag0C->length, _bufferFormatLogMessage, sizeof(_bufferFormatLogMessage)) > 0) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "TAG <0C> found: %s", _bufferFormatLogMessage); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "TAG <0C> found: ..."); + + + if (extractIntegerFromByteArray(ptrNotificationTag80->value, ptrNotificationTag80->length, &seqNumber)) + { + LPA_NOTIFICATION_EVENT notificationEvent = LPA_NOTIFICATION_UNKNOWN; // Default value + LPA_PROFILE_NOTIFICATION_METADATA* ptrCurrentProfileNotificationMetadata = &(ptrProfileNotificationList->notificationMetadataList[ptrProfileNotificationList->countNotification]); + + if(ptrCurrentProfileNotificationMetadata != NULL) + { + ptrCurrentProfileNotificationMetadata->seqNumber = seqNumber; + ptrCurrentProfileNotificationMetadata->notificationAddressRawDataSize = 0; + + // Extract Notification Event value + notificationEvent = _doExtractNotificationEventValue(ptrNotificationTag81->value, ptrNotificationTag81->length); + ptrCurrentProfileNotificationMetadata->profileManagementOperation = notificationEvent; + + // Add Notification Address + if (ptrNotificationTag0C->length <= LPA_MAX_NOTIFICATION_ADDRESS_RAW_DATA_SIZE) + { + memcpy(ptrCurrentProfileNotificationMetadata->notificationAddressRawData, ptrNotificationTag0C->value, ptrNotificationTag0C->length); + ptrCurrentProfileNotificationMetadata->notificationAddressRawDataSize = ptrNotificationTag0C->length; + } + else + { + isSequenceError = true; + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + } + else // AK added this by security, but this error is more relevant from internal data structure error than a card error. + { + isSequenceError = true; + lpaSetErrorCode(LPA_ERROR_NOTIFICATION_UNDEFINED_ERROR); + } + } + else + { + isSequenceError = true; + lpaSetErrorCode(LPA_ERROR_NOTIFICATION_INVALID_CARD_DATA); + } + } + else + { + isSequenceError = true; + lpaSetErrorCode(LPA_ERROR_NOTIFICATION_INVALID_CARD_DATA); + } + + if (!isSequenceError) + ptrProfileNotificationList->countNotification++; + + // Do cleanup for current notification + ERASE_BERTLV(ptrNotificationTag80); + ERASE_BERTLV(ptrNotificationTag81); + ERASE_BERTLV(ptrNotificationTag0C); + } + + berTLVCurrentInsideSequenceTag = berTLVCurrentInsideSequenceTag->ptrNext; + } + + if (countTLVFound == ptrProfileNotificationList->countNotification) + res = true; + } + else + res = (countTLVFound == 0 && tlvListInsideSequenceTag == NULL); // If no data => OK + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "No notification available"); + res = true; // Ok, APDU data response like "BF2802A000" + } + } + + + // Do cleanup + ERASE_BERTLV(berTLVListNotificationTag); + ERASE_BERTLV(berTLVSequenceTag); + ERASE_BERTLV_LIST(tlvListInsideSequenceTag); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter(s)!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- _doExtractMetadataForGetProfileNotificationList(...) return %s", (res ? "true" : "false")); + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +LPA_NOTIFICATION_EVENT _doExtractNotificationEventValue(unsigned char* ptrDataValue, size_t dataLength) +{ + LPA_NOTIFICATION_EVENT notificationEvent = LPA_NOTIFICATION_UNKNOWN; + + if (dataLength == 2 && ptrDataValue != NULL) + { + uint16_t value = ptrDataValue[0] << 8 | ptrDataValue[1]; + switch (value) + { + case 0x0780: + notificationEvent = LPA_NOTIFICATION_INSTALL; + break; + + case 0x0640: + notificationEvent = LPA_NOTIFICATION_ENABLE; + break; + + case 0x0520: + notificationEvent = LPA_NOTIFICATION_DISABLE; + break; + + case 0x0410: + notificationEvent = LPA_NOTIFICATION_DELETE; + break; + } + } + + return notificationEvent; +} + +////////////////////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////////////////////// + +bool lpaManagerClearProfileNotification(uint16_t sequenceNumber) +{ + bool res = false; + unsigned char byteArraySequenceNumber[16]; + size_t byteArraySequenceNumberSize = 0; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaManagerClearProfileNotification(sequenceNumber=%u)", sequenceNumber); + + if (writeIntegerValueToByteArray(sequenceNumber, byteArraySequenceNumber, sizeof(byteArraySequenceNumber), &byteArraySequenceNumberSize)) + { + RawDataObject* rawDataObjectRemoveNotificationFromList = NULL; + RawDataObject* rawDataObjectSequenceNumber = NULL; + + rawDataObjectSequenceNumber = berTLV_createAndBuildRawDataObject(DER_ATTRIBUTE_TAG, byteArraySequenceNumberSize, byteArraySequenceNumber); + + if (rawDataObjectSequenceNumber != NULL) + rawDataObjectRemoveNotificationFromList = berTLV_createAndBuildRawDataObject(REMOVE_NOTIFICATION_FROM_LIST_TAG, rawDataObjectSequenceNumber->rawDataSize, rawDataObjectSequenceNumber->rawData); + + if (rawDataObjectRemoveNotificationFromList != NULL) + { + // build and Send APDU + uint16_t apduSW = 0x0000; + size_t dataBufferSize = 0; + + if (buildAndSendStoreDataCase4(rawDataObjectRemoveNotificationFromList, &apduSW, _dataBuffer, sizeof(_dataBuffer), &dataBufferSize)) + { + // APDU successfully sent => analyze SW + if((apduSW == 0x9000) || ((apduSW & 0xFF00) == 0x9100)) + { + LPA_DELETE_NOTIFICATION_STATUS deleteNotificationStatus = _doExtractClearProfileNotificationResponse(_dataBuffer, dataBufferSize); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaManagerClearProfileNotification(): deleteNotificationStatus = %d", deleteNotificationStatus); + + switch (deleteNotificationStatus) + { + case LPA_DELETE_NOTIFICATION_OK: + // operation done successfully + res = true; + break; + + case LPA_DELETE_NOTIFICATION_NOTHING_TO_DELETE: + lpaSetErrorCode(LPA_ERROR_NOTIFICATION_NOTHING_TO_DELETE); + break; + + case LPA_DELETE_NOTIFICATION_UNDEFINED_ERROR: + lpaSetErrorCode(LPA_ERROR_NOTIFICATION_UNDEFINED_ERROR); + break; + + default: + lpaSetErrorCode(LPA_ERROR_NOTIFICATION_UNKNOWN_ERROR); + } + } + else + lpaSetErrorCode(LPA_ERROR_INVALID_SW); + } + + // Do memory cleanup + ERASE_RAWDATAOBJECT(rawDataObjectRemoveNotificationFromList); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "rawDataObjectRemoveNotificationFromList is NULL!"); + + // Moved here, can be defined out of rawDataObjectRemoveNotificationFromList + ERASE_RAWDATAOBJECT(rawDataObjectSequenceNumber); + + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Unable to write sequenceNumber into byte array!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaManagerClearProfileNotification() return %s", (res ? "true" : "false")); + return res; +} + + +LPA_DELETE_NOTIFICATION_STATUS _doExtractClearProfileNotificationResponse(unsigned char *ptrData, size_t dataSize) +{ + LPA_DELETE_NOTIFICATION_STATUS deleteNotificationStatus = LPA_DELETE_NOTIFICATION_UNKNOWN; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ _doExtractClearProfileNotificationResponse(...)"); + + if (ptrData != NULL && dataSize > 0) + { + bool tagFound = false; + BeerTLV* berTLVAttributeTag = NULL; + BeerTLV* berTLVRemoveNotificationTag = NULL; + + berTLVRemoveNotificationTag = berTLV_extractTagUInt16(REMOVE_NOTIFICATION_FROM_LIST_TAG, ptrData, dataSize, &tagFound); + if (berTLVRemoveNotificationTag != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "BERTLV tag <%X> found", REMOVE_NOTIFICATION_FROM_LIST_TAG); + berTLVAttributeTag = berTLV_extractTagUInt16(DER_ATTRIBUTE_TAG, berTLVRemoveNotificationTag->value, berTLVRemoveNotificationTag->length, &tagFound); + } + + if (berTLVAttributeTag != NULL && berTLVAttributeTag->length == 1) + { + switch (berTLVAttributeTag->value[0]) + { + case 0: + deleteNotificationStatus = LPA_DELETE_NOTIFICATION_OK; + break; + + case 1: + deleteNotificationStatus = LPA_DELETE_NOTIFICATION_NOTHING_TO_DELETE; + break; + + case 127: + deleteNotificationStatus = LPA_DELETE_NOTIFICATION_UNDEFINED_ERROR; + break; + + default: + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, " -> Incorrect deleteNotificationStatus returned by the card: 0x%02x", berTLVAttributeTag->value[0]); + break; + } + } + + // Do cleanup + ERASE_BERTLV(berTLVRemoveNotificationTag); + ERASE_BERTLV(berTLVAttributeTag); + + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter(s)!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- _doExtractClearProfileNotificationResponse(...) return %d", deleteNotificationStatus); + + return deleteNotificationStatus; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +void _sendEventCallbackProgressText(const LPA_EventCallback* ptrEventCallback, size_t eventType, const char* ptrText) +{ + if ((ptrEventCallback != NULL) && (ptrText != NULL)) + { + if (ptrEventCallback->_lpaEventProgressText != NULL) + ptrEventCallback->_lpaEventProgressText(ptrEventCallback->_appParameter, eventType, ptrText); + } +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +void _sendEventCallbackProgressValue(LPA_EventCallback* ptrEventCallback, size_t eventType, size_t valueMin, size_t currentValue, size_t valueMax) +{ + if (ptrEventCallback != NULL) + { + if (ptrEventCallback->_lpaEventProgressValue != NULL) + ptrEventCallback->_lpaEventProgressValue(ptrEventCallback->_appParameter, eventType, valueMin, currentValue, valueMax); + } +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool _lpaManagerGetEuiccChallenge(LPA_GET_EUICC* ptrGetEUICC) +{ + return lpaManagerES10b_GetEuiccChallenge(ptrGetEUICC); +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool _lpaManagerPrepareCtxParam(const char* ptrMatchingId, const unsigned char* ptrDeviceInfoTlv, size_t deviceInfoTlvSize, RawDataObject ** ptrCtxParam) +{ + bool res = false; + bool isError = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_lpaManagerPrepareCtxParam() ..."); + + // Note: Given parameters pointers are checked not NULL below in the code, not at the beginning + + RawDataObject* ptrRawDataObjectMatchingId = NULL; + + if ((ptrDeviceInfoTlv != NULL) && (deviceInfoTlvSize > 0) && (ptrCtxParam != NULL)) + { + // Matching Id is optional + if (ptrMatchingId != NULL) + { + if (strlen(ptrMatchingId) > 0) + ptrRawDataObjectMatchingId = berTLV_createAndBuildRawDataObject(0x80, strlen(ptrMatchingId), (const unsigned char*)ptrMatchingId); + else + { + ptrRawDataObjectMatchingId = berTLV_createAndBuildRawDataObject(0x80, 0, NULL); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Matching Id is empty"); + } + + if (ptrRawDataObjectMatchingId == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Unable to create RawDataObjectMatchingId!"); + isError = true; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Matching Id is missing (NULL pointer"); + + // Create now CtxParams + if (!isError) + { + ERASE_RAWDATAOBJECT(*ptrCtxParam); + + if (ptrRawDataObjectMatchingId != NULL) + { + RawDataObject* rawDataObjectDeviceInfoTlv = rawDataObject_allocate(); + + // Update reference without new allocation => do not remove it + rawDataObjectDeviceInfoTlv->rawData = (unsigned char*)ptrDeviceInfoTlv; + rawDataObjectDeviceInfoTlv->rawDataSize = deviceInfoTlvSize; + + RawDataObject* rawDataObjectPart1And2 = rawDataObject_concat(ptrRawDataObjectMatchingId, rawDataObjectDeviceInfoTlv); + + rawDataObjectDeviceInfoTlv->rawData = NULL; // Reset memory pointer, no action on data source ptrDeviceInfoTlv + + // Allocate new buffer that contains new BERT TLV created + if (rawDataObjectPart1And2 != NULL) + { + *ptrCtxParam = berTLV_createAndBuildRawDataObject(0xA0, rawDataObjectPart1And2->rawDataSize, rawDataObjectPart1And2->rawData); + + ERASE_RAWDATAOBJECT(rawDataObjectPart1And2); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to create intermediate RawData \"rawDataObjectPart1And2\"."); + lpaSetErrorCode(LPA_ERROR_INVALID_CTX_PARAM); + } + + ERASE_RAWDATAOBJECT(rawDataObjectDeviceInfoTlv); + } + else + { + *ptrCtxParam = berTLV_createAndBuildRawDataObject(0xA0, deviceInfoTlvSize, ptrDeviceInfoTlv); + } + + if (*ptrCtxParam != NULL) + { + if (formatBytesToHexaString((const unsigned char *)(*ptrCtxParam)->rawData, (*ptrCtxParam)->rawDataSize, _bufferFormatLogMessage, sizeof(_bufferFormatLogMessage)) > 0) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "CtxParam (%llu bytes): <%s>", (long long unsigned)(*ptrCtxParam)->rawDataSize, _bufferFormatLogMessage); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "CtxParam (%llu bytes): ...", (long long unsigned)(*ptrCtxParam)->rawDataSize); + + res = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to allocate ptrCtxParam."); + lpaSetErrorCode(LPA_ERROR_INVALID_CTX_PARAM); + } + } + + ERASE_RAWDATAOBJECT(ptrRawDataObjectMatchingId); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** + * Get EUICCInfo1 or EUICCInfo2 with management of retry loop + * @param eUICCinfoTag Request Tag: GET_EUICC_INFO1_DGI_TAG or GET_EUICC_INFO2_DGI_TAG + * @param ptrGetEUICC Pointer on LPA_GET_EUICC data structure to fill + * @return True if Get EUICCInfo terminated OK + */ +bool _lpaManagerGetEuiccInfoWithRetry(const unsigned short eUICCinfoTag, LPA_GET_EUICC* ptrGetEUICC) +{ + bool res = false; + + int nbExecGetResp = LPA_LOOP_NUMBER_FOR_CHAINED_GET_RESPONSE; // Maximum of attempts to perform in case of problem on GetResponse chaining + + if ((ptrGetEUICC != NULL) && (eUICCinfoTag == GET_EUICC_INFO1_DGI_TAG || eUICCinfoTag == GET_EUICC_INFO2_DGI_TAG)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_lpaManagerGetEuiccInfoWithRetry: Request for get EUICCInfo%s", (eUICCinfoTag == GET_EUICC_INFO1_DGI_TAG)?"1":"2"); + + // Manage execution / retry loop + while(nbExecGetResp > 0) + { + // If GetResponse Chaining issue occur, _lpaManagerGetEuiccInfo1() will return false + if(lpaManagerES10b_GetEuiccInfo(eUICCinfoTag, ptrGetEUICC)) + { + // No chaining error detected, end execution loop + nbExecGetResp = 0; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Get EUICCInfo OK."); + res = true; + } + else + { + // Decrease execution loop. If Retry not enabled, will reach 0 so no retry + nbExecGetResp--; + + // Retry management + if(lpaGetErrorCodeNoClear() == SE_MEDIA_E_CHAINING_GET_RESPONSE && LPA_RETRY_CHAINED_GET_RESPONSE_MGT) + { + // If last loop not reached, clear error code to execute another attempt + // Else stay on error SE_MEDIA_E_CHAINING_GET_RESPONSE + if (nbExecGetResp > 0) + { + lpaResetErrorCode(); + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "_lpaManagerGetEuiccInfoWithRetry: GetResponse chaining issue detected, try another time, nbExecGetResp = %d", nbExecGetResp); + + // Avoid memory leak because assigned by lpaManagerES10b_GetEuiccInfo() through ES10b _storeHexBase64StructureRawDataPair() + ERASE_RAWDATAOBJECT(ptrGetEUICC->ptrEUICC); + ERASE_RAWDATAOBJECT(ptrGetEUICC->prtEUICC_Base64); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to get EUICCInfo!"); + // Error code lpaSetErrorCode() will be set by lpaManagerES10b_GetEuiccInfo() + nbExecGetResp = 0; // End execution loop, not recoverable error condition + } + } + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerGetEuiccInfoWithRetry: Invalid parameter!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** + * Get status of flag "deviceInfoExtensibilitySupport" in object "RspCapability" returned in EUICCInfo2 + * @param ptrGetEUICC Pointer on EUICCInfo2, LPA_GET_EUICC type + * @param ptrDeviceInfoExtensibilitySupport Boolean variable that will receive status of flag ptrDeviceInfoExtensibilitySupport + * @return True if parsing is correct + */ +bool _lpaManagerGetFlag_deviceInfoExtensibilitySupport(const LPA_GET_EUICC* ptrEUICCInfo2, bool* ptrDeviceInfoExtensibilitySupport) +{ + bool res = false; + + BeerTLV * BF22_mainTLV = NULL; + + BerTLVList * BF22_MainSequence = NULL; + uint8_t BF22_MainSequenceCount = 0; + BerTLVList * BF22_MainSequenceParser = NULL; + BeerTLV * BF22_MainSequenceCurrent = NULL; + + char display_rspCapability[70]; // Enough to display 256 bits BITSTRING, that shall never be reached + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_lpaManagerGetFlag_deviceInfoExtensibilitySupport()..."); + + if(ptrEUICCInfo2 != NULL && ptrEUICCInfo2->ptrEUICC != NULL && ptrDeviceInfoExtensibilitySupport != NULL) + { + // Check if EUICCInfo2 not empty, with minimum TL info + if(ptrEUICCInfo2->ptrEUICC->rawDataSize > 2) + { + // Extract main BERTLV object + BF22_mainTLV = berTLV_extractTagUInt16(0xBF22, ptrEUICCInfo2->ptrEUICC->rawData, ptrEUICCInfo2->ptrEUICC->rawDataSize, NULL); + if(BF22_mainTLV != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Main EUICCInfo2 TLV object BF22 found, generate SEQUENCE list..."); + + // Generate BERTLV SEQUENCE list to find object rspCapability (Tag <88>) + BF22_MainSequence = berTLV_extractList(BF22_mainTLV->value , BF22_mainTLV->length, &BF22_MainSequenceCount); + + // At least one object shall be present in list + if(BF22_MainSequence != NULL && BF22_MainSequenceCount > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "SEQUENCE list OK, search for rspCapability object (Tag <88>)..."); + + BF22_MainSequenceParser = BF22_MainSequence; + + while(BF22_MainSequenceParser != NULL) + { + BF22_MainSequenceCurrent = BF22_MainSequenceParser->berTLV; + + if(BF22_MainSequenceCurrent->tag == 0x88) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Found rspCapability object <88>, length: %lu", (long unsigned)BF22_MainSequenceCurrent->length); + + if(BF22_MainSequenceCurrent->length > 0) + { + memset(display_rspCapability, 0, sizeof(display_rspCapability)); + formatBytesToHexaString(BF22_MainSequenceCurrent->value, BF22_MainSequenceCurrent->length, display_rspCapability, sizeof(display_rspCapability)); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "rspCapability value: 0x%s", display_rspCapability); + + // Check if deviceInfoExtensibilitySupport (Bit 4) is set in BITSTRING rspCapability object + if(checkBitSetInStaticASN1BitString(BF22_MainSequenceCurrent->value, BF22_MainSequenceCurrent->length, 4, ptrDeviceInfoExtensibilitySupport)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "deviceInfoExtensibilitySupport flag (Bit 4) is %s set",(*ptrDeviceInfoExtensibilitySupport)?"":"not"); + res = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerGetFlag_deviceInfoExtensibilitySupport: Error while parsing BITSTRING rspCapability object!"); + lpaSetErrorCode(LPA_ERROR_PROCESSING_ERROR); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerGetFlag_deviceInfoExtensibilitySupport: rspCapability (Tag <88>) object empty!"); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_EUICC_INFO); + } + + break; // No need to parse any other object whatever is result + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Found object with tag <%X>, go to next one", BF22_MainSequenceCurrent->tag); + + // Go to next object + BF22_MainSequenceParser = BF22_MainSequenceParser->ptrNext; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerGetFlag_deviceInfoExtensibilitySupport: Cannot create main sequence objects list or list empty!"); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_EUICC_INFO); + } + + // Memory cleanup; + ERASE_BERTLV(BF22_mainTLV); + + ERASE_BERTLV_LIST(BF22_MainSequence); + BF22_MainSequenceParser = NULL; + BF22_MainSequenceCurrent = NULL; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerGetFlag_deviceInfoExtensibilitySupport: Cannot find main EUICCInfo2 BF22 object!"); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_EUICC_INFO); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerGetFlag_deviceInfoExtensibilitySupport: EUICCInfo2 empty!"); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_EUICC_INFO); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerGetFlag_deviceInfoExtensibilitySupport: Invalid parameter!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_lpaManagerGetFlag_deviceInfoExtensibilitySupport() return %s", (res)?"True":"False"); + + return res; +} + + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** + * Filter device capabilities informations in deviceInfo data depending deviceInfoExtensibilitySupport flag is set or not + * List of allowed capabilities when flag is not set are defined in LPA_LIST_ALLOWED_DEVICE_TAGS_NO_EXTENSIBILITY_SUPPORT / LPA_LIST_ALLOWED_DEVICE_TAGS_NO_EXTENSIBILITY_SUPPORT_SIZE + * @param ptrRawDeviceInfo Pointer on raw deviceInfo data, unsigned byte array format + * @param rawDeviceInfoSize Size of raw deviceInfo data + * @param ptrFilteredDeviceInfo Pointer on byte array that will receive filtered deviceInfo + * @param ptrFilteredDeviceInfoSize Pointer on size_t variable that will receive size of filtered deviceInfo + * @param maxFilteredDeviceInfoSize Maximum size output array for filtered information can store. Cannot be smaller that raw device information data + * @param deviceInfoExtensibilitySupport Status of flag deviceInfoExtensibilitySupport, true if supported by eUICC + * @param deviceInfoFilteringEnabled If true filtering is enabled, else no filtering will be performed + * @return True if processing is correct, else false + */ +bool _lpaManagerFilterDeviceCapabitilitiesInformation(const unsigned char * ptrRawDeviceInfo, const size_t rawDeviceInfoSize, + unsigned char * ptrFilteredDeviceInfo, size_t * ptrFilteredDeviceInfoSize, const size_t maxFilteredDeviceInfoSize, const bool deviceInfoExtensibilitySupport, + const bool deviceInfoFilteringEnabled) +{ + bool res = false; + + BeerTLV * inBERTLVmainDeviceInfo = NULL; + BeerTLV * inBERTLVtac = NULL; // Mandatory object + BeerTLV * inBERTLVdeviceCapabilities = NULL; // Mandatory object but can be empty + BeerTLV * inBERTLVimei = NULL; // Optional object + + BerTLVList * deviceCapabilities_Main = NULL; // To parse device capabilities list + uint8_t deviceCapabilities_Count = 0; + BerTLVList * deviceCapabilities_Parser = NULL; + BeerTLV * deviceCapabilities_Current = NULL; + + // Temp objects for rebuild of deviceCapabilities list data + RawDataObject * rawDataOutDeviceCapabilities_Data = NULL; + RawDataObject * rawCapabilityTemp = NULL; + + // Final rebuild of deviceInformation object for output + RawDataObject * rawDataOutBERTLV_tac = NULL; + RawDataObject * rawDataOutBERTLV_deviceCapabilities = NULL; + RawDataObject * rawDataOutBERTLV_Imei = NULL; + + RawDataObject * rawDataOutDeviceInfoData = NULL; + RawDataObject * rawDataOutDeviceInfoFullTLV = NULL; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_lpaManagerFilterDeviceCapabitilitiesInformation()..."); + + // Note: Device info shall be at least 10 bytes (Main Tag + Mandatory Tac Object & Device capabilities list container, even if empty) + // Output deviceInfo cannot be smaller than input deviceInfo + if(ptrRawDeviceInfo != NULL && rawDeviceInfoSize > 9 && ptrFilteredDeviceInfo != NULL && ptrFilteredDeviceInfoSize != NULL && maxFilteredDeviceInfoSize > 9 && rawDeviceInfoSize <= maxFilteredDeviceInfoSize) + { + lpaCoreLogAppendByteArray(SDK_LOG_LEVEL_DEBUG, "deviceInfo before processing", "deviceInfo", (unsigned char *)ptrRawDeviceInfo, rawDeviceInfoSize); // Cast avoid warning + + // Init output device info size, in case of failure during process + *ptrFilteredDeviceInfoSize = 0; + + // Extract / check main device info object + inBERTLVmainDeviceInfo = berTLV_extractTagUInt8(0xA1, ptrRawDeviceInfo, rawDeviceInfoSize, NULL); + if(inBERTLVmainDeviceInfo != NULL) + { + // Extract main TLV objects in device info + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Main TLV object found, extracting deviceInfo sub TLV objects"); + + inBERTLVtac = berTLV_extractTagUInt8(0x80, inBERTLVmainDeviceInfo->value, inBERTLVmainDeviceInfo->length, NULL); + inBERTLVdeviceCapabilities = berTLV_extractTagUInt8(0xA1, inBERTLVmainDeviceInfo->value, inBERTLVmainDeviceInfo->length, NULL); + inBERTLVimei = berTLV_extractTagUInt8(0x82, inBERTLVmainDeviceInfo->value, inBERTLVmainDeviceInfo->length, NULL); + + // Check mandatory fields + if(inBERTLVtac != NULL && inBERTLVdeviceCapabilities != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Mandatory sub TLV objects found, analyzing deviceCapabilities list"); + + // Check if device capabilities list is not empty or no filtering to apply + if((inBERTLVdeviceCapabilities->length > 0) && !deviceInfoExtensibilitySupport && deviceInfoFilteringEnabled) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "eUICC does not support extended device capabilities, filtering is enabled and deviceCapabilities is not empty, begin filtering..."); + // Allocate create RawData object that will receive filtered device capabilities list and newly generated deviceInfo data + // New objects will be equal or smaller than originals, so allocate original lengths + rawDataOutDeviceCapabilities_Data = rawDataObject_create(NULL, inBERTLVdeviceCapabilities->length); + rawDataOutDeviceInfoData = rawDataObject_create(NULL, inBERTLVmainDeviceInfo->length); + if(rawDataOutDeviceCapabilities_Data != NULL && rawDataOutDeviceInfoData != NULL) + { + // Generate BERTLV List for device capabilities + deviceCapabilities_Main = berTLV_extractList(inBERTLVdeviceCapabilities->value , inBERTLVdeviceCapabilities->length, &deviceCapabilities_Count); + if(deviceCapabilities_Main != NULL && deviceCapabilities_Count > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Parsing deviceCapabilities list TLV objects"); + + deviceCapabilities_Parser = deviceCapabilities_Main; + + while(deviceCapabilities_Parser != NULL) + { + deviceCapabilities_Current = deviceCapabilities_Parser->berTLV; + + // If capability in approved in list, add it to output device capability list + if(isElementPresentInArrayByte(LPA_LIST_ALLOWED_DEVICE_TAGS_NO_EXTENSIBILITY_SUPPORT, LPA_LIST_ALLOWED_DEVICE_TAGS_NO_EXTENSIBILITY_SUPPORT_SIZE, (unsigned char)(deviceCapabilities_Current->tag &0x00FF))) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Capability tag <%X> is allowed, adding it in new capabilities list", deviceCapabilities_Current->tag); + // Convert current BERTLV into Rawdata + rawCapabilityTemp = berTLV_buildRawDataObject(deviceCapabilities_Current); + // Any error with creating Rawdata object from current TLV will exit on error + if(rawCapabilityTemp == NULL) + break; + + // Append current TLV object to deviceCapability list. If failed exit on error + if(! rawDataObject_appendRawDataArray(rawDataOutDeviceCapabilities_Data, rawCapabilityTemp->rawData, rawCapabilityTemp->rawDataSize)) + break; + + ERASE_RAWDATAOBJECT(rawCapabilityTemp); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Capability tag <%X> is not allowed, disposed off", deviceCapabilities_Current->tag); + + // Go to next object in list + deviceCapabilities_Parser = deviceCapabilities_Parser->ptrNext; + } + // Memory cleanup in case of exit on error + ERASE_RAWDATAOBJECT(rawCapabilityTemp); + + // If exit on error occurred during filtering / building new deviceCapability list, end of input deviceCapabilities list will be not reached + if(deviceCapabilities_Parser == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Generating output data..."); + // At this step we will consider everything is OK. If any error occurs this status will be invalidated + res = true; + + // Convert "tac" TLV in rawData with checking + rawDataOutBERTLV_tac = berTLV_buildRawDataObject(inBERTLVtac); + if(rawDataOutBERTLV_tac == NULL) + res = false; + + // Build final filtered "deviceCapabilities" BERTLV and convert it in rawData with checking + if(res) + { + rawDataOutBERTLV_deviceCapabilities = berTLV_createAndBuildRawDataObject(0xA1, rawDataOutDeviceCapabilities_Data->rawDataSize, rawDataOutDeviceCapabilities_Data->rawData); + if(rawDataOutBERTLV_deviceCapabilities == NULL) + res = false; + } + + // Convert "imei" if field exists (Optional) + if(res && inBERTLVimei != NULL) + { + rawDataOutBERTLV_Imei = berTLV_buildRawDataObject(inBERTLVimei); + if(rawDataOutBERTLV_Imei == NULL) + res = false; + } + + // Concatenate new "deviceInfo" data + // Add "tac" data + if(res) + { + if(! rawDataObject_appendRawDataArray(rawDataOutDeviceInfoData, rawDataOutBERTLV_tac->rawData, rawDataOutBERTLV_tac->rawDataSize)) + res = false; + } + // Add filtered "deviceCapabilities" list data + if(res) + { + if(! rawDataObject_appendRawDataArray(rawDataOutDeviceInfoData, rawDataOutBERTLV_deviceCapabilities->rawData, rawDataOutBERTLV_deviceCapabilities->rawDataSize)) + res = false; + } + // Add "imei" if exist (Optional) + if(res && inBERTLVimei != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Imei object is defined"); + if(! rawDataObject_appendRawDataArray(rawDataOutDeviceInfoData, rawDataOutBERTLV_Imei->rawData, rawDataOutBERTLV_Imei->rawDataSize)) + res = false; + } + + // Generate rawData of final BERTLV object for "deviceInfo" with checking + if(res) + { + rawDataOutDeviceInfoFullTLV = berTLV_createAndBuildRawDataObject(0xA1, rawDataOutDeviceInfoData->rawDataSize, rawDataOutDeviceInfoData->rawData); + if(rawDataOutDeviceInfoFullTLV == NULL) + res = false; + } + + // Copy final result in output "deviceInfo" bytes array and return size + if(res) + { + memcpy(ptrFilteredDeviceInfo, rawDataOutDeviceInfoFullTLV->rawData, rawDataOutDeviceInfoFullTLV->rawDataSize); + *ptrFilteredDeviceInfoSize = rawDataOutDeviceInfoFullTLV->rawDataSize; + } + + // Memory cleanup + ERASE_RAWDATAOBJECT(rawDataOutBERTLV_tac); + ERASE_RAWDATAOBJECT(rawDataOutBERTLV_deviceCapabilities) + ERASE_RAWDATAOBJECT(rawDataOutBERTLV_Imei); + + ERASE_RAWDATAOBJECT(rawDataOutDeviceInfoFullTLV); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerFilterDeviceCapabitilitiesInformation: Failure while filtering / building new deviceCapability list!"); + lpaSetErrorCode(LPA_ERROR_PROCESSING_ERROR); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerFilterDeviceCapabitilitiesInformation: Cannot build device capabilities list!"); + lpaSetErrorCode(LPA_ERROR_INVALID_DEVICE_INFO_TLV); + } + + // Memory cleanup + ERASE_BERTLV_LIST(deviceCapabilities_Main); + deviceCapabilities_Parser = NULL; + deviceCapabilities_Current = NULL; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerFilterDeviceCapabitilitiesInformation: Cannot create rawData buffers for output deviceInfo buffer"); + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + + // Memory cleanup (Done here in case of fail on only one of these objects creation) + ERASE_RAWDATAOBJECT(rawDataOutDeviceCapabilities_Data); + ERASE_RAWDATAOBJECT(rawDataOutDeviceInfoData); + } + else + { + // Device capability list empty or no filtering to apply (eUICC support extended capabilities or filtering disabled) => Nothing to filter, Cancel + // operation and re-copy deviceInfo as it in output + // Already check that source cannot be greater than destination + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "eUICC supports Extended Device Capabilities or filtering is disabled or deviceCapabilities list is empty, no filtering to apply"); + + memcpy(ptrFilteredDeviceInfo, ptrRawDeviceInfo, rawDeviceInfoSize); + *ptrFilteredDeviceInfoSize = rawDeviceInfoSize; + res = true; + } + + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerFilterDeviceCapabitilitiesInformation: Invalid deviceInfo! Mandatory sub TLV object missing (tac or deviceCapabilities)"); + lpaSetErrorCode(LPA_ERROR_INVALID_DEVICE_INFO_TLV); + } + + // Memory cleanup + ERASE_BERTLV(inBERTLVtac); + ERASE_BERTLV(inBERTLVdeviceCapabilities); + ERASE_BERTLV(inBERTLVimei); + + ERASE_BERTLV(inBERTLVmainDeviceInfo); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerFilterDeviceCapabitilitiesInformation: Invalid deviceInfo! (Main TLV object not found or invalid TLV format)"); + lpaSetErrorCode(LPA_ERROR_INVALID_DEVICE_INFO_TLV); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerFilterDeviceCapabitilitiesInformation: Invalid parameter!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + if(res) + lpaCoreLogAppendByteArray(SDK_LOG_LEVEL_DEBUG, "deviceInfo after processing", "deviceInfo", ptrFilteredDeviceInfo, *ptrFilteredDeviceInfoSize); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_lpaManagerFilterDeviceCapabitilitiesInformation() return %s", (res)?"True":"False"); + + return res; +} + + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool lpaManagerInitiateAuthentication(ptr_serverData p_serverData, const LPA_EventCallback* ptrLpaEventCallback, const char * ptrEuiccChallenge, const char * ptrEuiccInfo1, const char* ptrSmdpAddress) +{ + return lpaManagerES9Plus_InitiateAuthentication(p_serverData, ptrLpaEventCallback, ptrEuiccChallenge, ptrEuiccInfo1, ptrSmdpAddress); +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool _lpaManagerAuthenticateServer(ptr_serverData p_serverData, const LPA_EventCallback* ptrLpaEventCallback, RawDataObject * ptrCtxParam, AUTHENTICATE_SERVER_RESPONSE* ptrAuthServerResp) +{ + return lpaManagerES10b_AuthenticateServer(p_serverData, ptrLpaEventCallback, ptrCtxParam, ptrAuthServerResp); +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool _lpaManagerAuthenticateClient(ptr_serverData p_serverData, const LPA_EventCallback* ptrLpaEventCallback, const char* ptrSmdpAddress, const unsigned char* ptrAuthenticateServerResponse) +{ + return lpaManagerES9Plus_AuthenticateClient(p_serverData, ptrLpaEventCallback, ptrSmdpAddress, ptrAuthenticateServerResponse); +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool _lpaManagerGetBoundProfilePackage(ptr_serverData p_serverData, const LPA_EventCallback* ptrLpaEventCallback, const char* ptrSmdpAddress, const unsigned char* ptrPrepareDownloadResponse, bool * cancelForBPPerrors) +{ + return lpaManagerES9Plus_GetBoundProfilePackage(p_serverData, ptrLpaEventCallback, ptrSmdpAddress, ptrPrepareDownloadResponse, cancelForBPPerrors); +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool _lpaManagerPrepareDownload(ptr_serverData p_serverData, const LPA_EventCallback* ptrLpaEventCallback, const char * ptrStringHashCC, PREPARE_DOWNLOAD_RESPONSE* ptrPrepareDownloadResp) +{ + return lpaManagerES10b_PrepareDownload(p_serverData, ptrLpaEventCallback, ptrStringHashCC, ptrPrepareDownloadResp); +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** +* Cancel download session on card and server side +* @param p_serverData Server data containing transactionID (structure pointer, ptr_serverData type) +* @param p_reasonCode Cancel reason code as defined in SGP.22 +* @param ptrSmdpAddress SM-DP address, string format +* @return True if cancel is successful +*/ +bool _lpaManagerCancelSession(const char * transactionID, const unsigned int p_reasonCode, const char* ptrSmdpAddress, const LPA_EventCallback* ptrLpaEventCallback) +{ + bool res = false; + CANCEL_SESSION_RESPONSE *ptrCancelSessionResp = NULL; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_lpaManagerCancelSession..."); + + if ((ptrSmdpAddress != NULL) && (transactionID != NULL) && (strlen(transactionID) > 0) && (strlen(transactionID) < LPA_TRANSACTION_ID_MAX_SIZE) && + isElementPresentInArrayUInt(LPA_ALLOWED_CANCEL_SESSION_CODE_LIST, LPA_ALLOWED_CANCEL_SESSION_CODE_LIST_SIZE, p_reasonCode)) + { + ptrCancelSessionResp = lpaCoreMemoryAlloc(sizeof(CANCEL_SESSION_RESPONSE)); + if (ptrCancelSessionResp != NULL) + { + memset(ptrCancelSessionResp, 0x00, sizeof(CANCEL_SESSION_RESPONSE)); + res = lpaManagerES10b_CancelSession(transactionID, p_reasonCode, ptrCancelSessionResp); + if(res) res = lpaManagerES9plus_CancelSession(transactionID, ptrCancelSessionResp, ptrSmdpAddress, ptrLpaEventCallback); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerCancelSession: Cannot allocate memory for response buffer."); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerCancelSession: Parameters error."); + + if(res) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_lpaManagerCancelSession: Operation is successful."); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerCancelSession: Operation failed."); + + if (ptrCancelSessionResp != NULL) + { + lpaCoreMemoryFree(ptrCancelSessionResp); + ptrCancelSessionResp = NULL; + } + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** +* Extract element at position x (After '$' delimiter number x) in Activation Code. So SM-DP adress is at postion 1 +* Note: If size of element to extract exceeds maximum output buffer size, function result will be false but output buffer will contain truncated value of found element +* @param ptrActivationCodeStr Activation Code string +* @param elementNumber Position of element to found. Start at 1 +* @param ptrElement Buffer that will receive element data, string format +* @param maxElementSize Maximum size of buffer data, including '0' at the end of string. So shall be at least 2 +* @return True if element x successfully extracted +*/ +bool _extractElementFromActivationCode(const char * ptrActivationCodeStr, const int elementNumber, char * ptrElement, const int maxElementSize) +{ + bool res = false; + int i; + int j; + int len; + int countDollar = 0; + + if((ptrActivationCodeStr != NULL) && (elementNumber > 0) && (ptrElement != NULL) && (maxElementSize > 1)) + { + // Security in case of asking an element above what is available in Activation Code + if (countCharOccurencesInString(ptrActivationCodeStr, '$') >= elementNumber) + { + len = strlen(ptrActivationCodeStr); + i = 0; + // Stop if end of activation string reached or element found or found but overflow detected + while ((i < len) && (!res) && (countDollar < elementNumber)) + { + if (ptrActivationCodeStr[i] == '$') countDollar++; + + // Increment "i" here allow to go directly to next element after '$' separator + i++; + + // Element # found + if (countDollar == elementNumber) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_extractElementFromActivationCode: Target element found"); + + j = 0; + // Stop to copy in output buffer if end of string reached, max size of output buffer reached or another delimiter reached + while (((i + j) < len) && (j < maxElementSize) && (ptrActivationCodeStr[i + j] != '$')) + { + *(ptrElement + j) = ptrActivationCodeStr[i + j]; + j++; + } + // Check if no overflow of reception buffer. If overflow, extraction will be considered as failed. + if (j < maxElementSize) + { + // Terminate output buffer to have a string + *(ptrElement + j) = 0; + res = true; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_extractElementFromActivationCode: Element extracted successfully"); + } + else + { + // In case of overflow terminate output buffer to avoid undefined length string. + *(ptrElement + maxElementSize - 1) = 0; + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_extractElementFromActivationCode: Element exceeds output buffer size. Return it truncated."); + } + } + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_extractElementFromActivationCode: Not enough '$' separators in Activation Code to find target element"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_extractElementFromActivationCode: Invalid Parameter(s)!"); + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** +* Check if Activation Code is correct (String valid / size, syntax...) +* @param ptrActivationCodeStr Activation Code string to analyze +* @return true if Activation Code is correct, else false +*/ +bool _checkActivationCodeValid(const char* ptrActivationCodeStr) +{ + bool res = false; + int nbDollars; + + // At least 5 characters shall be present + if (ptrActivationCodeStr != NULL && (strlen(ptrActivationCodeStr) > 4) && (strlen(ptrActivationCodeStr) < LPA_ACTIVATION_CODE_MAX_STRING_BUFFER_SIZE)) + { + // Activation Code contains 2 to 4 '$' signs + nbDollars = countCharOccurencesInString(ptrActivationCodeStr, '$'); + if ((nbDollars > 1) && (nbDollars < 5)) + { + // Check Activation Code begin with "1$" + if ((ptrActivationCodeStr[0] == '1') && (ptrActivationCodeStr[1] == '$')) + res = true; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_checkActivationCodeValid: Invalid Parameter!"); + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** +* Extract SM-DP Address and MatchingID from Activation Code +* +* @param ptrActivationCodeStr - Activation Code to check, String format +* @param ptrActivationCode - Data structure that will store SM-DP Address and MatchingID, ACTIVATION_CODE type +* @return True if extraction is successful +*/ +bool _decodeActivationCodeStr(const char* ptrActivationCodeStr, ACTIVATION_CODE* ptrActivationCode) +{ + bool res = false; + bool checkOID_OK = true; // Checking job can be done fully on "res", but allow to isolate OID check result from main result for future needs + size_t lastOIDcharacter = 0; + size_t i = 0; + + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Decode and parse Activation Code..."); + + if ((ptrActivationCodeStr != NULL) && (_checkActivationCodeValid(ptrActivationCodeStr)) && (ptrActivationCode != NULL)) + { + // Try to extract server address, 1st position + res = _extractElementFromActivationCode(ptrActivationCodeStr, 1, ptrActivationCode->smdxAddr, LPA_SMDP_ADDRESS_SIZE); + if (res) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Activation Code parsing: SM-DP server address found: \"%s\".", ptrActivationCode->smdxAddr); + // Check if not empty + if (strlen(ptrActivationCode->smdxAddr) == 0) + { + res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Activation Code parsing: SM-DP server address empty!"); + lpaSetErrorCode(LPA_ERROR_INVALID_ACTIVATION_CODE); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Activation Code parsing: SM-DP server address cannot be found or size exceeds limits."); + lpaSetErrorCode(LPA_ERROR_INVALID_ACTIVATION_CODE); + } + + // If OK for address, try with Matching ID, at 2nd position + if (res) + { + res = _extractElementFromActivationCode(ptrActivationCodeStr, 2, ptrActivationCode->matchingId, LPA_MATCHING_ID_SIZE); + if (res) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Activation Code parsing: MatchingID found: \"%s\".", ptrActivationCode->matchingId); + // Note: Empty Matching ID shall be supported + } + else + { + // Missing delimiter for Matching ID is considered as an error + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Activation Code parsing: MatchingID cannot be found or size exceeds limits."); + lpaSetErrorCode(LPA_ERROR_INVALID_ACTIVATION_CODE); + } + } + + // If OK for address & Matching ID, try with OID, at 3rd position + if (res) + { + // If not found, will be not a blocking point and will set empty string on it + if (_extractElementFromActivationCode(ptrActivationCodeStr, 3, ptrActivationCode->oid, LPA_OID_SIZE)) + { + if(strlen(ptrActivationCode->oid) > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Activation Code parsing: OID found: \"%s\".", ptrActivationCode->oid); + // Perform basic checking on OID given in Activation Code. If invalid, exit on error. + lastOIDcharacter = strlen(ptrActivationCode->oid) - 1; + // Must have at least 3 characters (Minimum format is x.y) + if(strlen(ptrActivationCode->oid) < 3) + checkOID_OK = false; + // Must start with digit 0, 1 or 2 + if(ptrActivationCode->oid[0] < '0' || ptrActivationCode->oid[0] > '2') + checkOID_OK = false; + // Second character must be a dot '.' + if(ptrActivationCode->oid[1] != '.') + checkOID_OK = false; + // Third and last character must be a numeric digit (0..9) + if(ptrActivationCode->oid[2] < '0' || ptrActivationCode->oid[2] > '9' || ptrActivationCode->oid[lastOIDcharacter] < '0' || ptrActivationCode->oid[lastOIDcharacter] > '9') + checkOID_OK = false; + // Nothing else than (0..9) and '.' must be present inside + // 3 first characters and last one already checked + for(i = 3; i < lastOIDcharacter; i++) + { + if(! ((ptrActivationCode->oid[i] >= '0' && ptrActivationCode->oid[i] <= '9') || ptrActivationCode->oid[i] == '.')) + checkOID_OK = false; + } + + if(checkOID_OK) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Activation Code parsing: OID format check OK"); + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Activation Code parsing: OID format check failed."); + lpaSetErrorCode(LPA_ERROR_INVALID_ACTIVATION_CODE); + res = false; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "Activation Code parsing: OID is empty."); + } + else + { + // If OID returned by _extractElementFromActivationCode() has a length, it means that OID was too big, so exit on error + if(strlen(ptrActivationCode->oid) > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Activation Code parsing: OID size exceeds limits."); + lpaSetErrorCode(LPA_ERROR_INVALID_ACTIVATION_CODE); + res = false; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "Activation Code parsing: OID cannot be found."); + + ptrActivationCode->oid[0] = 0; + } + } + + // If OK for Address, Matching ID & OID, try to extract Confirmation Code Required Flag at 4th position. + if (res) + { + // If not found, will be not a blocking point and will set empty string on it + if (_extractElementFromActivationCode(ptrActivationCodeStr, 4, ptrActivationCode->ccRequiredFlag, LPA_CC_REQUIRED_FLAG_SIZE)) + { + // If the Confirmation Code Required Flag is not set, it SHALL not be defined, so the delimiter shall not exist (Condition SHALL in SGP.22 chapter 4.1 Table 8) + if(strlen(ptrActivationCode->ccRequiredFlag) > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Activation Code parsing: Confirmation Code Required Flag found: \"%s\".", ptrActivationCode->ccRequiredFlag); + + // Confirmation Code Required Flag Format check: + // Length must be = 1, value must be '1' (Condition SHALL in SGP.22 chapter 4.1 Table 8) + if((strlen(ptrActivationCode->ccRequiredFlag) != 1) || (ptrActivationCode->ccRequiredFlag[0] != '1')) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Activation Code parsing: Confirmation Code Required Flag is invalid."); + lpaSetErrorCode(LPA_ERROR_INVALID_ACTIVATION_CODE); + res = false; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Activation Code parsing: Confirmation Code Required Flag check OK."); + } + else + { + // Empty value is an error considering that delimiter SHALL not be defined if flag is not set + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Activation Code parsing: Confirmation Code Required Flag is empty."); + lpaSetErrorCode(LPA_ERROR_INVALID_ACTIVATION_CODE); + res = false; + } + } + else + { + // If flag returned by _extractElementFromActivationCode() has a length, it means that OID was too big, so exit on error + if(strlen(ptrActivationCode->ccRequiredFlag) > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Activation Code parsing: Confirmation Code Required Flag size exceeds limits."); + lpaSetErrorCode(LPA_ERROR_INVALID_ACTIVATION_CODE); + res = false; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "Activation Code parsing: Confirmation Code Required Flag cannot be found."); + + ptrActivationCode->ccRequiredFlag[0] = 0; + } + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid Activation Code!"); + lpaSetErrorCode(LPA_ERROR_INVALID_ACTIVATION_CODE); + } + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** +* Check if Activation Code contains Confirmation Code request +* +* @param ptrActivationCodeStr - Activation Code to check, String format +* @return True if contains Confirmation Code request +*/ +bool _checkConfirmationCodeRequestInActivationCodeStr(const char* ptrActivationCodeStr) +{ + bool res = false; + char readFlag[LPA_CC_REQUIRED_FLAG_SIZE]; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Check if Confirmation Code Required Flag present in Activation Code and check value..."); + + if ((ptrActivationCodeStr != NULL) && _checkActivationCodeValid(ptrActivationCodeStr)) + { + // Confirmation Code Required Flag is at 4th position in Activation Code + if (_extractElementFromActivationCode(ptrActivationCodeStr, 4, readFlag, LPA_CC_REQUIRED_FLAG_SIZE)) + { + res = (strcmp(readFlag, "1") == 0) ? true : false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Confirmation Code Required Flag found, status is %s", (res) ? "\"Required.\"" : "\"Not required.\""); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "No Confirmation Code Required Flag found in Activation Code"); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid Activation Code!"); + lpaSetErrorCode(LPA_ERROR_INVALID_ACTIVATION_CODE); + } + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool lpaManagerloadBoundProfilePackage(ptr_serverData p_serverData, PROFILE_INSTALLATION_RESULT *pir, bool * cancelForBPPerrors) +{ + return lpaManagerES10b_LoadBoundProfilePackage(p_serverData, pir, cancelForBPPerrors); +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool extractSeqNumbFromPIR(PROFILE_INSTALLATION_RESULT* ptrPir, uint16_t * ptrSeqNumb) +{ + bool res = false; + BeerTLV *ptrBerTLV_BF37 = NULL, *ptrBerTLV_BF27 = NULL, *ptrBerTLV_BF2F = NULL, *ptrBerTLV_80 = NULL; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "extractSeqNumbFromPIR()..."); + + if ((ptrPir != NULL) && ptrPir->hasResult && (ptrPir->ptrProfileInstallationResultTlv != NULL) && (ptrPir->ptrProfileInstallationResultTlv->rawDataSize > 0) && (ptrSeqNumb != NULL)) + { + ptrBerTLV_BF37 = berTLV_extractTagUInt16(0xBF37, ptrPir->ptrProfileInstallationResultTlv->rawData, ptrPir->ptrProfileInstallationResultTlv->rawDataSize, NULL); + + if (ptrBerTLV_BF37 != NULL && ptrBerTLV_BF37->length > 0) + { + ptrBerTLV_BF27 = berTLV_extractTagUInt16(0xBF27, ptrBerTLV_BF37->value, ptrBerTLV_BF37->length, NULL); + if (ptrBerTLV_BF27 != NULL && ptrBerTLV_BF27->length > 0) + { + ptrBerTLV_BF2F = berTLV_extractTagUInt16(0xBF2F, ptrBerTLV_BF27->value, ptrBerTLV_BF27->length, NULL); + if (ptrBerTLV_BF2F != NULL && ptrBerTLV_BF2F->length > 0) + { + ptrBerTLV_80 = berTLV_extractTagUInt8(0x80, ptrBerTLV_BF2F->value, ptrBerTLV_BF2F->length, NULL); + if (ptrBerTLV_80 != NULL && ptrBerTLV_80->length > 0) + { + //seqNumber + if (extractIntegerFromByteArray(ptrBerTLV_80->value, ptrBerTLV_80->length, ptrSeqNumb)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "The sequence number is: %02X", *ptrSeqNumb); + res = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to get sequence number from installation result! "); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, " Tag <80> not found or invalid TLV format! "); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, " Tag not found or invalid TLV format! "); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, " Tag not found or invalid TLV format! "); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, " Tag not found or invalid TLV format! "); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, " Invalid installation result! "); + + // Cleanup memory + ERASE_BERTLV(ptrBerTLV_80); + ERASE_BERTLV(ptrBerTLV_BF2F); + ERASE_BERTLV(ptrBerTLV_BF27); + ERASE_BERTLV(ptrBerTLV_BF37); + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool _handleNotification(const char* ptrSmdpAddr, size_t smdpAddrSize, const unsigned char* ptrPendingNotification, const LPA_EventCallback* ptrLpaEventCallback, bool* ptrNormalNotifAcknowledge) +{ + return lpaManagerES9Plus_HandleNotification(ptrSmdpAddr, smdpAddrSize, ptrPendingNotification, ptrLpaEventCallback, ptrNormalNotifAcknowledge); +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** +* Calculate hash of Confirmation Code with Transaction ID as defined in SGP.22 chapter 3.1.3 +* +* @param confirmationCode - Confirmation Code data, String +* @param confirmationCodeLength - Confirmation Code length, integer, must be > 0 else error +* @param transactionID Transaction ID, - String Format, 32 CHARACTERS (String conversion of TransactionID) +* @param hashConfirmationCode - Returned calculated value of Confirmation Code Hash, String format, MUST BE AT LEAST 68 CHARACTERS +* @return True if processing OK +*/ +bool _calculateConfirmationCodeHash(const char * confirmationCode, const int confirmationCodeLength, const char * transactionID, char * hashConfirmationCode) +{ + bool res = false; + + uint8_t bufferCalcHash[32] = {0}; + unsigned char tabTransactionID[16] = { 0 }; + char concatHashCCTransationID[48] = { 0 }; + int convLen = 16; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Confirmation Code Hash calculation..."); + + if ((confirmationCode != NULL) && (confirmationCodeLength > 0) && (transactionID != NULL) && (strlen(transactionID) == 32) && + (hashConfirmationCode != NULL)) + { + // Convert Transaction ID string to values tab + if (hexStr2ByteArray((unsigned char *)transactionID, 32, tabTransactionID, &convLen) && (convLen == 16)) + { + calc_sha_256(bufferCalcHash, confirmationCode, confirmationCodeLength); + + // Concatenate Hash Confirmation Code + Transaction ID + memcpy(concatHashCCTransationID, bufferCalcHash, 32); + memcpy(concatHashCCTransationID + 32, tabTransactionID, 16); + + calc_sha_256(bufferCalcHash, &concatHashCCTransationID, 48); + + // Format response in String + check final length + if (formatBytesToHexaString(bufferCalcHash, 32, hashConfirmationCode, 68) == 64) + { + res = true; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Confirmation Code Hash calculation done."); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Confirmation Code Hash calculation: Cannot convert TransactionID in hex."); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Confirmation Code Hash calculation: Parameters problem."); + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** + * Return if PPR1 is defined in PPR flag + * @param pprFlag - PPR flag to evaluate + * @return true if PPR1 is defined in PPR flag + */ +bool _isPPR1definedInPPRflag(const unsigned int pprFlag) +{ + bool pprStatus = false; + + switch(pprFlag) + { + case LPA_PPRDEF_PPR1_PPR2: + case LPA_PPRDEF_PPRUC_PPR1_PPR2: + case LPA_PPRDEF_PPR1: + case LPA_PPRDEF_PPRUC_PPR1: + pprStatus = true; + break; + default: + break; + } + + return pprStatus; +} + +/** + * Return if PPR2 is defined in PPR flag + * @param pprFlag - PPR flag to evaluate + * @return true if PPR2 is defined in PPR flag + */ +bool _isPPR2definedInPPRflag(const unsigned int pprFlag) +{ + bool pprStatus = false; + + switch(pprFlag) + { + case LPA_PPRDEF_PPR2: + case LPA_PPRDEF_PPR1_PPR2: + case LPA_PPRDEF_PPRUC_PPR2: + case LPA_PPRDEF_PPRUC_PPR1_PPR2: + pprStatus = true; + break; + default: + break; + } + + return pprStatus; +} + + +/** + * Get RAT (Rules Authorization Table) from eUICC + * @param ptrGetRATA - Address of pointer that will receive the RawdataObject who will store RAT value + * @return true if operation is correct + */ +bool _lpaManagerGetRAT(RawDataObject ** ptrGetRAT) +{ + return lpaManagerES10b_GetRAT(&*ptrGetRAT); +} + + +/** + * Check if profile can be installed or user must be warned considering its PPR flags and profiles already installed in card + * @param incomingProfileFields - Pointer on incoming profile data's + * @param currenltyInstalledProfiles - Pointer on simplified (PPR check) profiles list installed on eUICC + * @return true if operation was successful + */ +bool _checkIncomingProfilePPRconditionVersusInstalledProfiles(LPA_DOWNLOADED_PROFILE_DATA_FOR_PPR* ptrIncomingProfileData, + const LPA_GET_PROFILES_INFO * ptrCurrentlyInstalledProfiles) +{ + bool res = false; + size_t indexProfile = 0; + bool checkForEnabledPPR1 = true; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_checkIncomingProfilePPRconditionVersusInstalledProfiles()..."); + + if(ptrIncomingProfileData != NULL && ptrCurrentlyInstalledProfiles != NULL) + { + // Profiles retrieval check for warning + if(ptrCurrentlyInstalledProfiles->countProfileInfo < ptrCurrentlyInstalledProfiles->numberProfileInfoFound) + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Found more profiles available on eUICC than retrieved in list. SHALL not happen! eUICC profile parsing may be incomplete."); + + // Init main values by security + ptrIncomingProfileData->userCallBackType = LPA_USR_CONSENT_NO_PPR; + ptrIncomingProfileData->performCancelSession = false; + + // No need to parse if no profile installed in eUICC + if(ptrCurrentlyInstalledProfiles->countProfileInfo > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Found %llu profiles on eUICC", (long long unsigned)ptrCurrentlyInstalledProfiles->countProfileInfo); + + // CASE 1: Incoming profile has PPR1 + if(ptrIncomingProfileData->hasPPR1) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Incoming profile has PPR1 defined, will check if an Operational profile is already loaded."); + + for (indexProfile = 0; indexProfile < ptrCurrentlyInstalledProfiles->countProfileInfo; indexProfile++) + { + LPA_PROFILE_INFO_FOR_PPR* ptrProfileInfo = (LPA_PROFILE_INFO_FOR_PPR*)(ptrCurrentlyInstalledProfiles->profileInfoList + (indexProfile * sizeof(LPA_PROFILE_INFO_FOR_PPR))); + + // CASE 1: Incoming profile has PPR1 defined, check if an Operational profile is already loaded (Abort download) + if(ptrIncomingProfileData->hasPPR1) + { + // Check profile Class + if (ptrProfileInfo->profileClassSize > 0) + { + // If Operational profile, download if not granted + if (ptrProfileInfo->profileClass[0] == 0x02) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Profile #%llu is an Operational profile, download is not allowed due to PPR1 set on incoming profile.", (long long unsigned)indexProfile); + ptrIncomingProfileData->performCancelSession = true; + ptrIncomingProfileData->cancelSessionReason = LPA_CANCEL_SESSION_PPR_NOT_ALLOWED; + ptrIncomingProfileData->userCallBackType = LPA_USR_CONSENT_NO_PPR; // No more need to set any PPR request for user consent + + break; // Here no need to parse another profile or check something else + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Profile #%llu: Is not an Operational profile.", (long long unsigned)indexProfile); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "Profile #%llu: No profile Class found.", (long long unsigned)indexProfile); + } + + // CASE 2: All profiles class, check if installed profile has PPR1 set and is Enabled. If yes User Consent shall be required + // Note: This User Consent request is defined in SGP.21, requirement LPA46. Used in some SGP.23 testing. + if(checkForEnabledPPR1) + { + // Check profile PPR status + if (ptrProfileInfo->profilePolicyRulesSize > 0) + { + // Check if profile has PPR1 + if (_isPPR1definedInPPRflag((ptrProfileInfo->profilePolicyRules[0] << 8) + (ptrProfileInfo->profilePolicyRules[1]))) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Profile #%llu: Has PPR1 defined.", (long long unsigned)indexProfile); + // Check profile State + if (ptrProfileInfo->profileStateSize > 0) + { + // Check if profile is Enabled + if (ptrProfileInfo->profileState[0] == 0x01) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Profile #%llu: Is in Enabled state, user consent is required.", (long long unsigned)indexProfile); + // Note: This condition may be mixed with warnings about PPRs during RAT rules parsing + ptrIncomingProfileData->userCallBackType = LPA_USR_CONSENT_PROFILE_WITH_PPR1_ENABLED_PRESENT; + + checkForEnabledPPR1 = false; // Here no need to parse another profile for that condition + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Profile #%llu: Is in Disabled state.", (long long unsigned)indexProfile); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "Profile #%llu: No profile State found.", (long long unsigned)indexProfile); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Profile #%llu: Does not have PPR1 defined.", (long long unsigned)indexProfile); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Profile #%llu: No Profile Policy Rules (PPR) found.", (long long unsigned)indexProfile); + } + } + + res = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Did not find profiles on eUICC, no limitation due to installed profile."); + res = true; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter(s)!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_checkIncomingProfilePPRconditionVersusInstalledProfiles() return %s", (res ? "true" : "false")); + + return res; +} + +/** + * Check profile PPR elements wersus RAT to determine if user download is authorized, blocked or used must be warned + * @param ptrIncomingProfileData - Pointer on incoming profile data's - Will also contain action to be performed + * @param ptrRATrules - Pointer on Rawdata object containing RAT retrieved from eUICC + * @return true if RAT analysis is OK, else false if RAT data error detected or other issue encountered + */ +bool _checkIncomingProfilePPRattributesVersusRAT(LPA_DOWNLOADED_PROFILE_DATA_FOR_PPR* ptrIncomingProfileData, const RawDataObject* ptrRATrules) +{ + bool res = false; + LPA_PPR_RAT_ANALYSIS_FLAGS checkPPR1; // Analysis flags for PPR1 + LPA_PPR_RAT_ANALYSIS_FLAGS checkPPR2; // Analysis flags for PPR2 + + BeerTLV * berEUICC_RAT = NULL; + BeerTLV * berRATmainSequenceA0 = NULL; + BerTLVList * berTLVlistA0base = NULL; + uint8_t tlvListA0BaseCount = 0; + BerTLVList * berTLVlistA0parser = NULL; + BeerTLV * berTLVlistA0current = NULL; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_checkIncomingProfilePPRattributesVersurRAT()..."); + + // Valid RAT rules object must be at least 5 bytes (Tag BF43 + Length + Tag A0 + Length) + if(ptrIncomingProfileData != NULL && ptrRATrules != NULL && ptrRATrules->rawDataSize > 4) + { + // Check first if there is something to check in incoming profile + if(ptrIncomingProfileData->hasPPR1 || ptrIncomingProfileData->hasPPR2) + { + if (formatBytesToHexaString(ptrRATrules->rawData, ptrRATrules->rawDataSize, _bufferFormatLogMessage, sizeof(_bufferFormatLogMessage)) > 0) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "RAT retrieved from eUICC: %llu bytes: %s", (long long unsigned)ptrRATrules->rawDataSize, _bufferFormatLogMessage); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "RAT retrieved from eUICC: %llu bytes", (long long unsigned)ptrRATrules->rawDataSize); + + // Analysis flags initialization + checkPPR1.pprValidated = false; + checkPPR1.matchLevelMCC_MNC = 0; + checkPPR1.matchedGID1 = false; + checkPPR1.matchedGID2 = false; + checkPPR1.matchLevelGID = 0; + checkPPR1.userConsentRequired = false; + + checkPPR2.pprValidated = false; + checkPPR2.matchLevelMCC_MNC = 0; + checkPPR2.matchedGID1 = false; + checkPPR2.matchedGID2 = false; + checkPPR2.matchLevelGID = 0; + checkPPR2.userConsentRequired = false; + + // Check main tag BF43 + berEUICC_RAT = berTLV_extractTagUInt16(EUICC_RAT_TAG, ptrRATrules->rawData, ptrRATrules->rawDataSize, NULL); + if(berEUICC_RAT != NULL) + { + // Check main sequence tag + berRATmainSequenceA0 = berTLV_extractTagUInt8(0xA0, berEUICC_RAT->value, berEUICC_RAT->length, NULL); + if(berRATmainSequenceA0 != NULL) + { + // If rules are not empty continue, else cancel download + if(berRATmainSequenceA0->length > 0) + { + berTLVlistA0base = berTLV_extractList(berRATmainSequenceA0->value, berRATmainSequenceA0->length, &tlvListA0BaseCount); + + // List shall contain at least one element + if(berTLVlistA0base != NULL && tlvListA0BaseCount > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Found %u PPAR (Profile Policy Authorization Rule) in RAT (Rules Access Table)", tlvListA0BaseCount); + // At this step we consider parsing OK, except if something invalidate this status + res = true; + + berTLVlistA0parser = berTLVlistA0base; + // Parse list of PPR rules + while(berTLVlistA0parser != NULL) + { + berTLVlistA0current = berTLVlistA0parser->berTLV; + if(berTLVlistA0current != NULL) + { + // Check PPAR (RAT list element) tag before going next level of analysis + if(berTLVlistA0current->tag == 0x30) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Launch analysis of next PPAR..."); + res = _analysePPARversusProfileAttribute(berTLVlistA0current, ptrIncomingProfileData, &checkPPR1, &checkPPR2); + + // If error detected while analyzing PPAR, stop parsing and cancel profile download + if(! res) + break; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid tag found for PPAR entry (Not 0x30), profile download is not allowed"); + ptrIncomingProfileData->performCancelSession = true; + lpaSetErrorCode(LPA_ERROR_INVALID_GET_RAT); + + break; // No need to continue parsing + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "RAT rules parser: Current BERTLV list element appear to be NULL ? Go to next one..."); + + berTLVlistA0parser = berTLVlistA0parser->ptrNext; + } + + // Final validation of loading authorization + // PPR1 + if(ptrIncomingProfileData->hasPPR1) + { + if(checkPPR1.pprValidated) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Profile PPR1 validated by RAT"); + // Check if user consent required for this PPR + if(checkPPR1.userConsentRequired) + { + ptrIncomingProfileData->userCallBackType = ptrIncomingProfileData->userCallBackType | LPA_USR_CONSENT_PPR1; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "User Consent required"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "User Consent not required"); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Profile PPR1 not validated by RAT, cancel download"); + ptrIncomingProfileData->performCancelSession = true; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Profile does not have PPR1 defined"); + + // PPR2 + if(ptrIncomingProfileData->hasPPR2) + { + if(checkPPR2.pprValidated) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Profile PPR2 validated by RAT"); + // Check if user consent required for this PPR + if(checkPPR2.userConsentRequired) + { + ptrIncomingProfileData->userCallBackType = ptrIncomingProfileData->userCallBackType | LPA_USR_CONSENT_PPR2; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "User Consent required"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "User Consent not required"); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Profile PPR2 not validated by RAT, cancel download"); + ptrIncomingProfileData->performCancelSession = true; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Profile does not have PPR2 defined"); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Problem with RAT rules list, profile download is not allowed"); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_RAT); + } + + // Memory cleanup + ERASE_BERTLV_LIST(berTLVlistA0base); + berTLVlistA0parser = NULL; + berTLVlistA0current = NULL; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Empty RAT rules list found, profile download is not allowed"); + ptrIncomingProfileData->performCancelSession = true; + + res = true; // Empty rules but parsing OK + } + + // Memory cleanup + ERASE_BERTLV(berRATmainSequenceA0); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid RAT, main sequence tag not found or invalid TLV format!"); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_RAT); + } + + // Memory cleanup + ERASE_BERTLV(berEUICC_RAT); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid RAT, main tag <%X> not found or invalid TLV format!", EUICC_RAT_TAG); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_RAT); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "Submitted profile has no PPR defined, checking stop here."); + res = true; // This is not an error but a useless checking + } + + // If any problem during parsing, cancel profile loading + if (!res) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Error reported during RAT rules parsing, canceling current download session"); + ptrIncomingProfileData->performCancelSession = true; + } + + // Set cancel reason (Only one possible here) and invalidate eventual already set User Consent if session download is canceled + if (ptrIncomingProfileData->performCancelSession) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Cancel Session required, setting Cancel Reason and disabling any User Consent for PPR"); + ptrIncomingProfileData->cancelSessionReason = LPA_CANCEL_SESSION_PPR_NOT_ALLOWED; + ptrIncomingProfileData->userCallBackType = LPA_USR_CONSENT_NO_PPR; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter(s)!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_checkIncomingProfilePPRattributesVersurRAT() return %s", (res ? "true" : "false")); + + return res; +} + +/** + * Analyze PPAR (RAT rule) versus profile PPR attributes. Update LPA_PPR_RAT_ANALYSIS_FLAGS structures if rule found is more accurate. + * @param ptrPPARrule - Pointer on current PPAR rule to evaluate + * @param ptrIncomingProfileData - Pointer on incoming profile data, so here PPR status, MCC/MNC and GID1 / GID2 + * @param ptrCheckPPR1 - Pointer on LPA_PPR_RAT_ANALYSIS_FLAGS structure for PPR1 + * @param ptrCheckPPR2 - Poitner on LPA_PPR_RAT_ANALYSIS_FLAGS structure for PPR2 + * @return true if analysis is OK, else false if PPAR data error detected or other issue encountered + */ +bool _analysePPARversusProfileAttribute(BeerTLV * ptrPPARrule, LPA_DOWNLOADED_PROFILE_DATA_FOR_PPR * ptrIncomingProfileData, LPA_PPR_RAT_ANALYSIS_FLAGS * ptrCheckPPR1, + LPA_PPR_RAT_ANALYSIS_FLAGS * ptrCheckPPR2) +{ + bool res = false; + + // PPAR main elements + BeerTLV * berPprIds = NULL; + BeerTLV * berAllowedOperators = NULL; + BeerTLV * berConsentRequired = NULL; + + bool ppr1InPPAR = false; + bool ppr2InPPAR = false; + bool consentRequiredFlag = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_analysePPARversusProfileAttribute()..."); + + if(ptrPPARrule != NULL && ptrIncomingProfileData != NULL && ptrCheckPPR1 != NULL && ptrCheckPPR2 != NULL) + { + // Extract PprIDs TLV, Tag <80> + berPprIds = berTLV_extractTagUInt8(0x80, ptrPPARrule->value, ptrPPARrule->length, NULL); + // Extract allowedOperators list, Tag + berAllowedOperators = berTLV_extractTagUInt8(0xA1, ptrPPARrule->value, ptrPPARrule->length, NULL); + // Extract consentResuired flag, Tag <82> + berConsentRequired = berTLV_extractTagUInt8(0x82, ptrPPARrule->value, ptrPPARrule->length, NULL); + + // All these fields are mandatory, if any is missing RAT structure is damaged, exit on error + if(berPprIds != NULL && berAllowedOperators != NULL && berConsentRequired) + { + // All these fields cannot be empty, defined lengths for PprIds & consentRequired + // allowedOperator must be at least 7 bytes (At least one operator with MCC/MNC object defined in (A1 + L + 30 + L + 80 + L + MCCMNC) + if(berPprIds->length == 2 && berAllowedOperators->length >= 7 && (berConsentRequired->length == 0x02 || berConsentRequired->length == 0x01)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "PPAR TLV objects validated. Now retrieving PPR(s) and consentRequired defined in PPAR"); + // At this step we consider result OK until something invalidate it + res = true; + + // Check if PPR1 / PPR2 defined in PPAR (Extract from 2 bytes Bitsring Value) + ppr1InPPAR = _isPPR1definedInPPRflag((berPprIds->value[0] << 8) + berPprIds->value[1]); + ppr2InPPAR = _isPPR2definedInPPRflag((berPprIds->value[0] << 8) + berPprIds->value[1]); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "PPAR - PPR1 status: PPAR: %s - Profile: %s", (ppr1InPPAR)?"Defined":"Not defined", + (ptrIncomingProfileData->hasPPR1)?"Defined":"Not defined"); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "PPAR - PPR2 status: PPAR: %s - Profile: %s", (ppr2InPPAR)?"Defined":"Not defined", + (ptrIncomingProfileData->hasPPR2)?"Defined":"Not defined"); + + // Recover consentRequired flag. If fag set bitstring value = 0x780 else 0 + if(berConsentRequired->length == 0x02) + { + if(((berConsentRequired->value[0] << 8) + berConsentRequired->value[1]) == 0x0780) + consentRequiredFlag = true; + else + res = false; + } + else + { + // Length 0x01 already checked + if(berConsentRequired->value[0] == 0) + consentRequiredFlag = false; + else + res = false; + } + + // Continue only if consentRequired correctly encoded + if(res) + { + // Launch operator analysis for PPR1 & PPR2 + if(ppr1InPPAR && ptrIncomingProfileData->hasPPR1) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "PPAR - Launch allowedOperator analysis for PPR1"); + res = _analysePPARallowedOperatorVersusProfile(ptrIncomingProfileData, ptrCheckPPR1, berAllowedOperators, consentRequiredFlag); + } + + if(res && ppr2InPPAR && ptrIncomingProfileData->hasPPR2) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "PPAR - Launch allowedOperator analysis for PPR2"); + res = _analysePPARallowedOperatorVersusProfile(ptrIncomingProfileData, ptrCheckPPR2, berAllowedOperators, consentRequiredFlag); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Incorrect value detected in TLV consentRequired, profile download is not allowed"); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_RAT); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Incorrect length detected in TLV object in current PPAR, profile download is not allowed"); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_RAT); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Missing TLV object in current PPAR, profile download is not allowed"); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_RAT); + } + + // Memory cleanup + ERASE_BERTLV(berPprIds); + ERASE_BERTLV(berAllowedOperators); + ERASE_BERTLV(berConsentRequired); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter NULL!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_analysePPARversusProfileAttribute() return %s", (res ? "true" : "false")); + + return res; +} + +/** + * Analyze PPAR Allowed Operator list versus profile PPR attributes. Update LPA_PPR_RAT_ANALYSIS_FLAGS structures if rule found is more accurate. + * @param ptrIncomingProfileData - Pointer on incoming profile data, so here MCC/MNC and GID1 / GID2 + * @param ptrCheckPPR - Pointer on LPA_PPR_RAT_ANALYSIS_FLAGS structure for currently evaluated PPR + * @param berAllowedOperators - Pointer on BeerTLV TLV containing Allowed Operator list + * @param consentRequiredFlag - Consent Required flag for current PPAR, already decoded as boolen flag + * @return true if analysis is OK, else false if Allowed Operator data error detected or other issue encountered + */ +bool _analysePPARallowedOperatorVersusProfile(LPA_DOWNLOADED_PROFILE_DATA_FOR_PPR * ptrIncomingProfileData, LPA_PPR_RAT_ANALYSIS_FLAGS * ptrCheckPPR, + BeerTLV * berAllowedOperators, const bool consentRequiredFlag) +{ + bool res = false; + + BerTLVList * berTLVlistOperatorsBase = NULL; + uint8_t tlvListOperatorsCount = 0; + BerTLVList * berTLVlistOperatorsParser = NULL; + BeerTLV * berTLVlistOperatorsCurrent = NULL; + + BeerTLV * berTLVmccMnc = NULL; + BeerTLV * berTLVgid1 = NULL; + BeerTLV * berTLVgid2 = NULL; + + bool compareMCCMNCmatch = false; + int compareMCCMNClevel = 0; + bool definedGID1inPPAR = false; + bool compareGID1match = false; + bool definedGID2inPPAR = false; + bool compareGID2match = false; + bool profileMatchRule = false; + int ruleGIDlevel = 0; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_analysePPARallowedOperatorVersusProfile()..."); + + if(ptrIncomingProfileData != NULL && ptrCheckPPR != NULL && berAllowedOperators != NULL) + { + // Extract allowedOperators list from PPAR + berTLVlistOperatorsBase = berTLV_extractList(berAllowedOperators->value, berAllowedOperators->length, &tlvListOperatorsCount); + + // PPAR allowedOperators list shall contain at least one element + if(berTLVlistOperatorsBase != NULL && tlvListOperatorsCount > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Found %u allowedOperator in PPAR", tlvListOperatorsCount); + // At this step we consider parsing OK, except if something invalidate this status + res = true; + + berTLVlistOperatorsParser = berTLVlistOperatorsBase; + // Parse list of Allowed Operators defined in PPAR + while(berTLVlistOperatorsParser != NULL) + { + berTLVlistOperatorsCurrent = berTLVlistOperatorsParser->berTLV; + if(berTLVlistOperatorsCurrent != NULL) + { + // Operator tag entry is <30> + if(berTLVlistOperatorsCurrent->tag == 0x30) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "TLV allowedOperator tag correct, extracting MCC/MNC"); + // Extract MCC/MNC from allowedOperator entry. This is a mandatory tag, always 3 bytes long + berTLVmccMnc = berTLV_extractTagUInt8(0x80, berTLVlistOperatorsCurrent->value, berTLVlistOperatorsCurrent->length, NULL); + if(berTLVmccMnc != NULL && berTLVmccMnc->length == 3) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Compare allowedOperator MCC/MNC with profile MCC/MNC"); + // Compare MCC/MNC, with possible wildcards + res = _comparePPARallowedOperator_MCC_MNC(berTLVmccMnc->value, ptrIncomingProfileData->mccMnc, &compareMCCMNCmatch, &compareMCCMNClevel); + + if(res) + { + // If there is a somewhat matching between MCC/MNC with allowedOperator, continue with comparison + if(compareMCCMNCmatch) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "AllowedOperator MCC/MNC and profile MCC/MNC can match, now extracting GID's from rule"); + + // Initialize allowedOperator GID level + ruleGIDlevel = 0; + + // If GID1 defined in allowedOperator, compare with incoming profile + compareGID1match = false; + berTLVgid1 = berTLV_extractTagUInt8(0x81, berTLVlistOperatorsCurrent->value, berTLVlistOperatorsCurrent->length, NULL); + if(berTLVgid1 != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "GID1 is defined"); + // GID1 exists even if length = 0 + definedGID1inPPAR = true; + // Useless to compare length = 0 because becomes a wildcard value + if(berTLVgid1->length > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "GID1 contain data"); + if(berTLVgid1->length == ptrIncomingProfileData->gid1Size) + { + if(0 == memcmp(berTLVgid1->value, ptrIncomingProfileData->gid1, berTLVgid1->length)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "GID1 from allowedOperator and profile are equal"); + compareGID1match = true; + } + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "GID1 is empty"); + } + else + definedGID1inPPAR = false; + + // If GID2 defined in allowedOperator, compare with incoming profile + compareGID2match = false; + berTLVgid2 = berTLV_extractTagUInt8(0x82, berTLVlistOperatorsCurrent->value, berTLVlistOperatorsCurrent->length, NULL); + if(berTLVgid2 != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "GID2 is defined"); + // GID1 exists even if length = 0 + definedGID2inPPAR = true; + // Useless to compare length = 0 because becomes a wildcard value + if(berTLVgid2->length > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "GID2 contain data"); + if(berTLVgid2->length == ptrIncomingProfileData->gid2Size) + { + if(0 == memcmp(berTLVgid2->value, ptrIncomingProfileData->gid2, berTLVgid2->length)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "GID2 from allowedOperator and profile are equal"); + compareGID2match = true; + } + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "GID2 is empty"); + } + else + definedGID2inPPAR = false; + + // Log status of incoming profile GID's + // Incoming GID1 + if(ptrIncomingProfileData->gid1Defined) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Incoming profile GID1 is defined, length = %llu", (long long unsigned)ptrIncomingProfileData->gid1Size); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Incoming profile GID1 is not defined"); + // Incoming GID2 + if(ptrIncomingProfileData->gid2Defined) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Incoming profile GID2 is defined, length = %llu", (long long unsigned)ptrIncomingProfileData->gid2Size); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Incoming profile GID2 is not defined"); + + + // Final comparison with evaluated PPR, considering MMC/MNC and GID + profileMatchRule = true; + + // At least same matching level for MCC / MNC is needed + if(ptrCheckPPR->matchLevelMCC_MNC <= compareMCCMNClevel) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Level of allowedOperator MCC/MNC is higher or equal than previously evaluated one"); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Now check allowedOperator GID's compatibility with profile GID's"); + // GID1 defined in PPAR allowedOperator + if(definedGID1inPPAR) + { + // If length = 0 becomes a wildcard so no need to compare + if(berTLVgid1->length > 0) + { + // If GID match increase matching level else profile does not match rule + if(compareGID1match) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "GID1's are the same, increasing GID matching level"); + ruleGIDlevel++; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "GID1's are different, PPAR allowedOperator discarded"); + profileMatchRule = false; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Empty GID1 defined in allowedOperator, compatible with any profile GID1"); + } + else + { + // If GID not defined in PPAR, must also be not defined in profile + if(ptrIncomingProfileData->gid1Defined) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "GID1 not defined in allowedOperator while defined in profile, PPAR allowedOperator discarded"); + profileMatchRule = false; + } + else + { + // GID not defined in PPAR and incoming profile is also an exact match + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "GID1 not defined in allowedOperator and profile, increasing GID matching level"); + compareGID1match = true; + ruleGIDlevel++; + } + } + + if(profileMatchRule) + { + // GID2 defined in PPAR allowedOperator + if(definedGID2inPPAR) + { + // If length = 0 becomes a wildcard so no need to compare + if(berTLVgid2->length > 0) + { + // If GID match increase matching level else profile does not match rule + if(compareGID2match) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "GID2's are the same, increasing GID matching level"); + ruleGIDlevel++; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "GID2's are different, PPAR allowedOperator discarded"); + profileMatchRule = false; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Empty GID2 defined in allowedOperator, compatible with any profile GID2"); + } + else + { + // If GID not defined in PPAR, must also be not defined in profile + if(ptrIncomingProfileData->gid2Defined) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "GID2 not defined in allowedOperator while defined in profile, PPAR allowedOperator discarded"); + profileMatchRule = false; + } + else + { + // GID not defined in PPAR and incoming profile is also an exact match + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "GID2 not defined in allowedOperator and profile, increasing GID matching level"); + compareGID2match = true; + ruleGIDlevel++; + } + } + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Level of rule MCC/MNC is lower than previously evaluated allowedOperator, PPAR allowedOperator discarded"); + profileMatchRule = false; + } + + // If matched all conditions and GID matching "weight" is bigger than previous, update status of evaluated PPR + if(profileMatchRule) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "PPAR allowedOperator match with incoming profile"); + if(ruleGIDlevel >= ptrCheckPPR->matchLevelGID) + { + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Level of GID's is higher or equal than previously evaluated one, PPR validated with actual levels and use PPAR condition for User Consent"); + ptrCheckPPR->pprValidated = true; // PPR has been validated at least one time + ptrCheckPPR->matchLevelMCC_MNC = compareMCCMNClevel; // Matching level for MCC / MNC + ptrCheckPPR->matchedGID1 = compareGID1match; + ptrCheckPPR->matchedGID2 = compareGID2match; + ptrCheckPPR->matchLevelGID = ruleGIDlevel; + ptrCheckPPR->userConsentRequired = consentRequiredFlag; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Level of allowedOperator GID's is lower than previously evaluated rule, PPAR allowedOperator discarded"); + + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "AllowedOperator MCC/MNC and profile MCC/MNC cannot match, PPAR allowedOperator does not fit with profile"); + + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid MCC/MNC in allowedOperator or profile, profile download is not allowed"); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_RAT); + res = false; + break; // No need to parse another operator + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Mandatory MCC/MNC tag missing or incorrect length in allowedOperator entry, profile download is not allowed"); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_RAT); + res = false; + break; // No need to parse another operator + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid tag detected for allowedOperator list element, profile download is not allowed"); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_RAT); + res = false; + break; // No need to parse another operator + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "PPAR allowedOperator parser: Current BerTLV list element appear to be NULL ? Go to next one..."); + + berTLVlistOperatorsParser = berTLVlistOperatorsParser->ptrNext; + } + + // Memory cleanup + ERASE_BERTLV(berTLVmccMnc); + ERASE_BERTLV(berTLVgid1); + ERASE_BERTLV(berTLVgid2); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Operator list not found or empty or invalid TLV format, profile download is not allowed"); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_RAT); + } + + // Memory cleanup + ERASE_BERTLV_LIST(berTLVlistOperatorsBase); + berTLVlistOperatorsParser = NULL; + berTLVlistOperatorsCurrent = NULL; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter NULL!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_analysePPARallowedOperatorVersusProfile() return %s", (res ? "true" : "false")); + + return res; +} + +/** + * Compare allowedOperator and profile MCC/MNC, taking account of wildcard digits 'E' in allowedOperator. Also return matching level (0 if all wildcard, 6 if all match) + * @param ptrAllowOpMCCMNC - Pointer on allowedOperator MCC/MNC, 3 bytes long + * @param ptrProfileMCCMNC - Pointer on incoming profile MCC/MNC, 3 bytes long + * @param ptrMatchingFlag - Pointer on flag confirming if MCC/MNC match + * @param ptrMatchinglevel - Pointer on Matching level value to return + * @return true if operation OK and MCC/MNC digits are correct + */ +bool _comparePPARallowedOperator_MCC_MNC(const unsigned char * ptrAllowOpMCCMNC, const unsigned char * ptrIncomingProfileMCCMNC, bool * ptrMatchingFlag, int * ptrMatchinglevel) +{ + bool res = false; + uint32_t allowedOperatorMCCMNC32 = 0; + uint32_t profileMCCMNC32 = 0; + unsigned char checkDigitAllOp = 0; + unsigned char checkDigitProf = 0; + int i = 0; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_comparePPARallowedOperator_MCC_MNC()..."); + + if(ptrAllowOpMCCMNC != NULL && ptrIncomingProfileMCCMNC != NULL && ptrMatchingFlag != NULL && ptrMatchinglevel != NULL) + { + // Convert the 3 bytes of MCC MNC in 32 bits values + allowedOperatorMCCMNC32 = (ptrAllowOpMCCMNC[0] << 16) + (ptrAllowOpMCCMNC[1] << 8) + ptrAllowOpMCCMNC[2]; + profileMCCMNC32 = (ptrIncomingProfileMCCMNC[0] << 16) + (ptrIncomingProfileMCCMNC[1] << 8) + ptrIncomingProfileMCCMNC[2]; + + // For the moment we consider that all digits will match and comparison is OK + *ptrMatchinglevel = 6; + *ptrMatchingFlag = true; + res = true; + + // Check MCC/MNC digits and build comparison mask + while(i < 6 && res && *ptrMatchingFlag) + { + // Extract lower digit + checkDigitAllOp = allowedOperatorMCCMNC32 & 0x0000000F; + checkDigitProf = profileMCCMNC32 & 0x0000000F; + + // Check digits + // allowedOperator: 0-9 + E + F + // profile: 0-9 + F + if(! ((checkDigitAllOp >= 0x00 && checkDigitAllOp <= 0x09) || checkDigitAllOp == 0x0E || checkDigitAllOp == 0x0F)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid digit detected in allowedProfile MCC/MNC"); + res = false; + } + if(! ((checkDigitProf >= 0x00 && checkDigitProf <= 0x09) || checkDigitProf == 0x0F)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid digit detected in incoming profile MCC/MNC"); + res = false; + } + + if(res) + { + // If wildcard in allowedOperator, digit is validated and matching level decreased + if(checkDigitAllOp == 0x0E) + *ptrMatchinglevel = *ptrMatchinglevel - 1; + else + { + // check if digits are matching. If not stop here + if(checkDigitAllOp != checkDigitProf) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Digit %d is different, allowedOperator and incoming profile does not match", (6 - i)); + *ptrMatchingFlag = false; + } + } + } + + // Go to next digit to check + allowedOperatorMCCMNC32 = allowedOperatorMCCMNC32 >> 4; + profileMCCMNC32 = profileMCCMNC32 >> 4; + i++; + } + + if(res && *ptrMatchingFlag) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "allowedOperator and incoming profile MCC/MNC are compatible, with level %d", *ptrMatchinglevel); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter NULL!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_comparePPARallowedOperator_MCC_MNC() return %s", (res ? "true" : "false")); + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** + * Notify application owner about Cancel Session result through callback + * Avoid to repeat that 3 times in _manageDownloadProfile() + * + * @param ptrLpaEventCallback - Event Callback, type LPA_EventCallback + * @param cancelResult - Result of the Cancel Session operation + * @param callbackLevel - Level / event type of notification for Callback + */ +void _notifyAppliOwnerCancelResult(const LPA_EventCallback* ptrLpaEventCallback, const bool cancelResult, size_t callbackEventType) +{ + if (ptrLpaEventCallback != NULL && ptrLpaEventCallback->_lpaEventProgressText != NULL) + { + if(cancelResult) + ptrLpaEventCallback->_lpaEventProgressText(ptrLpaEventCallback->_appParameter, callbackEventType, "Cancel Session done"); + else + ptrLpaEventCallback->_lpaEventProgressText(ptrLpaEventCallback->_appParameter, callbackEventType, "Cancel Session failed"); + } +} + +/** +* Perform profile download operation from calling entry point (With or without Confirmation Code provided). +* +* @param ptrActivationCodeStr - Activation Code, String format +* @param ptrConfirmationCodeStr - Confirmation Code, String format. Set it as "" if not used +* @param confirmationCodeLength - Length of Confirmation Code, Integer. Set it to 0 if not used. +* @param ptrLpaEventCallback - Event Callback, type LPA_EventCallback +* @param ptrDownloadProfileResult - Download profile result, type LPA_DOWNLOAD_PROFILE_RESULT +* @param retryRequested - Pointer to bool flag. If returned "true" ask to caller to perform another retry due to error (Chained GetResponse,...) +* @return True if profile download is successful +*/ +static bool _manageDownloadProfile(const char * ptrActivationCodeStr, const char * ptrConfirmationCodeStr, const int confirmationCodeLength, const LPA_EventCallback* ptrLpaEventCallback, LPA_DOWNLOAD_PROFILE_RESULT* ptrDownloadProfileResult, bool * retryRequested) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ _manageDownloadProfile(...)"); + + LPA_GET_EUICC getEuiccChallenge; + LPA_GET_EUICC getEuiccInfo; // Used for EUICCInfo1 then EUICCInfo2 + bool deviceInfoExtensibilitySupport = false; + unsigned char filteredDeviceInfo[LPA_CFG_DEVICE_INFO_TLV_BYTE_ARRAY_MAX_SIZE]; + size_t filteredDeviceInfoSize = 0; + + RawDataObject * prepareCtxParam = NULL; + LPA_SERVER_DATA serverData; + PROFILE_INSTALLATION_RESULT pir; + ACTIVATION_CODE activationCode; + + unsigned char certificateOIDrawASN1[LPA_OID_SIZE]; // By all the way Raw ASN1 will be always smaller than text version + size_t certificateOIDrawASN1Length = 0; + char certificateOIDtext[LPA_OID_SIZE]; + + LPA_EVENT_INCOMING_PROFILE_INFORMATION incomingProfileInfoForCallback; + LPA_DOWNLOADED_PROFILE_DATA_FOR_PPR incomingProfileDataForPPR; + LPA_GET_PROFILES_INFO currentlyInstalledProfiles; + RawDataObject* eUICC_RATrules = NULL; + LPA_REQUEST_USER_CONSENT_FOR_LOADING_PROFILE lpaRequestUserConsent; + + AUTHENTICATE_SERVER_RESPONSE authentServerResp; + PREPARE_DOWNLOAD_RESPONSE prepareDownloadResp; + + bool cancelForBPPerrors = false; + bool isNeedToSendPIR = false; + LPA_API_ERROR lpaApiError = LPA_NO_ERROR; + bool res = false; + + char hashConfirmCode[70]; + bool cancelResult = false; + BeerTLV* ptrBerTLVsmdpSigned2Objects = NULL; + BeerTLV* ptrBerTLVccRequiredFlag = NULL; + bool tagFound; + + bool normalNotifAcknowledge = false; + + int nbExecGetResp = LPA_LOOP_NUMBER_FOR_CHAINED_GET_RESPONSE; + *retryRequested = false; // For the moment, do not request retry in case of GetResponseChaining failure + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Start to Download Profile..."); + + // Step 1: Initialize variables and structures + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "LPA Download: Step 1 -> Initialization..."); + + memset(&activationCode, 0x00, sizeof(ACTIVATION_CODE)); + memset(&incomingProfileInfoForCallback, 0x00, sizeof(LPA_EVENT_INCOMING_PROFILE_INFORMATION)); + memset(&incomingProfileDataForPPR, 0x00, sizeof(LPA_DOWNLOADED_PROFILE_DATA_FOR_PPR)); + memset(¤tlyInstalledProfiles, 0x00, sizeof(LPA_GET_PROFILES_INFO)); + memset(&certificateOIDrawASN1, 0x00, LPA_OID_SIZE); + memset(&certificateOIDtext, 0x00, LPA_OID_SIZE); + memset(filteredDeviceInfo, 0x00, sizeof(filteredDeviceInfo)); + + getEuiccChallenge.ptrEUICC = NULL; + getEuiccChallenge.prtEUICC_Base64 = NULL; + + getEuiccInfo.ptrEUICC = NULL; + getEuiccInfo.prtEUICC_Base64 = NULL; + + _lpaManagerInitServerData(&serverData, true); + + pir.hasResult = false; + pir.ptrProfileInstallationResultTlv = NULL; + pir.ptrProfileInstallationResultTlv_Base64 = NULL; + + authentServerResp.ptrAuthenticateServerResponse = NULL; + authentServerResp.ptrAuthenticateServerResponse_Base64 = NULL; + + prepareDownloadResp.ptrPrepareDownloadResponse = NULL; + prepareDownloadResp.ptrPrepareDownloadResponse_Base64 = NULL; + + // Step2: Parameters checks + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "LPA Download: Step 2 -> Parameters check..."); + // ptrLpaEventCallback is checked each time it has to be used + if (ptrActivationCodeStr != NULL && ptrDownloadProfileResult != NULL && ptrConfirmationCodeStr != NULL) + { + ptrDownloadProfileResult->countProfileInstalled = 0; + ptrDownloadProfileResult->countProfileTotal = 0; + } + else + lpaApiError = LPA_ERROR_INVALID_PARAMETER; + + // Step 3: GetEuiccChallenge + if (lpaApiError == LPA_NO_ERROR) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "LPA Download: Step 3 -> GetEuiccChallenge..."); + + if (_lpaManagerGetEuiccChallenge(&getEuiccChallenge)) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Success to get EuiccChallenge"); + else + lpaApiError = LPA_ERROR_INVALID_GET_UICC_CHALLENGE; + } + + // Step 4: GetEuiccInfo1 + if (lpaApiError == LPA_NO_ERROR) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "LPA Download: Step 4 -> GetEuiccInfo1..."); + + if(! _lpaManagerGetEuiccInfoWithRetry(GET_EUICC_INFO1_DGI_TAG, &getEuiccInfo)) + lpaApiError = LPA_ERROR_INVALID_GET_EUICC_INFO; // Prevent going on next steps for nothing, general error code already set by _lpaManagerGetEuiccInfoWithRetry() + } + + + // Step 5: Manage Activation Code + if (lpaApiError == LPA_NO_ERROR) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "LPA Download: Step 5 -> Manage Activation Code..."); + + if (_decodeActivationCodeStr(ptrActivationCodeStr, &activationCode)) + { + _sendEventCallbackProgressText(ptrLpaEventCallback, 0, "Activation Code decoded"); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to extract data from Activation Code."); + lpaApiError = LPA_ERROR_FAILED_GET_DATA_FROM_ACTIVATION_CODE; + } + } + + // Step 6: Initiate Authentication + if (lpaApiError == LPA_NO_ERROR) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "LPA Download: Step 6 -> Initiate Authentication..."); + if ( getEuiccChallenge.prtEUICC_Base64 != NULL && getEuiccInfo.prtEUICC_Base64 != NULL && + lpaManagerInitiateAuthentication(&serverData, ptrLpaEventCallback, (const char*)getEuiccChallenge.prtEUICC_Base64->rawData, + (const char*)getEuiccInfo.prtEUICC_Base64->rawData, activationCode.smdxAddr)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Initiate authentication done"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 1, "Initiate authentication done"); + + // Check transactionId + if (serverData._transactionId != NULL && serverData._transactionId->rawDataSize > 0 && serverData._transactionId->rawDataSize < LPA_TRANSACTION_ID_MAX_SIZE) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "LPA Download: TransactionId: <%s>", serverData._transactionId->rawData); + else + lpaApiError = LPA_ERROR_INVALID_TRANSACTIONID; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to Initiate authentication"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 1, "Failed to Initiate authentication"); + + lpaApiError = LPA_ERROR_FAILED_INITIAL_AUTHENTICATION; + } + } + + // Memory cleanup + ERASE_RAWDATAOBJECT(getEuiccChallenge.ptrEUICC); + ERASE_RAWDATAOBJECT(getEuiccChallenge.prtEUICC_Base64); + + ERASE_RAWDATAOBJECT(getEuiccInfo.ptrEUICC); + ERASE_RAWDATAOBJECT(getEuiccInfo.prtEUICC_Base64); + + // Step 7: GetEuiccInfo2 + if (lpaApiError == LPA_NO_ERROR && _deviceCapabilitiesFilter) // No need to perform it if filtering is disabled + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "LPA Download: Step 7 -> GetEuiccInfo2..."); + + if(! _lpaManagerGetEuiccInfoWithRetry(GET_EUICC_INFO2_DGI_TAG, &getEuiccInfo)) + lpaApiError = LPA_ERROR_INVALID_GET_EUICC_INFO; // Prevent going on next steps for nothing, general error code already set by _lpaManagerGetEuiccInfoWithRetry() + } + + // Step 8: Get status of flag "deviceInfoExtensibilitySupport" in object "RspCapability" returned in EUICCInfo2 + if (lpaApiError == LPA_NO_ERROR && _deviceCapabilitiesFilter) // No need to perform it if filtering is disabled + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "LPA Download: Step 8 -> Get status of flag deviceInfoExtensibilitySupport..."); + + if(! _lpaManagerGetFlag_deviceInfoExtensibilitySupport(&getEuiccInfo, &deviceInfoExtensibilitySupport)) + lpaApiError = LPA_ERROR_PROCESSING_ERROR; // Prevent going on next steps for nothing + } + + // Memory cleanup + ERASE_RAWDATAOBJECT(getEuiccInfo.ptrEUICC); + ERASE_RAWDATAOBJECT(getEuiccInfo.prtEUICC_Base64); + + // Step 9: Manage "deviceInformation" "deviceCapabilities" features depending "deviceInfoExtensibilitySupport" flag status and filtering option + // Note: Even if filtering is disabled, this step remain mandatory to get copy of deviceInformation + if (lpaApiError == LPA_NO_ERROR) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "LPA Download: Step 9 -> Management of deviceInformation..."); + + if(!_lpaManagerFilterDeviceCapabitilitiesInformation(_deviceInfoByteArray, _deviceInfoByteArraySize, filteredDeviceInfo, &filteredDeviceInfoSize, + sizeof(filteredDeviceInfo), deviceInfoExtensibilitySupport, _deviceCapabilitiesFilter)) + lpaApiError = LPA_ERROR_PROCESSING_ERROR; // Prevent going on next steps for nothing + } + + // Step 10: Check SM-DP+ Address + if (lpaApiError == LPA_NO_ERROR) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "LPA Download: Step 10 -> Check SM-DP+ Address..."); + if (serverData._serverSigned1 != NULL && _verifySMDPAddress(activationCode.smdxAddr, (const char*)serverData._serverSigned1->rawData, serverData._serverSigned1->rawDataSize)) + { + _sendEventCallbackProgressText(ptrLpaEventCallback, 1, "SM-DP+ address checking done"); + + if (activationCode.matchingId != NULL && strlen(_deviceInfo) > 0 && _lpaManagerPrepareCtxParam(activationCode.matchingId, filteredDeviceInfo, filteredDeviceInfoSize, &prepareCtxParam)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Success to prepareCtxParam"); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to prepareCtxParam"); + lpaApiError = LPA_ERROR_INVALID_CTX_PARAM; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid SMDP address"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 1, "Failed to check SM-DP+ address, invalid"); + lpaApiError = LPA_ERROR_INVALID_SERVER_ADDRESS; + } + } + + // Step 11: Check OID. If error at this step no need to perform Cancel Session because Authenticate client not yet performed. + if(lpaApiError == LPA_NO_ERROR) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "LPA Download: Step 11 -> Check Activation Code OID versus OID in certificate returned by server..."); + + // Note: Activation Code OID format has already been checked by _decodeActivationCodeStr() function + + // If OID is not defined in Activation Code, OID test will be not performed + if(strlen(activationCode.oid) > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "OID provided in Activation Code, extracting OID from certificate..."); + + // Extract OID from certificate. If not defined or error in extraction, exit on error + if(extractOIDfromCertificate(serverData._serverCertificate->rawData, serverData._serverCertificate->rawDataSize, certificateOIDrawASN1, &certificateOIDrawASN1Length, LPA_OID_SIZE)) + { + convertASN1_OIDtoText(certificateOIDrawASN1, certificateOIDrawASN1Length, certificateOIDtext, LPA_OID_SIZE); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "OID extracted from Activation Code: %s", activationCode.oid); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "OID extracted from certificate : %s", certificateOIDtext); + + // Compare OID's. Stop download if mismatch + if(strcmp(activationCode.oid, certificateOIDtext) == 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "OID check done successfully. Match with Activation Code"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 1, "OID comparison done"); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "OIDs do not match. Check failed. Abort download"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 1, "Failed to OID comparison, does not match"); + lpaApiError = LPA_ERROR_OID_MISMATCH; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "An issue has been encountered while extracting OID from certificate returned by server or OID not found"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 1, "Failed to retrieve OID from certificate"); + lpaApiError = LPA_ERROR_INVALID_SERVERCERTIFICATE; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "No OID defined in Activation Code, checking canceled."); + } + + // Step 12: Authenticate Server + if (lpaApiError == LPA_NO_ERROR) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "LPA Download: Step 12 -> Authenticate server..."); + + // If GetResponse chaining error, _lpaManagerAuthenticateServer() will return false + if(_lpaManagerAuthenticateServer(&serverData, ptrLpaEventCallback, prepareCtxParam, &authentServerResp) && authentServerResp.ptrAuthenticateServerResponse_Base64 != NULL) + { + _sendEventCallbackProgressText(ptrLpaEventCallback, 2, "Authenticate server done"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Authenticate server done"); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Authenticate server response: %s ", authentServerResp.ptrAuthenticateServerResponse_Base64->rawData); + + // Clear server data but keep trasactionID + _lpaManagerFreeServerData(&serverData, false); + } + else + { + // Management of GetResponse chaining issue. Command retry is not possible at this step, cancel current session and inform caller that + // retry of entire process is requested + if(lpaGetErrorCodeNoClear() == SE_MEDIA_E_CHAINING_GET_RESPONSE && LPA_RETRY_CHAINED_GET_RESPONSE_MGT) + { + *retryRequested = true; + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "AuthenticateServer: GetResponse chaining issue detected, stop current profile download"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 2, "AuthenticateServer: GetResponse chaining issue detected, stop current profile download"); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to Authenticate server."); + _sendEventCallbackProgressText(ptrLpaEventCallback, 2, "Failed to Authenticate server"); + } + + lpaApiError = LPA_ERROR_FAILED_AUTHENTICATE_SERVER; + } + } + + // Memory cleanup + ERASE_RAWDATAOBJECT(prepareCtxParam); + + // Step 13: Authenticate Client + if (lpaApiError == LPA_NO_ERROR) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "LPA Download: Step 13 -> Authenticate client..."); + + if (_lpaManagerAuthenticateClient(&serverData, ptrLpaEventCallback, activationCode.smdxAddr, authentServerResp.ptrAuthenticateServerResponse_Base64->rawData)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Authenticate client done"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 3, "Authenticate client done"); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to Authenticate client!"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 3, "Failed to Authenticate client"); + + lpaApiError = LPA_ERROR_FAILED_AUTHENTICATE_CLIENT; + } + } + + // Do memory cleanup + ERASE_RAWDATAOBJECT(authentServerResp.ptrAuthenticateServerResponse); + ERASE_RAWDATAOBJECT(authentServerResp.ptrAuthenticateServerResponse_Base64); + + // Total Profile - At this step (Authenticate Client OK) we consider we have a profile available + if (lpaApiError == LPA_NO_ERROR) + { + // No need to increase because we always start from 0 + ptrDownloadProfileResult->countProfileTotal = 1; + } + + // Step 14: Extract informations from incoming profile Metadata retrieved after Authenticate Client + // Used for profile information Callback and PPR management - Also check if PPR1 or PPR2 is defined in profile + if (lpaApiError == LPA_NO_ERROR) + { + incomingProfileInfoForCallback.profileMetadataAvailable = false; + // Other incoming profile data for information callback already initialized by memset() at beginning + + // Incoming profile data initialization for PPR + incomingProfileDataForPPR.profilePPR = 0; + incomingProfileDataForPPR.hasPPR1 = false; + incomingProfileDataForPPR.hasPPR2 = false; + // mccMnc already set to 00 by memset + // gid1 already set to 00 by memset + // gid1Size already set to 00 by memset + incomingProfileDataForPPR.gid1Defined = false; + // gid2 already set to 00 by memset + // gid2Size already set to 00 by memset + incomingProfileDataForPPR.gid2Defined = false; + // profileName already set to 00 by memset + incomingProfileDataForPPR.userCallBackType = LPA_USR_CONSENT_NO_PPR; + incomingProfileDataForPPR.performCancelSession = false; + // cancelSessionReason already set to 00 by memset, no meaning while performCancelSession = false + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "LPA Download: Step 14 -> Extract Metadata from incoming profile (Information Callback and PPR management)..."); + // Launch extraction only if metadata have been retrieved from profile (Optional in Authenticate Client response) + if(serverData._profileMetadata->rawDataSize > 0) + { + // Set "Metadata Available" flag in profile data structure for information callback + incomingProfileInfoForCallback.profileMetadataAvailable = true; + + if(_extractFieldsFromProfileMetadata(serverData._profileMetadata->rawData, serverData._profileMetadata->rawDataSize, &incomingProfileDataForPPR, &incomingProfileInfoForCallback)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Profile informations successfully extracted, send user information callback"); + + // Send callback only if has been defined by calling application + if (ptrLpaEventCallback != NULL && ptrLpaEventCallback->_lpaEventDisplayIncomingProfileInformation != NULL) + { + ptrLpaEventCallback->_lpaEventDisplayIncomingProfileInformation(ptrLpaEventCallback->_appParameter, 3, &incomingProfileInfoForCallback); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to extract Metadata from incoming profile!"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 3, "Failed to extract Metadata from incoming profile"); + lpaApiError = LPA_ERROR_LOCAL_PROFILE_UNABLE_TO_EXTRACT_DATA; + + // This error will drive to Cancel Session with reason "Undefined" (Case not covered) + incomingProfileDataForPPR.performCancelSession = true; + incomingProfileDataForPPR.cancelSessionReason = LPA_CANCEL_SESSION_UNDEFINED_REASON; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "No profile Metadata returned by Authenticate Client"); + + // Send callback even if no data available, to keep calling application informed through "profileMetadataAvailable" flag + // And only if has been defined by calling application + if (ptrLpaEventCallback != NULL && ptrLpaEventCallback->_lpaEventDisplayIncomingProfileInformation != NULL) + { + ptrLpaEventCallback->_lpaEventDisplayIncomingProfileInformation(ptrLpaEventCallback->_appParameter, 3, &incomingProfileInfoForCallback); + } + } + } + + // Step 14 bis: Check if any PPR apply to profile and if supportDownloadOfProfilesWithPPR = false. If yes do not allow profile download and request Cancel Session + if (lpaApiError == LPA_NO_ERROR && (incomingProfileDataForPPR.hasPPR1 || incomingProfileDataForPPR.hasPPR2) && (! _supportDownloadOfProfilesWithPPR)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "LPA Download: Step 18 bis -> Download of profiles with PPR is currently not allowed by LPA setting, canceling download session..."); + _sendEventCallbackProgressText(ptrLpaEventCallback, 3, "Download of profiles with PPR is currently not allowed by LPA setting, canceling download session"); + + incomingProfileDataForPPR.performCancelSession = true; + incomingProfileDataForPPR.cancelSessionReason = LPA_CANCEL_SESSION_PPR_NOT_ALLOWED; + lpaApiError = LPA_ERROR_PPR_NOT_ALLOWED; + } + + // Step 15: Get RAT from eUICC if PPR1 or PPR2 is defined + if (lpaApiError == LPA_NO_ERROR && (incomingProfileDataForPPR.hasPPR1 || incomingProfileDataForPPR.hasPPR2)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "LPA Download: Step 15 -> Retrieve RAT from eUICC..."); + if(! _lpaManagerGetRAT(&eUICC_RATrules)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to retrieve RAT from eUICC!"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 3, "Failed to retrieve RAT from eUICC"); + lpaApiError = LPA_ERROR_INVALID_GET_RAT; + + // Error in this process will drive to Cancel Session with "PPR not allowed" + incomingProfileDataForPPR.performCancelSession = true; + incomingProfileDataForPPR.cancelSessionReason = LPA_CANCEL_SESSION_PPR_NOT_ALLOWED; + } + } + + // Step 16: Extract already installed profiles info, list apply for PPR management + if (lpaApiError == LPA_NO_ERROR) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "LPA Download: Step 16 -> Retrieve information of already installed profiles..."); + // Launch retrieve of information for profiles already installed on eUICC + if(! _getProfilesInfoForPPR(¤tlyInstalledProfiles)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to retrieve installed profiles informations from eUICC!"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 3, "Failed to retrieve installed profiles informations from eUICC"); + lpaApiError = LPA_ERROR_INVALID_GET_PROFILES_INFO_EXCHANGE; + + // This error will drive to Cancel Session with reason "Undefined" (Case not covered) + incomingProfileDataForPPR.performCancelSession = true; + incomingProfileDataForPPR.cancelSessionReason = LPA_CANCEL_SESSION_UNDEFINED_REASON; + } + } + + // Step 17: PPR management: Check if downloaded profile can be installed versus profiles already installed on eUICC + // If profile has PPR some conditions apply + if (lpaApiError == LPA_NO_ERROR) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "LPA Download: Step 17 -> Checking incoming profile PPR versus already installed profiles..."); + if(! _checkIncomingProfilePPRconditionVersusInstalledProfiles(&incomingProfileDataForPPR, ¤tlyInstalledProfiles)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to check PPR of incoming profile versus already installed profiles!"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 3, "Failed to check PPR of incoming profile versus already installed profiles"); + lpaApiError = LPA_ERROR_INVALID_GET_PROFILES_INFO_EXCHANGE; + + // This error will drive to Cancel Session with reason "Undefined" (Case not covered) + incomingProfileDataForPPR.performCancelSession = true; + incomingProfileDataForPPR.cancelSessionReason = LPA_CANCEL_SESSION_UNDEFINED_REASON; + } + else + { + // Set lpaApiError in case cancel is due to PPR not allowed + if(incomingProfileDataForPPR.performCancelSession) + { + _sendEventCallbackProgressText(ptrLpaEventCallback, 3, "Profile download not allowed (has PPR1 set whereas at least one Operational profile is already loaded on eUICC)"); + lpaApiError = LPA_ERROR_PPR_NOT_ALLOWED; + } + } + } + + // Step 18: Check incoming profile PPR (If defined) versus RAT rules. + // Does not apply if already Canceled by checking versus installed profiles (So lpaApiError = LPA_ERROR_PPR_NOT_ALLOWED so not entering here) + if (lpaApiError == LPA_NO_ERROR && (incomingProfileDataForPPR.hasPPR1 || incomingProfileDataForPPR.hasPPR2)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "LPA Download: Step 18 -> Checking incoming profile PPR versus RAT rules..."); + if(! _checkIncomingProfilePPRattributesVersusRAT(&incomingProfileDataForPPR, eUICC_RATrules)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to check incoming profile PPR versus PPR rules stored in RAT!"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 3, "Failed to check incoming profile PPR versus PPR rules stored in RAT"); + + // Error in this process will drive to Cancel Session with "PPR not allowed" + incomingProfileDataForPPR.performCancelSession = true; + incomingProfileDataForPPR.cancelSessionReason = LPA_CANCEL_SESSION_PPR_NOT_ALLOWED; + } + + // If Cancel Session required (All due to PPR not allowed) set lpaApiError to cancel remaining of procedure + if(incomingProfileDataForPPR.performCancelSession) + { + _sendEventCallbackProgressText(ptrLpaEventCallback, 3, "Profile download not allowed by RAT"); + lpaApiError = LPA_ERROR_PPR_NOT_ALLOWED; + } + } + + // Memory cleanup: Profile list / RAT used for PPR management + if(currentlyInstalledProfiles.profileInfoList != NULL) + { + lpaCoreMemoryFree(currentlyInstalledProfiles.profileInfoList); + currentlyInstalledProfiles.profileInfoList = NULL; + // currentlyInstalledProfiles is a local member structure, will be removed from heap at the end of function + } + ERASE_RAWDATAOBJECT(eUICC_RATrules); + + // Step 19: Perform User Consent through Callback (Mandatory since SGP.22 V2.3) if loading not already refused by PPR conditions (lpaApiError = LPA_ERROR_PPR_NOT_ALLOWED) + // Systematical default User Consent without PPR can also be bypassed by _bypassDefaultUserConsentWithNoPPR = true + if ((lpaApiError == LPA_NO_ERROR) && ((incomingProfileDataForPPR.userCallBackType != LPA_USR_CONSENT_NO_PPR) || (! _bypassDefaultUserConsentWithNoPPR))) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "LPA Download: Step 19 -> User Consent for profile download..."); + + // Query User Consent only if Callback is defined + if(ptrLpaEventCallback != NULL && ptrLpaEventCallback->_lpaEventRequestUserConsentForLoadingProfile != NULL ) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "User Consent Callback address defined, initializing request..."); + // To be sure to initialize it a each request + memset(&lpaRequestUserConsent, 0x00, sizeof(LPA_REQUEST_USER_CONSENT_FOR_LOADING_PROFILE)); + + lpaRequestUserConsent.userCallBackType = incomingProfileDataForPPR.userCallBackType; + lpaRequestUserConsent.downloadAllowed = false; + lpaRequestUserConsent.cancelSessionReason = LPA_CANCEL_SESSION_UNDEFINED_REASON; + + // Copy profile name in callback structure. If problem during copy, set "..." as profile name + if(NULL == strncpy(lpaRequestUserConsent.profileName, incomingProfileDataForPPR.profileName, LPA_PROFILE_NAME_MAX_SIZE + 1)) + { + lpaRequestUserConsent.profileName[0] = '.'; + lpaRequestUserConsent.profileName[1] = '.'; + lpaRequestUserConsent.profileName[2] = '.'; + lpaRequestUserConsent.profileName[3] = '\0'; + } + + if ( !ptrLpaEventCallback->_lpaEventRequestUserConsentForLoadingProfile(ptrLpaEventCallback->_appParameter, &lpaRequestUserConsent)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "User Consent Callback returned false => Cancel Session Postponed"); + incomingProfileDataForPPR.performCancelSession = true; + incomingProfileDataForPPR.cancelSessionReason = LPA_CANCEL_SESSION_POSTPONED; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "User Consent Callback execution is correct, get user response"); + incomingProfileDataForPPR.performCancelSession = ! lpaRequestUserConsent.downloadAllowed; + incomingProfileDataForPPR.cancelSessionReason = lpaRequestUserConsent.cancelSessionReason; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "No Callback defined to query User Consent, download will be granted by default."); + + // If Cancel Session required due to User choice or no response (Time out case), set lpaApiError to cancel remaining of procedure + if(incomingProfileDataForPPR.performCancelSession) + lpaApiError = LPA_ERROR_DOWNLOAD_SESSION_CANCELED_BY_USER; + } + + // Step 20: Perform Cancel Session if required + if (incomingProfileDataForPPR.performCancelSession) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "LPA Download: Step 20 -> Cancel Session required, initiating it with reason code %u...", incomingProfileDataForPPR.cancelSessionReason); + + cancelResult = _lpaManagerCancelSession((char*)serverData._transactionId->rawData, incomingProfileDataForPPR.cancelSessionReason, activationCode.smdxAddr, ptrLpaEventCallback); + // Notify application owner (Callback) + _notifyAppliOwnerCancelResult(ptrLpaEventCallback, cancelResult, 3); + } + + // Step 21: Confirm PPR check has been done + if (lpaApiError == LPA_NO_ERROR) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "LPA Download: Step 21 -> PPR conditions check performed successfully, download granted..."); + _sendEventCallbackProgressText(ptrLpaEventCallback, 3, "PPR conditions check done"); + } + + // Step 22: prepareDownload + if (lpaApiError == LPA_NO_ERROR) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "LPA Download: Step 22 -> prepare Download..."); + if (lpaApiError == LPA_NO_ERROR) + { + if (serverData._smdpSigned2 != NULL) + { + hashConfirmCode[0] = 0; // Init empty string for Confirmation Code Hash, not yet checked if required + + // Check if server requires Confirmation Code + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Check if Confirmation Code requested by server..."); + + if (serverData._smdpSigned2->rawDataSize > 0){ + ptrBerTLVsmdpSigned2Objects = berTLV_extractTagUInt8(ASN1_SMDPSIGNED2_TAG, serverData._smdpSigned2->rawData, serverData._smdpSigned2->rawDataSize, &tagFound); + + if (ptrBerTLVsmdpSigned2Objects != NULL){ + ptrBerTLVccRequiredFlag = berTLV_extractTagUInt8(ASN1_CCREQUIREDFLAG_TAG, ptrBerTLVsmdpSigned2Objects->value, ptrBerTLVsmdpSigned2Objects->length, &tagFound); + + if (ptrBerTLVccRequiredFlag != NULL){ + if ((ptrBerTLVccRequiredFlag->length == 1) && (*ptrBerTLVccRequiredFlag->value != 0)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Confirmation Code required by server: ccRequiredFlag = Required"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 4, "Confirmation Code required by server"); + + // Generate Confirmation Code Hash if Confirmation Code provided, else error + if (confirmationCodeLength > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Confirmation Code provided."); + if (_calculateConfirmationCodeHash(ptrConfirmationCodeStr, confirmationCodeLength, (char*)serverData._transactionId->rawData, hashConfirmCode)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Confirmation Code Hash : %s", hashConfirmCode); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to calculate Confirmation Code Hash."); + lpaApiError = LPA_ERROR_FAILED_PREPARE_DOWNLOAD; + } + } + else + { + // Confirmation Code not yet present + if (ptrLpaEventCallback != NULL && ptrLpaEventCallback->_lpaEventRequestConfirmationCode != NULL) + { + // CallBack for query of Confirmation Code exist => call it + + LPA_REQUEST_CONFIRMATION_CODE lpaRequestConfirmationCode; + lpaRequestConfirmationCode.confirmationCodeMaxBufferSize = LPA_CONFIRMATION_CODE_MAX_SIZE; + memset(lpaRequestConfirmationCode.confirmationCode, 0x00, LPA_CONFIRMATION_CODE_MAX_SIZE); + lpaRequestConfirmationCode.reasonCodeNoCC = LPA_CANCEL_SESSION_POSTPONED; // In case callback does not set it when return false. + + bool resultCallbackCC = ptrLpaEventCallback->_lpaEventRequestConfirmationCode(ptrLpaEventCallback->_appParameter, &lpaRequestConfirmationCode); + if (resultCallbackCC) + { + if (strlen(lpaRequestConfirmationCode.confirmationCode) > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Confirmation Code recovered from callback: %s", lpaRequestConfirmationCode.confirmationCode); + + // Generate Confirmation Code hash + if (_calculateConfirmationCodeHash(lpaRequestConfirmationCode.confirmationCode, + strlen(lpaRequestConfirmationCode.confirmationCode), (char*)serverData._transactionId->rawData, hashConfirmCode)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Confirmation Code Hash: %s", hashConfirmCode); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to calculate Confirmation Code Hash"); + lpaApiError = LPA_ERROR_FAILED_PREPARE_DOWNLOAD; + lpaSetErrorCode(lpaApiError); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Empty Confirmation Code returned. Canceling session..."); + _sendEventCallbackProgressText(ptrLpaEventCallback, 4, "Empty Confirmation Code returned. Canceling session..."); + + lpaApiError = LPA_ERROR_CONFIRMATION_CODE_MISSING_OR_EMPTY; + lpaSetErrorCode(lpaApiError); // Set LPA ErrorCode before doing lpaManagerCancelSession + + // Send Cancel Session to SM-DP server, reason "Postponed" (1) + cancelResult = _lpaManagerCancelSession((char*)serverData._transactionId->rawData, LPA_CANCEL_SESSION_POSTPONED, + activationCode.smdxAddr, ptrLpaEventCallback); + + // Notify application owner (Callback) + _notifyAppliOwnerCancelResult(ptrLpaEventCallback, cancelResult, 4); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to query Confirmation Code or operation canceled from application. Canceling session with reason code %u.", + lpaRequestConfirmationCode.reasonCodeNoCC); + + _sendEventCallbackProgressText(ptrLpaEventCallback, 4, "Failed to query Confirmation Code or operation canceled from application. Canceling session..."); + + // Send Cancel Session to SM-DP server, reason specified by application + // If reason code incorrect or other error, will use "Postponed" reason + if(isElementPresentInArrayUInt(LPA_ALLOWED_CANCEL_SESSION_CODE_LIST, LPA_ALLOWED_CANCEL_SESSION_CODE_LIST_SIZE, lpaRequestConfirmationCode.reasonCodeNoCC)) + cancelResult = _lpaManagerCancelSession((char*)serverData._transactionId->rawData, + lpaRequestConfirmationCode.reasonCodeNoCC, activationCode.smdxAddr, ptrLpaEventCallback); + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "cancelSession reasonCode unknown, \"Postponed\" (0x01) will be used instead!"); + cancelResult = _lpaManagerCancelSession((char*)serverData._transactionId->rawData, + LPA_CANCEL_SESSION_POSTPONED, activationCode.smdxAddr, ptrLpaEventCallback); + } + + // Notify application owner (Callback) + _notifyAppliOwnerCancelResult(ptrLpaEventCallback, cancelResult, 4); + + // Set error code after in case Cancel session return its own Error Code due to failed operation + lpaApiError = LPA_ERROR_CONFIRMATION_CODE_MISSING_OR_EMPTY; + lpaSetErrorCode(lpaApiError); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Confirmation Code not provided. Canceling session..."); + _sendEventCallbackProgressText(ptrLpaEventCallback, 4, "Confirmation Code not provided. Canceling session..."); + + lpaApiError = LPA_ERROR_CONFIRMATION_CODE_MISSING_OR_EMPTY; + lpaSetErrorCode(lpaApiError); // Set LPA ErrorCode before doing lpaManagerCancelSession + + // Send Cancel Session to SM-DP server, reason "Postponed" (1) + cancelResult = _lpaManagerCancelSession((char*)serverData._transactionId->rawData, LPA_CANCEL_SESSION_POSTPONED, + activationCode.smdxAddr, ptrLpaEventCallback); + + // Notify application owner (Callback) + _notifyAppliOwnerCancelResult(ptrLpaEventCallback, cancelResult, 4); + } + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Confirmation Code not required by server: ccRequiredFlag = Not required"); + // Confirmation Code not required by server so do nothing, hashConfirmCode will be empty so not added + // in prepareDownload command + } + + ERASE_BERTLV(ptrBerTLVccRequiredFlag); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Error: Server data invalid, cannot find ccRequiredFlag in smdpSigned2."); + lpaApiError = LPA_ERROR_FAILED_PREPARE_DOWNLOAD; + } + + ERASE_BERTLV(ptrBerTLVsmdpSigned2Objects); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Error: Server data invalid, cannot find smdpSigned2 objects data."); + lpaApiError = LPA_ERROR_FAILED_PREPARE_DOWNLOAD; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "smdpSigned2 length empty."); + lpaApiError = LPA_ERROR_FAILED_PREPARE_DOWNLOAD; + } + + // If preparing steps OK send "prepareDownload" to eUICC + if (lpaApiError == LPA_NO_ERROR) + { + nbExecGetResp = LPA_LOOP_NUMBER_FOR_CHAINED_GET_RESPONSE; + + // Management of execution / retry loop for PrepareDownload + while(nbExecGetResp > 0) + { + // If GetResponse Chaining issue occur, _lpaManagerPrepareDownload() will also return false + if (_lpaManagerPrepareDownload(&serverData, ptrLpaEventCallback, hashConfirmCode, &prepareDownloadResp)) + { + // No chaining error detected, end execution loop + nbExecGetResp = 0; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "PrepareDownload success."); + + // Erase server data, but keep transactionID + _lpaManagerFreeServerData(&serverData, false); + } + else + { + // Decrease execution loop. If Retry not enabled, will reach 0 so no retry + nbExecGetResp--; + + // Retry management + if(lpaGetErrorCodeNoClear() == SE_MEDIA_E_CHAINING_GET_RESPONSE && LPA_RETRY_CHAINED_GET_RESPONSE_MGT) + { + // If last loop not reached, clear error code to execute another attempt + // Else stay on error SE_MEDIA_E_CHAINING_GET_RESPONSE + if(nbExecGetResp > 0) + { + lpaResetErrorCode(); + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "prepareDownload: GetResponse chaining issue detected, try another time, nbExecGetResp = %d", nbExecGetResp); + + // Avoid memory leak because assigned by _lpaManagerPrepareDownload() + ERASE_RAWDATAOBJECT(prepareDownloadResp.ptrPrepareDownloadResponse); + ERASE_RAWDATAOBJECT(prepareDownloadResp.ptrPrepareDownloadResponse_Base64); + } + else + lpaApiError = SE_MEDIA_E_CHAINING_GET_RESPONSE; // Prevent going on next step when error state is permanent + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to prepareDownload. "); + lpaApiError = LPA_ERROR_FAILED_PREPARE_DOWNLOAD; + + nbExecGetResp = 0; // End execution loop, another error encountered + } + } + } + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Server data is invalid, smdpSigned2 value = NULL. "); + lpaApiError = LPA_ERROR_FAILED_PREPARE_DOWNLOAD; + } + } + } + + // Step 23: Manage Bound Profile Package + if (lpaApiError == LPA_NO_ERROR) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "LPA Download: Step 23 -> Manage Bound Profile Package..."); + if (_lpaManagerGetBoundProfilePackage(&serverData, ptrLpaEventCallback, activationCode.smdxAddr, prepareDownloadResp.ptrPrepareDownloadResponse_Base64->rawData, &cancelForBPPerrors)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Get Bound Profile Package done."); + _sendEventCallbackProgressText(ptrLpaEventCallback, 5, "Get Bound Profile Package done"); + + isNeedToSendPIR = true; + + //loadBoundProfilePackage + if (lpaManagerloadBoundProfilePackage(&serverData, &pir, &cancelForBPPerrors)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Load Bound Profile Package done - Profile download successful"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 6, "Load Bound Profile Package done - Profile download successful"); + + ptrDownloadProfileResult->countProfileInstalled = 1; + } + else + { + // Change error message in case Chained GetResponse issue for loadBoundProfilePackage result and PIR retrieve + if (LPA_RETRY_CHAINED_GET_RESPONSE_MGT && lpaGetErrorCodeNoClear() == SE_MEDIA_E_CHAINING_GET_RESPONSE) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to retrieve final result of loadBoundProfilePackage due to Chained GetResponse issue"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 6, "Failed to retrieve final result of load Bound Profile Package"); + } + else + { + // Do not display this message if BPP error has been detected + if(! cancelForBPPerrors) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to Load Bound Profile Package."); + _sendEventCallbackProgressText(ptrLpaEventCallback, 6, "Failed to Load Bound Profile Package"); + } + + lpaApiError = LPA_ERROR_FAILED_LOAD_BPP; + } + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to Get Bound Profile Package."); + _sendEventCallbackProgressText(ptrLpaEventCallback, 5, "Failed to Get Bound Profile Package"); + + lpaApiError = LPA_ERROR_FAILED_GET_BOUND_PROFILE_PACKAGE; + } + } + // Step 24: Cancel session if BPP error has been detected, in lpaManagerGetBoundProfilePackage() or lpaManagerloadBoundProfilePackage() + if(cancelForBPPerrors) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to Load Bound Profile Package due to BPP error, canceling session."); + _sendEventCallbackProgressText(ptrLpaEventCallback, 6, "Failed to Load Bound Profile Package due to BPP error, canceling session"); + + cancelResult = _lpaManagerCancelSession((char*)serverData._transactionId->rawData, LPA_CANCEL_SESSION_LOAD_BPP_EXECUTION_ERROR, activationCode.smdxAddr, ptrLpaEventCallback); + // Notify application owner (Callback) + _notifyAppliOwnerCancelResult(ptrLpaEventCallback, cancelResult, 6); + + // Due to Cancel Session, no have to send PIR + isNeedToSendPIR = false; + } + + // Memory cleanup + _lpaManagerFreeServerData(&serverData, true); + + ERASE_RAWDATAOBJECT(prepareDownloadResp.ptrPrepareDownloadResponse); + ERASE_RAWDATAOBJECT(prepareDownloadResp.ptrPrepareDownloadResponse_Base64); + + // Step 25: Send PIR is needed + if (isNeedToSendPIR) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "LPA Download: Step 24 -> Send PIR..."); + + //PIR management + if (pir.hasResult && pir.ptrProfileInstallationResultTlv != NULL) + { + if (_sendPIRDuringDownloadProfileOperation) + { + // handle notification + normalNotifAcknowledge = false; + if (activationCode.smdxAddr != NULL && _handleNotification(activationCode.smdxAddr, strlen(activationCode.smdxAddr), pir.ptrProfileInstallationResultTlv_Base64->rawData, ptrLpaEventCallback, &normalNotifAcknowledge)) + { + // Report Successful overall execution if profile successfully loaded AND PIR successfully sent to server + if(ptrDownloadProfileResult->countProfileInstalled == 1) + res = true; + + // Log / send suitable message depending PIR send OK or just acknowledged with error + if(normalNotifAcknowledge) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Send PIR notification to server done"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 7, "Send PIR notification to server done"); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "SM-DP+ server acknowledged PIR notification but returned an error"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 7, "SM-DP+ server acknowledged PIR notification but returned an error"); + } + + //get seq number for remove notification + uint16_t seqNumber = 0; + if (extractSeqNumbFromPIR(&pir, &seqNumber)) + { + //success to get the seq number + if (lpaManagerClearProfileNotification(seqNumber)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Success to clear the PIR notification"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 8, "Clear PIR notification done"); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to Clear PIR notification"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 8, "Failed to Clear PIR notification"); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to get the PIR notification sequence number"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 8, "Failed to get PIR notification sequence number"); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to Send PIR notification to server"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 7, "Failed to Send PIR notification to server"); + + lpaSetErrorCode(LPA_ERROR_FAILED_SEND_NOTIFICATION_OR_NOT_GET_STATUS_CODE); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "PIR notification sending feature deactivated"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 7, "PIR notification sending feature deactivated"); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to retrieve PIR notification from eUICC"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 7, "Failed to retrieve PIR notification from eUICC"); + + lpaSetErrorCode(LPA_ERROR_INVALID_PIR_RESPONSE); + } + } + + // Memory cleanup + ERASE_RAWDATAOBJECT(pir.ptrProfileInstallationResultTlv); + ERASE_RAWDATAOBJECT(pir.ptrProfileInstallationResultTlv_Base64); + + if (lpaApiError != LPA_NO_ERROR) + lpaSetErrorCode(lpaApiError); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- _manageDownloadProfile(...) return %s", (res ? "true" : "false")); + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** +* Profile Download entry point, without Confirmation Code provided +* Note: Do not specify "Confirmation Code Required Flag" in Activation Code, else request will be rejected. +* +* @param ptrActivationCodeStr - Activation Code, String format +* @param ptrLpaEventCallback - Event Callback, type LPA_EventCallback +* @param ptrDownloadProfileResult - Download profile result, type LPA_DOWNLOAD_PROFILE_RESULT +* @return True if profile download is successful +*/ + +bool lpaManagerDownloadProfile(const char * ptrActivationCodeStr, const LPA_EventCallback* ptrLpaEventCallback, LPA_DOWNLOAD_PROFILE_RESULT* ptrDownloadProfileResult) +{ + bool res = false; + int nbExecGetResp = LPA_LOOP_NUMBER_FOR_CHAINED_GET_RESPONSE; + bool retryRequested = false; + + // Registering LPA_EVENT_EXECUTION_ERROR (if configured) for this call only + _registerAppEventExecutionCallback(ptrLpaEventCallback); + + // ptrLpaEventCallback can be NULL, managed after + if((ptrActivationCodeStr != NULL) && (ptrDownloadProfileResult != NULL)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaManagerDownloadProfile(...)"); + + // Check if Confirmation Code required. If yes exits + if (!_checkConfirmationCodeRequestInActivationCodeStr(ptrActivationCodeStr)) + { + // Management execution / retry for GetResponse chained issue + // Here manages issue when occurring at AuthenticateServer + while(nbExecGetResp > 0) + { + res = _manageDownloadProfile(ptrActivationCodeStr, "", 0, ptrLpaEventCallback, ptrDownloadProfileResult, &retryRequested); + if(res) + { + // No error detected, end execution loop anyway + nbExecGetResp = 0; + } + else + { + // Manage retry from return issued by _manageDownloadProfile() + if(retryRequested && LPA_RETRY_CHAINED_GET_RESPONSE_MGT) + { + nbExecGetResp--; + // If last loop not reached, clear error code to execute another attempt + if(nbExecGetResp > 0) + { + lpaResetErrorCode(); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Restart another download attempt from SM-DP, nbExecGetResp=%d", nbExecGetResp); + _sendEventCallbackProgressText(ptrLpaEventCallback, 0, "Restart another download attempt from SM-DP server..."); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Maximum download attempts reached, do not retry anymore."); + _sendEventCallbackProgressText(ptrLpaEventCallback, 0, "Maximum download attempts reached, do not retry anymore"); + } + } + else + { + // Issue not caused by GetReponse chaining error or no management, end execution loop + nbExecGetResp = 0; + } + } + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Error: Confirmation Code Request Flag present in Activation Code. Not supported in this entry point."); + lpaSetErrorCode(LPA_ERROR_DOWNLOAD_PROFILE_PARAMETER_ERROR); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter(s)!"); + lpaSetErrorCode(LPA_ERROR_DOWNLOAD_PROFILE_PARAMETER_ERROR); + } + + // And unregistering LPA_EVENT_EXECUTION_ERROR callback + _unregisterAppEventExecutionCallback(); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaManagerDownloadProfile(...) return %s", (res ? "true" : "false")); + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** +* Profile Download entry point, with Confirmation Code provided. +* Note: If server does not confirm use of Confirmation Code, it will be ignored. +* +* @param ptrActivationCodeStr - Activation Code, String format +* @param ptrConfirmationCodeStr - Confirmation Code, String format +* @param ptrLpaEventCallback - Event Callback, type LPA_EventCallback +* @param ptrDownloadProfileResult - Download profile result, type LPA_DOWNLOAD_PROFILE_RESULT +* @return True if profile download is successful +*/ +bool lpaManagerDownloadProfileWithConfirmationCode(const char * ptrActivationCodeStr, const char * ptrConfirmationCodeStr, const LPA_EventCallback* ptrLpaEventCallback, LPA_DOWNLOAD_PROFILE_RESULT* ptrDownloadProfileResult) +{ + bool res = false; + int nbExecGetResp = LPA_LOOP_NUMBER_FOR_CHAINED_GET_RESPONSE; + bool retryRequested = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaManagerDownloadProfileWithConfirmationCode(...)"); + + // Registering LPA_EVENT_EXECUTION_ERROR (if configured) for this call only + _registerAppEventExecutionCallback(ptrLpaEventCallback); + + // ptrLpaEventCallback can be NULL, managed after + if ((ptrActivationCodeStr != NULL) && (ptrConfirmationCodeStr != NULL) && (ptrDownloadProfileResult != NULL)) + { + int confirmationCodeLength = strlen(ptrConfirmationCodeStr); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Parameters check..."); + if (confirmationCodeLength <= 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Error: Confirmation Code length <= 0"); + lpaSetErrorCode(LPA_ERROR_DOWNLOAD_PROFILE_PARAMETER_ERROR); + } + else + { + // Management of execution / retry for GetResponse chained issue + // Here manages issue when occurring at AuthenticateServer + while(nbExecGetResp > 0) + { + res = _manageDownloadProfile(ptrActivationCodeStr, ptrConfirmationCodeStr, confirmationCodeLength, ptrLpaEventCallback, ptrDownloadProfileResult, &retryRequested); + if(res) + { + // No error detected, end execution loop anyway + nbExecGetResp = 0; + } + else + { + // Manage retry from return issued by _manageDownloadProfile() + if(retryRequested && LPA_RETRY_CHAINED_GET_RESPONSE_MGT) + { + nbExecGetResp--; + // If last loop not reached, clear error code to execute another attempt + if(nbExecGetResp > 0) + { + lpaResetErrorCode(); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Restart another download attempt from SM-DP, nbExecGetResp=%d", nbExecGetResp); + _sendEventCallbackProgressText(ptrLpaEventCallback, 0, "Restart another download attempt from SM-DP server..."); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Maximum download attempts reached, do not retry anymore."); + _sendEventCallbackProgressText(ptrLpaEventCallback, 0, "Maximum download attempts reached, do not retry anymore"); + } + + } + else + { + // Issue not caused by GetReponse chaining error or no management, end execution loop + nbExecGetResp = 0; + } + } + } + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter(s)!"); + lpaSetErrorCode(LPA_ERROR_DOWNLOAD_PROFILE_PARAMETER_ERROR); + } + + // And unregistering LPA_EVENT_EXECUTION_ERROR callback + _unregisterAppEventExecutionCallback(); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaManagerDownloadProfileWithActivationCode(...) return %s", (res ? "true" : "false")); + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** + * Initialize fields of LPA_SERVER_DATA / *ptr_serverData structure + * @param p_serverData Pointer on server data structure + * @param clearTransactionID If true transactionID will be also initialized + * @return true is parameters are correct + */ +bool _lpaManagerInitServerData(ptr_serverData p_serverData, bool initTransactionID) +{ + bool res = false; + if (p_serverData != NULL) + { + if(initTransactionID) + p_serverData->_transactionId = NULL; + + // Initiate Authentication objects + p_serverData->_serverSigned1 = NULL; + p_serverData->_serverSignature1 = NULL; + p_serverData->_euiccCiPKIdToBeUsed = NULL; + p_serverData->_serverCertificate = NULL; + + // Authenticate Client objects + p_serverData->_smdpCertificate = NULL; + p_serverData->_smdpSignature2 = NULL; + p_serverData->_smdpSigned2 = NULL; + p_serverData->_profileMetadata = NULL; + + p_serverData->_boundProfilePackage = NULL; + p_serverData->_boundProfilePackageLength = 0; + p_serverData->_boundProfilePackageContainerCount = 0; + + res = true; + } + return res; +} +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** + * De-allocate fields of LPA_SERVER_DATA / *ptr_serverData structure + * @param p_serverData Pointer on server data structure + * @param clearTransactionID If true transactionID will be also cleared + * @return true is parameters are correct + */ +bool _lpaManagerFreeServerData(ptr_serverData p_serverData, bool clearTransactionID) +{ + bool res = false; + + if (p_serverData != NULL) + { + if(clearTransactionID) + ERASE_RAWDATAOBJECT(p_serverData->_transactionId); + + // Initiate Authentication objects + ERASE_RAWDATAOBJECT(p_serverData->_serverSigned1); + ERASE_RAWDATAOBJECT(p_serverData->_serverSignature1); + ERASE_RAWDATAOBJECT(p_serverData->_euiccCiPKIdToBeUsed); + ERASE_RAWDATAOBJECT(p_serverData->_serverCertificate); + + // Authenticate Client objects + ERASE_RAWDATAOBJECT(p_serverData->_smdpCertificate); + ERASE_RAWDATAOBJECT(p_serverData->_smdpSignature2); + ERASE_RAWDATAOBJECT(p_serverData->_smdpSigned2); + ERASE_RAWDATAOBJECT(p_serverData->_profileMetadata); + + ERASE_BERTLV_LIST(p_serverData->_boundProfilePackage); + p_serverData->_boundProfilePackageLength = 0; + p_serverData->_boundProfilePackageContainerCount = 0; + + res = true; + } + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + + +/** + * Extract useful fields from currently downloaded profile metadata returned by Authenticate Client. + * Also checks that mandatory fields are present (ICCID, serviceProviderName and profileName) + * Initialize fields of LPA_DOWNLOADED_PROFILE_DATA_FOR_PPR structure for PPR management (If needed) + * Initialize field of LPA_EVENT_INCOMING_PROFILE_INFORMATION structure for profile information return during download + * @param profileMetadata - Pointer on profile metadata, bytes + * @param profileMetadataSize - Profile metatadata size. Must be > 2 (At least tag + length) + * @param ptrProfileFieldsForPPR - Pointer on LPA_DOWNLOADED_PROFILE_DATA_FOR_PPR structure who will receive extracted data for PPR management - Optional, NULL if not used + * @param ptrProfileFieldsForInfo - Pointer on LPA_EVENT_INCOMING_PROFILE_INFORMATION who will receive extracted data for profile information + * @return true if OK, else false if parsing failed (Metadata anomaly / missing fields detected) + */ +bool _extractFieldsFromProfileMetadata(const unsigned char * ptrProfileMetadata, const size_t profileMetadataSize, + LPA_DOWNLOADED_PROFILE_DATA_FOR_PPR * ptrProfileFieldsForPPR, LPA_EVENT_INCOMING_PROFILE_INFORMATION * ptrProfileFieldsForInfo) +{ + bool res = false; + + // Main Metadata object + BeerTLV * berProfileMetadata = NULL; + // Metadata main objects / fields parsing + BerTLVList * berProfileFieldList = NULL; + uint8_t profileFieldListCount = 0; + BerTLVList * berTLVlistParser = NULL; + BeerTLV * berTLVlistCurrent = NULL; + // Profile Owner objects / fields parsing + BerTLVList * berTLVProfileOwnerList = NULL; + uint8_t profileOwnerListCount = 0; + BerTLVList* berTLVProfileOwnerListParser = NULL; + BeerTLV* berTLVProfileOwnerListCurrent = NULL; + + bool iccidTagDetectedValidated = false; + bool serviceProviderNameTagDetected = false; + bool profileNameTagDetected = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_extractFieldsFromProfileMetadata()..."); + + // ptrProfileFieldsForPPR is optional + if((ptrProfileMetadata != NULL) && (profileMetadataSize > 2) && (ptrProfileFieldsForInfo != NULL)) + { + berProfileMetadata = berTLV_extractTagUInt16(PROFILE_METADATA_TAG, (unsigned char *)ptrProfileMetadata, profileMetadataSize, NULL); + + if(berProfileMetadata != NULL) + { + // No need to process a empty list with not enough bytes to make at least one TL object + if(berProfileMetadata->length > 1) + { + berProfileFieldList = berTLV_extractList(berProfileMetadata->value, berProfileMetadata->length, &profileFieldListCount); + + // Metadata shall contain at least 3 elements: ICCID, serviceProviderName and profileName + if(berProfileFieldList != NULL && profileFieldListCount > 2) + { + res = true; // At this step we consider that structure is correct. Any problem found after will disable this status + + // Extracted profile fields initialization + if(ptrProfileFieldsForPPR != NULL) + { + ptrProfileFieldsForPPR->gid1Defined = false; + ptrProfileFieldsForPPR->gid2Defined = false; + } + + // Parse Metadata main fields + berTLVlistParser = berProfileFieldList; + while (berTLVlistParser != NULL) + { + berTLVlistCurrent = berTLVlistParser->berTLV; + + if(berTLVlistCurrent != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Found profile Metadata field tag: <%X> - Length: %lu", berTLVlistCurrent->tag, (long unsigned)berTLVlistCurrent->length); + + switch(berTLVlistCurrent->tag) + { + case 0x99: // PPR definition + // Recover ASN1 tag on 2 bytes and convert it to unsigned int + ptrProfileFieldsForInfo->profilePPR = (berTLVlistCurrent->value[0] << 8) + berTLVlistCurrent->value[1]; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "TAG <99> -> PPR ASN1 value: 0x%X", ptrProfileFieldsForInfo->profilePPR); + + if(ptrProfileFieldsForPPR != NULL) + { + ptrProfileFieldsForPPR->profilePPR = (berTLVlistCurrent->value[0] << 8) + berTLVlistCurrent->value[1]; + + ptrProfileFieldsForPPR->hasPPR1 = _isPPR1definedInPPRflag(ptrProfileFieldsForPPR->profilePPR); + ptrProfileFieldsForPPR->hasPPR2 = _isPPR2definedInPPRflag(ptrProfileFieldsForPPR->profilePPR); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "PPR defined in profile:%s%s%s", ((ptrProfileFieldsForPPR->hasPPR1)?" PPR1":""), + ((ptrProfileFieldsForPPR->hasPPR2)?" PPR2":""), (!(ptrProfileFieldsForPPR->hasPPR1 || ptrProfileFieldsForPPR->hasPPR2))?" None or PPRUC only":""); + } + + break; + + case 0xB7: // Profile Owner object - Only used when data retrieval for PPR management is required + if(ptrProfileFieldsForPPR != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Profile Owner tag list found, parsing it..."); + // Profile Owner integrate mandatory mccMnc and optional gid1 / gid2 in a list + berTLVProfileOwnerList = berTLV_extractList(berTLVlistCurrent->value, berTLVlistCurrent->length, &profileOwnerListCount); + + if(berTLVProfileOwnerList != NULL && profileOwnerListCount > 0) + { + berTLVProfileOwnerListParser = berTLVProfileOwnerList; + + // Parse Profile Owner fields + while(berTLVProfileOwnerListParser != NULL && res) + { + berTLVProfileOwnerListCurrent = berTLVProfileOwnerListParser->berTLV; + + if(berTLVProfileOwnerListCurrent != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Found Profile Owner tag: <%X>", berTLVProfileOwnerListCurrent->tag); + + switch(berTLVProfileOwnerListCurrent->tag) + { + case 0x80: // MCC / MNC (Mandatory) + if(berTLVProfileOwnerListCurrent->length == 3) + { + memcpy(ptrProfileFieldsForPPR->mccMnc, berTLVProfileOwnerListCurrent->value, 3); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "TAG -> <80> -> MCC/MNC value: %X%X%X", + berTLVProfileOwnerListCurrent->value[0], berTLVProfileOwnerListCurrent->value[1], + berTLVProfileOwnerListCurrent->value[2]); + } + else + { + res = false; + lpaSetErrorCode(LPA_ERROR_INVALID_PROFILE_METADATA); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Profile Owner list: Incorrect length for MCC/MNC!"); + } + + break; + + case 0x81: // GID1 + ptrProfileFieldsForPPR->gid1Defined = true; // Field exists, even if length = 0 (Used for PPR conditions) + if(berTLVProfileOwnerListCurrent->length <= LPA_GID_MAX_SIZE) // If empty no copy done, length = 0 + { + memcpy(ptrProfileFieldsForPPR->gid1, berTLVProfileOwnerListCurrent->value, berTLVProfileOwnerListCurrent->length); + ptrProfileFieldsForPPR->gid1Size = berTLVProfileOwnerListCurrent->length; + lpaCoreLogAppendByteArray(SDK_LOG_LEVEL_DEBUG, NULL, "TAG -> <81> -> GID1", ptrProfileFieldsForPPR->gid1, + ptrProfileFieldsForPPR->gid1Size); + } + else + { + res = false; + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Profile Owner list: GID1 size bigger (%lu) than maximum allowed (%u)!", + (long unsigned)berTLVProfileOwnerListCurrent->length, LPA_GID_MAX_SIZE); + } + + break; + + case 0x82: // GID2 + ptrProfileFieldsForPPR->gid2Defined = true; // Field exists, even if length = 0 (Used for PPR conditions) + if(berTLVProfileOwnerListCurrent->length <= LPA_GID_MAX_SIZE) // If empty no copy done, length = 0 + { + memcpy(ptrProfileFieldsForPPR->gid2, berTLVProfileOwnerListCurrent->value, berTLVProfileOwnerListCurrent->length); + ptrProfileFieldsForPPR->gid2Size = berTLVProfileOwnerListCurrent->length; + lpaCoreLogAppendByteArray(SDK_LOG_LEVEL_DEBUG, NULL, "TAG -> <82> -> GID2", ptrProfileFieldsForPPR->gid2, + ptrProfileFieldsForPPR->gid2Size); + } + else + { + res = false; + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Profile Owner list: GID2 size bigger (%lu) than maximum allowed (%u)!", + (long unsigned)berTLVProfileOwnerListCurrent->length, LPA_GID_MAX_SIZE); + } + + break; + + default: + res = false; + lpaSetErrorCode(LPA_ERROR_INVALID_PROFILE_METADATA); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Profile Owner list: Unattended element detected!"); + + break; + } + } + else + { + res = false; + lpaSetErrorCode(LPA_ERROR_INVALID_PROFILE_METADATA); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Profile Owner: Current BERTLV list element appear to be NULL ?"); + } + + berTLVProfileOwnerListParser = berTLVProfileOwnerListParser->ptrNext; + } + + // MCC / MNC is a mandatory field of Profile Owner object, so if missing goes on error + // Note: Value "000000" shall not exist (Also variable contain if not updated) + if((ptrProfileFieldsForPPR->mccMnc[0] == 0) && (ptrProfileFieldsForPPR->mccMnc[1] == 0) && (ptrProfileFieldsForPPR->mccMnc[2] == 0)) + { + res = false; + lpaSetErrorCode(LPA_ERROR_INVALID_PROFILE_METADATA); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Profile Owner: MCC / MNC missing or invalid value \"000000\"!"); + } + } + else + { + res = false; + lpaSetErrorCode(LPA_ERROR_INVALID_PROFILE_METADATA); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Profile Metadata: Corrupted data detected in Profile Owner!"); + } + + // Memory cleanup + berTLVProfileOwnerListParser = NULL; // Remove reference to data to be released + berTLVProfileOwnerListCurrent = NULL; // Remove reference to data to be released + ERASE_BERTLV_LIST(berTLVProfileOwnerList); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Profile Owner tag list found but not used now"); + + break; + + case 0x92: // Profile Name + profileNameTagDetected = true; + // Recover profile name and store it as string. If too long generate error + if(berTLVlistCurrent->length <= (LPA_PROFILE_NAME_MAX_SIZE)) + { + memcpy(ptrProfileFieldsForInfo->profileName, berTLVlistCurrent->value, berTLVlistCurrent->length); + ptrProfileFieldsForInfo->profileName[berTLVlistCurrent->length] = 0; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "TAG <92> -> Profile Name: %s", ptrProfileFieldsForInfo->profileName); + + if(ptrProfileFieldsForPPR != NULL) + { + memcpy(ptrProfileFieldsForPPR->profileName, berTLVlistCurrent->value, berTLVlistCurrent->length); + ptrProfileFieldsForPPR->profileName[berTLVlistCurrent->length] = 0; + } + } + else + { + res = false; + lpaSetErrorCode(LPA_ERROR_INVALID_PROFILE_METADATA); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Profile Metadata: Too big length found (%lu) for Profile Name!", (long unsigned)berTLVlistCurrent->length); + } + + break; + + case 0x91: // Service Provider Name + serviceProviderNameTagDetected = true; + // Recover service provide name and store it as string. If too long generate error + if(berTLVlistCurrent->length <= (LPA_PROFILE_SERVICE_PROVIDER_NAME_MAX_SIZE)) + { + memcpy(ptrProfileFieldsForInfo->serviceProviderName, berTLVlistCurrent->value, berTLVlistCurrent->length); + ptrProfileFieldsForInfo->serviceProviderName[berTLVlistCurrent->length] = 0; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "TAG <91> -> Service Provider Name: %s", ptrProfileFieldsForInfo->serviceProviderName); + } + else + { + res = false; + lpaSetErrorCode(LPA_ERROR_INVALID_PROFILE_METADATA); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Profile Metadata: Too big length found (%lu) for Service Provider Name!", (long unsigned)berTLVlistCurrent->length); + } + + break; + + case 0x5A: // ICCID + // We can also validate length, that is fixed. + if(berTLVlistCurrent->length == 0x0A) + { + iccidTagDetectedValidated = true; + + memcpy(ptrProfileFieldsForInfo->iccid, berTLVlistCurrent->value, berTLVlistCurrent->length); + ptrProfileFieldsForInfo->iccidSize = 0x0A; + + if (formatBytesToHexaString(ptrProfileFieldsForInfo->iccid, ptrProfileFieldsForInfo->iccidSize, _bufferFormatLogMessage, sizeof(_bufferFormatLogMessage)) > 0) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "TAG <5A> -> ICCID: %s", _bufferFormatLogMessage); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "TAG <5A> -> ICCID: ... (Translation problem)"); + + } + else + { + res = false; + lpaSetErrorCode(LPA_ERROR_INVALID_PROFILE_METADATA); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Profile Metadata: Incorrect length found (%lu) for ICCID!", (long unsigned)berTLVlistCurrent->length); + } + + break; + + case 0x93: // Icon Type + // Shall be a short value, equal to 0 (JPG) or 1 (PNG) so no more than one byte + if(berTLVlistCurrent->length > 0 && berTLVlistCurrent->length < 2) + { + ptrProfileFieldsForInfo->profileIconType = berTLVlistCurrent->value[0]; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "TAG <93> -> Icon Type: %u", ptrProfileFieldsForInfo->profileIconType); + } + else + { + res = false; + lpaSetErrorCode(LPA_ERROR_INVALID_PROFILE_METADATA); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Profile Metadata: Incorrect length found (%lu) for Icon Type!", (long unsigned)berTLVlistCurrent->length); + } + + break; + + case 0x94: // Icon + // Recover icon data. If too long generate error + if(berTLVlistCurrent->length <= (LPA_PROFILE_ICON_MAX_SIZE)) + { + memcpy(ptrProfileFieldsForInfo->profileIcon, berTLVlistCurrent->value, berTLVlistCurrent->length); + ptrProfileFieldsForInfo->profileIconSize = berTLVlistCurrent->length; + + lpaCoreLogAppendByteArray(SDK_LOG_LEVEL_DEBUG, NULL, "TAG <94> -> Icon", ptrProfileFieldsForInfo->profileIcon, + ptrProfileFieldsForInfo->profileIconSize); + } + else + { + res = false; + lpaSetErrorCode(LPA_ERROR_INVALID_PROFILE_METADATA); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Profile Metadata: Too big length found (%lu) for Icon!", (long unsigned)berTLVlistCurrent->length); + } + + break; + + default: + // No processing for other tags + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Not used here."); + break; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "Profile Metadata: Current BERTLV list element appear to be NULL ? Go to next one..."); + + berTLVlistParser = berTLVlistParser->ptrNext; + } + + // Check if mandatory fields of profile Metadata have been all checked OK + if(!profileNameTagDetected || !serviceProviderNameTagDetected || !iccidTagDetectedValidated) + { + res = false; + lpaSetErrorCode(LPA_ERROR_INVALID_PROFILE_METADATA); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Missing or invalid Metadata field (ICCID, Service Provider Name or Profile Name)"); + } + } + else + { + lpaSetErrorCode(LPA_ERROR_INVALID_PROFILE_METADATA); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_extractFieldsFromProfileMetadata: Failed to extract field list or corrupted Metadata!"); + } + + // Memory cleanup + ERASE_BERTLV_LIST(berProfileFieldList); + } + else + { + // Empty metadata container. + // Generate an error because object StoreMetadataRequest defining it shall at least contain: ICCID, serviceProviderName and profileName + lpaSetErrorCode(LPA_ERROR_INVALID_PROFILE_METADATA); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_extractFieldsFromProfileMetadata: Metadata container is empty."); + } + + + // Memory cleanup + ERASE_BERTLV(berProfileMetadata); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_extractFieldsFromProfileMetadata: Profile Metadata main tag not found or invalid TLV format!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PROFILE_METADATA); + } + + // Initialize general purpose fields whatever is result + if(ptrProfileFieldsForPPR != NULL) + { + ptrProfileFieldsForPPR->userCallBackType = LPA_USR_CONSENT_NO_PPR; + ptrProfileFieldsForPPR->performCancelSession = false; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_extractFieldsFromProfileMetadata: Invalid parameter!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_extractFieldsFromProfileMetadata() return %s", (res)?"True":"False"); + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** + * Set default SM-DP address in eUICC + * @param ptrSMDPAddr SM-DP address to set, string format, length smaller than LPA_SMDP_ADDRESS_SIZE + * @return true if address setting OK + */ + +bool lpaManagerSetDefaultSMDPAddress(const char* ptrSMDPAddr) +{ + bool res = false; + + const int responseBufferSize = 10; // Response object contains only TLV header and a flag on one byte , so normally 6 bytes shall be enough + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerSetDefaultSMDPAddress()..."); + + if (ptrSMDPAddr != NULL && strlen(ptrSMDPAddr) < LPA_SMDP_ADDRESS_SIZE) // ptrSMDPAddr can contains an empty string + { + unsigned char *ptrResponseBuffer = lpaCoreMemoryAlloc(responseBufferSize); + if (ptrResponseBuffer != NULL) + { + size_t dataBufferSize = 0; + uint16_t sw = 0x0000; + RawDataObject* rawDataObjectSDMDAddr_80 = NULL; + rawDataObjectSDMDAddr_80 = berTLV_createAndBuildRawDataObject(0x80, strlen(ptrSMDPAddr), (const unsigned char*)ptrSMDPAddr); + + if (rawDataObjectSDMDAddr_80 != NULL && rawDataObjectSDMDAddr_80->rawDataSize > 0) + { + RawDataObject* rawDataObjectSDMDAddr = NULL; + rawDataObjectSDMDAddr = berTLV_createAndBuildRawDataObject(0xBF3F, rawDataObjectSDMDAddr_80->rawDataSize, rawDataObjectSDMDAddr_80->rawData); + if (rawDataObjectSDMDAddr != NULL && rawDataObjectSDMDAddr->rawDataSize > 0) + { + if (buildAndSendStoreDataCase4(rawDataObjectSDMDAddr, &sw, ptrResponseBuffer, responseBufferSize, &dataBufferSize)) + { + // Check SW = 90.00 or 91.xx + if ((sw == 0x9000) || ((sw & 0xFF00) == 0x9100)) + { + if (dataBufferSize > 1) + { + if (ptrResponseBuffer[dataBufferSize - 1] == 0) + { + res = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to set default SMDP address"); + lpaSetErrorCode(LPA_ERROR_INVALID_SET_DEFAULT_SMDP_ADDRESS); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "No Raw data available!"); + lpaSetErrorCode(LPA_ERROR_INVALID_SET_DEFAULT_SMDP_ADDRESS); + } + } + else + { + // No or Invalid SW + lpaSetErrorCode(LPA_ERROR_INVALID_SW); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to set default SMDP address"); + lpaSetErrorCode(LPA_ERROR_INVALID_SET_DEFAULT_SMDP_ADDRESS); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to build data object!"); + lpaSetErrorCode(LPA_ERROR_INVALID_SET_DEFAULT_SMDP_ADDRESS); + } + + ERASE_RAWDATAOBJECT(rawDataObjectSDMDAddr); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to build data object!"); + lpaSetErrorCode(LPA_ERROR_INVALID_SET_DEFAULT_SMDP_ADDRESS); + } + + ERASE_RAWDATAOBJECT(rawDataObjectSDMDAddr_80); + + lpaCoreMemoryFree(ptrResponseBuffer); + ptrResponseBuffer = NULL; + } + else + { + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + } + else + { + if (ptrSMDPAddr == NULL) + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter NULL!"); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "SM-DP address too long, maximum %d characters allowed!", LPA_SMDP_ADDRESS_SIZE - 1); + + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** + * Perform GetEuiccConfiguredAddresses request for default SM-DP + * @param ptrAddressData Pointer on ADDRESS_DATA object that will return retrieved SM-DP address (May be empty) + * @return True if operation OK + */ +bool lpaManagerGetSMDPAddress(ADDRESS_DATA* ptrAddressData) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerGetSMDPAddress()..."); + + // Checking of ptrAddressData pointer wil be done in _processGetSMserverAddress() + return _processGetSMserverAddress(ptrAddressData, true); +} + + +/** + * Perform GetEuiccConfiguredAddresses request for SM-DS + * @param ptrAddressData Pointer on ADDRESS_DATA object that will return retrieved SM-DS address + * @return True if operation OK + */ + +bool lpaManagerGetSMDSAddress(ADDRESS_DATA* ptrAddressData) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerGetSMDSAddress()..."); + + // Checking of ptrAddressData pointer wil be done in _processGetSMserverAddress() + return _processGetSMserverAddress(ptrAddressData, false); +} + + +/** + * Perform the processing of GetEuiccConfiguredAddresses request response + * @param ptrAddressData Pointer on ADDRESS_DATA object that will return retrieved address + * @param isSMDPserver If true will indicate that we want to retrieve default SM-DP address, else it will be SM-DP + * @return True if operation OK + */ +bool _processGetSMserverAddress(ADDRESS_DATA* ptrAddressData, bool isSMDPserver) +{ + bool res = false; + RawDataObject* euiccAddr; + unsigned char addressTag = 0; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_processGetSMserverAddress()... %s mode", isSMDPserver ? "SM-DP" : "SM-DS"); + + if (ptrAddressData != NULL) + { + addressTag = isSMDPserver ? 0x80 : 0x81; // Tag to find 0x80 for SM-DP, 0x81 for SM-DS + + memset(ptrAddressData, 0, sizeof(ADDRESS_DATA)); // In case not have been done by caller + + euiccAddr = rawDataObject_allocate(); + + if(euiccAddr != NULL) + { + if (_getEUICCconfiguredAddresses(euiccAddr)) + { + if (euiccAddr->rawDataSize > 0 && euiccAddr->rawData != NULL) + { + BeerTLV* berTLV_BF3C = berTLV_extractTagUInt16(0xBF3C, (const unsigned char*)euiccAddr->rawData, euiccAddr->rawDataSize, NULL); + + if (berTLV_BF3C != NULL) + { + BeerTLV* berTLV_addressTLV = berTLV_extractTagUInt8(addressTag, berTLV_BF3C->value, berTLV_BF3C->length, NULL); + if (berTLV_addressTLV != NULL) + { + if (berTLV_addressTLV->length <= LPA_SMDS_ADDRESS_SIZE) + { + memcpy(ptrAddressData->address_Data, berTLV_addressTLV->value, berTLV_addressTLV->length); + ptrAddressData->address_DataSize = berTLV_addressTLV->length; + res = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Output buffer too small for copying address data!"); + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + ERASE_BERTLV(berTLV_addressTLV); + } + else + { + if(isSMDPserver) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Default SM-DP address is not present (optional)"); + ptrAddressData->address_DataSize = 0; + res = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to get SM-DS address"); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_SMDS_ADDRESS); + } + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to get %s address (No BF3C TLV)", isSMDPserver ? "default SM-DP" : "SM-DS"); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_SMDS_ADDRESS); + } + + ERASE_BERTLV(berTLV_BF3C); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid Get eUICC address response (Empty or NULL)"); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_EUICC_ADDRESS); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Problem encountered while requesting eUICC address"); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_EUICC_ADDRESS); + } + + // Memory cleanup + ERASE_RAWDATAOBJECT(euiccAddr); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Cannot initialize RawData object euiccAddr!"); + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + return res; +} + + +/** + * Perform GetEuiccConfiguredAddresses request with retry management + * @param ptrRawDataEuiccAddr pointer of RawData object that will return the eUICC response + * @return True if operation OK + */ +bool _getEUICCconfiguredAddresses(RawDataObject* ptrRawDataEuiccAddr) +{ + bool res = false; + int nbExecGetResp = LPA_LOOP_NUMBER_FOR_CHAINED_GET_RESPONSE; // If retry deactivated, will be performed only one time + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_getEUICCconfiguredAddresses()..."); + + if (ptrRawDataEuiccAddr != NULL) + { + size_t dataBufferSize = 0; + uint16_t sw = 0x0000; + RawDataObject* rawDataObjectGetAddr = NULL; + rawDataObjectGetAddr = berTLV_createAndBuildRawDataObject(0xBF3C, 0, 0x00); + if (rawDataObjectGetAddr != NULL && rawDataObjectGetAddr->rawDataSize > 0) + { + // Execution / retry management + while(nbExecGetResp > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "do buildAndSendStoreDataCase4(GetEUICCConfiguredAddress) ..."); + if (buildAndSendStoreDataCase4(rawDataObjectGetAddr, &sw, _dataBuffer, LPA_MANAGER_DATA_BUFFER_MAX_SIZE, &dataBufferSize)) + { + // No chaining error detected, end execution loop + nbExecGetResp = 0; + + // Check SW = 90.00 or 91.xx + if ((sw == 0x9000) || ((sw & 0xFF00) == 0x9100)) + { + if (dataBufferSize > 0) + { + // Copy Data from card, with success check + if(rawDataObject_appendRawDataArray(ptrRawDataEuiccAddr, _dataBuffer, dataBufferSize)) + res = true; + //memcpy(ptrEuiccAddr->eUICCConfiguredAddr_RawData, _dataBuffer, dataBufferSize); + //ptrEuiccAddr->eUICCConfiguredAddr_RawDataSize = dataBufferSize; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "No address data available from eUICC!"); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_EUICC_ADDRESS); + } + } + else + { + // No or Invalid SW + lpaSetErrorCode(LPA_ERROR_INVALID_SW); + } + } + else + { + // Decrease execution loop. If Retry not enabled, will reach 0 so no retry + nbExecGetResp--; + + // Retry management + if(lpaGetErrorCodeNoClear() == SE_MEDIA_E_CHAINING_GET_RESPONSE && LPA_RETRY_CHAINED_GET_RESPONSE_MGT) + { + // If last loop not reached, clear error code to execute another attempt + // Else stay on error SE_MEDIA_E_CHAINING_GET_RESPONSE + if(nbExecGetResp > 0) + { + lpaResetErrorCode(); + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "_getEUICCconfiguredAddresses: GetResponse chaining issue detected, try another time, nbExecGetResp = %d", nbExecGetResp); + } + } + else + { + lpaSetErrorCode(LPA_ERROR_INVALID_GET_EUICC_ADDRESS); + nbExecGetResp = 0; // End execution loop, another error encountered + } + } + } + } + else + lpaSetErrorCode(LPA_ERROR_INVALID_GET_EUICC_ADDRESS); + + ERASE_RAWDATAOBJECT(rawDataObjectGetAddr); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter: address NULL!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + return res; +} + + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** + * Load profile using Default SM-DP defined in eUICC + * @param ptrLpaEventCallback Pointer on callback for calling layer information messages. If NULL no callback performed + * @param ptrDownloadProfileResult Pointer for profile download results return, LPA_DOWNLOAD_PROFILE_RESULT type. + * @return Return "true" if profile download in eUICC is successful + */ +bool lpaManagerDownloadProfileWithDefaultSMDPAddress(const LPA_EventCallback* ptrLpaEventCallback, LPA_DOWNLOAD_PROFILE_RESULT* ptrDownloadProfileResult) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaManagerDownloadProfileWithDefaultSMDPAddress(...)"); + + bool res = false; + ADDRESS_DATA smdpAddr; + int nbExecGetResp = LPA_LOOP_NUMBER_FOR_CHAINED_GET_RESPONSE; + bool retryRequested = false; + bool getDefaultSMDPaddressOK = false; + + // Registering LPA_EVENT_EXECUTION_ERROR (if configured) for this call only + _registerAppEventExecutionCallback(ptrLpaEventCallback); + + // ptrLpaEventCallback can be NULL, managed below + if (ptrDownloadProfileResult != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Start to Download Profile with default SMDP Address..."); + + ptrDownloadProfileResult->countProfileInstalled = 0; + ptrDownloadProfileResult->countProfileTotal = 0; + + memset(&smdpAddr, 0, sizeof(ADDRESS_DATA)); + + // Retrieve Default SMDP address. If not bypassed by parameter get it from eUICC + if((strlen(_deviceDefaultSMDPaddress) > 0) && (strlen(_deviceDefaultSMDPaddress) < LPA_SMDP_ADDRESS_SIZE)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Use alternate Default SM-DP + address defined in parameters: %s", _deviceDefaultSMDPaddress); + + memcpy(smdpAddr.address_Data, _deviceDefaultSMDPaddress, strlen(_deviceDefaultSMDPaddress)); // smdpAddr is initialized with 0 so OK for EOS + smdpAddr.address_DataSize = strlen(_deviceDefaultSMDPaddress); + getDefaultSMDPaddressOK = true; + } + else + getDefaultSMDPaddressOK = lpaManagerGetSMDPAddress(&smdpAddr); + + // If failed due to unsuccessful Retry on getting default SMDP address, will exit with code related to Chained GetResponse issue. + if (getDefaultSMDPaddressOK) + { + if((smdpAddr.address_Data != NULL) && (smdpAddr.address_DataSize > 0)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Success to get Default SM-DP + address: %s", smdpAddr.address_Data); + _sendEventCallbackProgressText(ptrLpaEventCallback, 0, "Get default SM-DP + Address done"); + + // Management of execution / retry loop for GetResponse chained issue + // Here manages issue when occurring at AuthenticateServer + while(nbExecGetResp > 0) + { + // Load profile. If GetResponse chaining issue occur, will also return false + if(_performProfileDownloadFromDefaultAddress(ptrLpaEventCallback, smdpAddr.address_Data, smdpAddr.address_DataSize, "", ptrDownloadProfileResult, true, &retryRequested)) + { + // No error detected, end execution loop anyway + nbExecGetResp = 0; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Profile loading is successful."); + res = true; + } + else + { + // Manage retry from return issued by _performProfileDownloadFromDefaultAddress() + if(retryRequested && LPA_RETRY_CHAINED_GET_RESPONSE_MGT) + { + nbExecGetResp--; + // If last loop not reached, clear error code to execute another attempt + if(nbExecGetResp > 0) + { + lpaResetErrorCode(); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Restart another download attempt from SM-DP, nbExecGetResp=%d", nbExecGetResp); + _sendEventCallbackProgressText(ptrLpaEventCallback, 0, "Restart another download attempt from SM-DP server..."); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Maximum download attempts reached, do not retry anymore."); + _sendEventCallbackProgressText(ptrLpaEventCallback, 0, "Maximum download attempts reached, do not retry anymore"); + } + } + else + { + // Issue not caused by GetReponse chaining error or no management, end execution loop + nbExecGetResp = 0; + + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Profile loading failed."); + } + } + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Default SM-DP Address invalid"); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_SMDP_ADDRESS); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to get Default SM-DP Address"); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_SMDP_ADDRESS); + } + + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + // And unregistering LPA_EVENT_EXECUTION_ERROR callback + _unregisterAppEventExecutionCallback(); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaManagerDownloadProfileWithDefaultSMDPAddress(...)"); + + return res; +} + + +/** + * Perform profile download from an SM-DP when loading using SM-DS or default SM-DP defined in eUICC + * @param ptrLpaEventCallback Pointer on callback for calling layer information messages. If NULL no callback performed + * @param pSmdpAddr Address of SM-DP server, string format + * @param pSmdpAddrSize SM-DP address length + * @param pEventID EventID for SM-DS operations. Must be an empty string "" for SM-DP operations. + * @param ptrDownloadProfileResult Pointer for profile download results return, LPA_DOWNLOAD_PROFILE_RESULT type. + * @param requestFromDefaultSMDPload Boolean flag, must me set to "true" for SM-DP operation, "false" for SM-DS operations + * @param retryRequested Pointer to boolean flag, if returned "true" means to caller that it is requested to retry request due to error (GetResponse chaining...) + * @return Return "true" if profile download in eUICC is successful, including successful sending of PIR to server + */ +bool _performProfileDownloadFromDefaultAddress(const LPA_EventCallback* ptrLpaEventCallback, const char* pSmdpAddr, const size_t pSmdpAddrSize, + const char* pEventID, LPA_DOWNLOAD_PROFILE_RESULT* ptrDownloadProfileResult, const bool requestFromDefaultSMDPload, bool * retryRequested) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ _performProfileDownloadFromDefaultAddress(...)"); + + bool res = false; + bool isProcessOK = true; + bool cancelForBPPerrors = false; + bool cancelResult = false; + + LPA_GET_EUICC getEuiccChallenge; + LPA_GET_EUICC getEuiccInfo; + bool deviceInfoExtensibilitySupport = false; + unsigned char filteredDeviceInfo[LPA_CFG_DEVICE_INFO_TLV_BYTE_ARRAY_MAX_SIZE]; + size_t filteredDeviceInfoSize = 0; + + RawDataObject * prepareCtxParam = NULL; + LPA_SERVER_DATA serverData; + AUTHENTICATE_SERVER_RESPONSE authentServerResp; + PREPARE_DOWNLOAD_RESPONSE prepareDownloadResp; + PROFILE_INSTALLATION_RESULT pir; + + LPA_EVENT_INCOMING_PROFILE_INFORMATION incomingProfileInfoForCallback; + LPA_DOWNLOADED_PROFILE_DATA_FOR_PPR incomingProfileDataForPPR; + + bool normalNotifAcknowledge = false; + + int nbExecGetResp = LPA_LOOP_NUMBER_FOR_CHAINED_GET_RESPONSE; + *retryRequested = false; // For the moment, do not request retry in case of GetResponseChaining failure + + // Initialize variables and structures + _lpaManagerInitServerData(&serverData, true); + + getEuiccChallenge.ptrEUICC = NULL; + getEuiccChallenge.prtEUICC_Base64 = NULL; + + getEuiccInfo.ptrEUICC = NULL; + getEuiccInfo.prtEUICC_Base64 = NULL; + + memset(filteredDeviceInfo, 0x00, sizeof(filteredDeviceInfo)); + + authentServerResp.ptrAuthenticateServerResponse = NULL; + authentServerResp.ptrAuthenticateServerResponse_Base64 = NULL; + + prepareDownloadResp.ptrPrepareDownloadResponse = NULL; + prepareDownloadResp.ptrPrepareDownloadResponse_Base64 = NULL; + + pir.hasResult = false; + pir.ptrProfileInstallationResultTlv = NULL; + pir.ptrProfileInstallationResultTlv_Base64 = NULL; + + memset(&incomingProfileInfoForCallback, 0x00, sizeof(LPA_EVENT_INCOMING_PROFILE_INFORMATION)); + memset(&incomingProfileDataForPPR, 0x00, sizeof(LPA_DOWNLOADED_PROFILE_DATA_FOR_PPR)); + + // STEP 1: Parameters check. ptrLpaEventCallback can be NULL, managed below depending needs. + if ((ptrDownloadProfileResult == NULL) || (pSmdpAddr == NULL) || (pSmdpAddrSize <= 0) || (pEventID == NULL) || ((strlen(pEventID) != 0) && requestFromDefaultSMDPload) || + ((strlen(pEventID) <= 0) && !requestFromDefaultSMDPload)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + isProcessOK = false; + } + + // STEP 2: Get UiccChallenge and UiccInfo1 + if(isProcessOK) + { + if(_lpaManagerGetEuiccChallenge(&getEuiccChallenge)) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Get UiccChallenge OK."); + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to get UiccChallenge!"); + // Error code lpaSetErrorCode() has to be set by _lpaManagerGetEuiccChallenge() + isProcessOK = false; + } + + if(isProcessOK) + { + if(_lpaManagerGetEuiccInfoWithRetry(GET_EUICC_INFO1_DGI_TAG, &getEuiccInfo)) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Get EUICCInfo1 OK."); + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to get EUICCInfo1!"); + // Error code lpaSetErrorCode() has to be set by _lpaManagerGetEuiccInfoWithRetry() + isProcessOK = false; + } + } + } + + // STEP 3: Perform initiateAuthentication + if(isProcessOK) + { + if (getEuiccChallenge.prtEUICC_Base64 != NULL && getEuiccInfo.prtEUICC_Base64 != NULL && + lpaManagerInitiateAuthentication(&serverData, ptrLpaEventCallback, (const char*)getEuiccChallenge.prtEUICC_Base64->rawData, (const char*)getEuiccInfo.prtEUICC_Base64->rawData, pSmdpAddr)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Initiate authentication done."); + _sendEventCallbackProgressText(ptrLpaEventCallback, 1, "Initiate authentication done"); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to Initiate authentication!"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 1, "Failed to Initiate authentication"); + + lpaSetErrorCode(LPA_ERROR_FAILED_INITIAL_AUTHENTICATION); + isProcessOK = false; + } + } + + // Memory cleanup + ERASE_RAWDATAOBJECT(getEuiccChallenge.ptrEUICC); + ERASE_RAWDATAOBJECT(getEuiccChallenge.prtEUICC_Base64); + + ERASE_RAWDATAOBJECT(getEuiccInfo.ptrEUICC); + ERASE_RAWDATAOBJECT(getEuiccInfo.prtEUICC_Base64); + + // STEP 4: Check transactionID + if(isProcessOK) + { + if ((serverData._transactionId == NULL) || (serverData._transactionId->rawDataSize < 1) || (serverData._transactionId->rawDataSize >= LPA_TRANSACTION_ID_MAX_SIZE)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid TransactionID!"); + lpaSetErrorCode(LPA_ERROR_INVALID_TRANSACTIONID); + isProcessOK = false; + } + } + + // STEP 5: Log transactionId and check SM-DP+ Address + if(isProcessOK) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "LPA Download: TransactionId: <%s>", serverData._transactionId->rawData); + + if ((serverData._serverSigned1 != NULL) && _verifySMDPAddress(pSmdpAddr, (const char*)serverData._serverSigned1->rawData, serverData._serverSigned1->rawDataSize)) + { + _sendEventCallbackProgressText(ptrLpaEventCallback, 1, "SM-DP+ address checking done"); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid SM-DP+ Address"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 1, "Failed to check SM-DP+ address, invalid"); + lpaSetErrorCode(LPA_ERROR_INVALID_SERVER_ADDRESS); + isProcessOK = false; + } + } + + // STEP 6: GetEuiccInfo2 + if (isProcessOK && _deviceCapabilitiesFilter) // No need to perform it if filtering is disabled + { + if(_lpaManagerGetEuiccInfoWithRetry(GET_EUICC_INFO2_DGI_TAG, &getEuiccInfo)) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Get EUICCInfo2 done."); + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to get EUICCInfo2!"); + // Error code lpaSetErrorCode() has to be set by _lpaManagerGetEuiccInfoWithRetry() + isProcessOK = false; + } + } + + // STEP 7: Get status of flag "deviceInfoExtensibilitySupport" in object "RspCapability" returned in EUICCInfo2 + if (isProcessOK && _deviceCapabilitiesFilter) // No need to perform it if filtering is disabled + { + if(_lpaManagerGetFlag_deviceInfoExtensibilitySupport(&getEuiccInfo, &deviceInfoExtensibilitySupport)) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Get status of flag deviceInfoExtensibilitySupport done."); + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to get status of flag deviceInfoExtensibilitySupport!"); + // Error code lpaSetErrorCode() has to be set by _lpaManagerGetEuiccInfoWithRetry() + isProcessOK = false; + } + } + + // Memory cleanup + ERASE_RAWDATAOBJECT(getEuiccInfo.ptrEUICC); + ERASE_RAWDATAOBJECT(getEuiccInfo.prtEUICC_Base64); + + // STEP 8: Manage "deviceInformation" "deviceCapabilities" features depending "deviceInfoExtensibilitySupport" flag status and filtering option + // Note: Even if filtering is disabled, this step remain mandatory to get copy of deviceInformation + if(isProcessOK) + { + if(_lpaManagerFilterDeviceCapabitilitiesInformation(_deviceInfoByteArray, _deviceInfoByteArraySize, filteredDeviceInfo, &filteredDeviceInfoSize, + sizeof(filteredDeviceInfo), deviceInfoExtensibilitySupport, _deviceCapabilitiesFilter)) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Management of deviceInfomation done."); + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to manage deviceInformation!"); + // Error code lpaSetErrorCode() has to be set by _lpaManagerFilterDeviceCapabitilitiesInformation() + isProcessOK = false; + } + } + + // STEP 9: Check CTX param + if(isProcessOK) + { + if ((strlen(_deviceInfo) > 0) && _lpaManagerPrepareCtxParam(pEventID, filteredDeviceInfo, filteredDeviceInfoSize, &prepareCtxParam)) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "PrepareCtxParam OK"); + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid CTX Params"); + lpaSetErrorCode(LPA_ERROR_INVALID_CTX_PARAM); + isProcessOK = false; + } + } + + // STEP 10: Perform and check authenticateServer + if(isProcessOK) + { + // If GetResponse chaining error, _lpaManagerAuthenticateServer() will return false + if (_lpaManagerAuthenticateServer(&serverData, ptrLpaEventCallback, prepareCtxParam, &authentServerResp) && authentServerResp.ptrAuthenticateServerResponse_Base64 != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Authenticate server done"); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "AuthenticateServer response: %s ", authentServerResp.ptrAuthenticateServerResponse_Base64->rawData); + + _sendEventCallbackProgressText(ptrLpaEventCallback, 2, "Authenticate server done"); + } + else + { + // Management of GetResponse chaining issue. Command retry is not possible at this step, cancel current session and inform caller that + // retry of entire process is requested + if(lpaGetErrorCodeNoClear() == SE_MEDIA_E_CHAINING_GET_RESPONSE && LPA_RETRY_CHAINED_GET_RESPONSE_MGT) + { + *retryRequested = true; + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "AuthenticateServer: GetResponse chaining issue detected, stop current profile download."); + _sendEventCallbackProgressText(ptrLpaEventCallback, 2, "AuthenticateServer: GetResponse chaining issue detected, stop current profile download"); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to Authenticate server!"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 2, "Failed to Authenticate server"); + } + + lpaSetErrorCode(LPA_ERROR_FAILED_AUTHENTICATE_SERVER); + isProcessOK = false; + } + } + + // Memory cleanup + ERASE_RAWDATAOBJECT(prepareCtxParam); + + // STEP 11: Perform and check authenticateClient + if(isProcessOK) + { + // Clear server data but keep transactionID + _lpaManagerFreeServerData(&serverData, false); + + if (_lpaManagerAuthenticateClient(&serverData, ptrLpaEventCallback, pSmdpAddr, authentServerResp.ptrAuthenticateServerResponse_Base64->rawData)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Authenticate client done"); + + _sendEventCallbackProgressText(ptrLpaEventCallback, 3, "Authenticate client done"); + + // FOR DEFAULT SM-DP LOAD ONLY: + // Total Profile management - At this step (Authenticate Client OK) we consider we have a profile available + // No need to increase because we always start from 0 + if(requestFromDefaultSMDPload) + ptrDownloadProfileResult->countProfileTotal = 1; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to Authenticate client!"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 3, "Failed to Authenticate client"); + + lpaSetErrorCode(LPA_ERROR_FAILED_AUTHENTICATE_CLIENT); + isProcessOK = false; + } + + ERASE_RAWDATAOBJECT(authentServerResp.ptrAuthenticateServerResponse); + ERASE_RAWDATAOBJECT(authentServerResp.ptrAuthenticateServerResponse_Base64); + } + + // Step 12: Check smdpSigned2 for prepareDownload + if(isProcessOK) + { + if (serverData._smdpSigned2 == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Server data smdpSigned2 is invalid!"); + lpaSetErrorCode(LPA_ERROR_FAILED_PREPARE_DOWNLOAD); + isProcessOK = false; + } + } + + // Step 13: Extract informations from incoming profile Metadata retrieved after Authenticate Client for profile information callback + // Also check if PPR1 or PPR2 is defined in profile for blocking of incoming profile with PPR if needed + if(isProcessOK) + { + incomingProfileInfoForCallback.profileMetadataAvailable = false; + // Other incoming profile data for information callback already initialized by memset() at beginning + + // Incoming profile data initialization for PPR + incomingProfileDataForPPR.profilePPR = 0; + incomingProfileDataForPPR.hasPPR1 = false; + incomingProfileDataForPPR.hasPPR2 = false; + // mccMnc already set to 00 by memset + // gid1 already set to 00 by memset + // gid1Size already set to 00 by memset + incomingProfileDataForPPR.gid1Defined = false; + // gid2 already set to 00 by memset + // gid2Size already set to 00 by memset + incomingProfileDataForPPR.gid2Defined = false; + // profileName already set to 00 by memset + incomingProfileDataForPPR.userCallBackType = LPA_USR_CONSENT_NO_PPR; + incomingProfileDataForPPR.performCancelSession = false; + // cancelSessionReason already set to 00 by memset, no meaning while performCancelSession = false + + if(serverData._profileMetadata->rawDataSize > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Server has returned Metadata for incoming profile. Extracting data for user information callback..."); + // Set "Metadata Available" flag in profile data structure for information callback + incomingProfileInfoForCallback.profileMetadataAvailable = true; + + if(_extractFieldsFromProfileMetadata(serverData._profileMetadata->rawData, serverData._profileMetadata->rawDataSize, &incomingProfileDataForPPR, &incomingProfileInfoForCallback)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Profile informations successfully extracted, send user information callback"); + + // Send callback only if has been defined by calling application + if (ptrLpaEventCallback != NULL && ptrLpaEventCallback->_lpaEventDisplayIncomingProfileInformation != NULL) + { + ptrLpaEventCallback->_lpaEventDisplayIncomingProfileInformation(ptrLpaEventCallback->_appParameter, 3, &incomingProfileInfoForCallback); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to extract Metadata from incoming profile!"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 3, "Failed to extract Metadata from incoming profile"); + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_UNABLE_TO_EXTRACT_DATA); + // Error is linked to incorrect data received from server, stopping download + isProcessOK = false; + + // This error will drive to Cancel Session with reason "Undefined" (Case not covered) + incomingProfileDataForPPR.performCancelSession = true; + incomingProfileDataForPPR.cancelSessionReason = LPA_CANCEL_SESSION_UNDEFINED_REASON; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "No profile Metadata returned by Authenticate Client"); + + // Send callback even if no data available, to keep calling application informed through "profileMetadataAvailable" flag + // And only if has been defined by calling application + if (ptrLpaEventCallback != NULL && ptrLpaEventCallback->_lpaEventDisplayIncomingProfileInformation != NULL) + { + ptrLpaEventCallback->_lpaEventDisplayIncomingProfileInformation(ptrLpaEventCallback->_appParameter, 3, &incomingProfileInfoForCallback); + } + } + } + + // STEP 14: Check if any PPR apply to profile and if supportDownloadOfProfilesWithPPR = false. If yes do not allow profile download and request Cancel Session + if (isProcessOK && (incomingProfileDataForPPR.hasPPR1 || incomingProfileDataForPPR.hasPPR2) && (! _supportDownloadOfProfilesWithPPR)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "Download of profiles with PPR is currently not allowed by LPA setting, canceling download session..."); + _sendEventCallbackProgressText(ptrLpaEventCallback, 3, "Download of profiles with PPR is currently not allowed by LPA setting, canceling download session"); + + incomingProfileDataForPPR.performCancelSession = true; + incomingProfileDataForPPR.cancelSessionReason = LPA_CANCEL_SESSION_PPR_NOT_ALLOWED; + isProcessOK = false; // Stop current session download + } + + // STEP 15: Cancel session if parsing of incoming profile metadata failed or profile refused because having PPR defined + if((! isProcessOK) && (incomingProfileDataForPPR.performCancelSession)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Cancel Session required, initiating it with reason code %u...", incomingProfileDataForPPR.cancelSessionReason); + + cancelResult = _lpaManagerCancelSession((char*)serverData._transactionId->rawData, incomingProfileDataForPPR.cancelSessionReason, pSmdpAddr, ptrLpaEventCallback); + // Notify application owner (Callback) + _notifyAppliOwnerCancelResult(ptrLpaEventCallback, cancelResult, 3); + } + + // STEP 16: Perform and check prepareDownload + if(isProcessOK) + { + nbExecGetResp = LPA_LOOP_NUMBER_FOR_CHAINED_GET_RESPONSE; + + // Management of execution / retry loop for PrepareDownload + while(nbExecGetResp > 0) + { + // If GetResponse Chaining issue occur, _lpaManagerPrepareDownload() will also return false + if (!_lpaManagerPrepareDownload(&serverData, ptrLpaEventCallback, "", &prepareDownloadResp)) + { + // Decrease execution loop. If Retry not enabled, will reach 0 so no retry + nbExecGetResp--; + + // Retry management + if(lpaGetErrorCodeNoClear() == SE_MEDIA_E_CHAINING_GET_RESPONSE && LPA_RETRY_CHAINED_GET_RESPONSE_MGT) + { + // If last loop not reached, clear error code to execute another attempt + // Else stay on error SE_MEDIA_E_CHAINING_GET_RESPONSE + if(nbExecGetResp > 0) + { + lpaResetErrorCode(); + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "prepareDownload: GetResponse chaining issue detected, try another time, nbExecGetResp = %d", nbExecGetResp); + + // Avoid memory leak because assigned by _lpaManagerPrepareDownload() + ERASE_RAWDATAOBJECT(prepareDownloadResp.ptrPrepareDownloadResponse); + ERASE_RAWDATAOBJECT(prepareDownloadResp.ptrPrepareDownloadResponse_Base64); + } + else + isProcessOK = false; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to prepareDownload!"); + lpaSetErrorCode(LPA_ERROR_FAILED_PREPARE_DOWNLOAD); + isProcessOK = false; + + nbExecGetResp = 0; // End execution loop, another error encountered + } + } + else + { + nbExecGetResp = 0; // No chaining error detected, end execution loop + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "PrepareDownload success."); + } + + } + } + + // STEP 17: Perform and check getBoundProfilePackage + if(isProcessOK) + { + // Clear server data but keep transactionID + _lpaManagerFreeServerData(&serverData, false); + + if (prepareDownloadResp.ptrPrepareDownloadResponse_Base64 != NULL && _lpaManagerGetBoundProfilePackage(&serverData, ptrLpaEventCallback, pSmdpAddr, + prepareDownloadResp.ptrPrepareDownloadResponse_Base64->rawData, &cancelForBPPerrors)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Get Bound Profile Package OK"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 5, "Get Bound Profile Package done"); + } + else + { + // Eventual Cancel session for BPP error is processed after + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to Get Bound Profile Package. "); + _sendEventCallbackProgressText(ptrLpaEventCallback, 5, "Failed to Get Bound Profile Package"); + + lpaSetErrorCode(LPA_ERROR_FAILED_GET_BOUND_PROFILE_PACKAGE); + isProcessOK = false; + } + + ERASE_RAWDATAOBJECT(prepareDownloadResp.ptrPrepareDownloadResponse); + ERASE_RAWDATAOBJECT(prepareDownloadResp.ptrPrepareDownloadResponse_Base64); + } + + // STEP 18: Perform and check loadBoundProfilePackage, then process PIR + if(isProcessOK) + { + if (lpaManagerloadBoundProfilePackage(&serverData, &pir, &cancelForBPPerrors)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Load Bound Profile Package done - Profile download successful"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 6, "Load Bound Profile Package done - Profile download successful"); + + // At this step we confirm that profile is installed, increase installation counter (INCREASE APPLY FOR SM-DS MULTIPLE PROFILES OPERATIONS) + ptrDownloadProfileResult->countProfileInstalled++; + + // Report overall success of download operation, but status can be invalidated in case PIR sending is failed + res = true; + } + else + { + // Change error message in case Chained GetResponse issue for loadBoundProfilePackage result and PIR retrieve + if (LPA_RETRY_CHAINED_GET_RESPONSE_MGT && lpaGetErrorCodeNoClear() == SE_MEDIA_E_CHAINING_GET_RESPONSE) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to retrieve final result of loadBoundProfilePackage due to Chained GetResponse issue"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 6, "Failed to retrieve final result of load Bound Profile Package"); + } + else + { + // Do not display this message if BPP error has been detected + if(! cancelForBPPerrors) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to Load Bound Profile Package."); + _sendEventCallbackProgressText(ptrLpaEventCallback, 6, "Failed to Load Bound Profile Package"); + } + + lpaSetErrorCode(LPA_ERROR_FAILED_LOAD_BPP); + } + } + + // STEP 19: PIR management, if no Cancel Session due to BPP error detected before + if(! cancelForBPPerrors) + { + if (pir.hasResult && pir.ptrProfileInstallationResultTlv->rawData != NULL) + { + if (_sendPIRDuringDownloadProfileOperation) + { + // handle notification + normalNotifAcknowledge = false; + if (_handleNotification(pSmdpAddr, pSmdpAddrSize, pir.ptrProfileInstallationResultTlv_Base64->rawData, ptrLpaEventCallback, &normalNotifAcknowledge)) + { + // Log / send suitable message depending PIR send OK or just acknowledged with error + if(normalNotifAcknowledge) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Send PIR notification to server done."); + _sendEventCallbackProgressText(ptrLpaEventCallback, 7, "Send PIR notification to server done"); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "SM-DP+ server acknowledged PIR notification but returned an error"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 7, "SM-DP+ server acknowledged PIR notification but returned an error"); + } + + //get seq number for remove notification + uint16_t seqNumber = 0; + if (extractSeqNumbFromPIR(&pir, &seqNumber)) + { + //success to get the seq number + if (lpaManagerClearProfileNotification(seqNumber)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Clear the PIR notification OK"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 8, "Clear PIR notification done"); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to Clear PIR notification"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 8, "Failed to Clear PIR notification"); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to get the PIR notification sequence number"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 8, "Failed to get PIR notification sequence number"); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to Send PIR notification to server"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 7, "Failed to Send PIR notification to server"); + + // PIR sending failed, so invalidate eventual overall success + res = false; + + lpaSetErrorCode(LPA_ERROR_FAILED_SEND_NOTIFICATION_OR_NOT_GET_STATUS_CODE); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "PIR notification sending feature deactivated."); + _sendEventCallbackProgressText(ptrLpaEventCallback, 7, "PIR notification sending feature deactivated"); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to retrieve PIR notification from eUICC!"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 7, "Failed to retrieve PIR notification from eUICC"); + + // No PIR available invalidates eventual overall success + res = false; + + lpaSetErrorCode(LPA_ERROR_INVALID_PIR_RESPONSE); + } + } + } + + // Cancel session if BPP error has been detected, in lpaManagerGetBoundProfilePackage() or lpaManagerloadBoundProfilePackage() + if(cancelForBPPerrors) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to Load Bound Profile Package due to BPP error, canceling session."); + _sendEventCallbackProgressText(ptrLpaEventCallback, 6, "Failed to Load Bound Profile Package due to BPP error, canceling session"); + + cancelResult = _lpaManagerCancelSession((char*)serverData._transactionId->rawData, LPA_CANCEL_SESSION_LOAD_BPP_EXECUTION_ERROR, pSmdpAddr, ptrLpaEventCallback); + // Notify application owner (Callback) + _notifyAppliOwnerCancelResult(ptrLpaEventCallback, cancelResult, 6); + } + + // Do not display / log this message if retry requested (GetResponse Chaining issue management) or if download from default SM-DP + // Allow to recognize more easily failed download(s) when loading multiple profiles from SM-DS Event List + if(((! *retryRequested) && (! requestFromDefaultSMDPload)) && ((! isProcessOK) || (! res))) + { + // Report failed status to be sure to notify user when issue occurred during a step without application owner notification, before final Load Bound Profile Package + // Especially not visible when SM-DS is used + + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Problem occurred during download!"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 9, "Problem occurred during download"); + } + + + // Memory cleanup + ERASE_RAWDATAOBJECT(authentServerResp.ptrAuthenticateServerResponse); + ERASE_RAWDATAOBJECT(authentServerResp.ptrAuthenticateServerResponse_Base64); + + ERASE_RAWDATAOBJECT(pir.ptrProfileInstallationResultTlv); + ERASE_RAWDATAOBJECT(pir.ptrProfileInstallationResultTlv_Base64); + + ERASE_RAWDATAOBJECT(prepareDownloadResp.ptrPrepareDownloadResponse); + ERASE_RAWDATAOBJECT(prepareDownloadResp.ptrPrepareDownloadResponse_Base64); + + _lpaManagerFreeServerData(&serverData, true); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- _performProfileDownloadFromDefautlAddress(...)"); + + return res; +} + + +bool _verifySMDPAddress(const char* ptrSmdpAddress, const char* ptrServerSignedTLV, size_t serverSignedTLVSize) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_verifySMDPAddress()..."); + + if (ptrSmdpAddress != NULL && ptrServerSignedTLV != NULL && serverSignedTLVSize > 0) + { + if (formatBytesToHexaString((const unsigned char *)ptrServerSignedTLV, serverSignedTLVSize, _bufferFormatLogMessage, sizeof(_bufferFormatLogMessage)) > 0) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "ptrServerSignedTLV (%llu bytes): <%s>", (long long unsigned)serverSignedTLVSize, _bufferFormatLogMessage); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "ptrServerSignedTLV (%llu bytes): ...", (long long unsigned)serverSignedTLVSize); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "ptrSmdpAddress (%llu bytes): <%s>", (long long unsigned)strlen(ptrSmdpAddress), ptrSmdpAddress); + + char* ptrServerSmdpAddress = NULL; + BeerTLV* berTLV_30 = NULL; + BerTLVList* BerTLVListInsideTag30 = NULL; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Extracting SMDP Address from ptrServerSignedTLV..."); + + bool isTagFound_30 = false; + berTLV_30 = berTLV_extractTagUInt16(0x30, (const unsigned char*)ptrServerSignedTLV, serverSignedTLVSize, &isTagFound_30); + if (berTLV_30 != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "TAG <30> Present"); + + uint8_t countTLVFound = 0; + BerTLVListInsideTag30 = berTLV_extractList(berTLV_30->value, berTLV_30->length, &countTLVFound); + + if (countTLVFound > 0 && BerTLVListInsideTag30 != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "%u tag found inside BERTLV object", countTLVFound); + + BerTLVList* berTLVCurrentInsideSequenceTag = BerTLVListInsideTag30; + while (berTLVCurrentInsideSequenceTag != NULL) + { + if (formatBytesToHexaString(berTLVCurrentInsideSequenceTag->berTLV->value, berTLVCurrentInsideSequenceTag->berTLV->length, _bufferFormatLogMessage, + sizeof(_bufferFormatLogMessage)) > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Tag <%X> (%lu bytes): <%s>", berTLVCurrentInsideSequenceTag->berTLV->tag, (long unsigned)berTLVCurrentInsideSequenceTag->berTLV->length, + _bufferFormatLogMessage); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Tag <%X> (%lu bytes): ...", berTLVCurrentInsideSequenceTag->berTLV->tag, (long unsigned)berTLVCurrentInsideSequenceTag->berTLV->length); + + + if (berTLVCurrentInsideSequenceTag->berTLV->tag == 0x83) + { + if (berTLVCurrentInsideSequenceTag->berTLV->length > 0) + { + // The RSP Server address as an FQDN + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, " ServerAdress item found => extract string from rawdata"); + + ptrServerSmdpAddress = lpaCoreMemoryAlloc(berTLVCurrentInsideSequenceTag->berTLV->length + 1); + if (ptrServerSmdpAddress != NULL) + { + memcpy(ptrServerSmdpAddress, berTLVCurrentInsideSequenceTag->berTLV->value, + berTLVCurrentInsideSequenceTag->berTLV->length); + ptrServerSmdpAddress[berTLVCurrentInsideSequenceTag->berTLV->length] = 0x00; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, " ServerAdress extracted: <%s>", ptrServerSmdpAddress); + } + } + } + + berTLVCurrentInsideSequenceTag = berTLVCurrentInsideSequenceTag->ptrNext; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "No tag found inside BERTLV object!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "TAG <30> absent!"); + + + + if (ptrServerSmdpAddress != NULL && strcmp(ptrServerSmdpAddress, ptrSmdpAddress) == 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "SM-DP Address is valid"); + res = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "SM-DP Address is invalid!"); + lpaSetErrorCode(LPA_ERROR_INVALID_SERVER_ADDRESS); + } + + // Cleanup memory + ERASE_BERTLV_LIST(BerTLVListInsideTag30); + ERASE_BERTLV(berTLV_30); + if (ptrServerSmdpAddress != NULL) + { + lpaCoreMemoryFree(ptrServerSmdpAddress); + ptrServerSmdpAddress = NULL; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter(s)!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + return res; +} + + +///////////////////////////////////////////// +// +///////////////////////////////////////////// +/** + * Load profile(s) using Default SM-DS defined in eUICC. Manage multiple profile list that could be returned by server. + * @param ptrLpaEventCallback Pointer on callback for calling layer information messages. If NULL no callback performed + * @param ptrDownloadProfileResult Pointer for profile download results return, LPA_DOWNLOAD_PROFILE_RESULT type. + * @return Return "true" if profile download in eUICC is successful + */ +bool lpaManagerDownloadProfileWithSMDSAddress(const LPA_EventCallback* ptrLpaEventCallback, LPA_DOWNLOAD_PROFILE_RESULT* ptrDownloadProfileResult) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaManagerDownloadProfileWithSMDSAddress(...)"); + + bool res = false; + bool isDSprocessOK = true; + LPA_GET_EUICC getEuiccChallenge; + LPA_GET_EUICC getEuiccInfo; + bool deviceInfoExtensibilitySupport = false; + unsigned char filteredDeviceInfo[LPA_CFG_DEVICE_INFO_TLV_BYTE_ARRAY_MAX_SIZE]; + size_t filteredDeviceInfoSize = 0; + RawDataObject * prepareCtxParam = NULL; + LPA_SERVER_DATA serverData; + + AUTHENTICATE_SERVER_RESPONSE ptrAuthServerResp; + + EVENT_RECORD_LIST eventRecordList; + ADDRESS_DATA smdsAddr; + + char callbackDisplayBuffer[100]; + + int nbExecGetResp = LPA_LOOP_NUMBER_FOR_CHAINED_GET_RESPONSE; + int nbExecGetRespAuthServDS = LPA_LOOP_NUMBER_FOR_CHAINED_GET_RESPONSE; // Need another loop because other retry processes runs inside + bool retryRequested = false; + + LPA_API_ERROR firstEncounteredErrorCode = LPA_NO_ERROR; // To store first encountered profile download error code if GetResponse Retry mechanism enabled + + // Initialize variables and data structures + getEuiccChallenge.ptrEUICC = NULL; + getEuiccChallenge.prtEUICC_Base64 = NULL; + + getEuiccInfo.ptrEUICC = NULL; + getEuiccInfo.prtEUICC_Base64 = NULL; + + _lpaManagerInitServerData(&serverData, true); + + memset(&smdsAddr, 0, sizeof(ADDRESS_DATA)); + memset(&eventRecordList, 0x00, sizeof(EVENT_RECORD_LIST)); + memset(filteredDeviceInfo, 0x00, sizeof(filteredDeviceInfo)); + + ptrAuthServerResp.ptrAuthenticateServerResponse = NULL; + ptrAuthServerResp.ptrAuthenticateServerResponse_Base64 = NULL; + + // Registering LPA_EVENT_EXECUTION_ERROR (if configured) for this call only + _registerAppEventExecutionCallback(ptrLpaEventCallback); + + // ptrLpaEventCallback can be NULL, managed below + if (ptrDownloadProfileResult != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Start to Download Profile list (Event list) with SMDS address..."); + + // Install counters init + ptrDownloadProfileResult->countProfileInstalled = 0; + ptrDownloadProfileResult->countProfileTotal = 0; + + // STEP 1: Get default SM-DS address from eUICC + // If failed due to unsuccessful Retry on getting default SMDS address, will exit with code related to Chained GetResponse issue. + if(isDSprocessOK) + { + // Retrieve Default SMDS address. If not bypassed by parameter get it from eUICC + if((strlen(_deviceSMDSaddress) > 0) && (strlen(_deviceSMDSaddress) < LPA_SMDS_ADDRESS_SIZE)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Use alternate SM-DS address defined in parameters: %s", _deviceSMDSaddress); + + memcpy(smdsAddr.address_Data, _deviceSMDSaddress, strlen(_deviceSMDSaddress)); // smdsAddr is initialized with 0 so OK for EOS + smdsAddr.address_DataSize = strlen(_deviceSMDSaddress); + } + else + isDSprocessOK = lpaManagerGetSMDSAddress(&smdsAddr); + + if (isDSprocessOK) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Success to get SM-DS address: %s", smdsAddr.address_Data); + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to get SM-DS address!"); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_SMDS_ADDRESS); + } + } + + // Restart point for management of Retry on GetResponse chaining issue for AuthenticateServer - SM-DS Events retrieval execution loop + while(nbExecGetRespAuthServDS > 0) + { + // STEP 2: Get and check successful retrieve of EuiccChallenge and EuiccInfo1 (SM-DS operations) + if(isDSprocessOK) + { + _lpaManagerFreeServerData(&serverData, true); // Needed in case of retry + + if(_lpaManagerGetEuiccChallenge(&getEuiccChallenge)) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Get UiccChallenge for SM-DS Events retrieval OK"); + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to get UiccChallenge for SM-DS Events retrieval!"); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_EUICC_INFO); + isDSprocessOK = false; + } + + if(isDSprocessOK) + { + if(_lpaManagerGetEuiccInfoWithRetry(GET_EUICC_INFO1_DGI_TAG, &getEuiccInfo)) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Get UiccInfo1 for SM-DS Events retrieval OK"); + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to get UiccInfo1 for SM-DS Events retrieval!"); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_EUICC_INFO); + isDSprocessOK = false; + } + } + } + + // STEP 3: Perform and check initiateAuthentication execution (SM-DS operations) + if(isDSprocessOK) + { + if (lpaManagerInitiateAuthentication(&serverData, ptrLpaEventCallback, (const char*)getEuiccChallenge.prtEUICC_Base64->rawData, (const char*)getEuiccInfo.prtEUICC_Base64->rawData, smdsAddr.address_Data)) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Execution of initiateAuthentication for SM-DS Events retrieval OK"); + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to process initiateAuthentication for SM-DS Events retrieval!"); + lpaSetErrorCode(LPA_ERROR_FAILED_INITIAL_AUTHENTICATION); + isDSprocessOK = false; + } + } + + // Memory cleanup + ERASE_RAWDATAOBJECT(getEuiccChallenge.ptrEUICC); + ERASE_RAWDATAOBJECT(getEuiccChallenge.prtEUICC_Base64); + + ERASE_RAWDATAOBJECT(getEuiccInfo.ptrEUICC); + ERASE_RAWDATAOBJECT(getEuiccInfo.prtEUICC_Base64); + + // STEP 4: Check serverSigned1, SM-DS address and transactionID then confirm successful initiateAuthentication (SM-DS operations) + if(isDSprocessOK) + { + if (serverData._serverSigned1 != NULL) + { + if(_verifySMDPAddress(smdsAddr.address_Data, (const char*)serverData._serverSigned1->rawData, serverData._serverSigned1->rawDataSize)) + { + // Check and log transactionId + if (serverData._transactionId != NULL && serverData._transactionId->rawDataSize > 0 && serverData._transactionId->rawDataSize < LPA_TRANSACTION_ID_MAX_SIZE) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "LPA Download: TransactionId (DS): <%s>", serverData._transactionId->rawData); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid transactionId (SM-DS Events retrieval)!"); + lpaSetErrorCode(LPA_ERROR_INVALID_TRANSACTIONID); + isDSprocessOK = false; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid SM-DS address (SM-DS Events retrieval)!"); + lpaSetErrorCode(LPA_ERROR_INVALID_SERVER_ADDRESS); + isDSprocessOK = false; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid serverSigned1 (SM-DS Events retrieval)!"); + lpaSetErrorCode(LPA_ERROR_FAILED_INITIAL_AUTHENTICATION); + isDSprocessOK = false; + } + } + + // Step 5: GetEuiccInfo2 (SM-DS operations) + if (isDSprocessOK && _deviceCapabilitiesFilter) // No need to perform it if filtering is disabled + { + if(_lpaManagerGetEuiccInfoWithRetry(GET_EUICC_INFO2_DGI_TAG, &getEuiccInfo)) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Get EUICCInfo2 for SM-DS Events retrieval OK"); + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to get EUICCInfo2 for SM-DS Events retrieval!"); + // Error code lpaSetErrorCode() has to be set by _lpaManagerGetEuiccInfoWithRetry() + isDSprocessOK = false; + } + } + + // Step 6: Get status of flag "deviceInfoExtensibilitySupport" in object "RspCapability" returned in EUICCInfo2 (SM-DS operations) + if (isDSprocessOK && _deviceCapabilitiesFilter) // No need to perform it if filtering is disabled + { + if(_lpaManagerGetFlag_deviceInfoExtensibilitySupport(&getEuiccInfo, &deviceInfoExtensibilitySupport)) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Get status of flag deviceInfoExtensibilitySupport for SM-DS Events retrieval OK"); + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to get status of flag deviceInfoExtensibilitySupport for SM-DS Events retrieval!"); + // Error code lpaSetErrorCode() has to be set by _lpaManagerGetEuiccInfoWithRetry() + isDSprocessOK = false; + } + } + + // Memory cleanup + ERASE_RAWDATAOBJECT(getEuiccInfo.ptrEUICC); + ERASE_RAWDATAOBJECT(getEuiccInfo.prtEUICC_Base64); + + // Step 7: Manage "deviceInformation" "deviceCapabilities" features depending "deviceInfoExtensibilitySupport" flag status and filtering option + // Note: Even if filtering is disabled, this step remain mandatory to get copy of deviceInformation + if(isDSprocessOK) + { + if(_lpaManagerFilterDeviceCapabitilitiesInformation(_deviceInfoByteArray, _deviceInfoByteArraySize, filteredDeviceInfo, &filteredDeviceInfoSize, + sizeof(filteredDeviceInfo), deviceInfoExtensibilitySupport, _deviceCapabilitiesFilter)) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Management of deviceInfomation for SM-DS Events retrieval OK"); + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to manage deviceInformation for SM-DS Events retrieval!"); + // Error code lpaSetErrorCode() has to be set by _lpaManagerFilterDeviceCapabitilitiesInformation() + isDSprocessOK = false; + } + } + + // STEP 8: Perform and check prepareCtxParam (SM-DS operations) + if(isDSprocessOK) + { + if (strlen(_deviceInfo) > 0 && _lpaManagerPrepareCtxParam("", filteredDeviceInfo, filteredDeviceInfoSize, &prepareCtxParam)) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "PrepareCtxParam for SM-DS Events retrieval OK"); + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to prepareCtxParam for SM-DS Events retrieval!"); + lpaSetErrorCode(LPA_ERROR_INVALID_CTX_PARAM); + isDSprocessOK = false; + } + } + + // STEP 9: Perform and check authenticateServer (SM-DS operations) + if(isDSprocessOK) + { + // If GetResponse chaining error, _lpaManagerAuthenticateServer() will return false + if (_lpaManagerAuthenticateServer(&serverData, ptrLpaEventCallback, prepareCtxParam, &ptrAuthServerResp) && ptrAuthServerResp.ptrAuthenticateServerResponse_Base64 != NULL) + { + // No error detected, end execution loop anyway + nbExecGetRespAuthServDS = 0; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "AuthenticateServer for SM-DS Events retrieval OK"); + + if(ptrAuthServerResp.ptrAuthenticateServerResponse_Base64->rawData != NULL ) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "AuthenticateServer for Events retrieval response: %s ", ptrAuthServerResp.ptrAuthenticateServerResponse_Base64->rawData); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "AuthenticateServer for Events retrieval response: No Base64 object available!"); + } + else + { + // Decrease execution loop. If Retry not enabled, will reach 0 so no retry + nbExecGetRespAuthServDS--; + + // Retry management + if(lpaGetErrorCodeNoClear() == SE_MEDIA_E_CHAINING_GET_RESPONSE && LPA_RETRY_CHAINED_GET_RESPONSE_MGT) + { + // If last loop not reached, clear error code to execute another attempt + // Else stay on error SE_MEDIA_E_CHAINING_GET_RESPONSE + if(nbExecGetRespAuthServDS > 0) + { + lpaResetErrorCode(); + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "AuthenticateServer for Events retrieval: GetResponse chaining issue detected, try another time, nbExecGetRespAuthServDS = %d", nbExecGetRespAuthServDS); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "AuthenticateServer for Events retrieval: GetResponse chaining issue detected, no more attempt performed"); + isDSprocessOK = false; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to Authenticate server for SM-DS Events retrieval!"); + lpaSetErrorCode(LPA_ERROR_FAILED_AUTHENTICATE_SERVER); + isDSprocessOK = false; + + nbExecGetRespAuthServDS = 0; // End execution loop, another error encountered + } + } + } + else + nbExecGetRespAuthServDS = 0; // If error other than GetResponse Chaining issue stop execution loop for AuthenticateServer - SM-DS Events retrieval + }// End of execution loop for AuthenticateServer - SM-DS Events retrieval + + // Clear server data but keep transactionID for next steps + _lpaManagerFreeServerData(&serverData, false); + + // Memory cleanup + ERASE_RAWDATAOBJECT(prepareCtxParam); + + // STEP 10: Retrieve Events list (Profile list)serverData._transactionId->rawData + if(isDSprocessOK) + { + if (lpaManagerES9Plus_EventRetrieval((char *)serverData._transactionId->rawData, ptrLpaEventCallback, smdsAddr.address_Data, + ptrAuthServerResp.ptrAuthenticateServerResponse_Base64->rawData, &eventRecordList)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Event(s) retrieval done. SM-DS reported %llu profile(s) to download", (long long unsigned)eventRecordList.countEvent); + + // Notify application owner + if (ptrLpaEventCallback != NULL && ptrLpaEventCallback->_lpaEventProgressText != NULL) + { + snprintf(callbackDisplayBuffer, sizeof(callbackDisplayBuffer), "Event(s) retrieval done. SM-DS reported %llu profile(s) to download", (long long unsigned)eventRecordList.countEvent); + ptrLpaEventCallback->_lpaEventProgressText(ptrLpaEventCallback->_appParameter, 0, callbackDisplayBuffer); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to retrieve event(s) list (Authenticate client)."); + + lpaSetErrorCode(LPA_ERROR_FAILED_AUTHENTICATE_CLIENT); + isDSprocessOK = false; + } + + ERASE_RAWDATAOBJECT(ptrAuthServerResp.ptrAuthenticateServerResponse); + ERASE_RAWDATAOBJECT(ptrAuthServerResp.ptrAuthenticateServerResponse_Base64); + } + + // STEP 11: Process Event list -> Download profile(s) in eUICC if Event list contains elements + if(isDSprocessOK) + { + if (eventRecordList.countEvent > 0) + { + // start to download one by one + size_t i; + + ptrDownloadProfileResult->countProfileTotal = eventRecordList.countEvent; + // Note: Installed profiles counter ptrDownloadProfileResult->countProfileInstalled is managed by _performProfileDownloadFromDefautAddress() + + for (i = 0; i < eventRecordList.countEvent; i++) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "============================================="); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Start to process the Event record #%llu", (long long unsigned)(i + 1)); + + // Notify application owner + if (ptrLpaEventCallback != NULL && ptrLpaEventCallback->_lpaEventProgressText != NULL) + { + snprintf(callbackDisplayBuffer, sizeof(callbackDisplayBuffer),"====== Start to process Event record #%llu ======", (long long unsigned)(i + 1)); + ptrLpaEventCallback->_lpaEventProgressText(ptrLpaEventCallback->_appParameter, 1, callbackDisplayBuffer); + } + + // Management execution / retry loop for GetResponse chained issue + // Here manages issue when occurring at AuthenticateServer + nbExecGetResp = LPA_LOOP_NUMBER_FOR_CHAINED_GET_RESPONSE; + while(nbExecGetResp > 0) + { + // Load profile. If GetResponse chaining issue occur, will also return false + if(_performProfileDownloadFromDefaultAddress(ptrLpaEventCallback, eventRecordList.eventRecordList[i].rspServerAddress, strlen(eventRecordList.eventRecordList[i].rspServerAddress), eventRecordList.eventRecordList[i].eventId, ptrDownloadProfileResult, false, &retryRequested)) + { + // No error detected, end execution loop anyway + nbExecGetResp = 0; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Profile loading is successful."); + } + else + { + // Manage retry from return issued by _performProfileDownloadFromDefaultAddress() + if(retryRequested && LPA_RETRY_CHAINED_GET_RESPONSE_MGT) + { + nbExecGetResp--; + // If last loop not reached, clear error code to execute another attempt + if(nbExecGetResp > 0) + { + lpaResetErrorCode(); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Restart another download attempt from SM-DP for Event record #%llu, nbExecGetResp=%d", (long long unsigned)(i + 1), nbExecGetResp); + + // Notify application owner + if (ptrLpaEventCallback != NULL && ptrLpaEventCallback->_lpaEventProgressText != NULL) + { + snprintf(callbackDisplayBuffer, sizeof(callbackDisplayBuffer), "Restart another download attempt from SM-DP server for Event record #%llu...", (long long unsigned)(i + 1)); + ptrLpaEventCallback->_lpaEventProgressText(ptrLpaEventCallback->_appParameter, 0, callbackDisplayBuffer); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Maximum download attempts reached, do not retry anymore for Event record #%llu", (long long unsigned)(i + 1)); + + // Notify application owner + if (ptrLpaEventCallback != NULL && ptrLpaEventCallback->_lpaEventProgressText != NULL) + { + snprintf(callbackDisplayBuffer, sizeof(callbackDisplayBuffer), "Maximum download attempts reached, do not retry anymore for Event record #%llu", (long long unsigned)(i + 1)); + ptrLpaEventCallback->_lpaEventProgressText(ptrLpaEventCallback->_appParameter, 0, callbackDisplayBuffer); + } + } + + } + else + { + // Issue not caused by GetReponse chaining error (AuthenticateServer) or no management, end execution loop + nbExecGetResp = 0; + + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Profile loading failed."); + } + } + } + + // Management of error code. Need to clear it at each profile download if GetResponse Retry mechanism is enabled + // So keep the first one encountered to deliver it at the end like previously + if(LPA_RETRY_CHAINED_GET_RESPONSE_MGT) + { + if(lpaGetErrorCodeNoClear() != LPA_NO_ERROR && firstEncounteredErrorCode == LPA_NO_ERROR) + { + firstEncounteredErrorCode = lpaGetErrorCodeNoClear(); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerDownloadProfileWithSMDSAddress(): First encountered Error Code while download profiles: 0x%06X", firstEncounteredErrorCode); + } + + lpaResetErrorCode(); + } + } + + // Management of error code if GetResponse Retry mechanism enabled + // If any error encountered while download profiles(s), restore it (First occurrence only) + if(LPA_RETRY_CHAINED_GET_RESPONSE_MGT) + { + if(firstEncounteredErrorCode != LPA_NO_ERROR) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerDownloadProfileWithSMDSAddress(): Restore first Error Code encountered while download profiles: 0x%06X", firstEncounteredErrorCode); + lpaResetErrorCode(); + lpaSetErrorCode(firstEncounteredErrorCode); + } + } + + if (ptrDownloadProfileResult->countProfileInstalled == eventRecordList.countEvent) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "==== All Events (Profiles) defined by SM-DS were successfully loaded in eUICC"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 2, "All Events (Profiles) defined by SM-DS were successfully loaded in eUICC"); + res = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "==== Some issues occurred during Events (Profiles) loading in eUICC"); + _sendEventCallbackProgressText(ptrLpaEventCallback, 2, "Some issues occurred during Events (Profiles) loading in eUICC"); + + // No longer set error when one or more profile(s) failed + res = true; + } + + } + else + { + // No event record => Result OK with empty counters + res = true; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "=== No pending event record!"); + } + } + else + _sendEventCallbackProgressText(ptrLpaEventCallback, 0, "Failed to retrieve Events list from SM-DS"); + + ERASE_RAWDATAOBJECT(ptrAuthServerResp.ptrAuthenticateServerResponse); + ERASE_RAWDATAOBJECT(ptrAuthServerResp.ptrAuthenticateServerResponse_Base64); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + _lpaManagerFreeServerData(&serverData, true); + + // And unregistering LPA_EVENT_EXECUTION_ERROR callback + _unregisterAppEventExecutionCallback(); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaManagerDownloadProfileWithSMDSAddress(...)"); + + return res; +} + +///////////////////////////////////////////// +// Redirection +///////////////////////////////////////////// + +/** + * Set new Nickname field in profile identified by ICCID. + * @param ptrProfileID Profile ICCI size, raw format + * @param profileIdSize Profile ICCID size, size_t + * @param ptrNickname New Nickname to set, raw hex format + * @param nickNameSize New Nickname size, size_t + * @return true is nickname change operation successful + */ +bool lpaManagerSetNickname(const unsigned char* ptrProfileId, size_t profileIdSize, const unsigned char* ptrNickname, size_t nickNameSize) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaManagerSetNickname(...)"); + + bool res = lpaManagerES10c_SetNickname(ptrProfileId, profileIdSize, ptrNickname, nickNameSize); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaManagerSetNickname(...)"); + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +void _registerAppEventExecutionCallback(const LPA_EventCallback* ptrEventCallback) +{ + if (ptrEventCallback != NULL && ptrEventCallback->_lpaEventExecutionError != NULL ) + { + // Registering LPA_EVENT_EXECUTION_ERROR + _appEventExecutionErrorCallback._appParameter = ptrEventCallback->_appParameter; + _appEventExecutionErrorCallback._lpaEventExecutionError = ptrEventCallback->_lpaEventExecutionError; + } +} + +void _unregisterAppEventExecutionCallback() +{ + // Unregistering LPA_EVENT_EXECUTION_ERROR + if (_appEventExecutionErrorCallback._lpaEventExecutionError != NULL) + { + _appEventExecutionErrorCallback._lpaEventExecutionError = NULL; + _appEventExecutionErrorCallback._appParameter = NULL; + } +} + + +void _lpaManagerEventExecutionErrorCallback(const void* ptrAppParameter, const LPA_EVENT_EXECUTION_ERROR_INFO* ptrEventExecutionErrorInfo) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ _lpaManagerEventExecutionErrorCallback(...)"); + + if (_appEventExecutionErrorCallback._lpaEventExecutionError != NULL ) + { + // ptrAppParameter must be NULL if called internally + if (ptrEventExecutionErrorInfo != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "send Event to appEventExecutionErrorCallback..."); + _appEventExecutionErrorCallback._lpaEventExecutionError(_appEventExecutionErrorCallback._appParameter, ptrEventExecutionErrorInfo); + } + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- _lpaManagerEventExecutionErrorCallback(...)"); +} + + +///////////////////////////////////////////// +// Redirection +///////////////////////////////////////////// + +bool lpaManagerSEMediaManagerIsInitialized() +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerSEMediaManagerIsInitialized()"); + + return seMediaManagerIsInitialized(); +} + +///////////////////////////////////////////// +// Redirection +///////////////////////////////////////////// + +bool lpaManagerSEMediaManagerUninitialize() +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerSEMediaManagerUninitialize()"); + + return seMediaManagerUninitialize(); +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + + +bool lpaManagerSEMediaCardReset() +{ + bool reset = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerSEMediaCardReset()"); + + // In first, establish SEMedia + if (!seMediaManagerIsContextEstablished()) + { + if (seMediaManagerEstablishContext()) + { + if (seMediaManagerConnect(_seMediaReaderName)) + reset = seMediaManagerDisconnectWithReset(); + else + lpaSetErrorCode(LPA_ERROR_SE_MEDIA_READER_CONNECTION); + } + else + lpaSetErrorCode(LPA_ERROR_SE_MEDIA_CONTEXT_NOT_ESTABLISHED); + } + else + { + // Manage abnormal use case: context already established + if (isISDRAppletSelected() && !unselectISDRApplet()) + lpaSetErrorCode(LPA_ERROR_SE_MEDIA_UNABLE_TO_UNSELECT_ISDR); + + // If ISDR applet is now unselected, do Disconnect + if (!isISDRAppletSelected()) + { + if (!seMediaManagerIsConnected() && !seMediaManagerConnect(_seMediaReaderName) ) + lpaSetErrorCode(LPA_ERROR_SE_MEDIA_READER_CONNECTION); + + if (seMediaManagerIsConnected()) + reset = seMediaManagerDisconnectWithReset(); + } + } + + if (seMediaManagerIsContextEstablished()) + { + if (!seMediaManagerReleaseContext()) + lpaSetErrorCode(LPA_ERROR_SE_MEDIA_READER_NOT_DISCONNECTED); + } + + return (reset && !lpaIsError()); // Reset must be done without LPA error +} + +////////////////////////////////////////////// +// Manage SEMedia connection and Select ISDR +////////////////////////////////////////////// + +bool lpaManagerConnectReaderAndSelectISDR() +{ + bool res = false; + + if (seMediaManagerIsInitialized()) + { + if (seMediaManagerIsContextEstablished()) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "seMediaManagerIsContextEstablished() = true -> do _lpaManagerUnselectISDRAndDisconnectReader()..."); + lpaManagerUnselectISDRAndDisconnectReader(); + } + + if (!seMediaManagerIsContextEstablished()) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Try to established SEMedia context..."); + + if (seMediaManagerEstablishContext()) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "SEMedia context established => connect reader..."); + if (seMediaManagerConnect(_seMediaReaderName)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Reader connected => select ISDR..."); + res = selectISDRApplet(); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Unable to connect reader!"); + lpaSetErrorCode(LPA_ERROR_SE_MEDIA_READER_CONNECTION); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Unable to establish SEMedia context!"); + lpaSetErrorCode(LPA_ERROR_SE_MEDIA_CONTEXT_NOT_ESTABLISHED); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "SEMedia context not released!"); + lpaSetErrorCode(LPA_ERROR_SE_MEDIA_CONTEXT_NOT_RELEASED); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "SEMedia not initialized!"); + lpaSetErrorCode(LPA_ERROR_SE_MEDIA_NOT_INITIALIZED); + } + + return res; +} + +//////////////////////////////////////////////// +// Unselect ISDR and release SEMedia connection +//////////////////////////////////////////////// + +bool lpaManagerUnselectISDRAndDisconnectReader() +{ + bool res = false; + + if (isISDRAppletSelected()) + { + if (!unselectISDRApplet()) + lpaSetErrorCode(LPA_ERROR_SE_MEDIA_UNABLE_TO_UNSELECT_ISDR); + } + + if (!isISDRAppletSelected() && seMediaManagerIsConnected()) + { + if (!seMediaManagerDisconnect()) + lpaSetErrorCode(LPA_ERROR_SE_MEDIA_READER_NOT_DISCONNECTED); + } + + if (!seMediaManagerIsConnected() && seMediaManagerIsContextEstablished()) + { + if (!seMediaManagerReleaseContext()) + lpaSetErrorCode(LPA_ERROR_SE_MEDIA_READER_NOT_DISCONNECTED); + } + + if (!seMediaManagerIsContextEstablished()) + res = true; + + return res; +} + +///////////////////////////////////////////// +// Redirection +///////////////////////////////////////////// + +bool lpaManagerHttpMediaManagerIsInitialized() +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerHttpMediaManagerIsInitialized()"); + + return httpMediaManagerIsInitialized(); +} + +///////////////////////////////////////////// +// Redirection +///////////////////////////////////////////// + +bool lpaManagerHttpMediaManagerDelete() +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerHttpMediaManagerDelete()"); + + return httpMediaManagerDelete(); +} \ No newline at end of file diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/lpa_manager_api.c b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/lpa_manager_api.c new file mode 100755 index 000000000..43a11f42d --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/lpa_manager_api.c @@ -0,0 +1,678 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + + +#include "lpasdk/core/lpa_manager_api.h" // For main API +#include "lpasdk/core/lpa_manager.h" // For main API + +#include "lpasdk/core/lpa_log.h" +#include "lpasdk/core/semedia_manager.h" + +#include + +// Monitor LPA MANAGER API usage +static size_t _apiUsage = 0; + +#define LPA_MANAGER_API_BEGIN(apiName) { _apiUsage ++ ; assert( _apiUsage == 1); } +#define LPA_MANAGER_API_END() { _apiUsage --; assert( _apiUsage == 0); } + + +// Manage automatic connect/disconnect with reader + select/unselectISDR +bool _lpaManagerApiConnectReaderAndSelectISDR(); +bool _lpaManagerApiUnselectISDRAndDisconnectReader(); + + +//////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////// + +UT_EXPORT_DLL bool lpaManagerApiInitialize(const char* ptrLpaFolder) +{ + LPA_MANAGER_API_BEGIN("lpaManagerApiInitialize"); + bool res = lpaManagerInitialize(ptrLpaFolder); + LPA_MANAGER_API_END(); + + return res; +} + +//////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////// + +UT_EXPORT_DLL bool lpaManagerApiSetConfigParameter(const char* ptrParameterName, LPA_PARAMETER_TYPE parameterType, const void* ptrParameterValue, bool internalCall) +{ + LPA_MANAGER_API_BEGIN("lpaManagerApiSetConfigParameter"); + bool res = lpaManagerSetConfigParameter(ptrParameterName, parameterType, ptrParameterValue, internalCall); + LPA_MANAGER_API_END(); + + return res; +} + +//////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////// + +UT_EXPORT_DLL bool lpaManagerApiGetConfigParameter(const char* ptrParameterName, LPA_PARAMETER_TYPE parameterType, void* ptrParameterValue, size_t parameterValueMaxSize) +{ + LPA_MANAGER_API_BEGIN("lpaManagerApiGetConfigParameter"); + bool res = lpaManagerGetConfigParameter(ptrParameterName, parameterType, ptrParameterValue, parameterValueMaxSize); + LPA_MANAGER_API_END(); + + return res; +} + +//////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////// + +/** + * Check if parameter exists in parameter list, if yes return parameter type. + * If not in Extended Mode and parameter use is restricted, function will return that parameter does not exist. + * + * @param ptrParameterName Pointer on parameter name to check, string type + * @param ptrParameterType Pointer on parameter type to return, LPA_PARAMETER_TYPE type + * @param ptrIsExist Pointer on boolean flag returning if parameter exists, if yes return true + * @return True if no error occurred during check + */ +UT_EXPORT_DLL bool lpaManagerApiIsConfigParameterExist(const char* ptrParameterName, LPA_PARAMETER_TYPE* ptrParameterType, bool* ptrIsExist) +{ + LPA_MANAGER_API_BEGIN("lpaManagerApiIsConfigParameterExist"); + + bool accessRight = false; + bool res = lpaManagerIsConfigParameterExist(ptrParameterName, ptrParameterType, ptrIsExist, &accessRight); + + // Manage AccessRight use case: Extended parameter not authorized in Normal Mode, so invalid parameter existence status + // Note: Do not check ptrParameterType because already done in lpaManagerIsConfigParameterExist() + if (res && (NULL != ptrIsExist) && (true == *ptrIsExist) && (!accessRight)) + { + *ptrIsExist = false; + *ptrParameterType = LPA_PARAMETER_TYPE_UNKNOWN; + } + + LPA_MANAGER_API_END(); + + return res; +} + +//////////////////////////////////////////////////////////// +// Redirection +//////////////////////////////////////////////////////////// + +UT_EXPORT_DLL bool lpaManagerApiGetFullParametersList(LPA_PARAMETERS_LIST * ptrLpaParametersList) +{ + LPA_MANAGER_API_BEGIN("lpaManagerApiGetFullParametersList"); + bool res = lpaManagerGetFullParametersList(ptrLpaParametersList); + LPA_MANAGER_API_END(); + + return res; +} + + +// Reconnect SEMedia +UT_EXPORT_DLL bool lpaManagerApiSEMediaCardReset() +{ + LPA_MANAGER_API_BEGIN("lpaManagerApiSEMediaCardReset"); + bool res = lpaManagerSEMediaCardReset(); + LPA_MANAGER_API_END(); + + return res; +} + + +// Exchange with ISDR applet +UT_EXPORT_DLL bool lpaManagerApiGetReaderList(LPA_SE_MEDIA_READER_NAME_INFO * ptrReaderNameInfoList, size_t readerNameInfoMax, size_t* ptrCountReader) +{ + bool res = false; + + LPA_MANAGER_API_BEGIN("lpaManagerApiGetReaderList"); + // In first, establish SEMedia + if (seMediaManagerIsContextEstablished() || seMediaManagerEstablishContext()) + { + res = lpaManagerGetReaderList(ptrReaderNameInfoList, readerNameInfoMax, ptrCountReader); + } + // At the end, do cleanup + bool resCleanup = seMediaManagerReleaseContext(); + + if (res) // manage error during cleanup + res = resCleanup; + LPA_MANAGER_API_END(); + + return res; +} + +UT_EXPORT_DLL bool lpaManagerApiGetProfilesInfo(LPA_GET_PROFILES_INFO* ptrGetProfilesInfo) +{ + bool res = false; + + LPA_MANAGER_API_BEGIN("lpaManagerApiGetProfilesInfo"); + // In first, connect reader (if not yet connected) and select ISDR (if not yet selected) + if (_lpaManagerApiConnectReaderAndSelectISDR()) + { + res = lpaManagerGetProfilesInfo(ptrGetProfilesInfo); + } + + // At the end, unselect ISDR (if selected) and disconnect reader (if connected) + bool resCleanup = _lpaManagerApiUnselectISDRAndDisconnectReader(); + + if (res) // manage error during cleanup + res = resCleanup; + + LPA_MANAGER_API_END(); + + return res; +} + +UT_EXPORT_DLL bool lpaManagerApiGetProfilesNumber(size_t * ptrNumberOfProfiles) +{ + bool res = false; + + LPA_MANAGER_API_BEGIN("lpaManagerApiGetProfilesNumber"); + // In first, connect reader (if not yet connected) and select ISDR (if not yet selected) + if (_lpaManagerApiConnectReaderAndSelectISDR()) + { + res = lpaManagerGetProfilesNumber(ptrNumberOfProfiles); + } + + // At the end, unselect ISDR (if selected) and disconnect reader (if connected) + bool resCleanup = _lpaManagerApiUnselectISDRAndDisconnectReader(); + + if (res) // manage error during cleanup + res = resCleanup; + + LPA_MANAGER_API_END(); + + return res; +} + +UT_EXPORT_DLL bool lpaManagerApiGetEID(LPA_GET_EID* ptrGetEID) +{ + bool res = false; + + LPA_MANAGER_API_BEGIN("lpaManagerApiGetEID"); + // In first, connect reader (if not yet connected) and select ISDR (if not yet selected) + if (_lpaManagerApiConnectReaderAndSelectISDR()) + { + res = lpaManagerGetEID(ptrGetEID); + } + + // At the end, unselect ISDR (if selected) and disconnect reader (if connected) + bool resCleanup = _lpaManagerApiUnselectISDRAndDisconnectReader(); + + if (res) // manage error during cleanup + res = resCleanup; + + LPA_MANAGER_API_END(); + + return res; +} + +UT_EXPORT_DLL bool lpaManagerApiGetEUICCInfo(LPA_GET_EUICC_INFO* ptrGetEUICCInfo) +{ + bool res = false; + + LPA_MANAGER_API_BEGIN("lpaManagerApiGetEUICCInfo"); + // In first, connect reader (if not yet connected) and select ISDR (if not yet selected) + if (_lpaManagerApiConnectReaderAndSelectISDR()) + { + res = lpaManagerGetEUICCInfo2(ptrGetEUICCInfo); + } + + // At the end, unselect ISDR (if selected) and disconnect reader (if connected) + bool resCleanup = _lpaManagerApiUnselectISDRAndDisconnectReader(); + + if (res) // manage error during cleanup + res = resCleanup; + + LPA_MANAGER_API_END(); + + return res; +} + +UT_EXPORT_DLL bool lpaManagerApiMemoryReset(const unsigned char* ptrMemoryResetOptionParameter, const size_t memoryResetOptionSize) +{ + bool res = false; + + LPA_MANAGER_API_BEGIN("lpaManagerApiMemoryReset"); + // In first, connect reader (if not yet connected) and select ISDR (if not yet selected) + if (_lpaManagerApiConnectReaderAndSelectISDR()) + { + res = lpaManagerMemoryReset(ptrMemoryResetOptionParameter, memoryResetOptionSize); + } + + // At the end, unselect ISDR (if selected) and disconnect reader (if connected) + bool resCleanup = _lpaManagerApiUnselectISDRAndDisconnectReader(); + + if (res) // manage error during cleanup + res = resCleanup; + + LPA_MANAGER_API_END(); + + return res; +} + +UT_EXPORT_DLL bool lpaManagerApiSendPendingNotification(LPA_EventCallback* ptrLpaEventCallback, LPA_SENDING_NOTIFICATION_RESULT* ptrSendingNotificationResult) +{ + bool res = false; + LPA_MANAGER_API_BEGIN("lpaManagerApiSendPendingNotification"); + + // Initialize values in case not already done in calling application, avoid return random values if cannot connect to reader / ISDR and main result not checked + if(ptrSendingNotificationResult != NULL) + { + ptrSendingNotificationResult->countNotificationDetected = 0; + ptrSendingNotificationResult->countNotificationSend = 0; + } + + // In first, connect reader (if not yet connected) and select ISDR (if not yet selected) + if (_lpaManagerApiConnectReaderAndSelectISDR()) + { + res = lpaManagerSendPendingNotification(ptrLpaEventCallback, ptrSendingNotificationResult); + } + // At the end, unselect ISDR (if selected) and disconnect reader (if connected) + bool resCleanup = _lpaManagerApiUnselectISDRAndDisconnectReader(); + + if (res) // manage error during cleanup + res = resCleanup; + + LPA_MANAGER_API_END(); + + return res; +} + + +// Manage Enable/Disable/Delete Profile +UT_EXPORT_DLL bool lpaManagerApiEnableProfileByIccid(const unsigned char* ptrProfileId, size_t profileIdSize) +{ + bool res = false; + + LPA_MANAGER_API_BEGIN("lpaManagerApiEnableProfileByIccid"); + // In first, connect reader (if not yet connected) and select ISDR (if not yet selected) + if (_lpaManagerApiConnectReaderAndSelectISDR()) + { + res = lpaManagerEnableProfileByIccid(ptrProfileId, profileIdSize); + } + // At the end, unselect ISDR (if selected) and disconnect reader (if connected) + bool resCleanup = _lpaManagerApiUnselectISDRAndDisconnectReader(); + + if (res) // manage error during cleanup + res = resCleanup; + LPA_MANAGER_API_END(); + + return res; +} + +UT_EXPORT_DLL bool lpaManagerApiDisableProfileByIccid(const unsigned char* ptrProfileId, size_t profileIdSize) +{ + bool res = false; + + LPA_MANAGER_API_BEGIN("lpaManagerApiDisableProfileByIccid"); + // In first, connect reader (if not yet connected) and select ISDR (if not yet selected) + if (_lpaManagerApiConnectReaderAndSelectISDR()) + { + res = lpaManagerDisableProfileByIccid(ptrProfileId, profileIdSize); + } + // At the end, unselect ISDR (if selected) and disconnect reader (if connected) + bool resCleanup = _lpaManagerApiUnselectISDRAndDisconnectReader(); + + if (res) // manage error during cleanup + res = resCleanup; + LPA_MANAGER_API_END(); + + return res; +} + +UT_EXPORT_DLL bool lpaManagerApiDeleteProfileByIccid(const unsigned char* ptrProfileId, size_t profileIdSize) +{ + bool res = false; + + LPA_MANAGER_API_BEGIN("lpaManagerApiDeleteProfileByIccid"); + // In first, connect reader (if not yet connected) and select ISDR (if not yet selected) + if (_lpaManagerApiConnectReaderAndSelectISDR()) + { + res = lpaManagerDeleteProfileByIccid(ptrProfileId, profileIdSize); + } + // At the end, unselect ISDR (if selected) and disconnect reader (if connected) + bool resCleanup = _lpaManagerApiUnselectISDRAndDisconnectReader(); + + if (res) // manage error during cleanup + res = resCleanup; + LPA_MANAGER_API_END(); + + return res; +} + +// Manage notification list +UT_EXPORT_DLL bool lpaManagerApiGetProfileNotificationList(LPA_PROFILE_NOTIFICATION_LIST* ptrProfileNotificationList) +{ + bool res = false; + + LPA_MANAGER_API_BEGIN("lpaManagerApiGetProfileNotificationList"); + // In first, connect reader (if not yet connected) and select ISDR (if not yet selected) + if (_lpaManagerApiConnectReaderAndSelectISDR()) + { + res = lpaManagerGetProfileNotificationList(ptrProfileNotificationList); + } + // At the end, unselect ISDR (if selected) and disconnect reader (if connected) + bool resCleanup = _lpaManagerApiUnselectISDRAndDisconnectReader(); + LPA_MANAGER_API_END(); + if (res) // manage error during cleanup + res = resCleanup; + + return res; +} + +UT_EXPORT_DLL bool lpaManagerApiClearProfileNotification(uint16_t sequenceNumber) +{ + bool res = false; + LPA_MANAGER_API_BEGIN("lpaManagerApiClearProfileNotification"); + // In first, connect reader (if not yet connected) and select ISDR (if not yet selected) + if (_lpaManagerApiConnectReaderAndSelectISDR()) + { + res = lpaManagerClearProfileNotification(sequenceNumber); + } + // At the end, unselect ISDR (if selected) and disconnect reader (if connected) + bool resCleanup = _lpaManagerApiUnselectISDRAndDisconnectReader(); + LPA_MANAGER_API_END(); + if (res) // manage error during cleanup + res = resCleanup; + + + return res; +} + +UT_EXPORT_DLL bool lpaManagerApiSetDefaultSMDPAddress(const char* ptrSMDPAddr) +{ + bool res = false; + LPA_MANAGER_API_BEGIN("lpaManagerApiSetDefaultSMDPAddress"); + // In first, connect reader (if not yet connected) and select ISDR (if not yet selected) + if (_lpaManagerApiConnectReaderAndSelectISDR()) + { + res = lpaManagerSetDefaultSMDPAddress(ptrSMDPAddr); + } + // At the end, unselect ISDR (if selected) and disconnect reader (if connected) + bool resCleanup = _lpaManagerApiUnselectISDRAndDisconnectReader(); + LPA_MANAGER_API_END(); + if (res) // manage error during cleanup + res = resCleanup; + + return res; +} + +UT_EXPORT_DLL bool lpaManagerApiGetSMDPAddress(ADDRESS_DATA* ptrAddressData) +{ + bool res = false; + + LPA_MANAGER_API_BEGIN("lpaManagerApiGetSMDPAddress"); + // In first, connect reader (if not yet connected) and select ISDR (if not yet selected) + if (_lpaManagerApiConnectReaderAndSelectISDR()) + { + res = lpaManagerGetSMDPAddress(ptrAddressData); + } + // At the end, unselect ISDR (if selected) and disconnect reader (if connected) + bool resCleanup = _lpaManagerApiUnselectISDRAndDisconnectReader(); + LPA_MANAGER_API_END(); + if (res) // manage error during cleanup + res = resCleanup; + + return res; +} +UT_EXPORT_DLL bool lpaManagerApiGetSMDSAddress(ADDRESS_DATA* ptrAddressData) +{ + bool res = false; + + LPA_MANAGER_API_BEGIN("lpaManagerApiGetSMDSAddress"); + // In first, connect reader (if not yet connected) and select ISDR (if not yet selected) + if (_lpaManagerApiConnectReaderAndSelectISDR()) + { + res = lpaManagerGetSMDSAddress(ptrAddressData); + } + // At the end, unselect ISDR (if selected) and disconnect reader (if connected) + bool resCleanup = _lpaManagerApiUnselectISDRAndDisconnectReader(); + LPA_MANAGER_API_END(); + if (res) // manage error during cleanup + res = resCleanup; + return res; +} + +UT_EXPORT_DLL bool lpaManagerApiDownloadProfile(const char * ptrActivationCodeStr, const LPA_EventCallback* ptrLpaEventCallback, LPA_DOWNLOAD_PROFILE_RESULT* ptrDownloadProfileResult) +{ + bool res = false; + + LPA_MANAGER_API_BEGIN("lpaManagerApiDownloadProfile"); + + // Reset DownloadProfileResult if defined + if (ptrDownloadProfileResult != NULL) + { + ptrDownloadProfileResult->countProfileInstalled = 0; + ptrDownloadProfileResult->countProfileTotal = 0; + } + + // In first, connect reader (if not yet connected) and select ISDR (if not yet selected) + if (_lpaManagerApiConnectReaderAndSelectISDR()) + { + res = lpaManagerDownloadProfile(ptrActivationCodeStr, ptrLpaEventCallback, ptrDownloadProfileResult); + } + // At the end, unselect ISDR (if selected) and disconnect reader (if connected) + bool resCleanup = _lpaManagerApiUnselectISDRAndDisconnectReader(); + + if (res) // manage error during cleanup + res = resCleanup; + + LPA_MANAGER_API_END(); + + return res; +} + +UT_EXPORT_DLL bool lpaManagerApiDownloadProfileWithConfirmationCode(const char * ptrActivationCodeStr, const char * ptrConfirmationCodeStr, const LPA_EventCallback* ptrLpaEventCallback, LPA_DOWNLOAD_PROFILE_RESULT* ptrDownloadProfileResult) +{ + bool res = false; + + LPA_MANAGER_API_BEGIN("lpaManagerApiDownloadProfileWithConfirmationCode"); + + // Reset DownloadProfileResult if defined + if (ptrDownloadProfileResult != NULL) + { + ptrDownloadProfileResult->countProfileInstalled = 0; + ptrDownloadProfileResult->countProfileTotal = 0; + } + + // In first, connect reader (if not yet connected) and select ISDR (if not yet selected) + if (_lpaManagerApiConnectReaderAndSelectISDR()) + { + res = lpaManagerDownloadProfileWithConfirmationCode(ptrActivationCodeStr, ptrConfirmationCodeStr, ptrLpaEventCallback, ptrDownloadProfileResult); + } + // At the end, unselect ISDR (if selected) and disconnect reader (if connected) + bool resCleanup = _lpaManagerApiUnselectISDRAndDisconnectReader(); + + if (res) // manage error during cleanup + res = resCleanup; + LPA_MANAGER_API_END(); + + return res; +} + +UT_EXPORT_DLL bool lpaManagerApiDownloadProfileWithDefaultSMDPAddress(const LPA_EventCallback* ptrLpaEventCallback, LPA_DOWNLOAD_PROFILE_RESULT* ptrDownloadProfileResult) +{ + bool res = false; + + LPA_MANAGER_API_BEGIN("lpaManagerApiDownloadProfileWithDefaultSMDPAddress"); + + // Reset DownloadProfileResult if defined + if (ptrDownloadProfileResult != NULL) + { + ptrDownloadProfileResult->countProfileInstalled = 0; + ptrDownloadProfileResult->countProfileTotal = 0; + } + + // In first, connect reader (if not yet connected) and select ISDR (if not yet selected) + if (_lpaManagerApiConnectReaderAndSelectISDR()) + { + res = lpaManagerDownloadProfileWithDefaultSMDPAddress(ptrLpaEventCallback, ptrDownloadProfileResult); + } + // At the end, unselect ISDR (if selected) and disconnect reader (if connected) + bool resCleanup = _lpaManagerApiUnselectISDRAndDisconnectReader(); + + if (res) // manage error during cleanup + res = resCleanup; + LPA_MANAGER_API_END(); + + return res; +} + +UT_EXPORT_DLL bool lpaManagerApiDownloadProfileWithSMDSAddress(const LPA_EventCallback* ptrLpaEventCallback, LPA_DOWNLOAD_PROFILE_RESULT* ptrDownloadProfileResult) +{ + bool res = false; + + LPA_MANAGER_API_BEGIN("lpaManagerApiDownloadProfileWithSMDSAddress"); + + // Reset DownloadProfileResult if defined + if (ptrDownloadProfileResult != NULL) + { + ptrDownloadProfileResult->countProfileInstalled = 0; + ptrDownloadProfileResult->countProfileTotal = 0; + } + + // In first, connect reader (if not yet connected) and select ISDR (if not yet selected) + if (_lpaManagerApiConnectReaderAndSelectISDR()) + { + res = lpaManagerDownloadProfileWithSMDSAddress(ptrLpaEventCallback, ptrDownloadProfileResult); + } + // At the end, unselect ISDR (if selected) and disconnect reader (if connected) + bool resCleanup = _lpaManagerApiUnselectISDRAndDisconnectReader(); + + if (res) // manage error during cleanup + res = resCleanup; + LPA_MANAGER_API_END(); + + return res; +} + + +//////////////////////////////////////////////////////////// +// Redirection +//////////////////////////////////////////////////////////// + +/** + * Set new Nickname field in profile identified by ICCID. + * @param ptrProfileID Profile ICCI size, raw format + * @param profileIdSize Profile ICCID size, size_t + * @param ptrNickname New Nickname to set, raw hex format + * @param nickNameSize New Nickname size, size_t + * @return true is nickname change operation successful + */ +UT_EXPORT_DLL bool lpaManagerApiSetNickname(const unsigned char* ptrProfileId, size_t profileIdSize, const unsigned char* ptrNickname, size_t nickNameSize) +{ + bool res = false; + + LPA_MANAGER_API_BEGIN("lpaManagerApiSetNickname"); + // In first, connect reader (if not yet connected) and select ISDR (if not yet selected) + if (_lpaManagerApiConnectReaderAndSelectISDR()) + { + res = lpaManagerSetNickname(ptrProfileId, profileIdSize, ptrNickname, nickNameSize); + } + + // At the end, unselect ISDR (if selected) and disconnect reader (if connected) + bool resCleanup = _lpaManagerApiUnselectISDRAndDisconnectReader(); + + // manage error during cleanup + if (res) + res = resCleanup; + + LPA_MANAGER_API_END(); + + return res; +} + + +///////////////////////////////////////////// +// Redirection +///////////////////////////////////////////// + +UT_EXPORT_DLL bool lpaManagerApiSEMediaManagerIsInitialized() +{ + LPA_MANAGER_API_BEGIN("lpaManagerApiSEMediaManagerIsInitialized"); + + bool res = lpaManagerSEMediaManagerIsInitialized(); + + LPA_MANAGER_API_END(); + + return res; +} + +///////////////////////////////////////////// +// Redirection +///////////////////////////////////////////// + +UT_EXPORT_DLL bool lpaManagerApiSEMediaManagerUninitialize() +{ + LPA_MANAGER_API_BEGIN("lpaManagerApiSEMediaManagerUninitialize"); + + bool res = lpaManagerSEMediaManagerUninitialize(); + + LPA_MANAGER_API_END(); + + return res; + +} + +///////////////////////////////////////////// +// Redirection +///////////////////////////////////////////// + +UT_EXPORT_DLL bool lpaManagerApiHttpMediaManagerIsInitialized() +{ + LPA_MANAGER_API_BEGIN("lpaManagerApiHttpMediaManagerIsInitialized"); + + bool res = lpaManagerHttpMediaManagerIsInitialized(); + + LPA_MANAGER_API_END(); + + return res; +} + +///////////////////////////////////////////// +// Redirection +///////////////////////////////////////////// + +UT_EXPORT_DLL bool lpaManagerApiHttpMediaManagerDelete() +{ + LPA_MANAGER_API_BEGIN("lpaManagerApiHttpMediaManagerDelete"); + + bool res = lpaManagerHttpMediaManagerDelete(); + + LPA_MANAGER_API_END(); + + return res; +} + +//////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////// + + +bool _lpaManagerApiConnectReaderAndSelectISDR() +{ + return lpaManagerConnectReaderAndSelectISDR(); +} + +bool _lpaManagerApiUnselectISDRAndDisconnectReader() +{ + return lpaManagerUnselectISDRAndDisconnectReader(); +} \ No newline at end of file diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/lpa_manager_es10b.c b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/lpa_manager_es10b.c new file mode 100755 index 000000000..71e97ad3a --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/lpa_manager_es10b.c @@ -0,0 +1,2387 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#include "lpasdk/core/lpa_manager_es10b.h" +#include "lpasdk/core/lpa_manager.h" +#include "lpasdk/core/lpa_manager_helper.h" +#include "lpasdk/core/semedia_manager.h" + +#include "lpasdk/core/lpa_log.h" +#include "lpasdk/core/rawdata_object.h" +#include "lpasdk/core/util.h" +#include "lpasdk/lpasdk_internal_api.h" +#include "lpasdk/core/lpa_memory.h" + + +///////////////////////////////////////////// + +#define LPA_MANAGER_ES10B_DATA_BUFFER_MAX_SIZE MAX_LPA_MANAGER_APDU_BUFFER_SIZE +static unsigned char _dataBuffer[LPA_MANAGER_ES10B_DATA_BUFFER_MAX_SIZE]; + +static char _bufferFormatLogMessage[1024]; // 1Ko is enough (to increase it, use dynamic memory allocation) + + +#define GET_EUICC_CHALLENGE_DGI_TAG 0xBF2E +#define PREPARE_DOWNLOAD_DGI_TAG 0xBF21 +#define AUTH_SERVER_DGI_TAG 0xBF38 +#define CANCEL_SESSION_DGI_TAG 0xBF41 +#define GET_RAT_DGI_TAG 0xBF43 + +bool _prepareDownloadTlv(ptr_serverData p_serverData, const char * ptrStringHashCC, RawDataObject ** ptrPrepareDownloadTlv); +bool _checkBoundProfilePackageMainObjects(ptr_serverData p_serverData); +bool _sendInitalizeSecureChannel(ptr_serverData p_serverData, const BeerTLV* p_berTLV_BF23, PROFILE_INSTALLATION_RESULT *pir, bool * cancelForBPPerrors); +bool _sendConfigureISDP(const BeerTLV* p_berTLV_A0, PROFILE_INSTALLATION_RESULT *pir, bool * cancelForBPPerrors); +bool _sendStoreMetaData(const BeerTLV* p_berTLV_A1, PROFILE_INSTALLATION_RESULT *pir, bool * cancelForBPPerrors); +bool _sendReplaceSessionKey(const BeerTLV* p_berTLV_A2, PROFILE_INSTALLATION_RESULT *pir, bool * cancelForBPPerrors); +bool _loadProfileElements(const BeerTLV* p_berTLV_A3, PROFILE_INSTALLATION_RESULT *pir, bool * cancelForBPPerrors); +bool _sendBoundProfileRawDataOject(RawDataObject* rawDataObj, PROFILE_INSTALLATION_RESULT *pir); +bool _extract_PIRdataFromEUICCresponse(PROFILE_INSTALLATION_RESULT *pir, unsigned char * dataFromEUICC, const size_t dataFromEUICC_size); +bool _prepareAuthenticateServerTlv(ptr_serverData p_serverData, RawDataObject * ptrCtxParam, RawDataObject ** ptrAuthServerTlv); +bool _isPIRContainsSuccessResult(PROFILE_INSTALLATION_RESULT *pir); + +bool _isValidAuthenticateServerResponse(unsigned char * ptrRawData, size_t rawDataSize, size_t maxRawDataSize); +bool _isValidPrepareDownloadResponse(unsigned char * ptrRawData, size_t rawDataSize, size_t maxRawDataSize); +bool _checkAndExtractEuiccChallenge(unsigned char * ptrRawData, size_t rawDataSize, LPA_GET_EUICC* ptrGetEuicc); +bool _extractDataFromSmdpSigned2(unsigned char* ptrSmdpSigned2, size_t smdpSigned2Len, SMDP_SIGNED2_DATA *ptrSmd2Signed2Detail); + +bool _prepareCancelSessionTlv(const char * transactionID, const unsigned int p_reasonCode, RawDataObject** ptrRawDataCancelSessionRequest); +bool _isValidCancelSessionResponse(unsigned char * ptrResponse, size_t rawResponseSize); + +bool _storeHexBase64StructureRawDataPair(RawDataObject ** ptrHexElement, RawDataObject ** ptrBase64Element, const unsigned char * ptrHexData, const size_t hexDataSize, const size_t maxDataSize); + +///////////////////////////////////////////// +// ES10b part +///////////////////////////////////////////// + +bool lpaManagerES10b_PrepareDownload(ptr_serverData p_serverData, const LPA_EventCallback* ptrLpaEventCallback, const char * ptrStringHashCC, PREPARE_DOWNLOAD_RESPONSE* ptrPrepareDownloadResp) +{ + bool res = false, isError = false; + RawDataObject * prepareDownloadTlv = NULL; + + SMDP_SIGNED2_DATA smdpSigned2Detail; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerES10b_PrepareDownload..."); + + if((p_serverData != NULL) && (ptrStringHashCC != NULL) && (ptrPrepareDownloadResp != NULL)) + { + memset(&smdpSigned2Detail, 0x0, sizeof(SMDP_SIGNED2_DATA)); + + if (p_serverData->_smdpSigned2 != NULL) + { + // Check if Confirmation code required by SmdpSigned2 + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Extracting data from SmdpSigned2..."); + + if (_extractDataFromSmdpSigned2(p_serverData->_smdpSigned2->rawData, p_serverData->_smdpSigned2->rawDataSize, &smdpSigned2Detail)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Data extracted from SmdpSigned2"); + + if (smdpSigned2Detail.ptrRawDataObjectTLV_transactionId != NULL) + lpaCoreLogAppendByteArray(SDK_LOG_LEVEL_DEBUG, NULL, "TLV transactionId", smdpSigned2Detail.ptrRawDataObjectTLV_transactionId->rawData, smdpSigned2Detail.ptrRawDataObjectTLV_transactionId->rawDataSize); + + if (smdpSigned2Detail.ptrRawDataObjectTLV_ccRequiredFlag != NULL) + lpaCoreLogAppendByteArray(SDK_LOG_LEVEL_DEBUG, NULL, "TLV ccRequiredFlag", smdpSigned2Detail.ptrRawDataObjectTLV_ccRequiredFlag->rawData, smdpSigned2Detail.ptrRawDataObjectTLV_ccRequiredFlag->rawDataSize); + + if (smdpSigned2Detail.ptrRawDataObjectTLV_bppEuiccOtpk != NULL) + lpaCoreLogAppendByteArray(SDK_LOG_LEVEL_DEBUG, NULL, "TLV bppEuiccOtpk", smdpSigned2Detail.ptrRawDataObjectTLV_bppEuiccOtpk->rawData, smdpSigned2Detail.ptrRawDataObjectTLV_bppEuiccOtpk->rawDataSize); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "unable to extract data from SmdpSigned2!"); + isError = true; + } + + if (!isError && _prepareDownloadTlv(p_serverData, ptrStringHashCC, &prepareDownloadTlv)) + { + if ((prepareDownloadTlv->rawData != NULL) && (prepareDownloadTlv->rawDataSize >0)) + { + uint16_t sw = 0x0000; + size_t dataBufferSize = 0; + if (buildAndSendStoreDataCase4(prepareDownloadTlv, &sw, _dataBuffer, LPA_AUTHENTICATE_SERVER_MAX_SIZE, &dataBufferSize)) + { + // Check 90.00 or 91.xx + if ((sw == 0x9000) || ((sw & 0xFF00) == 0x9100)) + { + // Check if PrepareDownloadResponse contains downloadResponseOk or downloadResponseError + if (_isValidPrepareDownloadResponse(_dataBuffer, dataBufferSize, LPA_AUTHENTICATE_SERVER_MAX_SIZE)) + { + if(_storeHexBase64StructureRawDataPair(&(ptrPrepareDownloadResp->ptrPrepareDownloadResponse), + &(ptrPrepareDownloadResp->ptrPrepareDownloadResponse_Base64), + _dataBuffer, dataBufferSize, LPA_AUTHENTICATE_SERVER_MAX_SIZE)) + res = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "PrepareDownload response does not contain downloadResponseOk!"); + } + else + { + // No or Invalid SW + lpaSetErrorCode(LPA_ERROR_INVALID_SW); + } + } + else + lpaSetErrorCode(LPA_ERROR_INVALID_PREPARE_DOWNLOAD_RESPONSE); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Incorrect prepare download TLV data!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to prepare download TLV!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid server data!"); + + + // Cleanup memory + ERASE_RAWDATAOBJECT(smdpSigned2Detail.ptrRawDataObjectTLV_transactionId); + ERASE_RAWDATAOBJECT(smdpSigned2Detail.ptrRawDataObjectTLV_ccRequiredFlag); + ERASE_RAWDATAOBJECT(smdpSigned2Detail.ptrRawDataObjectTLV_bppEuiccOtpk); + + ERASE_RAWDATAOBJECT(prepareDownloadTlv); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool _extractDataFromSmdpSigned2(unsigned char* ptrSmdpSigned2, size_t smdpSigned2Len, SMDP_SIGNED2_DATA *ptrSmd2Signed2Detail) +{ + bool res = false; + + // SmdpSigned2 :: = SEQUENCE{ + // transactionId[0] TransactionId, --The TransactionID generated by the SM - DP + + // ccRequiredFlag BOOLEAN, --Indicates if the Confirmation Code is required + // bppEuiccOtpk[APPLICATION 73] OCTET STRING OPTIONAL -- otPK.EUICC.ECKA already used for binding the BPP, tag <5F49> + // } + + if (ptrSmdpSigned2 != NULL && smdpSigned2Len > 0 && ptrSmd2Signed2Detail != NULL) + { + BeerTLV *ptrBerTLV30 = NULL; + BerTLVList* ptrTlvList = NULL; + + ptrBerTLV30 = berTLV_extractTagUInt16(0x30, ptrSmdpSigned2, smdpSigned2Len, NULL); + if (ptrBerTLV30 != NULL) + { + uint8_t countTlvFound = 0; + ptrTlvList = berTLV_extractList(ptrBerTLV30->value, ptrBerTLV30->length, &countTlvFound); + if (ptrTlvList != NULL ) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Smdp2 contains %u TLV => extracting data...", countTlvFound); + + if (countTlvFound >= 2 ) + { + BeerTLV *ptrBerTlv_transactionId = NULL, *ptrBerTlv_ccRequiredFlag = NULL, *ptrBerTlv_bppEuiccOtpk = NULL; + BerTLVList* ptrCurrentTlvItem = ptrTlvList; + bool isError = false; + + // Item [0]: transactionId + if (ptrCurrentTlvItem != NULL) + { + if (ptrCurrentTlvItem->berTLV != NULL) + ptrBerTlv_transactionId = ptrCurrentTlvItem->berTLV; + + if (ptrBerTlv_transactionId != NULL) + { + ptrSmd2Signed2Detail->ptrRawDataObjectTLV_transactionId = berTLV_buildRawDataObject(ptrBerTlv_transactionId); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Smdp2 -> transactionId extracted "); + } + else + isError = true; + + ptrCurrentTlvItem = ptrCurrentTlvItem->ptrNext; + } + + // Item [1]: ccRequiredFlag + if (ptrCurrentTlvItem != NULL) + { + if (ptrTlvList->berTLV != NULL) + ptrBerTlv_ccRequiredFlag = ptrCurrentTlvItem->berTLV; + + if (ptrBerTlv_ccRequiredFlag != NULL) + { + ptrSmd2Signed2Detail->ptrRawDataObjectTLV_ccRequiredFlag = berTLV_buildRawDataObject(ptrBerTlv_ccRequiredFlag); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Smdp2 -> ccRequiredFlag extracted "); + } + else + isError = true; + + ptrCurrentTlvItem = ptrCurrentTlvItem->ptrNext; + } + + // Item [2]: bppEuiccOtpk + if (ptrCurrentTlvItem != NULL) + { + if (ptrTlvList->berTLV != NULL) + ptrBerTlv_bppEuiccOtpk = ptrCurrentTlvItem->berTLV; + + if (ptrBerTlv_bppEuiccOtpk != NULL) + { + ptrSmd2Signed2Detail->ptrRawDataObjectTLV_bppEuiccOtpk = berTLV_buildRawDataObject(ptrBerTlv_bppEuiccOtpk); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Smdp2 -> bppEuiccOtpk extracted"); + } + else + isError = true; + + ptrCurrentTlvItem = ptrCurrentTlvItem->ptrNext; + } + + if (!isError) + res = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "one or more TLV missing on SmdpSigned2 item!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Unable to extract TLVs from SmdpSigned2 item!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Unable to extract TLV from SmdpSigned2 item!"); + + // Memory cleanup + ERASE_BERTLV_LIST(ptrTlvList); + ERASE_BERTLV(ptrBerTLV30); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** + * Perform loading of profile in eUICC + * @param p_serverData Pointer on server data, LPA_SERVER_DATA structure. Contain boundProfilePackage, in BerTLVlist format + * @param pir Pointer on PIR data structure + * @param cancelForBPPerrors Pointer on flag informing, if returned true, that CancelSession must be performed due to incorrect boundProfilePackage + * @return true if operations processing is OK + */ +bool lpaManagerES10b_LoadBoundProfilePackage(ptr_serverData p_serverData, PROFILE_INSTALLATION_RESULT *pir, bool * cancelForBPPerrors) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerES10b_LoadBoundProfilePackage..."); + + bool loadProcessOK = true; + bool res = false; + + BerTLVList * berTLVlistBPPdataContainerParser = NULL; + BeerTLV * berTLVlistBPPdataContainerCurrent = NULL; + bool targetTagNotFound = true; + + const uint16_t tagSendingOrder[] = {0xBF23, 0xA0, 0xA1, 0xA2, 0xA3}; // This list ensure to send the different objects in correct order + const size_t TAG_SENDING_ORDER_SIZE = 5; // Size of tagSendingOrder[], keep aligned with it + size_t tagSendingIndex = 0; + uint16_t currentTagUsed = 0; + + if(p_serverData != NULL && pir != NULL && cancelForBPPerrors != NULL) + { + *cancelForBPPerrors = false; + + if (loadProcessOK) + { + // Step 01: Check that boundProfilePackage is available + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Step 01: Check that boundProfilePackage is available"); + if (p_serverData->_boundProfilePackage != NULL && p_serverData->_boundProfilePackageLength > 0 && p_serverData->_boundProfilePackageContainerCount > 0) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "p_serverData->_boundProfilePackage found, %u objects available.", p_serverData->_boundProfilePackageContainerCount); + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "p_serverData->_boundProfilePackage is NULL or empty or no objects count inside!"); + lpaSetErrorCode(LPA_ERROR_FAILED_LOAD_BPP); + loadProcessOK = false; + } + } + + // Step 02: Check Bound Profile package main objects (Unknown / empty tags detection) + if (loadProcessOK) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Step 02: Check Bound Profile Package main objects..."); + + *cancelForBPPerrors = ! _checkBoundProfilePackageMainObjects(p_serverData); + if(*cancelForBPPerrors) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Bound Profile Package main objects checking failed"); + lpaSetErrorCode(LPA_ERROR_INVALID_BPP_DATA); + loadProcessOK = false; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Bound Profile Package main objects checked successfully"); + } + + // Step 03: Parse all objects in boundProfilePackage in the defined order and process related operations + if (loadProcessOK) + { + // Parse all Tags IDs in order defined in tagSendingOrder[] + while((tagSendingIndex < TAG_SENDING_ORDER_SIZE) && loadProcessOK) + { + currentTagUsed = tagSendingOrder[tagSendingIndex]; + + // Search for target Tag in boundProfilePackage + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Step 03: LoadBoundProfilePackage: Currently processing Tag <%X>, searching it in boundProfilePackage objects", currentTagUsed); + targetTagNotFound = true; + berTLVlistBPPdataContainerParser = p_serverData->_boundProfilePackage; + while(berTLVlistBPPdataContainerParser != NULL && targetTagNotFound) + { + berTLVlistBPPdataContainerCurrent = berTLVlistBPPdataContainerParser->berTLV; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, " - Tag found: <%X>", berTLVlistBPPdataContainerCurrent->tag); + // If tag found stop parsing loop + if(berTLVlistBPPdataContainerCurrent->tag == currentTagUsed) + targetTagNotFound = false; + + berTLVlistBPPdataContainerParser = berTLVlistBPPdataContainerParser->ptrNext; + } + + // Check if target Tag found, else stop on error + // Note: Tag "Replace Session Key" is optional, so no error if not found + if((targetTagNotFound || berTLVlistBPPdataContainerCurrent == NULL) && (currentTagUsed != 0xA2)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Tag <%X> not found or invalid TLV format", currentTagUsed); + lpaSetErrorCode(LPA_ERROR_INVALID_BPP_DATA); + loadProcessOK = false; + } + else + { + // Process operation related to current tag used + switch(currentTagUsed) + { + //////// Send Init Secure Channel + case 0xBF23: + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Step 03-%llu: Send Init Secure Channel (Tag )...", (long long unsigned)tagSendingIndex); + if (_sendInitalizeSecureChannel(p_serverData, berTLVlistBPPdataContainerCurrent, pir, cancelForBPPerrors)) + { + if (pir->hasResult) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to send InitializeSecureChannel (PIR has result)"); + lpaSetErrorCode(LPA_ERROR_FAILED_INITIAL_SECURITY_CHANNEL); + loadProcessOK = false; + } + } + else + { + if(*cancelForBPPerrors) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Error detected in tag data object"); + lpaSetErrorCode(LPA_ERROR_INVALID_BPP_DATA); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to send InitializeSecureChannel "); + lpaSetErrorCode(LPA_ERROR_FAILED_INITIAL_SECURITY_CHANNEL); + } + loadProcessOK = false; + } + break; + + //////// Send Configure ISDP + case 0xA0: + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Step 03-%llu: Send Configure ISDP (Tag )...", (long long unsigned)tagSendingIndex); + if (_sendConfigureISDP(berTLVlistBPPdataContainerCurrent, pir, cancelForBPPerrors)) + { + if (pir->hasResult) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to send Configure ISDP (PIR has result)"); + lpaSetErrorCode(LPA_ERROR_FAILED_CONFIGURE_ISDP); + loadProcessOK = false; + } + } + else + { + if(*cancelForBPPerrors) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Error detected in tag data object"); + lpaSetErrorCode(LPA_ERROR_INVALID_BPP_DATA); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to send Configure ISDP "); + lpaSetErrorCode(LPA_ERROR_FAILED_CONFIGURE_ISDP); + } + loadProcessOK = false; + } + break; + + //////// Send Store Metadata + case 0xA1: + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Step 03-%llu: Send Store Metadata (Tag )...", (long long unsigned)tagSendingIndex); + if (_sendStoreMetaData(berTLVlistBPPdataContainerCurrent, pir, cancelForBPPerrors)) + { + if (pir->hasResult) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to send Store Metadata (PIR has result)"); + lpaSetErrorCode(LPA_ERROR_FAILED_STORE_META_DATA); + loadProcessOK = false; + } + } + else + { + if(*cancelForBPPerrors) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Error detected in tag data object"); + lpaSetErrorCode(LPA_ERROR_INVALID_BPP_DATA); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to send Store Metadata"); + lpaSetErrorCode(LPA_ERROR_FAILED_STORE_META_DATA); + } + loadProcessOK = false; + } + break; + + //////// Send replace Session Key + case 0xA2: + // Tag is optional, following condition prevent error if not defined + if(!targetTagNotFound && berTLVlistBPPdataContainerCurrent != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Step 03-%llu: Send replace Session Key (Tag )...", (long long unsigned)tagSendingIndex); + if (_sendReplaceSessionKey(berTLVlistBPPdataContainerCurrent, pir, cancelForBPPerrors)) + { + if (pir->hasResult) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to send replace Session Key (PIR has result)"); + lpaSetErrorCode(LPA_ERROR_FAILED_REPLACE_SESSION_KEY); + loadProcessOK = false; + } + } + else + { + if(*cancelForBPPerrors) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Error detected in tag data object"); + lpaSetErrorCode(LPA_ERROR_INVALID_BPP_DATA); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to send replace Session Key"); + lpaSetErrorCode(LPA_ERROR_FAILED_REPLACE_SESSION_KEY); + } + loadProcessOK = false; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Step 03-%llu: Optional tag (Replace Session Key) not found, skipping it", (long long unsigned)tagSendingIndex); + + break; + + //////// Load Profile elements + case 0xA3: + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Step 03-%llu: load Profile elements (Tag )...", (long long unsigned)tagSendingIndex); + if (_loadProfileElements(berTLVlistBPPdataContainerCurrent, pir, cancelForBPPerrors)) + { + if (!pir->hasResult || pir->ptrProfileInstallationResultTlv == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, " No Profile Installation Result! "); + lpaSetErrorCode(LPA_ERROR_FAILED_LOAD_PROFILE_ELEMENTS); + } + else + { + if (!_isPIRContainsSuccessResult(pir)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to load profile elements (PIR contains error)"); + lpaSetErrorCode(LPA_ERROR_FAILED_LOAD_PROFILE_ELEMENTS); + } + } + } + else + { + if(*cancelForBPPerrors) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Error detected in tag data object"); + lpaSetErrorCode(LPA_ERROR_INVALID_BPP_DATA); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to load profile elements "); + lpaSetErrorCode(LPA_ERROR_FAILED_LOAD_PROFILE_ELEMENTS); + } + loadProcessOK = false; + } + break; + + // Unknown tag (Shall not happen) + default: + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Error unknown Tag <%X> detected in loadBoundProfile process stack. SHALL NOT HAPPEN", currentTagUsed); + lpaSetErrorCode(LPA_ERROR_PROCESSING_ERROR); + loadProcessOK = false; + break; + } + } + + // Go to next Tag + tagSendingIndex++; + + // Reset boundProfilePackage BerTLVlist parsing pointers (No need to free) + berTLVlistBPPdataContainerParser = NULL; + berTLVlistBPPdataContainerCurrent = NULL; + } + } + + if (loadProcessOK) + res = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + return res; +} + +/** + * Check PIR response + * @param pir PIR data structure "PROFILE_INSTALLATION_RESULT" type + * @return True if Successful parsing and "successful result" tag found + */ +bool _isPIRContainsSuccessResult(PROFILE_INSTALLATION_RESULT *pir) +{ + bool isOk = false; + + BeerTLV *ptrBerTLV_BF37 = NULL, *ptrBerTLV_BF27 = NULL; + BerTLVList* ptrBerTlvList = NULL; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_isPIRContainsSuccessResult()"); + + if(pir != NULL) + { + ptrBerTLV_BF37 = berTLV_extractTagUInt16(0xBF37, pir->ptrProfileInstallationResultTlv->rawData, pir->ptrProfileInstallationResultTlv->rawDataSize, NULL); + if (ptrBerTLV_BF37 != NULL && ptrBerTLV_BF37->length > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "BER-TLV present and not empty => Analyze it"); + + ptrBerTLV_BF27 = berTLV_extractTagUInt16(0xBF27, ptrBerTLV_BF37->value, ptrBerTLV_BF37->length, NULL); + if (ptrBerTLV_BF27 != NULL && ptrBerTLV_BF27->length > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "BER-TLV present and not empty => Analyze it"); + + uint8_t countTlvTag = 0; + ptrBerTlvList = berTLV_extractList(ptrBerTLV_BF27->value, ptrBerTLV_BF27->length, &countTlvTag); + if (ptrBerTlvList != NULL && countTlvTag > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "%u BER-TLV objects present inside BER-TLV ", countTlvTag); + + BerTLVList* ptrBerTLVCurrentInsideBF27 = ptrBerTlvList; + BeerTLV* ptrBerTLV_A2 = NULL; + + while (ptrBerTLVCurrentInsideBF27 != NULL) + { + if (ptrBerTLVCurrentInsideBF27->berTLV == NULL) + break; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "TLV tag <%X> present (%lu bytes)", ptrBerTLVCurrentInsideBF27->berTLV->tag, (long unsigned)ptrBerTLVCurrentInsideBF27->berTLV->length); + + if (ptrBerTLVCurrentInsideBF27->berTLV->tag == 0xA2) + { + // Final result tag found :) + ptrBerTLV_A2 = ptrBerTLVCurrentInsideBF27->berTLV; + break; + } + + ptrBerTLVCurrentInsideBF27 = ptrBerTLVCurrentInsideBF27->ptrNext; + } + + if (ptrBerTLV_A2 != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Analyzing 'finalResult' Tag..."); + + // check if (successResultTag) or (errorResultTag) tag present + BeerTLV* ptrBerTLV_A2_A0 = berTLV_extractTagUInt16(0xA0, ptrBerTLV_A2->value, ptrBerTLV_A2->length, NULL); + BeerTLV* ptrBerTLV_A2_A1 = berTLV_extractTagUInt16(0xA1, ptrBerTLV_A2->value, ptrBerTLV_A2->length, NULL); + + if (ptrBerTLV_A2_A0 != NULL || ptrBerTLV_A2_A1 != NULL) + { + if (ptrBerTLV_A2_A0 != NULL) + { + if (formatBytesToHexaString(ptrBerTLV_A2_A0->value, ptrBerTLV_A2_A0->length, _bufferFormatLogMessage, sizeof(_bufferFormatLogMessage)) > 0) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "SuccessResult Tag present (%lu bytes) => %s", (long unsigned)ptrBerTLV_A2_A0->length, _bufferFormatLogMessage); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "SuccessResult Tag present (%lu bytes) => ...", (long unsigned)ptrBerTLV_A2_A0->length); + + isOk = true; + } + + if (ptrBerTLV_A2_A1 != NULL) + { + if (formatBytesToHexaString(ptrBerTLV_A2_A1->value, ptrBerTLV_A2_A1->length, _bufferFormatLogMessage, sizeof(_bufferFormatLogMessage)) > 0) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "ErrorResult Tag present (%lu bytes) => %s", (long unsigned)ptrBerTLV_A2_A1->length, _bufferFormatLogMessage); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "ErrorResult Tag present (%lu bytes) => ...", (long unsigned)ptrBerTLV_A2_A1->length); + } + } + + // Cleanup memory + ERASE_BERTLV(ptrBerTLV_A2_A0); + ERASE_BERTLV(ptrBerTLV_A2_A1); + } + else + { + // We consider that at this level, it is just informative, so set a warning + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "Tag not found or invalid TLV format!"); + } + } + } + } + + // cleanup memory + ERASE_BERTLV(ptrBerTLV_BF27); + ERASE_BERTLV(ptrBerTLV_BF37); + ERASE_BERTLV_LIST(ptrBerTlvList); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_isPIRContainsSuccessResult(): Invalid parameter!"); + + return isOk; +} + + +///////////////////////////////////////////// +// +///////////////////////////////////////////// +bool lpaManagerES10b_GetEuiccChallenge(LPA_GET_EUICC* ptrGetEUICC) +{ + bool res = false; + + size_t dataBufferSize = 0; + uint16_t sw = 0x0000; + RawDataObject* rawDataObjectGetEuiccChallenge = NULL; + + if (ptrGetEUICC != NULL) + { + rawDataObjectGetEuiccChallenge = berTLV_createAndBuildRawDataObject(GET_EUICC_CHALLENGE_DGI_TAG, 0, NULL); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "do buildAndSendStoreDataCase4(GetEuiccChallenge)..."); + if (rawDataObjectGetEuiccChallenge != NULL) + { + if (buildAndSendStoreDataCase4(rawDataObjectGetEuiccChallenge, &sw, _dataBuffer, sizeof(_dataBuffer), &dataBufferSize)) + { + // Check if SW=90.00 or 91.xx + if ((sw == 0x9000) || ((sw & 0xFF00) == 0x9100)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "SW=90.00 => Extracting data"); + + if (dataBufferSize > 0) + { + if (dataBufferSize <= LPA_GET_EUICC_CHALLENGE_MAX_SIZE) + { + if (_checkAndExtractEuiccChallenge(_dataBuffer, dataBufferSize, ptrGetEUICC)) + { + res = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid Raw Data for EuiccChallenge!"); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_UICC_CHALLENGE); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Buffer too small for copying raw data!"); + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + } + else + { + // No data = error too + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "No Raw data available!"); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_UICC_CHALLENGE); + } + } + else + { + // No or Invalid SW + lpaSetErrorCode(LPA_ERROR_INVALID_SW); + } + } + else + { + lpaSetErrorCode(LPA_ERROR_INVALID_GET_UICC_CHALLENGE); + } + + // Do memory cleanup + ERASE_RAWDATAOBJECT(rawDataObjectGetEuiccChallenge); + } + else + { + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + } + else + { + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + return res; +} + + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool lpaManagerES10b_GetEuiccInfo(const unsigned short eUICCinfoTag, LPA_GET_EUICC* ptrGetEUICC) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerES10b_GetEuiccInfo() - Called with tag <%X>", eUICCinfoTag); + + if ((ptrGetEUICC != NULL) && (eUICCinfoTag == GET_EUICC_INFO1_DGI_TAG || eUICCinfoTag == GET_EUICC_INFO2_DGI_TAG)) + { + size_t dataBufferSize = 0; + uint16_t sw = 0x0000; + RawDataObject* ptrRawDataObjectGetEuiccInfo = NULL; + + ptrRawDataObjectGetEuiccInfo = berTLV_createAndBuildRawDataObject(eUICCinfoTag, 0, NULL); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "do buildAndSendStoreDataCase4(GetEuiccInfo)..."); + if (ptrRawDataObjectGetEuiccInfo != NULL) + { + if (buildAndSendStoreDataCase4(ptrRawDataObjectGetEuiccInfo, &sw, _dataBuffer, sizeof(_dataBuffer), &dataBufferSize)) + { + // Check if SW=90.00 or 91.xx + if ((sw == 0x9000) || ((sw & 0xFF00) == 0x9100)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "SW=90.00 => Extracting data"); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Returned EUICCinfo data length: %llu bytes", (long long unsigned)dataBufferSize); + + if (dataBufferSize > 0) // Also tested below, but allow here to produce a specific error if needed + { + if(_storeHexBase64StructureRawDataPair(&(ptrGetEUICC->ptrEUICC), &(ptrGetEUICC->prtEUICC_Base64), _dataBuffer, dataBufferSize, LPA_GET_EUICC_BUFFER_MAX_SIZE)) + res = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "No Raw data available!"); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_EUICC_INFO); + } + } + else + { + // No or Invalid SW + lpaSetErrorCode(LPA_ERROR_INVALID_SW); + } + } + else + { + lpaSetErrorCode(LPA_ERROR_INVALID_GET_EUICC_INFO); + } + + // Do memory cleanup + ERASE_RAWDATAOBJECT(ptrRawDataObjectGetEuiccInfo); + } + else + { + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + } + else + { + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool lpaManagerES10b_AuthenticateServer(ptr_serverData p_serverData, const LPA_EventCallback* ptrLpaEventCallback, RawDataObject * ptrCtxParam, AUTHENTICATE_SERVER_RESPONSE* ptrAuthServerResp) +{ + bool res = false; + + RawDataObject * authServerTlv = NULL; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerES10b_AuthenticateServer()..."); + + if((p_serverData != NULL) && (ptrCtxParam != NULL) && (ptrAuthServerResp != NULL)) + { + if (_prepareAuthenticateServerTlv(p_serverData, ptrCtxParam, &authServerTlv)) + { + if (authServerTlv != NULL) + { + uint16_t sw = 0x0000; + size_t dataBufferSize = 0; + + if (buildAndSendStoreDataCase4(authServerTlv, &sw, _dataBuffer, sizeof(_dataBuffer), &dataBufferSize)) + { + // Check if SW=90.00 or 91.xx + if ((sw == 0x9000) || ((sw & 0xFF00) == 0x9100)) + { + // Check if AuthenticateServerResponse contains authenticateResponseOk or authenticateResponseError + if (_isValidAuthenticateServerResponse(_dataBuffer, dataBufferSize, LPA_AUTHENTICATE_SERVER_MAX_SIZE)) + { + + if(_storeHexBase64StructureRawDataPair(&(ptrAuthServerResp->ptrAuthenticateServerResponse), + &(ptrAuthServerResp->ptrAuthenticateServerResponse_Base64), + _dataBuffer, dataBufferSize, LPA_AUTHENTICATE_SERVER_MAX_SIZE)) + res = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Authenticate server response does not contain authenticateResponseOk!"); + } + else + { + // No or Invalid SW + lpaSetErrorCode(LPA_ERROR_INVALID_SW); + } + } + else + lpaSetErrorCode(LPA_ERROR_INVALID_AUTHENTICATE_SERVER_RESPONSE); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Returned authServerTlv object is void!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to prepareAuthenticateServerTlv!"); + + ERASE_RAWDATAOBJECT(authServerTlv); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + return res; +} + +bool _isValidAuthenticateServerResponse(unsigned char * ptrRawData, size_t rawDataSize, size_t maxRawDataSize) +{ + bool isValid = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_isValidAuthenticateServerResponse()..."); + + if ((ptrRawData != NULL) && (rawDataSize > 0) && (rawDataSize <= maxRawDataSize)) + { + BeerTLV* berTLV_BF38 = berTLV_extractTagUInt16(0xBF38, ptrRawData, rawDataSize, NULL); + if (berTLV_BF38 != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, " tag present "); + + uint8_t countTLVFound = 0; + BerTLVList* BerTLVListInsideBF38 = berTLV_extractList(berTLV_BF38->value, berTLV_BF38->length, &countTLVFound); + + if (BerTLVListInsideBF38 != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "%u tag present inside ", countTLVFound ); + + // Normally only one TLV present + if (countTLVFound == 1) + { + switch (BerTLVListInsideBF38->berTLV->tag) + { + case 0xA1: // authenticateResponseError + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "authenticateResponseError detected"); + break; + + case 0xA0: // authenticateResponseOk + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "authenticateResponseOk detected"); + isValid = true; + break; + + default: + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid authenticateResponse Tag!"); + break; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Only one tag must be present inside !"); + + ERASE_BERTLV_LIST(BerTLVListInsideBF38); + } + ERASE_BERTLV(berTLV_BF38); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Tag not found or invalid TLV format!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter!"); + + return isValid; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool _isValidPrepareDownloadResponse(unsigned char * ptrRawData, size_t rawDataSize, size_t maxRawDataSize) +{ + bool isValid = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_isValidPrepareDownloadResponse()..."); + + if ((ptrRawData != NULL) && (rawDataSize > 0) && (rawDataSize <= maxRawDataSize)) + { + BeerTLV* berTLV_BF21 = berTLV_extractTagUInt16(0xBF21, ptrRawData, rawDataSize, NULL); + if (berTLV_BF21 != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, " tag present "); + + uint8_t countTLVFound = 0; + BerTLVList* BerTLVListInsideBF21 = berTLV_extractList(berTLV_BF21->value, berTLV_BF21->length, &countTLVFound); + + if (BerTLVListInsideBF21 != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "%u tag present inside ", countTLVFound); + + // Normally only one TLV present + if (countTLVFound == 1) + { + switch (BerTLVListInsideBF21->berTLV->tag) + { + case 0xA1: // downloadResponseError + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "downloadResponseError detected"); + break; + + case 0xA0: // downloadResponseOk + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "downloadResponseOk detected"); + isValid = true; + break; + + default: + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid downloadResponse Tag!"); + break; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Only one tag must be present inside !"); + + ERASE_BERTLV_LIST(BerTLVListInsideBF21); + } + ERASE_BERTLV(berTLV_BF21); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Tag not found or invalid TLV format!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter or given data size out of bounds!"); + + return isValid; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool _checkAndExtractEuiccChallenge(unsigned char * ptrRawData, size_t rawDataSize, LPA_GET_EUICC* ptrGetEuicc) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_checkAndExtractEuiccChallenge()..."); + + if (ptrRawData != NULL && rawDataSize > 0 && ptrGetEuicc != NULL) + { + BeerTLV* berTLV_BF2E = NULL; + + berTLV_BF2E = berTLV_extractTagUInt16(0xBF2E, ptrRawData, rawDataSize, NULL); + if (berTLV_BF2E != NULL) + { + snprintf(_bufferFormatLogMessage, sizeof(_bufferFormatLogMessage), "TLV tag <%X> (%lu bytes):", berTLV_BF2E->tag, (long unsigned)berTLV_BF2E->length); + lpaCoreLogAppendByteArray(SDK_LOG_LEVEL_DEBUG, _bufferFormatLogMessage, "TLV", berTLV_BF2E->value, berTLV_BF2E->length); + + bool isTagFound_80 = false; + BeerTLV* berTLV_80 = berTLV_extractTagUInt8(0x80, berTLV_BF2E->value, berTLV_BF2E->length, &isTagFound_80); + if (berTLV_80 != NULL) + { + snprintf(_bufferFormatLogMessage, sizeof(_bufferFormatLogMessage), "TLV tag <%X> (%lu bytes):", berTLV_80->tag, (long unsigned)berTLV_80->length); + lpaCoreLogAppendByteArray(SDK_LOG_LEVEL_DEBUG, _bufferFormatLogMessage, "TLV", berTLV_80->value, berTLV_80->length); + + if(_storeHexBase64StructureRawDataPair(&(ptrGetEuicc->ptrEUICC), &(ptrGetEuicc->prtEUICC_Base64), berTLV_80->value, + berTLV_80->length, LPA_GET_EUICC_CHALLENGE_MAX_SIZE)) + res = true; + + ERASE_BERTLV(berTLV_80); + } + + ERASE_BERTLV(berTLV_BF2E); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Tag not found or invalid TLV format!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter!"); + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool _prepareDownloadTlv(ptr_serverData p_serverData, const char * ptrStringHashCC, RawDataObject ** ptrPrepareDownloadTlv) +{ + bool res = false; + int convLen = 32; + unsigned char TLVConfirmationCodeHash[34]; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_prepareDownloadTlv()..."); + + + // Verify mandatory parameters + if (p_serverData != NULL && p_serverData->_smdpSigned2->rawDataSize > 0 && p_serverData->_smdpSignature2->rawDataSize >0 && p_serverData->_smdpCertificate->rawDataSize > 0 && + ptrStringHashCC != NULL && ptrPrepareDownloadTlv != NULL) + { + // Container for smdpSigned2, smdpSignature2, hashCc and smdpCertificate + bool error = false; + ERASE_RAWDATAOBJECT(*ptrPrepareDownloadTlv); + + RawDataObject* ptrRawData = rawDataObject_allocate(); + if (ptrRawData != NULL) + { + if (!rawDataObject_appendRawDataArray(ptrRawData, p_serverData->_smdpSigned2->rawData, p_serverData->_smdpSigned2->rawDataSize)) + error = true; + + if (!error &&!rawDataObject_appendRawDataArray(ptrRawData, p_serverData->_smdpSignature2->rawData, p_serverData->_smdpSignature2->rawDataSize) ) + error = true; + + if (!error) + { + if(strlen(ptrStringHashCC) == 64) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Confirmation Code Hash with correct length provided, adding hashCc TLV."); + + if(hexStr2ByteArray((unsigned char *)ptrStringHashCC, 64, TLVConfirmationCodeHash + 2, &convLen)) + { + // TLV = 04 20 hash32bytes + TLVConfirmationCodeHash[0] = 0x04; + TLVConfirmationCodeHash[1] = 0x20; + + if(!rawDataObject_appendRawDataArray(ptrRawData, TLVConfirmationCodeHash, 34)) + error = true; + } + else + error = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Confirmation Code Hash empty or incorrect length, hashCc TLV not added."); + } + else + error = true; + + if (!error && !rawDataObject_appendRawDataArray(ptrRawData, p_serverData->_smdpCertificate->rawData, p_serverData->_smdpCertificate->rawDataSize)) + error = true; + + if (!error) + { + if(ptrRawData->rawDataSize < LPA_AUTHENTICATE_SERVER_MAX_SIZE) + { + *ptrPrepareDownloadTlv = berTLV_createAndBuildRawDataObject(PREPARE_DOWNLOAD_DGI_TAG, ptrRawData->rawDataSize, ptrRawData->rawData); + if ((*ptrPrepareDownloadTlv != NULL) && ((*ptrPrepareDownloadTlv)->rawDataSize > 0)) + { + snprintf(_bufferFormatLogMessage, sizeof(_bufferFormatLogMessage), "_prepareDownloadTlv() => request generated (%llu bytes): ...", (long long unsigned) ((*ptrPrepareDownloadTlv)->rawDataSize)); + lpaCoreLogAppendByteArray(SDK_LOG_LEVEL_DEBUG, _bufferFormatLogMessage, "PrepareDownloadRequest", (*ptrPrepareDownloadTlv)->rawData, (*ptrPrepareDownloadTlv)->rawDataSize); + + res = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Unable to allocate ptrPrepareDownloadTlv or incorrect length!"); + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "ptrPrepareDownloadTlv out of bounds: %llu needed, %u max allowed", (long long unsigned)ptrRawData->rawDataSize, LPA_AUTHENTICATE_SERVER_MAX_SIZE - 1); + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Error when updating ptrRawData!"); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Unable to allocate ptrRawData!"); + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + + ERASE_RAWDATAOBJECT(ptrRawData); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter(s)!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_prepareDownloadTlv() return %s", (res ? LPA_RES_TRUE_STRING : LPA_RES_FALSE_STRING)); + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** + * Check if any unknown tag is not defined between the first tag (Tags BF23, A0 to A3) for GCF testing, and if regular tags are not empty + * @param p_berTLV_BF36 Pointer on BERTLV object containing Bound Profile Package + * @return true if checking is successful + */ +bool _checkBoundProfilePackageMainObjects(ptr_serverData p_serverData) +{ + bool res = false; + + BerTLVList * berTLVlistBPPdataContainerParser = NULL; + BeerTLV * berTLVlistBPPdataContainerCurrent = NULL; + + bool objectA3notReached = true; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_checkBoundProfilePackageMainObjects()"); + + if(p_serverData != NULL && p_serverData->_boundProfilePackage != NULL) + { + // At least 4 mandatory objects must be found (BF23, A0, A1 & A3) + if(p_serverData->_boundProfilePackageContainerCount > 3) + { + // Will presume Bound Profile Package is OK. If any error is detected, will be turned to false. + res = true; + + berTLVlistBPPdataContainerParser = p_serverData->_boundProfilePackage; + // Scan all objects, until end reached or (sequenceOf86, payload) found or error detected + while(berTLVlistBPPdataContainerParser != NULL && objectA3notReached && res) + { + berTLVlistBPPdataContainerCurrent = berTLVlistBPPdataContainerParser->berTLV; + + switch(berTLVlistBPPdataContainerCurrent->tag) + { + case 0xBF23: + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Object (InitialiseSecureChannelRequest) found"); + if(berTLVlistBPPdataContainerCurrent->length < 1) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Object empty, canceling download..."); + res = false; + } + break; + + case 0xA0: + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Object (firsSequenceOf87) found"); + if(berTLVlistBPPdataContainerCurrent->length < 2) // At least one segment header + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Object size too small, canceling download..."); + res = false; + } + break; + + case 0xA1: + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Object (SequenceOf88) found"); + if(berTLVlistBPPdataContainerCurrent->length < 2) // At least one segment header + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Object size too small, canceling download..."); + res = false; + } + break; + + case 0xA2: + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Object (secondSequenceOf87) found"); + if(berTLVlistBPPdataContainerCurrent->length < 2) // At least one segment header + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Object size too small, canceling download..."); + res = false; + } + break; + + case 0xA3: + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Object (sequenceOf86) found, do not check for more possible unknown tags in Bound Profile Package"); + objectA3notReached = false; + + if(berTLVlistBPPdataContainerCurrent->length < 2) // At least one segment header + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Object size too small, canceling download..."); + res = false; + } + break; + + default: + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Object with unknown tag <%X> found, canceling download...", berTLVlistBPPdataContainerCurrent->tag); + res = false; + break; + } + + berTLVlistBPPdataContainerParser = berTLVlistBPPdataContainerParser->ptrNext; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Not enough objects found in boundProfilePackage (%u, at least 4 needed)", p_serverData->_boundProfilePackageContainerCount); + + // Remove reference from parsing pointers + berTLVlistBPPdataContainerParser = NULL; + berTLVlistBPPdataContainerCurrent = NULL; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter(s)!"); + + return res; +} + + +/** + * Send boundProfile package header and "Initialize Secure Channel" to eUICC + * @param p_serverData Pointer on LPA_SERVER_DATA structure (For total length of boundProfilePackage) + * @param p_berTLV_BF23 Pointer on BERTLV object + * @param pir Pointer on PIR structure + * @param cancelForBPPerrors Pointer on flag informing, if returned true, that CancelSession must be performed due to incorrect boundProfilePackage + * @return true if operation OK + */ +bool _sendInitalizeSecureChannel(ptr_serverData p_serverData, const BeerTLV* p_berTLV_BF23, PROFILE_INSTALLATION_RESULT *pir, bool * cancelForBPPerrors) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "sendInitalizeSecureChannel()"); + + RawDataObject* rawDataObjectBF36Header = NULL; + RawDataObject* rawDataObjectBF23Data = NULL; + RawDataObject* rawDataObjectInitializeSecureChannel = NULL; + + if((p_serverData != NULL) && (p_berTLV_BF23 != NULL) && (pir != NULL) && (cancelForBPPerrors != NULL)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Re-encoding Tag Length header (To be send to eUICC before sending Initialize Secure Channel)"); + unsigned char BF36Header[20]; + unsigned char lenHexStr[10]; + size_t headsize = 0; + if(encodeLength(p_serverData->_boundProfilePackageLength, lenHexStr, sizeof(lenHexStr), &headsize)) + { + // Better specify this than 0, but I think that length encoding shall be at least 3 bytes (Total size of boundProfilePackage) + if (headsize > 1) + { + BF36Header[0] = 0xBF; + BF36Header[1] = 0x36; + memcpy(BF36Header + 2, lenHexStr, headsize); + headsize += 2; // Include the tag size + rawDataObjectBF36Header = rawDataObject_create(BF36Header, headsize); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Re-encoding of object Length returned too few bytes: %llu", (long long unsigned)headsize); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Re-encoding of object Length - encodeLength() - returned an error!"); + + // Do not continue if BF36 header re-creation failed + if(rawDataObjectBF36Header != NULL) + { + if (p_berTLV_BF23->tag == 0xBF23 && p_berTLV_BF23->length > 0) + { + snprintf(_bufferFormatLogMessage, sizeof(_bufferFormatLogMessage), "Tag value (%lu bytes):", (long unsigned)p_berTLV_BF23->length); + lpaCoreLogAppendByteArray(SDK_LOG_LEVEL_DEBUG, _bufferFormatLogMessage, "", p_berTLV_BF23->value, p_berTLV_BF23->length); + + rawDataObjectBF23Data = berTLV_createAndBuildRawDataObject(p_berTLV_BF23->tag, p_berTLV_BF23->length, p_berTLV_BF23->value); + + if (rawDataObjectBF23Data != NULL) + { + rawDataObjectInitializeSecureChannel = rawDataObject_concat(rawDataObjectBF36Header, rawDataObjectBF23Data); + ERASE_RAWDATAOBJECT(rawDataObjectBF36Header); + ERASE_RAWDATAOBJECT(rawDataObjectBF23Data); + + if (rawDataObjectInitializeSecureChannel != NULL) + { + if (_sendBoundProfileRawDataOject(rawDataObjectInitializeSecureChannel, pir)) + { + res = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to send InitializeSecureChannel"); + + ERASE_RAWDATAOBJECT(rawDataObjectInitializeSecureChannel); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to generate rawDataObjectInitializeSecureChannel!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to generate rawDataObjectBF23Data!"); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Object given is incorrect! (No Tag or empty)"); + // Incorrect data detected, initiate Cancel Session + *cancelForBPPerrors = true; + } + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter(s)!"); + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool _sendBoundProfileRawDataOject(RawDataObject* rawDataObj, PROFILE_INSTALLATION_RESULT *pir) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_sendBoundProfileRawDataOject()"); + + if (rawDataObj != NULL && pir != NULL) + { + //build and send APDU + uint16_t apduSW = 0x0000; + size_t dataBufferSize = 0; + + if (buildAndSendStoreDataCase4(rawDataObj, &apduSW, _dataBuffer, sizeof(_dataBuffer), &dataBufferSize)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Send APDU raw data object success => check APDU response..."); + + // Check SW = 90.00 or 91.xx + if((apduSW == 0x9000) || ((apduSW & 0xFF00) == 0x9100)) + { + if (dataBufferSize == 0) + { + res = true; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Send APDU raw data object success!"); + } + else + { + if(_extract_PIRdataFromEUICCresponse(pir, _dataBuffer, dataBufferSize)) + { + if (_isPIRContainsSuccessResult(pir)) + res = true; + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, " Failed to _sendBoundProfileRawDataOject"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, " Failed to extract / convert PIR data!"); + } + } + else + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_INCORRECT_CARD_RESPONSE); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter(s)!"); + + return res; +} + +/** + * Extract PIR data from eUICC response and store it in PROFILE_INSTALLATION_RESULT structure (HEX and BASE64 format) + * @param pir Structure that will receive PIR, PROFILE_INSTALLATION_RESULT type + * @param dataFromEUICC Data recovered from eUICC + * @param dataFromEUICC_size Data recovered from eUICC size, must be greater than 0 and smaller than LPA_PIR_BUFFER_SIZE + * @return True if extraction and storage is successful + */ +bool _extract_PIRdataFromEUICCresponse(PROFILE_INSTALLATION_RESULT *pir, unsigned char * dataFromEUICC, const size_t dataFromEUICC_size) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_extract_PIRdataFromEUICCresponse()"); + + if((pir != NULL) && (dataFromEUICC != NULL) && (dataFromEUICC_size > 0)) + { + pir->hasResult = false; + + // Other pir structure elements are initialized and filled below + if(_storeHexBase64StructureRawDataPair(&(pir->ptrProfileInstallationResultTlv), &(pir->ptrProfileInstallationResultTlv_Base64), dataFromEUICC, + dataFromEUICC_size, LPA_PIR_BUFFER_MAX_SIZE)) + { + pir->hasResult = true; + res = true; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter(s)!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + return res; +} + + +/** + * Send "Configure ISDP" to eUICC + * @param p_berTLV_A0 Pointer on BERTLV object + * @param pir Pointer on PIR structure + * @param cancelForBPPerrors Pointer on flag informing, if returned true, that CancelSession must be performed due to incorrect boundProfilePackage + * @return true if operation OK + */ +bool _sendConfigureISDP(const BeerTLV* p_berTLV_A0, PROFILE_INSTALLATION_RESULT *pir, bool * cancelForBPPerrors) +{ + bool res = false; + RawDataObject* rawDataObjectConfigureISDP = NULL; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "ConfigureISDP(...)"); + + if((p_berTLV_A0 != NULL) && (pir != NULL) && (cancelForBPPerrors != NULL)) + { + if (p_berTLV_A0->tag == 0xA0 && p_berTLV_A0->length > 0) + { + // Check that object A0 contain a segment <87> like it shall be + if(p_berTLV_A0->value[0] == 0x87) + { + snprintf(_bufferFormatLogMessage, sizeof(_bufferFormatLogMessage), "Tag value (%lu bytes):", (long unsigned)p_berTLV_A0->length); + lpaCoreLogAppendByteArray(SDK_LOG_LEVEL_DEBUG, _bufferFormatLogMessage, "", p_berTLV_A0->value, p_berTLV_A0->length); + + rawDataObjectConfigureISDP = berTLV_createAndBuildRawDataObject(p_berTLV_A0->tag, p_berTLV_A0->length, p_berTLV_A0->value); + if (rawDataObjectConfigureISDP != NULL) + { + if (_sendBoundProfileRawDataOject(rawDataObjectConfigureISDP, pir)) + { + res = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to send Configure ISDP"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to generate rawDataObjectConfigureISDP!"); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "No segment <87> found in TLV object!"); + // Incorrect BPP structure detected, initiate Cancel Session + *cancelForBPPerrors = true; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Object given is incorrect! (No Tag or empty)"); + // Incorrect BPP structure detected, initiate Cancel Session + *cancelForBPPerrors = true; + } + + ERASE_RAWDATAOBJECT(rawDataObjectConfigureISDP); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter(s)!"); + + return res; +} + + +/** + * Send "Store Metadata" to eUICC + * @param p_berTLV_A1 Pointer on BERTLV object + * @param pir Pointer on PIR structure + * @param cancelForBPPerrors Pointer on flag informing, if returned true, that CancelSession must be performed due to incorrect boundProfilePackage + * @return true if operation OK + */ +bool _sendStoreMetaData(const BeerTLV* p_berTLV_A1, PROFILE_INSTALLATION_RESULT *pir, bool * cancelForBPPerrors) +{ + bool res = false; + + BerTLVList* berTLVListInsideA1 = NULL; + RawDataObject* rawDataObjectHeader = NULL; + RawDataObject* rawDataObjectStoreMetaData = NULL; + uint8_t countTLVFoundInsideA1 = 0; + int countTLV88 = 0; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_sendStoreMetaData(...)"); + + if((p_berTLV_A1 != NULL) && (pir != NULL) && (cancelForBPPerrors != NULL)) + { + if (p_berTLV_A1->tag == 0xA1 && p_berTLV_A1->length > 0) + { + snprintf(_bufferFormatLogMessage, sizeof(_bufferFormatLogMessage), "Tag value (%lu bytes):", (long unsigned)p_berTLV_A1->length); + lpaCoreLogAppendByteArray(SDK_LOG_LEVEL_DEBUG, _bufferFormatLogMessage, "", p_berTLV_A1->value, p_berTLV_A1->length); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Re-encoding Tag Length header before sending segments"); + unsigned char A1Header[20]; + unsigned char lenHexStr[10]; + size_t headsize = 0; + if(encodeLength(p_berTLV_A1->length, lenHexStr, sizeof(lenHexStr), &headsize)) + { + // Metadata object can be so small that length can be coded on one byte only + if (headsize > 0) + { + A1Header[0] = 0xA1; + memcpy(A1Header + 1, lenHexStr, headsize); + headsize += 1; // Include the tag size + rawDataObjectHeader = rawDataObject_create(A1Header, headsize); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Re-encoding of object Length returned too few bytes: %llu", (long long unsigned)headsize); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Re-encoding of object Length - encodeLength() - returned an error!"); + + // Do not continue if header re-creation failed + if (rawDataObjectHeader != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Sending header containing sequence of <88> segments..."); + if (_sendBoundProfileRawDataOject(rawDataObjectHeader, pir)) + { + berTLVListInsideA1 = berTLV_extractList(p_berTLV_A1->value, p_berTLV_A1->length, &countTLVFoundInsideA1); + + // Try to found one or more <88> BERTLV objects in BERTLV + if(berTLVListInsideA1 != NULL && countTLVFoundInsideA1 > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "countTLVFoundInsideA1: %u", countTLVFoundInsideA1); + + // Look inside list + BerTLVList* berTLVCurrentInsideA1 = berTLVListInsideA1; + while (berTLVCurrentInsideA1 != NULL) + { + // Check for tag <88>. If yes send segment to eUICC + if (berTLVCurrentInsideA1->berTLV != NULL && berTLVCurrentInsideA1->berTLV->tag == 0x88) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "==============================================="); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Sending Segment <88> >>>> #%d", ++countTLV88); + + res = false; // Reset flag in case one <88> segment already successfully sent + + rawDataObjectStoreMetaData = berTLV_createAndBuildRawDataObject(berTLVCurrentInsideA1->berTLV->tag, berTLVCurrentInsideA1->berTLV->length, berTLVCurrentInsideA1->berTLV->value); + if (rawDataObjectStoreMetaData != NULL) + { + if (_sendBoundProfileRawDataOject(rawDataObjectStoreMetaData, pir)) + { + res = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to send StoreMetaData"); + + // Avoid memory leak in case of failure + ERASE_RAWDATAOBJECT(rawDataObjectStoreMetaData); + + // Any failure to send a segment will stop object parsing, avoid return successful result if sending + // of possible next segment worked without returning any error + break; + } + + // Clear it immediately after use else will create memory leak if multiple segments used + ERASE_RAWDATAOBJECT(rawDataObjectStoreMetaData); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Cannot create RawDataObject for segment <88> sending!"); + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + break; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Unexpected TLV found in TLV ! (NULL or not <88> tag)"); + // Incorrect BPP structure detected, stop segments parsing and initiate Cancel Session + *cancelForBPPerrors = true; + res = false; // If already set to true due to previous segment successfully sent + break; + } + + berTLVCurrentInsideA1 = berTLVCurrentInsideA1->ptrNext; + } // End of while loop for segments ============== + + // In case parsing loop interrupted due to segment data error or sending problem, free pointer before BERTLV list berTLVListInsideA1 cleanup + berTLVCurrentInsideA1 = NULL; + + if(countTLV88 < 1) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Not any TLV <88> segments found in object!"); + // Incorrect BPP structure detected, initiate Cancel Session + *cancelForBPPerrors = true; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Not any TLV segments found in object or failed to create list"); + // Incorrect BPP structure detected, initiate Cancel Session + *cancelForBPPerrors = true; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed send header to eUICC!"); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Object given is incorrect! (No Tag or empty)"); + // Incorrect BPP structure detected, initiate Cancel Session + *cancelForBPPerrors = true; + } + + ERASE_BERTLV_LIST(berTLVListInsideA1); + + ERASE_RAWDATAOBJECT(rawDataObjectStoreMetaData); // Normally useless, but added by security + ERASE_RAWDATAOBJECT(rawDataObjectHeader); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_sendStoreMetaData(): Invalid parameter(s)!"); + + return res; +} + + +/** + * Send "Replace Session Key" to eUICC + * @param p_berTLV_A2 Pointer on BerTLV object + * @param pir Pointer on PIR structure + * @param cancelForBPPerrors Pointer on flag informing, if returned true, that CancelSession must be performed due to incorrect boundProfilePackage + * @return true if operation OK + */ +bool _sendReplaceSessionKey(const BeerTLV* p_berTLV_A2, PROFILE_INSTALLATION_RESULT *pir, bool * cancelForBPPerrors) +{ + bool res = false; + + RawDataObject* rawDataObjectReplaceSessionKey = NULL; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Replace Session Key(...)"); + + if((p_berTLV_A2 != NULL) && (pir != NULL) && (cancelForBPPerrors != NULL)) + { + if (p_berTLV_A2->tag == 0xA2 && p_berTLV_A2->length > 0) + { + // Check that object contain a segment <87> like it shall be + if(p_berTLV_A2->value[0] == 0x87) + { + snprintf(_bufferFormatLogMessage, sizeof(_bufferFormatLogMessage), "Tag value (%lu bytes):", (long unsigned)p_berTLV_A2->length); + lpaCoreLogAppendByteArray(SDK_LOG_LEVEL_DEBUG, _bufferFormatLogMessage, "", p_berTLV_A2->value, p_berTLV_A2->length); + + rawDataObjectReplaceSessionKey = berTLV_createAndBuildRawDataObject(p_berTLV_A2->tag, p_berTLV_A2->length, p_berTLV_A2->value); + if (rawDataObjectReplaceSessionKey != NULL) + { + if (_sendBoundProfileRawDataOject(rawDataObjectReplaceSessionKey, pir)) + { + res = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to send Replace Session Key"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to generate rawDataObjectReplaceSessionKey"); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "No segment <87> found in TLV object!"); + // Incorrect BPP structure detected, initiate Cancel Session + *cancelForBPPerrors = true; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Object given is incorrect! (No Tag or empty)"); + // Incorrect BPP structure detected, initiate Cancel Session + *cancelForBPPerrors = true; + } + + ERASE_RAWDATAOBJECT(rawDataObjectReplaceSessionKey); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter(s)!"); + + return res; +} + + +/** + * Send "Load Profile Elements" to eUICC + * @param p_berTLV_A3 Pointer on BERTLV object + * @param pir Pointer on PIR structure + * @param cancelForBPPerrors Pointer on flag informing, if returned true, that CancelSession must be performed due to incorrect boundProfilePackage + * @return true if operation OK + */ +bool _loadProfileElements(const BeerTLV* p_berTLV_A3, PROFILE_INSTALLATION_RESULT *pir, bool * cancelForBPPerrors) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Load Profile Elements(...)"); + + if ((p_berTLV_A3 != NULL) && (pir !=NULL) && (cancelForBPPerrors != NULL)) + { + RawDataObject* rawDataObjectHeader = NULL; + RawDataObject* rawDataObjectProfileElement = NULL; + + if (p_berTLV_A3->tag == 0xA3 && p_berTLV_A3->length > 0) + { + snprintf(_bufferFormatLogMessage, sizeof(_bufferFormatLogMessage), "Tag value (%lu bytes):", (long unsigned)p_berTLV_A3->length); + lpaCoreLogAppendByteArray(SDK_LOG_LEVEL_DEBUG, _bufferFormatLogMessage, "", p_berTLV_A3->value, p_berTLV_A3->length); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Re-encoding Tag Length header before sending segments"); + unsigned char A3Header[20]; + unsigned char lenHexStr[10]; + size_t headsize = 0; + if(encodeLength(p_berTLV_A3->length, lenHexStr, sizeof(lenHexStr), &headsize)) + { + // Leaved this as initially written, but I think that length encoding shall be at least 3 bytes (Total size of Tag ) + if (headsize > 1) + { + A3Header[0] = 0xA3; + memcpy(A3Header + 1, lenHexStr, headsize); + headsize += 1; // Include the tag size + rawDataObjectHeader = rawDataObject_create(A3Header, headsize); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Re-encoding of object Length returned too few bytes: %llu", (long long unsigned)headsize); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Re-encoding of object Length - encodeLength() - returned an error!"); + + // Do not continue if header re-creation failed + if (rawDataObjectHeader != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Sending header containing sequence of <86> segments..."); + if (_sendBoundProfileRawDataOject(rawDataObjectHeader, pir)) + { + // Memory cleanup + ERASE_RAWDATAOBJECT(rawDataObjectHeader); + + // Read all TLV present inside Tag + uint8_t countTLVFoundInsideA3 = 0; + BerTLVList* ber86TLVList = berTLV_extractList(p_berTLV_A3->value, p_berTLV_A3->length, &countTLVFoundInsideA3); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "countTLVFoundInsideA3: %u", countTLVFoundInsideA3); + int countTLV86 = 0; + + if (ber86TLVList != NULL && countTLVFoundInsideA3 > 0) + { + BerTLVList* berTLVCurrentInside86 = ber86TLVList; + RawDataObject* ptrRawData86 = NULL; + BerTLVList* berTLVNextInside86 = NULL; + + // Turnaround to detect invalid segment before beginning to send segments <86> (Case of Cancel Session not possible after first segment send) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG,"Check segments headers before sending them to eUICC"); + while (berTLVCurrentInside86 != NULL) + { + berTLVNextInside86 = berTLVCurrentInside86->ptrNext; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Checking segment #%d", ++countTLV86); + + if (berTLVCurrentInside86->berTLV == NULL || berTLVCurrentInside86->berTLV->tag != 0x86) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Unexpected TLV found in TLV ! (NULL or not <86> tag)"); + // Incorrect BPP structure detected, stop segment parsing loop and initiate Cancel Session + *cancelForBPPerrors = true; + break; + } + + berTLVCurrentInside86 = berTLVNextInside86; + } + + // Begin to send segment to eUICC after successful segments checking + if(! *cancelForBPPerrors) + { + berTLVCurrentInside86 = ber86TLVList; + berTLVNextInside86 = NULL; + countTLV86 = 0; + + while (berTLVCurrentInside86 != NULL) + { + berTLVNextInside86 = berTLVCurrentInside86->ptrNext; + + if (berTLVCurrentInside86->berTLV != NULL && berTLVCurrentInside86->berTLV->tag == 0x86) + { + ptrRawData86 = berTLV_createAndBuildRawDataObject(berTLVCurrentInside86->berTLV->tag, berTLVCurrentInside86->berTLV->length, berTLVCurrentInside86->berTLV->value); + if (ptrRawData86 != NULL) + { + uint16_t sw = 0x0000; + size_t dataBufferSize = 0; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "==============================================="); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Sending Segment <86> >>>> #%d", ++countTLV86); + if (buildAndSendStoreDataCase4(ptrRawData86, &sw, _dataBuffer, LPA_PIR_BUFFER_MAX_SIZE, &dataBufferSize)) + { + // Check if SW = 90.00 or 91.xx + if ((sw == 0x9000) || ((sw & 0xFF00) == 0x9100)) + { + if (dataBufferSize > 0) + { + if(_extract_PIRdataFromEUICCresponse(pir, _dataBuffer, dataBufferSize)) + { + if (_isPIRContainsSuccessResult(pir)) + res = true; + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to load profile elements!"); + lpaSetErrorCode(LPA_ERROR_FAILED_LOAD_PROFILE_ELEMENTS); + } + } + else + { + // Error code will be set by _extract_ConvertB64_PIRdataFromEUICCresponse() + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, " Failed to extract / convert PIR data!"); + } + + if(pir->hasResult) + { + if (formatBytesToHexaString(pir->ptrProfileInstallationResultTlv->rawData, pir->ptrProfileInstallationResultTlv->rawDataSize, _bufferFormatLogMessage, sizeof(_bufferFormatLogMessage)) > 0) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Profile Installation Result ==> value (%llu bytes) = %s", (long long unsigned)pir->ptrProfileInstallationResultTlv->rawDataSize, _bufferFormatLogMessage); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Profile Installation Result (%llu bytes) = ... ", (long long unsigned)pir->ptrProfileInstallationResultTlv->rawDataSize); + } + + if (countTLV86 != countTLVFoundInsideA3) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Not reach the last segment for loading!"); + break; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "No data response available for this segment..."); + } + else + { + lpaSetErrorCode(LPA_ERROR_INVALID_SW); + break; + } + } + else + { + lpaSetErrorCode(LPA_ERROR_FAILED_LOAD_BPP); + break; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to create Raw Data for Tag <86>!"); + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + break; + } + + ERASE_RAWDATAOBJECT(ptrRawData86); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Unexpected TLV found in TLV ! (NULL or not <86> tag) - SHALL NOT HAPPEN AT THIS STEP"); + // Incorrect BPP structure detected, stop segment parsing loop and initiate Cancel Session + *cancelForBPPerrors = true; + break; + } + + berTLVCurrentInside86 = berTLVNextInside86; + } // End of while loop for segments ============== + } + + // Memory cleanup even if loop terminated in error + ERASE_RAWDATAOBJECT(ptrRawData86); + // Release intermediate pointers from the memory zone they point on + berTLVNextInside86 = NULL; + berTLVCurrentInside86 = NULL; + + if(countTLV86 < 1) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Not any TLV <86> segment found in object!"); + // Incorrect BPP structure detected, initiate Cancel Session + *cancelForBPPerrors = true; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Not any TLV found in object or failed to build list of Tag <86> Segments"); + // Incorrect BPP structure detected, initiate Cancel Session + *cancelForBPPerrors = true; + } + + ERASE_BERTLV_LIST(ber86TLVList); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to send TLV header to eUICC!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to generate rawDataObjectHeader!"); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Object given is incorrect! (No Tag or empty)"); + // Incorrect BPP structure detected, initiate Cancel Session + *cancelForBPPerrors = true; + } + + ERASE_RAWDATAOBJECT(rawDataObjectProfileElement); + ERASE_RAWDATAOBJECT(rawDataObjectHeader); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Load Profile Elements: Invalid parameter(s)!"); + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool _prepareAuthenticateServerTlv(ptr_serverData p_serverData, RawDataObject * ptrCtxParam, RawDataObject ** ptrAuthServerTlv) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_prepareAuthenticateServerTlv()..."); + + // Verify mandatory parameters. For ptrAuthServerTlv a pointer container address must be provided + if (p_serverData != NULL && ptrCtxParam != NULL && ptrAuthServerTlv != NULL && + p_serverData->_serverSigned1 != NULL && p_serverData->_serverSigned1->rawDataSize > 0 && + p_serverData->_serverSignature1 != NULL && p_serverData->_serverSignature1->rawDataSize > 0 && + p_serverData->_euiccCiPKIdToBeUsed != NULL && p_serverData->_euiccCiPKIdToBeUsed->rawDataSize > 0 && + p_serverData->_serverCertificate->rawData != NULL && p_serverData->_serverCertificate->rawDataSize > 0 && + ptrCtxParam->rawData != NULL && ptrCtxParam->rawDataSize > 0 ) + { + bool error = false; + RawDataObject* ptrRawDataAuthenticateServer = NULL; + RawDataObject* ptrRawData = rawDataObject_allocate(); + + if (ptrRawData != NULL) + { + if (!rawDataObject_appendRawDataArray(ptrRawData, p_serverData->_serverSigned1->rawData, p_serverData->_serverSigned1->rawDataSize )) + error = true; + + if (!error &&!rawDataObject_appendRawDataArray(ptrRawData, p_serverData->_serverSignature1->rawData, p_serverData->_serverSignature1->rawDataSize)) + error = true; + + if (!error &&!rawDataObject_appendRawDataArray(ptrRawData, p_serverData->_euiccCiPKIdToBeUsed->rawData, p_serverData->_euiccCiPKIdToBeUsed->rawDataSize)) + error = true; + + if (!error &&!rawDataObject_appendRawDataArray(ptrRawData, p_serverData->_serverCertificate->rawData, p_serverData->_serverCertificate->rawDataSize)) + error = true; + + if (!error &&!rawDataObject_appendRawDataArray(ptrRawData, ptrCtxParam->rawData, ptrCtxParam->rawDataSize)) + error = true; + + if (!error) + { + ptrRawDataAuthenticateServer = berTLV_createAndBuildRawDataObject(AUTH_SERVER_DGI_TAG, ptrRawData->rawDataSize, ptrRawData->rawData); + if (ptrRawDataAuthenticateServer != NULL) + { + // Update structure + if (ptrRawDataAuthenticateServer->rawDataSize <= LPA_AUTHENTICATE_SERVER_MAX_SIZE) + { + ERASE_RAWDATAOBJECT(*ptrAuthServerTlv); + *ptrAuthServerTlv = rawDataObject_create(ptrRawDataAuthenticateServer->rawData, ptrRawDataAuthenticateServer->rawDataSize); + + if(*ptrAuthServerTlv != NULL) + { + snprintf(_bufferFormatLogMessage, sizeof(_bufferFormatLogMessage), "_prepareAuthenticateServerTlv() => request generated (%llu bytes): ...", (long long unsigned)((*ptrAuthServerTlv)->rawDataSize)); + lpaCoreLogAppendByteArray(SDK_LOG_LEVEL_DEBUG, _bufferFormatLogMessage, "AuthenticateServerRequest", (*ptrAuthServerTlv)->rawData, (*ptrAuthServerTlv)->rawDataSize); + + res = true; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "ptrRawDataAuthenticateServer->rawData too small to be updated!"); + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Unable to allocate ptrRawDataAuthenticateServer!"); + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Error when updating ptrRawData!"); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Unable to allocate ptrRawData!"); + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + + // Cleanup memory + if (ptrRawDataAuthenticateServer != NULL) + ERASE_RAWDATAOBJECT(ptrRawDataAuthenticateServer); + + if (ptrRawData != NULL) + ERASE_RAWDATAOBJECT(ptrRawData); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter(s)!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_prepareAuthenticateServerTlv() return %s", (res ? LPA_RES_TRUE_STRING : LPA_RES_FALSE_STRING)); + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** + * Submit Cancel Session request to eUICC and retrieve result + * @param transactionID TransactionID of current server session, string format + * @param p_reasonCode Cancel Reason Code as defined in SGP.22 - Values limited between 0 and 255 + * @param ptrCancelSessionResp Data structure that will receive card response + * @return True if operations OK and cancelResponseOK returned by eUICC + */ +bool lpaManagerES10b_CancelSession(const char * transactionID, const unsigned int p_reasonCode, CANCEL_SESSION_RESPONSE * ptrCancelSessionResp) +{ + bool res = false; + char printBuffer[LPA_CANCEL_SESSION_RESPONSE_BUFFER_SIZE * 2]; + + if((transactionID != NULL) && (ptrCancelSessionResp != NULL) && isElementPresentInArrayUInt(LPA_ALLOWED_CANCEL_SESSION_CODE_LIST, LPA_ALLOWED_CANCEL_SESSION_CODE_LIST_SIZE, p_reasonCode)) + { + RawDataObject* ptrRawDataCancelSessionRequest = NULL; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Cancel Session ES10B..."); + + // Continue if preparation of command request is OK + if(_prepareCancelSessionTlv(transactionID, p_reasonCode, &ptrRawDataCancelSessionRequest) && (ptrRawDataCancelSessionRequest != NULL)) + { + uint16_t sw = 0x0000; + size_t dataBufferSize = 0; + + // Send Request + // _dataBuffer is a global variable of lpa_manager_es10b.c + if (buildAndSendStoreDataCase4(ptrRawDataCancelSessionRequest, &sw, _dataBuffer, sizeof(_dataBuffer), &dataBufferSize)) + { + // Check 90.00 or 91.xx + if ((sw == 0x9000) || ((sw & 0xFF00) == 0x9100)) + { + if ((dataBufferSize > 0) && (dataBufferSize <= LPA_CANCEL_SESSION_RESPONSE_BUFFER_SIZE)) + { + // Save eUICC response in CANCEL_SESSION_RESPONSE ptrCancelSessionResp structure + memcpy(ptrCancelSessionResp->cancelSessionResponse_RawData, _dataBuffer, dataBufferSize); + ptrCancelSessionResp->cancelSessionResponse_RawDataSize = dataBufferSize; + + ptrCancelSessionResp->resultOK = false; + + // Analyze if cancelSessionResponseOk returned by eUICC + if (_isValidCancelSessionResponse(_dataBuffer, dataBufferSize)) + { + ptrCancelSessionResp->resultOK = true; + res = true; + formatBytesToHexaString(ptrCancelSessionResp->cancelSessionResponse_RawData, ptrCancelSessionResp->cancelSessionResponse_RawDataSize, printBuffer, LPA_CANCEL_SESSION_RESPONSE_BUFFER_SIZE * 2); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Cancel Session ES10B: Returned cancelSessionResponse: %s", printBuffer); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Cancel Session ES10B: Did not returned cancelSessionResponseOk."); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Cancel Session ES10B: Response from eUICC out of bounds."); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Cancel Session ES10B: Incorrect status word reported by card: %04X", sw); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Cancel Session ES10B: Failed to execute command request."); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Cancel Session ES10B: Failed to generate command request."); + + ERASE_RAWDATAOBJECT(ptrRawDataCancelSessionRequest); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Cancel Session ES10B: Invalid parameter detected"); + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** + * Builds request for Cancel Session command (TLV object coded in raw format) + * @param transactionID TransactionID of current server session, string format + * @param p_reasonCode Reason Code as defined in SGP.22 - Values limited between 0 and 255 + * @param ptrRawDataCancelSessionRequest Output, will contain request to send to eUICC, RawDataObject format + * @return true if request building ran correctly + */ +bool _prepareCancelSessionTlv(const char * transactionID, const unsigned int p_reasonCode, RawDataObject** ptrRawDataCancelSessionRequest) +{ + bool res = false; + unsigned char tabReasonCode[1] = { 0 }; + unsigned char tabTransactionID[16] = { 0 }; + int convLen = 16; + + // Check input parameters before building + if ((transactionID != NULL) && (strlen(transactionID) > 0) && (strlen(transactionID) < LPA_TRANSACTION_ID_MAX_SIZE) && (p_reasonCode >= 0) && (p_reasonCode < 256) && + (ptrRawDataCancelSessionRequest != NULL)) + { + if (hexStr2ByteArray((unsigned char *)transactionID, 32, tabTransactionID, &convLen) && (convLen == 16)) + { + // Build "Cancel Session" request + RawDataObject* ptrRawDataTransactionID = NULL; + RawDataObject* ptrRawDataReasonCode = NULL; + + // Reminder: Request = BF41 L (80 L transactionID + 81 L reasonCode) + + ptrRawDataTransactionID = berTLV_createAndBuildRawDataObject(0x80, (size_t)16, tabTransactionID); + tabReasonCode[0] = (unsigned char)p_reasonCode; + ptrRawDataReasonCode = berTLV_createAndBuildRawDataObject(0x81, (size_t)1, tabReasonCode); + + if((ptrRawDataTransactionID != NULL) && (ptrRawDataReasonCode != NULL)) + { + RawDataObject* ptrRawDataObjectsConcat = NULL; + + ptrRawDataObjectsConcat = rawDataObject_concat(ptrRawDataTransactionID, ptrRawDataReasonCode); + + if(ptrRawDataObjectsConcat != NULL) + { + *ptrRawDataCancelSessionRequest = berTLV_createAndBuildRawDataObject(CANCEL_SESSION_DGI_TAG, ptrRawDataObjectsConcat->rawDataSize, ptrRawDataObjectsConcat->rawData); + + if(*ptrRawDataCancelSessionRequest != NULL) + res = true; + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_prepareCancelSessionTlv: TLV objects creation step #3 problem"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_prepareCancelSessionTlv: TLV objects creation step #2 problem"); + + ERASE_RAWDATAOBJECT(ptrRawDataObjectsConcat); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_prepareCancelSessionTlv: TLV objects creation step #1 problem"); + + ERASE_RAWDATAOBJECT(ptrRawDataTransactionID); + ERASE_RAWDATAOBJECT(ptrRawDataReasonCode); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_prepareCancelSessionTlv: Cannot convert TransactionID in hex."); + + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_prepareCancelSessionTlv: Invalid TransactionID or reasonCode"); + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** + * Analyzes eUICC data returned after Cancel Session request. Search for cancelSessionResponseOk Object. If found copy it in Cancel Session response storage structure. + * @param ptrRawResponse Response data field returned by card (bytes) + * @param rawResponseSize Response data field returned by card size (bytes number) + * @param ptrCancelSessionResp Pointer on Cancel Session response storage structure (CANCEL_SESSION_RESPONSE type) + * @return true if cancelSessionResponseOk Object detected. + */ +bool _isValidCancelSessionResponse(unsigned char * ptrRawResponse, size_t rawResponseSize) +{ + bool isValid = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_isValidCancelSessionResponse()..."); + + if ((ptrRawResponse != NULL) && (rawResponseSize > 0)) + { + BeerTLV* berTLV_BF41 = berTLV_extractTagUInt16(CANCEL_SESSION_DGI_TAG, ptrRawResponse, rawResponseSize, NULL); + if (berTLV_BF41 != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_isValidCancelSessionResponse: tag present"); + + BeerTLV* berTLV_A0 = berTLV_extractTagUInt8((uint8_t)0xA0, berTLV_BF41->value, berTLV_BF41->length, NULL); + + if (berTLV_A0 != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_isValidCancelSessionResponse: tag present, cancelSessionResponseOk detected."); + + // Confirm cancelSessionResponseOk detected, so response is valid + isValid = true; + + ERASE_BERTLV(berTLV_A0); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_isValidCancelSessionResponse: tag not present or cancelSessionResponseError encountered"); + + ERASE_BERTLV(berTLV_BF41); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_isValidCancelSessionResponse: tag not present"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_isValidCancelSessionResponse: Invalid parameters."); + + return isValid; +} + +/** + * Convert Hex data in Base 64 and store it in Rawdata objects pair, generally stored in data structure. + * Note 1: Zero size objects is considered as an error. + * Note 2: Eventual existing RawData objects will be cleared. + * Note 3: In case of error output RawData will be cleared (So addresses will point on NULL). + * @param ptrHexElement Address of pointer that will receive the RawdataObject who will store HEX version of the data + * @param ptrBase64Element Address of pointer that will receive the RawdataObject who will store BASE64 version of the data + * @param ptrHexData Pointer on HEX data to be stored in RawdataObjec + * @param hexDataSize Size of HEX data to store. Must be > 0 + * @param maxDataSize Maximum size allowed for HEX data given + * @return true if conversion and RawData objects allocation / storage OK (Zero size objects goes on error state) + */ +bool _storeHexBase64StructureRawDataPair(RawDataObject ** ptrHexElement, RawDataObject ** ptrBase64Element, const unsigned char * ptrHexData, const size_t hexDataSize, const size_t maxDataSize) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_storeHexBase64StructureRawDataPair()..."); + + if((ptrHexElement != NULL) && (ptrBase64Element != NULL) && (ptrHexData != NULL)) + { + if(hexDataSize > 0) + { + if(hexDataSize <= maxDataSize) + { + // Reserve 150% greater for Base 64 conversion (Shall be at least 137%) + size_t BASE_64_CONVERSION_BUFFER_SIZE = hexDataSize + (hexDataSize /2) + 1; // Adding one byte for final 0x00 (End of String) + + unsigned char * tmpInfo = lpaCoreMemoryAlloc(BASE_64_CONVERSION_BUFFER_SIZE); + if(tmpInfo != NULL) + { + memset(tmpInfo, 0, BASE_64_CONVERSION_BUFFER_SIZE); + + // Reset objects by security + ERASE_RAWDATAOBJECT(*ptrHexElement); + ERASE_RAWDATAOBJECT(*ptrBase64Element); + + // Create Hex element object + *ptrHexElement = rawDataObject_create(ptrHexData, hexDataSize); + + if(((*ptrHexElement) != NULL) && ((*ptrHexElement)->rawDataSize > 0)) + { + size_t outlen = 0; + if (base64_encode((*ptrHexElement)->rawData, (*ptrHexElement)->rawDataSize, (char *)tmpInfo, &outlen, BASE_64_CONVERSION_BUFFER_SIZE)) + { + // Adding one byte at the end to manage End of String (0x00) + tmpInfo[outlen] = 0x00; + + *ptrBase64Element = rawDataObject_create(tmpInfo, outlen +1 ); + + if(((*ptrBase64Element) != NULL) && ((*ptrBase64Element)->rawDataSize > 0)) + res = true; + else + { + // If Base64 object creation NOK invalidate all objects in data structure + ERASE_RAWDATAOBJECT(*ptrHexElement); + ERASE_RAWDATAOBJECT(*ptrBase64Element); + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to create Raw Data Base64 element!"); + } + } + else + { + // If Base64 conversion NOK invalidate raw object in AUTHENTICATE_SERVER_RESPONSE structure + ERASE_RAWDATAOBJECT(*ptrHexElement); + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Cannot convert hex element in Base 64!"); + } + } + else + { + ERASE_RAWDATAOBJECT(*ptrHexElement); + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to create Raw Data hex element!"); + } + + // Memory cleanup + lpaCoreMemoryFree(tmpInfo); + tmpInfo = NULL; + } + else + { + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Not enough memory for Base 64 conversion buffer!"); + } + } + else + { + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Raw / hex data given size out of bounds: %llu requested, %llu maximum allowed!", (long long unsigned)hexDataSize, (long long unsigned)maxDataSize); + } + } + else + { + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "No raw / hex data available or size <= 0!"); + } + + } + else + { + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid NULL parameter!"); + } + + return res; + } + + + +/** + * Get RAT (Rules Authorization Table) from eUICC + * @param ptrGetRAT - Address of pointer that will receive the RawdataObject who will store RAT value + * @return true if operation is correct + */ +bool lpaManagerES10b_GetRAT(RawDataObject ** ptrGetRAT) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerES10b_GetRAT()..."); + + if (ptrGetRAT != NULL) + { + // Reset object by security + ERASE_RAWDATAOBJECT(*ptrGetRAT); + + size_t dataBufferSize = 0; + uint16_t sw = 0x0000; + RawDataObject* ptrRawDataObjectGetRATrequest = NULL; + + ptrRawDataObjectGetRATrequest = berTLV_createAndBuildRawDataObject(GET_RAT_DGI_TAG, 0, NULL); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Do buildAndSendStoreDataCase4(GetRAT)..."); + if (ptrRawDataObjectGetRATrequest != NULL) + { + if (buildAndSendStoreDataCase4(ptrRawDataObjectGetRATrequest, &sw, _dataBuffer, sizeof(_dataBuffer), &dataBufferSize)) + { + // Check if SW=90.00 or 91.xx + if ((sw == 0x9000) || ((sw & 0xFF00) == 0x9100)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "SW=90.00 or 91.xx => Extracting data"); + + // At least 5 bytes (Tag BF43 + Length + Tag A0 + Length) shall be returned + if (dataBufferSize > 4 && dataBufferSize <= LPA_RAT_MAXIMUM_SIZE) + { + *ptrGetRAT = rawDataObject_create(_dataBuffer, dataBufferSize); + + if(*ptrGetRAT != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "PPR data found, %llu bytes length", (long long unsigned)dataBufferSize); + res = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to create RawDataObject for RAT storage!"); + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "No response data available or response length out of bounds (5 to %u)! Returned size = %llu", LPA_RAT_MAXIMUM_SIZE, (long long unsigned)dataBufferSize); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_RAT); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid response Status Word!"); + lpaSetErrorCode(LPA_ERROR_INVALID_SW); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "GetRAT request execution failed!"); + lpaSetErrorCode(LPA_ERROR_INVALID_GET_RAT); + } + + // Do memory cleanup + ERASE_RAWDATAOBJECT(ptrRawDataObjectGetRATrequest); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to create RawDataObject to build GetRAT request!"); + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid NULL parameter!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerES10b_GetRAT() return %s", (res ? LPA_RES_TRUE_STRING : LPA_RES_FALSE_STRING)); + + return res; +} diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/lpa_manager_es10c.c b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/lpa_manager_es10c.c new file mode 100755 index 000000000..45dada7c4 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/lpa_manager_es10c.c @@ -0,0 +1,1627 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#include "lpasdk/core/lpa_manager_es10c.h" +#include "lpasdk/core/lpa_manager.h" +#include "lpasdk/core/lpa_manager_helper.h" + +#include "lpasdk/core/rawdata_object.h" +#include "lpasdk/core/lpa_log.h" +#include "lpasdk/core/bertlv_object.h" +#include "lpasdk/lpasdk_internal_api.h" +#include "lpasdk/core/util.h" +#include "lpasdk/core/lpa_memory.h" + +///////////////////////////////////////////// + +#define LPA_MANAGER_ES10C_DATA_BUFFER_MAX_SIZE MAX_LPA_MANAGER_APDU_BUFFER_SIZE +static unsigned char _dataBuffer[LPA_MANAGER_ES10C_DATA_BUFFER_MAX_SIZE]; + +#define PROFILE_ICCID_TAG 0x5A +#define PROFILE_NICKNAME_TAG 0x90 + +#define GET_PROFILE_INFO_DGI_TAG 0xBF2D +#define GET_EID_DGI_TAG 0xBF3E +#define MEMORY_RESET_TAG 0xBF34 + +#define ENABLE_PROFILE_DGI_TAG 0xBF31 +#define DISABLE_PROFILE_DGI_TAG 0xBF32 +#define DELETE_PROFILE_DGI_TAG 0xBF33 + +#define SET_NICKNAME_TAG 0xBF29 + +#define DER_ATTRIBUTE_TAG 0x80 + +#define MEMORY_RESET_OPTION_SIZE 0x02 + +#define TEMP_BUFFER_SIZE_FOR_PROFILES_COUNT 768 // Temporary buffer size for request "GetProfilesInfo ICCID only". Should never need to be changed, very large. + +static const unsigned char PROFILE_INFO_LIST_ICCID_ONLY_REQUEST [] = {0x5C, 0x01, 0x5A}; +static const unsigned char PROFILE_INFO_FOR_PPR_MGT_REQUEST [] = {0x5C, 0x05 , 0x5A, 0x9F, 0x70, 0x95, 0x99}; +static const unsigned char PROFILE_INFO_LIST_HOST_APPLICATION_REQUEST [] = {0x5C, 0x0A, 0x5A, 0x9F, 0x70, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x99}; + +typedef enum +{ + enableProfile = ENABLE_PROFILE_DGI_TAG, + disableProfile = DISABLE_PROFILE_DGI_TAG, + deleteProfile = DELETE_PROFILE_DGI_TAG +}PROFILE_OPERATION; + +static const unsigned char GET_EID_OPTION_PARAMETER [] = { 0x5C, 0x01, 0x5A }; + +static char _bufferFormatLogMessage[1024]; // 1Ko is enough for logging message +static bool _refreshFlagActivated = true; + +///////////////////////////////////////////// + +bool _extractDataFromGetProfileInfoRawData(LPA_GET_PROFILES_INFO* ptrLpaGetProfileInfoAll, unsigned char* rawData, size_t rawDataSize, bool fillFrofileFields, bool requestForPPRmanagement); +bool _updateProfileInfoFromBerTLV(unsigned char* ptrLpaProfileInfo, BeerTLV* ptrBerTLV, bool requestForPPRmanagement); +bool _doProfileOperationByIccid(PROFILE_OPERATION profileOperation, const unsigned char* profileId, size_t profileIdSize); +LPA_MEMORY_RESET_STATUS _doExtractMemoryResetResponse(const unsigned char *ptrData, size_t dataSize); + +bool _extractResponseForEnableProfileOperation(const unsigned char *ptrData, size_t dataSize); +bool _extractResponseForDisableProfileOperation(const unsigned char *ptrData, size_t dataSize); +bool _extractResponseForDeleteProfileOperation(const unsigned char *ptrData, size_t dataSize); +bool _doExtractEIDResponse(const unsigned char *ptrData, size_t dataSize, LPA_GET_EID* ptrGetEID); + +bool _extractResponseForSetNicknameOperation(const unsigned char *ptrData, size_t dataSize); + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +void lpaManagerES10c_SetRefreshFlag(bool refreshFlagActivated) +{ + _refreshFlagActivated = refreshFlagActivated; +} + +bool lpaManagerES10c_IsRefreshFlag() +{ + return _refreshFlagActivated; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** + * Perform ES10C GetProfilesInfo request and fill LPA_GET_PROFILES_INFO structure with profiles informations returned by eUICC + * @param ptrLpaGetProfilesInfo Pointer on LPA_GET_PROFILES_INFO structure to fill with profiles informations + * @param continueRetry Pointer of flag informing if retry can be performed again, true = yes (Manage case when failed to retrieve number of profiles due to Chained GetResponse issue) + * @param requestForPPRmanagement If set to "true" request will be performed for PPR management (Different profiles structure, find number of profiles, memory allocation) + * @return true if operation is successful + */ +bool lpaManagerES10c_GetProfilesInfo(LPA_GET_PROFILES_INFO* ptrLpaGetProfilesInfo, bool * continueRetry, bool requestForPPRmanagement) +{ + bool res = false; + bool resCount = false; + size_t numberOfProfilesOnEUICC = 0; + size_t fullProfileInfoBufferSize = 0; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaManagerES10c_GetProfilesInfo(...)"); + + // profileInfoList storage area must have been initialized, and maxNumberProfileInfo must define at least one profile + if(ptrLpaGetProfilesInfo != NULL && continueRetry != NULL && + ((ptrLpaGetProfilesInfo->profileInfoList != NULL && ptrLpaGetProfilesInfo->maxNumberProfileInfo > 0) || requestForPPRmanagement)) + { + // Avoid potential problems of initialization, if forget to be done in caller + ptrLpaGetProfilesInfo->countProfileInfo = 0; + ptrLpaGetProfilesInfo->numberProfileInfoFound = 0; + + // Management of profile-info list depending PPR management of not + if(requestForPPRmanagement) + { + // De-allocate profile-info list if used for PPR management (Bad parameter or retry for chained GetResponse issues) + if(ptrLpaGetProfilesInfo->profileInfoList != NULL) + lpaCoreMemoryFree(ptrLpaGetProfilesInfo->profileInfoList); + } + else + { + // Reset profile info list + memset(ptrLpaGetProfilesInfo->profileInfoList, 0, (ptrLpaGetProfilesInfo->maxNumberProfileInfo * sizeof(LPA_PROFILE_INFO))); + } + + // Retrieve number of profiles stored in card, to set request response buffer size. + // Note: Use entry point in lpa_manager instead of one in lpa_manager_es10c to get benefit of retry mechanism set for this command (Chained GetResponse issue) + resCount = lpaManagerGetProfilesNumber(&numberOfProfilesOnEUICC); + + // Invalidate retry in case failed to retrieve number of profiles due to Chained GetResponse error permanent issue, in that case inform caller to give up performing request. + if(lpaGetErrorCodeNoClear() == SE_MEDIA_E_CHAINING_GET_RESPONSE) + *continueRetry = false; + else + *continueRetry = true; + + // If failed to retrieve number of profiles stored in card, exit on error + // If failed on retry for lpaManagerES10c_GetProfilesNumber(), resCount will be false anyway. + if(resCount) + { + // If no profiles found on card, it is useless to perform request + if(numberOfProfilesOnEUICC > 0) + { + + // If request for PPR management, set maximum of profiles and Allocate memory for profile info list + if(requestForPPRmanagement) + { + ptrLpaGetProfilesInfo->maxNumberProfileInfo = numberOfProfilesOnEUICC; + ptrLpaGetProfilesInfo->profileInfoList = lpaCoreMemoryAlloc(numberOfProfilesOnEUICC * sizeof(LPA_PROFILE_INFO_FOR_PPR)); + + // Memory allocation success => Initialize memory area else exit with error + if(ptrLpaGetProfilesInfo->profileInfoList != NULL) + { + memset(ptrLpaGetProfilesInfo->profileInfoList, 0, (numberOfProfilesOnEUICC * sizeof(LPA_PROFILE_INFO_FOR_PPR))); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Cannot allocate memory area for profileInfoList data! (PPR management) Needed %llu bytes", (long long unsigned)(numberOfProfilesOnEUICC * sizeof(LPA_PROFILE_INFO_FOR_PPR))); + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + return res; + } + } + + // Full GetProfileInfo size = Header / (9 bytes + 1 security) + (number of profiles found in card x Size of Retrievable profiles) + if(requestForPPRmanagement) + fullProfileInfoBufferSize = 10 + (numberOfProfilesOnEUICC * LPA_PROFILE_INFO_BUFFER_MAX_SIZE_FOR_PPR); + else + fullProfileInfoBufferSize = 10 + (numberOfProfilesOnEUICC * LPA_PROFILE_INFO_BUFFER_MAX_SIZE); + + unsigned char * fullProfileInfoBuffer = lpaCoreMemoryAlloc(fullProfileInfoBufferSize); + + // Cannot allocate buffer for GetProfileInfoResponse => exit with error + if(fullProfileInfoBuffer == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Cannot allocate response buffer for GetProfileInfo eUICC response! Needed %llu bytes", (long long unsigned)fullProfileInfoBufferSize); + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + + // Avoid possible memory leak + if(requestForPPRmanagement && ptrLpaGetProfilesInfo->profileInfoList != NULL) + lpaCoreMemoryFree(ptrLpaGetProfilesInfo->profileInfoList); + + return res; + } + + size_t dataBufferSize = 0; + uint16_t sw = 0x0000; + RawDataObject* rawDataObjectGetProfilesInfo = NULL; + + // Build request depending normal request or for PPR management + if(requestForPPRmanagement) + { + // For PPR request, specify defined list of tags defined in PROFILE_INFO_FOR_PPR_TAG_LIST + rawDataObjectGetProfilesInfo = berTLV_createAndBuildRawDataObject(GET_PROFILE_INFO_DGI_TAG, sizeof(PROFILE_INFO_FOR_PPR_MGT_REQUEST), PROFILE_INFO_FOR_PPR_MGT_REQUEST); + } + else + { + // Empty request for normal profile info request + rawDataObjectGetProfilesInfo = berTLV_createAndBuildRawDataObject(GET_PROFILE_INFO_DGI_TAG, sizeof(PROFILE_INFO_LIST_HOST_APPLICATION_REQUEST), PROFILE_INFO_LIST_HOST_APPLICATION_REQUEST); + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "do buildAndSendStoreDataCase4(GetProfilesInfo)..."); + if (rawDataObjectGetProfilesInfo != NULL) + { + if (buildAndSendStoreDataCase4(rawDataObjectGetProfilesInfo, &sw, fullProfileInfoBuffer, fullProfileInfoBufferSize, &dataBufferSize)) + { + // Check if SW=90.00 or 91.xx + if ((sw == 0x9000) || ((sw & 0xFF00) == 0x9100)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "SW=90.00 or 91.xx => Extracting data"); + + if (dataBufferSize > 0) + { + // Extract data, recover and fill profiles fields required + if(_extractDataFromGetProfileInfoRawData(ptrLpaGetProfilesInfo, fullProfileInfoBuffer, dataBufferSize, true, requestForPPRmanagement)) + res = true; + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Profile data extraction cannot be performed!"); + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_UNABLE_TO_EXTRACT_DATA); + } + } + else + { + // No data = error, card shall return at least a response + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "No Raw data available!"); + } + } + else + { + // No or Invalid SW + lpaSetErrorCode(LPA_ERROR_INVALID_SW); + } + } + else + { + lpaSetErrorCode(LPA_ERROR_INVALID_GET_PROFILES_INFO_EXCHANGE); + } + } + else + { + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + + // Do memory cleanup + ERASE_RAWDATAOBJECT(rawDataObjectGetProfilesInfo); + lpaCoreMemoryFree(fullProfileInfoBuffer); + fullProfileInfoBuffer = NULL; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "No profiles found in card. GetProfileInfo \"Full Profile\" request is bypassed"); + res = true; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to retrieve number of profiles stored in card! GetProfileInfo aborted."); + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_UNABLE_TO_EXTRACT_DATA); + } + } + else + { + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaManagerES10c_GetProfilesInfo(...)"); + + return res; +} + + +/** + * Uses ES10C GetProfilesInfo request to retrieve number of profiles available on eUICC + * @param ptrLpaGetProfilesInfo Pointer on variable were number of profile will be returned, size_t type + * @return true if operation is successful + */ +bool lpaManagerES10c_GetProfilesNumber(size_t * ptrNumberOfProfiles) +{ + bool res = false; + LPA_GET_PROFILES_INFO tempLpaGetProfilesInfo; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaManagerES10c_GetProfilesNumber(...)"); + + if (ptrNumberOfProfiles != NULL) + { + // Reset profiles number value if not already done by caller + *ptrNumberOfProfiles = 0; + + // Temporary buffer for GetProfileInfo request + unsigned char * requestResponseBuffer = lpaCoreMemoryAlloc(TEMP_BUFFER_SIZE_FOR_PROFILES_COUNT); + + // Cannot allocate response buffer for GetProfileIno request => exit with error + if(requestResponseBuffer == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Cannot allocate response buffer for GetProfileNumber eUICC response! Needed %u bytes", TEMP_BUFFER_SIZE_FOR_PROFILES_COUNT); + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + return res; + } + + // Temporary profile info structure initialization + tempLpaGetProfilesInfo.countProfileInfo = 0; // No real function here + tempLpaGetProfilesInfo.maxNumberProfileInfo = 0; // No real function here + tempLpaGetProfilesInfo.numberProfileInfoFound = 0; + // Here we do not want to fill profiles fields, just count profiles so profileInfoList data area pointer is set to NULL + tempLpaGetProfilesInfo.profileInfoList = NULL; + + size_t dataBufferSize = 0; + uint16_t sw = 0x0000; + RawDataObject* rawDataObjectGetProfilesInfo = NULL; + + // Build request, only ICCID tags required + rawDataObjectGetProfilesInfo = berTLV_createAndBuildRawDataObject(GET_PROFILE_INFO_DGI_TAG, sizeof(PROFILE_INFO_LIST_ICCID_ONLY_REQUEST), PROFILE_INFO_LIST_ICCID_ONLY_REQUEST); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "do buildAndSendStoreDataCase4(GetProfilesNumber)..."); + if (rawDataObjectGetProfilesInfo != NULL) + { + if (buildAndSendStoreDataCase4(rawDataObjectGetProfilesInfo, &sw, requestResponseBuffer, TEMP_BUFFER_SIZE_FOR_PROFILES_COUNT, &dataBufferSize)) + { + // Check if SW=90.00 or 91.xx + if ((sw == 0x9000) || ((sw & 0xFF00) == 0x9100)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "SW=90.00 or 91.xx => Extracting data"); + + if (dataBufferSize > 0) + { + // Extract data, do not require to recover profiles fields, not a PPR request + if(_extractDataFromGetProfileInfoRawData(&tempLpaGetProfilesInfo, requestResponseBuffer, dataBufferSize, false, false)) + { + // Return number of profiles effectively found + *ptrNumberOfProfiles = tempLpaGetProfilesInfo.numberProfileInfoFound; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerES10c_GetProfilesNumber: Found %llu profile(s)", (long long unsigned)(*ptrNumberOfProfiles)); + + res = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Profile data extraction cannot be performed!"); + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_UNABLE_TO_EXTRACT_DATA); + } + } + else + { + // No data = error, card shall return at least a response + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "No Raw data available!"); + } + } + else + { + // No or Invalid SW + lpaSetErrorCode(LPA_ERROR_INVALID_SW); + } + } + else + { + lpaSetErrorCode(LPA_ERROR_INVALID_GET_PROFILES_INFO_EXCHANGE); + } + } + else + { + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + + // Do memory cleanup + ERASE_RAWDATAOBJECT(rawDataObjectGetProfilesInfo); + lpaCoreMemoryFree(requestResponseBuffer); + requestResponseBuffer = NULL; + } + else + { + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaManagerES10c_GetProfilesNumber() return %s", (res ? "true" : "false")); + + return res; +} + + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool lpaManagerES10c_GetEID(LPA_GET_EID* ptrGetEID) +{ + bool res = false; + + if (ptrGetEID != NULL) + { + // Reset Raw Data size + ptrGetEID->EID_DataSize = 0; + + size_t dataBufferSize = 0; + uint16_t sw = 0x0000; + RawDataObject* rawDataObjectGetEID = NULL; + + // Select done correctly + rawDataObjectGetEID = berTLV_createAndBuildRawDataObject(GET_EID_DGI_TAG, sizeof(GET_EID_OPTION_PARAMETER), GET_EID_OPTION_PARAMETER); + if (rawDataObjectGetEID != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "do buildAndSendStoreDataCase4(GetEID)..."); + if (buildAndSendStoreDataCase4(rawDataObjectGetEID, &sw, _dataBuffer, sizeof(_dataBuffer), &dataBufferSize)) + { + // Check if SW=90.00 or 91.xx + if ((sw == 0x9000) || ((sw & 0xFF00) == 0x9100)) + { + res = true; // By default no error but if error detected => reset it to false + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "SW=90.00 or 91.xx => Extracting data"); + + if (dataBufferSize > 0) + { + res = _doExtractEIDResponse(_dataBuffer, dataBufferSize, ptrGetEID); + } + else + { + // No error SW, but no data :( + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "No Raw data available!"); + } + } + else + { + // No or Invalid SW + lpaSetErrorCode(LPA_ERROR_INVALID_SW); + } + + // + if (lpaIsError()) + res = false; + } + else + { + lpaSetErrorCode(LPA_ERROR_INVALID_GET_EID_EXCHANGE); + } + } + else + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + + // Do memory cleanup + ERASE_RAWDATAOBJECT(rawDataObjectGetEID); + } + else + { + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool lpaManagerES10c_MemoryReset(const unsigned char* memoryResetOptionParameter, const size_t memoryResetOptionSize) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaManagerES10c_MemoryReset(...)"); + + if((memoryResetOptionParameter != NULL) && (memoryResetOptionSize == MEMORY_RESET_OPTION_SIZE)) + { + RawDataObject* rawDataMemoryResetRequest = NULL; + RawDataObject* rawDataMemoryResetParameterTag = NULL; + + // create reset request + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Creating rawDataMemoryResetParameterTag object..."); + + rawDataMemoryResetParameterTag = berTLV_createAndBuildRawDataObject(0x82, memoryResetOptionSize, memoryResetOptionParameter); + if (rawDataMemoryResetParameterTag != NULL) + { + rawDataMemoryResetRequest = berTLV_createAndBuildRawDataObject(MEMORY_RESET_TAG, rawDataMemoryResetParameterTag->rawDataSize, rawDataMemoryResetParameterTag->rawData); + } + + if (rawDataMemoryResetRequest != NULL) + { + // build and Send APDU + uint16_t apduSW = 0x0000; + size_t dataBufferSize = 0; + + if (buildAndSendStoreDataCase4(rawDataMemoryResetRequest, &apduSW, _dataBuffer, sizeof(_dataBuffer), &dataBufferSize)) + { + // Check if SW = 90.00 or 91.xx (STK refresh or other) + if((apduSW == 0x9000) || ((apduSW & 0xFF00) == 0x9100)) + { + // APDU successfully sent + if (dataBufferSize == 0) + { + res = true; // no data + } + else + { + // Check APDU response data + LPA_MEMORY_RESET_STATUS memoryResetStatus = _doExtractMemoryResetResponse(_dataBuffer, dataBufferSize); + switch (memoryResetStatus) + { + case LPA_MEMORY_RESET_OK: + res = true; + break; + + case LPA_MEMORY_RESET_NOTHING_TO_DELETE: + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_NOTHING_TO_DELETE); + break; + + case LPA_MEMORY_RESET_CAT_BUSY: + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_CAT_BUSY); + break; + + case LPA_MEMORY_RESET_UNDEFINED_ERROR: + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_UNDEFINED_ERROR); + break; + + default: + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_UNKNOWN_ERROR); + break; + } + } + } + else + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_INCORRECT_CARD_RESPONSE); + } + else + { + lpaSetErrorCode(LPA_ERROR_INVALID_MEMORY_RESET_EXCHANGE); + } + } + else + { + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + + // Do memory cleanup + ERASE_RAWDATAOBJECT(rawDataMemoryResetParameterTag); + ERASE_RAWDATAOBJECT(rawDataMemoryResetRequest); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaManagerES10c_MemoryReset() return %s", (res ? "true" : "false")); + } + else + { + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool lpaManagerES10c_EnableProfileByIccid(const unsigned char* ptrProfileId, size_t profileIdSize) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaManagerES10c_EnableProfileByIccid(...)"); + + res = _doProfileOperationByIccid(enableProfile, ptrProfileId, profileIdSize); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaManagerES10c_EnableProfileByIccid() return %s", (res ? "true" : "false")); + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool lpaManagerES10c_DisableProfileByIccid(const unsigned char* ptrProfileId, size_t profileIdSize) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaManagerES10c_DisableProfileByIccid(...)"); + + res = _doProfileOperationByIccid(disableProfile, ptrProfileId, profileIdSize); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaManagerES10c_DisableProfileByIccid() return %s", (res ? "true" : "false")); + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool lpaManagerES10c_DeleteProfileByIccid(const unsigned char* ptrProfileId, size_t profileIdSize) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaManagerES10c_DeleteProfileByIccid(...)"); + + res = _doProfileOperationByIccid(deleteProfile, ptrProfileId, profileIdSize); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaManagerES10c_DeleteProfileByIccid() return %s", (res ? "true" : "false")); + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** + * Store profiles information from GetProfilesInfo returned by eUICC in LPA_GET_PROFILES_INFO data structure + * @param ptrLpaGetProfileInfoAll Pointer on LPA_GET_PROFILES_INFO structure to fill with profiles informations + * @param rawData Pointer on GetProfilesInfo response returned by eUICC + * @param rawDataSize Size of GetProfilesInfo response returned by eUICC + * @param fillFrofileFields It true, will fill ptrLpaGetProfileInfoAll->profileInfoList data area with profile fields, else will only count profiles + * @param requestForPPRmanagement If set to "true" request will be performed for PPR management (Different profiles structure) + * @return true if operation is successful + */ +bool _extractDataFromGetProfileInfoRawData(LPA_GET_PROFILES_INFO* ptrLpaGetProfileInfoAll, unsigned char* rawData, size_t rawDataSize, bool fillFrofileFields, bool requestForPPRmanagement) +{ + bool res = false; + + BeerTLV* berTLV_BF2D = NULL; + unsigned long profileAccessOffset = 0; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_extractDataFromGetProfileInfoRawData()"); + + if((ptrLpaGetProfileInfoAll != NULL) && (rawData != NULL) && (rawDataSize > 0)) + { + berTLV_BF2D = berTLV_extractTagUInt16(0xBF2D, rawData, rawDataSize, NULL); + if (berTLV_BF2D != NULL) + { + lpaCoreLogAppendByteArray(SDK_LOG_LEVEL_DEBUG, "Tag found", "berTLV_BF2D", berTLV_BF2D->value, berTLV_BF2D->length); + + BeerTLV* berTLV_A0 = berTLV_extractTagUInt8(0xA0, berTLV_BF2D->value, berTLV_BF2D->length, NULL); + + if (berTLV_A0 != NULL) + { + // Finding tag is the minimum to consider that there is a valid response + res = true; + + uint8_t countTLVFoundInsideA0 = 0; + + lpaCoreLogAppendByteArray(SDK_LOG_LEVEL_DEBUG, "Tag found", "berTLV_A0", berTLV_A0->value, berTLV_A0->length); + + BerTLVList* berTLVListInsideA0 = berTLV_extractList(berTLV_A0->value, berTLV_A0->length, &countTLVFoundInsideA0); + if (berTLVListInsideA0 != NULL) + { + if (countTLVFoundInsideA0 > 0) + { + BerTLVList* berTLVCurrentInsideA0 = berTLVListInsideA0; + while (berTLVCurrentInsideA0 != NULL) + { + BerTLVList* berTLVNextInsideA0 = berTLVCurrentInsideA0->ptrNext; + if (berTLVCurrentInsideA0->berTLV != NULL && berTLVCurrentInsideA0->berTLV->tag == 0xE3) + { + // Tag found :) + BeerTLV* berTLV_E3 = berTLVCurrentInsideA0->berTLV; + + lpaCoreLogAppendByteArray(SDK_LOG_LEVEL_DEBUG, "Tag found", "berTLV_E3", berTLV_E3->value, berTLV_E3->length); + + // Fill profiles field area only if required, else will only count profiles + if(fillFrofileFields) + { + if (ptrLpaGetProfileInfoAll->countProfileInfo < ptrLpaGetProfileInfoAll->maxNumberProfileInfo) + { + // Calculate offset in profileInfoList from profileInfoList base, profile# and LPA_PROFILE_INFO size, depending normal or PPR request + if(requestForPPRmanagement) + profileAccessOffset = ptrLpaGetProfileInfoAll->countProfileInfo * sizeof(LPA_PROFILE_INFO_FOR_PPR); + else + profileAccessOffset = ptrLpaGetProfileInfoAll->countProfileInfo * sizeof(LPA_PROFILE_INFO); + + if(! _updateProfileInfoFromBerTLV((unsigned char *)(ptrLpaGetProfileInfoAll->profileInfoList + profileAccessOffset), berTLV_E3, requestForPPRmanagement)) + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid data detected for profile #%llu!", (long long unsigned)ptrLpaGetProfileInfoAll->countProfileInfo); + + ptrLpaGetProfileInfoAll->countProfileInfo++; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "WARNING: Number of profiles found (%llu) exceeds maximum allowed (%llu)! Profile not stored.", (long long unsigned)(ptrLpaGetProfileInfoAll->numberProfileInfoFound + 1), (long long unsigned)ptrLpaGetProfileInfoAll->maxNumberProfileInfo); + } + + ptrLpaGetProfileInfoAll->numberProfileInfoFound++; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Current BERTLV NULL or not Tag , jumping on next"); + + berTLVCurrentInsideA0 = berTLVNextInsideA0; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "TLV count inside tag <= 0!"); + + ERASE_BERTLV_LIST(berTLVListInsideA0); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "No BERTLV inside tag !"); + + ERASE_BERTLV(berTLV_A0); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Tag not found or invalid TLV format!"); + + ERASE_BERTLV(berTLV_BF2D); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Tag not found or invalid TLV format!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter(s)!"); + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** + * Extract profile informations from profile data bloc (BERTLV from eUICC) and store them in profile information list + * @param ptrLpaProfileInfo Profile location in profile information list (pointer) + * @param ptrBerTLV Data bloc containing BERTLV profile information, BeerTLV type + * @param requestForPPRmanagement If set to "true" request will be performed for PPR management (Different profiles structure) + * @return true if profile extraction is successful (Can extract BerTLVList from ptrBerTLV) + */ +bool _updateProfileInfoFromBerTLV(unsigned char* ptrLpaProfileInfo, BeerTLV* ptrBerTLV, bool requestForPPRmanagement) +{ + bool res = false; + + if((ptrLpaProfileInfo != NULL) && (ptrBerTLV != NULL)) + { + // Set structure type depending type of request used (Normal or for PPR management + // Note: Both structures are declared on same pointer source. Avoid warnings / errors for structure elements matching check at compiling. + LPA_PROFILE_INFO* ptrNormalProfileInfoAccess = (LPA_PROFILE_INFO *)ptrLpaProfileInfo; + LPA_PROFILE_INFO_FOR_PPR* ptrPPRprofileInfoAccess = (LPA_PROFILE_INFO_FOR_PPR *)ptrLpaProfileInfo; + + // Reset profile structure depending type of request effectively asked (Use correct size) + if(requestForPPRmanagement) + memset(ptrPPRprofileInfoAccess, 0x00, sizeof(LPA_PROFILE_INFO_FOR_PPR)); + else + memset(ptrNormalProfileInfoAccess, 0x00, sizeof(LPA_PROFILE_INFO)); + + // Copy Raw Data (If not for PPR management). If exceeds maximum size limit or returned profile raw data = NULL, exit with error state + if(! requestForPPRmanagement) + { + if (ptrBerTLV->length <= LPA_PROFILE_INFO_BUFFER_MAX_SIZE && ptrBerTLV->value != NULL) + { + memcpy(ptrNormalProfileInfoAccess->rawData, ptrBerTLV->value, ptrBerTLV->length); + ptrNormalProfileInfoAccess->rawDataSize = ptrBerTLV->length; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_updateProfileInfoFromBerTLV() - Profile raw data size too big (%lu vs %u max) or profile raw data = NULL!", (long unsigned)ptrBerTLV->length, LPA_PROFILE_INFO_BUFFER_MAX_SIZE); + return res; + } + } + + // Read all TLV present inside Tag + uint8_t countTLVFound = 0; + BerTLVList* berTLVList = berTLV_extractList(ptrBerTLV->value, ptrBerTLV->length, &countTLVFound); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "countTLVFound: %u", countTLVFound); + if (berTLVList != NULL) + { + // At this step we consider that we have a possible valid structure. + // No more control is done on elements considering they are all declared "Optional" in SGP.22 + res = true; + + BerTLVList* berTLVCurrent = berTLVList; + while (berTLVCurrent != NULL) + { + BeerTLV* currentBerTLV = berTLVCurrent->berTLV; + if (currentBerTLV != NULL) + { + if (formatBytesToHexaString(currentBerTLV->value, currentBerTLV->length, _bufferFormatLogMessage, sizeof(_bufferFormatLogMessage)) > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "IDX[%u] TLV tag <%X> (%lu bytes) => %s", berTLVCurrent->index, currentBerTLV->tag, + (long unsigned)currentBerTLV->length, _bufferFormatLogMessage); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "IDX[%u] TLV tag <%X> (%lu bytes) => ...", berTLVCurrent->index, currentBerTLV->tag, (long unsigned)currentBerTLV->length); + } + + switch (currentBerTLV->tag) + { + case 0x5A: // ICCID + if (currentBerTLV->length > 0 && currentBerTLV->value != NULL) + { + if (currentBerTLV->length <= LPA_PROFILE_ICCID_BUFFER_MAX_SIZE) + { + if(requestForPPRmanagement) + { + memcpy(ptrPPRprofileInfoAccess->iccid, currentBerTLV->value, currentBerTLV->length); + ptrPPRprofileInfoAccess->iccidSize = currentBerTLV->length; + } + else + { + memcpy(ptrNormalProfileInfoAccess->iccid, currentBerTLV->value, currentBerTLV->length); + ptrNormalProfileInfoAccess->iccidSize = currentBerTLV->length; + } + } + } + break; + + case 0x9F70: // profileState + if (currentBerTLV->length > 0 && currentBerTLV->value != NULL) + { + if (currentBerTLV->length <= LPA_PROFILE_STATE_MAX_SIZE) + { + if(requestForPPRmanagement) + { + memcpy(ptrPPRprofileInfoAccess->profileState, currentBerTLV->value, currentBerTLV->length); + ptrPPRprofileInfoAccess->profileStateSize = currentBerTLV->length; + } + else + { + memcpy(ptrNormalProfileInfoAccess->profileState, currentBerTLV->value, currentBerTLV->length); + ptrNormalProfileInfoAccess->profileStateSize = currentBerTLV->length; + } + } + } + break; + + case 0x90: // nickname + if(requestForPPRmanagement) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "WARNING! Tag <90> \"nickname\" detected on profile info request for PPR. Shall not happen."); + } + else + { + if (currentBerTLV->length > 0 && currentBerTLV->value != NULL) + { + if (currentBerTLV->length <= LPA_PROFILE_NICKNAME_MAX_SIZE) + { + memcpy(ptrNormalProfileInfoAccess->profileNickname, currentBerTLV->value, currentBerTLV->length); + ptrNormalProfileInfoAccess->profileNicknameSize = currentBerTLV->length; + } + } + } + break; + + case 0x91: // serviceProviderName + if(requestForPPRmanagement) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "WARNING! Tag <91> \"serviceProviderName\" detected on profile info request for PPR. Shall not happen."); + } + else + { + if (currentBerTLV->length > 0 && currentBerTLV->value != NULL) + { + if (currentBerTLV->length <= LPA_PROFILE_SERVICE_PROVIDER_NAME_MAX_SIZE) + { + memcpy(ptrNormalProfileInfoAccess->serviceProviderName, currentBerTLV->value, currentBerTLV->length); + ptrNormalProfileInfoAccess->serviceProviderNameSize = currentBerTLV->length; + } + } + } + break; + + case 0x92: // profileName + if(requestForPPRmanagement) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "WARNING! Tag <92> \"profileName\" detected on profile info request for PPR. Shall not happen."); + } + else + { + if (currentBerTLV->length > 0 && currentBerTLV->value != NULL) + { + if (currentBerTLV->length <= LPA_PROFILE_NAME_MAX_SIZE) + { + memcpy(ptrNormalProfileInfoAccess->profileName, currentBerTLV->value, currentBerTLV->length); + ptrNormalProfileInfoAccess->profileNameSize = currentBerTLV->length; + } + } + } + break; + + case 0x93: // iconType + if(requestForPPRmanagement) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "WARNING! Tag <93> \"iconType\" detected on profile info request for PPR. Shall not happen."); + } + else + { + if (currentBerTLV->length > 0 && currentBerTLV->value != NULL) + { + if (currentBerTLV->length <= LPA_PROFILE_ICON_TYPE_MAX_SIZE) + { + memcpy(ptrNormalProfileInfoAccess->profileIconType, currentBerTLV->value, currentBerTLV->length); + ptrNormalProfileInfoAccess->profileIconTypeSize = currentBerTLV->length; + } + } + } + break; + + case 0x94: // icon + if(requestForPPRmanagement) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "WARNING! Tag <94> \"icon\" detected on profile info request for PPR. Shall not happen."); + } + else + { + if (currentBerTLV->length > 0 && currentBerTLV->value != NULL) + { + if (currentBerTLV->length <= LPA_PROFILE_ICON_MAX_SIZE) + { + memcpy(ptrNormalProfileInfoAccess->profileIcon, currentBerTLV->value, currentBerTLV->length); + ptrNormalProfileInfoAccess->profileIconSize = currentBerTLV->length; + } + } + } + break; + + case 0x95: // profileClass + if (currentBerTLV->length > 0 && currentBerTLV->value != NULL) + { + if (currentBerTLV->length <= LPA_PROFILE_CLASS_MAX_SIZE) + { + if(requestForPPRmanagement) + { + memcpy(ptrPPRprofileInfoAccess->profileClass, currentBerTLV->value, currentBerTLV->length); + ptrPPRprofileInfoAccess->profileClassSize = currentBerTLV->length; + } + else + { + memcpy(ptrNormalProfileInfoAccess->profileClass, currentBerTLV->value, currentBerTLV->length); + ptrNormalProfileInfoAccess->profileClassSize = currentBerTLV->length; + } + } + } + break; + + case 0x99: // profilePolicyRules + if (currentBerTLV->length > 0 && currentBerTLV->value != NULL) + { + if (currentBerTLV->length <= LPA_PROFILE_POLICY_RULES_MAX_SIZE) + { + if(requestForPPRmanagement) + { + memcpy(ptrPPRprofileInfoAccess->profilePolicyRules, currentBerTLV->value, currentBerTLV->length); + ptrPPRprofileInfoAccess->profilePolicyRulesSize = currentBerTLV->length; + } + else + { + memcpy(ptrNormalProfileInfoAccess->profilePolicyRules, currentBerTLV->value, currentBerTLV->length); + ptrNormalProfileInfoAccess->profilePolicyRulesSize = currentBerTLV->length; + } + } + } + break; + + default: + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "WARNING! Unattended Tag <%X> detected in profile info. Ignoring it.", currentBerTLV->tag); + break; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Current BERTLV NULL, jumping on next"); + + berTLVCurrent = berTLVCurrent->ptrNext; + } + + ERASE_BERTLV_LIST(berTLVList); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_updateProfileInfoFromBerTLV() - BerTLV list NULL!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_updateProfileInfoFromBerTLV() - Invalid parameter(s)!"); + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +LPA_MEMORY_RESET_STATUS _doExtractMemoryResetResponse(const unsigned char *ptrData, size_t dataSize) +{ + LPA_MEMORY_RESET_STATUS memoryResetStatus = LPA_MEMORY_RESET_UNKNOWN; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ _doExtractMemoryResetResponse(...)"); + + if (ptrData != NULL && dataSize > 0) + { + bool tagFound = false; + BeerTLV* ptrBerTLVMemoryResetTag = NULL; + BeerTLV* ptrBerTLVAttributeValue = NULL; + + ptrBerTLVMemoryResetTag = berTLV_extractTagUInt16(MEMORY_RESET_TAG, ptrData, dataSize, &tagFound); + if (ptrBerTLVMemoryResetTag != NULL) + { + ptrBerTLVAttributeValue = berTLV_extractTagUInt16(0x80, ptrBerTLVMemoryResetTag->value, ptrBerTLVMemoryResetTag->length, &tagFound); + } + + if (ptrBerTLVAttributeValue != NULL && ptrBerTLVAttributeValue->length == 1) + { + switch (ptrBerTLVAttributeValue->value[0]) + { + case 0: + memoryResetStatus = LPA_MEMORY_RESET_OK; + break; + + case 1: + memoryResetStatus = LPA_MEMORY_RESET_NOTHING_TO_DELETE; + break; + + case 5: + memoryResetStatus = LPA_MEMORY_RESET_CAT_BUSY; + break; + + case 127: + memoryResetStatus = LPA_MEMORY_RESET_UNDEFINED_ERROR; + break; + + default: + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, " -> Incorrect memoryResetStatus returned by the card: 0x%02x", ptrBerTLVAttributeValue->value[0]); + break; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "BERTLV attribute Value NULL or length not equal 1!"); + + // Do cleanup + ERASE_BERTLV(ptrBerTLVAttributeValue); + ERASE_BERTLV(ptrBerTLVMemoryResetTag); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter(s)!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- _doExtractMemoryResetResponse(...) return %d", memoryResetStatus); + + return memoryResetStatus; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool _doProfileOperationByIccid(PROFILE_OPERATION profileOperation, const unsigned char* ptrProfileId, size_t profileIdSize) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_doProfileOperationByIccid(...)"); + + // profileOperation not checked, just an enum passed by value, not critical and managed below + if (ptrProfileId != NULL && profileIdSize > 0) + { + RawDataObject* rawDataICCID = NULL; + RawDataObject* rawDataA0 = NULL; + RawDataObject* rawDataDGI = NULL; + RawDataObject* rawDataA0WithRefresh = NULL; + + // create ICCID Ber TVL + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Creating ICCID BERTLV..."); + + rawDataICCID = berTLV_createAndBuildRawDataObject(PROFILE_ICCID_TAG, profileIdSize, ptrProfileId); + if (rawDataICCID != NULL) + { + if (formatBytesToHexaString(rawDataICCID->rawData, rawDataICCID->rawDataSize, _bufferFormatLogMessage, sizeof(_bufferFormatLogMessage)) > 0) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "ICCID BERTLV RawData: %s", _bufferFormatLogMessage); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "ICCID BERTLV RawData: ..."); + } + else + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + + if (profileOperation == enableProfile || profileOperation == disableProfile) + { + // Adding Tag + Refresh flag + if (rawDataICCID != NULL) + { + // Creating Tag (contains ICCID tag) + rawDataA0 = berTLV_createAndBuildRawDataObject(0xA0, rawDataICCID->rawDataSize, rawDataICCID->rawData); + } + + if (rawDataA0 != NULL) + { + // Append RefreshFlag for Enable/Disable + unsigned char refreshFlagValue = (_refreshFlagActivated ? 0xFF : 0x00); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Append Refreshflag with value 0x%02X", refreshFlagValue); + RawDataObject* rawDataObjectRefreshFlag = berTLV_createAndBuildRawDataObject(0x81, 0x01, &refreshFlagValue); + if (rawDataObjectRefreshFlag != NULL) + { + rawDataA0WithRefresh = rawDataObject_concat(rawDataA0, rawDataObjectRefreshFlag); + + ERASE_RAWDATAOBJECT(rawDataObjectRefreshFlag); + rawDataObjectRefreshFlag = NULL; + } + } + else + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + + if (((profileOperation == enableProfile || profileOperation == disableProfile) && rawDataA0WithRefresh != NULL) || (profileOperation == deleteProfile && rawDataICCID != NULL)) + { + // Include it on DGI TAG + RawDataObject* rawDataObjectInsideDGI = NULL; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Creating DGI BERTLV..."); + + // + if (profileOperation == deleteProfile) + rawDataObjectInsideDGI = rawDataICCID; + else + rawDataObjectInsideDGI = rawDataA0WithRefresh; + + switch (profileOperation) + { + case enableProfile: + rawDataDGI = berTLV_createAndBuildRawDataObject(ENABLE_PROFILE_DGI_TAG, rawDataObjectInsideDGI->rawDataSize, rawDataObjectInsideDGI->rawData); + break; + + case disableProfile: + rawDataDGI = berTLV_createAndBuildRawDataObject(DISABLE_PROFILE_DGI_TAG, rawDataObjectInsideDGI->rawDataSize, rawDataObjectInsideDGI->rawData); + break; + + case deleteProfile: + rawDataDGI = berTLV_createAndBuildRawDataObject(DELETE_PROFILE_DGI_TAG, rawDataObjectInsideDGI->rawDataSize, rawDataObjectInsideDGI->rawData); + break; + + default: + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid profileOperation!"); + break; + } + + rawDataObjectInsideDGI = NULL; + if (rawDataDGI != NULL) + { + if (formatBytesToHexaString(rawDataDGI->rawData, rawDataDGI->rawDataSize, _bufferFormatLogMessage, sizeof(_bufferFormatLogMessage)) > 0) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "DGI BERTLV RawData: %s", _bufferFormatLogMessage); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "DGI BERTLV RawData: ..."); + } + else + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + else + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_UNDEFINED_ERROR); + + if (rawDataDGI != NULL) + { + // build and Send APDU + uint16_t apduSW = 0x0000; + size_t dataBufferSize = 0; + + if (buildAndSendStoreDataCase4(rawDataDGI, &apduSW, _dataBuffer, sizeof(_dataBuffer), &dataBufferSize)) + { + // Check SW = 90.00 or 91.xx + if ((apduSW == 0x9000) || ((apduSW & 0xFF00) == 0x9100)) + { + // Analyze response (depending of profileOperation) + switch (profileOperation) + { + case enableProfile: + res = _extractResponseForEnableProfileOperation(_dataBuffer, dataBufferSize); + break; + + case disableProfile: + res = _extractResponseForDisableProfileOperation(_dataBuffer, dataBufferSize); + break; + + case deleteProfile: + res = _extractResponseForDeleteProfileOperation(_dataBuffer, dataBufferSize); + break; + + default: + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid profileOperation!"); + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_UNDEFINED_ERROR); + break; + } + } + else + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_INCORRECT_CARD_RESPONSE); + } + else + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_INVALID_DATA_EXCHANGE); + } + + // Do memory cleanup + ERASE_RAWDATAOBJECT(rawDataDGI); + ERASE_RAWDATAOBJECT(rawDataA0); + ERASE_RAWDATAOBJECT(rawDataA0WithRefresh); + ERASE_RAWDATAOBJECT(rawDataICCID); + } + else + { + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool _extractResponseForEnableProfileOperation(const unsigned char *ptrData, size_t dataSize) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_extractResponseForEnableProfileOperation(...)"); + + if (ptrData != NULL && dataSize > 0) + { + bool tagFound = false; + BeerTLV* ptrBerTLVEnableOperationTag = NULL; + BeerTLV* ptrBerTLVAttributeValue = NULL; + + ptrBerTLVEnableOperationTag = berTLV_extractTagUInt16(ENABLE_PROFILE_DGI_TAG, ptrData, dataSize, &tagFound); + if (ptrBerTLVEnableOperationTag != NULL) + { + ptrBerTLVAttributeValue = berTLV_extractTagUInt16(0x80, ptrBerTLVEnableOperationTag->value, ptrBerTLVEnableOperationTag->length, &tagFound); + if (ptrBerTLVAttributeValue != NULL && ptrBerTLVAttributeValue->length == 1) + { + int enableResult = ptrBerTLVAttributeValue->value[0]; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "enableResult:%d", enableResult); + + switch (enableResult) + { + case 0: // OK + res = true; + break; + + case 1: // iccidOrAidNotFound + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_ICCID_OR_AID_NOT_FOUND); + break; + + case 2: // profileNotInDisabledState + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_NOT_IN_DISABLE_STATE); + break; + + case 3: // disallowedByPolicy + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_DISALLOWED_BY_POLICY); + break; + + case 4: // wrongProfileReenabling + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_WRONG_PROFILE_REENABLING); + break; + + case 5: // catBusy + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_CAT_BUSY); + break; + + case 127: // undefinedError + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_UNDEFINED_ERROR); + break; + + default: + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_INCORRECT_CARD_RESPONSE); + break; + } + } + else + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_INCORRECT_CARD_RESPONSE); + } + else + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_INCORRECT_CARD_RESPONSE); + + // Do cleanup + ERASE_BERTLV(ptrBerTLVAttributeValue); + ERASE_BERTLV(ptrBerTLVEnableOperationTag); + } + else + { + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter(s)!"); + } + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool _extractResponseForDisableProfileOperation(const unsigned char *ptrData, size_t dataSize) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_extractResponseForDisableProfileOperation(...)"); + if (ptrData != NULL && dataSize > 0) + { + bool tagFound = false; + BeerTLV* ptrBerTLVDisableOperationTag = NULL; + BeerTLV* ptrBerTLVAttributeValue = NULL; + + ptrBerTLVDisableOperationTag = berTLV_extractTagUInt16(DISABLE_PROFILE_DGI_TAG, ptrData, dataSize, &tagFound); + if (ptrBerTLVDisableOperationTag != NULL) + { + ptrBerTLVAttributeValue = berTLV_extractTagUInt16(0x80, ptrBerTLVDisableOperationTag->value, ptrBerTLVDisableOperationTag->length, &tagFound); + if (ptrBerTLVAttributeValue != NULL && ptrBerTLVAttributeValue->length == 1) + { + int disableResult = ptrBerTLVAttributeValue->value[0]; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "disableResult:%d", disableResult); + + switch (disableResult) + { + case 0: + res = true; + break; + + case 1: // iccidOrAidNotFound + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_ICCID_OR_AID_NOT_FOUND); + break; + + case 2: // profileNotInEnabledState + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_NOT_IN_ENABLE_STATE); + break; + + case 3: // disallowedByPolicy + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_DISALLOWED_BY_POLICY); + break; + + case 5: // catBusy + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_CAT_BUSY); + break; + + case 127: // undefinedError + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_UNDEFINED_ERROR); + break; + + default: + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_INCORRECT_CARD_RESPONSE); + break; + } + + } + else + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_INCORRECT_CARD_RESPONSE); + } + else + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_INCORRECT_CARD_RESPONSE); + + // Do cleanup + ERASE_BERTLV(ptrBerTLVAttributeValue); + ERASE_BERTLV(ptrBerTLVDisableOperationTag); + } + else + { + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter(s)!"); + } + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool _extractResponseForDeleteProfileOperation(const unsigned char *ptrData, size_t dataSize) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_extractResponseForDeleteProfileOperation(...)"); + + if (ptrData != NULL && dataSize > 0) + { + bool tagFound = false; + BeerTLV* ptrBerTLVDeleteOperationTag = NULL; + BeerTLV* ptrBerTLVAttributeValue = NULL; + + ptrBerTLVDeleteOperationTag = berTLV_extractTagUInt16(DELETE_PROFILE_DGI_TAG, ptrData, dataSize, &tagFound); + if (ptrBerTLVDeleteOperationTag != NULL) + { + ptrBerTLVAttributeValue = berTLV_extractTagUInt16(0x80, ptrBerTLVDeleteOperationTag->value, ptrBerTLVDeleteOperationTag->length, &tagFound); + if (ptrBerTLVAttributeValue != NULL && ptrBerTLVAttributeValue->length == 1) + { + int deleteResult = ptrBerTLVAttributeValue->value[0]; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "deleteResult:%d", deleteResult); + + switch (deleteResult) + { + case 0: + res = true; + break; + + case 1: // iccidOrAidNotFound + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_ICCID_OR_AID_NOT_FOUND); + break; + + case 2: // profileNotInDisabledState + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_NOT_IN_DISABLE_STATE); + break; + + case 3: // disallowedByPolicy + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_DISALLOWED_BY_POLICY); + break; + + case 127: // undefinedError + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_UNDEFINED_ERROR); + break; + + default: + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_INCORRECT_CARD_RESPONSE); + break; + } + } + else + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_INCORRECT_CARD_RESPONSE); + } + else + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_INCORRECT_CARD_RESPONSE); + + // Do cleanup + ERASE_BERTLV(ptrBerTLVAttributeValue); + ERASE_BERTLV(ptrBerTLVDeleteOperationTag); + } + else + { + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter(s)!"); + } + + return res; +} + +bool _doExtractEIDResponse(const unsigned char *ptrData, size_t dataSize, LPA_GET_EID* ptrGetEID) +{ + bool res = false; + + if (ptrData != NULL && dataSize > 0 && ptrGetEID != NULL ) + { + BeerTLV* ptrBerTLV_EIDTag = NULL; + BeerTLV* ptrBerTLV_5ATag = NULL; + + ptrBerTLV_EIDTag = berTLV_extractTagUInt16(GET_EID_DGI_TAG, ptrData, dataSize, NULL); + if (ptrBerTLV_EIDTag != NULL) + { + ptrBerTLV_5ATag = berTLV_extractTagUInt16(0x5A, ptrBerTLV_EIDTag->value, ptrBerTLV_EIDTag->length, NULL); + if (ptrBerTLV_5ATag != NULL) + { + if (ptrBerTLV_5ATag->length <= LPA_GET_EID_BUFFER_SIZE) + { + // Copy Data + memcpy(ptrGetEID->EID_Data, ptrBerTLV_5ATag->value, ptrBerTLV_5ATag->length); + ptrGetEID->EID_DataSize = ptrBerTLV_5ATag->length; + + res = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Buffer too small for copying raw data!"); + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + } + } + else + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_UNABLE_TO_EXTRACT_DATA); + + // Do cleanup + ERASE_BERTLV(ptrBerTLV_5ATag); + ERASE_BERTLV(ptrBerTLV_EIDTag); + } + else + { + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter(s)!"); + } + + return res; +} + +/** + * Set new Nickname field in profile identified by ICCID. + * @param ptrProfileID Profile ICCID size, raw format + * @param profileIdSize Profile ICCID size, size_t + * @param ptrNickname New Nickname to set, raw hex format + * @param nickNameSize New Nickname size, size_t - If length = 0, Nickname will be cleared + * @return true is nickname change operation successful + */ +bool lpaManagerES10c_SetNickname(const unsigned char* ptrProfileId, size_t profileIdSize, const unsigned char* ptrNickname, size_t nickNameSize) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaManagerES10c_SetNickname(...)"); + + // Zero value case for 'nickNameSize' is accepted, allow to clear nickname + if(ptrProfileId != NULL && profileIdSize > 0 && ptrNickname != NULL && nickNameSize >= 0 && nickNameSize <= LPA_PROFILE_NICKNAME_MAX_SIZE) + { + RawDataObject* rawDataICCID = NULL; + RawDataObject* rawDataNewNickname = NULL; + RawDataObject* rawDataSetNickmameData = NULL; + RawDataObject* rawDataSetNicknameRequest = NULL; + + // Create ICCID BERTLV + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Creating ICCID and Nickname BERTLV..."); + + rawDataICCID = berTLV_createAndBuildRawDataObject(PROFILE_ICCID_TAG, profileIdSize, ptrProfileId); + if (rawDataICCID != NULL) + { + if (formatBytesToHexaString(rawDataICCID->rawData, rawDataICCID->rawDataSize, _bufferFormatLogMessage, sizeof(_bufferFormatLogMessage)) > 0) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "ICCID BERTLV RawData: %s", _bufferFormatLogMessage); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "ICCID BERTLV RawData: ..."); + } + else + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + + // Create Nickname BERTLV + rawDataNewNickname = berTLV_createAndBuildRawDataObject(PROFILE_NICKNAME_TAG, nickNameSize, ptrNickname); + if (rawDataNewNickname != NULL) + { + if (formatBytesToHexaString(rawDataNewNickname->rawData, rawDataNewNickname->rawDataSize, _bufferFormatLogMessage, sizeof(_bufferFormatLogMessage)) > 0) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Nickname BERTLV RawData: %s", _bufferFormatLogMessage); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Nickname BERTLV RawData: ..."); + } + else + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + + if(rawDataICCID != NULL && rawDataNewNickname != NULL) + { + // Concatenate command data's + rawDataSetNickmameData = rawDataObject_concat(rawDataICCID, rawDataNewNickname); + + if(rawDataSetNickmameData != NULL) + { + // Generate setNickname request + rawDataSetNicknameRequest = berTLV_createAndBuildRawDataObject(SET_NICKNAME_TAG, rawDataSetNickmameData->rawDataSize, rawDataSetNickmameData->rawData); + if(rawDataSetNicknameRequest != NULL) + { + if (formatBytesToHexaString(rawDataSetNicknameRequest->rawData, rawDataSetNicknameRequest->rawDataSize, _bufferFormatLogMessage, sizeof(_bufferFormatLogMessage)) > 0) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Set Nickname request: %s", _bufferFormatLogMessage); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Set Nickname request: ..."); + } + else + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + else + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + + // If request build OK, send it + if(rawDataSetNicknameRequest != NULL) + { + // build and Send APDU + uint16_t apduSW = 0x0000; + size_t dataBufferSize = 0; + + if (buildAndSendStoreDataCase4(rawDataSetNicknameRequest, &apduSW, _dataBuffer, sizeof(_dataBuffer), &dataBufferSize)) + { + // Check SW = 90.00 or 91.xx + if ((apduSW == 0x9000) || ((apduSW & 0xFF00) == 0x9100)) + { + res = _extractResponseForSetNicknameOperation(_dataBuffer, dataBufferSize); + } + else + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_INCORRECT_CARD_RESPONSE); + } + else + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_INVALID_DATA_EXCHANGE); + } + + // Memory cleanup + ERASE_RAWDATAOBJECT(rawDataICCID); + ERASE_RAWDATAOBJECT(rawDataNewNickname); + ERASE_RAWDATAOBJECT(rawDataSetNickmameData); + ERASE_RAWDATAOBJECT(rawDataSetNicknameRequest); + } + else + { + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "lpaManagerES10c_SetNickname: Invalid parameters(s)"); + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaManagerES10c_SetNickname() return %s", (res ? "true" : "false")); + return res; +} + +/** + * Analyzes response to ES10c SetNickname request and report execution status + * @param ptrData Pointer on response returned buy eUICC, raw format + * @param dataSize Size of response returned by eUICC + * @return true if response report operation successful + */ +bool _extractResponseForSetNicknameOperation(const unsigned char *ptrData, size_t dataSize) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_extractResponseForSetNicknameOperation(...)"); + + if (ptrData != NULL && dataSize > 0) + { + bool tagFound = false; + BeerTLV* ptrBerTLVSetNicknameOperationTag = NULL; + BeerTLV* ptrBerTLVAttributeValue = NULL; + + ptrBerTLVSetNicknameOperationTag = berTLV_extractTagUInt16(SET_NICKNAME_TAG, ptrData, dataSize, &tagFound); + if (ptrBerTLVSetNicknameOperationTag != NULL) + { + ptrBerTLVAttributeValue = berTLV_extractTagUInt16(0x80, ptrBerTLVSetNicknameOperationTag->value, ptrBerTLVSetNicknameOperationTag->length, &tagFound); + if (ptrBerTLVAttributeValue != NULL && ptrBerTLVAttributeValue->length == 1) + { + int setNicknameResult = ptrBerTLVAttributeValue->value[0]; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "setNicknameResult:%d", setNicknameResult); + + switch (setNicknameResult) + { + case 0: // OK + res = true; + break; + + case 1: // iccidOrAidNotFound + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_ICCID_OR_AID_NOT_FOUND); + break; + + case 127: // undefinedError + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_UNDEFINED_ERROR); + break; + + default: + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_INCORRECT_CARD_RESPONSE); + break; + } + } + else + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_INCORRECT_CARD_RESPONSE); + } + else + lpaSetErrorCode(LPA_ERROR_LOCAL_PROFILE_INCORRECT_CARD_RESPONSE); + + // Do cleanup + ERASE_BERTLV(ptrBerTLVAttributeValue); + ERASE_BERTLV(ptrBerTLVSetNicknameOperationTag); + } + else + { + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_extractResponseForSetNicknameOperation: Invalid parameter(s)!"); + } + + return res; +} \ No newline at end of file diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/lpa_manager_es9plus.c b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/lpa_manager_es9plus.c new file mode 100755 index 000000000..6ec6aca83 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/lpa_manager_es9plus.c @@ -0,0 +1,1963 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#include "lpasdk/core/lpa_manager_es9plus.h" +#include "lpasdk/core/lpa_manager.h" +#include "lpasdk/core/lpa_manager_helper.h" +#include "lpasdk/core/semedia_manager.h" +#include "lpasdk/core/httpmedia_manager.h" + +#include "lpasdk/lpasdk_internal_api.h" + +#include "lpasdk/core/lpa_log.h" +#include "lpasdk/core/rawdata_object.h" +#include "lpasdk/core/bertlv_object.h" +#include "lpasdk/core/util.h" +#include "lpasdk/core/lpa_memory.h" + +#include "cJSON/cJSON.h" + +#include + +#define INITIATE_AUTHENTICATION_PATH "/gsma/rsp2/es9plus/initiateAuthentication" +#define AUTHENTICATE_CLIENT_PATH "/gsma/rsp2/es9plus/authenticateClient" +#define GET_BOUND_PROFILE_PACKAGE_PATH "/gsma/rsp2/es9plus/getBoundProfilePackage" +#define HANDLE_NOTIFICATION_PATH "/gsma/rsp2/es9plus/handleNotification" +#define CANCEL_SESSION_PATH "/gsma/rsp2/es9plus/cancelSession" + +static char _certPath[LPA_CFG_CERT_PATH_MAX_SIZE]; + +static char _bufferFormatLogMessage[1024]; // 1K is enough (to increase it, use dynamic memory allocation) + +bool _convertHostURLtoLowerCase(const char * ptrSourceURL, char * ptrDestURL, size_t ptrDestURLsize); + +bool _lpaManagerInitiateAuthenticationExtractDataFromCJSON(cJSON* ptrcjsonHttpInitAuthResp, RawDataObject** ptrExtractedField, size_t extractedFieldSizeMax, + const char* ptrJSONname, const bool doBase64, const bool extractAsString); + +char* _lpaManagerAuthenticateClientSendRequest(LPA_API_ERROR* ptrLpaError, const char* ptrTransactionId, const char* ptrSmdpAddress, const char* ptrAuthenticateServerResponse, const LPA_EventCallback* ptrLpaEventCallback); +LPA_API_ERROR _lpaManagerAuthenticateClientCheckTransactionId(cJSON* ptrcjsonHttpAuthClientResp, const char* ptrTransactionId); +LPA_API_ERROR _lpaManagerAuthenticateClientExtractAllDataFromCJSON(cJSON* ptrcjsonHttpAuthClientResp, ptr_serverData p_serverData); +LPA_API_ERROR _lpaManagerAuthenticateClientExtractDataFromCJSON(cJSON* ptrcjsonHttpAuthClientResp, RawDataObject** ptrBuffer, size_t bufferSizeMax, const char* ptrName); + +bool _checkJSONresponseStatusSuccessful(cJSON* cjson, const LPA_EventCallback* ptrLpaEventCallback); +bool _checkJSONresponseErrorCode(const cJSON* p_cjson, const char * p_subjectCode, const char * p_reasonCode); +void _clearJsonAndBuffer(cJSON * ptrcjson, char *ptrBuffer); + +bool _lpaManagerES9SendCancelSession(const char * transactionID, CANCEL_SESSION_RESPONSE * ptrCancelSessionResp, const char* ptrSmdpAddress, const LPA_EventCallback* ptrLpaEventCallback); + +void _sendCallbackNotificationForHttpErrors(const LPA_EventCallback* ptrLpaEventCallback, const char * pErrorMessage); + + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +void lpaManagerES9Plus_Init(const char * defaultCertPath) +{ + // Try to use eventual default value fixed in constant + if(defaultCertPath != NULL && sizeof(defaultCertPath) > 0 && sizeof(defaultCertPath) < LPA_CFG_CERT_PATH_MAX_SIZE) + { + if (snprintf(_certPath, sizeof(_certPath), "%s", defaultCertPath) >= sizeof(_certPath)) + memset(_certPath, 0, sizeof(_certPath)); + } + else + memset(_certPath, 0, sizeof(_certPath)); +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool lpaManagerES9Plus_setCertPath(const char* ptrCertPath) +{ + bool res = false; + + if (ptrCertPath != NULL && strlen(ptrCertPath) < LPA_CFG_CERT_PATH_MAX_SIZE) + { + snprintf(_certPath, sizeof(_certPath), "%s", ptrCertPath); + res = true; + } + + return res; +} + +size_t lpaManagerES9Plus_getCertPathSize() +{ + return strlen(_certPath); +} + +bool lpaManagerES9Plus_getCertPath(char* ptrCertPath, size_t ptrCertPathMaxSize) +{ + bool res = false; + + if ((ptrCertPath != NULL) && (strlen(_certPath) < ptrCertPathMaxSize)) + { + snprintf(ptrCertPath, ptrCertPathMaxSize, "%s", _certPath); + res = true; + } + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + + +char* lpaManagerES9Plus_ExecutePost(const char * ptrTargetURL, const char * ptrJsonRequest, bool* ptrIsSuccess, long *ptrHttpCode, const LPA_EventCallback* ptrLpaEventCallback) +{ + char* resp = NULL; + + char urlStr[LPA_ADDRESS_MAX_SIZE]; + char lowerCaseTargetURL[LPA_ADDRESS_MAX_SIZE]; + + char * secureHttps = "https://"; + + memset(urlStr, 0, sizeof(urlStr)); + memset(lowerCaseTargetURL, 0, sizeof(lowerCaseTargetURL)); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaManagerES9Plus_ExecutePost()"); + + if (ptrTargetURL != NULL && ptrJsonRequest != NULL && ptrIsSuccess != NULL && ptrHttpCode != NULL) + { + *ptrIsSuccess = false; // before starting process, set to false + + // Converts URL to address to lowercase + if(_convertHostURLtoLowerCase(ptrTargetURL, lowerCaseTargetURL, sizeof(lowerCaseTargetURL))) + { + if ((strlen(secureHttps) + strlen(lowerCaseTargetURL)) < sizeof(urlStr)) + { + if (snprintf(urlStr, sizeof(urlStr), "%s%s", secureHttps, lowerCaseTargetURL) >= sizeof(urlStr)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Buffer too small for building https URL!!!"); + urlStr[0] = '\0'; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Buffer too small for building https URL!"); + urlStr[0] = '\0'; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Cannot convert target host URL to lowercase!"); + urlStr[0] = '\0'; + } + + // Check target URL. If empty due to problems, goes on error + if (strlen(urlStr) > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "urlStr:%s", urlStr); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "start to set opt data..."); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "urlStr: Empty!", urlStr); + lpaSetErrorCode(LPA_ERROR_INVALID_SERVER_ADDRESS); + } + + if (strlen(urlStr) > 0 && httpMediaManagerHttpExecuteInit()) + { + resp = httpMediaManagerPost(_certPath, urlStr, ptrJsonRequest, ptrIsSuccess, ptrHttpCode); + if (*ptrIsSuccess) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Server return HTTP status code %ld", *ptrHttpCode); + + switch (*ptrHttpCode) + { + case 204: // HTTP OK - No data + break; + + case 200: // HTTP OK with data + // Note: Actually, case below of code 200 without data cannot be reached here due to filtering performed in + // httpmedia_manager.c -> httpMediaManagerPost() were *ptrIsSuccess is set to false when server return 2xx + // without data (Except for 204). Kept for possible evolution of httpmedia_manager.c removing this test. + if (resp == NULL) + { + // Incorrect case: HTTP 200 must having data + lpaSetErrorCode(LPA_ERROR_SERVER_COMMUNICATION_ISSUE); + _sendCallbackNotificationForHttpErrors(ptrLpaEventCallback, "http error: Server returned code 200 without data"); + } + break; + + case 404: + lpaSetErrorCode(LPA_ERROR_SERVER_RETURN_404_STATUS_CODE); + _sendCallbackNotificationForHttpErrors(ptrLpaEventCallback, "http error: Server returned code 404"); + break; + + case 500: + lpaSetErrorCode(LPA_ERROR_SERVER_RETURN_500_STATUS_CODE); + _sendCallbackNotificationForHttpErrors(ptrLpaEventCallback, "http error: Server returned code 500"); + break; + + default: + // Managed by lpa_manager directly + lpaSetErrorCode(LPA_ERROR_SERVER_COMMUNICATION_ISSUE); + snprintf(_bufferFormatLogMessage, sizeof(_bufferFormatLogMessage), "http error: Server returned code %ld", *ptrHttpCode); + _sendCallbackNotificationForHttpErrors(ptrLpaEventCallback, _bufferFormatLogMessage); + break; + } + } + else + { + lpaSetErrorCode(LPA_ERROR_SERVER_COMMUNICATION_ISSUE); + // Note: Check of code 200 here is here needed by pre-processing of code 200 in httpmedia_manager.c -> httpMediaManagerPost() were + // *ptrIsSuccess is set to false when server return 200 without data + if(*ptrHttpCode == 200) + _sendCallbackNotificationForHttpErrors(ptrLpaEventCallback, "http error: Server returned code 200 without data"); + else + { + // Note: Other codes 2xx without data will be also notified here, without specific indication like for code 200 + if(*ptrHttpCode > 0) + { + snprintf(_bufferFormatLogMessage, sizeof(_bufferFormatLogMessage), "http error: Communication issue. http code returned: %ld", *ptrHttpCode); + _sendCallbackNotificationForHttpErrors(ptrLpaEventCallback, _bufferFormatLogMessage); + } + else + _sendCallbackNotificationForHttpErrors(ptrLpaEventCallback, "http error: Communication issue"); + + } + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "httpMediaManagerHttpExectueInit failed!"); + lpaSetErrorCode(LPA_ERROR_UNABLE_TO_INITIALIZE_HTTP_MEDIA); + _sendCallbackNotificationForHttpErrors(ptrLpaEventCallback, "http error: Cannot initialize http media or problem with target URL"); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter(s)!"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + return resp; +} + + +/** + * Search for host at the beginning of server URL (Up to first '/' character) and convert it to lowercase + * @param ptrSourceURL URL to convert, string format + * @param ptrDestURL Buffer that will receive converted URL, string format + * @param ptrDestURLSize Size of destination buffer, Must be large enough to receive destination URL with '\0' character at the end. + * @return True if conversion is successful + */ +bool _convertHostURLtoLowerCase(const char * ptrSourceURL, char * ptrDestURL, size_t ptrDestURLsize) +{ + bool res = false; + size_t sourceLength = 0; + bool hostNotfinished = true; + + if(ptrSourceURL != NULL && ptrDestURL != NULL && ptrDestURLsize > 0) + { + sourceLength = strlen(ptrSourceURL); + + if(sourceLength < ptrDestURLsize) // Check destination buffer size + { + size_t i = 0; + + while(i < sourceLength) + { + // Stop conversion when first '/' is encountered + if(ptrSourceURL[i] == '/') + hostNotfinished = false; + + if(hostNotfinished) + ptrDestURL[i] = tolower(ptrSourceURL[i]); + else + ptrDestURL[i] = ptrSourceURL[i]; + + i++; + } + ptrDestURL[i] = '\0'; // Terminate destination string + + // Validate conversion OK only if not only an host URL has been copied in destination buffer + if(! hostNotfinished) + res = true; + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_convertHostURLtoLowerCase: Only host URL detected."); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_convertHostURLtoLowerCase: Destination buffer too small."); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_convertHostURLtoLowerCase: Invalid Parameters."); + + return res; +} + + +/** + * Send Callback notification for http errors + * @param ptrLpaEventCallback Callback pointer + * @param pErrorMessage message to return, string format. If null no Callback is send + */ +void _sendCallbackNotificationForHttpErrors(const LPA_EventCallback* ptrLpaEventCallback, const char * pErrorMessage) +{ + if ((ptrLpaEventCallback != NULL) && (pErrorMessage != NULL)) + { + if (ptrLpaEventCallback->_lpaEventExecutionError != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "Creating Callback Notification Error for http..."); + LPA_EVENT_EXECUTION_ERROR_INFO eventExecutionErrorInfo; + memset(&eventExecutionErrorInfo, 0x00, sizeof(LPA_EVENT_EXECUTION_ERROR_INFO)); + + eventExecutionErrorInfo.executionErrorType = LPA_EVENT_EXECUTION_HTTP_ERROR_TYPE; + eventExecutionErrorInfo.detailErrorMask = LPA_EVENT_EXECUTION_ERROR_EXTRA_INFO_MASK; + + eventExecutionErrorInfo.ptrErrorExtraInfo = pErrorMessage; + + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "Sending Callback Notification Error to LPA application..."); + ptrLpaEventCallback->_lpaEventExecutionError(ptrLpaEventCallback->_appParameter, &eventExecutionErrorInfo); + } + } +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool lpaManagerES9Plus_InitiateAuthentication(ptr_serverData p_serverData, const LPA_EventCallback* ptrLpaEventCallback, const char * ptrEuiccChallenge, const char * ptrEuiccInfo1, const char* ptrSmdpAddress) +{ + cJSON* jsonObject = cJSON_CreateObject(); + char * httpServerResp = NULL; // De-allocated by httpMediaManagerHttpExecuteCleanup() + bool isSuccess = false; + bool res = false; + + // Reminder: Used members of p_serverData (_transactionId, _serverSigned1, _serverSignature1, _euiccCiPKIdToBeUsed & _serverCertificate) are not checked here because + // allocated / filled here and shall be NULL at this time + if (p_serverData != NULL && ptrEuiccChallenge != NULL && ptrEuiccInfo1 != NULL && ptrSmdpAddress != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerES9Plus_InitiateAuthentication..."); + + if(jsonObject != NULL) + { + cJSON_AddItemToObject(jsonObject, "euiccInfo1", cJSON_CreateString(ptrEuiccInfo1)); + cJSON_AddItemToObject(jsonObject, "euiccChallenge", cJSON_CreateString(ptrEuiccChallenge)); + cJSON_AddItemToObject(jsonObject, "smdpAddress", cJSON_CreateString(ptrSmdpAddress)); + + char* buffer = cJSON_Print(jsonObject); + cJSON_Delete(jsonObject); + jsonObject = NULL; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, ">> HTTP request %s\n", buffer); + + char initialAuthSmdpAddr[LPA_ADDRESS_MAX_SIZE]; + memset(&initialAuthSmdpAddr, 0, sizeof(initialAuthSmdpAddr)); + + if ((strlen(ptrSmdpAddress) + strlen(INITIATE_AUTHENTICATION_PATH)) < LPA_ADDRESS_MAX_SIZE) + { + memcpy(initialAuthSmdpAddr, ptrSmdpAddress, strlen(ptrSmdpAddress)); + memcpy(initialAuthSmdpAddr + strlen(ptrSmdpAddress), INITIATE_AUTHENTICATION_PATH, strlen(INITIATE_AUTHENTICATION_PATH)); + + long httpCode = 0; + httpServerResp = lpaManagerES9Plus_ExecutePost(initialAuthSmdpAddr, buffer, &isSuccess, &httpCode, ptrLpaEventCallback); + + if (httpServerResp != NULL && isSuccess) + { + if (httpCode > 0) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "initiateAuthentication() => HTTP Request return httpCode=%ld", httpCode); + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "initiateAuthentication() => HTTP Request return invalid httpCode!"); + lpaSetErrorCode(LPA_ERROR_INVALID_SERVER_RESPONSE); + isSuccess = false; + } + + if(isSuccess) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "<< HTTP response %s", httpServerResp); + + cJSON* cjsonParsed = cJSON_Parse(httpServerResp); + if (cjsonParsed == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "json pack into cjson error..."); + lpaSetErrorCode(LPA_ERROR_CJSON_PARSE_FAILURE); + + // do memory cleanup + if (buffer != NULL) + { + lpaCoreMemoryFree(buffer); + buffer = NULL; + } + httpMediaManagerHttpExecuteCleanup(); + return res; + } + + if (!_checkJSONresponseStatusSuccessful(cjsonParsed, ptrLpaEventCallback)) + { + _clearJsonAndBuffer(cjsonParsed, buffer); + // Turnaround because pointers are not set to NULL by _clearJsonAndBuffer() + buffer = NULL; + cjsonParsed = NULL; + httpMediaManagerHttpExecuteCleanup(); + return res; + } + + if(! _lpaManagerInitiateAuthenticationExtractDataFromCJSON(cjsonParsed, &(p_serverData->_transactionId), + LPA_TRANSACTION_ID_MAX_SIZE, "transactionId", false, true)) + { + lpaSetErrorCode(LPA_ERROR_INVALID_TRANSACTIONID); + isSuccess = false; + } + + if(isSuccess) + { + if(! _lpaManagerInitiateAuthenticationExtractDataFromCJSON(cjsonParsed, &(p_serverData->_serverSigned1), + LPA_INITIAL_AUTHENTICATE_SERVER_SIGNED1_MAX_SIZE, "serverSigned1", true, false)) + { + lpaSetErrorCode(LPA_ERROR_INVALID_SERVERSIGNED1); + isSuccess = false; + } + } + + if(isSuccess) + { + if(! _lpaManagerInitiateAuthenticationExtractDataFromCJSON(cjsonParsed, &(p_serverData->_serverSignature1), + LPA_INITIAL_AUTHENTICATE_SERVER_SIGNATURE1_MAX_SIZE, "serverSignature1", true, false)) + { + lpaSetErrorCode(LPA_ERROR_INVALID_SERVERSIGNATURE1); + isSuccess = false; + } + } + + if(isSuccess) + { + if(! _lpaManagerInitiateAuthenticationExtractDataFromCJSON(cjsonParsed, &(p_serverData->_euiccCiPKIdToBeUsed), + LPA_INITIAL_AUTHENTICATE_EUICC_CIPKID_TO_BE_USED_MAX_SIZE, "euiccCiPKIdToBeUsed", true, false)) + { + lpaSetErrorCode(LPA_ERROR_INVALID_EUICCCIPKIDTOBEUSED); + isSuccess = false; + } + } + + if(isSuccess) + { + if(! _lpaManagerInitiateAuthenticationExtractDataFromCJSON(cjsonParsed, &(p_serverData->_serverCertificate), + LPA_INITIAL_AUTHENTICATE_SERVER_CERTIFICATE_MAX_SIZE, "serverCertificate", true, false)) + { + lpaSetErrorCode(LPA_ERROR_INVALID_SERVERCERTIFICATE); + isSuccess = false; + } + } + + // JSON / Buffer cleanup + _clearJsonAndBuffer(cjsonParsed, buffer); + // Turnaround because pointers are not set to NULL by _clearJsonAndBuffer(). Can cause locking issue at the end. + buffer = NULL; + cjsonParsed = NULL; + + // Return OK ONLY if no problem during execution! + if(isSuccess) + res = true; + } + } + else + { + // Enter here match to an error case or response type not expected here (Example 204) + // Set an error if not already performed by lpaManagerES9Plus_ExecutePost() + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Server communication error detected!"); + lpaSetErrorCode(LPA_ERROR_SERVER_COMMUNICATION_ISSUE); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid address"); + lpaSetErrorCode(LPA_ERROR_INVALID_SERVER_ADDRESS); + } + + // do memory cleanup + if (buffer != NULL) + { + lpaCoreMemoryFree(buffer); + buffer = NULL; + } + httpMediaManagerHttpExecuteCleanup(); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Cannot create JSON object jsonObject!"); + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "initiateAuthentication() - Invalid parameter"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + return res; +} + +/** + * Parse Base64 JSON item from server Initiate authentication JSON response and store item in LPA_SERVER_DATA field, in RawDataObject format + * @param ptrcjsonHttpInitAuthResp Pointer on JSON response to parse + * @param ptrExtractedField Pointer on address of LPA_SERVER_DATA field who will receive extracted item, RawDataObject format + * @param extractedFieldSizeMax Maximum size allowed for extracted item + * @param ptrJSONname Name of item to parse from JSON response + * @param doBase64 If true, item extracted from JSON response will be converted from Base64 to hex + * @param extractAsString if true, item extracted will be extracted at size+1 to also get End Of String and store is as a string + * @return true if operation is OK + */ +bool _lpaManagerInitiateAuthenticationExtractDataFromCJSON(cJSON* ptrcjsonHttpInitAuthResp, RawDataObject** ptrExtractedField, size_t extractedFieldSizeMax, + const char* ptrJSONname, const bool doBase64, const bool extractAsString) +{ + bool res = false; + + cJSON* ptrcJSONItem_Retrieval = NULL; // Note: Not need to be de-allocated, point on object given by JSON library + char * bindata = NULL; // Note: Not need to be de-allocated, point on object given by JSON library + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_lpaManagerAuthenticateClientExtractBase64DataFromCJSON..."); + + // *ptrExtractedField can be NULL because not yet allocated + if (ptrcjsonHttpInitAuthResp != NULL && extractedFieldSizeMax > 0 && ptrJSONname != NULL) + { + ptrcJSONItem_Retrieval = cJSON_GetObjectItem(ptrcjsonHttpInitAuthResp, ptrJSONname); + if(ptrcJSONItem_Retrieval != NULL) + { + bindata = cJSON_GetStringValue(ptrcJSONItem_Retrieval); + + if(bindata != NULL) + { + // Decode and store serverCertificate and check it does not exceed maximum allowed size + if(doBase64) + *ptrExtractedField = rawDataObject_createFromBase64(bindata, strlen(bindata), extractedFieldSizeMax); // Convert JSON item from Base64 to hex + else + if(strlen(bindata) < extractedFieldSizeMax) + { + if(extractAsString) + *ptrExtractedField = rawDataObject_create((unsigned char *)bindata, (strlen(bindata) + 1)); // Store JSON item as a string + else + *ptrExtractedField = rawDataObject_create((unsigned char *)bindata, strlen(bindata)); // Store JSON item as it + } + + if(*ptrExtractedField != NULL) + { + snprintf(_bufferFormatLogMessage, sizeof(_bufferFormatLogMessage), "%s (%llu bytes):", ptrJSONname, (long long unsigned)(*ptrExtractedField)->rawDataSize); + lpaCoreLogAppendByteArray(SDK_LOG_LEVEL_DEBUG, _bufferFormatLogMessage, ptrJSONname, (*ptrExtractedField)->rawData, (*ptrExtractedField)->rawDataSize); + res = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to decode '%s' from base64 or it's size exceed maximum allowed!", ptrJSONname); + + // Temporary pointer cleanup, no need to free, allocated in cJSON object + bindata = NULL; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to parse '%s' from JSON object!", ptrJSONname); + + // Temporary pointer cleanup, no need to free, allocated in cJSON object + ptrcJSONItem_Retrieval = NULL; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "'%s' not found on JSON response", ptrJSONname); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerAuthenticateClientExtractBase64DataFromCJSON: One or more parameter NULL!!"); + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** + * Perform GetBoundProfilePackage with server and recover profile package. Also check that transactionID is matching and main TLV object of profile is correct + * @param p_serverData Pointer on LPA_SERVER_DATA structure, bring server data and return boundProfilePackage as BerTLVlist + * @param ptrLpaEventCallback Pointer on callback, allow to return errors from lpaManagerES9Plus_ExecutePost() + * @param ptrSmdpAddress Pointer on SM-DP server address, string format + * @param ptrPrepareDownloadResponse Pointer on PrepareDowloadResponse data + * @param cancelForBPPerrors Pointer on flag informing, if returned true, that CancelSession must be performed due to incorrect boundProfilePackage + * @return True if no error + */ +bool lpaManagerES9Plus_GetBoundProfilePackage(ptr_serverData p_serverData, const LPA_EventCallback* ptrLpaEventCallback, const char* ptrSmdpAddress, const unsigned char* ptrPrepareDownloadResponse, bool * cancelForBPPerrors) +{ + bool res = false; + char * bindata = NULL; + bool isSuccess = false; + char* httpServerResp = NULL; + + bool transactionIDcheckedOK = false; + + RawDataObject * boundProfilePackageHex = NULL; + BeerTLV* berTLV_BF36 = NULL; + + // Note: p_serverData->_boundProfilePackage not tested because allocated / filled here and shall be NULL at this time + if (p_serverData != NULL && p_serverData->_transactionId != NULL && ptrSmdpAddress != NULL && ptrPrepareDownloadResponse != NULL && cancelForBPPerrors != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerGetBoundProfilePackage..."); + *cancelForBPPerrors = false; // For the moment, no error detected in main containers or boudProfilePackage + cJSON* jsonObject = cJSON_CreateObject(); + + if(jsonObject != NULL) + { + cJSON_AddItemToObject(jsonObject, "transactionId", cJSON_CreateString((char*)p_serverData->_transactionId->rawData)); + cJSON_AddItemToObject(jsonObject, "prepareDownloadResponse", cJSON_CreateString((char*)ptrPrepareDownloadResponse)); + char* buffer = cJSON_Print(jsonObject); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, ">> HTTP request %s\n ", buffer); + cJSON_Delete(jsonObject); + jsonObject = NULL; + + char getBoundProfileSmdpAddr[LPA_ADDRESS_MAX_SIZE]; + memset(&getBoundProfileSmdpAddr, 0, sizeof(getBoundProfileSmdpAddr)); + if ((strlen(ptrSmdpAddress) + strlen(GET_BOUND_PROFILE_PACKAGE_PATH))< LPA_ADDRESS_MAX_SIZE) + { + memcpy(getBoundProfileSmdpAddr, ptrSmdpAddress, strlen(ptrSmdpAddress)); + memcpy(getBoundProfileSmdpAddr + strlen(ptrSmdpAddress), GET_BOUND_PROFILE_PACKAGE_PATH, strlen(GET_BOUND_PROFILE_PACKAGE_PATH)); + + long httpCode = 0; + httpServerResp = lpaManagerES9Plus_ExecutePost(getBoundProfileSmdpAddr, buffer, &isSuccess, &httpCode, ptrLpaEventCallback); + + if (httpServerResp != NULL && isSuccess) + { + if (httpCode > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerGetBoundProfilePackage() => HTTP Request return httpCode=%ld", httpCode); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "HTTP response size: %llu bytes", (long long unsigned)strlen(httpServerResp)); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerAuthenticateClientSendRequest() => HTTP Request return invalid httpCode!"); + + lpaCoreLogAppendLongText(SDK_LOG_LEVEL_DEBUG, "<< HTTP response:", httpServerResp, strlen(httpServerResp)); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Parsing JSON object from HTTP response..."); + cJSON* cjson = cJSON_Parse(httpServerResp); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Release data from HTTP response"); + httpMediaManagerHttpExecuteCleanup(); + + // Process JSON object found in HTTP response + if (cjson == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "JSON pack into CJSON error..."); + lpaSetErrorCode(LPA_ERROR_CJSON_PARSE_FAILURE); + + // do memory cleanup + if (buffer != NULL) + { + lpaCoreMemoryFree(buffer); + buffer = NULL; + } + return res; + } + else + { + if (!_checkJSONresponseStatusSuccessful(cjson, ptrLpaEventCallback)) + { + _clearJsonAndBuffer(cjson, buffer); + cjson = NULL; + buffer = NULL; + return res; + } + + // Check transactionId + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Extracting transactionId from JSON server response..."); + + cJSON* ptrcJSONItem_TransactionID = cJSON_GetObjectItem(cjson, "transactionId"); + char* ptrServerTransactionId = NULL; + if(ptrcJSONItem_TransactionID != NULL) + { + ptrServerTransactionId = cJSON_GetStringValue(ptrcJSONItem_TransactionID); + ptrcJSONItem_TransactionID = NULL; // Remove reference on CJSON object that will be released after, no need to free it + } + + if (ptrServerTransactionId == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to get transactionId from server"); + lpaSetErrorCode(LPA_ERROR_INVALID_TRANSACTIONID); + } + else + { + if (strcmp(ptrServerTransactionId, (char *)p_serverData->_transactionId->rawData) == 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "transactionId matching checked OK"); + transactionIDcheckedOK = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid transactionId from server"); + lpaSetErrorCode(LPA_ERROR_INVALID_TRANSACTIONID); + } + + ptrServerTransactionId = NULL; // Remove reference on CJSON object that will be released after, no need to free it + } + + // No need to extract boundProfilePackage if transaction ID checking failed + if(transactionIDcheckedOK) + { + // BoundProfilePackage - Extract it from JSON returned in HTTP response + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Extracting boundProfilePackage from JSON server response..."); + cJSON* ptrcJSON_boundProfilePackage = cJSON_GetObjectItem(cjson, "boundProfilePackage"); + if (ptrcJSON_boundProfilePackage != NULL) + { + if (cJSON_IsString(ptrcJSON_boundProfilePackage) || cJSON_IsRaw(ptrcJSON_boundProfilePackage)) + { + if (cJSON_IsString(ptrcJSON_boundProfilePackage)) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "boundProfilePackage JSON object is String type"); + + if (cJSON_IsRaw(ptrcJSON_boundProfilePackage)) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "boundProfilePackage JSON object is Raw type"); + + bindata = cJSON_GetStringValue(ptrcJSON_boundProfilePackage); + + if(bindata != NULL) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "JSON Base64 boundProfilePackage size: %llu bytes", (long long unsigned)strlen(bindata)); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Cannot retrieve value from boundProfilePackage cJSON object"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "boundProfilePackage cJSON object not String or Raw type"); + + ptrcJSON_boundProfilePackage = NULL; // Do not delete it. Remove reference on CJSON object that will be released after, no need to free it + } + + if (bindata != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Translating boundProfilePackage from Base64 to HEX..."); + // Translate profile package from Base64 to raw hex, with size limitation check (Return NULL if size exceed limit) + boundProfilePackageHex = rawDataObject_createFromBase64(bindata, strlen(bindata), LPA_GET_BOUND_PROFILE_MAX_SIZE); + + if(boundProfilePackageHex != NULL) + { + snprintf(_bufferFormatLogMessage, sizeof(_bufferFormatLogMessage), "boundProfilePackage HEX (%llu bytes):", (long long unsigned)boundProfilePackageHex->rawDataSize); + lpaCoreLogAppendByteArray(SDK_LOG_LEVEL_DEBUG, _bufferFormatLogMessage, "boundProfilePackage", boundProfilePackageHex->rawData, boundProfilePackageHex->rawDataSize); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to decode boundProfilePackage from base64 or it's size exceed limit (%llu bytes)", (long long unsigned)LPA_GET_BOUND_PROFILE_MAX_SIZE); + + bindata = NULL; // Remove reference on CJSON object that will be released below, no need to free it + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid boundProfilePackage from server! (Cannot be extracted from server JSON response)"); + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Release CJSON object"); + cJSON_Delete(cjson); + cjson = NULL; + } //end cjson null + + // Since API 1.8: A part of boundProfilePackage checking is now done here, due to memory saving optimization + + // If transaction ID checking failed, there will be no profile to provide + // This is a double security, boundProfilePackageHex then berTLV_BF36 will be also NULL by extension + if(transactionIDcheckedOK) + { + // Since API 1.8: Convert boundProfilePackage into BeerTLV and check main Tag + if(boundProfilePackageHex != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Converting boundProfilePackage HEX to BERTLV and checking main Tag..."); + + berTLV_BF36 = berTLV_extractTagUInt16(0xBF36, boundProfilePackageHex->rawData, boundProfilePackageHex->rawDataSize, NULL); + + if (berTLV_BF36 == NULL || berTLV_BF36->length == 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "boundProfilePackage main Tag not found or invalid TLV format or empty"); + lpaSetErrorCode(LPA_ERROR_INVALID_BPP_DATA); + *cancelForBPPerrors = true; + + ERASE_BERTLV(berTLV_BF36); // In case not NULL but length = 0 + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "boundProfilePackage main Tag found, data length: %lu bytes", (long unsigned)berTLV_BF36->length); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Release HEX raw data image of boundProfilePackage"); + ERASE_RAWDATAOBJECT(boundProfilePackageHex); + } + + // Since API 1.8: Convert boundProfilePackage BeerTLV in BerTLVList, with basic coherence check + if(berTLV_BF36 != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Converting boundProfilePackage BERTLV to BerTLVList and checking number of objects inside..."); + + p_serverData->_boundProfilePackage = berTLV_extractList(berTLV_BF36->value, berTLV_BF36->length, &p_serverData->_boundProfilePackageContainerCount); + // At least 4 mandatory objects must be found (BF23, A0, A1 & A3) + if(p_serverData->_boundProfilePackage != NULL && p_serverData->_boundProfilePackageContainerCount > 3) + { + // Store length of BF36 object for BF36 header sending to eUICC at loadBoundProfilePackage + p_serverData->_boundProfilePackageLength = berTLV_BF36->length; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "boundProfilePackage BerTLVList successfully created, found %u objects inside", p_serverData->_boundProfilePackageContainerCount); + res = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to create boundProfilePackage BerTLVList or not enough objects inside (Found %u, at least 3 required)", p_serverData->_boundProfilePackageContainerCount); + lpaSetErrorCode(LPA_ERROR_INVALID_BPP_DATA); + *cancelForBPPerrors = true; + + ERASE_BERTLV_LIST(p_serverData->_boundProfilePackage); // In case BerTLVList created but not enough objects inside + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Release boundProfilePackage main BERTLV object"); + ERASE_BERTLV(berTLV_BF36); + } + } + } + else + { + // Enter here match to an error case or response type not expected here (Example 204) + // Set an error if not already performed by lpaManagerES9Plus_ExecutePost() + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Server communication error detected!"); + lpaSetErrorCode(LPA_ERROR_SERVER_COMMUNICATION_ISSUE); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Invalid Address"); + + // do memory cleanup + if (buffer != NULL) + { + lpaCoreMemoryFree(buffer); + buffer = NULL; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Cannot create JSON object jsonObject!"); + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + //httpMediaManagerHttpExecuteCleanup(); + return res; +} + + +/** + * Perform "Authenticate Client" with server + * @param p_serverData Pointer on LPA_SERVER_DATA structure. Also contain TransactionID + * @param ptrLpaEventCallback Pointer on Callback for information return of functions used inside + * @param ptrSmdpAddress Pointer on SM-DP address, string format + * @param ptrAuthenticateServerResponse Pointer on authenticateServerResponse data, string format + * @return true if process OK + */ +bool lpaManagerES9Plus_AuthenticateClient(ptr_serverData p_serverData, const LPA_EventCallback* ptrLpaEventCallback, const char* ptrSmdpAddress, const unsigned char* ptrAuthenticateServerResponse) +{ + bool res = false; + LPA_API_ERROR lpaError = LPA_NO_ERROR; + char* ptrHttpAuthClientResp = NULL; + cJSON* ptrcjsonHttpAuthClientResp = NULL; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerAuthenticateClient..."); + + if(p_serverData != NULL && p_serverData->_transactionId != NULL && ptrSmdpAddress != NULL && ptrAuthenticateServerResponse != NULL) + { + // Step 1: authenticate client + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerAuthenticateClient() => Step1: authenticateClient..."); + + ptrHttpAuthClientResp = _lpaManagerAuthenticateClientSendRequest(&lpaError, (char*)p_serverData->_transactionId->rawData, ptrSmdpAddress, + (const char*)ptrAuthenticateServerResponse, ptrLpaEventCallback); + if (ptrHttpAuthClientResp == NULL || lpaError != LPA_NO_ERROR) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "lpaManagerAuthenticateClient() => ptrHttpAuthClientResp is NULL or lpaError not equal to LPA_NO_ERROR"); + lpaError = LPA_ERROR_AUTHENTICATE_CLIENT_EXCHANGE; + } + + if (lpaError == LPA_NO_ERROR) + { + // Step 2: manage HTTP response + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerAuthenticateClient() => Step2: manage response..."); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "<< HTTP response %s", ptrHttpAuthClientResp); + ptrcjsonHttpAuthClientResp = cJSON_Parse(ptrHttpAuthClientResp); + if (ptrcjsonHttpAuthClientResp != NULL) + { + if (_checkJSONresponseStatusSuccessful(ptrcjsonHttpAuthClientResp, ptrLpaEventCallback)) + lpaError = _lpaManagerAuthenticateClientCheckTransactionId(ptrcjsonHttpAuthClientResp, (char*)p_serverData->_transactionId->rawData); + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "cJSON content error!"); + lpaError = LPA_ERROR_FAILED_AUTHENTICATE_CLIENT; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "json pack into cjson error..."); + lpaError = LPA_ERROR_CJSON_PARSE_FAILURE; + } + } + + if (lpaError == LPA_NO_ERROR) + { + // Step 3: Extract data from HTTP response + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerAuthenticateClient() => Step3: extract data from HTTP response..."); + + lpaError = _lpaManagerAuthenticateClientExtractAllDataFromCJSON(ptrcjsonHttpAuthClientResp, p_serverData); + } + + // Memory cleanup + /////////////////////////////////// + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Do memory cleanup..."); + if (ptrHttpAuthClientResp != NULL) + { + ptrHttpAuthClientResp = NULL; // Do not free here, will be done inside httpMediaManagerHttpExecuteCleanup()!!! + } + + if (ptrcjsonHttpAuthClientResp != NULL) + { + cJSON_Delete(ptrcjsonHttpAuthClientResp); + ptrcjsonHttpAuthClientResp = NULL; + } + + httpMediaManagerHttpExecuteCleanup(); + + if (lpaError == LPA_NO_ERROR) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerAuthenticateClient() => return TRUE"); + res = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerAuthenticateClient() => LPA Error: 0x%04X", lpaError); + lpaSetErrorCode(lpaError); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + return res; +} + + +///////////////////////////////////////////////// +// +///////////////////////////////////////////////// + +char* _lpaManagerAuthenticateClientSendRequest(LPA_API_ERROR* ptrLpaError, const char* ptrTransactionId, const char* ptrSmdpAddress, const char* ptrAuthenticateServerResponse, const LPA_EventCallback* ptrLpaEventCallback) +{ + LPA_API_ERROR lpaError = LPA_NO_ERROR; + char* ptrHttpAuthClientResp = NULL; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_lpaManagerAuthenticateClientSendRequest..."); + + if (ptrLpaError != NULL && ptrTransactionId != NULL && ptrSmdpAddress != NULL && ptrAuthenticateServerResponse != NULL) + { + cJSON* jsonObject = cJSON_CreateObject(); + if (jsonObject != NULL) + { + cJSON_AddItemToObject(jsonObject, "transactionId", cJSON_CreateString(ptrTransactionId)); + cJSON_AddItemToObject(jsonObject, "authenticateServerResponse", cJSON_CreateString((char*)ptrAuthenticateServerResponse)); + char* ptrBufferJSON = cJSON_Print(jsonObject); + if (ptrBufferJSON != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, ">> HTTP request %s", ptrBufferJSON); + + char authClientSmdpAddr[LPA_ADDRESS_MAX_SIZE]; + memset(&authClientSmdpAddr, 0, sizeof(authClientSmdpAddr)); + if ((strlen(ptrSmdpAddress) + strlen(AUTHENTICATE_CLIENT_PATH)) < LPA_ADDRESS_MAX_SIZE) + { + memcpy(authClientSmdpAddr, ptrSmdpAddress, strlen(ptrSmdpAddress)); + memcpy(authClientSmdpAddr + strlen(ptrSmdpAddress), AUTHENTICATE_CLIENT_PATH, strlen(AUTHENTICATE_CLIENT_PATH)); + + bool isSuccess = false; + long httpCode = 0; + ptrHttpAuthClientResp = lpaManagerES9Plus_ExecutePost(authClientSmdpAddr, ptrBufferJSON, &isSuccess, &httpCode, ptrLpaEventCallback); + //transactionId+profileMetadata+smdpSigned2+smdpSignature2+smdpCertificate + + if (ptrHttpAuthClientResp != NULL) + { + if (isSuccess) + { + if( httpCode > 0 ) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_lpaManagerAuthenticateClientSendRequest() => HTTP Request return httpCode=%ld", httpCode); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerAuthenticateClientSendRequest() => HTTP Request return invalid httpCode!"); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, ">> HTTP response: %s", ptrHttpAuthClientResp); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid response!"); + lpaError = LPA_ERROR_AUTHENTICATE_CLIENT_EXCHANGE; + + lpaCoreMemoryFree(ptrHttpAuthClientResp); + ptrHttpAuthClientResp = NULL; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Server communication issue (ptrHttpAuthClientResp is NULL)"); + lpaError = LPA_ERROR_AUTHENTICATE_CLIENT_EXCHANGE; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "No enough memory to manage authClientSmdpAddr!"); + lpaError = LPA_ERROR_INSUFFICIENT_BUFFER; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Unable to create CJSON object!"); + lpaError = LPA_ERROR_INSUFFICIENT_BUFFER; + } + + cJSON_Delete(jsonObject); + jsonObject = NULL; + + // do memory cleanup DAVY + if (ptrBufferJSON != NULL) + { + lpaCoreMemoryFree(ptrBufferJSON); + ptrBufferJSON = NULL; + } + + //httpMediaManagerHttpExecuteCleanup(); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "No enough memory to create CJSON object!"); + lpaError = LPA_ERROR_INSUFFICIENT_BUFFER; + } + } + else + lpaError = LPA_ERROR_INVALID_PARAMETER; + + if (ptrLpaError != NULL) + *ptrLpaError = lpaError; + + return ptrHttpAuthClientResp; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +LPA_API_ERROR _lpaManagerAuthenticateClientCheckTransactionId(cJSON* ptrcjsonHttpAuthClientResp, const char* ptrTransactionId) +{ + LPA_API_ERROR lpaError = LPA_NO_ERROR; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_lpaManagerAuthenticateClientCheckTransactionId..."); + + if (ptrcjsonHttpAuthClientResp != NULL && ptrTransactionId != NULL) + { + cJSON* ptrcJSONItem_TransactionID = cJSON_GetObjectItem(ptrcjsonHttpAuthClientResp, "transactionId"); + char* ptrServerTransactionId = NULL; + if(ptrcJSONItem_TransactionID != NULL) + { + ptrServerTransactionId = cJSON_GetStringValue(ptrcJSONItem_TransactionID); + ptrcJSONItem_TransactionID = NULL; // Enough to free it + } + + if (ptrServerTransactionId != NULL) + { + if (strlen(ptrServerTransactionId) < LPA_TRANSACTION_ID_MAX_SIZE) + { + if (strcmp(ptrTransactionId, ptrServerTransactionId) == 0) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "transactionId checking OK"); + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Incorrect transactionId!"); + lpaError = LPA_ERROR_INVALID_TRANSACTIONID; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to get transactionId from server"); + lpaError = LPA_ERROR_INVALID_TRANSACTIONID; + } + + ptrServerTransactionId = NULL; // No need to free it!!! + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to get transactionId from server"); + lpaError = LPA_ERROR_INVALID_TRANSACTIONID; + } + + } + else + lpaError = LPA_ERROR_INVALID_PARAMETER; + + return lpaError; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +LPA_API_ERROR _lpaManagerAuthenticateClientExtractAllDataFromCJSON(cJSON* ptrcjsonHttpAuthClientResp, ptr_serverData p_serverData) +{ + LPA_API_ERROR lpaError = LPA_NO_ERROR; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_lpaManagerAuthenticateClientExtractAllDataFromCJSON..."); + + // Reminder: Used p_serverData members (_smdpSigned2, _smdpSignature2, _profileMetadata & _smdpCertificate) not checked her because allocated / filled here and + // shall be NULL at this time + if (ptrcjsonHttpAuthClientResp != NULL && p_serverData != NULL) + { + if (lpaError == LPA_NO_ERROR) + { + lpaError = _lpaManagerAuthenticateClientExtractDataFromCJSON(ptrcjsonHttpAuthClientResp, &(p_serverData->_smdpSigned2), + LPA_AUTHENTICATE_CLIENT_SMDP_SIGNED2_MAX_SIZE, "smdpSigned2"); + } + + if (lpaError == LPA_NO_ERROR) + { + lpaError = _lpaManagerAuthenticateClientExtractDataFromCJSON(ptrcjsonHttpAuthClientResp, &(p_serverData->_smdpSignature2), + LPA_AUTHENTICATE_CLIENT_SMDP_SIGNATURE2_MAX_SIZE, "smdpSignature2"); + } + + if (lpaError == LPA_NO_ERROR) + { + lpaError = _lpaManagerAuthenticateClientExtractDataFromCJSON(ptrcjsonHttpAuthClientResp, &(p_serverData->_profileMetadata), + LPA_AUTHENTICATE_CLIENT_PROFILE_METADATA_MAX_SIZE, "profileMetadata"); + } + + if (lpaError == LPA_NO_ERROR) + { + lpaError = _lpaManagerAuthenticateClientExtractDataFromCJSON(ptrcjsonHttpAuthClientResp, &(p_serverData->_smdpCertificate), + LPA_AUTHENTICATE_CLIENT_SMDP_CERTIFICATE_MAX_SIZE, "smdpCertificate"); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "ptrcjsonHttpAuthClientResp or/and p_serverData NULL!!"); + lpaError = LPA_ERROR_AUTHENTICATE_CLIENT_EXCHANGE; + } + + + return lpaError; +} + +/** + * Parse Base64 JSON item from server Authenticate Client JSON response and store item in LPA_SERVER_DATA field, in RawDataObject hex format + * @param ptrcjsonHttpAuthClientResp Pointer on JSON response to parse + * @param ptrExtractedField Pointer on address of LPA_SERVER_DATA field who will receive extracted item, RawDataObject hex format + * @param extractedFieldSizeMax Maximum size allowed for extracted item + * @param ptrJSONname Name of item to parse from JSON response + * @return LPA_NO_ERROR if operation is OK, else LPA_ERROR_AUTHENTICATE_CLIENT_EXCHANGE + */ +LPA_API_ERROR _lpaManagerAuthenticateClientExtractDataFromCJSON(cJSON* ptrcjsonHttpAuthClientResp, RawDataObject** ptrExtractedField, size_t extractedFieldSizeMax, const char* ptrJSONname) +{ + LPA_API_ERROR lpaError = LPA_NO_ERROR; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_lpaManagerAuthenticateClientExtractDataFromCJSON..."); + + // *ptrBuffer can be NULL because not yet allocated + if (ptrcjsonHttpAuthClientResp != NULL && extractedFieldSizeMax > 0 && ptrJSONname != NULL) + { + char * ptrBindata = NULL; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Extracting data for <%s> ...", ptrJSONname); + + cJSON* ptrcJsonName = cJSON_GetObjectItem(ptrcjsonHttpAuthClientResp, ptrJSONname); + if (ptrcJsonName != NULL) + { + ptrBindata = cJSON_GetStringValue(ptrcJsonName); + ptrcJsonName = NULL; // Enough to free it with JSON library + + if(ptrBindata != NULL) + { + *ptrExtractedField = rawDataObject_createFromBase64(ptrBindata, strlen(ptrBindata), extractedFieldSizeMax); + if(*ptrExtractedField != NULL) + { + if(((*ptrExtractedField)->rawDataSize * 2) < sizeof(_bufferFormatLogMessage)) + { + if (formatBytesToHexaString((*ptrExtractedField)->rawData, (*ptrExtractedField)->rawDataSize, _bufferFormatLogMessage, sizeof(_bufferFormatLogMessage)) > 0) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "%s: %s ", ptrJSONname, _bufferFormatLogMessage); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "%s ...", ptrJSONname); + } + else + { + // For long data exceeding _bufferFormatLogMessage, avoid "Name ..." if conversion failed due to text buffer size + lpaCoreLogAppendByteArray(SDK_LOG_LEVEL_DEBUG, NULL, ptrJSONname, (*ptrExtractedField)->rawData, (*ptrExtractedField)->rawDataSize); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to decode '%s' from base64 or it's size exceed maximum allowed!", ptrJSONname); + lpaError = LPA_ERROR_AUTHENTICATE_CLIENT_EXCHANGE; + } + + ptrBindata = NULL; // Enough to free it with JSON library + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to parse '%s' from JSON object!", ptrJSONname); + lpaError = LPA_ERROR_AUTHENTICATE_CLIENT_EXCHANGE; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "'%s' not found on JSON response", ptrJSONname); + lpaError = LPA_ERROR_AUTHENTICATE_CLIENT_EXCHANGE; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "lpaManagerAuthenticateClientExtractDataFromCJSON: One or more parameter NULL!!"); + lpaError = LPA_ERROR_AUTHENTICATE_CLIENT_EXCHANGE; + } + + return lpaError; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** + * Send notification to SM-DP+ server and check reception acknowledgment from it. + * @param ptrSmdpAddr Pointer on SM-DP+ address + * @param smdpAddrSize Size of SM-DP+ address + * @param ptrPendingNotification Pointer on Pending Notification data, string format + * @param ptrLpaEventCallback Pointer on Callback used to manage messaging events + * @param ptrNormalAcknowledge Pointer on boolean returning if acknowledge was normal (True) or performed with error + * @return True if server acknowledge reception of notification (http code 204 OK or 200 with error data) else false + */ +bool lpaManagerES9Plus_HandleNotification(const char* ptrSmdpAddr, size_t smdpAddrSize, const unsigned char* ptrPendingNotification, const LPA_EventCallback* ptrLpaEventCallback, bool * ptrNormalAcknowledge) +{ + bool res = false; + cJSON* jsonObject = cJSON_CreateObject(); + char * httpServerResp = NULL; + bool isSuccess = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "ES9plus handleNotification..."); + if (ptrPendingNotification != NULL && ptrSmdpAddr != NULL && smdpAddrSize > 0 && ptrNormalAcknowledge != NULL) + { + // This "Normal acknowledge" status flag is needed in case of loading of multiple profiles by SM-DS + // Need to know if API error code LPA_ERROR_SERVER_RETURN_ERROR_STATUS is issued now or while processing a previous profile + *ptrNormalAcknowledge = false; + + if(jsonObject != NULL) + { + cJSON_AddItemToObject(jsonObject, "pendingNotification", cJSON_CreateString((char*)ptrPendingNotification)); + + char* buffer = cJSON_Print(jsonObject); + cJSON_Delete(jsonObject); + jsonObject = NULL; + + if(buffer != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, ">> HTTP request %s\n", buffer); + + char notificationSmdpAddr[LPA_ADDRESS_MAX_SIZE]; + memset(¬ificationSmdpAddr, 0, sizeof(notificationSmdpAddr)); + if (smdpAddrSize + strlen(HANDLE_NOTIFICATION_PATH) < LPA_ADDRESS_MAX_SIZE) + { + memcpy(notificationSmdpAddr, ptrSmdpAddr, smdpAddrSize); + memcpy(notificationSmdpAddr + smdpAddrSize, HANDLE_NOTIFICATION_PATH, strlen(HANDLE_NOTIFICATION_PATH)); + + long httpCode = 0; + httpServerResp = lpaManagerES9Plus_ExecutePost(notificationSmdpAddr, buffer, &isSuccess, &httpCode, ptrLpaEventCallback); + + if (isSuccess) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerES9Plus_ExecutePost() return true (httpCode=%ld)", httpCode); + + switch (httpCode) + { + case 204: + // HTTP Code 204 => No data expected + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Success to send notification to server and get the status code (No data expected)"); + *ptrNormalAcknowledge = true; + res = true; + break; + + case 200: + // HTTP Code 200 => data expected + if (httpServerResp != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "HTTP Code 200 with data always present on error case (on notification management). Try to retrieve error code."); + + // Process data returned to retrieve error code from server + cJSON* cjson = cJSON_Parse(httpServerResp); + if (cjson != NULL) + { + if (_checkJSONresponseStatusSuccessful(cjson, ptrLpaEventCallback)) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "NOTE: No error reported in JSON object..."); + + cJSON_Delete(cjson); + cjson = NULL; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "json pack into cjson error..."); + + // By all the way even a return with an error is considered as an acknowledgment from the server, so return true + res = true; + lpaSetErrorCode(LPA_ERROR_SERVER_RETURN_ERROR_STATUS); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "HTTP Code 200 without data!"); + lpaSetErrorCode(LPA_ERROR_FAILED_SEND_NOTIFICATION_OR_NOT_GET_STATUS_CODE); + } + break; + + default: + if (httpCode >= 200 && httpCode < 300) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "handleNotification() => Other 2xx HTTP Code not authorized for Handle Notification!"); + lpaSetErrorCode(LPA_ERROR_FAILED_SEND_NOTIFICATION_OR_NOT_GET_STATUS_CODE); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "handleNotification() => Not 2xx HTTP Code "); + lpaSetErrorCode(LPA_ERROR_FAILED_SEND_NOTIFICATION_OR_NOT_GET_STATUS_CODE); + } + break; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Unable to send successfully notification to server"); + lpaSetErrorCode(LPA_ERROR_FAILED_SEND_NOTIFICATION_OR_NOT_GET_STATUS_CODE); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "No enough memory to update pirNotiSmdpAddr!"); + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + + // do memory cleanup + if (buffer != NULL) + { + lpaCoreMemoryFree(buffer); + buffer = NULL; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to retrieve http request from JSON object!"); + lpaSetErrorCode(LPA_ERROR_CJSON_PARSE_FAILURE); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Cannot create JSON object jsonObject!"); + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + httpMediaManagerHttpExecuteCleanup(); + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +bool lpaManagerES9Plus_EventRetrieval(const char* ptrTransactionId, const LPA_EventCallback* ptrLpaEventCallback, const char* ptrSmdsAddress, const unsigned char* ptrAuthenticateServerResponse, EVENT_RECORD_LIST* ptrEventRecordList) +{ + bool res = false; + char* httpResp = NULL; + bool isSuccess = false; + + if (ptrTransactionId != NULL && ptrSmdsAddress != NULL && ptrAuthenticateServerResponse != NULL && ptrEventRecordList != NULL) { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerEventRetrieval..."); + + cJSON* jsonObject = cJSON_CreateObject(); + if(jsonObject != NULL) + { + cJSON_AddItemToObject(jsonObject, "transactionId", cJSON_CreateString(ptrTransactionId)); + cJSON_AddItemToObject(jsonObject, "authenticateServerResponse", cJSON_CreateString((char*)ptrAuthenticateServerResponse)); + char* buffer = cJSON_Print(jsonObject); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, ">> HTTP request %s\n ", buffer); + cJSON_Delete(jsonObject); + jsonObject = NULL; + + char anthClientSmdsAddr[LPA_ADDRESS_MAX_SIZE]; + memset(&anthClientSmdsAddr, 0, sizeof(anthClientSmdsAddr)); + if ((strlen(ptrSmdsAddress) + strlen(AUTHENTICATE_CLIENT_PATH))< LPA_ADDRESS_MAX_SIZE) + { + memcpy(anthClientSmdsAddr, ptrSmdsAddress, strlen(ptrSmdsAddress)); + memcpy(anthClientSmdsAddr + strlen(ptrSmdsAddress), AUTHENTICATE_CLIENT_PATH, strlen(AUTHENTICATE_CLIENT_PATH)); + + long httpCode = 0; + httpResp = lpaManagerES9Plus_ExecutePost(anthClientSmdsAddr, buffer, &isSuccess, &httpCode, ptrLpaEventCallback); + + if (httpResp != NULL && isSuccess) + { + if (httpCode > 0) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerEventRetrieval() => HTTP Request return httpCode=%ld", httpCode); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "lpaManagerEventRetrieval() => HTTP Request return invalid httpCode!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "<< HTTP response %s \n ", httpResp); + cJSON* cjson = cJSON_Parse(httpResp); + + if (cjson == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "json pack into cjson error..."); + lpaSetErrorCode(LPA_ERROR_CJSON_PARSE_FAILURE); + + if (buffer != NULL) + { + lpaCoreMemoryFree(buffer); + buffer = NULL; + } + httpMediaManagerHttpExecuteCleanup(); + return res; + } + else + { + + if (!_checkJSONresponseStatusSuccessful(cjson, ptrLpaEventCallback)) + { + _clearJsonAndBuffer(cjson, buffer); + cjson = NULL; + buffer = NULL; + httpMediaManagerHttpExecuteCleanup(); + return res; + } + + cJSON *eventEntries = cJSON_GetObjectItem(cjson, "eventEntries"); + + if (eventEntries != NULL) + { + int i; + int count = cJSON_GetArraySize(eventEntries); + ptrEventRecordList->countEvent = count; + if (count == 0) + { + // + } + else + { + for (i = 0; i < count; i++) + { + cJSON *item = cJSON_GetArrayItem(eventEntries, i); + + if (item != NULL) + { + char* tempstr = NULL; + cJSON* ptrcJSONItem_Retrieval = cJSON_GetObjectItem(item, "eventId"); + if(ptrcJSONItem_Retrieval != NULL) + tempstr = cJSON_GetStringValue(ptrcJSONItem_Retrieval); + + if (tempstr != NULL && strlen(tempstr) < LPA_MATCHING_ID_SIZE) + { + memcpy(ptrEventRecordList->eventRecordList[i].eventId, tempstr, strlen(tempstr)); + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "the eventId: %s", ptrEventRecordList->eventRecordList[i].eventId); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to get eventId"); + lpaSetErrorCode(LPA_ERROR_INVALID_EVENT_ID); + } + + tempstr = NULL; + ptrcJSONItem_Retrieval = cJSON_GetObjectItem(item, "rspServerAddress"); + if(ptrcJSONItem_Retrieval != NULL) + { + tempstr = cJSON_GetStringValue(ptrcJSONItem_Retrieval); + ptrcJSONItem_Retrieval = NULL; + } + + if (tempstr != NULL && strlen(tempstr) < LPA_SMDP_ADDRESS_SIZE){ + memcpy(ptrEventRecordList->eventRecordList[i].rspServerAddress, tempstr, strlen(tempstr)); + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "the rspServerAddress: %s", ptrEventRecordList->eventRecordList[i].rspServerAddress); + tempstr = NULL; // Enough to free it + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to get rspServerAddress"); + lpaSetErrorCode(LPA_ERROR_INVALID_RSP_SERVER_ADDRESS); + } + + // Cleanup + item = NULL; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to get event entries list"); + lpaSetErrorCode(LPA_ERROR_INVALID_EVENT_ENTRIES); + } + + } + + } + eventEntries = NULL; // Enough to free it + } + else + { + lpaSetErrorCode(LPA_ERROR_INVALID_EVENT_ENTRIES); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "JSON key \"eventEntries\" not found"); + } + cJSON_Delete(cjson); + cjson = NULL; + + res = true; + }// end of cjson not NULL + + } + else + { + // Enter here match to an error case or response type not expected here (Example 204) + // Set an error if not already performed by lpaManagerES9Plus_ExecutePost() + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Server communication error detected!"); + lpaSetErrorCode(LPA_ERROR_SERVER_COMMUNICATION_ISSUE); + } + + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, " Invalid Address"); + + // do memory cleanup + if (buffer != NULL) + { + lpaCoreMemoryFree(buffer); + buffer = NULL; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Cannot create JSON object jsonObject!"); + lpaSetErrorCode(LPA_ERROR_INSUFFICIENT_BUFFER); + } + + } + else{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Invalid parameter"); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + httpMediaManagerHttpExecuteCleanup(); + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** + * Return true if JSON object "status" key = "Executed-Success" or "eventEntries" key found + * @param cjson JSON object to evaluate + * @return Status of checking + */ +bool _checkJSONresponseStatusSuccessful(cJSON* cjson, const LPA_EventCallback* ptrLpaEventCallback) +{ + bool res = false; + + cJSON* header = NULL; + cJSON* functionExecutionStatus = NULL; + cJSON* statusCodeData = NULL; + char* status = NULL; + char* subcode = NULL; + char* rescode = NULL; + + if(cjson != NULL) + { + if (cJSON_HasObjectItem(cjson, "header")) + { + header = cJSON_GetObjectItem(cjson, "header"); + functionExecutionStatus = cJSON_GetObjectItem(header, "functionExecutionStatus"); + + if (functionExecutionStatus != NULL) + { + cJSON* ptrcJSON_status = cJSON_GetObjectItem(functionExecutionStatus, "status"); + + if (ptrcJSON_status == NULL ) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "no Status"); + return res; + } + + status = cJSON_GetStringValue(ptrcJSON_status); + if (status != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "_checkJSONresponseStatusSuccessful(): status: %s ", status); + + // Normally we shall no have case sensitive comparison problems, but some servers are not correctly programmed + if (compareEqualStringIgnoringCase(status, "Executed-Success")) + res = true; + + statusCodeData = cJSON_GetObjectItem(functionExecutionStatus, "statusCodeData"); + if (statusCodeData != NULL) + { + cJSON* ptrcJSON_subjectCode = cJSON_GetObjectItem(statusCodeData, "subjectCode"); + cJSON* ptrcJSON_reasonCode = cJSON_GetObjectItem(statusCodeData, "reasonCode"); + + subcode = (ptrcJSON_subjectCode != NULL ? cJSON_GetStringValue(ptrcJSON_subjectCode) : NULL); + rescode = (ptrcJSON_reasonCode != NULL ? cJSON_GetStringValue(ptrcJSON_reasonCode) : NULL); + + + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "_checkJSONresponseStatusSuccessful(): subjectCode: %s reasonCode: %s", + (subcode != NULL ? subcode : "N/A"), (rescode != NULL ? rescode : "N/A")); + + if (ptrLpaEventCallback != NULL && (subcode != NULL || rescode != NULL) ) + { + if (ptrLpaEventCallback->_lpaEventExecutionError != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "Creating Notification Error..."); + LPA_EVENT_EXECUTION_ERROR_INFO eventExecutionErrorInfo; + memset(&eventExecutionErrorInfo, 0x00, sizeof(LPA_EVENT_EXECUTION_ERROR_INFO)); + + eventExecutionErrorInfo.executionErrorType = LPA_EVENT_EXECUTION_SERVER_ERROR_TYPE; + eventExecutionErrorInfo.detailErrorMask = LPA_EVENT_EXECUTION_ERROR_NO_DETAIL_MASK; // By default + + if (subcode != NULL) + { + eventExecutionErrorInfo.detailErrorMask |= LPA_EVENT_EXECUTION_ERROR_SUBJECT_CODE_MASK; + eventExecutionErrorInfo.ptrErrorSubjectCode = subcode; + } + + if (rescode != NULL) + { + eventExecutionErrorInfo.detailErrorMask |= LPA_EVENT_EXECUTION_ERROR_REASON_CODE_MASK; + eventExecutionErrorInfo.ptrErrorReasonCode = rescode; + } + + if (eventExecutionErrorInfo.detailErrorMask != LPA_EVENT_EXECUTION_ERROR_NO_DETAIL_MASK) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "Sending Notification Error to LPA application..."); + ptrLpaEventCallback->_lpaEventExecutionError(ptrLpaEventCallback->_appParameter, &eventExecutionErrorInfo); + } + } + } + + // Cleanup + ptrcJSON_subjectCode = NULL; + ptrcJSON_reasonCode = NULL; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_checkJSONresponseStatusSuccessful(): \"status\" value string cannot be retrieved."); + + // Cleanup + functionExecutionStatus = NULL; + ptrcJSON_status = NULL; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "_checkJSONresponseStatusSuccessful(): No functionExecutionStatus"); + + // Cleanup + header = NULL; + + } + else + if (cJSON_HasObjectItem(cjson, "eventEntries")) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "_checkJSONresponseStatusSuccessful(): eventEntries found => OK"); + res = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "_checkJSONresponseStatusSuccessful(): No header"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_checkJSONresponseStatusSuccessful(): Invalid parameter: JSON object NULL!"); + + return res; +} + + +/** + * Return true if error code returned in JSON object match Subject Code and Reason Code specified + * @param p_cjson JSON object to evaluate + * @param p_subjectCode Subject Code to compare, string format + * @param p_reasonCode Reason Code to compare, string format + * @return Status of checking + */ +bool _checkJSONresponseErrorCode(const cJSON* p_cjson, const char * p_subjectCode, const char * p_reasonCode) +{ + bool res = false; + + cJSON* header = NULL; + cJSON* functionExecutionStatus = NULL; + cJSON* statusCodeData = NULL; + char* subcode = NULL; + char* rescode = NULL; + + if((p_cjson != NULL) && (p_subjectCode != NULL) && (p_reasonCode != NULL)) + { + if (cJSON_HasObjectItem(p_cjson, "header")) + { + header = cJSON_GetObjectItem(p_cjson, "header"); + functionExecutionStatus = cJSON_GetObjectItem(header, "functionExecutionStatus"); + + if (functionExecutionStatus != NULL) + { + statusCodeData = cJSON_GetObjectItem(functionExecutionStatus, "statusCodeData"); + if (statusCodeData != NULL) + { + cJSON* ptrcJSON_subjectCode = cJSON_GetObjectItem(statusCodeData, "subjectCode"); + cJSON* ptrcJSON_reasonCode = cJSON_GetObjectItem(statusCodeData, "reasonCode"); + + subcode = (ptrcJSON_subjectCode != NULL ? cJSON_GetStringValue(ptrcJSON_subjectCode) : NULL); + rescode = (ptrcJSON_reasonCode != NULL ? cJSON_GetStringValue(ptrcJSON_reasonCode) : NULL); + + if((subcode != NULL) && (rescode != NULL)) + { + res = (strcmp(subcode, p_subjectCode) == 0) ? true : false; + if(res) + res = (strcmp(rescode, p_reasonCode) == 0) ? true : false; + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "_checkJSONresponseErrorCode(): subjectCode: %s reasonCode: %s - Check status = %s", + (subcode != NULL ? subcode : "N/A"), (rescode != NULL ? rescode : "N/A"), (res ? "True" : "False")); + + // Cleanup + statusCodeData = NULL; + ptrcJSON_subjectCode = NULL; + ptrcJSON_reasonCode = NULL; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "_checkJSONresponseErrorCode(): No statusCodeData"); + + // Cleanup + functionExecutionStatus = NULL; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "_checkJSONresponseErrorCode(): No functionExecutionStatus"); + + // Cleanup + header = NULL; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "_checkJSONresponseErrorCode(): No header"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_checkJSONresponseErrorCode(): Invalid parameter NULL detected!"); + + return res; +} + + +void _clearJsonAndBuffer(cJSON * ptrcjson, char *ptrBuffer) +{ + if (ptrcjson != NULL) + { + cJSON_Delete(ptrcjson); + ptrcjson = NULL; + } + + if (ptrBuffer != NULL) + { + lpaCoreMemoryFree(ptrBuffer); + ptrBuffer = NULL; + } +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** + * Submit Cancel Session request to SM-DP server + * @param transactionID TransactionID of current server session, string format + * @param ptrCancelSessionResp Pointer on CANCEL_SESSION_RESPONSE object containing cancelSessionResponse issued by eUICC + * @return True if operations OK and server response OK + */ +bool lpaManagerES9plus_CancelSession(const char * transactionID, CANCEL_SESSION_RESPONSE * ptrCancelSessionResp, const char* ptrSmdpAddress, const LPA_EventCallback* ptrLpaEventCallback) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerES9plus_CancelSession..."); + + if ((transactionID != NULL) && (strlen(transactionID) > 0) && (strlen(transactionID) < LPA_TRANSACTION_ID_MAX_SIZE) && (ptrCancelSessionResp != NULL) && (ptrSmdpAddress != NULL)) + { + // Reminder: Request = BF41 L cancelSesionResponseOk + + // We use response data directly given by the eUICC instead of cancelSessionResponseOK object because it is already encapsulated in BF41 TLV + if ((ptrCancelSessionResp->cancelSessionResponse_RawDataSize > 0) && (ptrCancelSessionResp->resultOK == true)) + { + if(_lpaManagerES9SendCancelSession(transactionID, ptrCancelSessionResp, ptrSmdpAddress, ptrLpaEventCallback)) + { + res = true; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaManagerES9plus_CancelSession: Request sending is successful."); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "lpaManagerES9plus_CancelSession: Request sending failed."); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "lpaManagerES9plus_CancelSession: Invalid cancelSessionResponse object."); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "lpaManagerES9plus_CancelSession: Invalid parameter."); + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + + + return res; +} + +///////////////////////////////////////////// +// +///////////////////////////////////////////// + +/** + * Build server request (JSON object) and send it to server + * @param transactionID Input, TransactionID of current server session, string format + * @param ptrCancelSessionResp Pointer on CANCEL_SESSION_RESPONSE object containing cancelSessionResponse issued by eUICC + * @param ptrSmdpAddress Pointer on SM-DP server address, string format + * @return true if sending is successful + */ +bool _lpaManagerES9SendCancelSession(const char * transactionID, CANCEL_SESSION_RESPONSE * ptrCancelSessionResp, const char* ptrSmdpAddress, const LPA_EventCallback* ptrLpaEventCallback) +{ + bool res = false; + bool isExchangeSuccess = false; + size_t cancelSessionResponseBase64size = 0; + long httpCode = 0; + char* httpServerResp = NULL; + size_t sizeBase64 = 0; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_lpaManagerES9SendCancelSession..."); + + // Check input parameters before building + if ((transactionID != NULL) && (strlen(transactionID) > 0) && (strlen(transactionID) < LPA_TRANSACTION_ID_MAX_SIZE) && (ptrCancelSessionResp != NULL) && (ptrSmdpAddress != NULL)) + { + if ((ptrCancelSessionResp->cancelSessionResponse_RawDataSize > 0) && (ptrCancelSessionResp->resultOK == true)) + { + // Converts cancelSessionResponse in Base64 + // Size "original_byte_object * 2" is enough, Base64 will be always smaller than ASCII translation. + sizeBase64 = ptrCancelSessionResp->cancelSessionResponse_RawDataSize * 2; + char * cancelSessionResponseBase64 = lpaCoreMemoryAlloc(sizeBase64); + if (cancelSessionResponseBase64 != NULL) + { + // Turnaround to avoid problems with Base64 conversion that does not add \0 character at the end of Base64 object + // \0 is needed by cJSON_CreateString() that needs a string as entry parameter + memset(cancelSessionResponseBase64, 0, sizeBase64); + + if (base64_encode(ptrCancelSessionResp->cancelSessionResponse_RawData, ptrCancelSessionResp->cancelSessionResponse_RawDataSize, cancelSessionResponseBase64, &cancelSessionResponseBase64size, sizeBase64)) + { + // Build JSON object request + cJSON* jsonObject = cJSON_CreateObject(); + if (jsonObject != NULL){ + cJSON_AddItemToObject(jsonObject, "transactionId", cJSON_CreateString(transactionID)); + cJSON_AddItemToObject(jsonObject, "cancelSessionResponse", cJSON_CreateString(cancelSessionResponseBase64)); + char* requestBuffer = cJSON_Print(jsonObject); + cJSON_Delete(jsonObject); + jsonObject = NULL; + if (requestBuffer != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, ">> HTTP request %s\n ", requestBuffer); + + // Prepare sending + char smdpServerAddr[LPA_ADDRESS_MAX_SIZE]; + memset(&smdpServerAddr, 0, sizeof(smdpServerAddr)); + + if ((strlen(ptrSmdpAddress) + strlen(CANCEL_SESSION_PATH)) < LPA_ADDRESS_MAX_SIZE) + { + memcpy(smdpServerAddr, ptrSmdpAddress, strlen(ptrSmdpAddress)); + memcpy(smdpServerAddr + strlen(ptrSmdpAddress), CANCEL_SESSION_PATH, strlen(CANCEL_SESSION_PATH)); + + httpServerResp = lpaManagerES9Plus_ExecutePost(smdpServerAddr, requestBuffer, &isExchangeSuccess, &httpCode, ptrLpaEventCallback); + + if (isExchangeSuccess) + { + if (httpCode > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_lpaManagerES9SendCancelSession: HTTP Request return httpCode = %ld", httpCode); + + // Final check of server response + switch (httpCode) + { + case 204: + // HTTP Code 204 => No data expected + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerES9SendCancelSession: Confirmation JSON is missing, but server return operation successful? (http 204)."); + break; + + case 200: + // HTTP Code 200 => data expected + if (httpServerResp != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_lpaManagerES9SendCancelSession: HTTP Code 200 with data, analysing server response."); + + // Process data returned to final status from server + cJSON* cjson = cJSON_Parse(httpServerResp); + if (cjson != NULL) + { + if (_checkJSONresponseStatusSuccessful(cjson, ptrLpaEventCallback)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_lpaManagerES9SendCancelSession: Cancel Session confirmed successful by server."); + res = true; + } + else + { + lpaSetErrorCode(LPA_ERROR_FAILED_CANCEL_SESSION); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerES9SendCancelSession: Server reported an error."); + } + + cJSON_Delete(cjson); + cjson = NULL; + } + else + { + lpaSetErrorCode(LPA_ERROR_INVALID_SERVER_RESPONSE); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerES9SendCancelSession: json pack into cjson error..."); + } + } + else + // Error code already set by lpaManagerES9Plus_ExecutePost() + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "HTTP Code 200 without data!"); + break; + + default: + // Error code already set by lpaManagerES9Plus_ExecutePost() + if (httpCode >= 200 && httpCode < 300) + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerES9SendCancelSession: Other 2xx HTTP Code not authorized for Cancel Session!"); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerES9SendCancelSession: Not 2xx HTTP Code "); + break; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerES9SendCancelSession: HTTP Request return invalid httpCode!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerES9SendCancelSession: Invalid HTTP exchange!"); + + httpMediaManagerHttpExecuteCleanup(); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerES9SendCancelSession: HTTP address is too long."); + + // Memory clean + lpaCoreMemoryFree(requestBuffer); + requestBuffer = NULL; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerES9SendCancelSession: Cannot build JSON object."); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerES9SendCancelSession: Cannot create JSON object."); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerES9SendCancelSession: Cannot convert cancelSessionResponse in Base64."); + + lpaCoreMemoryFree(cancelSessionResponseBase64); + cancelSessionResponseBase64 = NULL; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerES9SendCancelSession: Cannot allocate memory for cancelSessionResponseBase64."); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerES9SendCancelSession: Invalid cancelSessionResponse object."); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_lpaManagerES9SendCancelSession: Invalid Parameters."); + + return res; +} diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/lpa_manager_helper.c b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/lpa_manager_helper.c new file mode 100755 index 000000000..ec0827773 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/lpa_manager_helper.c @@ -0,0 +1,422 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#include "lpasdk/core/lpa_manager_helper.h" +#include "lpasdk/core/lpa_manager.h" +#include "lpasdk/core/semedia_manager.h" + +#include "lpasdk/core/lpa_log.h" +#include "lpasdk/core/lpa_memory.h" +#include "lpasdk/core/util.h" +#include "lpasdk/api/lpasdk_api.h" + +static const unsigned char APDU_COMMAND_STORE_DATA_PROFILE_CASE3_HEADER[] = { 0x80, 0xE2, 0x90, 0x00, 0x00 }; +static const unsigned char APDU_COMMAND_STORE_DATA_PROFILE_CASE4_HEADER[] = { 0x80, 0xE2, 0x91, 0x00, 0x00 }; + +static unsigned char _apduResponseBytes[MAX_LPA_MANAGER_APDU_BUFFER_SIZE]; + +static char _bufferFormatLogMessage[2018]; + +static bool _addLeToApuCase4 = true; + +bool _buildAndSendApduCase4(const RawDataObject* ptrRawDataObject, uint16_t *ptrSW, unsigned char *ptrResponseApduData, size_t responseApduDataMaxSize, size_t *ptrResponseApduDataSize); + +/////////////////////////////////////////////////////////////////////////////////////////////// +// +/////////////////////////////////////////////////////////////////////////////////////////////// + +void lpaManagerHelperSetLeToAddApduCase4(bool enable) +{ + _addLeToApuCase4 = enable; +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +// +/////////////////////////////////////////////////////////////////////////////////////////////// + +bool lpaManagerHelperIsLeAddedToApduCase4() +{ + return _addLeToApuCase4; +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +// +/////////////////////////////////////////////////////////////////////////////////////////////// + +bool buildAndSendStoreDataCase3WithoutResponseData(const RawDataObject* ptrRawDataObject, uint16_t *ptrSW) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "buildAndSendStoreDataCase3WithoutResponseData(...)"); + return buildAndSendStoreDataCase3(ptrRawDataObject, ptrSW, NULL, 0, NULL); +} + +bool buildAndSendStoreDataCase3(const RawDataObject* ptrRawDataObject, uint16_t *ptrSW, unsigned char *ptrResponseApduData, size_t responseApduDataMaxSize, size_t *ptrResponseApduDataSize) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "buildAndSendStoreDataCase3(...)"); + if (ptrRawDataObject != NULL && ptrSW != NULL) + { + if (ptrRawDataObject->rawDataSize <= LPA_STORE_DATA_APDU_DATA_SIZE_MAX) + { + RawDataObject* apduStoreDataHeader = rawDataObject_create(APDU_COMMAND_STORE_DATA_PROFILE_CASE3_HEADER, sizeof(APDU_COMMAND_STORE_DATA_PROFILE_CASE3_HEADER)); + if (apduStoreDataHeader != NULL) + { + // Add data + RawDataObject* apduStoreData = rawDataObject_concat(apduStoreDataHeader, ptrRawDataObject); + if (apduStoreData != NULL) + { + size_t apduResponseMaxSize = MAX_LPA_MANAGER_APDU_BUFFER_SIZE; + + if (apduStoreData->rawDataSize > 4) + { + // Update LE + apduStoreData->rawData[4] = (unsigned char) ptrRawDataObject->rawDataSize; + + if (formatBytesToHexaString(apduStoreData->rawData, apduStoreData->rawDataSize, _bufferFormatLogMessage, sizeof(_bufferFormatLogMessage)) > 0) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "StoreData APDU (case 3): %s", _bufferFormatLogMessage); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "StoreData APDU (case 3): ..."); + + // Send APDU + if (seMediaManagerTransmitApdu(apduStoreData->rawData, apduStoreData->rawDataSize, _apduResponseBytes, &apduResponseMaxSize)) + { + if (apduResponseMaxSize >= 2) + { + // APDU successfully sent + *ptrSW = _apduResponseBytes[apduResponseMaxSize - 2] << 8 | _apduResponseBytes[apduResponseMaxSize - 1]; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "StoreData APDU SW: %04lX", *ptrSW); + res = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "APDU response too short!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "APDU sending through seMedia Manager failed!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "apduStoreData object too small: APDU not send!"); + + ERASE_RAWDATAOBJECT(apduStoreData); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "buildAndSendStoreDataCase3() - apduStoreData NULL!"); + + // Do cleanup + ERASE_RAWDATAOBJECT(apduStoreDataHeader); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "buildAndSendStoreDataCase3() - apduStoreDataHeader NULL!"); + } + else + { + // Need to split APDU on many APDU - To be developed if needed + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Sending more than one APDU for StoreDataCase3 not yet implemented"); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "buildAndSendStoreDataCase3() - Invalid NULL parameter!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "buildAndSendStoreDataCase3(...) => return %s", (res ? "true" : "false")); + + return res; +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +// +/////////////////////////////////////////////////////////////////////////////////////////////// + +bool buildAndSendStoreDataCase4WithoutResponseData(const RawDataObject* ptrRawDataObject, uint16_t *ptrSW) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "buildAndSendStoreDataCase4WithoutResponseData(...)"); + res = buildAndSendStoreDataCase4(ptrRawDataObject, ptrSW, NULL, 0, NULL); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "buildAndSendStoreDataCase4WithoutResponseData(...) => return %s", (res ? "true" : "false")); + + return res; +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +// +/////////////////////////////////////////////////////////////////////////////////////////////// + +bool buildAndSendStoreDataCase4(const RawDataObject* ptrRawDataObject, uint16_t *ptrSW, unsigned char *ptrResponseApduData, size_t responseApduDataMaxSize, size_t *ptrResponseApduDataSize) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "buildAndSendStoreDataCase4(...)"); + + // ptrResponseApduData & ptrResponseApduDataSize NULL checking is managed in buildAndSendApduCase4() + if (ptrRawDataObject != NULL && ptrSW != NULL) + { + if (ptrRawDataObject->rawDataSize > 0 && ptrRawDataObject->rawData != NULL) + { + RawDataObject* apduStoreDataHeader = rawDataObject_create(APDU_COMMAND_STORE_DATA_PROFILE_CASE4_HEADER, sizeof(APDU_COMMAND_STORE_DATA_PROFILE_CASE4_HEADER)); + if (apduStoreDataHeader != NULL) + { + if (ptrRawDataObject->rawDataSize <= LPA_STORE_DATA_APDU_DATA_SIZE_MAX) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Sending StoreData in one APDU..."); + + // add data + RawDataObject* ptrApduStoreData = rawDataObject_concat(apduStoreDataHeader, ptrRawDataObject); + if (ptrApduStoreData != NULL) + { + if (ptrApduStoreData->rawDataSize > 4) + { + // Update Lc + ptrApduStoreData->rawData[4] = (unsigned char) ptrRawDataObject->rawDataSize; + res = buildAndSendApduCase4(ptrApduStoreData, ptrSW, ptrResponseApduData, responseApduDataMaxSize, ptrResponseApduDataSize); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "buildAndSendStoreDataCase4() - apduStoreData object too small: APDU not send!"); + + // Do memory cleanup + ERASE_RAWDATAOBJECT(ptrApduStoreData); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "buildAndSendStoreDataCase4() - apduStoreData object NULL: APDU not send!"); + } + else + { + bool isLastBlock = false; + uint8_t blockNumber = 0; + size_t dataSizeAlreadySend = 0; + size_t blockSize = 0; + bool isErrorDetected = false; + + // Need to split Data on many APDU + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "Sending StoreData with more than one APDU..."); + + while (!isLastBlock) + { + + size_t remainingSize = ptrRawDataObject->rawDataSize - dataSizeAlreadySend; + if (remainingSize <= LPA_STORE_DATA_APDU_DATA_SIZE_MAX) + { + isLastBlock = true; + blockSize = remainingSize; + } + else + blockSize = LPA_STORE_DATA_APDU_DATA_SIZE_MAX; + + // add data + RawDataObject* apduStoreData = rawDataObject_concatPartially(apduStoreDataHeader, ptrRawDataObject, dataSizeAlreadySend, blockSize); + if (apduStoreData == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "buildAndSendStoreDataCase4() - Insufficient memory resources!"); + break; // Memory allocation error + } + + if (apduStoreData->rawDataSize > 4) + { + // Update P1 + if (isLastBlock) + apduStoreData->rawData[2] = 0x91; // Last block + else + apduStoreData->rawData[2] = 0x11; //Not the last block + + // Update P2 + apduStoreData->rawData[3] = blockNumber; + + // Update Lc + apduStoreData->rawData[4] = (unsigned char) blockSize; + res = buildAndSendApduCase4(apduStoreData, ptrSW, ptrResponseApduData, responseApduDataMaxSize, ptrResponseApduDataSize); + if (!res) + isErrorDetected = true; // Error when sending APDU + + dataSizeAlreadySend += blockSize; + blockNumber++; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "buildAndSendStoreDataCase4() - apduStoreData object too small: APDU not send!"); + isErrorDetected = true; + } + + // Do memory cleanup + ERASE_RAWDATAOBJECT(apduStoreData); + + if (isErrorDetected) + { + res = false; + break; + } + } + } + + // Do memory cleanup + ERASE_RAWDATAOBJECT(apduStoreDataHeader); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "buildAndSendStoreDataCase4() - Invalid NULL APDU header!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "buildAndSendStoreDataCase4() - Invalid NULL or zero length parameter!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "buildAndSendStoreDataCase4() - Invalid NULL parameter!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "buildAndSendStoreDataCase4(...) => return %s", (res ? "true" : "false")); + + return res; +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +// +/////////////////////////////////////////////////////////////////////////////////////////////// + +bool buildAndSendApduCase4(const RawDataObject* ptrRawDataObject, uint16_t *ptrSW, unsigned char *ptrResponseApduData, size_t responseApduDataMaxSize, size_t *ptrResponseApduDataSize) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "buildAndSendApduCase4(...)"); + + res = _buildAndSendApduCase4(ptrRawDataObject, ptrSW, ptrResponseApduData, responseApduDataMaxSize, ptrResponseApduDataSize); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "buildAndSendApduCase4(...) => return %s", (res ? "true" : "false")); + + return res; +} + +bool buildAndSendApduCase4Ex(const unsigned char* ptrApduC, uint16_t apduCSize, uint16_t *ptrSW, unsigned char *ptrResponseApduData, size_t responseApduDataMaxSize, size_t *ptrResponseApduDataSize) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "buildAndSendApduCase4Ex(...)"); + + // create temporary RawDataObject without dynamic allocation + RawDataObject rawDataObjectApduC; + rawDataObjectApduC.rawData = (unsigned char*) ptrApduC; + rawDataObjectApduC.rawDataSize = apduCSize; + + res = _buildAndSendApduCase4(&rawDataObjectApduC, ptrSW, ptrResponseApduData, responseApduDataMaxSize, ptrResponseApduDataSize); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "buildAndSendApduCase4Ex(...) => return %s", (res ? "true" : "false")); + + return res; +} + +bool _buildAndSendApduCase4(const RawDataObject* ptrRawDataObject, uint16_t *ptrSW, unsigned char *ptrResponseApduData, size_t responseApduDataMaxSize, size_t *ptrResponseApduDataSize) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_buildAndSendApduCase4(...)"); + + if (ptrRawDataObject != NULL && ptrSW != NULL && ptrResponseApduDataSize != NULL) + { + bool apduSend = false; + size_t apduResponseMaxSize = MAX_LPA_MANAGER_APDU_BUFFER_SIZE; + + if (!_addLeToApuCase4) + { + if (formatBytesToHexaString(ptrRawDataObject->rawData, ptrRawDataObject->rawDataSize, _bufferFormatLogMessage, sizeof(_bufferFormatLogMessage)) > 0) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "APDU (without adding Le): %s", _bufferFormatLogMessage); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "APDU (without adding Le): ..."); + + apduSend = seMediaManagerTransmitApdu(ptrRawDataObject->rawData, ptrRawDataObject->rawDataSize, _apduResponseBytes, &apduResponseMaxSize); + } + else + { + RawDataObject* rawDataObjectWithZeroFinal = NULL; + RawDataObject* apduCase4WithLe = NULL; + + // Add '00' at the end (for case 4) + unsigned char byteZero = 0x00; + + rawDataObjectWithZeroFinal = rawDataObject_create(&byteZero, 1); + if (rawDataObjectWithZeroFinal != NULL) + apduCase4WithLe = rawDataObject_concat(ptrRawDataObject, rawDataObjectWithZeroFinal); + + if (apduCase4WithLe != NULL) + { + if (formatBytesToHexaString(apduCase4WithLe->rawData, apduCase4WithLe->rawDataSize, _bufferFormatLogMessage, sizeof(_bufferFormatLogMessage)) > 0) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "APDU (case 4 with Le added): %s", _bufferFormatLogMessage); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "APDU (case 4 with Le added): ..."); + + apduSend = seMediaManagerTransmitApdu(apduCase4WithLe->rawData, apduCase4WithLe->rawDataSize, _apduResponseBytes, &apduResponseMaxSize); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Failed to build apduCase4WithLe object!"); + + // Do memory cleanup + ERASE_RAWDATAOBJECT(rawDataObjectWithZeroFinal); + ERASE_RAWDATAOBJECT(apduCase4WithLe); + } + + if (apduSend) + { + if (apduResponseMaxSize >= 2) + { + // APDU successfully sent + *ptrSW = _apduResponseBytes[apduResponseMaxSize - 2] << 8 | _apduResponseBytes[apduResponseMaxSize - 1]; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "APDU SW: %04lX", *ptrSW); + + if ((ptrResponseApduData != NULL) && (responseApduDataMaxSize > 0) && (ptrResponseApduDataSize != NULL)) + { + size_t dataSize = apduResponseMaxSize - 2; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Managing data response..."); + + // Managing data response => copy data from APDU Response + *ptrResponseApduDataSize = 0; + + if (dataSize > 0) + { + // Data available + if (dataSize <= responseApduDataMaxSize) + { + memcpy(ptrResponseApduData, _apduResponseBytes, dataSize); + *ptrResponseApduDataSize = dataSize; + res = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Data buffer size to small (Maximum allowed:%llu bytes - needed:%llu bytes)", (long long unsigned)responseApduDataMaxSize, (long long unsigned)dataSize); + } + } + else + { + // No data + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "No data available from R-APDU"); + res = true; + } + } + else + { + // Not managing data response + res = true; + } + } + else + { + apduSend = false; // SW is empty / incomplete or incorrect data (Too short to be a SW, can be data corruption or error detected at lower layer) + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Incorrect data or invalid SW or error! (Too short response < 2)"); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "APDU sending operation through seMedia failed!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_buildAndSendApduCase4() - Invalid NULL parameter!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_buildAndSendApduCase4(...) => return %s", (res ? "true" : "false")); + + return res; +} \ No newline at end of file diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/lpa_memory.c b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/lpa_memory.c new file mode 100755 index 000000000..8160c236f --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/lpa_memory.c @@ -0,0 +1,1194 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#include "lpasdk/core/lpa_memory.h" +#include "lpasdk/core/lpa_log.h" + +#ifdef LPA_SDK__MEMORY + + +#include +#include +#include + +#include "lpasdk/core/lpa_core.h" + + + // Activate it to trace (Verbose mode all memory management operation) + #ifdef LPA_SDK__MEMORY_MONITORING +static const bool _activateLogForMemoryManagementOperation = true; + #else +static const bool _activateLogForMemoryManagementOperation = false; + #endif // + +// Memory stat +// ///////////////////// + +static long _countMemoryAllocCall = 0; +static long _countMemoryFreeCall = 0; +static long _currentMemoryBlockAllocated = 0; + + +static long _currentMemoryAllocated = 0; +static long _totalMemoryAllocated = 0; + +static long _maxMemoryAllocated = 0; +static long _maxMemoryBlockAllocated = 0; + +#define INVALID_MONITORING_INDEX 0xFFFFFF + +// Simulating Memory Error if requested +// If value <= 0, do nothing +static long _generateErrIfMemoryCounterEQValue = 0; +static long _generateErrIfMemoryCounterGTValue = 0; +static long _generateErrIfMemoryCounterGEValue = 0; + +static long _generateErrIfMemorySizeRequestedEQValue = 0; +static long _generateErrIfMemorySizeRequestedGTValue = 0; +static long _generateErrIfMemorySizeRequestedGEValue = 0; + +static unsigned long long maxMemoryAllocationSize = 0; + +// Internal function +// ///////////////////// + +size_t _lpaCoreMemoryGetBlockSize(void* ptrMemoryBlock, bool* ptrIsValidMemoryBlock); + +void* _lpaCoreMemoryAlloc(size_t size, bool isAllocationSource, char* ptrFileName, int fileLine); +void* _lpaCoreMemoryRealloc(void* ptrMemoryOldBlock, size_t newSize, bool isAllocationSource, char* ptrFileName, int fileLine); +void* _lpaCoreMemoryCalloc(size_t count, size_t size, bool isAllocationSource, char* ptrFileName, int fileLine); +void _lpaCoreMemoryFree(void* ptrMemoryBlock, bool isAllocationSource, char* ptrFileName, int fileLine); + +void _memoryMonitoringBreakpointDebugger(); +bool _isSimulateMemoryErrorAllocation(size_t size); + +#define MEMORY_CONTENT_INIT_PATTERN 0xBD // Pattern used to initialize LPASDK memory block + +#endif // LPA_SDK__MEMORY + +// This function is available whatever the configuration +UT_EXPORT_DLL void lpaCoreMemoryInitialize() +{ + // Do internal module initialization (eg mutex when supported) + + #ifdef LPA_SDK__MEMORY + size_t index = 0; + size_t size_tSize = 0; + size_t unsignedLongLongSize = 0; + unsigned long long binaryWeight = 1; + + // Calculate maximum value a size_t can support to avoid possible overflow issues when calling _lpaCoreMemoryAlloc(), while taking in account header size + // Depending environment "size_t" can be the same than "unsigned long long" so need to make a specific calculation else maximum value can be false due to overflow if equal + size_tSize = sizeof(index); + unsignedLongLongSize = sizeof(maxMemoryAllocationSize); + + // Should not happen but in case of... Of course will limit the maximum allocatable memory, but this should be not a problem considering size typically used + if(size_tSize > unsignedLongLongSize) + size_tSize = unsignedLongLongSize; + + size_tSize = size_tSize * 8; + + // This calculation method will avoid overflow. binaryWeight already = 1 + maxMemoryAllocationSize = 0; + for(index = 0; index < size_tSize; index++) + { + maxMemoryAllocationSize += binaryWeight; + binaryWeight = binaryWeight << 1; // Will produce an overflow on last iteration but we do not care, this last value will be not used + } + + // Remove memory block header size, here 18 bytes + maxMemoryAllocationSize -= 18; + #endif // LPA_SDK__MEMORY +} + +#ifdef LPA_SDK__MEMORY + +#ifdef LPA_SDK__MEMORY_MONITORING + + void _lpaCoreMemoryCheckMemoryAllocated(bool trace); + + #define MAX_MEMORY_BLOCK_INFORMATION 4096 + #define MAX_MEMORY_ALLOCATION_INFORMATION 1024 + #define ALLOCATION_FILE_NAME_SIZE 64 + + // Internal structure definition + // ///////////////////// + + // Contains @ of memory block allocated + entry in MEMORY_ALLOCATION_INFORMATION table (for managing memory leak) + typedef struct + { + void* memoryBlockAllocated; // Internal @ of Memory block allocated + size_t memorySize; // memory size requested + size_t indexMemoryAllocationInformation; // -> In MEMORY_ALLOCATION_INFORMATION table + } MEMORY_BLOCK_INFORMATION; + + // Contains memory allocation source + typedef struct + { + char allocationFileName[ALLOCATION_FILE_NAME_SIZE]; + size_t allocationLine; + size_t allocationCounter; + } MEMORY_ALLOCATION_INFORMATION; + + // Array that contains + MEMORY_BLOCK_INFORMATION* _ptrMemoryBlockInformation = NULL; // MAX_MEMORY_BLOCK_INFORMATION; + MEMORY_ALLOCATION_INFORMATION* _ptrMemoryAllocationInformation = NULL; //MAX_MEMORY_ALLOCATION_INFORMATION]; + + size_t _addMemoryAllocationMonitoring(char* ptrFileName, int fileLine, void* ptrMem, size_t size); + void _freeMemoryAllocationMonitoring(void *ptrMemoryBlock, size_t index); + void _initMemoryAllocationMonitoring(); + void _writeLogMemoryAllocationBlockBefore(void* ptrMemoryBlock); + + bool _getMemoryAllocationInformation(MEMORY_ALLOCATION_INFORMATION* ptrMemoryAllocationInformation, size_t index); + + // Monitoring of allocation source + //////////////////////////////////////////////////// + + UT_EXPORT_DLL void* lpaCoreMemoryMonitorAlloc(char* ptrFilename, int line, size_t size) + { + return _lpaCoreMemoryAlloc(size, true, ptrFilename, line); + } + + ////////////////////////////////////////////////////////////// + // + ////////////////////////////////////////////////////////////// + + UT_EXPORT_DLL void* lpaCoreMemoryMonitorCalloc(char* ptrFilename, int line, size_t count, size_t size) + { + return _lpaCoreMemoryCalloc(count, size, true, ptrFilename, line); + } + + ////////////////////////////////////////////////////////////// + // + ////////////////////////////////////////////////////////////// + + UT_EXPORT_DLL void* lpaCoreMemoryMonitorRealloc(char* ptrFilename, int line, void* ptrMemoryOldBlock, size_t newSize) + { + return _lpaCoreMemoryRealloc(ptrMemoryOldBlock, newSize, true, ptrFilename, line); + } + + ////////////////////////////////////////////////////////////// + // free memory + ////////////////////////////////////////////////////////////// + + UT_EXPORT_DLL void lpaCoreMemoryMonitorFree(char* ptrFilename, int line, void* ptrMemoryBlock) + { + _lpaCoreMemoryFree(ptrMemoryBlock, true, ptrFilename, line); + } + +#endif // LPA_SDK__MEMORY_MONITORING + +// For unitary test purpose +UT_EXPORT_DLL void lpaCoreMemoryResetParamGenerateErr() +{ + // EQ = Equal + // GT = Greater + // GE = Greater or Equal + + // Trigger on counters + _generateErrIfMemoryCounterEQValue = 0; + _generateErrIfMemoryCounterGTValue = 0; + _generateErrIfMemoryCounterGEValue = 0; + + // Trigger on sizes + _generateErrIfMemorySizeRequestedEQValue = 0; + _generateErrIfMemorySizeRequestedGTValue = 0; + _generateErrIfMemorySizeRequestedGEValue = 0; +} + +// For unitary test purpose +UT_EXPORT_DLL bool lpaCoreMemorySetParamGenerateErr(uint8_t param, long value) +{ + bool result = false; + + switch (param) + { + case LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_COUNTER_EQ: + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKMEM] update LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_COUNTER_EQ <%ld> to <%ld>", _generateErrIfMemoryCounterEQValue, value ); + _generateErrIfMemoryCounterEQValue = value; + result = true; + break; + + case LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_COUNTER_GT: + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKMEM] update LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_COUNTER_GT <%ld> to <%ld>", _generateErrIfMemoryCounterGTValue, value); + _generateErrIfMemoryCounterGTValue = value; + result = true; + break; + + case LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_COUNTER_GE: + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKMEM] update LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_COUNTER_GE <%ld> to <%ld>", _generateErrIfMemoryCounterGEValue, value); + _generateErrIfMemoryCounterGEValue = value; + result = true; + break; + + /////////////////////////////////// + + case LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_SIZE_REQUESTED_EQ: + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKMEM] update LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_SIZE_REQUESTED_EQ <%ld> to <%ld>", _generateErrIfMemorySizeRequestedEQValue, value); + _generateErrIfMemorySizeRequestedEQValue = value; + result = true; + break; + + case LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_SIZE_REQUESTED_GT: + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKMEM] update LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_SIZE_REQUESTED_GT <%ld> to <%ld>", _generateErrIfMemorySizeRequestedGTValue, value); + _generateErrIfMemorySizeRequestedGTValue = value; + result = true; + break; + + case LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_SIZE_REQUESTED_GE: + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKMEM] update LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_SIZE_REQUESTED_GE <%ld> to <%ld>", _generateErrIfMemorySizeRequestedGEValue, value); + _generateErrIfMemorySizeRequestedGEValue = value; + result = true; + break; + + default: + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] lpaCoreMemorySetParamGenerateErr() => Invalid parameter %u", param); + break; + } + + return result; +} + +bool lpaCoreMemoryGetParamGenerateErr(uint8_t param, long* ptrValue) +{ + bool result = false; + + if (ptrValue != NULL) + { + switch (param) + { + case LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_COUNTER_EQ: + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKMEM] get LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_COUNTER_EQ <%ld>", _generateErrIfMemoryCounterEQValue); + *ptrValue = _generateErrIfMemoryCounterEQValue; + result = true; + break; + + case LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_COUNTER_GT: + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKMEM] get LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_COUNTER_GT <%ld>", _generateErrIfMemoryCounterGTValue); + *ptrValue = _generateErrIfMemoryCounterGTValue; + result = true; + break; + + case LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_COUNTER_GE: + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKMEM] get LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_COUNTER_GE <%ld>", _generateErrIfMemoryCounterGEValue); + *ptrValue = _generateErrIfMemoryCounterGEValue; + result = true; + break; + + /////////////////////////////////// + + case LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_SIZE_REQUESTED_EQ: + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKMEM] get LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_SIZE_REQUESTED_EQ <%ld>", _generateErrIfMemorySizeRequestedEQValue); + *ptrValue = _generateErrIfMemorySizeRequestedEQValue; + result = true; + break; + + case LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_SIZE_REQUESTED_GT: + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKMEM] get LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_SIZE_REQUESTED_GT <%ld>", _generateErrIfMemorySizeRequestedGTValue); + *ptrValue = _generateErrIfMemorySizeRequestedGTValue; + result = true; + break; + + case LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_SIZE_REQUESTED_GE: + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKMEM] get LPA_CORE_MEMORY_GENERATE_ERR_IF_MEMORY_SIZE_REQUESTED_GE <%ld>", _generateErrIfMemorySizeRequestedGEValue); + *ptrValue = _generateErrIfMemorySizeRequestedGEValue; + result = true; + break; + + default: + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] lpaCoreMemoryGetGenerateErr() => Invalid parameter %u", param); + break; + } + } + return result; +} + + #ifndef LPA_SDK__MEMORY_MONITORING + +// No monitoring of allocation source +//////////////////////////////////////////////////// + +void* lpaCoreMemoryAlloc(size_t size) +{ + return _lpaCoreMemoryAlloc(size, false, NULL, 0); +} + +////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////// + +void* lpaCoreMemoryCalloc(size_t count, size_t size) +{ + return _lpaCoreMemoryCalloc(count, size, false, NULL, 0); +} + +////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////// + +void* lpaCoreMemoryRealloc(void* ptrMemoryOldBlock, size_t newSize) +{ + return _lpaCoreMemoryRealloc(ptrMemoryOldBlock, newSize, false, NULL, 0); +} + +////////////////////////////////////////////////////////////// +// free memory +////////////////////////////////////////////////////////////// + +void lpaCoreMemoryFree(void* ptrMemoryBlock) +{ + _lpaCoreMemoryFree(ptrMemoryBlock, false, NULL, 0); +} + + + #endif // LPA_SDK__MEMORY_MONITORING NOT DEFINED + +////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////// + + #ifdef LPA_SDK__USING_EX_API +UT_EXPORT_DLL bool lpaCoreGetMemoryStatus(LPA_MEMORY_STATUS* prtMemoryStatus) +{ + bool res = false; + + if (prtMemoryStatus != NULL) + { + prtMemoryStatus->countMemoryAllocCall = _countMemoryAllocCall; + prtMemoryStatus->countMemoryFreeCall = _countMemoryFreeCall; + prtMemoryStatus->currentMemoryBlockAllocated = _currentMemoryBlockAllocated; + + prtMemoryStatus->currentMemoryAllocated = _currentMemoryAllocated; + prtMemoryStatus->totalMemoryAllocated = _totalMemoryAllocated; + + prtMemoryStatus->maxMemoryAllocated = _maxMemoryAllocated; + prtMemoryStatus->maxMemoryBlockAllocated = _maxMemoryBlockAllocated; + + res = true; + } + + return res; +} + +#endif // LPA_SDK__USING_EX_API + +////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////// + +void lpaCoreMemoryDumpStatusIntoLog() +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKMEM] === Memory status ==="); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKMEM] * countMemoryAllocCall: %ld", _countMemoryAllocCall); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKMEM] * countMemoryFreeCall: %ld", _countMemoryFreeCall); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKMEM] * currentMemoryBlockAllocated: %ld", _currentMemoryBlockAllocated); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKMEM] * currentMemoryAllocated: %ld bytes", _currentMemoryAllocated); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKMEM] * maxMemoryBlockAllocated: %ld", _maxMemoryBlockAllocated); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKMEM] * maxMemoryAllocated: %ld bytes", _maxMemoryAllocated); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKMEM] * totalMemoryAllocated: %ld bytes", _totalMemoryAllocated); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "=== ============= ==="); + +#ifdef LPA_SDK__MEMORY_MONITORING + + size_t indexEntryMemoryAlloc = 0; + size_t indexEntryMemoryBlock = 0; + + // Parse _memoryAllocationInformation to display some potential memory leak + // /////////////////////////////////////////////////////////////////////////// + if (_ptrMemoryAllocationInformation != NULL && _ptrMemoryBlockInformation != NULL) + { + for (indexEntryMemoryAlloc = 0; indexEntryMemoryAlloc < MAX_MEMORY_ALLOCATION_INFORMATION; indexEntryMemoryAlloc ++) + { + if (_ptrMemoryAllocationInformation[indexEntryMemoryAlloc].allocationCounter > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKMEM] <%llu> allocation done at %s:%llu", + (long long unsigned)_ptrMemoryAllocationInformation[indexEntryMemoryAlloc].allocationCounter, + _ptrMemoryAllocationInformation[indexEntryMemoryAlloc].allocationFileName, + (long long unsigned)_ptrMemoryAllocationInformation[indexEntryMemoryAlloc].allocationLine); + + for (indexEntryMemoryBlock = 0; indexEntryMemoryBlock < MAX_MEMORY_BLOCK_INFORMATION; indexEntryMemoryBlock ++) + { + if (_ptrMemoryBlockInformation[indexEntryMemoryBlock].indexMemoryAllocationInformation == indexEntryMemoryAlloc && _ptrMemoryBlockInformation[indexEntryMemoryBlock].memoryBlockAllocated != NULL ) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKMEM] - memory block 0x%08lX => %llu bytes", _ptrMemoryBlockInformation[indexEntryMemoryBlock].memoryBlockAllocated, + (long long unsigned)_ptrMemoryBlockInformation[indexEntryMemoryBlock].memorySize); + } + } + } + } + } + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "=== ============= ==="); +#endif // LPA_SDK__MEMORY_MONITORING +} + +////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////// + +void lpaCoreMemoryCheckMemoryAllocated() +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKMEM] === Check Memory Allocated ==="); + +#ifdef LPA_SDK__MEMORY_MONITORING + _lpaCoreMemoryCheckMemoryAllocated(true); +#endif // LPA_SDK__MEMORY_MONITORING + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "=== ============= ==="); +} + +////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////// + +bool _isSimulateMemoryErrorAllocation(size_t size) +{ + bool simulateMemoryErrorAllocation = false; + + if (!simulateMemoryErrorAllocation && _generateErrIfMemoryCounterEQValue > 0 && _countMemoryAllocCall == _generateErrIfMemoryCounterEQValue ) + simulateMemoryErrorAllocation = true; + + if (!simulateMemoryErrorAllocation && _generateErrIfMemoryCounterGTValue > 0 && _countMemoryAllocCall > _generateErrIfMemoryCounterGTValue) + simulateMemoryErrorAllocation = true; + + if (!simulateMemoryErrorAllocation && _generateErrIfMemoryCounterGEValue > 0 && _countMemoryAllocCall >= _generateErrIfMemoryCounterGEValue ) + simulateMemoryErrorAllocation = true; + + if (!simulateMemoryErrorAllocation && _generateErrIfMemorySizeRequestedEQValue > 0 && (size == ((size_t)_generateErrIfMemorySizeRequestedEQValue)) ) + simulateMemoryErrorAllocation = true; + + if (!simulateMemoryErrorAllocation && _generateErrIfMemorySizeRequestedGTValue > 0 && (size > ((size_t)_generateErrIfMemorySizeRequestedGTValue)) ) + simulateMemoryErrorAllocation = true; + + if (!simulateMemoryErrorAllocation && _generateErrIfMemorySizeRequestedGEValue > 0 && (size >= ((size_t)_generateErrIfMemorySizeRequestedGEValue)) ) + simulateMemoryErrorAllocation = true; + + return simulateMemoryErrorAllocation; +} + +void* _lpaCoreMemoryAlloc(size_t size, bool isAllocationSource, char* ptrFileName, int fileLine) +{ + void* ptrMemoryBlock = NULL; + +#ifdef LPA_SDK__MEMORY_MONITORING + if (_countMemoryAllocCall == 0) + _initMemoryAllocationMonitoring(); + +#ifdef LPA_SDK__PAMPERS + _lpaCoreMemoryCheckMemoryAllocated(false); +#endif // LPA_SDK__PAMPERS + +#endif // LPA_SDK__MEMORY_MONITORING + + _countMemoryAllocCall++; + + if (size > 0) + { + // maxMemoryAllocationSize take in account the 18 bytes added for header. See calculation in lpaCoreMemoryInitialize() + if(size <= maxMemoryAllocationSize) + { + if (!_isSimulateMemoryErrorAllocation(size)) + { + unsigned char* ptrMem = malloc(size + 18); + + // 2 bytes => Tag Begin + // 4 bytes => data size + // 1 byte => status: 0x11 ==> Allocated - 0x22 => Free, Other code are forbidden + // 3 byte => Index on _memory table (used if LPA_SDK__MEMORY_MONITORING) + // 4 bytes => Not yet used (Must be 0x00 for the moment) + // 2 bytes => Tag Middle + // xx bytes => real memory requested + // 2 bytes => Tag End + + if (ptrMem != NULL) + { + // Tag begin + ptrMem[0] = 0xA5; + ptrMem[1] = 0x5A; + + // Data size + ptrMem[2] = (unsigned char)((size & 0xFF000000) >> 24); + ptrMem[3] = (unsigned char)((size & 0x00FF0000) >> 16); + ptrMem[4] = (unsigned char)((size & 0x0000FF00) >> 8); + ptrMem[5] = (unsigned char)(size & 0x000000FF); + + // Status + ptrMem[6] = (unsigned char)0x11; // Allocated + + // Index info + size_t indexMemoryBlockInfo = INVALID_MONITORING_INDEX; // By default, No information + +#ifdef LPA_SDK__MEMORY_MONITORING + if (isAllocationSource && ptrFileName != NULL) + { + indexMemoryBlockInfo = _addMemoryAllocationMonitoring(ptrFileName, fileLine, ptrMem, size); + } +#endif // LPA_SDK__MEMORY_MONITORING + + ptrMem[7] = (unsigned char)((indexMemoryBlockInfo & 0xFF0000) >> 16); + ptrMem[8] = (unsigned char)((indexMemoryBlockInfo & 0x00FF00) >> 8); + ptrMem[9] = (unsigned char)((indexMemoryBlockInfo & 0x0000FF)); + + // Not yet used: padding + ptrMem[10] = 0x00; + ptrMem[11] = 0x00; + ptrMem[12] = 0x00; + ptrMem[13] = 0x00; + + // Tag: middle + ptrMem[14] = 0x16; + ptrMem[15] = 0x64; + + ptrMemoryBlock = ptrMem + 16; + + if (_activateLogForMemoryManagementOperation) + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "[LPASDKMEM] _lpaCoreMemoryAlloc(%llu bytes) => mem:0x%08lX (real memory @ 0x%08lX)", (long long unsigned)size, ptrMem, ptrMemoryBlock); + + // Initialize LPA SDK memory content + memset(ptrMemoryBlock, MEMORY_CONTENT_INIT_PATTERN, size); + + // Tag End + ptrMem[size + 16] = 0xAA; + ptrMem[size + 17] = 0x55; + + _currentMemoryBlockAllocated++; + _currentMemoryAllocated += size; + _totalMemoryAllocated += size; + + + if (_currentMemoryBlockAllocated > _maxMemoryBlockAllocated) + { + _maxMemoryBlockAllocated = _currentMemoryBlockAllocated; + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "[LPASDKMEM] _lpaCoreMemoryAlloc() => maxMemoryBlockAllocated updated to %ld ", _maxMemoryBlockAllocated); + } + //tracking memory evolution. + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKMEM] Current MemoAllocated %ld", _currentMemoryAllocated); + if (_currentMemoryAllocated > _maxMemoryAllocated) + { + _maxMemoryAllocated = _currentMemoryAllocated; + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "[LPASDKMEM] _lpaCoreMemoryAlloc() => maxMemoryAllocated updated to %ld bytes", _maxMemoryAllocated); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] _lpaCoreMemoryAlloc() do not allocate memory (Requested %llu bytes)", (unsigned long long)size ); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] _lpaCoreMemoryAlloc() do not allocate memory as requested"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] _lpaCoreMemoryAlloc() => Size of memory requested (%llu bytes) overflows size_t limits + management header!!", (unsigned long long)size); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] _lpaCoreMemoryAlloc() => No memory allocation for 0 bytes!!"); + + return ptrMemoryBlock; +} + +#ifdef LPA_SDK__MEMORY_MONITORING + +void _initMemoryAllocationMonitoring() +{ + if (_ptrMemoryBlockInformation == NULL) + { + _ptrMemoryBlockInformation = malloc(sizeof(MEMORY_BLOCK_INFORMATION) * MAX_MEMORY_BLOCK_INFORMATION); + if (_ptrMemoryBlockInformation != NULL) + memset(_ptrMemoryBlockInformation, 0x00, sizeof(MEMORY_BLOCK_INFORMATION) * MAX_MEMORY_BLOCK_INFORMATION); + } + + if (_ptrMemoryAllocationInformation == NULL) + { + _ptrMemoryAllocationInformation = malloc(sizeof(MEMORY_ALLOCATION_INFORMATION) * MAX_MEMORY_ALLOCATION_INFORMATION); + if (_ptrMemoryAllocationInformation != NULL) + memset(_ptrMemoryAllocationInformation, 0x00, sizeof(MEMORY_ALLOCATION_INFORMATION) * MAX_MEMORY_ALLOCATION_INFORMATION); + } +} + +size_t _addMemoryAllocationMonitoring(char* ptrFileName, int fileLine, void* ptrMem, size_t size) +{ + size_t indexArray = 0; // Using to parse different array + size_t indexMemoryBlockInfo = INVALID_MONITORING_INDEX; // By default, no entry available + size_t indexMemoryAllocationInfo = INVALID_MONITORING_INDEX; // By default, no entry available + + if (_ptrMemoryAllocationInformation != NULL && _ptrMemoryBlockInformation != NULL && ptrFileName != NULL && ptrMem != NULL ) + { + // Step 1: Search if source file + line entry already present + for (indexArray = 0; indexArray < MAX_MEMORY_ALLOCATION_INFORMATION; indexArray++) + { + if (_ptrMemoryAllocationInformation[indexArray].allocationCounter > 0) + { + // Record is not free => check if match with source file+line + if (_ptrMemoryAllocationInformation[indexArray].allocationLine == fileLine) + { + char shortFileName[ALLOCATION_FILE_NAME_SIZE]; + if (strlen(ptrFileName) < ALLOCATION_FILE_NAME_SIZE) + snprintf(shortFileName, ALLOCATION_FILE_NAME_SIZE, "%s", ptrFileName); + else + snprintf(shortFileName, ALLOCATION_FILE_NAME_SIZE, "%s", &ptrFileName[strlen(ptrFileName) - ALLOCATION_FILE_NAME_SIZE]); + + if (strcmp(shortFileName, _ptrMemoryAllocationInformation[indexArray].allocationFileName) == 0) + { + // Same source + indexMemoryAllocationInfo = indexArray; + break; + } + } + } + } + + if (indexMemoryAllocationInfo == INVALID_MONITORING_INDEX) + { + // Step 2: Search empty record inside _ptrMemoryAllocationInformation + for (indexArray = 0; indexArray < MAX_MEMORY_ALLOCATION_INFORMATION; indexArray++) + { + if (_ptrMemoryAllocationInformation[indexArray].allocationCounter == 0) + { + // Record is free + indexMemoryAllocationInfo = indexArray; + break; + } + } + } + + if (indexMemoryAllocationInfo != INVALID_MONITORING_INDEX) + { + // Step 3: Update _ptrMemoryAllocationInformation + if (_ptrMemoryAllocationInformation[indexMemoryAllocationInfo].allocationCounter == 0) + { + // First call from this source code + if (_activateLogForMemoryManagementOperation) + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "[LPASDKMEM] _lpaCoreMemoryAlloc() => Using entry <%llu> on _ptrMemoryAllocationInformation object", (long long unsigned)indexMemoryAllocationInfo); + + _ptrMemoryAllocationInformation[indexMemoryAllocationInfo].allocationCounter = 1; + _ptrMemoryAllocationInformation[indexMemoryAllocationInfo].allocationLine = fileLine; + + if (strlen(ptrFileName) < ALLOCATION_FILE_NAME_SIZE) + snprintf(_ptrMemoryAllocationInformation[indexMemoryAllocationInfo].allocationFileName, ALLOCATION_FILE_NAME_SIZE, "%s", ptrFileName); + else + snprintf(_ptrMemoryAllocationInformation[indexMemoryAllocationInfo].allocationFileName, ALLOCATION_FILE_NAME_SIZE, "%s", &ptrFileName[strlen(ptrFileName) - ALLOCATION_FILE_NAME_SIZE]); + } + else + { + + // Some call from this source code already under monitoring + _ptrMemoryAllocationInformation[indexMemoryAllocationInfo].allocationCounter++; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] _lpaCoreMemoryAlloc() => Unable to obtain a free entry on _ptrMemoryAllocationInformation object!"); + + + // Step 4: Search empty record on _ptrMemoryBlockInformation + for (indexArray = 0; indexArray < MAX_MEMORY_BLOCK_INFORMATION; indexArray++) + { + if (_ptrMemoryBlockInformation[indexArray].memoryBlockAllocated == NULL) + { + // Record is free + indexMemoryBlockInfo = indexArray; + break; + } + } + + if (indexMemoryBlockInfo != INVALID_MONITORING_INDEX) + { + _ptrMemoryBlockInformation[indexMemoryBlockInfo].memoryBlockAllocated = ptrMem; + _ptrMemoryBlockInformation[indexMemoryBlockInfo].memorySize = size; + _ptrMemoryBlockInformation[indexMemoryBlockInfo].indexMemoryAllocationInformation = indexMemoryAllocationInfo; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] _lpaCoreMemoryAlloc() => Unable to obtain a free entry on _ptrMemoryBlockInformation object!"); + + } + + return indexMemoryBlockInfo; +} + +void _writeLogMemoryAllocationBlockBefore(void *ptrMemoryBlock) +{ + // Search block allocated just before + size_t indexArray = 0; // Using to parse different array + void *ptrMemoryBlockBefore = NULL; + size_t indexBlockBefore = INVALID_MONITORING_INDEX; + + if (ptrMemoryBlock != NULL) + { + for (indexArray = 0; indexArray < MAX_MEMORY_BLOCK_INFORMATION; indexArray++) + { + if (_ptrMemoryBlockInformation[indexArray].memoryBlockAllocated != NULL) + { + if (ptrMemoryBlockBefore < _ptrMemoryBlockInformation[indexArray].memoryBlockAllocated && _ptrMemoryBlockInformation[indexArray].memoryBlockAllocated < ptrMemoryBlock) + { + ptrMemoryBlock = _ptrMemoryBlockInformation[indexArray].memoryBlockAllocated; + indexBlockBefore = indexArray; + } + } + } + + if (indexBlockBefore != INVALID_MONITORING_INDEX) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] Memory block before at real memory @ 0x%08lX (%llu bytes)", ptrMemoryBlock, (long long unsigned)_ptrMemoryBlockInformation[indexBlockBefore].memorySize ); + size_t indexMemoryAllocationInfo = _ptrMemoryBlockInformation[indexBlockBefore].indexMemoryAllocationInformation; + if (indexMemoryAllocationInfo != INVALID_MONITORING_INDEX) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] Memory block before allocated at %s:%llu", + _ptrMemoryAllocationInformation[indexMemoryAllocationInfo].allocationFileName, (long long unsigned)_ptrMemoryAllocationInformation[indexMemoryAllocationInfo].allocationLine); + } + } + } +} + +#endif // LPA_SDK__MEMORY_MONITORING + +////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////// + +void* _lpaCoreMemoryCalloc(size_t count, size_t size, bool isAllocationSource, char* ptrFileName, int fileLine) +{ + void* ptrMemoryBlock = NULL; + size_t memorySizeRequested = count * size; + + if (_activateLogForMemoryManagementOperation) + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "[LPASDKMEM] _lpaCoreMemoryCalloc(%llu*%llu=%llu) => calling lpaCoreMemoryAlloc...", (long long unsigned)count, (long long unsigned)size, (long long unsigned)memorySizeRequested); + + if (memorySizeRequested > 0) + { + ptrMemoryBlock = lpaCoreMemoryAlloc(memorySizeRequested); + if (ptrMemoryBlock != NULL) + { + // Clear memory bloc allocated + memset(ptrMemoryBlock, 0x00, memorySizeRequested); + } + } + + return ptrMemoryBlock; +} + +////////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////////// + +void* _lpaCoreMemoryRealloc(void* ptrMemoryOldBlock, size_t newSize, bool isAllocationSource, char* ptrFileName, int fileLine) +{ + void* ptrNewMemoryBlock = NULL; + + if (_activateLogForMemoryManagementOperation) + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "[LPASDKMEM] _lpaCoreMemoryRealloc(%08lX,%llu)", ptrMemoryOldBlock, (long long unsigned)newSize); + + if (ptrMemoryOldBlock == NULL) + { + if (newSize > 0) + { + // Case 1.1: As malloc function + ptrNewMemoryBlock = lpaCoreMemoryAlloc(newSize); + } + else + { + // Case 1.2: No old memory bloc and no memory allocation needed + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "[LPASDKMEM] _lpaCoreMemoryRealloc() => No memory allocation for 0 bytes!!"); + } + } + else + { + // case 2 + if (newSize == 0) + { + // Case 2.1: As free memory + lpaCoreMemoryFree(ptrMemoryOldBlock); + ptrMemoryOldBlock = NULL; + } + else + { + // Case 2.2: Normal use case + bool isValidMemoryBlock = false; + size_t oldMemoryBlocSize = _lpaCoreMemoryGetBlockSize(ptrMemoryOldBlock, &isValidMemoryBlock); + if (isValidMemoryBlock) + { + if (oldMemoryBlocSize != newSize) + { + ptrNewMemoryBlock = lpaCoreMemoryAlloc(newSize); + if (ptrNewMemoryBlock != NULL) + { + memcpy(ptrNewMemoryBlock, ptrMemoryOldBlock, (newSize < oldMemoryBlocSize ? newSize : oldMemoryBlocSize)); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] _lpaCoreMemoryRealloc() => Unable to allocate requested (%llu bytes) memory size!!", (long long unsigned)newSize); + + // free old memory bloc + lpaCoreMemoryFree(ptrMemoryOldBlock); + ptrMemoryOldBlock = NULL; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKMEM] _lpaCoreMemoryRealloc(): Previous and requested size are identical => do nothing"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] _lpaCoreMemoryRealloc() => Do nothing because memory block is invalid!!"); + } + } + + return ptrNewMemoryBlock; +} + + +////////////////////////////////////////////////////////////// +// free memory +////////////////////////////////////////////////////////////// + +void _lpaCoreMemoryFree(void* ptrMemoryBlockUser, bool isAllocationSource, char* ptrFileName, int fileLine) +{ + _countMemoryFreeCall++; + + if (ptrMemoryBlockUser != NULL) + { + unsigned char* ptrMemoryBlockBegin = ((unsigned char*)ptrMemoryBlockUser) - 16; + + // Check Tag Begin + if (ptrMemoryBlockBegin[0] == 0xA5 && ptrMemoryBlockBegin[1] == 0x5A) + { + // Begin tag is correct => Check if allocated or free + if (ptrMemoryBlockBegin[6] == 0x11) + { + // retrieve data size + size_t memoryBlocSize = (size_t)(ptrMemoryBlockBegin[2] << 24) + (size_t)(ptrMemoryBlockBegin[3] << 16) + (size_t)(ptrMemoryBlockBegin[4] << 8) + ptrMemoryBlockBegin[5]; + + if (_activateLogForMemoryManagementOperation ) + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "[LPASDKMEM] _lpaCoreMemoryFree(0x%08lX) => memoryBlockSize:%llu - mem:0x%08lX", ptrMemoryBlockUser, (long long unsigned)memoryBlocSize, ptrMemoryBlockBegin); + + // Check Tag middle + if (ptrMemoryBlockBegin[14] == 0x16 && ptrMemoryBlockBegin[15] == 0x64) + { +#ifdef LPA_SDK__MEMORY_MONITORING + bool isCurrentMemoryAllocationInformation = false; + + size_t indexMemoryBlock = (size_t)(ptrMemoryBlockBegin[7] << 16) + (size_t)(ptrMemoryBlockBegin[8] << 8) + ptrMemoryBlockBegin[9]; + + MEMORY_ALLOCATION_INFORMATION currentMemoryAllocationInformation; + memset( ¤tMemoryAllocationInformation, 0x00, sizeof(MEMORY_ALLOCATION_INFORMATION)); + + if (indexMemoryBlock == 0xFFFFFF) + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] _lpaCoreMemoryFree() => memory block 0x%08lX not contains entry on _memoryAllocationInformation object", ptrMemoryBlockBegin); + else + { + isCurrentMemoryAllocationInformation = _getMemoryAllocationInformation( ¤tMemoryAllocationInformation, indexMemoryBlock); + _freeMemoryAllocationMonitoring(ptrMemoryBlockBegin, indexMemoryBlock); + } +#endif // LPA_SDK__MEMORY_MONITORING + + if (ptrMemoryBlockBegin[memoryBlocSize + 16] == 0xAA && ptrMemoryBlockBegin[memoryBlocSize + 17] == 0x55) + { + _currentMemoryAllocated -= memoryBlocSize; + _currentMemoryBlockAllocated--; + + // Tracking memory evolution + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKMEM] Current MemoAllocated %ld", _currentMemoryAllocated); + + // Check memory usage + if (memoryBlocSize > 0) + { + for (size_t countMemoryContent = 0; countMemoryContent < memoryBlocSize; countMemoryContent ++) + { + if ( (((unsigned char*)ptrMemoryBlockUser)[memoryBlocSize - countMemoryContent - 1]) != MEMORY_CONTENT_INIT_PATTERN) + { + if (countMemoryContent > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKMEM] _lpaCoreMemoryFree() => Last %llu bytes seems not be used (memory block size: %llu)", + (long long unsigned)countMemoryContent, (long long unsigned)memoryBlocSize ); + +#ifdef LPA_SDK__MEMORY_MONITORING + if (isCurrentMemoryAllocationInformation) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKMEM] _lpaCoreMemoryFree() => Memory block allocated at %s, line %llu", + currentMemoryAllocationInformation.allocationFileName, (long long unsigned)currentMemoryAllocationInformation.allocationLine); + } +#endif // LPA_SDK__MEMORY_MONITORING + lpaCoreLogFlush(); + } + break; + } + } + } + + // And free this memory + ptrMemoryBlockBegin[6] = 0x22; // Mark as free + free(ptrMemoryBlockBegin); + + ptrMemoryBlockBegin = NULL; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] _lpaCoreMemoryFree() => invalid End Tag for memory block 0x%08lX (real memory @ 0x%08lX)", ptrMemoryBlockUser, ptrMemoryBlockBegin); + lpaCoreLogFlush(); + _memoryMonitoringBreakpointDebugger(); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] _lpaCoreMemoryFree() => invalid Middle Tag for memory block 0x%08lX (real memory @ 0x%08lX)", ptrMemoryBlockUser, ptrMemoryBlockBegin); + lpaCoreLogFlush(); + _memoryMonitoringBreakpointDebugger(); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] _lpaCoreMemoryFree() => memory block 0x%08lX (real memory @ 0x%08lX) already free", ptrMemoryBlockUser, ptrMemoryBlockBegin); + lpaCoreLogFlush(); + _memoryMonitoringBreakpointDebugger(); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] _lpaCoreMemoryFree() => invalid Begin Tag for memory block 0x%08lX (real memory @ 0x%08lX)", ptrMemoryBlockUser, ptrMemoryBlockBegin); + #ifdef LPA_SDK__MEMORY_MONITORING + _writeLogMemoryAllocationBlockBefore(ptrMemoryBlockBegin); + #endif + lpaCoreLogFlush(); + _memoryMonitoringBreakpointDebugger(); + } + +#if defined(LPA_SDK__MEMORY_MONITORING) && defined(LPA_SDK__PAMPERS) + _lpaCoreMemoryCheckMemoryAllocated(false); +#endif // LPA_SDK__MEMORY_MONITORING && LPA_SDK__PAMPERS + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "[LPASDKMEM] _lpaCoreMemoryFree() => try to free NULL memory block"); + lpaCoreLogFlush(); + _memoryMonitoringBreakpointDebugger(); + } + +} + +#ifdef LPA_SDK__MEMORY_MONITORING +void _freeMemoryAllocationMonitoring(void *ptrMemoryBlock, size_t indexMemoryBlockInfo) +{ + if (_ptrMemoryAllocationInformation != NULL && _ptrMemoryBlockInformation != NULL && ptrMemoryBlock != NULL) + { + // Step 1: Update _ptrMemoryBlockInformation + if (indexMemoryBlockInfo != INVALID_MONITORING_INDEX && indexMemoryBlockInfo < MAX_MEMORY_BLOCK_INFORMATION) + { + if (_ptrMemoryBlockInformation[indexMemoryBlockInfo].memoryBlockAllocated == ptrMemoryBlock) + { + size_t indexMemoryAllocationInfo = _ptrMemoryBlockInformation[indexMemoryBlockInfo].indexMemoryAllocationInformation; + + if (indexMemoryAllocationInfo != INVALID_MONITORING_INDEX && indexMemoryAllocationInfo < MAX_MEMORY_ALLOCATION_INFORMATION) + { + if (_ptrMemoryAllocationInformation[indexMemoryAllocationInfo].allocationCounter > 0) + { + _ptrMemoryAllocationInformation[indexMemoryAllocationInfo].allocationCounter--; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] _freeMemoryAllocationMonitoring() => indexMemoryAllocationInfo <%llu> is invalid!", (long long unsigned)indexMemoryBlockInfo); + + // Record is now free + _ptrMemoryBlockInformation[indexMemoryBlockInfo].memoryBlockAllocated = NULL; + _ptrMemoryBlockInformation[indexMemoryBlockInfo].indexMemoryAllocationInformation = INVALID_MONITORING_INDEX; + } + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] _freeMemoryAllocationMonitoring() => indexMemoryBlockInfo <%llu> is invalid!", (long long unsigned)indexMemoryBlockInfo); +} + +bool _getMemoryAllocationInformation(MEMORY_ALLOCATION_INFORMATION* ptrMemoryAllocationInformation, size_t indexMemoryBlockInfo) +{ + bool isMemoryAllocationInformation = false; + + if (_ptrMemoryAllocationInformation != NULL && _ptrMemoryBlockInformation != NULL && ptrMemoryAllocationInformation != NULL) + { + if (indexMemoryBlockInfo != INVALID_MONITORING_INDEX && indexMemoryBlockInfo < MAX_MEMORY_BLOCK_INFORMATION) + { + size_t indexMemoryAllocationInfo = _ptrMemoryBlockInformation[indexMemoryBlockInfo].indexMemoryAllocationInformation; + + if (indexMemoryAllocationInfo != INVALID_MONITORING_INDEX && indexMemoryAllocationInfo < MAX_MEMORY_ALLOCATION_INFORMATION) + { + if (_ptrMemoryAllocationInformation[indexMemoryAllocationInfo].allocationCounter > 0) + { + + ptrMemoryAllocationInformation->allocationCounter = _ptrMemoryAllocationInformation[indexMemoryAllocationInfo].allocationCounter; + ptrMemoryAllocationInformation->allocationLine = _ptrMemoryAllocationInformation[indexMemoryAllocationInfo].allocationLine; + memcpy(ptrMemoryAllocationInformation->allocationFileName, _ptrMemoryAllocationInformation[indexMemoryAllocationInfo].allocationFileName, sizeof(ptrMemoryAllocationInformation->allocationFileName)); + + isMemoryAllocationInformation = true; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] _getMemoryAllocationInformation() => indexMemoryAllocationInfo <%llu> is invalid!", (long long unsigned)indexMemoryBlockInfo); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] _getMemoryAllocationInformation() => invalid parameter!"); + + return isMemoryAllocationInformation; +} + +#endif // LPA_SDK__MEMORY_MONITORING + +size_t _lpaCoreMemoryGetBlockSize(void* ptrMemoryBlock, bool* ptrIsValidMemoryBlock) +{ + size_t memoryBlockSize = 0; + + if (ptrMemoryBlock != NULL && ptrIsValidMemoryBlock != NULL) + { + unsigned char* dataBegin = ((unsigned char*)ptrMemoryBlock) - 16; + *ptrIsValidMemoryBlock = false; + + // Check Tag Begin + if (dataBegin[0] == 0xA5 && dataBegin[1] == 0x5A) + { + // Begin tag is correct => check if block always allocated + if (dataBegin[6] == 0x11) + { + // retrieve data size + memoryBlockSize = (size_t)(dataBegin[2] << 24) + (size_t)(dataBegin[3] << 16) + (size_t)(dataBegin[4] << 8) + dataBegin[5]; + + if (dataBegin[memoryBlockSize + 16] != 0xAA || dataBegin[memoryBlockSize + 17] != 0x55) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] _lpaCoreMemoryGetBlocSize() => invalid End Tag for memory block 0x%08lX (real memory @ 0x%08lX)", ptrMemoryBlock, dataBegin); + lpaCoreLogFlush(); + _memoryMonitoringBreakpointDebugger(); + } + else + *ptrIsValidMemoryBlock = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] _lpaCoreMemoryGetBlocSize() => Memory block 0x%08lx (real memory @ 0x%08lx) already free", ptrMemoryBlock, dataBegin); + lpaCoreLogFlush(); + _memoryMonitoringBreakpointDebugger(); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] _lpaCoreMemoryGetBlocSize() => invalid Begin Tag for memory block 0x%08lx (real memory @ 0x%08lx)", ptrMemoryBlock, dataBegin); + #ifdef LPA_SDK__MEMORY_MONITORING + _writeLogMemoryAllocationBlockBefore(dataBegin); + #endif + lpaCoreLogFlush(); + _memoryMonitoringBreakpointDebugger(); + } + } + + return memoryBlockSize; +} + +void _memoryMonitoringBreakpointDebugger() +{ +#ifdef LPA_SDK__MEMORY_MONITORING + #if defined(WIN32) && defined(_DEBUG) && defined(_WINDOWS) + __debugbreak(); + #endif + + #ifdef LPA_SDK__PLATFORM_CYGWIN + __builtin_trap(); + #endif // LPA_SDK__PLATFORM_CYGWIN +#endif // LPA_SDK__MEMORY_MONITORING +} + + +#ifdef LPA_SDK__MEMORY_MONITORING +void _lpaCoreMemoryCheckMemoryAllocated(bool trace) +{ + size_t indexEntryMemoryBlock = 0; + + for (indexEntryMemoryBlock = 0; indexEntryMemoryBlock < MAX_MEMORY_BLOCK_INFORMATION; indexEntryMemoryBlock++) + { + unsigned char* ptrMemoryBlockBegin = _ptrMemoryBlockInformation[indexEntryMemoryBlock].memoryBlockAllocated; + size_t memorySize = _ptrMemoryBlockInformation[indexEntryMemoryBlock].memorySize; + + if (ptrMemoryBlockBegin != NULL) + { + bool isblockErrorDetected = false; + if (trace) + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "[LPASDKMEM] _lpaCoreMemoryCheckMemoryAllocated() --> checking _ptrMemoryBlockInformation #%llu ...", (long long unsigned)indexEntryMemoryBlock); + + // Check Tag Begin + if (ptrMemoryBlockBegin[0] != 0xA5 || ptrMemoryBlockBegin[1] != 0x5A) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] _lpaCoreMemoryCheckMemoryAllocated() => real memory @ 0x%08lx: Invalid Begin Tag", ptrMemoryBlockBegin); + isblockErrorDetected = true; + + _writeLogMemoryAllocationBlockBefore(ptrMemoryBlockBegin); + } + + // Check if allocated or free + if (!isblockErrorDetected && ptrMemoryBlockBegin[6] != 0x11) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] _lpaCoreMemoryCheckMemoryAllocated() => real memory @ 0x%08lx: Invalid Block status", ptrMemoryBlockBegin); + isblockErrorDetected = true; + } + + if (!isblockErrorDetected) + { + // retrieve data size + size_t memoryRegisteredSize = (size_t)(ptrMemoryBlockBegin[2] << 24) + (size_t)(ptrMemoryBlockBegin[3] << 16) + (size_t)(ptrMemoryBlockBegin[4] << 8) + ptrMemoryBlockBegin[5]; + if (memoryRegisteredSize != _ptrMemoryBlockInformation[indexEntryMemoryBlock].memorySize) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] _lpaCoreMemoryCheckMemoryAllocated() => real memory @ 0x%08lx: Inconsistent memory size", ptrMemoryBlockBegin); + isblockErrorDetected = true; + } + } + + if (!isblockErrorDetected) + { + // Check Padding padding + if (ptrMemoryBlockBegin[10] != 0x00 || ptrMemoryBlockBegin[11] != 0x00) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] _lpaCoreMemoryCheckMemoryAllocated() => real memory @ 0x%08lx: Inconsistent memory padding", ptrMemoryBlockBegin); + isblockErrorDetected = true; + } + } + + if (!isblockErrorDetected) + { + // Tag: middle + if (ptrMemoryBlockBegin[14] != 0x16 || ptrMemoryBlockBegin[15] != 0x64) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] _lpaCoreMemoryCheckMemoryAllocated() => real memory @ 0x%08lx: Invalid Middle Tag", ptrMemoryBlockBegin); + isblockErrorDetected = true; + } + } + + if (!isblockErrorDetected) + { + // Tag: end + if (ptrMemoryBlockBegin[memorySize + 16] != 0xAA || ptrMemoryBlockBegin[memorySize + 17] != 0x55) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "[LPASDKMEM] _lpaCoreMemoryCheckMemoryAllocated() => real memory @ 0x%08lx: Invalid End Tag", ptrMemoryBlockBegin); + isblockErrorDetected = true; + } + } + + if (isblockErrorDetected) + { + lpaCoreLogFlush(); + _memoryMonitoringBreakpointDebugger(); + } + } + } +} + +#endif // LPA_SDK__MEMORY_MONITORING + +#endif // LPA_SDK__MEMORY diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/rawdata_object.c b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/rawdata_object.c new file mode 100755 index 000000000..645e119da --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/rawdata_object.c @@ -0,0 +1,534 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#include "lpasdk/core/rawdata_object.h" +#include "lpasdk/core/lpa_memory.h" +#include "lpasdk/core/lpa_log.h" +#include "lpasdk/core/util.h" +#include + +//RawDataObject* rawDataObject_allocate(); + +////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////// + +/** + * Create RawDataObject object structure in memory, and initializes its internal structure (Data points to NULL, size = 0) + * @return Pointer on newly created RawDataObject object, else NULL if failed + */ +UT_EXPORT_DLL RawDataObject* rawDataObject_allocate() +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "rawDataObject_allocate()"); + + RawDataObject* ptrRawDataObject = lpaCoreMemoryAlloc(sizeof(RawDataObject)); + if (ptrRawDataObject != NULL) + { + ptrRawDataObject->rawData = NULL; + ptrRawDataObject->rawDataSize = 0; + } + + return ptrRawDataObject; +} + +////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////// + +/** + * Create RawDataObject object from bytes field and size + * @param ptrRawData Pointer on data bytes field to store + * @param rawDataSize Size of data bytes field, size_t format + * @return Pointer on newly created RawDataObject object, else NULL if failed + */ +UT_EXPORT_DLL RawDataObject* rawDataObject_create(const unsigned char* ptrRawData, size_t rawDataSize) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "rawDataObject_create()"); + + RawDataObject* ptrRawDataObject = rawDataObject_allocate(); + if (ptrRawDataObject != NULL) + { + if (ptrRawData != NULL && rawDataSize > 0) + { + ptrRawDataObject->rawData = lpaCoreMemoryAlloc(rawDataSize); + if (ptrRawDataObject->rawData != NULL) + { + memcpy(ptrRawDataObject->rawData, ptrRawData, rawDataSize); + ptrRawDataObject->rawDataSize = rawDataSize; + } + else + { + // Memory allocation error: Release allocated memory + lpaCoreMemoryFree(ptrRawDataObject); + ptrRawDataObject = NULL; + } + } + } + + return ptrRawDataObject; +} + + +/** + * Create RawDataObject object from bytes field and size, but store data with header including size, as LV coded object + * @param ptrRawData Pointer on data bytes field to store + * @param rawDataSize Size of data bytes field, size_t format + * @return Pointer on newly created RawDataObject object, else NULL if failed + */ +UT_EXPORT_DLL RawDataObject* rawDataObject_createAsLV(const unsigned char* ptrRawData, size_t rawDataSize) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "rawDataObject_createAsLV()"); + + RawDataObject* ptrRawDataObject = NULL; + if (ptrRawData != NULL && rawDataSize > 0) + { + ptrRawDataObject = rawDataObject_allocate(); + if (ptrRawDataObject != NULL) + { + size_t nbBytesLength = rawDataSize <= 0x7F ? 1 : (rawDataSize <= 0xFF ? 2 : (rawDataSize <= 0xFFFF ? 3 : 4)); + size_t totalRawDataObjectSize = nbBytesLength + rawDataSize; + + ptrRawDataObject->rawData = lpaCoreMemoryAlloc(totalRawDataObjectSize); + if (ptrRawDataObject->rawData != NULL) + { + switch (nbBytesLength) + { + case 1: + ptrRawDataObject->rawData[0] = (unsigned char)rawDataSize; + break; + + case 2: + ptrRawDataObject->rawData[0] = 0x81; + ptrRawDataObject->rawData[1] = (unsigned char)rawDataSize; + break; + + case 3: + ptrRawDataObject->rawData[0] = 0x82; + ptrRawDataObject->rawData[1] = (rawDataSize >> 8) & 0xFF; + ptrRawDataObject->rawData[2] = rawDataSize & 0x00FF; + break; + + case 4: + ptrRawDataObject->rawData[0] = 0x83; + ptrRawDataObject->rawData[1] = (rawDataSize >> 16) & 0xFF; + ptrRawDataObject->rawData[2] = (rawDataSize >> 8) & 0xFF; + ptrRawDataObject->rawData[3] = rawDataSize & 0x00FF; + break; + } + + memcpy(&ptrRawDataObject->rawData[nbBytesLength], ptrRawData, rawDataSize); + ptrRawDataObject->rawDataSize = totalRawDataObjectSize; + } + else + { + // Memory allocation error: Release allocated memory + lpaCoreMemoryFree(ptrRawDataObject); + ptrRawDataObject = NULL; + } + } + } + + return ptrRawDataObject; +} + + +/** + * Create RawDataObject object from Base64 encoded data. Output RawDataObjet will be stored in hex format, decoded from Base64 + * @param ptrBase64Data Pointer on Base64 data to decode and store + * @param base64DataSize Size of Base64 data + * @param maximumRawdataSize Maximum size allowed for Output RawDataObjet. If size = 0, no limit will be applied + * @return Pointer on newly created RawDataObject object, else NULL if failed or empty data given + */ +UT_EXPORT_DLL RawDataObject* rawDataObject_createFromBase64(const char* ptrBase64Data, const size_t base64DataSize, const size_t maximumRawdataSize) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "rawDataObject_createFromBase64()"); + + RawDataObject* ptrRawDataObject = NULL; + + size_t rawDataObjectSize = 0; // For RawDataObjet payload allocation in advance + + if(ptrBase64Data != NULL && base64DataSize > 0) + { + // Calculate decoded size from Base64. Normally "/ 4 * 3" shall be enough but add 1 by security + rawDataObjectSize = base64DataSize / 4 * 3 + 1; + + // Check maximum size specified. If equal 0 no limitation will be applied + if(maximumRawdataSize == 0 || rawDataObjectSize < maximumRawdataSize) + { + // Create RawDataObject. Done by advance to avoid creation of intermediate buffer and save memory + ptrRawDataObject = rawDataObject_allocate(); + if(ptrRawDataObject != NULL) + { + // Reserve memory buffer for raw data object payload + ptrRawDataObject->rawData = lpaCoreMemoryAlloc(rawDataObjectSize); + if(ptrRawDataObject->rawData != NULL) + { + // Convert Base64 object in raw hex and store it directly in rawDataObject. In case of failure, destroy created RawDataObject + if(! base64_decode(ptrBase64Data, base64DataSize, ptrRawDataObject->rawData, &ptrRawDataObject->rawDataSize, rawDataObjectSize)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "rawDataObject_createFromBase64: Failed to decode Base64 data!"); + lpaCoreMemoryFree(ptrRawDataObject->rawData); + lpaCoreMemoryFree(ptrRawDataObject); + ptrRawDataObject = NULL; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "rawDataObject_createFromBase64: Failed to allocate memory for RawDataObject data area!"); + lpaCoreMemoryFree(ptrRawDataObject); + ptrRawDataObject = NULL; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "rawDataObject_createFromBase64: Failed to create RawDataObject!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "rawDataObject_createFromBase64: Decoded data size (%llu bytes) exceed maximum allowed (%llu bytes)!", + (long long unsigned)rawDataObjectSize, (long long unsigned)maximumRawdataSize); + } + + return ptrRawDataObject; +} + +////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////// + +/** + * Concatenates 2 RawDataObject objects in an unique RawDataObject object, first Object 1 then Object 2 + * @param ptrRawDataObject1 Pointer on Object 1 to concatenate, RawDataObject type + * @param ptrRawDataObject2 Pointer on Object 2 to concatenate, RawDataObject type + * @return Pointer on newly created RawDataObject object storing both concatenated input objects, else NULL if failed + */ +UT_EXPORT_DLL RawDataObject* rawDataObject_concat(const RawDataObject* ptrRawDataObject1, const RawDataObject*ptrRawDataObject2) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "rawDataObject_concat()"); + + RawDataObject* ptrRawDataObject = rawDataObject_allocate(); + if (ptrRawDataObject != NULL) + { + size_t rawDataSize1 = ((ptrRawDataObject1 != NULL && ptrRawDataObject1->rawData != NULL) ? ptrRawDataObject1->rawDataSize : 0); + size_t rawDataSize2 = ((ptrRawDataObject2 != NULL && ptrRawDataObject2->rawData != NULL) ? ptrRawDataObject2->rawDataSize : 0); + size_t rawDataSize = rawDataSize1 + rawDataSize2; + + if ((rawDataSize1 + rawDataSize2) > 0) + { + ptrRawDataObject->rawData = lpaCoreMemoryAlloc(rawDataSize); + if (ptrRawDataObject->rawData != NULL) + { + if (rawDataSize1 > 0) + memcpy(ptrRawDataObject->rawData, ptrRawDataObject1->rawData, rawDataSize1); + + if (rawDataSize2 > 0) + memcpy(&ptrRawDataObject->rawData[rawDataSize1], ptrRawDataObject2->rawData, rawDataSize2); + + ptrRawDataObject->rawDataSize = rawDataSize; + } + else + { + // Memory allocation error: Release allocated memory + lpaCoreMemoryFree(ptrRawDataObject); + ptrRawDataObject = NULL; + } + } + } + + return ptrRawDataObject; +} + +////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////// + +/** + * Concatenates a RawDataObject object and a raw data array in an unique RawDataObject object, first RawDataObject object then raw data array. + * Note 1: If one object is NULL (Including data of RawDataObject object) or empty, output RawDataObject object will only store other not NULL / empty object. + * Note 2: If both objects are NULL / empty, output RawDataObject object will be empty. + * @param ptrRawDataObjectInput1 Pointer on RawDataObject object to concatenate + * @param ptrRawDataInput2 Pointer on raw data array to concatenate + * @param rawDataSizeInput2 Size of raw data array to concatenate + * @return Pointer on newly created RawDataObject object storing both concatenated input objects, else NULL if failed + */ +UT_EXPORT_DLL RawDataObject* rawDataObject_concatRawDataArray(const RawDataObject* ptrRawDataObjectInput1, const unsigned char* ptrRawDataInput2, size_t rawDataSizeInput2) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "rawDataObject_concatRawDataArray()"); + + RawDataObject* ptrRawDataObjectOutput = rawDataObject_allocate(); + if (ptrRawDataObjectOutput != NULL) + { + size_t rawDataSize1 = ((ptrRawDataObjectInput1 != NULL && ptrRawDataObjectInput1->rawData != NULL) ? ptrRawDataObjectInput1->rawDataSize : 0); + size_t rawDataSize2 = (ptrRawDataInput2 != NULL ? rawDataSizeInput2 : 0); + size_t rawDataSize = rawDataSize1 + rawDataSize2; + + if ((rawDataSize1 + rawDataSize2) > 0) + { + ptrRawDataObjectOutput->rawData = lpaCoreMemoryAlloc(rawDataSize); + if (ptrRawDataObjectOutput->rawData != NULL) + { + if (rawDataSize1 > 0) + memcpy(ptrRawDataObjectOutput->rawData, ptrRawDataObjectInput1->rawData, rawDataSize1); + + if (rawDataSize2 > 0) + memcpy(&ptrRawDataObjectOutput->rawData[rawDataSize1], ptrRawDataInput2, rawDataSize2); + + ptrRawDataObjectOutput->rawDataSize = rawDataSize; + } + else + { + // Memory allocation error: Release allocated memory + lpaCoreMemoryFree(ptrRawDataObjectOutput); + ptrRawDataObjectOutput = NULL; + } + } + } + + return ptrRawDataObjectOutput; +} + +////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////// + +/** + * Append raw data array to an existing RawDataObject object. If data array pointer is NULL AND its size = 0 operation will still be considered as successful + * @param ptrRawDataObjectSource Pointer on RawDataObject object. If NULL operation will be canceled / failed. + * @param ptrRawDataAppend Pointer on raw data array to append. + * @param rawDataSizeAppend Size of raw data to append, size_t format. + * @return true if operation is successful, else false + */ +UT_EXPORT_DLL bool rawDataObject_appendRawDataArray(RawDataObject* ptrRawDataObjectSource, const unsigned char* ptrRawDataAppend, size_t rawDataSizeAppend) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "rawDataObject_appendRawDataArray()"); + if (ptrRawDataObjectSource != NULL && ptrRawDataAppend != NULL && rawDataSizeAppend > 0 ) + { + size_t rawDataSize1 = (ptrRawDataObjectSource->rawData != NULL ? ptrRawDataObjectSource->rawDataSize : 0); + size_t rawDataSize2 = (ptrRawDataAppend != NULL ? rawDataSizeAppend : 0); + size_t rawDataSize = rawDataSize1 + rawDataSize2; + + if ((rawDataSize1 + rawDataSize2) > 0) + { + // 1) create new buffer with all data + unsigned char* ptrNewRawData = lpaCoreMemoryAlloc(rawDataSize); + if (ptrNewRawData != NULL) + { + if (rawDataSize1 > 0) + memcpy(ptrNewRawData, ptrRawDataObjectSource->rawData, rawDataSize1); + + if (rawDataSize2 > 0) + memcpy(&ptrNewRawData[rawDataSize1], ptrRawDataAppend, rawDataSizeAppend); + + // Free old buffer + if (ptrRawDataObjectSource->rawData != NULL) + lpaCoreMemoryFree(ptrRawDataObjectSource->rawData); + + // Update RawData object source + ptrRawDataObjectSource->rawData = ptrNewRawData; + ptrRawDataObjectSource->rawDataSize = rawDataSize; + + res = true; + } + } + } + + // If Raw Data to happen is completely void, we consider result successful + if (ptrRawDataAppend == NULL && rawDataSizeAppend == 0) + res = true; // No data to append + + return res; +} + +////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////// + +/** + * Concatenate data of RawDataObject object 1 and a selected area of data in RawDataObject object 2 + * Note 1: If one object is NULL (Including data of RawDataObject object) or empty, output RawDataObject object will only store target data of other not NULL / empty object. + * Note 2: If both objects are NULL / empty, output RawDataObject object will be empty. + * @param ptrRawDataObject1 Pointer on Object 1 to concatenate, RawDataObject type. + * @param ptrRawDataObject2 Pointer on Object 2 to concatenate partially, RawDataObject type. + * @param offset Starting offset for data concatenation from object 2, size_t format. If greater that size of Object 2, output RawDataObject object will only contain object 1. + * @param length Length of data to concatenate from object 2, size_t format. If offset + length exceeds object 2 data length, length will be adjusted to max available in object 2. + * @return Pointer on newly created RawDataObject object storing both concatenated input objects, else NULL if failed + */ +UT_EXPORT_DLL RawDataObject* rawDataObject_concatPartially(const RawDataObject* ptrRawDataObject1, const RawDataObject*ptrRawDataObject2, size_t offset, size_t length) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "rawDataObject_concatPartially()"); + + RawDataObject* ptrRawDataObject = rawDataObject_allocate(); + if (ptrRawDataObject != NULL) + { + size_t rawDataSize1 = ((ptrRawDataObject1 != NULL && ptrRawDataObject1->rawData != NULL) ? ptrRawDataObject1->rawDataSize : 0); + size_t rawDataSize2 = ((ptrRawDataObject2 != NULL && ptrRawDataObject2->rawData != NULL) ? ptrRawDataObject2->rawDataSize : 0); + size_t rawPartialSize2 = 0; + + if (offset < rawDataSize2) + { + if (offset + length <= rawDataSize2) + rawPartialSize2 = length; + else + rawPartialSize2 = rawDataSize2 - offset; + } + size_t rawDataSize = rawDataSize1 + rawPartialSize2; + + if (rawDataSize > 0) + { + ptrRawDataObject->rawData = lpaCoreMemoryAlloc(rawDataSize); + if (ptrRawDataObject->rawData != NULL) + { + if (rawDataSize1 > 0) + memcpy(ptrRawDataObject->rawData, ptrRawDataObject1->rawData, rawDataSize1); + + if (rawPartialSize2 > 0) + memcpy(&ptrRawDataObject->rawData[rawDataSize1], &ptrRawDataObject2->rawData[offset], rawPartialSize2); + + ptrRawDataObject->rawDataSize = rawDataSize; + } + else + { + // Memory allocation error: Release allocated memory + lpaCoreMemoryFree(ptrRawDataObject); + ptrRawDataObject = NULL; + } + } + } + + return ptrRawDataObject; +} + +////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////// + +/** +* Update RawDataObject object with new data content +* @param ptrRawDataObject pointer on RawDataObject object to update. If NULL operation is failed. +* @param ptrRawData Pointer on new data to store in RawDataObject object. If NULL operation is failed, except if rawDataSize = 0 +* @param rawDataSize New size of data to store, size_t type. If < 1 RawDataObject object will be empty or leaved as it if new size = previous size. +* @return true if RawDataObject object updated successfully, else false +*/ +UT_EXPORT_DLL bool rawDataObject_update(RawDataObject* ptrRawDataObject, const unsigned char* ptrRawData, size_t rawDataSize) +{ + bool doUpdate = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "rawDataObject_update()"); + + if (ptrRawDataObject != NULL) + { + // If old and new data have same size, do not allocate/free memory + if (ptrRawDataObject->rawDataSize == rawDataSize) + { + doUpdate = true; + if (rawDataSize > 0) + { + if(ptrRawData != NULL) + memcpy(ptrRawDataObject->rawData, ptrRawData, rawDataSize); + else + doUpdate = false; + } + } + else + { + //Old and new data have not same size => allocate new buffer before release old buffer + if (rawDataSize > 0) + { + if (ptrRawData != NULL) + { + unsigned char* ptrNewRawData = lpaCoreMemoryAlloc(rawDataSize); + if (ptrNewRawData != NULL) + { + memcpy(ptrNewRawData, ptrRawData, rawDataSize); + + // Now release old buffer + if (ptrRawDataObject->rawData != NULL) + lpaCoreMemoryFree(ptrRawDataObject->rawData); + + ptrRawDataObject->rawData = ptrNewRawData; + ptrRawDataObject->rawDataSize = rawDataSize; + + doUpdate = true; + } + } + } + else + { + // No data => Clear memory if needed + if (ptrRawDataObject->rawData != NULL) + { + lpaCoreMemoryFree(ptrRawDataObject->rawData); + ptrRawDataObject->rawData = NULL; + } + + ptrRawDataObject->rawDataSize = 0; + doUpdate = true; + } + } + } + + return doUpdate; +} + +////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////// + +/** +* Remove content of a RawDataObject object +* @param ptrRawDataObject Pointer on RawDataObject object to clear +*/ + +UT_EXPORT_DLL void rawDataObject_clear(RawDataObject* ptrRawDataObject) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "rawDataObject_clear()"); + + if (ptrRawDataObject != NULL) + { + if (ptrRawDataObject->rawData != NULL) + { + lpaCoreMemoryFree(ptrRawDataObject->rawData); + ptrRawDataObject->rawData = NULL; + } + + ptrRawDataObject->rawDataSize = 0; + } +} + +////////////////////////////////////////////////////////// +// +////////////////////////////////////////////////////////// + +/** + * Free memory used by RawDataObject object and affect object pointer to NULL + * @param ptrRawDataObject Pointer on RawDataObject object to free + */ +UT_EXPORT_DLL void rawDataObject_free(RawDataObject* ptrRawDataObject) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "rawDataObject_free()"); + + if (ptrRawDataObject != NULL) + { + if (ptrRawDataObject->rawData != NULL ) + lpaCoreMemoryFree(ptrRawDataObject->rawData); + lpaCoreMemoryFree(ptrRawDataObject); + ptrRawDataObject = NULL; + } +} \ No newline at end of file diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/semedia_base.c b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/semedia_base.c new file mode 100755 index 000000000..e9cc56040 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/semedia_base.c @@ -0,0 +1,39 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + + +#include "lpasdk/core/semedia_base.h" +#include "lpasdk/core/lpa_log.h" +#include "lpasdk/core/lpa_memory.h" + +TSEMedia* New_SEMediaBase() +{ + TSEMedia* ptrSEmediaBase = NULL; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++New_SEMediaBase"); + + ptrSEmediaBase = lpaCoreMemoryAlloc(sizeof(TSEMedia)); + + if(ptrSEmediaBase != NULL) + memset(ptrSEmediaBase, 0, sizeof(TSEMedia)); + + return ptrSEmediaBase; +} \ No newline at end of file diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/semedia_manager.c b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/semedia_manager.c new file mode 100755 index 000000000..56af3c2a4 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/semedia_manager.c @@ -0,0 +1,455 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + + +#include "lpasdk/core/semedia_manager.h" +#include "lpasdk/core/lpa_log.h" +#include "lpasdk/lpasdk_internal_api.h" + +#ifdef LPA_SDK__SEMEDIA_DRIVER_EXTERNAL + #if defined(LPA_SDK__PLATFORM_WIN) + #include "lpasdk/driver/semedia_external.h" // External (dynamic) driver + #else + #error "SE Media external driver only supported on WIN platform" + #endif // LPA_SDK__PLATFORM_WIN +#elif LPA_SDK__SEMEDIA_DRIVER_GENERIC_MODEM + #include "lpasdk/driver/semedia_genericmodem.h" // Generic Modem driver +#elif LPA_SDK__SEMEDIA_DRIVER_WINSCARD + #if defined(LPA_SDK__PLATFORM_WIN) || defined(LPA_SDK__PLATFORM_CYGWIN) || defined(LPA_SDK__PLATFORM_RASPBIAN) + #include "lpasdk/driver/semedia_winscard.h" // SE driver for Windows (using Winscard API) or Cygwin (using also Winscard API) + #endif // LPA_SDK__PLATFORM_WIN || LPA_SDK__PLATFORM_CYGWIN || defined(LPA_SDK__PLATFORM_RASPBIAN) +#else + //#error "No SEMedia compilation option defined" + #include "lpasdk/driver/semedia_winscard.h" +#endif // LPA_SDK__SEMEDIA_DRIVER_EXTERNAL + + +static TSEMedia* _seMedia = NULL; +static bool _manageAutomatically61XX = true; +static bool _manageAutomatically6CXX = false; + +///////////////////////////////////////////////////////// +// +///////////////////////////////////////////////////////// + +UT_EXPORT_DLL bool seMediaManagerInitialize() +{ + bool initOk = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+seMediaManagerInitialize()"); + + if (_seMedia == NULL) + { +#ifdef LPA_SDK__SEMEDIA_DRIVER_EXTERNAL + _seMedia = New_SEMediaExternal(); +#elif LPA_SDK__SEMEDIA_DRIVER_GENERIC_MODEM + _seMedia = New_SEMediaGenericModem(); +#elif LPA_SDK__SEMEDIA_DRIVER_WINSCARD + #if defined(LPA_SDK__PLATFORM_WIN) || defined(LPA_SDK__PLATFORM_CYGWIN) || defined(LPA_SDK__PLATFORM_RASPBIAN) + _seMedia = New_SEMediaWinSCard(); + #endif // LPA_SDK__PLATFORM_WIN || LPA_SDK__PLATFORM_CYGWIN +#endif // LPA_SDK__SEMEDIA_DRIVER_GENERIC_MODEM + + initOk = _seMedia != NULL; + + if(! initOk) + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "seMediaManagerInitialize(): Unable to create _seMedia!"); + } + + return initOk; +} + +///////////////////////////////////////////////////////// +// +///////////////////////////////////////////////////////// + +UT_EXPORT_DLL bool seMediaManagerSetCallbackEventExecutionError(LPA_EVENT_EXECUTION_ERROR lpaEventExecutionErrorCallback) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+seMediaManagerSetCallbackEventExecutionError()"); + + if (_seMedia != NULL) + res = _seMedia->seMediaSetCallbackEventExecutionError(_seMedia, lpaEventExecutionErrorCallback); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- seMediaManagerSetCallbackEventExecutionError() return %s", (res ? "true" : "false")); + return res; +} + +///////////////////////////////////////////////////////// +// +///////////////////////////////////////////////////////// + +UT_EXPORT_DLL bool seMediaManagerIsInitialized() +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+seMediaManagerIsInitialized()"); + + return (_seMedia != NULL); +} + +///////////////////////////////////////////////////////// +// +///////////////////////////////////////////////////////// + +UT_EXPORT_DLL bool seMediaManagerUninitialize() +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+seMediaManagerUninitialize()"); + + if (_seMedia != NULL) + { +#ifdef LPA_SDK__SEMEDIA_DRIVER_EXTERNAL + Delete_SEMediaExternal(_seMedia); +#elif LPA_SDK__SEMEDIA_DRIVER_GENERIC_MODEM + Delete_SEMediaGenericModem(_seMedia); +#elif LPA_SDK__SEMEDIA_DRIVER_WINSCARD + #if defined(LPA_SDK__PLATFORM_WIN) || defined(LPA_SDK__PLATFORM_CYGWIN)|| defined(LPA_SDK__PLATFORM_RASPBIAN) + Delete_SEMediaWinSCard(_seMedia); + #endif // LPA_SDK__PLATFORM_WIN || LPA_SDK__PLATFORM_CYGWIN +#endif // LPA_SDK__SEMEDIA_DRIVER_GENERIC_MODEM + _seMedia = NULL; + res = true; + } + + return res; +} + +///////////////////////////////////////////////////////// +// +///////////////////////////////////////////////////////// + +bool seMediaManagerEstablishContext() +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+seMediaManagerEstablishContext()"); + bool res = false; + + if (_seMedia != NULL) + { + if( _seMedia->seMediaEstablishContext != NULL ) + res = _seMedia->seMediaEstablishContext(_seMedia); + } + return res; +} + +///////////////////////////////////////////////////////// +// +///////////////////////////////////////////////////////// + +bool seMediaManagerReleaseContext() +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+seMediaManagerReleaseContext()"); + bool res = false; + + if (_seMedia != NULL) + { + if( _seMedia->seMediaReleaseContext != NULL ) + res = _seMedia->seMediaReleaseContext(_seMedia); + } + return res; +} + +///////////////////////////////////////////////////////// +// +///////////////////////////////////////////////////////// + +bool seMediaManagerIsContextEstablished() +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+seMediaManagerIsContextEstablished()"); + bool res = false; + + if (_seMedia != NULL) + { + if( _seMedia->seMediaIsContextEstablished != NULL ) + res = _seMedia->seMediaIsContextEstablished(_seMedia); + } + return res; +} + +///////////////////////////////////////////////////////// +// +///////////////////////////////////////////////////////// + +bool seMediaManagerIsValidContext() +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+seMediaManagerIsValidContext()"); + bool res = false; + + if (_seMedia != NULL) + { + if( _seMedia->seMediaIsValidContext != NULL ) + res = _seMedia->seMediaIsValidContext(_seMedia); + } + return res; +} + +///////////////////////////////////////////////////////// +// +///////////////////////////////////////////////////////// + +bool seMediaManagerListReader(LPA_SE_MEDIA_READER_NAME_INFO * readerNameInfoList, size_t readerNameInfoMax, size_t* countReader) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+seMediaManagerListReader()"); + bool res = false; + + if (_seMedia != NULL && readerNameInfoList != NULL && countReader != NULL) + { + if( _seMedia->seMediaListReader != NULL ) + res = _seMedia->seMediaListReader(_seMedia, readerNameInfoList, readerNameInfoMax, countReader); + } + return res; +} + +///////////////////////////////////////////////////////// +// +///////////////////////////////////////////////////////// + +bool seMediaManagerConnect(const char *readerName) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+seMediaManagerConnect()"); + bool res = false; + + if (_seMedia != NULL && readerName != NULL) + { + if( _seMedia->seMediaConnect != NULL ) + res = _seMedia->seMediaConnect(_seMedia, readerName); + } + return res; +} + +///////////////////////////////////////////////////////// +// +///////////////////////////////////////////////////////// + +bool seMediaManagerIsConnected() +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+seMediaManagerIsConnected()"); + bool res = false; + + if (_seMedia != NULL) + { + if( _seMedia->seMediaIsConnected != NULL ) + res = _seMedia->seMediaIsConnected(_seMedia); + } + return res; +} + +///////////////////////////////////////////////////////// +// +///////////////////////////////////////////////////////// + +bool seMediaManagerTransmitApdu(const unsigned char* apduCommandBytes, size_t apduCommandSize, unsigned char* apduResponseBytes, size_t* apduResponseMaxSize) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+seMediaManagerTransmitApdu()"); + bool res = false; + + if (_seMedia != NULL && apduCommandBytes != NULL && apduResponseBytes != NULL && apduResponseMaxSize != NULL) + { + size_t apduResponseSize = *apduResponseMaxSize; + + if (_seMedia->seMediaTransmitApdu != NULL && seMediaManagerIsConnected() ) + { + res = _seMedia->seMediaTransmitApdu(_seMedia, apduCommandBytes, apduCommandSize, apduResponseBytes, &apduResponseSize); + + if (res) + { + if (apduResponseSize >= 2) + { + if (apduResponseBytes[apduResponseSize - 2] == 0x61) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "APDU R - SW is 61.XX type"); + + // Manage 61.XX + if (_manageAutomatically61XX) + { + bool errorManaging61XX = false; + bool endOfData = false; + size_t totalDataSize = 0; + size_t partialApduResponseSize = *apduResponseMaxSize; + + unsigned char dataSizeRequested = apduResponseBytes[apduResponseSize - 1]; + unsigned char apduGetResponse[] = { 0x00, 0xC0, 0x00, 0x00, 0x00 }; + + // Manage data available on first APDU + if (apduResponseSize > 2) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Data available on first 61.XX APDU"); + totalDataSize += apduResponseSize - 2; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Partial data size: %llu", (long long unsigned)totalDataSize); + } + + // Management of chained 61XX begin here + while (!errorManaging61XX && !endOfData) + { + apduGetResponse[4] = dataSizeRequested; + partialApduResponseSize = (*apduResponseMaxSize - totalDataSize); + + res = _seMedia->seMediaTransmitApdu(_seMedia, apduGetResponse, sizeof(apduGetResponse), &apduResponseBytes[totalDataSize], &partialApduResponseSize); + if (res && partialApduResponseSize >= 2) + { + // check if another SW=61.XX + if (apduResponseBytes[totalDataSize + partialApduResponseSize - 2] == 0x61) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "APDU R - SW is again 61.XX type"); + dataSizeRequested = apduResponseBytes[totalDataSize + partialApduResponseSize - 1]; + totalDataSize += (partialApduResponseSize - 2); // No SW included + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Partial data size: %llu bytes", (long long unsigned)totalDataSize); + } + else + { + // Accept responses 0x90 00 or 0x91 xx + if ((apduResponseBytes[totalDataSize + partialApduResponseSize - 2] == 0x90 && + apduResponseBytes[totalDataSize + partialApduResponseSize - 1] == 0x00) || + (apduResponseBytes[totalDataSize + partialApduResponseSize - 2] == 0x91)) + { + totalDataSize += partialApduResponseSize; + apduResponseSize = totalDataSize; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Final data size: %llu bytes", (long long unsigned)totalDataSize); + endOfData = true; + } + else + { + // Detection of 0x6D00 in chained response loop, if detection is enabled + if(LPA_RETRY_CHAINED_GET_RESPONSE_MGT && + (apduResponseBytes[totalDataSize + partialApduResponseSize - 2] == 0x6D) && + (apduResponseBytes[totalDataSize + partialApduResponseSize - 1] == 0x00)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "SW 0x6D00 detected in chained GetResponse()!"); + errorManaging61XX = true; + apduResponseSize = 0; // With length=0 will be see as "Incorrect data / Invalid SW / error" on lpa_manager_helper layer + lpaSetErrorCode(SE_MEDIA_E_CHAINING_GET_RESPONSE); + } + else + { + // Other error cases will produce an error + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "90.00 or 91.xx or 61.XX Status Word expected!"); + errorManaging61XX = true; + apduResponseSize = 0; // With length=0 will be see as "Incorrect data / Invalid SW / error" on lpa_manager_helper layer + } + } + } + } + else + { + errorManaging61XX = true; + apduResponseSize = 0; // With length=0 will be see as "Incorrect data / Invalid SW / error" on lpa_manager_helper layer + } + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Automatic GetResponse for 61.XX not activated => do nothing"); + } + else + { + if (apduResponseBytes[apduResponseSize - 2] == 0x6C) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "APDU R - SW is 6C.XX type"); + + // Manage 6C.XX + if (_manageAutomatically6CXX) + { + // Implement 6C.XX if needed + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "6C.XX not yet implemented => do nothing"); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Automatic GetResponse for 6C.XX not activated => do nothing"); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Apdu response size < 2 bytes!"); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMedia->seMediaTransmitApdu return false!"); + apduResponseSize = 0; // With length=0 will be see as "Incorrect data / Invalid SW / error" on lpa_manager_helper layer + } + + if (!res) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "Problem during transmitAPDU process => Check Status..."); + if (_seMedia->seMediaGetStatus != NULL) + { + // try to get SCard Status + SE_MEDIA_CARD_STATUS cardStatus = SE_MEDIA_STATUS_SCARD_UNKNOWN; + if (_seMedia->seMediaGetStatus(_seMedia, &cardStatus)) + { + if (cardStatus == SE_MEDIA_STATUS_REMOVED_CARD) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Card removed -> do disconnect!"); + seMediaManagerDisconnect(); + } + } + } + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMedia->seMediaTransmitApdu NULL or failed at seMediaManagerIsConnected()!"); + + *apduResponseMaxSize = apduResponseSize; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter NULL!"); + + return res; +} + +///////////////////////////////////////////////////////// +// +///////////////////////////////////////////////////////// + +bool seMediaManagerDisconnect() +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+seMediaManagerDisconnect()"); + bool res = false; + + if (_seMedia != NULL) + { + if( _seMedia->seMediaDisconnect != NULL ) + res = _seMedia->seMediaDisconnect(_seMedia); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "_seMedia->seMediaDisconnect is NULL!"); + } + + return res; +} + +///////////////////////////////////////////////////////// +// +///////////////////////////////////////////////////////// + +bool seMediaManagerDisconnectWithReset() +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+seMediaManagerDisconnectWithReset()"); + bool res = false; + + if (_seMedia != NULL) + { + if (_seMedia->seMediaDisconnect != NULL) + res = _seMedia->seMediaDisconnectWithReset(_seMedia); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "_seMedia->seMediaDisconnectWithReset is NULL!"); + } + + return res; +} + diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/util.c b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/util.c new file mode 100755 index 000000000..2f7568826 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/core/util.c @@ -0,0 +1,1334 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + + +#include "lpasdk/core/util.h" +#include "lpasdk/core/lpa_log.h" +#include "lpasdk/core/bertlv_object.h" + +#include +#include +#include +#include + +#include "base64/base64.h" + + +bool _extractOIDfromCertificateExtensionList(const unsigned char * ptrExtensionListData, const size_t ExtensionListDataSize, unsigned char * ptrOID, size_t * ptrOIDsize, const size_t oidSizeMax); + + +int formatBytesToHexaString(const unsigned char *ptrDataBytes, size_t dataSize, char* ptrBufferString, size_t bufferStringMaxSize) +{ + size_t formattedStringSize = 0; + + if (ptrDataBytes != NULL && ptrBufferString != NULL && (dataSize * 2 + 1) < bufferStringMaxSize) + { + size_t offsetDataBytes = 0; + ptrBufferString[0] = 0; // Initializes empty string for output buffer. If dataSize = 0, ptrBufferString can still contain old string + + while (offsetDataBytes < dataSize ) + { + if (formattedStringSize + 3 < bufferStringMaxSize) + { + snprintf(&ptrBufferString[formattedStringSize], 3, "%02X", ptrDataBytes[offsetDataBytes]); // Limited to 3 because we only append hex value of a byte + offsetDataBytes++; + formattedStringSize += 2; + } + else + break; + } + } + + return formattedStringSize; +} + +bool writeIntegerValueToByteArray(uint16_t integerValue, unsigned char *ptrByteArray, size_t byteArrayMaxSize, size_t* byteArraySize) +{ + bool res = false; + + if (ptrByteArray != NULL && byteArraySize != NULL && byteArrayMaxSize > 0) + { + *byteArraySize = 0; + + if (integerValue <= 0xFF) + { + if (byteArrayMaxSize >= 1) + { + // One byte for Integer value + ptrByteArray[0] = (unsigned char) integerValue; + *byteArraySize = 1; + + res = true; + } + } + else + { + if (integerValue <= 0xFFFF) + { + // Two byte for Integer value + if (byteArrayMaxSize >= 2) + { + ptrByteArray[0] = (integerValue & 0xFF00) >> 8; + ptrByteArray[1] = (integerValue & 0xFF); + + *byteArraySize = 2; + res = true; + } + } + else + { + if (integerValue <= 0xFFFFFF) + { + // Two byte for Integer value + if (byteArrayMaxSize >= 3) + { + ptrByteArray[0] = (integerValue & 0x00FF0000) >> 16; + ptrByteArray[1] = (integerValue & 0x00FF) >> 8 ; + ptrByteArray[2] = (integerValue & 0xFF); + + *byteArraySize = 3; + res = true; + } + } + } + } + } + + return res; +} + +bool extractIntegerFromByteArray(const unsigned char *ptrByteArray, size_t byteArraySize, uint16_t* ptrIntegerValue) +{ + bool res = false; + + if (ptrByteArray != NULL && byteArraySize > 0 && ptrIntegerValue != NULL) + { + if (byteArraySize == 0x01) + { + *ptrIntegerValue = ptrByteArray[0]; + res = true; + } + + if (byteArraySize == 0x02) + { + *ptrIntegerValue = (ptrByteArray[0] << 8) | ptrByteArray[1]; + res = true; + } + + if (byteArraySize == 0x03) + { + *ptrIntegerValue = (ptrByteArray[0] << 16) | (ptrByteArray[1] << 8) | ptrByteArray[2]; + res = true; + } + + if (byteArraySize == 0x04) + { + *ptrIntegerValue = (ptrByteArray[0] << 24) | (ptrByteArray[1] << 16) | (ptrByteArray[2] << 8) | ptrByteArray[3]; + res = true; + } + } + + return res; +} + + +/** + * Encode BERTLV length "L" in an array, with attributes (0x81, 82 & 83) + * @param length - Value of the length to encode + * @param lengthTLV - Pointer on array that will receive the encoded length, binary hex format + * @param lengthTLVsize - Size of array that will receive the encoded length + * @param attributeLength - Pointer on variable that will receive length of "L" object (0 to 4) + * @return True if not problems with parameters (NULL pointer, array size too small) + */ +bool encodeLength(int length, unsigned char* lengthTLV, const size_t lengthTLVsize, size_t * attributeLength) +{ + bool res = false; + + if(lengthTLV != NULL && attributeLength != NULL) + { + unsigned char *p = lengthTLV; + *attributeLength = 0; + + if (length > 0) + { + if (length > 0x0000FFFF) { + if(lengthTLVsize >= 4) + { + *p++ = 0x83; + *p++ = (length & 0x00FF0000) >> 16; + *p++ = (length & 0x0000FF00) >> 8; + *p++ = length & 0x000000FF; + *attributeLength = 4; + res = true; + } + } else if (length > 0x000000FF) { + if(lengthTLVsize >= 3) + { + *p++ = 0x82; + *p++ = (length & 0x0000FF00) >> 8; + *p++ = length & 0x000000FF; + *attributeLength = 3; + res = true; + } + } else if (length > 0x0000007F) { + if(lengthTLVsize >= 2) + { + *p++ = 0x81; + *p++ = length & 0x000000FF; + *attributeLength = 2; + res = true; + } + } else { + if(lengthTLVsize >= 1) + { + *p++ = length & 0x000000FF; + *attributeLength = 1; + res = true; + } + } + *p = 0; + } + else + res = true; // Case of empty length + } + + return res; +} + + +/** + * Encode BERTLV length "L" in an array, without attributes (0x81, 82 & 83) + * @param length - Value of the length to encode + * @param lengthHex - Pointer on array that will receive the encoded length, binary hex format + * @param lengthHexsize - Size of array that will receive the encoded length + * @param attributeLength - Pointer on variable that will receive length of "L" object (0 to 3) + * @return True if not problems with parameters (NULL pointer, array size too small) + */ +bool generateLength(int length, unsigned char* lengthHex, const size_t lengthHexsize, size_t * attributeLength) +{ + bool res = false; + + if (lengthHex != NULL && attributeLength != NULL) + { + unsigned char *p = lengthHex; + *attributeLength = 0; + + if (length > 0) + { + if (length > 0x0000FFFF) + { + if(lengthHexsize >= 3) + { + *p++ = (length & 0x00FF0000) >> 16; + *p++ = (length & 0x0000FF00) >> 8; + *p++ = length & 0x000000FF; + *attributeLength = 3; + res = true; + } + } + else if (length > 0x00000FF) + { + if(lengthHexsize >= 2) + { + *p++ = (length & 0x0000FF00) >> 8; + *p++ = length & 0x000000FF; + *attributeLength = 2; + res = true; + } + } + else + { + if(lengthHexsize >= 1) + { + *p++ = length & 0x000000FF; + *attributeLength = 1; + res = true; + } + } + } + else + res = true; // Case of empty length + + *p = 0; + } + + return res; +} + + +int oneHexCharToHex(char h) +{ + int x = 0; + if (isdigit((unsigned char)h)) + { + x = h - '0'; + } else if (isupper((unsigned char)h)) + { + x = h - 'A' + 10; + } else + { + x = h - 'a' + 10; + } + return x; + +} + + +bool hexStr2ByteArray(const unsigned char * ptrInHexString, int inLen, unsigned char * ptrOutHex, int* ptrOutLen) +{ + bool success = false; + + do + { + if (NULL == ptrInHexString || NULL == ptrOutHex || NULL == ptrOutLen ) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "hexStr2ByteArray() => error: ptrInHexString or ptrOutHex or ptrOutLen is null!"); + break; + } + + if (inLen <= 1) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "hexStr2ByteArray() => error: inLen <= 1!"); + break; + } + + if (inLen % 2 != 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "hexStr2ByteArray() => error: ptrInHexString not modulo 2!"); + break; + } + + int outputMaxSize = *ptrOutLen; + int outputSize = 0; + *ptrOutLen = 0; + for (int i = 0; i < inLen; i += 2) + { + if (outputSize > outputMaxSize) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "hexStr2ByteArray() => output buffer too small! "); + goto exit; + } + + int ch1 = ptrInHexString[i]; + int ch2 = ptrInHexString[i + 1]; + + //ptrOutHex[i / 2 + 1] = 0; + if (isxdigit((unsigned char)ch1) && isxdigit((unsigned char)ch2)) + { + ch1 = oneHexCharToHex(ch1); + ch2 = oneHexCharToHex(ch2); + + ptrOutHex[outputSize] = (ch1 << 4) | ch2; + outputSize++; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "hexStr2ByteArray() => error: %c or %c is not hex digit! ", (char)ch1, (char)ch2); + goto exit; + } + } + + if (outputSize <= outputMaxSize) + { + *ptrOutLen = outputSize; + success = true; //OK + } + } + while(0); + + exit: + + return success; +} + + +bool findSubstr(char* source, char* target) +{ + int i, j; + int s_len = 0; + int t_len = 0; + + if((source != NULL) && (target != NULL)) + { + s_len = strlen(source); + t_len = strlen(target); + + if (t_len > s_len) + { + return -1; + } + + for (i = 0; i <= s_len - t_len; i++) + { + j = 0; + int flag = 1; + if (source[i] == target[j]) + { + int k, p = i; + for (k = 0; k < t_len; k++) + { + if (source[p] == target[j]) + { + p++; + j++; + continue; + } + else + { + flag = 0; + break; + } + } + } + else + { + continue; + } + if (flag == 1) + { + return true; + } + } + } + return false; +} + + +/** + * Return number of occurrences of a character in a string + * @param pString String to analyse + * @param c Character to find + * @return Number of characters, 0 if none found + */ +int countCharOccurencesInString(const char * pString, const char c) +{ + int i; + int len = 0; + int count = 0; + + if(pString != NULL) + { + len = strlen(pString); + for(i = 0; i < len; i++) + { + if(pString[i] == c) count++; + } + } + return count; +} + +/** + * Check if a value is present in an array (Both unsigned integer) + * @param pReferenceArray Array containing reference values + * @param pArraySize Number of elements of reference array + * @param pValue Value to check in reference array + * @return True is value exists in reference array + */ +bool isElementPresentInArrayUInt(const unsigned int *pReferenceArray, const size_t pArraySize, const unsigned int pValue) +{ + size_t i = 0; + bool res = false; + + if((pReferenceArray != NULL) && (pArraySize > 0)) + { + while((i < pArraySize) && (! res)) + { + if(*(pReferenceArray + i) == pValue) res = true; + i++; + } + } + + return res; +} + + +/** + * Check if a value is present in an array (Both unsigned bytes) + * @param pReferenceArray Array containing reference values + * @param pArraySize Number of elements of reference array + * @param pValue Value to check in reference array + * @return True is value exists in reference array + */ +bool isElementPresentInArrayByte(const unsigned char *pReferenceArray, const size_t pArraySize, const unsigned char pValue) +{ + size_t i = 0; + bool res = false; + + if((pReferenceArray != NULL) && (pArraySize > 0)) + { + while((i < pArraySize) && (! res)) + { + if(*(pReferenceArray + i) == pValue) res = true; + i++; + } + } + + return res; +} + + +/** + * Check if two strings are equals ignoring case + * @param pString1 + * @param pString2 + * @return true if strings are identical and not any string is NULL + */ +bool compareEqualStringIgnoringCase(const char * pString1, const char * pString2) +{ + bool res = false; + size_t len_str1; + size_t len_str2; + size_t i = 0; + + if((pString1 != NULL ) && (pString2 != NULL)) + { + len_str1 = strlen(pString1); + len_str2 = strlen(pString2); + + // No need to compare different length strings, go to false directly + if(len_str1 == len_str2) + { + // Status true will be invalidated if any difference is detected + res = true; + + // Compare characters while end of string and still equal + while((i < len_str1) && res) + { + if(toupper(pString1[i]) != toupper(pString2[i])) + res = false; + + i++; + } + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "compareEqualStringIgnoringCase: Invalid Parameters."); + + return res; +} + + +/** + * Converts a string to boolean flag depending syntax (true / false, yes / no) + * @param ptrParameterValue + * @param ptrBooleanValue + * @return True if any comparison matched + */ +bool convertStringToBoolean(const char* ptrParameterValue, bool *ptrBooleanValue) +{ + bool res = false; + + if (ptrParameterValue != NULL && ptrBooleanValue != NULL) + { + if (strcmp("true", ptrParameterValue) == 0 || strcmp("TRUE", ptrParameterValue) == 0 || strcmp("YES", ptrParameterValue) == 0 || strcmp("yes", ptrParameterValue) == 0) + { + *ptrBooleanValue = true; + res = true; + } + + if (strcmp("false", ptrParameterValue) == 0 || strcmp("FALSE", ptrParameterValue) == 0 || strcmp("NO", ptrParameterValue) == 0 || strcmp("no", ptrParameterValue) == 0) + { + *ptrBooleanValue = false; + res = true; + } + + } + + return res; +} + + +/** + * Converts a string to long value, with checking of length reached + * @param ptrParameterValue + * @param ptrLongValue + * @return True if conversion operation and length checking OK. + */ +bool convertStringToLong(const char* ptrParameterValue, long *ptrLongValue) +{ + bool res = false; + + if (ptrParameterValue != NULL && ptrLongValue != NULL) + { + char* ptrEnd = NULL; + long longValue = strtol(ptrParameterValue, &ptrEnd, 10); + if (ptrEnd == ptrParameterValue + strlen(ptrParameterValue)) + { + *ptrLongValue = longValue; + res = true; + } + } + + return res; +} + + +/** + * Convert string to lowercase + * @param ptrSourceString Pointer on string to convert + * @param ptrDestString Pointer on buffer that will receive converted string + * @param ptrDestStringSize Size of destination buffer. Must be large enough to receive string with '\0' character at the end. + * @return True if conversion is successful. + */ +bool convertStringToLower(const char * ptrSourceString, char * ptrDestString, size_t ptrDestStringSize) +{ + bool res = false; + size_t sourceLength = 0; + + if(ptrSourceString != NULL && ptrDestString != NULL && ptrDestStringSize > 0) + { + sourceLength = strlen(ptrSourceString); + + if(sourceLength < ptrDestStringSize) // Check destination buffer size + { + size_t i = 0; + + while(i < sourceLength) + { + ptrDestString[i] = tolower(ptrSourceString[i]); + i++; + } + ptrDestString[i] = '\0'; // Terminate destination string + + res = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "convertStringToLower: Destination buffer too small."); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "convertStringToLower: Invalid Parameters."); + + return res; +} + +/** + * Extract subjectAltName (Id 2.5.29.17) OID raw Object Identifier from a certificate (X509). + * Note: Certificate data structure check is not fully accurate (longer study needed), this is not the purpose of this function. + * @param ptrCertificate Pointer on data area containing certificate, hex format + * @param certificateLength Length of data field containing certificate + * @param ptrOID Pointer on data area that will receive OID raw data + * @param ptrOIDsize Will return size of OID found in certificate, zero if not found + * @param oidSizeMax Define the maximum size allowed for data area that will contain OID + * @return True if successful, false if problem during parsing (Incorrect TLV structure detected) or not found or invalid parameter. Not having extensions defined is also considered as an error. + */ +bool extractOIDfromCertificate(const unsigned char * ptrCertificate, const size_t certificateLength, unsigned char * ptrOID, size_t * ptrOIDsize, const size_t oidSizeMax) +{ + bool res = false; + + BeerTLV * berTLVmainContainer30 = NULL; + BeerTLV * berTLVtbsCertificateContainer30 = NULL; + BerTLVList * berTLVlist_tbsCert30base = NULL; + uint8_t tlvList_tbsCert30baseCount = 0; + BerTLVList * berTLVlist_tbsCert30baseParser = NULL; + BeerTLV * berTLVlist_tbsCert30baseCurrent = NULL; + BeerTLV * berTLVextensionSequence30 = NULL; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "extractOIDfromCertificate()..."); + + // Certificate minimum size is totally arbitrary, not studied here. Better write at least 15 than 0 + // OID minimum data area size fixed to 1, because only one byte can encode the 2 first digits of OID + if(ptrCertificate != NULL && certificateLength > 15 && ptrOID != NULL && ptrOIDsize != NULL && oidSizeMax > 0) + { + // Initialize OID length + *ptrOIDsize = 0; + + // Main certificate container <30> + berTLVmainContainer30 = berTLV_extractTagUInt8(0x30, ptrCertificate, certificateLength, NULL); + // Certificate minimum size is totally arbitrary, not studied here. Better write at least 12 than 0 + if(berTLVmainContainer30 != NULL && berTLVmainContainer30->length > 12) + { + berTLVtbsCertificateContainer30 = berTLV_extractTagUInt8(0x30, berTLVmainContainer30->value, berTLVmainContainer30->length, NULL); + // tbsCertificate container minimum size is totally arbitrary, not studied here. Better write at least 10 than 0 + if(berTLVtbsCertificateContainer30 != NULL && berTLVtbsCertificateContainer30->length > 10) + { + berTLVlist_tbsCert30base = berTLV_extractList(berTLVtbsCertificateContainer30->value, berTLVtbsCertificateContainer30->length, &tlvList_tbsCert30baseCount); + // At least 6 objects must exist in tbsCertificate container (Exact mandatory list not fully studied, should be 7 including Certificate Extensions, TBC) + if(berTLVlist_tbsCert30base != NULL && tlvList_tbsCert30baseCount > 5) + { + berTLVlist_tbsCert30baseParser = berTLVlist_tbsCert30base; + // Parse main objects to find Certificate Extensions container + while(berTLVlist_tbsCert30baseParser != NULL) + { + berTLVlist_tbsCert30baseCurrent = berTLVlist_tbsCert30baseParser->berTLV; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Main object tag found: <%X>", berTLVlist_tbsCert30baseCurrent->tag); + + if(berTLVlist_tbsCert30baseCurrent->tag == 0xA3) + { + // Extract extensions main sequence container <30> + berTLVextensionSequence30 = berTLV_extractTagUInt8(0x30, berTLVlist_tbsCert30baseCurrent->value, berTLVlist_tbsCert30baseCurrent->length, NULL); + // At least 2 bytes in container (So tag + zero length) + if(berTLVextensionSequence30 != NULL && berTLVextensionSequence30->length > 1) + { + // Parse sequence container to find OID (subjectAltName -> Registered ID) + res = _extractOIDfromCertificateExtensionList(berTLVextensionSequence30->value, berTLVextensionSequence30->length, ptrOID, ptrOIDsize, oidSizeMax); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "extractOIDfromCertificate: Sequence container <30> not found or invalid TLV format in Certificate Extension container or length too short."); + + ERASE_BERTLV(berTLVextensionSequence30); + + break; // No need to parse another main object in certificate + } + + // Parse next main object + berTLVlist_tbsCert30baseParser = berTLVlist_tbsCert30baseParser->ptrNext; + } + + // If main objects parser reached NULL, it means than Certificate Extension container was not found + if(berTLVlist_tbsCert30baseParser == NULL) + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "extractOIDfromCertificate: Certificate Extension container (Tag ) not found"); + + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "extractOIDfromCertificate: Failed to extract tbsCertificate objects list or not enough objects found."); + + ERASE_BERTLV_LIST(berTLVlist_tbsCert30base); + berTLVlist_tbsCert30baseParser = NULL; + berTLVlist_tbsCert30baseCurrent = NULL; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "extractOIDfromCertificate: tbsCertificate container <30> not found or invalid TVL format or size too small."); + + ERASE_BERTLV(berTLVtbsCertificateContainer30); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "extractOIDfromCertificate: Main container <30> not found or invalid TLV format or size too small."); + + ERASE_BERTLV(berTLVmainContainer30); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "extractOIDfromCertificate: Invalid Parameters."); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "extractOIDfromCertificate() return %s", (res ? "true" : "false")); + + return res; +} + + +/** + * Extract subjectAltName (Id 2.5.29.17) OID raw object (Registered ID) from Certificate Extension list (Sequence) - Note: Only first Registered ID will be used + * @param ptrExtensionListData Pointer on extension list data, hex format + * @param ExtensionListDataSize Extension list data size + * @param ptrOID Pointer on data area that will receive OID raw data + * @param ptrOIDsize Will return size of OID found in certificate, zero if not found + * @param oidSizeMax Define the maximum size allowed for data area that will contain OID + * @return True if successful, false if problem during parsing (Incorrect TLV structure detected) or invalid parameter or OID not found + */ +bool _extractOIDfromCertificateExtensionList(const unsigned char * ptrExtensionListData, const size_t ExtensionListDataSize, unsigned char * ptrOID, size_t * ptrOIDsize, const size_t oidSizeMax) +{ + bool res = false; + + const unsigned char subjectAltNameID[] = {0x55, 0x1D, 0x11}; // Coding of OID identifying subjectAltName (Id 2.5.29.17) + + BerTLVList * berTLVlistExtContainerBase = NULL; + uint8_t tlvListExtContainerCount = 0; + BerTLVList * berTLVlisExtContainerParser = NULL; + BeerTLV * berTLVlistExtContainerCurrent = NULL; + + BeerTLV * berTLVextensionId = NULL; + BeerTLV * berTLVsubjectAltNameMain = NULL; + BeerTLV * berTLVsubjectAltNameSeq30 = NULL; + BeerTLV * berTLVsubjectAltNameRegID = NULL; + + + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_extractOIDfromCertificateExtensionList()..."); + + // OID minimum data area size fixed to 1, because only one byte can encode the 2 first digits of OID + if(ptrExtensionListData != NULL && ExtensionListDataSize > 0 && ptrOID != NULL && ptrOIDsize != NULL && oidSizeMax > 0) + { + // Initialize OID length + *ptrOIDsize = 0; + + berTLVlistExtContainerBase = berTLV_extractList(ptrExtensionListData, ExtensionListDataSize, &tlvListExtContainerCount); + // At least one object shall be present in list + if(berTLVlistExtContainerBase != NULL && tlvListExtContainerCount > 0) + { + berTLVlisExtContainerParser = berTLVlistExtContainerBase; + + while(berTLVlisExtContainerParser != NULL) + { + berTLVlistExtContainerCurrent = berTLVlisExtContainerParser->berTLV; + + // Only consider sequence Extension objects, ignore eventual other ones + if(berTLVlistExtContainerCurrent->tag == 0x30) + { + lpaCoreLogAppendByteArray(SDK_LOG_LEVEL_DEBUG, "Certificate Extension data", ">>", berTLVlistExtContainerCurrent->value, berTLVlistExtContainerCurrent->length); + + // Search for Extension identifier. If not found generate an error because shall be present + berTLVextensionId = berTLV_extractTagUInt8(0x06, berTLVlistExtContainerCurrent->value, berTLVlistExtContainerCurrent->length, NULL); + + // Extension ID is always 3 bytes long + if(berTLVextensionId != NULL && berTLVextensionId->length == 3) + { + // Check if Extension is subjectAltName (Id 2.5.29.17 so 0x551D11) + if(0 == memcmp(berTLVextensionId->value, subjectAltNameID, 3)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "subjectAltName extension found (Id 2.5.29.17 so 0x551D11)"); + // Extract subjectAltName main container data, Tag <04> + berTLVsubjectAltNameMain = berTLV_extractTagUInt8(0x04, berTLVlistExtContainerCurrent->value, berTLVlistExtContainerCurrent->length, NULL); + + // Shall be at least 4 bytes long to contain sequence object + if(berTLVsubjectAltNameMain != NULL && berTLVsubjectAltNameMain->length > 3) + { + // Extract sequence object <30> from subjectAltName main container + berTLVsubjectAltNameSeq30 = berTLV_extractTagUInt8(0x30, berTLVsubjectAltNameMain->value, berTLVsubjectAltNameMain->length, NULL); + + // Shall be at least 2 bytes long to contain at least one object, even empty (RFC5280 defines that at least one object shall be defined) + if(berTLVsubjectAltNameSeq30 != NULL && berTLVsubjectAltNameSeq30->length > 1) + { + // Extract first Registered ID 0x88 in subjectAltName sequence + berTLVsubjectAltNameRegID = berTLV_extractTagUInt8(0x88, berTLVsubjectAltNameSeq30->value, berTLVsubjectAltNameSeq30->length, NULL); + + // Empty Registered ID does not exist, even 0.0 OID is written in one byte set at 0x00 + if(berTLVsubjectAltNameRegID != NULL && berTLVsubjectAltNameRegID->length > 0) + { + // If Registered ID found, copy it in OID, if size does not exceed buffer size + if(berTLVsubjectAltNameRegID->length <= oidSizeMax) + { + memcpy(ptrOID, berTLVsubjectAltNameRegID->value, berTLVsubjectAltNameRegID->length); + *ptrOIDsize = berTLVsubjectAltNameRegID->length; + + lpaCoreLogAppendByteArray(SDK_LOG_LEVEL_DEBUG, "OID found (Registered ID, tag <88>)", ">>>", ptrOID, *ptrOIDsize); + + res = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_extractOIDfromCertificateExtensionList: Registered ID size (%lu) exceeds bound (%llu)", + (long unsigned)berTLVsubjectAltNameRegID->length, (long long unsigned)oidSizeMax); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_extractOIDfromCertificateExtensionList: Registered ID tag <88> not found in subjectAltName sequence or invalid TLV format or too short."); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_extractOIDfromCertificateExtensionList: subjectAltName sequence container <30> not found or invalid TLV format or too short."); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_extractOIDfromCertificateExtensionList: subjectAltName data tag <04> not found in extension or invalid TLV format or too short."); + + + break; // No need to parse anymore whatever is result + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_extractOIDfromCertificateExtensionList: Extension identifier tag <06> not found in extension or invalid TLV format or incorrect length."); + break; // Stop to parse extensions + } + } + + // For cleanup if not subjectAltName encountered + ERASE_BERTLV(berTLVextensionId); + + // Go to next extension + berTLVlisExtContainerParser = berTLVlisExtContainerParser->ptrNext; + } + + if(berTLVlisExtContainerParser == NULL) + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "\"subjectAltName\" extension not found"); + + // Some erase reported again here due to stop parsing with break + ERASE_BERTLV(berTLVextensionId); + ERASE_BERTLV(berTLVsubjectAltNameMain); + ERASE_BERTLV(berTLVsubjectAltNameSeq30); + ERASE_BERTLV(berTLVsubjectAltNameRegID); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_extractOIDfromCertificateExtensionList: Failed to extract extension list or not enough elements."); + + ERASE_BERTLV_LIST(berTLVlistExtContainerBase); + berTLVlisExtContainerParser = NULL; + berTLVlistExtContainerCurrent = NULL; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_extractOIDfromCertificateExtensionList: Invalid Parameters."); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_extractOIDfromCertificateExtensionList() return %s", (res ? "true" : "false")); + + return res; +} + + +/** + * Convert raw ASN1 OID to text readable string (1.2....). + * Note: As reference, with use of long long unsigned integer on 64 bits it allow to support at least 63 bits, the maximum possible with VLQ value coded on 9 bytes. + * @param ptrOID Pointer on OID raw data, hex format + * @param OIDsize Length of OID raw data + * @param ptrOIDtext Pointer on text area that will receive OID text conversion, string format + * @param OIDtextMaxSize Maximum size of text area that will receive OID text, including end of string + * @return true if conversion is OK + */ +bool convertASN1_OIDtoText(const unsigned char * ptrOID, const size_t OIDsize, char * ptrOIDtext, const size_t OIDtextMaxSize) +{ + bool res = false; + unsigned char currentNode[20]; // 20 bytes are widely enough to handle values of 160 bits, really more than possible normally + size_t currentNodeLength = 0; + unsigned long long nodeValue = 0; + size_t oidParser = 0; + bool processFirstNodes = true; + unsigned long long firstNode = 0; + unsigned long long secondNode = 0; + char textBuffer[50]; // Very big numbers + additional node on startup can need some long space + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "convertASN1_OIDtoText()..."); + + // Note: With a single byte, OID text will have at least 3 characters "x.y" + if(ptrOID != NULL && OIDsize > 0 && ptrOIDtext != NULL && OIDtextMaxSize > 2) + { + // For the moment, we consider that no error is encountered + res = true; + + // Clear output text area + memset(ptrOIDtext, 0x00, OIDtextMaxSize); + + // Parse all source + while(oidParser < OIDsize) + { + currentNodeLength = 0; + + // Parse ASN1 OID value, taking account of possible nodes coded as VLQ values + if(parseDataWithVLQnodes(&ptrOID[oidParser], OIDsize - oidParser, currentNode, ¤tNodeLength, sizeof(currentNode))) + { + // If node is not VLQ encoded, take value as it + if(currentNodeLength == 1) + { + nodeValue = currentNode[0]; + oidParser++; + } + else + { + // If node is VLQ encoded, decode it + if(decodeVLQvalue(currentNode, currentNodeLength, &nodeValue)) + { + // Update parsing index with the length of VLQ node + oidParser = oidParser + currentNodeLength; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "convertASN1_OIDtoText: Issue encountered while decoding VLQ value. Conversion canceled."); + ptrOIDtext[0] = 0; + res = false; + break; + } + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "convertASN1_OIDtoText: Issue encountered while parsing OID nodes. Conversion canceled."); + ptrOIDtext[0] = 0; + res = false; + break; + } + + // Reset text Buffer + textBuffer[0] = '\0'; + + // Startup is specific: Two first OID nodes are encoded on a single value + if(processFirstNodes) + { + // Divide by 40 to find first node. Only 0, 1 or 2 can exist so if >= 2 will be 2 + firstNode = nodeValue / 40; + + if(firstNode > 1) + firstNode = 2; + + // Second node is the remaining of first value minus first node (Encoded x 40) + secondNode = nodeValue - (firstNode * 40); + + snprintf(textBuffer, sizeof(textBuffer), "%llu.%llu", firstNode, secondNode); + + processFirstNodes = false; + } + else + snprintf(textBuffer, sizeof(textBuffer), ".%llu", nodeValue); + + // Append new node while it does not exceed maximum output text length + if((strlen(ptrOIDtext) + strlen(textBuffer)) < OIDtextMaxSize) + strncat(ptrOIDtext, textBuffer, (OIDtextMaxSize - strlen(ptrOIDtext) - 1)); + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "convertASN1_OIDtoText: OID value length exceeds output buffer capabilities. Conversion canceled."); + ptrOIDtext[0] = 0; + res = false; + break; + } + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "convertASN1_OIDtoText: Invalid Parameters."); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "convertASN1_OIDtoText() return %s", (res ? "true" : "false")); + + return res; +} + + +/** + * Parse data that could contain Variable Length Quantity (VLQ) node and return first value encountered (single value minus than 128 or VLQ array) + * @param ptrSource Pointer on source data, hex format + * @param sourceLength Length of source data + * @param ptrExtractData Pointer on array that will receive value (Index 0) or VLQ array + * @param ptrExtractDatalength Length of extracted data (1 if simple non VLQ value) + * @param extractDataMaxSize Maximum size of array that will receive value or VLQ array + * @return true if extraction is OK + */ +bool parseDataWithVLQnodes(const unsigned char * ptrSource, const size_t sourceLength, unsigned char * ptrExtractData, size_t * ptrExtractDatalength, const size_t extractDataMaxSize) +{ + bool res = false; + unsigned int index = 0; + + if(ptrSource != NULL && sourceLength > 0 && ptrExtractData != NULL && ptrExtractDatalength != NULL && extractDataMaxSize > 0) + { + // For the moment, we consider that no error is encountered + res = true; + + // For the moment, nothing extracted + *ptrExtractDatalength = 0; + + // Check if first byte if VLQ value (Bit 7 set to 1) of other value + if((ptrSource[0] & 0x80) > 0) + { + // VLQ node encountered, copy values from data source to extracted data buffer + while(((ptrSource[index] & 0x80) > 0) && (index < sourceLength) && (index < extractDataMaxSize)) + { + ptrExtractData[index] = ptrSource[index]; + index++; + } + + // if end of data is not reached, copy next byte with b7 not set to "1" + if((index < sourceLength) && (index < extractDataMaxSize)) + { + ptrExtractData[index] = ptrSource[index]; + *ptrExtractDatalength = index + 1; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "parseDataWithVLQnodes: End of data reached before last VLQ byte (b7 = 0) found or extraction buffer overflow."); + res = false; + *ptrExtractDatalength = 0; + } + } + else + { + // Normal value between 0 and 0x7F, just return it as it + ptrExtractData[0] = ptrSource[0]; + *ptrExtractDatalength = 1; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "parseDataWithVLQnodes: Invalid Parameters."); + + return res; +} + + +/** + * Decode Variable Length Quantity (VLQ) value (Also named Base128) to unsigned integer (long long) + * Note: As reference, with use of long long unsigned integer on 64 bits it allow to support at least 63 bits, the maximum possible with VLQ value coded on 9 bytes + * @param ptrVLQvalue Pointer on array that contain VLQ value, hex format + * @param VLQvalueSize Length of array containing VLQ value + * @param ptrOutputValue Pointer on variable that will receive converted value + * @return true if decoding is OK + */ +bool decodeVLQvalue(const unsigned char * ptrVLQvalue, const size_t VLQvalueSize, unsigned long long * ptrOutputValue) +{ + bool res = false; + unsigned long long outputORmask = 0x01; + unsigned char inputANDmask = 0x01; + int inputShifter = 0; + int inputIndex = 0; + int totalShift = 0; + int maxShift = 0; + + // Note: Having a VLQ value of less than 2 bytes long is not applicable + if(ptrVLQvalue != NULL && VLQvalueSize > 1 && ptrOutputValue != NULL) + { + // For the moment, we consider that no error is encountered + res = true; + + *ptrOutputValue = 0; + // Size of long long can vary depending system / compiler used + maxShift = 8 * sizeof(*ptrOutputValue); + + // Parse VLQ from last element to first one + inputIndex = VLQvalueSize - 1; + + while(inputIndex >= 0 && res) + { + // Decode each bit of VLQ value byte and report it to output, from bits 0 to 6 (Bit 7 ignored) + for(inputShifter = 0; inputShifter < 7; inputShifter++) + { + // Manage number of shifting performed. + // If overflow long long size, stop process on error + totalShift++; + if(totalShift > maxShift) + { + res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "decodeVariableLengthQuantityValue: Output value (unsigned long long) capacity overflow, cancel decoding."); + *ptrOutputValue = 0; + break; + } + + // Get bit value in input. If set to 1, set corresponding bit to 1 in output, else leave it at 0. + if((ptrVLQvalue[inputIndex] & inputANDmask) > 0) + *ptrOutputValue = *ptrOutputValue | outputORmask; + + // Shift masks + inputANDmask = inputANDmask << 1; + outputORmask = outputORmask << 1; + } + + // Current VLQ byte finished, got to next one (Rigth to left) and reset input mask + inputIndex--; + inputANDmask = 0x01; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "decodeVariableLengthQuantityValue: Invalid Parameters."); + + return res; +} + + +/** + * Encodes an hex data field in Base64 format - Wrapper to base64.c library + * @param indata Input hex data field buffer, byte format + * @param inlen Input, Length of input data field buffer + * @param outdata Output Base64 data field, characters without \0 end + * @param outlen Output, Length of Base64 data stored in output buffer, optional if NULL specified + * @param maxSize Input, Maximum size allowed for output buffer + * @return true if conversion was successful + */ +bool base64_encode(const unsigned char *indata, size_t inlen, char *outdata, size_t *outlen, size_t maxSize) +{ + bool res = false; + unsigned int encodedSize = 0; + + if (indata != NULL && inlen > 0 && outdata != NULL) + { + // Check output buffer size before launch encoding + if(maxSize >= b64e_size((unsigned int)inlen)) + { + encodedSize = b64_encode(indata, (unsigned int)inlen, (unsigned char *)outdata); + + if(encodedSize > 0) + { + res = true; + + if (outlen != NULL) + *outlen = (size_t)encodedSize; + } + } + } + + return res; +} + + +/** + * Decodes a Base64 data field in hex format - Wrapper to base64.c library + * @param indata Input Base64 data field buffer, characters + * @param inlen Input, Length of input Base64 data field buffer + * @param outdata Output hex data field, bytes + * @param outlen Output, Length of Hex data stored in output buffer, optional if NULL specified + * @param destSize Input, Maximum size allowed for output buffer + * @return true if conversion was successful + */ +bool base64_decode(const char *indata, size_t inlen, unsigned char *outdata, size_t *outlen, size_t destSize) +{ + bool res = false; + unsigned int decodedSize = 0; + + if (indata != NULL && inlen > 0 && outdata != NULL && (inlen % 4 == 0)) + { + // Check output buffer size before launch decoding + if(destSize >= b64d_size((unsigned int)inlen)) + { + decodedSize = b64_decode((unsigned char*) indata, (unsigned int)inlen, outdata); + + if(decodedSize > 0) + { + res = true; + + if (outlen != NULL) + *outlen = (size_t)decodedSize; + } + } + } + + return res; +} + + +/** + * Extract list of bits sets in Static BIT STRING ASN1 object. Can process both DER and BER encoding (0 or 1 padded expression). + * Can process Static ASN1 BIT STRING with up to 256 bits. + * @param ptrASN1BitString Pointer on array containing Bit String value (Without Tag and length bytes) + * @param ASN1BitStringLength Length of Bit String Value contained in array + * @param ptrBitsSetList Pointer on array that will received bits set found in ASN1 expression + * @param maxBitsSetListSize Maximum number of elements that can be stored in found bits list (Max array size) + * @param nbBitsSetFound Pointer on size_t variable that will receive number of bits set found in ASN1 Bit String object + * @return True if extraction process is OK and ASN1 object is correct and array storing bit list is large enough, else false + */ +bool extractBitsSetListInStaticASN1BitString(const unsigned char * ptrASN1BitString, const size_t ASN1BitStringLength, unsigned char * ptrBitsSetList, const size_t maxBitsSetListSize, size_t * ptrNbBitsSetFound) +{ + bool res = false; + size_t idxBitString = 1; // Start to parse at 2nd byte, first one define number of padding bits + size_t idxOutputList = 0; // Index for output list + uint16_t currentBitNumber = 0; // Current bit number evaluated in ASN1 object, start from 0 + unsigned char byteMask = 0x80; // Mask for byte value check + unsigned char bitIndex = 0; // Number of bit currently evaluated in current BIT STRING byte + unsigned char maxBitCounter = 8; // Max bit numbers to evaluate in current BIT STRING byte. Limited by padding bits number if last byte reached + + // Note: Output list of bits set is an array of bytes, so no more than 256 bits are managed. Case having more than 256 bit to evaluate is not encountered for the moment + if(ptrASN1BitString != NULL && ASN1BitStringLength > 0 && ptrBitsSetList != NULL && maxBitsSetListSize > 0 && maxBitsSetListSize < 257 && ptrNbBitsSetFound != NULL) + { + // For the moment consider we have not found any bit set + *ptrNbBitsSetFound = 0; + + // Empty BIT STRING object if length equal to 1. Empty value will be tested below + if(ASN1BitStringLength > 1) + { + // Check padding bits value, stored on first byte of ASN1 object. 8 bits padding is a nonsense, no need to add a byte for nothing + if(ptrASN1BitString[0] >=0 && ptrASN1BitString[0] < 8) + { + // At this step we consider that ASN1 object is correct + res = true; + + // Parse BIT STRING bytes - Can still exit on error if size of output array is too small or too much bits to evaluate + while((idxBitString < ASN1BitStringLength) && res) + { + byteMask = 0x80; + + // Check if last byte is reached. If yes limit bits evaluated using padding bits value + if(idxBitString < (ASN1BitStringLength - 1)) + maxBitCounter = 8; + else + maxBitCounter = 8 - ptrASN1BitString[0]; + + for(bitIndex = 0; bitIndex < maxBitCounter; bitIndex++) + { + // Check if not overflow capacity of output list (Array of bytes so no more than 256 bits) + // Note: Checking done here else will fail when bit is the 255th and the last one to check + if(currentBitNumber > 255) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "extractBitsSetListInStaticASN1BitString: Evaluated bit number overflows output list capabilities (Value above 255)"); + res = false; + break; // Break FOR loop, "res" value will break WHILE loop + } + + // Check if current bit set in current BIT STRING byte. If yes put it in list + if((ptrASN1BitString[idxBitString] & byteMask) > 0) + { + // Check if not overflow output list array + if(idxOutputList < maxBitsSetListSize) + { + // Memorizes bit in list + ptrBitsSetList[idxOutputList] = (unsigned char)(currentBitNumber & 0x00FF); + idxOutputList++; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "extractBitsSetListInStaticASN1BitString: Output list array too small"); + res = false; + break; // Break FOR loop, "res" value will break WHILE loop + } + } + + // Increase bit number for next evaluation + currentBitNumber++; + + // Shift bit mask + byteMask = byteMask >> 1; + } + + // Got to the next BIT STRING byte + idxBitString++; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "extractBitsSetListInStaticASN1BitString: Invalid padding bits value detected: %u", ptrASN1BitString[0]); + } + else + { + // Check if empty bit string value is correctly set + if(ptrASN1BitString[0] == 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "extractBitsSetListInStaticASN1BitString: Empty BIT STRING object detected."); + res = true; + // Number of bit set found already set to 0 + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "extractBitsSetListInStaticASN1BitString: Invalid BIT STRING object detected (Size < 2 but value not zero)."); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "extractBitsSetListInStaticASN1BitString: Invalid Parameters."); + + // If OK, return number of set bits stored in output list + if(res) + *ptrNbBitsSetFound = idxOutputList; + + return res; +} + + +/** + * Check if a specific bit (Bit number) has been set in Static BIT STRING ASN1 object. Can process both DER and BER encoding (0 or 1 padded expression). + * @param ptrASN1BitString Pointer on array containing Bit String value (Without Tag and length bytes) + * @param ASN1BitStringLength Length of Bit String Value contained in array + * @param bitToCheck Number of bit to check in ASN1 BIT STRING object (From 0 to 255) + * @param ptrIsPresent Will be set to True if targeted bit is set in BIT STRING object + * @return True if checking process is OK, else false + */ +bool checkBitSetInStaticASN1BitString(const unsigned char * ptrASN1BitString, const size_t ASN1BitStringLength, const unsigned char bitToCheck, bool * ptrIsPresent) +{ + bool res = false; + + unsigned char bitsSetList[256]; + size_t numberOfBitSet = 0; + size_t idx = 0; + + if(ptrASN1BitString != NULL && ASN1BitStringLength > 0 && ptrIsPresent != NULL) + { + *ptrIsPresent = false; + + res = extractBitsSetListInStaticASN1BitString(ptrASN1BitString, ASN1BitStringLength, bitsSetList, 256, &numberOfBitSet); + + // If no error during bits extraction and some set bits have been found, compare with bit to check + if(res && numberOfBitSet > 0) + { + for(idx = 0; idx < numberOfBitSet; idx++) + { + if(bitsSetList[idx] == bitToCheck) + { + *ptrIsPresent = true; + break; // No need to parse other bits + } + } + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "checkBitSetInStaticASN1BitString: Invalid Parameters."); + + return res; +} diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/driver/httpmedia_curl.c b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/driver/httpmedia_curl.c new file mode 100755 index 000000000..99bc41196 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/driver/httpmedia_curl.c @@ -0,0 +1,925 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + +#include +#include +#include +#include +#include "curl/curl.h" + +#include "lpasdk/core/lpa_log.h" +#include "lpasdk/core/lpa_memory.h" +#include "lpasdk/core/httpmedia_base.h" +#include "lpasdk/driver/httpmedia_curl.h" + + +THTTPMedia* New_HTTPMediaCurl(); +void Delete_HTTPMediaCurl(THTTPMedia* httpMedia); + +static size_t _WriteRespCallback(void *contents, size_t size, size_t nmemb, void *userp); + +bool _httpMediaConfigure(const THTTPMedia* httpMedia); +bool _httpMediaSetTargetUrl(const THTTPMedia* httpMedia, const char* ptrTargetURL); +bool _httpMediaSetCertificatePath(const THTTPMedia* httpMedia, const char* ptrCertificatePath); +bool _httpMediaSetPostData(const THTTPMedia* httpMedia, const char* ptrPostdata); +bool _httpMediaSetHeaders(const THTTPMedia* httpMedia); + +bool _httpMediaSetBooleanOption(const THTTPMedia* ptrHttpMedia, HttpMediaOptionType optionType, bool enabled); +bool _httpMediaGetBooleanOption(const THTTPMedia* ptrHttpMedia, HttpMediaOptionType optionType, bool* ptrEnabled); + +bool _httpMediaSetLongOption(const THTTPMedia* ptrHttpMedia, HttpMediaOptionType optionType, long value); +bool _httpMediaGetLongOption(const THTTPMedia* ptrHttpMedia, HttpMediaOptionType optionType, long* ptrValue); + +bool _httpMediaSetCallbackEventExecutionError(const THTTPMedia* httpMedia, LPA_EVENT_EXECUTION_ERROR lpaEventExecutionErrorCallback); + +bool _httpMediaSetCallback(const THTTPMedia* httpMedia); +bool _httpMediaSetWriteData(const THTTPMedia* httpMedia); +char* _httpMediaGetBufferResponse(const THTTPMedia* httpMedia); + +bool _httpMediaHttpExecutePost(const THTTPMedia* httpMedia, long *ptrHttpCode); + +bool _httpMediaPost(const THTTPMedia* httpMedia, const char* ptrCertificatePath, const char* ptrTargetURL, const char* ptrPostdata, long* ptrHttpCode); + +void _httpMediaHttpExecuteCleanup(const THTTPMedia* httpMedia); +bool _httpMediaHttpExecuteInit(const THTTPMedia* httpMedia); + +static bool _curlOptionSSLVerifyPeer = true; +static bool _curlOptionSSLVerifyHost = true; +static bool _curlOptionVerbose = false; + +static long _curlOptionTimeOut = 30; // seconds +static long _curlOptionConnectTimeOut = 30; // seconds + +static unsigned int _curlVersion = 0; + +// Event execution error callback +static LPA_EVENT_EXECUTION_ERROR _lpaEventExecutionErrorCallback = NULL; + +#ifdef LPA_SDK__CURL_MEMORY +void *_httpMediaMallocCallback(size_t size); +void _httpMediaFreeCallback(void *ptr); +void *_httpMediaReallocCallback(void *ptr, size_t size); +char *_httpMediaStrdupCallback(const char *str); +void *_httpMediaCallocCallback(size_t nmemb, size_t size); +#endif // LPA_SDK__CURL_MEMORY + +//////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////// + +static size_t _WriteRespCallback(void *contents, size_t size, size_t nmemb, void *userp) +{ + size_t realsize = size * nmemb; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+httpmedia_curl :> _WriteRespCallback()"); + + if (NULL == contents || NULL == userp) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid NULL parameter!"); + return 0; + } + + struct RespStruct *respStr = (struct RespStruct *) userp; + + void* ptrRealloc = lpaCoreMemoryRealloc(respStr->resp, respStr->size + realsize + 1); + if (NULL == ptrRealloc) + { + // out of memory! + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Not enough memory (realloc returned NULL)"); + return 0; + } + respStr->resp = ptrRealloc; + memcpy(&(respStr->resp[respStr->size]), contents, realsize); + respStr->size += realsize; + respStr->resp[respStr->size] = 0; + + return realsize; +} + +THTTPMedia* New_HTTPMediaCurl() +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+httpmedia_curl :> New_HTTPMediaCurl()"); + + THTTPMedia* ptrHTTPMedia = NULL; + + THTTPMediaCURL* httpMediaCurl = (THTTPMediaCURL*) lpaCoreMemoryAlloc(sizeof (THTTPMediaCURL)); + if (httpMediaCurl != NULL) + { + httpMediaCurl->_base = New_HTTPMediaBase(); + if (httpMediaCurl->_base != NULL) + { + httpMediaCurl->_base->_childStruct = httpMediaCurl; + + httpMediaCurl->_base->httpMediaPost = _httpMediaPost; + httpMediaCurl->_base->httpMediaSetBooleanOption = _httpMediaSetBooleanOption; + httpMediaCurl->_base->httpMediaGetBooleanOption = _httpMediaGetBooleanOption; + + httpMediaCurl->_base->httpMediaGetBufferResponse = _httpMediaGetBufferResponse; + + httpMediaCurl->_base->httpMediaSetLongOption = _httpMediaSetLongOption; + httpMediaCurl->_base->httpMediaGetLongOption = _httpMediaGetLongOption; + + httpMediaCurl->_base->httpMediaHttpExecuteCleanup = _httpMediaHttpExecuteCleanup; + httpMediaCurl->_base->httpMediaHttpExecuteInit = _httpMediaHttpExecuteInit; + + httpMediaCurl->_base->httpMediaSetCallbackEventExecutionError = _httpMediaSetCallbackEventExecutionError; + + memset(&httpMediaCurl->_respdata, 0, sizeof(struct RespStruct)); + httpMediaCurl->_headers = NULL; + httpMediaCurl->_curl = NULL; + + _curlVersion = 0; // CURL Version not yet retrieved + +#ifdef LPA_SDK__CURL_MEMORY + CURLcode curlCode = curl_global_init_mem(CURL_GLOBAL_DEFAULT, _httpMediaMallocCallback, _httpMediaFreeCallback, _httpMediaReallocCallback, _httpMediaStrdupCallback, _httpMediaCallocCallback); + if(curlCode == CURLE_OK) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "CURL global memory initialization done successfully"); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Error during curl_global_init_mem()!"); +#endif // LPA_SDK__CURL_MEMORY + + ptrHTTPMedia = (THTTPMedia*)httpMediaCurl->_base; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "New_HTTPMediaCurl(): Cannot allocate memory for _base object!!"); + lpaCoreMemoryFree(httpMediaCurl); + httpMediaCurl = NULL; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "New_HTTPMediaCurl(): Cannot allocate memory for THTTPMediaCURL object!"); + + // By default, No callback available for LPA Event Execution error + _lpaEventExecutionErrorCallback = NULL; + + return ptrHTTPMedia; +} + +//////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////// + +void Delete_HTTPMediaCurl(THTTPMedia* httpMedia) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+httpmedia_curl :> Delete_HTTPMediaCurl()"); + + if (httpMedia != NULL) + { + THTTPMediaCURL* httpMediaCurl = (THTTPMediaCURL*)httpMedia->_childStruct; + if (httpMediaCurl != NULL) + { +#ifdef LPA_SDK__CURL_MEMORY + curl_global_cleanup(); +#endif // LPA_SDK__CURL_MEMORY + + lpaCoreMemoryFree(httpMediaCurl); + } + lpaCoreMemoryFree(httpMedia); + httpMedia = NULL; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Delete_HTTPMediaCurl() => Invalid parameter: httpMedia is NULL!"); +} + +//////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////// + +bool _httpMediaConfigure(const THTTPMedia* httpMedia) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+httpmedia_curl :> _httpMediaConfigure()"); + + if (httpMedia != NULL) + { + THTTPMediaCURL* httpMediaCurl = (THTTPMediaCURL*)httpMedia->_childStruct; + + if (httpMediaCurl != NULL && httpMediaCurl->_curl != NULL) + { + CURLcode curlCodeSSL_VERIFYPEER = curl_easy_setopt(httpMediaCurl->_curl, CURLOPT_SSL_VERIFYPEER, (_curlOptionSSLVerifyPeer ? 1 : 0)); + CURLcode curlCodeSSL_VERIFYHOST = curl_easy_setopt(httpMediaCurl->_curl, CURLOPT_SSL_VERIFYHOST, (_curlOptionSSLVerifyHost ? 2 : 0)); + CURLcode curlCodeVERBOSE = curl_easy_setopt(httpMediaCurl->_curl, CURLOPT_VERBOSE, (_curlOptionVerbose ? 1 : 0)); + + res = ((curlCodeSSL_VERIFYPEER == CURLE_OK) && (curlCodeSSL_VERIFYHOST == CURLE_OK) && (curlCodeVERBOSE == CURLE_OK)); + +#if defined(LPA_SDK__PLATFORM_WIN) && defined(LPA_SDK__CURLSSLOPT_NO_REVOKE) + if (res) + { + if (_curlVersion >= 0x072C00) // CURLSSLOPT_NO_REVOKE present since CURL 7.44.0 + { + if (curl_easy_setopt(httpMediaCurl->_curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE) != CURLE_OK) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_httpMediaConfigure() => Unable to do CURLSSLOPT_NO_REVOKE"); + res = false; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_httpMediaConfigure() => CURLSSLOPT_NO_REVOKE done successfully"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_httpMediaConfigure() => Unable to do CURLSSLOPT_NO_REVOKE (option not supported by current CURL library)"); + } +#endif // LPA_SDK__PLATFORM_WIN && LPA_SDK__CURLSSLOPT_NO_REVOKE + + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_httpMediaConfigure() => Invalid parameter: httpMedia is NULL!"); + + return res; +} + +//////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////// + +bool _httpMediaSetTargetUrl(const THTTPMedia* httpMedia, const char* ptrTargetURL) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+httpmedia_curl :> _httpMediaSetTargetUrl()"); + + if (httpMedia != NULL && ptrTargetURL != NULL) + { + THTTPMediaCURL* httpMediaCurl = (THTTPMediaCURL*)httpMedia->_childStruct; + + if (httpMediaCurl != NULL && httpMediaCurl->_curl != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, "* _httpMediaSetTargetUrl: %s", ptrTargetURL); + CURLcode curlCode = curl_easy_setopt(httpMediaCurl->_curl, CURLOPT_URL, ptrTargetURL); + if( curlCode == CURLE_OK ) + res = true; + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_httpMediaSetTargetUrl failed (curl error code: %d) => %s", curlCode, curl_easy_strerror(curlCode)); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_VERBOSE, " _httpMediaSetTargetUrl failed"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_httpMediaSetTargetUrl() => Invalid parameter NULL detected!"); + + return res; +} + +bool _httpMediaHttpExecuteInit(const THTTPMedia* httpMedia) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+httpmedia_curl :> _httpMediaHttpExecuteInit()"); + if (httpMedia != NULL) + { + THTTPMediaCURL* httpMediaCurl = (THTTPMediaCURL*)httpMedia->_childStruct; + if (httpMediaCurl != NULL) + { + httpMediaCurl->_curl = curl_easy_init(); + if (httpMediaCurl->_curl != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_httpMediaHttpExecuteInit() Init Success"); + + + curl_version_info_data * ptrData = curl_version_info(CURLVERSION_NOW); + if (ptrData != NULL) + { + if (ptrData->age >= 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "curl version: %s", (ptrData->version ? ptrData->version : "N/A")); + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "curl host : %s", (ptrData->host != NULL ? ptrData->host : "N/A")); + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "curl feature: 0x%lx", ptrData->features); + + _curlVersion = ptrData->version_num; + + // Check Minimal CURL version required + if (_curlVersion > 0x072200) // Minimal release required: 7.34.0 + { + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "curl version supported"); + + CURLcode curlCode = curl_easy_setopt(httpMediaCurl->_curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); + if (curlCode == CURLE_OK) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "CURL using TLS v1.2 or later"); + res = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Unable to use TLS v1.2 or later! (CURL configuration)"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "curl version not supported (require 7.34 or more)"); + } + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_httpMediaHttpExecuteInit() Initialization Failed"); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter: httpMedia is NULL!"); + + return res; +} + +bool _httpMediaSetCertificatePath(const THTTPMedia* httpMedia, const char* ptrCertificatePath) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+httpmedia_curl :> _httpMediaSetCertificatePath()"); + + if (httpMedia != NULL && ptrCertificatePath != NULL) + { + THTTPMediaCURL* httpMediaCurl = (THTTPMediaCURL*)httpMedia->_childStruct; + if (httpMediaCurl->_curl) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_httpMediaSetCertificatePath..."); + CURLcode curlCode = curl_easy_setopt(httpMediaCurl->_curl, CURLOPT_CAINFO, ptrCertificatePath); + if (curlCode == CURLE_OK) + res = true; + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_httpMediaSetCertificatePath failed (curl error code: %d) => %s", curlCode, curl_easy_strerror(curlCode)); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_httpMediaSetCertificatePath() => Invalid parameter NULL detected!"); + + return res; +} + +bool _httpMediaSetPostData(const THTTPMedia* httpMedia, const char* ptrPostdata) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+httpmedia_curl :> _httpMediaSetPostData()"); + if (httpMedia != NULL && ptrPostdata != NULL) + { + THTTPMediaCURL* httpMediaCurl = (THTTPMediaCURL*)httpMedia->_childStruct; + if (httpMediaCurl != NULL) + { + if (httpMediaCurl->_curl != NULL ) + { + CURLcode curlCode = curl_easy_setopt(httpMediaCurl->_curl, CURLOPT_POST, 1); + + if( curlCode == CURLE_OK) + curlCode = curl_easy_setopt(httpMediaCurl->_curl, CURLOPT_POSTFIELDS, ptrPostdata); + + if (curlCode == CURLE_OK) + curlCode = curl_easy_setopt(httpMediaCurl->_curl, CURLOPT_NOSIGNAL, 1); + + if (curlCode == CURLE_OK) + curlCode = curl_easy_setopt(httpMediaCurl->_curl, CURLOPT_CONNECTTIMEOUT, _curlOptionConnectTimeOut); + + if (curlCode == CURLE_OK) + curlCode = curl_easy_setopt(httpMediaCurl->_curl, CURLOPT_TIMEOUT, _curlOptionTimeOut); + + if (curlCode == CURLE_OK) + res = true; + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "setPostData failed (curl error code: %d) => %s", curlCode, curl_easy_strerror(curlCode)); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_httpMediaSetPostData => httpMediaCurl is NULL!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_httpMediaSetPostData => Invalid parameter NULL detected!"); + + return res; +} + +bool _httpMediaSetHeaders(const THTTPMedia* httpMedia) +{ + bool res = false; + + if (httpMedia != NULL) + { + THTTPMediaCURL* httpMediaCurl = (THTTPMediaCURL*)httpMedia->_childStruct; + if (httpMediaCurl != NULL) + { + if (httpMediaCurl->_curl != NULL) + { + struct curl_slist *headers = NULL; + + headers = curl_slist_append(headers, "X-Admin-Protocol:gsma/rsp/v2.3"); + headers = curl_slist_append(headers, "content-type:application/json"); + headers = curl_slist_append(headers, "charset:utf-8"); + headers = curl_slist_append(headers, "User-Agent: gsma-rsp-lpad"); + headers = curl_slist_append(headers, "Expect:"); + + httpMediaCurl->_headers = headers; + + CURLcode curlCode = curl_easy_setopt(httpMediaCurl->_curl, CURLOPT_HTTPHEADER, httpMediaCurl->_headers); + + if (curlCode == CURLE_OK) + res = true; + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_httpMediaSetHeaders failed (curl error code: %d) => %s", curlCode, curl_easy_strerror(curlCode)); + } + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_httpMediaSetHeaders() => Invalid parameter: httpMedia is NULL!"); + + return res; +} + +bool _httpMediaSetBooleanOption(const THTTPMedia* ptrHttpMedia, HttpMediaOptionType optionType, bool enabled) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+httpmedia_curl :> _httpMediaSetBooleanOption()"); + + bool isOptionIgnored = false; + + switch (optionType) + { + case HTTP_MEDIA_OPTION_TYPE_CURL_SSL_VERIFYPEER: + _curlOptionSSLVerifyPeer = enabled; + break; + + case HTTP_MEDIA_OPTION_TYPE_CURL_SSL_VERIFYHOST: + _curlOptionSSLVerifyHost = enabled; + break; + + case HTTP_MEDIA_OPTION_TYPE_CURL_VERBOSE: + _curlOptionVerbose = enabled; + break; + + default: + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "HttpMediaOptionType '%d' not supported", optionType); + isOptionIgnored = true; + break; + } + + if (!isOptionIgnored) + res = true; + + return res; +} + +bool _httpMediaGetBooleanOption(const THTTPMedia* ptrHttpMedia, HttpMediaOptionType optionType, bool* ptrEnabled) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+httpmedia_curl :> _httpMediaGetBooleanOption()"); + + if ( ptrEnabled != NULL) + { + bool isOptionIgnored = false; + switch (optionType) + { + case HTTP_MEDIA_OPTION_TYPE_CURL_SSL_VERIFYPEER: + *ptrEnabled = _curlOptionSSLVerifyPeer; + break; + + case HTTP_MEDIA_OPTION_TYPE_CURL_SSL_VERIFYHOST: + *ptrEnabled = _curlOptionSSLVerifyHost; + break; + + case HTTP_MEDIA_OPTION_TYPE_CURL_VERBOSE: + *ptrEnabled = _curlOptionVerbose; + break; + + default: + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "HttpMediaOptionType '%d' not supported", optionType); + isOptionIgnored = true; + break; + } + + if (!isOptionIgnored) + res = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_httpMediaGetBooleanOption() => Invalid parameter: ptrEnabled is NULL!"); + + return res; +} + +bool _httpMediaSetLongOption(const THTTPMedia* ptrHttpMedia, HttpMediaOptionType optionType, long value) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+httpmedia_curl :> _httpMediaSetBooleanOption()"); + + bool isOptionIgnored = false; + + switch (optionType) + { + case HTTP_MEDIA_OPTION_TYPE_CURL_CONNECT_TIMEOUT: + _curlOptionConnectTimeOut = value; + break; + + case HTTP_MEDIA_OPTION_TYPE_CURL_TIMEOUT: + _curlOptionTimeOut = value; + break; + + default: + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "HttpMediaOptionType '%d' not supported", optionType); + isOptionIgnored = true; + break; + } + + if (!isOptionIgnored) + res = true; + + return res; +} + +bool _httpMediaGetLongOption(const THTTPMedia* ptrHttpMedia, HttpMediaOptionType optionType, long* ptrValue) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+httpmedia_curl :> _httpMediaGetLongOption()"); + + if (ptrValue != NULL) + { + bool isOptionIgnored = false; + switch (optionType) + { + case HTTP_MEDIA_OPTION_TYPE_CURL_CONNECT_TIMEOUT: + *ptrValue = _curlOptionConnectTimeOut; + break; + + case HTTP_MEDIA_OPTION_TYPE_CURL_TIMEOUT: + *ptrValue = _curlOptionTimeOut; + break; + + default: + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "HttpMediaOptionType '%d' not supported", optionType); + isOptionIgnored = true; + break; + } + + if (!isOptionIgnored) + res = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_httpMediaGetLongOption() => Invalid parameter: ptrValue is NULL!"); + + return res; +} + +bool _httpMediaSetCallbackEventExecutionError(const THTTPMedia* httpMedia, LPA_EVENT_EXECUTION_ERROR lpaEventExecutionErrorCallback) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ httpmedia_curl :> _httpMediaSetCallbackEventExecutionError()"); + + bool res = false; + + if (lpaEventExecutionErrorCallback != NULL) + { + if (_lpaEventExecutionErrorCallback != lpaEventExecutionErrorCallback) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, " registering lpaEventExecutionErrorCallback..."); + _lpaEventExecutionErrorCallback = lpaEventExecutionErrorCallback; + res = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, " LpaEventExecutionErrorCallback already registered!"); + } + else + { + if (_lpaEventExecutionErrorCallback != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, " unregistering lpaEventExecutionErrorCallback..."); + _lpaEventExecutionErrorCallback = NULL; + res = true; + } + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- httpmedia_curl :> _httpMediaSetCallbackEventExecutionError() return res=%s", (res ? "true" : "false")); + + return res; +} + +bool _httpMediaSetCallback(const THTTPMedia* httpMedia) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+httpmedia_curl :> _httpMediaSetCallback()"); + + if (httpMedia != NULL) + { + THTTPMediaCURL* httpMediaCurl = (THTTPMediaCURL*)httpMedia->_childStruct; + if (httpMediaCurl != NULL) + { + if (httpMediaCurl->_curl != NULL) + { + CURLcode curlCode = curl_easy_setopt(httpMediaCurl->_curl, CURLOPT_WRITEFUNCTION, _WriteRespCallback); + if (curlCode == CURLE_OK) + res = true; + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_httpMediaSetCallback failed (curl error code: %d) => %s", curlCode, curl_easy_strerror(curlCode)); + } + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "_httpMediaSetCallback() => httpMedia is NULL!"); // For the moment I think it shall stay to WARNING in case callback not defined + + return res; +} + +bool _httpMediaSetWriteData(const THTTPMedia* httpMedia) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+httpmedia_curl :> _httpMediaSetWriteData()"); + + if (httpMedia != NULL) + { + THTTPMediaCURL* httpMediaCurl = (THTTPMediaCURL*)httpMedia->_childStruct; + if (httpMediaCurl != NULL) + { + if (httpMediaCurl->_curl != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "start to do http easy perform"); + CURLcode curlCode = curl_easy_setopt(httpMediaCurl->_curl, CURLOPT_WRITEDATA, (void *)&httpMediaCurl->_respdata); + if (curlCode == CURLE_OK) + res = true; + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_httpMediaSetWriteData failed (curl error code: %d) => %s", curlCode, curl_easy_strerror(curlCode)); + } + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_httpMediaSetWriteData() => Invalid parameter: httpMedia is NULL!"); + + return res; +} + +bool _httpMediaHttpExecutePost(const THTTPMedia* httpMedia, long *ptrHttpCode) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+httpmedia_curl :> _httpMediaHttpExecutePost()"); + + if (httpMedia == NULL || ptrHttpCode == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Invalid parameter NULL detected!"); + return res; + } + + THTTPMediaCURL* httpMediaCurl = (THTTPMediaCURL*) httpMedia->_childStruct; + *ptrHttpCode = 0; // By default + + CURLcode ret; + ret = curl_easy_perform(httpMediaCurl->_curl); + if (CURLE_OK == ret) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "the http execution result: >> CURLE_OK :)"); + + if (curl_easy_getinfo(httpMediaCurl->_curl, CURLINFO_RESPONSE_CODE, ptrHttpCode) == CURLE_OK ) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "curl => HTTP code: %ld ", *ptrHttpCode); + else + { + *ptrHttpCode = 0; + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "curl => Unable to get HTTP code!"); + } + + res = true; + } + else + { + const char* curlStrError = curl_easy_strerror(ret); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Http execution failed (curl error code: %d) => %s", ret, (curlStrError != NULL ? curlStrError : "N/A")); + + if (_lpaEventExecutionErrorCallback != NULL) + { + LPA_EVENT_EXECUTION_ERROR_INFO eventExecutionErrorInfo; + char errorSubjectCode[16]; + snprintf(errorSubjectCode, sizeof(errorSubjectCode), "%d", ret); + + eventExecutionErrorInfo.executionErrorType = LPA_EVENT_EXECUTION_CURL_ERROR_TYPE; + eventExecutionErrorInfo.detailErrorMask = LPA_EVENT_EXECUTION_ERROR_SUBJECT_CODE_MASK; + eventExecutionErrorInfo.ptrErrorReasonCode = NULL; + eventExecutionErrorInfo.ptrErrorSubjectCode = errorSubjectCode; + + if (curlStrError != NULL) + { + eventExecutionErrorInfo.detailErrorMask |= LPA_EVENT_EXECUTION_ERROR_EXTRA_INFO_MASK; + eventExecutionErrorInfo.ptrErrorExtraInfo = curl_easy_strerror(ret); + } + + _lpaEventExecutionErrorCallback(NULL, &eventExecutionErrorInfo); + } + + res = false; + } + + return res; +} + +char* _httpMediaGetBufferResponse(const THTTPMedia* httpMedia) +{ + if(httpMedia != NULL) + { + THTTPMediaCURL* httpMediaCurl = (THTTPMediaCURL*)httpMedia->_childStruct; + return ( httpMediaCurl != NULL ? httpMediaCurl->_respdata.resp : NULL); + } + else + return NULL; +} + +bool _httpMediaPost(const THTTPMedia* httpMedia, const char* ptrCertificatePath, const char* ptrTargetURL, const char* ptrPostdata, long* ptrHttpCode) +{ + bool resHttpMediaCall = false; + + if(httpMedia != NULL && ptrCertificatePath != NULL && ptrTargetURL != NULL && ptrPostdata != NULL && ptrHttpCode != NULL) + { + resHttpMediaCall = _httpMediaConfigure(httpMedia); + if (resHttpMediaCall) + resHttpMediaCall = _httpMediaSetTargetUrl(httpMedia,ptrTargetURL); + + if (resHttpMediaCall) + resHttpMediaCall = _httpMediaSetPostData(httpMedia,ptrPostdata); + + if (resHttpMediaCall) + resHttpMediaCall = _httpMediaSetHeaders(httpMedia); + + if(ptrCertificatePath != NULL) + { + if (resHttpMediaCall && strlen(ptrCertificatePath) > 0) + { + resHttpMediaCall = _httpMediaSetCertificatePath(httpMedia,ptrCertificatePath); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Certificate path is: %s", ptrCertificatePath); + } + } + else + resHttpMediaCall = false; + + if (resHttpMediaCall) + resHttpMediaCall = _httpMediaSetCallback(httpMedia); + + if (resHttpMediaCall) + resHttpMediaCall = _httpMediaSetWriteData(httpMedia); + + //start to execute post + if (resHttpMediaCall) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "HTTP execute post..."); + resHttpMediaCall = _httpMediaHttpExecutePost(httpMedia, ptrHttpCode); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_httpMediaGetBufferResponse() => Invalid parameter NULL detected!"); + + return resHttpMediaCall; +} + + + +void _httpMediaHttpExecuteCleanup(const THTTPMedia* httpMedia) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+httpmedia_curl :> _httpMediaHttpExecuteCleanup()"); + + if (httpMedia != NULL) + { + THTTPMediaCURL* httpMediaCurl = (THTTPMediaCURL*)httpMedia->_childStruct; + + if (httpMediaCurl->_headers != NULL) + { + curl_slist_free_all(httpMediaCurl->_headers); + httpMediaCurl->_headers = NULL; + } + + if (httpMediaCurl->_respdata.resp != NULL ) + { + lpaCoreMemoryFree(httpMediaCurl->_respdata.resp); + httpMediaCurl->_respdata.resp = NULL; + } + + httpMediaCurl->_respdata.size = 0; + + if (httpMediaCurl->_curl != NULL) + { + curl_easy_cleanup(httpMediaCurl->_curl); + httpMediaCurl->_curl = NULL; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_httpMediaHttpExecuteCleanup() => Invalid parameter: httpMedia is NULL!"); +} + + +///////////////////////// +// Memory Callback +///////////////////////// + +#ifdef LPA_SDK__CURL_MEMORY + +void *_httpMediaMallocCallback(size_t size) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[CURL_MEM] + httpmedia_curl:>_httpMediaMallocCallback()"); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[CURL_MEM] malloc(%llu bytes)...", (long long unsigned)size); + + void* ptrMalloc = NULL; + +#if defined(LPA_SDK__CURL_MEMORY_MONITORING) && defined(LPA_SDK__MEMORY) + ptrMalloc = lpaCoreMemoryAlloc(size); +#else + ptrMalloc = malloc(size); +#endif // LPA_SDK__CURL_MEMORY_MONITORING && LPA_SDK__MEMORY + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[CURL_MEM] allocated memory: 0x%lx", ptrMalloc); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[CURL_MEM] - httpmedia_curl:>_httpMediaMallocCallback()"); + + return ptrMalloc; +} + +void _httpMediaFreeCallback(void *ptr) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[CURL_MEM] + httpmedia_curl:>_httpMediaFreeCallback()"); + + if(ptr != NULL ) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[CURL_MEM] Free (0x%lx)...", ptr); + +#if defined(LPA_SDK__CURL_MEMORY_MONITORING) && defined(LPA_SDK__MEMORY) + lpaCoreMemoryFree(ptr); +#else + free(ptr); +#endif // LPA_SDK__CURL_MEMORY_MONITORING && LPA_SDK__MEMORY + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[CURL_MEM] Free (NULL) => Do nothing"); + + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[CURL_MEM] - httpmedia_curl:>_httpMediaFreeCallback()"); +} + +void *_httpMediaReallocCallback(void *ptr, size_t size) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[CURL_MEM] + httpmedia_curl:>_httpMediaReallocCallback()"); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[CURL_MEM] Realloc (0x%lx,%llu bytes)...", ptr, (long long unsigned)size); + + void* ptrRealloc = NULL; + +#if defined(LPA_SDK__CURL_MEMORY_MONITORING) && defined(LPA_SDK__MEMORY) + ptrRealloc = lpaCoreMemoryRealloc(ptr, size); +#else + ptrRealloc = realloc(ptr, size); +#endif // LPA_SDK__CURL_MEMORY_MONITORING && LPA_SDK__MEMORY + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[CURL_MEM] reallocated memory: 0x%lx", ptrRealloc); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[CURL_MEM] - httpmedia_curl:>_httpMediaReallocCallback()"); + return ptrRealloc; +} + +char *_httpMediaStrdupCallback(const char *str) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[CURL_MEM] + httpmedia_curl:>_httpMediaStrdupCallback()"); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[CURL_MEM] Strdup (0x%lx)...", str); + + char* ptrStrdup = NULL; + + if (str != NULL) + { + size_t strSize = strlen(str) + 1; +#if defined(LPA_SDK__CURL_MEMORY_MONITORING) && defined(LPA_SDK__MEMORY) + ptrStrdup = lpaCoreMemoryAlloc(strSize); +#else + ptrStrdup = malloc(strSize); +#endif // LPA_SDK__CURL_MEMORY_MONITORING && LPA_SDK__MEMORY + if (ptrStrdup != NULL) + { + memcpy(ptrStrdup, str, strSize); + ptrStrdup[strSize] = 0; + } + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[CURL_MEM] ptrStrdup => 0x%lx", ptrStrdup); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[CURL_MEM] - httpmedia_curl:>_httpMediaStrdupCallback()"); + + return ptrStrdup; +} + +void *_httpMediaCallocCallback(size_t nmemb, size_t size) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[CURL_MEM] + httpmedia_curl:>_httpMediaCallocCallback()"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[CURL_MEM] Calloc %llu,%llu...", (long long unsigned)nmemb, (long long unsigned)size); + + void* ptrCalloc = NULL; + +#if defined(LPA_SDK__CURL_MEMORY_MONITORING) && defined(LPA_SDK__MEMORY) + ptrCalloc = lpaCoreMemoryCalloc(nmemb, size); +#else + ptrCalloc = calloc(nmemb, size); +#endif // LPA_SDK__CURL_MEMORY_MONITORING && LPA_SDK__MEMORY + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[CURL_MEM] Calloc=> 0x%lx ", ptrCalloc); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[CURL_MEM] - httpmedia_curl:>_httpMediaCallocCallback()"); + + return ptrCalloc; +} + +#endif // LPA_SDK__CURL_MEMORY diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/driver/semedia_genericmodem.c b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/driver/semedia_genericmodem.c new file mode 100755 index 000000000..651680316 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/driver/semedia_genericmodem.c @@ -0,0 +1,1930 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + + +#include "lpasdk/driver/semedia_genericmodem.h" +#include "lpasdk/core/lpa_log.h" +#include "lpasdk/core/lpa_memory.h" +#include "lpasdk/core/util.h" + + +// This driver is compiled only if LPA_SDK__SEMEDIA_DRIVER_GENERIC_MODEM build option exist +#ifdef LPA_SDK__SEMEDIA_DRIVER_GENERIC_MODEM + +// For specific flags used by open() +#include + +#if defined(LPA_SDK__PLATFORM_CYGWIN) || defined(LPA_SDK__PLATFORM_RASPBIAN) + +#include +#include + +// For timer features +#include + +#endif // LPA_SDK__PLATFORM_CYGWIN || LPA_SDK__PLATFORM_RASPBIAN + + +// Functions needed for SE Media driver +bool _seMediaGenericModemSetCallbackEventExecutionError(const struct TSEMedia* ptrTSEMedia, LPA_EVENT_EXECUTION_ERROR lpaEventExecutionErrorCallback); + +bool _seMediaGenericModemEstablishContext(const struct TSEMedia* ptrTSEMedia); +bool _seMediaGenericModemReleaseContext(const struct TSEMedia* ptrTSEMedia); +bool _seMediaGenericModemIsValidContext(const struct TSEMedia* ptrTSEMedia); +bool _seMediaGenericModemIsContextEstablished(const struct TSEMedia* ptrTSEMedia); + +bool _seMediaGenericModemListReader(const struct TSEMedia* ptrTSEMedia, LPA_SE_MEDIA_READER_NAME_INFO * ptrReaderNameInfoList, size_t readerNameInfoMax, size_t* ptrCountReader); +bool _seMediaGenericModemConnect(const struct TSEMedia* ptrTSEMedia, const char *ptrReaderName); +bool _seMediaGenericModemTransmitApdu(const struct TSEMedia* ptrTSEMedia, const unsigned char* ptrApduCommandBytes, size_t apduCommandSize, unsigned char* ptrApduResponseBytes, size_t* ptrApduResponseMaxSize); +bool _seMediaGenericModemIsConnected(const struct TSEMedia* ptrTSEMedia); +bool _seMediaGenericModemDisconnect(const struct TSEMedia* ptrTSEMedia); +bool _seMediaGenericModemDisconnectWithReset(const struct TSEMedia* ptrTSEMedia); + +bool _seMediaGenericModemGetStatus(const struct TSEMedia* ptrTSEMedia, SE_MEDIA_CARD_STATUS* ptrStatus); + +// Internal functions to process APDU and AT commands +static bool _seMediaGenericModemApduToAtCommand(const char* ptrAPDU_cmd, char* ptrBuild_ATcommand, const size_t pMaxSize); +static bool _seMediaGenericModemAtCommandResponseToApdu(const char* ptrAt_command_response, char* ptrAPDU_response, size_t pMaxSize); +static bool _seMediaGenericModemCheckAPDU_OkResponse(const char* ptrAPDU_response); +static bool _seMediaGenericModemGetATcommandResponseData(const struct TSEMedia* ptrTSEMedia); +static bool _seMediaGenericModemCheckATcommandResponseOK(void); +static bool _seMediaGenericModemSendAPDUtoModemAndCheckOK(const char* ptrAPDU, const struct TSEMedia* ptrTSEMedia, bool checkStatusWord); +static bool _seMediaGenericModemOpenUICCChannel(const struct TSEMedia* ptrTSEMedia); +static bool _seMediaGenericModemCloseUICCChannel(const struct TSEMedia* ptrTSEMedia); +static bool _seMediaGenericModemProcessAPDUresponse(unsigned char* ptrAPDU_response, const size_t pMaxSize, size_t * pAPDU_response_size); + + +static LPA_EVENT_EXECUTION_ERROR _lpaEventExecutionErrorCallback = NULL; +void _seMediaGenericModemSendLpaEventExecutionError(long scErrorCode, const char* ptrErrorCodeDescription); + +void _seMediaGenericModemWaitingTimer(uint32_t pTime); +bool _seMediaGenericModemCloseDescriptorOrHandle(TSEMediaGenericModem* ptrTSEMediaGenericModem); + +// Specific functions for use under windows +#if defined(LPA_SDK__PLATFORM_WIN) +void _seMediaGenericModemWriteOnLogWindowsError(DWORD windowsError); +bool _seMediaDriverUpdateModemCommunicationPortConfiguration(HANDLE pModemHandle); +bool _seMediaDriverUpdateModemCommunicationTimeOutConfiguration(HANDLE pModemHandle); +#endif // LPA_SDK__PLATFORM_WIN + +#define GENERIC_MODEM_RESPONSE_BUFFER_SIZE 1536 // Can be increased in case modem perform multiple GetResponse chaining by itself +static char responseBuffer[GENERIC_MODEM_RESPONSE_BUFFER_SIZE]; + +#define GM_AT_COMMAND_BUFFER_SIZE 600 // AT command (Can vary) + (APDU header (5x2) + APDU data (255x2) + 2 quotes => 522) + '\0' => Commonly 537 characters, keep comfortable security + +// MODEM PARAMETERS + +// Port name. If already defined as a compilation parameter, will be not changed +// Note 1: Modem name is used as default port name if not specified and also used in _seMediaGenericModemListReader() for dummy list generation. +// Note 2: COM port number will vary depending host system used, it's even possible with 2 identical systems +#ifndef GM_SERIAL_PORT_NAME + #if defined LPA_SDK__PLATFORM_CYGWIN + #define GM_SERIAL_PORT_NAME "/dev/ttyS3" // Cygwin AK + #elif defined LPA_SDK__PLATFORM_RASPBIAN + #define GM_SERIAL_PORT_NAME "/dev/ttyUSB3" // Raspberry + #elif defined LPA_SDK__PLATFORM_WIN + #define GM_SERIAL_PORT_NAME "\\\\.\\COM4" // Windows AK + #endif // Platforms for default driver name in reader list +#endif // ndef GM_SERIAL_PORT_NAME + +#if defined(LPA_SDK__PLATFORM_WIN) + // Mandatory modem parameters + #define GM_SERIAL_PORT_BAUD_RATE 115200 + #define GM_SERIAL_PORT_PARITY NOPARITY + #define GM_SERIAL_PORT_BYTE_SIZE 8 + #define GM_SERIAL_STOP_BITS ONESTOPBIT + + // Time out configuration when reading Modem file + // Using 0 to deactivate timeout + #define GM_SERIAL_READ_INTERVAL_TIMEOUT 10 // ReadIntervalTimeout + #define GM_SERIAL_READ_TOTAL_TIMEOUT_CONSTANT 500 // ReadTotalTimeoutConstant + + // Optional modem parameters + // =>Uncomment if needed + + //#define GM_SERIAL_FBINARY 1 // fBinary + //#define GM_SERIAL_ABORT_ON_ERROR 1 // fAbortOnError + //#define GM_SERIAL_F_RTS_CONTROL 1 // fRtsControl + //#define GM_SERIAL_F_DTR_CONTROL 1 // fDtrControl + //#define GM_SERIAL_F_OUT_X_CTS_FLOW 0 // fOutxCtsFlow + //#define GM_SERIAL_F_OUT_X_DSR_FLOW 0 // fOutxDsrFlow +#else + // For parameters definition see termios.h + // cflag parameters: + // B115200 = Serial port speed, here 115200 bps + // CS8 = 8 bits data + // CLOCAL = Ignore modem status lines (RTS / CTS ? DTR / DSR / DCD ?) + // CREAD = Enable receiver + // Default 1 stop bit (Set CSTOPB for 2) + // Default parity none (PARENB not set) + + #define GM_SERIAL_PORT_PARAM_CFLAG B115200 | CS8 | CLOCAL | CREAD +#endif // LPA_SDK__PLATFORM_WIN + + +// Maximum number of loop waiting modem response +// COM port time out differs from platforms, explaining why so much differences +#if defined(LPA_SDK__PLATFORM_WIN) +#define GM_RETRIEVE_RESPONSE_TIMEOUT 20 +#else +#define GM_RETRIEVE_RESPONSE_TIMEOUT 200 +#endif // LPA_SDK__PLATFORM_WIN + + +// Set this flag only if Check Card Status feature is available on modem used here +//#define GM_CHECK_CARD_STATUS_ENABLED + +// AT command syntax definitions +#define GM_AT_COMMAND_PREFIX "AT+CSIM=" +#define GM_AT_COMMAND_RESPONSE_PREFIX "+CSIM:" +#define GM_AT_CMD_CHECK_CARD_STATUS "AT^SCKS?\r" +#define GM_AT_COMMAND_RESPONSE_OK "OK" +#define GM_AT_COMMAND_RESPONSE_ERROR "ERROR" +#define GM_AT_COMMAND_RESET_CARD "AT+CFUN=1,1\r" // CAUTION: This command can disconnect USB interface on some modem devices. Can also be rejected by modem, reason unknown + +// Note: Comment this define if modem does not support unsolicited event signaling modem startup +#define GM_AT_MODEM_START_EVENT "^SYSSTART" // This value depends on the modem brand / model used + +// APDU commands and constants +#define GM_APDU_OPEN_SIM_CHANNEL "0070000001" +#define GM_APDU_CLOSE_SIM_CHANNEL_PREFIX "007080" +#define GM_APDU_OK 0x9000 +#define GM_APDU_STK_OK 0x9100 +#define GM_APDU_CHAIN_OK 0x6100 // Manages Big size chained responses / Eventual normal T=0 GetResponse not managed by modem itself +#define GM_APDU_UPPER_SW_MASK 0xFF00// Filter only data size returned +#define GM_APDU_OK_LEN 4 + + +/** +* Initializes a structure type "TSEMediaGenericModem", affect TSEMediaGenericModem->ptrBase to a pointer type "TSEMedia" object and return it. +* Elements stored points on functions defined below and elsewhere. +* +* @return Pointer on object type TSEMedia +*/ +TSEMedia* New_SEMediaGenericModem() +{ + TSEMedia* ptrTSEMedia = NULL; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_genericmodem :> New_SEMediaGenericModem()"); + + TSEMediaGenericModem* seMediaGenericModem = (TSEMediaGenericModem*)lpaCoreMemoryAlloc(sizeof(TSEMediaGenericModem)); + if (seMediaGenericModem != NULL) + { + seMediaGenericModem->_ptrBase = New_SEMediaBase(); // See "semedia_base.c". Allocate memory bloc size of TSEMedia for TESMedia object + if (seMediaGenericModem->_ptrBase != NULL) + { + seMediaGenericModem->_ptrBase->_childStruct = seMediaGenericModem; // Points on seMediaGenericModem to allow find it through TSEMedia pointer + + seMediaGenericModem->_ptrBase->seMediaSetCallbackEventExecutionError = _seMediaGenericModemSetCallbackEventExecutionError; // Function defined below + + seMediaGenericModem->_ptrBase->seMediaEstablishContext = _seMediaGenericModemEstablishContext; // Function defined below + seMediaGenericModem->_ptrBase->seMediaReleaseContext = _seMediaGenericModemReleaseContext; // Function defined below + seMediaGenericModem->_ptrBase->seMediaIsValidContext = _seMediaGenericModemIsValidContext; // Function defined below + seMediaGenericModem->_ptrBase->seMediaIsContextEstablished = _seMediaGenericModemIsContextEstablished; // Function defined below + + seMediaGenericModem->_ptrBase->seMediaListReader = _seMediaGenericModemListReader; // Function defined below + seMediaGenericModem->_ptrBase->seMediaConnect = _seMediaGenericModemConnect; // Function defined below + seMediaGenericModem->_ptrBase->seMediaIsConnected = _seMediaGenericModemIsConnected; // Function defined below + seMediaGenericModem->_ptrBase->seMediaTransmitApdu = _seMediaGenericModemTransmitApdu; // Function defined below + seMediaGenericModem->_ptrBase->seMediaDisconnect = _seMediaGenericModemDisconnect; // Function defined below + seMediaGenericModem->_ptrBase->seMediaDisconnectWithReset = _seMediaGenericModemDisconnectWithReset; // Function defined below + seMediaGenericModem->_ptrBase->seMediaGetStatus = _seMediaGenericModemGetStatus; // Function defined below + + seMediaGenericModem->_contextEstablished = false; // Context flag. More useful for other interfaces + seMediaGenericModem->_apduChannel = 0; // Specific APDU channel + seMediaGenericModem->_apduChannelString[0] = '\0'; + +#if defined(LPA_SDK__PLATFORM_WIN) + seMediaGenericModem->_modemHandle = INVALID_HANDLE_VALUE; // Handle used to communicate with Modem +#else + seMediaGenericModem->_modemFD = 0; // File Descriptor used to communicate with Modem +#endif // LPA_SDK__PLATFORM_WIN + + ptrTSEMedia = (TSEMedia*)seMediaGenericModem->_ptrBase; // Will return base of TSEMedia object contained in seMediaGenericModem + } + else + { + // Free memory if allocation for seMediaGenericModem->_ptrBase failed + lpaCoreMemoryFree(seMediaGenericModem); + seMediaGenericModem = NULL; + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "New_SEMediaGenericModem(): Cannot allocate memory for _ptrBase object!"); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "New_SEMediaGenericModem(): Cannot allocate memory for TSEMediaGenericModem object!"); + + memset(responseBuffer, 0, GENERIC_MODEM_RESPONSE_BUFFER_SIZE); // Flush response buffer, will also appear as empty string + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- semedia_genericmodem :> New_SEMediaGenericModem() return ptrTSEMedia = 0x%lx", ptrTSEMedia); + + return ptrTSEMedia; +} + +/** +* Delete and free memory for TSEMedia object, including "parent" TSEMediaGenericModem structure linked through _childStruct. +* +* @param ptrTSEMedia - Pointer on TSEMedia object to delete +*/ +void Delete_SEMediaGenericModem(TSEMedia* ptrTSEMedia) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_genericmodem :> Delete_SEMediaGenericModem()"); + + if (ptrTSEMedia != NULL) + { + TSEMediaGenericModem* ptrTSEMediaGenericModem = (TSEMediaGenericModem*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaGenericModem != NULL) + lpaCoreMemoryFree(ptrTSEMediaGenericModem); + + lpaCoreMemoryFree(ptrTSEMedia); + ptrTSEMedia = NULL; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Delete_SEMediaGenericModem(): seMedia is NULL!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- semedia_external :> Delete_SEMediaExternal()"); +} + +/** + * Set LPA_EVENT_EXECUTION_ERROR callback + * + * @param ptrTSEMedia - TSEMedia object pointer + * @param LPA_EVENT_EXECUTION_ERROR - callback + * @return true if set callback successfully, otherwise false + */ +bool _seMediaGenericModemSetCallbackEventExecutionError(const struct TSEMedia* ptrTSEMedia, LPA_EVENT_EXECUTION_ERROR lpaEventExecutionErrorCallback) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_genericmodem :> _seMediaGenericModemSetCallbackEventExecutionError()"); + + bool res = false; + + if (lpaEventExecutionErrorCallback != NULL) + { + if (_lpaEventExecutionErrorCallback != lpaEventExecutionErrorCallback) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, " registering lpaEventExecutionErrorCallback..."); + _lpaEventExecutionErrorCallback = lpaEventExecutionErrorCallback; + res = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, " LpaEventExecutionErrorCallback already registered!"); + } + else + { + if (_lpaEventExecutionErrorCallback != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, " unregistering lpaEventExecutionErrorCallback..."); + _lpaEventExecutionErrorCallback = NULL; + res = true; + } + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- semedia_genericmodem :> _seMediaGenericModemSetCallbackEventExecutionError() return res = %s", (res ? "true" : "false")); + + return res; +} +/** + * Wait a time defined in milliseconds (Use various functions depending platform) + * @param pTime Time to wait in milliseconds + */ +void _seMediaGenericModemWaitingTimer(uint32_t pTime) +{ + #if defined LPA_SDK__PLATFORM_CYGWIN + // ! _POSIX_C_SOURCE >= 199309L + struct timespec tim; + tim.tv_sec = 0; + tim.tv_nsec = pTime * 1000000L; // Converts milli seconds into nano seconds + nanosleep(&tim, NULL); + + #elif defined LPA_SDK__PLATFORM_RASPBIAN + // Forced to redeclare it under Raspbian else "timespec" structure is not recognized + typedef struct + { + __time_t tv_sec; // Seconds. + __syscall_slong_t tv_nsec; // Nanoseconds. + }gm_timespec; + + gm_timespec tim; + tim.tv_sec = 0; + tim.tv_nsec = pTime * 1000000L; // Converts milli seconds into nano seconds + nanosleep(&tim, NULL); // Like usleep() compilation warning due to Raspbian + C99 (warning: implicit declaration of function 'nanosleep'...) + + #elif defined LPA_SDK__PLATFORM_WIN + // Here duration in milliseconds + Sleep(pTime); + + #else + // Special case for usleep() + // Depend from unistd.h. Can drive to "implicit declaration" error depending platform + // NOTE: Found that usleep() is considered as deprecated since POSIX-2008 + usleep(pTime * 1000); // Convert millisecond in microseconds + + #endif +} + + +/** +* Try to establish TSEMedia object "context" +* And update "context" status in TSEMedia object +* +* @param ptrTSEMedia - TSEMedia object pointer +* @return Status of "context established" state, boolean, true if established successfully +*/ +bool _seMediaGenericModemEstablishContext(const struct TSEMedia* ptrTSEMedia) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+ semedia_genericmodem :> _seMediaGenericModemEstablishContext()"); + bool res = false; + + if (ptrTSEMedia != NULL) + { + TSEMediaGenericModem* ptrTSEMediaGenericModem = (TSEMediaGenericModem*)ptrTSEMedia->_childStruct; + + if (!ptrTSEMediaGenericModem->_contextEstablished) + { + // Nothing to check on this interface + ptrTSEMediaGenericModem->_contextEstablished = true; + res = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "Context already established"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "seMedia is NULL!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- semedia_external :> _seMediaGenericModemEstablishContext() return res = %s", (res ? "true" : "false")); + + return res; +} + +/** +* Try to release TSEMedia object "context" +* And update "context" status in TSEMedia object +* +* @param ptrTSEMedia - TSEMedia object pointer +* @return True if "context" released successfully, boolean +*/ +bool _seMediaGenericModemReleaseContext(const struct TSEMedia* ptrTSEMedia) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_genericmodem :> _seMediaGenericModemReleaseContext()"); + + if (ptrTSEMedia != NULL) + { + // Disconnect before releasing context, if needed + if (_seMediaGenericModemIsConnected(ptrTSEMedia)) + { + _seMediaGenericModemDisconnect(ptrTSEMedia); + } + + + TSEMediaGenericModem* ptrTSEMediaGenericModem = (TSEMediaGenericModem*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaGenericModem->_contextEstablished) + { + ptrTSEMediaGenericModem->_contextEstablished = false; + res = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Context not established"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "seMedia is NULL!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- semedia_external :> _seMediaGenericModemReleaseContext() return res = %s", (res ? "true" : "false")); + + return res; +} + +/** +* Try to get status of "Media Valid" +* +* @param ptrTSEMedia - TSEMedia object pointer +* @return True if "Media Valid" status is verified successfully, boolean +*/ +bool _seMediaGenericModemIsValidContext(const struct TSEMedia* ptrTSEMedia) +{ + bool isValidContext = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_genericmodem :> _seMediaGenericModemIsValidContext()"); + + if (ptrTSEMedia != NULL) + { + TSEMediaGenericModem* ptrTSEMediaGenericModem = (TSEMediaGenericModem*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaGenericModem != NULL) + { +#if defined(LPA_SDK__PLATFORM_WIN) + // Check FileDescriptor valid or not. Channel opening status not applicable for this function. + if (ptrTSEMediaGenericModem->_modemHandle != INVALID_HANDLE_VALUE) + isValidContext = true; +#else + // Check FileDescriptor valid or not. Channel opening status not applicable for this function. + if (ptrTSEMediaGenericModem->_modemFD > 0) + isValidContext = true; +#endif // LPA_SDK__PLATFORM_WIN + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Media status: %s", (isValidContext) ? "Valid" : "Not Valid"); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "seMedia is NULL!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- semedia_external :> _seMediaGenericModemIsValidContext() return res = %s", (isValidContext ? "true" : "false")); + + return isValidContext; +} + +/** +* Return status of "context established" state stored in TSEMedia object +* +* @param ptrTSEMedia - TSEMedia object pointer +* @return Boolean, true or false +*/ +bool _seMediaGenericModemIsContextEstablished(const struct TSEMedia* ptrTSEMedia) +{ + bool isContextEstablished = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_genericmodem :> _seMediaGenericModemIsContextEstablished()"); + + if (ptrTSEMedia != NULL) + { + TSEMediaGenericModem* ptrTSEMediaGenericModem = (TSEMediaGenericModem*)ptrTSEMedia->_childStruct; + + if (ptrTSEMediaGenericModem != NULL) + isContextEstablished = ptrTSEMediaGenericModem->_contextEstablished; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "seMedia is NULL!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- semedia_external :> _seMediaGenericModemIsContextEstablished() return res = %s", (isContextEstablished ? "true" : "false")); + + return isContextEstablished; +} + +/** +* Try to get reader list +* +* @param ptrTSEMedia - TSEMedia object pointer +* @param readerNameInfoList - Structure LPA_SE_MEDIA_READER_NAME_INFO defined in "semedia.h" containing "readerName" char array. +* @param readerNameInfoMax - Maximum number of reader that can be reported in list, size_t +* @param countReader - Return number of readers found, size_t +* @return True if reader list retrieving finished successfully. +*/ +bool _seMediaGenericModemListReader(const struct TSEMedia* ptrTSEMedia, LPA_SE_MEDIA_READER_NAME_INFO * ptrReaderNameInfoList, size_t readerNameInfoMax, size_t* ptrCountReader) +{ + bool readListReader = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_genericmodem :> _seMediaGenericModemListReader()"); + + if (ptrTSEMedia != NULL && ptrReaderNameInfoList != NULL && ptrCountReader != NULL) + { + *ptrCountReader = 0; + + TSEMediaGenericModem* ptrTSEMediaGenericModem = (TSEMediaGenericModem*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaGenericModem != NULL) + { + memset(ptrReaderNameInfoList[0].readerName, 0x00, LPA_CFG_READER_NAME_MAX_SIZE); + strncpy(ptrReaderNameInfoList[0].readerName, GM_SERIAL_PORT_NAME, LPA_CFG_READER_NAME_MAX_SIZE - 1); + + *ptrCountReader = 1; + readListReader = true; + + // TODO: detect readers ... + // Unix based: Could be done by detecting "tty" devices under /dev + // It does not warranty all tty are a modem but it's a beginning + // Windows ? How to find different 'COMx' devices ? + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "NULL parameter detected!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- semedia_external :> _seMediaGenericModemListReader() return res = %s", (readListReader ? "true" : "false")); + + return readListReader; +} + +#if defined(LPA_SDK__PLATFORM_WIN) + +// Windows specific implementation +////////////////////////////////////// + +/** +* Check and update if needed COM port main parameters +* +* @param pModemHandle - COM port handle +* @return True if configuration operation is successfull. +*/ +bool _seMediaDriverUpdateModemCommunicationPortConfiguration(HANDLE pModemHandle) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_seMediaDriverUpdateModemCommunicationPortConfiguration()..."); + + DCB dcb; + memset(&dcb, 0x00, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + + // Read current configuration + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Read current configuration..."); + if (GetCommState(pModemHandle, &dcb)) + { + bool updateNeeded = false; + + //////////////////////////////////////////////// + // MANDATORY PARAMETERS + + if (dcb.BaudRate != GM_SERIAL_PORT_BAUD_RATE) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Will update BaudRate '%ld' to '%ld' ...", dcb.BaudRate, GM_SERIAL_PORT_BAUD_RATE); + dcb.BaudRate = GM_SERIAL_PORT_BAUD_RATE; + updateNeeded = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "BaudRate: %ld", dcb.BaudRate); + + if (dcb.ByteSize != GM_SERIAL_PORT_BYTE_SIZE) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Will update ByteSize '%d' to '%d' ...", dcb.ByteSize, GM_SERIAL_PORT_BYTE_SIZE); + dcb.ByteSize = GM_SERIAL_PORT_BYTE_SIZE; + updateNeeded = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "ByteSize: %d", dcb.ByteSize); + + if (dcb.Parity != GM_SERIAL_PORT_PARITY) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Will update Parity '%d' to '%d' ...", dcb.Parity, GM_SERIAL_PORT_PARITY); + dcb.Parity = GM_SERIAL_PORT_PARITY; + updateNeeded = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Parity: %d", dcb.Parity); + + if (dcb.StopBits != GM_SERIAL_STOP_BITS) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Will update StopBits '%d' to '%d' ...", dcb.StopBits, GM_SERIAL_STOP_BITS); + dcb.StopBits = GM_SERIAL_STOP_BITS; + updateNeeded = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "StopBits: %d", dcb.StopBits); + + //////////////////////////////////////////////// + // OPTIONAL PARAMETERS + +#if defined(GM_SERIAL_FBINARY) + if (dcb.fBinary != GM_SERIAL_FBINARY) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Will update fBinary '%ld' to '%ld' ...", dcb.fBinary, GM_SERIAL_FBINARY); + dcb.fBinary = GM_SERIAL_FBINARY; + updateNeeded = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "fBinary: %ld", dcb.fBinary); +#else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "fBinary: %ld", dcb.fBinary); +#endif // + +#if defined(GM_SERIAL_ABORT_ON_ERROR) + // Abort all reads and writes on Error + if (dcb.fAbortOnError != GM_SERIAL_ABORT_ON_ERROR) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Will update fAbortOnError '%ld' to '%ld' ...", dcb.fAbortOnError, GM_SERIAL_ABORT_ON_ERROR); + dcb.fAbortOnError = GM_SERIAL_ABORT_ON_ERROR; + updateNeeded = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "fAbortOnError: %ld", dcb.fAbortOnError); +#else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "fAbortOnError: %ld", dcb.fAbortOnError); +#endif + +#if defined(GM_SERIAL_F_OUT_X_CTS_FLOW) + // CTS handshaking on output + if (dcb.fOutxCtsFlow != GM_SERIAL_F_OUT_X_CTS_FLOW) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Will update fOutxCtsFlow '%ld' to '%ld' ...", dcb.fOutxCtsFlow, GM_SERIAL_F_OUT_X_CTS_FLOW); + dcb.fOutxCtsFlow = GM_SERIAL_F_OUT_X_CTS_FLOW; + updateNeeded = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "fOutxCtsFlow: %ld", dcb.fOutxCtsFlow); +#else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "fOutxCtsFlow: %ld", dcb.fOutxCtsFlow); +#endif // GM_SERIAL_F_OUT_X_CTS_FLOW + +#if defined(GM_SERIAL_F_DTR_CONTROL) + // DTR Flow control + if (dcb.fDtrControl != GM_SERIAL_F_DTR_CONTROL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "will update fDtrControl '%ld' to '%ld' ...", dcb.fDtrControl, GM_SERIAL_F_DTR_CONTROL); + dcb.fDtrControl = GM_SERIAL_F_DTR_CONTROL; + updateNeeded = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "fDtrControl: %ld", dcb.fDtrControl); +#else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "fDtrControl: %ld", dcb.fDtrControl); +#endif // GM_SERIAL_F_DTR_CONTROL + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "fOutxDsrFlow: %ld", dcb.fOutxDsrFlow); // DSR handshaking on output + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "fRtsControl: %ld", dcb.fRtsControl); // Rts Flow control + + if (updateNeeded) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Updating configuration..."); + if (SetCommState(pModemHandle, &dcb)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Configuration updated successfully"); + res = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Unable to update modem configuration"); + _seMediaGenericModemWriteOnLogWindowsError(GetLastError()); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Modem already configured"); + res = true; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Unable to configure communication with modem"); + _seMediaGenericModemWriteOnLogWindowsError(GetLastError()); + } + + return res; +} + + +/** +* Check and update if needed COM port timeout parameters +* +* @param pModemHandle - COM port handle +* @return True if configuration operation is successfull. +*/ +bool _seMediaDriverUpdateModemCommunicationTimeOutConfiguration(HANDLE pModemHandle) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_seMediaDriverUpdateModemCommunicationTimeOutConfiguration()..."); + + COMMTIMEOUTS commTimeout; + if (GetCommTimeouts(pModemHandle, &commTimeout)) + { + bool updateNeeded = false; + +#if defined(GM_SERIAL_READ_INTERVAL_TIMEOUT) + if (commTimeout.ReadIntervalTimeout != GM_SERIAL_READ_INTERVAL_TIMEOUT) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Will update ReadIntervalTimeout '%ld' to '%ld'", commTimeout.ReadIntervalTimeout, GM_SERIAL_READ_INTERVAL_TIMEOUT); + commTimeout.ReadIntervalTimeout = GM_SERIAL_READ_INTERVAL_TIMEOUT; + updateNeeded = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "ReadIntervalTimeout: %ld", commTimeout.ReadIntervalTimeout); +#else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "ReadIntervalTimeout: %ld", commTimeout.ReadIntervalTimeout); +#endif // GM_SERIAL_READ_INTERVAL_TIMEOUT + +#if defined(GM_SERIAL_READ_TOTAL_TIMEOUT_CONSTANT) + if (commTimeout.ReadTotalTimeoutConstant != GM_SERIAL_READ_TOTAL_TIMEOUT_CONSTANT) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Will update ReadTotalTimeoutConstant '%ld' to '%ld'", commTimeout.ReadTotalTimeoutConstant, GM_SERIAL_READ_TOTAL_TIMEOUT_CONSTANT); + commTimeout.ReadTotalTimeoutConstant = GM_SERIAL_READ_TOTAL_TIMEOUT_CONSTANT; + updateNeeded = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "ReadTotalTimeoutConstant: %ld", commTimeout.ReadTotalTimeoutConstant); +#else + logAppend("ReadTotalTimeoutConstant: %ld", commTimeout.ReadTotalTimeoutConstant); +#endif // GM_SERIAL_READ_TOTAL_TIMEOUT_CONSTANT + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "ReadTotalTimeoutMultiplier: %ld", commTimeout.ReadTotalTimeoutMultiplier); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "WriteTotalTimeoutMultiplier: %ld", commTimeout.WriteTotalTimeoutMultiplier); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "WriteTotalTimeoutConstant: %ld", commTimeout.WriteTotalTimeoutConstant); + + if (updateNeeded) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Updating Communication Timeout..."); + + if (SetCommTimeouts(pModemHandle, &commTimeout)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Communication Timeout updated successfully"); + res = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Unable to update Communication Timeout"); + _seMediaGenericModemWriteOnLogWindowsError(GetLastError()); + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "No communication timeout configuration information"); + res = true; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Unable to read Communication Timeout configuration"); + _seMediaGenericModemWriteOnLogWindowsError(GetLastError()); + } + + return res; +} + + +bool _seMediaGenericModemConnect(const struct TSEMedia* ptrTSEMedia, const char *ptrReaderName) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_genericmodem :> _seMediaGenericModemConnect()"); + + if (ptrTSEMedia != NULL && ptrReaderName != NULL) + { + TSEMediaGenericModem* ptrTSEMediaGenericModem = (TSEMediaGenericModem*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaGenericModem != NULL) + { + ptrTSEMediaGenericModem->_apduChannel = 0; + ptrTSEMediaGenericModem->_apduChannelString[0] = '\0'; + + // If no reader name specified, connect using default defined in driver + if (ptrReaderName != NULL && strlen(ptrReaderName) > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "ReaderName='%s'", ptrReaderName); + ptrTSEMediaGenericModem->_modemHandle = CreateFile(ptrReaderName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Connecting to default reader '%s' ...", GM_SERIAL_PORT_NAME); + ptrTSEMediaGenericModem->_modemHandle = CreateFile(GM_SERIAL_PORT_NAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + } + + if (ptrTSEMediaGenericModem->_modemHandle == INVALID_HANDLE_VALUE) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemConnect(): CreateFile() failed"); + + _seMediaGenericModemWriteOnLogWindowsError(GetLastError()); + + // Basic LPA Event error usage + _seMediaGenericModemSendLpaEventExecutionError(1, "Unable to open modem Handle"); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_seMediaGenericModemConnect(): CreateFile() is OK, Handle = %d", ptrTSEMediaGenericModem->_modemHandle); + + // COM port parameters update, can be not correctly initialized at opening + if (_seMediaDriverUpdateModemCommunicationPortConfiguration(ptrTSEMediaGenericModem->_modemHandle)) + { + // Time Out parameters update, can be not correctly initialized at opening + res = _seMediaDriverUpdateModemCommunicationTimeOutConfiguration(ptrTSEMediaGenericModem->_modemHandle); + } + } + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "NULL parameter detected!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- semedia_external :> _seMediaGenericModemConnect() return res = %s", (res ? "true" : "false")); + + return res; +} + +#else // LPA_SDK__PLATFORM_WIN + +// Cygwin & Raspbian implementation +////////////////////////////////////// + +bool _seMediaGenericModemConnect(const struct TSEMedia* ptrTSEMedia, const char *ptrReaderName) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_genericmodem :> _seMediaGenericModemConnect()"); + + if (ptrTSEMedia == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "seMedia is NULL!"); + return false; + } + + TSEMediaGenericModem* ptrTSEMediaGenericModem = (TSEMediaGenericModem*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaGenericModem != NULL) + { + ptrTSEMediaGenericModem->_apduChannel = 0; + ptrTSEMediaGenericModem->_modemFD = 0; + ptrTSEMediaGenericModem->_apduChannelString[0] = '\0'; + + // If no reader name specified, connect using default defined in driver + if (ptrReaderName != NULL && strlen(ptrReaderName) > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "ReaderName='%s'", ptrReaderName); + ptrTSEMediaGenericModem->_modemFD = open(ptrReaderName, O_RDWR | O_NOCTTY | O_NDELAY); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Connecting to default reader '%s' ...", GM_SERIAL_PORT_NAME); + ptrTSEMediaGenericModem->_modemFD = open(GM_SERIAL_PORT_NAME, O_RDWR | O_NOCTTY | O_NDELAY); + } + + if (ptrTSEMediaGenericModem->_modemFD < 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemConnect(): open() failed, result = %d", ptrTSEMediaGenericModem->_modemFD); + + // Basic LPA Event erro usage + _seMediaGenericModemSendLpaEventExecutionError(1, "Unable to open modem stream"); + } + else + { + struct termios options; + memset(&options, 0, sizeof(options)); + + options.c_cflag = GM_SERIAL_PORT_PARAM_CFLAG; + + // Flush communication port. TCIFLUSH = flush data received but not read + tcflush(ptrTSEMediaGenericModem->_modemFD, TCIFLUSH); + + // Set communication port parameters. TCSANOW = changes will occur immediately + tcsetattr(ptrTSEMediaGenericModem->_modemFD, TCSANOW, &options); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_seMediaGenericModemConnect(): open() is OK, file descriptor = %d", ptrTSEMediaGenericModem->_modemFD); + + res = true; + } + } + + return res; +} +#endif // LPA_SDK__PLATFORM_WIN + +/** +* Try perform sending of APDU on reader linked to TSEMedia object and retrieve response, with logical channel management +* +* @param ptrTSEMedia - TSEMedia object pointer +* @param apduCommandBytes - APDU command to send - bytes format +* @param apduCommandSize - Size of ADPDU command to send, size_t +* @param apduResponseBytes - Store command response returned by reader - bytes format +* @param apduResponseMaxSize - Size of command response, size_t +* @return True if reader reported that exchange was successful. +*/ +bool _seMediaGenericModemTransmitApdu(const struct TSEMedia* ptrTSEMedia, const unsigned char* ptrApduCommandBytes, size_t apduCommandSize, unsigned char* ptrApduResponseBytes, size_t* ptrApduResponseMaxSize) +{ + bool res = false; + char * apduCommandString = NULL; + size_t apduCommandStringSize = 0; + + unsigned char apduClass = 0; + unsigned char apduLogicalChannel = 0; + char apduClassString[4]; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_genericmodem :> _seMediaGenericModemTransmitApdu()"); + + if (ptrTSEMedia == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "seMedia is NULL!"); + return false; + } + + if (ptrApduCommandBytes != NULL && ptrApduResponseBytes != NULL && apduCommandSize >= 4 && apduCommandSize < 262 && ptrApduResponseMaxSize != NULL && *ptrApduResponseMaxSize >= 2) + { + TSEMediaGenericModem* ptrTSEMediaGenericModem = (TSEMediaGenericModem*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaGenericModem != NULL) + { + // Check if logical channel has been opened. If not, try to open it + if(ptrTSEMediaGenericModem->_apduChannel == 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Logical channel not yet opened, opening it..."); + + if(_seMediaGenericModemOpenUICCChannel(ptrTSEMedia)) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Logical channel opening succeed"); + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Logical channel opening failed! APDU transmit will abort"); + // Error code used is a reference to Manage Channel APDU INS. + _seMediaGenericModemSendLpaEventExecutionError(0x70, "Failed to open logical channel"); + } + } + + // Do not perform transmit and return error if logical channel has not been opened or invalid (Memory corruption, attack...) + if(ptrTSEMediaGenericModem->_apduChannel > 0 && ptrTSEMediaGenericModem->_apduChannel < 20) + { + // manage the APDU + apduCommandStringSize = (apduCommandSize * 2) + 2; + apduCommandString = lpaCoreMemoryAlloc(apduCommandStringSize); + + if(apduCommandString != NULL) + { + if (formatBytesToHexaString(ptrApduCommandBytes, apduCommandSize, apduCommandString, apduCommandStringSize) > 0) + { + // Class management. Set Logical Channel to be used to communicate with eUICC + // Cannot do it with original raw hex buffer because we cannot modify it. And did not want useless copy of whole raw hex buffer. + apduClass = (oneHexCharToHex(apduCommandString[0]) << 4) + oneHexCharToHex(apduCommandString[1]); + // Set coding of Logical Channel to apply to APDU class byte depending we work on normal or extended Logical Channel + if(ptrTSEMediaGenericModem->_apduChannel < 4) + apduLogicalChannel = ptrTSEMediaGenericModem->_apduChannel; + else + apduLogicalChannel = (ptrTSEMediaGenericModem->_apduChannel - 4) + 0x40; + // Note: Coding of bits relative to Secure Messaging (See GP chapters 11.1.4.1 / 11.1.4.2) are not implemented here because no Secure Messaging + // is used for LPA operations. Could be added in the future. + apduClass = apduClass | apduLogicalChannel; + snprintf(apduClassString, 3, "%02X", apduClass); + apduCommandString[0] = apduClassString[0]; + apduCommandString[1] = apduClassString[1]; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_seMediaGenericModemTransmitApdu(): APDU Command (%llu): %s", (long long unsigned)strlen(apduCommandString), apduCommandString); + + // Here do not check result status word, will be done by upper layers + if(_seMediaGenericModemSendAPDUtoModemAndCheckOK(apduCommandString, ptrTSEMedia, false)) + { + size_t maxRecvLength = *ptrApduResponseMaxSize; + + if(_seMediaGenericModemProcessAPDUresponse(ptrApduResponseBytes, maxRecvLength, ptrApduResponseMaxSize)) + res = true; + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemTransmitApdu(): Problem while extracting APDU response!"); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemTransmitApdu(): Failed to exchange successfully APDU with modem!"); + + // Basic LPA Event error usage + _seMediaGenericModemSendLpaEventExecutionError(2, "transmit issue"); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemTransmitApdu(): Failed to convert APDU in string format!"); + + lpaCoreMemoryFree(apduCommandString); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemTransmitApdu(): Cannot allocate memory for APDU command string buffer!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemTransmitApdu(): Invalid or out of context logical channel: %u", ptrTSEMediaGenericModem->_apduChannel); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemTransmitApdu(): Invalid parameters!"); + + return res; +} + +/** +* Return connection status of reader linked to TSEMedia object. +* +* @param ptrTSEMedia - TSEMedia object pointer +* @return True if reader connection status is verified successfully, boolean +*/ +bool _seMediaGenericModemIsConnected(const struct TSEMedia* ptrTSEMedia) +{ + bool isConnected = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_genericmodem :> _seMediaGenericModemIsConnected()"); + + if (ptrTSEMedia == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "seMedia is NULL!"); + return false; + } + + TSEMediaGenericModem* ptrTSEMediaGenericModem = (TSEMediaGenericModem*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaGenericModem != NULL) + { +#if defined(LPA_SDK__PLATFORM_WIN) + // Check Handle is opened and specific APDU channel created + if (ptrTSEMediaGenericModem->_modemHandle != INVALID_HANDLE_VALUE) + isConnected = true; +#else + // Check FileDescriptor is opened + if(ptrTSEMediaGenericModem->_modemFD > 0) + isConnected = true; +#endif + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Connection Status: %s", (isConnected) ? "Connected" : "Not Connected"); + } + + return isConnected; +} + +/** +* Try to perform "Disconnect" operation on reader linked to TSEMedia object. +* +* @param ptrTSEMedia - TSEMedia object pointer +* @return True if disconnect operation was successful. +*/ +bool _seMediaGenericModemDisconnect(const struct TSEMedia* ptrTSEMedia) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_genericmodem :> _seMediaGenericModemDisconnect()"); + + if (ptrTSEMedia == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "seMedia is NULL!"); + return false; + } + + TSEMediaGenericModem* ptrTSEMediaGenericModem = (TSEMediaGenericModem*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaGenericModem != NULL) + { + if (_seMediaGenericModemIsConnected(ptrTSEMedia)) + { + // Close logical channel if needed + // Reader will be disconnected whatever will be the status of logical channel closing, by all the way it is not recoverable + if(ptrTSEMediaGenericModem->_apduChannel != 0) + { + if(_seMediaGenericModemCloseUICCChannel(ptrTSEMedia)) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_seMediaGenericModemDisconnect(): Successful closing of current logical channel"); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemDisconnect(): Failed to close current logical channel!"); + } + + // Close file descriptor / handle + res = _seMediaGenericModemCloseDescriptorOrHandle(ptrTSEMediaGenericModem); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "_seMediaGenericModemInternalDisconnect(): Modem is already disconnected!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemInternalDisconnect(): ptrTSEMediaGenericModem is NULL!"); + + return res; +} + +/** +* Try to perform "Disconnect" with Reset operation on reader linked to TSEMedia object. +* +* @param ptrTSEMedia - TSEMedia object pointer +* @return True if disconnect operation was successful. +*/ +bool _seMediaGenericModemDisconnectWithReset(const struct TSEMedia* ptrTSEMedia) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_genericmodem :> _seMediaGenericModemDisconnectWithReset()"); + + if (ptrTSEMedia == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "seMedia is NULL!"); + return false; + } + + TSEMediaGenericModem* ptrTSEMediaGenericModem = (TSEMediaGenericModem*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaGenericModem != NULL) + { + if (_seMediaGenericModemIsConnected(ptrTSEMedia)) + { + bool writeResetCardCommand = false; + + #if defined(LPA_SDK__PLATFORM_WIN) + DWORD numberOfBytesWritten = 0; + if (WriteFile(ptrTSEMediaGenericModem->_modemHandle, GM_AT_COMMAND_RESET_CARD, strlen(GM_AT_COMMAND_RESET_CARD), &numberOfBytesWritten, NULL)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Number of bytes written: %ld", numberOfBytesWritten); + if (numberOfBytesWritten == strlen(GM_AT_COMMAND_RESET_CARD)) + { + writeResetCardCommand = true; + } + } + else + _seMediaGenericModemWriteOnLogWindowsError(GetLastError()); + #else + if( write(ptrTSEMediaGenericModem->_modemFD, GM_AT_COMMAND_RESET_CARD, strlen(GM_AT_COMMAND_RESET_CARD)) == strlen(GM_AT_COMMAND_RESET_CARD) ) + writeResetCardCommand = true; + #endif // LPA_SDK__PLATFORM_WIN + + if (!writeResetCardCommand) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemDisconnectWithReset(): Reset eUICC: Problem while transmitting AT command to modem."); + } + else + { + if (_seMediaGenericModemGetATcommandResponseData(ptrTSEMedia)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_seMediaGenericModemDisconnectWithReset(): Reset eUICC response: %s", responseBuffer); + if (_seMediaGenericModemCheckATcommandResponseOK()) + res = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemDisconnectWithReset(): Reset eUICC: Command acknowledge not received."); + } + + // Logical channel management if needed + if(ptrTSEMediaGenericModem->_apduChannel != 0) + { + // If card reset is successful, logical channel is marked closed, else try perform logical channel close to avoid leaving unused logical channel + if(res) + { + ptrTSEMediaGenericModem->_apduChannel = 0; + ptrTSEMediaGenericModem->_apduChannelString[0] = '\0'; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemDisconnectWithReset(): Error detected during reader reset. Try to close current logical channel..."); + if(_seMediaGenericModemCloseUICCChannel(ptrTSEMedia)) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_seMediaGenericModemDisconnectWithReset(): Successful closing of current logical channel after failed reader reset"); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemDisconnectWithReset(): Failed to close current logical channel after failed reader reset!"); + } + } + + // Close file descriptor / handle + if(_seMediaGenericModemCloseDescriptorOrHandle(ptrTSEMediaGenericModem)) + res = (res) ? true : false; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "_seMediaGenericModemDisconnectWithReset(): Modem is already disconnected!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemDisconnectWithReset(): ptrTSEMediaGenericModem is NULL!"); + + return res; +} + +/** + * Close File Descriptor (Linux,...) or Handle (Windows,...) opened on Modem communication port + * @param ptrTSEMediaGenericModem - TSEMediaGenericModem object pointer + * @return True if closing is successful + */ +bool _seMediaGenericModemCloseDescriptorOrHandle(TSEMediaGenericModem* ptrTSEMediaGenericModem) +{ + bool closedStatus = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_genericmodem :> _seMediaGenericModemCloseDescriptorOrHandle()"); + + if(ptrTSEMediaGenericModem != NULL) + { + #if defined(LPA_SDK__PLATFORM_WIN) + if (CloseHandle(ptrTSEMediaGenericModem->_modemHandle)) + { + ptrTSEMediaGenericModem->_modemHandle = INVALID_HANDLE_VALUE; + + // Return true only if previous operation (Reset or disconnect card) was successful + closedStatus = true; + } + else + { + closedStatus = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemCloseDescriptorOrHandle(): Error when closing Handle!"); + + _seMediaGenericModemWriteOnLogWindowsError(GetLastError()); + } + #else + if (close(ptrTSEMediaGenericModem->_modemFD) == 0) + { + ptrTSEMediaGenericModem->_modemFD = 0; + // Return true only if previous operation (Reset or disconnect card) was successful + closedStatus = true; + } + else + { + closedStatus = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemCloseDescriptorOrHandle(): Error for file descriptor close!"); + } + #endif // Platform + + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemCloseDescriptorOrHandle(): ptrTSEMediaGenericModem is NULL"); + + return closedStatus; +} + +/** +* Get current status of reader linked to TSEMedia object. +* +* @param ptrTSEMedia - TSEMedia object pointer +* @param ptrStatus - Return reader status in pointer on enum object type SE_MEDIA_CARD_STATUS defined in "semedia_base.h". +* @return True if condition SE_MEDIA_STATUS_SCARD_PRESENT or SE_MEDIA_STATUS_REMOVED_CARD is reported +*/ +bool _seMediaGenericModemGetStatus(const struct TSEMedia* ptrTSEMedia, SE_MEDIA_CARD_STATUS* ptrStatus) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_genericmodem :> _seMediaGenericModemGetStatus()"); + + // ptrStatus NULL is managed at the end + if (ptrTSEMedia == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "seMedia is NULL!"); + return false; + } + + TSEMediaGenericModem* ptrTSEMediaGenericModem = (TSEMediaGenericModem*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaGenericModem != NULL) + { + if(_seMediaGenericModemIsConnected(ptrTSEMedia)) + { + SE_MEDIA_CARD_STATUS cardStatus = SE_MEDIA_STATUS_SCARD_UNKNOWN; + +#if defined GM_CHECK_CARD_STATUS_ENABLED + // Send characters on serial port, and check that all has been really send + if(write(ptrTSEMediaGenericModem->_modemFD, GM_AT_CMD_CHECK_CARD_STATUS, strlen(GM_AT_CMD_CHECK_CARD_STATUS)) < strlen(GM_AT_CMD_CHECK_CARD_STATUS)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemGetStatus() return error for Card Check Status command %s", GM_AT_CMD_CHECK_CARD_STATUS); + } + else + { + if(_seMediaGenericModemGetATcommandResponseData(ptrTSEMedia)) + { + if(_seMediaGenericModemCheckATcommandResponseOK()) + { + // TODO Retrieve of response status cannot be kept as this, ABSOLUTELY NO WARANTY that status byte will be always at 20th position! + // No more development done because function not implemented in sample modem + if(strlen(responseBuffer) > 20) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Response buffer = %s - responseBuffer[20] = %02x", responseBuffer, responseBuffer[20]); + + switch(responseBuffer[20]) + { + case '1': + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "SCardStatus(): Card status reported USIM inserted"); + cardStatus = SE_MEDIA_STATUS_SCARD_PRESENT; + res = true; + break; + + case '0': + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "SCardStatus(): Card status reported USIM not inserted"); + cardStatus = SE_MEDIA_STATUS_REMOVED_CARD; + res = true; + break; + + default: + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "SCardStatus(): Card status reported unexpected code: %c", responseBuffer[20]); + break; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemGetStatus() Card Check Status request response too short!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemGetStatus() Card Check Status request returned an error!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemGetStatus() Failed to response for Card Check Status request!"); + + } +#else + // Used in case of Card Status Checking command not available with modem used + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "_seMediaGenericModemGetStatus() NOTE: Card Check Status bypassed, feature not available with this modem!"); + cardStatus = SE_MEDIA_STATUS_SCARD_PRESENT; + res = true; +#endif // GM_CHECK_CARD_STATUS_ENABLED + + // Report status even if result is false, except if given pointer is NULL (Invalidates correct function status) + if (ptrStatus != NULL) + *ptrStatus = cardStatus; + else + res = false; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemGetStatus() Modem connection status reported as disconnected!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemGetStatus() ptrTSEMediaGenericModem is NULL!"); + + return res; +} + + +/** + * Translates raw APDU command to AT modem command direct to SIM. + * Wraps it with command prefix, apdu length and quotes. + * + * @param ptrAPDU_cmd APDU to encode, string format + * @param ptrBuild_ATcommand AT command to generate, string format + * @param pMaxSize Maximum size allowed for AT command to build. Shall be able to store AT command + APDU + formatting characters + * @return True if the conversion has been successful + */ +static bool _seMediaGenericModemApduToAtCommand(const char* ptrAPDU_cmd, char* ptrBuild_ATcommand, const size_t pMaxSize) +{ + char apdu_length[4]; // Size will be send as decimal value, so up to 3 digits + \0 + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_apduToAtCommand()..."); + + if ((ptrBuild_ATcommand == NULL) || (pMaxSize < (strlen(GM_AT_COMMAND_PREFIX) + 13))) // + 13 bytes: length(3) + comma + quotes x2 + APDU (At least 5) + CR + '\0' + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_apduToAtCommand(): Invalid parameters!"); + return false; + } + + // Check if AT command prefix + APDU command + size(3) + formating characters(5) + \0 will not overflow build command buffer + if((strlen(GM_AT_COMMAND_PREFIX) + strlen(ptrAPDU_cmd) + 9) > pMaxSize) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_apduToAtCommand(): AT command to build too big for AT command buffer!"); + return false; + } + + // size_t to str conversion. By all the way ptrAPDU_cmd cannot exceed 522 characters so only up to 3 digits allowed + memset(apdu_length, 0, 4); + if(3 < snprintf(apdu_length, 4, "%llu", (long long unsigned)strlen(ptrAPDU_cmd))) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_apduToAtCommand(): Abnormal APDU command size conversion detected, string exceed 3 digits / characters! Abort."); + return false; + } + + memset(ptrBuild_ATcommand, 0x00, pMaxSize); // Start forming new command at the beginning of the buffer + + // NOTE: Despite command prefix has been set configurable, it may no work if the syntax differs: + // AT command prefix + APDU length in decimal + comma + APDU between quotes + Carriage Return + // In that case code below will need to be modified + + if((strlen(GM_AT_COMMAND_PREFIX) + strlen(apdu_length) + 2 + strlen(ptrAPDU_cmd) + 2) < pMaxSize) + { + // Note: lengths limits - 1 to reserve chain terminator '\0' + // Add AT command prefix + strncat(ptrBuild_ATcommand, GM_AT_COMMAND_PREFIX, (pMaxSize - 1)); + // Add apdu command length + strncat(ptrBuild_ATcommand, apdu_length, (pMaxSize - strlen(ptrBuild_ATcommand) - 1)); + // Add comma and opening quote + strncat(ptrBuild_ATcommand, ",\"", (pMaxSize - strlen(ptrBuild_ATcommand) - 1)); + // Add apdu code + strncat(ptrBuild_ATcommand, ptrAPDU_cmd, (pMaxSize - strlen(ptrBuild_ATcommand) - 1)); + // Add closing quote and Carriage Return + strncat(ptrBuild_ATcommand, "\"\r", (pMaxSize - strlen(ptrBuild_ATcommand) - 1)); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_apduToAtCommand(): Generated AT command: %s", ptrBuild_ATcommand); + + return true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_apduToAtCommand(): Output AT command buffer size is too small to receive full AT command!"); + + return false; +} + + +/** + * Extract APDU response from AT command response + * + * @param ptrAt_command_response AT command response, string format + * @param pAPDU_response Extracted APDU from At command response, string format + * @param ptrMaxSize Maximum size allowed for APDU response buffer. At least 2. + * @return True if the conversion has been successful + */ +static bool _seMediaGenericModemAtCommandResponseToApdu(const char* ptrAt_command_response, char* ptrAPDU_response, size_t pMaxSize) +{ + int trimmed_response_length = 0; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_atCommandResponseToApdu()..."); + + if ((ptrAt_command_response == NULL) || (ptrAPDU_response == NULL) || (pMaxSize < 2)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_atCommandResponseToApdu(): Invalid parameters!"); + return false; + } + + // Get the response part starting by prefix defined in AT_COMMAND_RESPONSE_PREFIX + char* response_part = strstr(ptrAt_command_response, GM_AT_COMMAND_RESPONSE_PREFIX); + if (response_part == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_atCommandResponseToApdu(): Response prefix not found!"); + return false; + } + + // Get substring starting from the first quote, from the beginning of response prefix + // NOTE: May have to be modified if modem does not use the same syntax (APDU response between quotes) + char* first_quote = strstr(response_part, "\""); + if (first_quote == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_atCommandResponseToApdu(): First quote not found!"); + return false; + } + + // Cut the first quote + first_quote++; + + // Find the second quote + char* second_quote = strstr(first_quote, "\""); + if (second_quote == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_atCommandResponseToApdu(): Second quote not found!"); + return false; + } + + // Cut from first to the last quote + trimmed_response_length = strlen(first_quote) - strlen(second_quote); + if((trimmed_response_length < 0) || (trimmed_response_length > (pMaxSize - 1))) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_atCommandResponseToApdu(): Invalid Response APDU length: %d found, max allowed %llu!", trimmed_response_length, (long long unsigned)pMaxSize); + return false; + } + + // Copy from first APDU character (first_quote) + memcpy(ptrAPDU_response, first_quote, trimmed_response_length); + // Terminate string + ptrAPDU_response[trimmed_response_length] = '\0'; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_atCommandResponseToApdu(): Extracted APDU response: %s", ptrAPDU_response); + + return true; +} + + +/** + * Checks if the APDU response is ended with successful Status Word (Success or chained data reception) + * + * @param ptrAPDU_response Response to be checked, string format + * @return True if the successful Status Word is found at end of response + */ +static bool _seMediaGenericModemCheckAPDU_OkResponse(const char* ptrAPDU_response) +{ + bool res = false; + char responseSWstr[GM_APDU_OK_LEN + 2]; + long responseSWbyte = 0; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_checkAPDU_OkResponse()..."); + + if (ptrAPDU_response == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_checkAPDU_OkResponse(): Invalid parameter NULL!"); + return false; + } + + + if (strlen(ptrAPDU_response) < GM_APDU_OK_LEN) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_checkAPDU_OkResponse(): Response to check too short!"); + return false; + } + else + { + // Extract SW that shall be at end of ptrAPDU_response + strncpy(responseSWstr, (ptrAPDU_response + strlen(ptrAPDU_response) - GM_APDU_OK_LEN), GM_APDU_OK_LEN); + responseSWstr[GM_APDU_OK_LEN] = '\0'; + responseSWbyte = strtol(responseSWstr, NULL, 16); + + if((responseSWbyte >= 0) && (responseSWbyte < 65536)) + { + // Check successful SW: 9000 or 91xx or 61xx (Normal T=0 GetResponse not managed by modem) + if((responseSWbyte == GM_APDU_OK) || ((responseSWbyte & GM_APDU_UPPER_SW_MASK) == GM_APDU_STK_OK) || ((responseSWbyte & GM_APDU_UPPER_SW_MASK) == GM_APDU_CHAIN_OK)) + res = true; + } + } + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_checkAPDU_OkResponse(): Successful Status Word %s: %X", (res)?"found":"NOT found", responseSWbyte); + + return res; +} + +/** + * Gets the data from the reception stream and store it in reception buffer as a string. + * + * @param ptrTSEMedia - TSEMedia object pointer + * @return true if some data were successfully retrieved + */ +static bool _seMediaGenericModemGetATcommandResponseData(const struct TSEMedia* ptrTSEMedia) +{ + bool res = false; + int nbReceivedChars = 0; + int readResult = 0; + int timeout = 0; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_getResponseData()..."); + + if (ptrTSEMedia == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_getResponseData(): ptrTSEMedia is NULL!"); + return false; + } + + TSEMediaGenericModem* ptrTSEMediaGenericModem = (TSEMediaGenericModem*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaGenericModem != NULL) + { + responseBuffer[0]='\0'; + + // Loop exit conditions are present below in the loop + while (1) + { + _seMediaGenericModemWaitingTimer(50); + +#if defined(LPA_SDK__PLATFORM_WIN) + DWORD countBytesRead = 0; + if (ReadFile(ptrTSEMediaGenericModem->_modemHandle, (responseBuffer + nbReceivedChars), (sizeof(responseBuffer) - nbReceivedChars -1), &countBytesRead, NULL)) + { + readResult = countBytesRead; + } + else + readResult = 0; +#else + readResult = read(ptrTSEMediaGenericModem->_modemFD, (responseBuffer + nbReceivedChars), (sizeof(responseBuffer) - nbReceivedChars)); +#endif // + // Note: If retrieved data exceeds response buffer size, will not reach OK / ERROR status so will fall in timeout + // Eventual truncated response will be blocked after in response syntax analysis + + if (readResult > 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Loop #%d: Number of bytes read: %d", (timeout + 1), readResult); + + nbReceivedChars += readResult; + + // Set receive buffer as string. + // In case of problems during reading attempt, also cancel eventual writing in receive buffer + responseBuffer[(nbReceivedChars < GENERIC_MODEM_RESPONSE_BUFFER_SIZE ? nbReceivedChars : (GENERIC_MODEM_RESPONSE_BUFFER_SIZE - 1))] = '\0'; + + // Modem returned OK, stop reception loop successful + if (strstr(responseBuffer, GM_AT_COMMAND_RESPONSE_OK) != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "AT COMMAND RESPONSE OK detected"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_getResponseData(): Data received at waiting loop #%d: %s", (timeout + 1), responseBuffer); + res = true; + break; + } + + // Log data received at this loop. Will be not displayed if OK response detected before + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Data read: '%s'", &responseBuffer[nbReceivedChars - readResult]); + + // Modem returns Error, stop reception loop with error + if (strstr(responseBuffer, GM_AT_COMMAND_RESPONSE_ERROR) != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "AT COMMAND RESPONSE ERROR detected at waiting loop #%d", (timeout + 1)); + break; + } + +#if defined(GM_AT_MODEM_START_EVENT) + // Modem Startup event detected, stop reception loop with error + if (strstr(responseBuffer, GM_AT_MODEM_START_EVENT) != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "MODEM STARTUP EVENT <%s> detected at waiting loop #%d", GM_AT_MODEM_START_EVENT, (timeout + 1)); + break; + } +#endif // GM_AT_MODEM_START_EVENT + + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Loop #%d: No bytes read", (timeout + 1)); + + timeout++; + + // Time Out elapsed, stop reception loop with error + if (timeout >= GM_RETRIEVE_RESPONSE_TIMEOUT) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_getResponseData(): Time Out elapsed, no valid data available"); + break; + } + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_getResponseData(): ptrTSEMediaGenericModem is NULL!"); + + return res; +} + + +/** + * Check if response buffer show AT command response as successful + * + * @return true if "success response" pattern is detected + */ +static bool _seMediaGenericModemCheckATcommandResponseOK(void) +{ + bool res = false; + + if((strlen(responseBuffer) > 1) && (strstr(responseBuffer, GM_AT_COMMAND_RESPONSE_OK) != NULL)) + res = true; + + return res; +} + + +/** + * Handle the whole process of sending APDU to the modem, retrieve response data and check response OK + * + * @param ptrAPDU APDU command to be sent to the modem + * @param ptrTSEMedia - TSEMedia object pointer + * @param checkStatusWord If true function will check response Status Word OK or not + * @return True if the response APDU is correct and ended with success Status Word + */ +static bool _seMediaGenericModemSendAPDUtoModemAndCheckOK(const char* ptrAPDU, const struct TSEMedia* ptrTSEMedia, bool checkStatusWord) +{ + bool res = false; + char ATcommand[GM_AT_COMMAND_BUFFER_SIZE]; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_sendAPDUtoModemAndCheckOK()..."); + + if((ptrTSEMedia == NULL) || (ptrAPDU == NULL)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_sendAPDUtoModemAndCheckOK(): Invalid parameter NULL!"); + return false; + } + + TSEMediaGenericModem* ptrTSEMediaGenericModem = (TSEMediaGenericModem*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaGenericModem != NULL) + { + if(_seMediaGenericModemApduToAtCommand(ptrAPDU, ATcommand, GM_AT_COMMAND_BUFFER_SIZE)) + { + bool writeSuccessfully = false; + +#if defined(LPA_SDK__PLATFORM_WIN) + DWORD bytesWritten = 0; + + if (WriteFile(ptrTSEMediaGenericModem->_modemHandle, ATcommand, strlen(ATcommand), &bytesWritten, NULL) == TRUE && (bytesWritten == strlen(ATcommand))) + writeSuccessfully = true; +#else + if (write(ptrTSEMediaGenericModem->_modemFD, ATcommand, strlen(ATcommand)) == strlen(ATcommand)) + writeSuccessfully = true; +#endif // LPA_SDK__PLATFORM_WIN + + if( !writeSuccessfully ) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_sendAPDUtoModemAndCheckOK(): Problem while transmitting AT command to modem."); + } + else + { + if(_seMediaGenericModemGetATcommandResponseData(ptrTSEMedia)) + { + if(_seMediaGenericModemCheckATcommandResponseOK()) + { + char * extracted_ADPU_response = lpaCoreMemoryAlloc(strlen(responseBuffer)); + if(extracted_ADPU_response != NULL) + { + if(_seMediaGenericModemAtCommandResponseToApdu(responseBuffer, extracted_ADPU_response, strlen(responseBuffer))) + { + // Status word have to be checked for driver internal operations, not for APDU's from upper layers + if(checkStatusWord) + res = _seMediaGenericModemCheckAPDU_OkResponse(extracted_ADPU_response); + else + res = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_sendAPDUtoModemAndCheckOK(): Cannot extract APDU response from response buffer!"); + + lpaCoreMemoryFree(extracted_ADPU_response); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_sendAPDUtoModemAndCheckOK(): Cannot allocate memory for temporary APDU buffer!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_sendAPDUtoModemAndCheckOK(): AT command response report an error!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_sendAPDUtoModemAndCheckOK(): Cannot retrieve AT command response!"); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_sendAPDUtoModemAndCheckOK(): Problem while converting APDU to AT command!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_sendAPDUtoModemAndCheckOK(): ptrTSEMediaGenericModem is NULL!"); + + return res; +} + + +/** + * Sends "open logical channel" APDU command to the module and retrieve logical channel ID in seMedia structure + * + * @param ptrTSEMedia - TSEMedia object pointer + * @return true if the command was successfully achieved. + */ +static bool _seMediaGenericModemOpenUICCChannel(const struct TSEMedia* ptrTSEMedia) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_seMediaGenericModemOpenUICCChannel()..."); + + if (ptrTSEMedia == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemOpenUICCChannel(): ptrTSEMedia is NULL!"); + return false; + } + + TSEMediaGenericModem* ptrTSEMediaGenericModem = (TSEMediaGenericModem*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaGenericModem != NULL) + { + ptrTSEMediaGenericModem->_apduChannel = 0; + ptrTSEMediaGenericModem->_apduChannelString[0] = '\0'; + + // This is a driver internal operation, so Status Word will be checked + if(_seMediaGenericModemSendAPDUtoModemAndCheckOK(GM_APDU_OPEN_SIM_CHANNEL, ptrTSEMedia, true)) + { + char * extracted_ADPU_response = lpaCoreMemoryAlloc(strlen(responseBuffer)); + if(extracted_ADPU_response != NULL) + { + if(_seMediaGenericModemAtCommandResponseToApdu(responseBuffer, extracted_ADPU_response, strlen(responseBuffer))) + { + ptrTSEMediaGenericModem->_apduChannelString[0] = extracted_ADPU_response[0]; + ptrTSEMediaGenericModem->_apduChannelString[1] = extracted_ADPU_response[1]; + ptrTSEMediaGenericModem->_apduChannelString[2] = '\0'; + + ptrTSEMediaGenericModem->_apduChannel = atoi(ptrTSEMediaGenericModem->_apduChannelString); + + // Extended logical channels also managed (So 1 to 19 range) + if((ptrTSEMediaGenericModem->_apduChannel > 0) && (ptrTSEMediaGenericModem->_apduChannel < 20)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_seMediaGenericModemOpenUICCChannel(): Logical channel #%u opened", ptrTSEMediaGenericModem->_apduChannel); + res = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemOpenUICCChannel(): Logical channel out of bounds or incorrect: %u", ptrTSEMediaGenericModem->_apduChannel); + ptrTSEMediaGenericModem->_apduChannel = 0; + ptrTSEMediaGenericModem->_apduChannelString[0] = '\0'; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemOpenUICCChannel(): Cannot extract APDU response from response buffer!"); + + lpaCoreMemoryFree(extracted_ADPU_response); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemOpenUICCChannel(): Cannot allocate memory for temporary APDU buffer!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemOpenUICCChannel(): Problem while sending logical channel opening command!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemOpenUICCChannel(): ptrTSEMediaGenericModem is NULL!"); + + return res; +} + + +/** + * Sends "close logical channel" APDU command to the module. Channel to close will be current one described in TSEmedia structures + * + * @param ptrTSEMedia - TSEMedia object pointer + * @return true if the command was successfully achieved. + */ +static bool _seMediaGenericModemCloseUICCChannel(const struct TSEMedia* ptrTSEMedia) +{ + bool res = false; + char apduCommand[20]; // APDU stored in string format + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_seMediaGenericModemCloseUICCChannel()..."); + + if (ptrTSEMedia == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemCloseUICCChannel(): ptrTSEMedia is NULL!"); + return false; + } + + TSEMediaGenericModem* ptrTSEMediaGenericModem = (TSEMediaGenericModem*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaGenericModem != NULL) + { + // Check logical channel defined + if(ptrTSEMediaGenericModem->_apduChannel != 0) + { + if(ptrTSEMediaGenericModem->_apduChannel > 0 && ptrTSEMediaGenericModem->_apduChannel < 20) + { + // TODO Should be better to avoid sending Close Logical Channel command after eUICC reset has been performed: + // A third party application could have re-opened this Logical Channel for another use in the meanwhile. + // Suggestion of problem solving: + // - Close Logical Channel may be blocked if profile Enable / Disable with eUICC Reset requested has just been invoked (Implies modification of whole library) + // - Could detect a specific Unsolicited Event that may indicate eUICC reset in the meanwhile + + memset(apduCommand, 0 , sizeof(apduCommand)); // Empty string + + // Build APDU Command + // Note: strncat lengths limits + 1 to avoid warnings with some compilers: "...'strncat' specified bound X equals source length..." + strncat(apduCommand, GM_APDU_CLOSE_SIM_CHANNEL_PREFIX, (strlen(GM_APDU_CLOSE_SIM_CHANNEL_PREFIX) + 1)); // Prefix + strncat(apduCommand, ptrTSEMediaGenericModem->_apduChannelString, 3); // Channel to close + strncat(apduCommand, "00", 3); // Length + + // Despite this is a driver internal operation, Status Word will be not checked to avoid false errors with modems restarting in the meanwhile (STK Refresh) + // and returning than operation ran correctly but with error in Status Word due to new logical channel context. + // If an issue really occurred with Logical Channel closing, it will be detected on next operations attempts when Open will fail. + if(_seMediaGenericModemSendAPDUtoModemAndCheckOK(apduCommand, ptrTSEMedia, false)) + { + ptrTSEMediaGenericModem->_apduChannel = 0; + ptrTSEMediaGenericModem->_apduChannelString[0] = '\0'; + res = true; + } + else + { + // Try to detect if failure to close Logical Channel is not caused by UICC Reset initiated by STK Refresh Reset for example + // Here try to find that GM_AT_COMMAND_RESPONSE_PREFIX is missing in response and that GM_AT_COMMAND_RESPONSE_ERROR can be found. + // -> In that case we will consider there was probably an UICC Reset performed by modem + // + // This method may not apply to other models / brand of modems and may be need to be changed + // This is just a turnaround for problem explained before Close Logical Channel command sending + + if((strstr(responseBuffer, GM_AT_COMMAND_RESPONSE_PREFIX) == NULL) && (strstr(responseBuffer, GM_AT_COMMAND_RESPONSE_ERROR) != NULL)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "_seMediaGenericModemCloseUICCChannel(): ! Detected possible eUICC Reset performed by modem, consider that Logical Channel is closed."); + + ptrTSEMediaGenericModem->_apduChannel = 0; + ptrTSEMediaGenericModem->_apduChannelString[0] = '\0'; + res = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemCloseUICCChannel(): Problem while sending logical channel closing command!"); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemCloseUICCChannel(): Invalid logical channel number: %u", ptrTSEMediaGenericModem->_apduChannel); + + } + else + { + // If the logical channel has not been opened, there is no reason to exit on error + res = true; + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "_seMediaGenericModemCloseUICCChannel(): No logical channel currently opened"); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaGenericModemCloseUICCChannel(): ptrTSEMediaGenericModem is NULL!"); + + return res; +} + + +/** + * Extract APDU response from reception buffer and return it in raw hex byte array. + * + * @param ptrAPDU_response Array that will receive raw hex transcription of APDU response + * @param pMaxSize Maximum size allowed for Hex response data array + * @param pAPDU_response_size Will receive useful length of raw hex data stored in byte array + * @return True if the extraction / conversion was successful. + */ +static bool _seMediaGenericModemProcessAPDUresponse(unsigned char* ptrAPDU_response, const size_t pMaxSize, size_t * pAPDU_response_size) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_processAPDUresponse()..."); + + if(_seMediaGenericModemCheckATcommandResponseOK()) + { + char * extracted_ADPU_response = lpaCoreMemoryAlloc(strlen(responseBuffer)); + if(extracted_ADPU_response != NULL) + { + if(_seMediaGenericModemAtCommandResponseToApdu(responseBuffer, extracted_ADPU_response, strlen(responseBuffer))) + { + // Set maximum size for hexStr2ByteArray() output + *pAPDU_response_size = pMaxSize; + if(hexStr2ByteArray((const unsigned char *)extracted_ADPU_response, (int)strlen(extracted_ADPU_response), ptrAPDU_response, (int *)pAPDU_response_size)) + res = true; + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_processAPDUresponse(): Cannot convert APDU response to raw Hex or APDU response buffer too small!"); + + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_processAPDUresponse(): Cannot extract APDU response from response buffer!"); + + lpaCoreMemoryFree(extracted_ADPU_response); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_processAPDUresponse(): Cannot allocate memory for temporary APDU buffer!"); + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_processAPDUresponse(): Success status not detected in AT command response buffer!"); + } + + return res; +} + +/** + * send LPA Event execution error. + * + * @param scErrorCode - Error code + * @param ptrErrorCodeDescription - String containing user readable error message + */ +void _seMediaGenericModemSendLpaEventExecutionError(long scErrorCode, const char* ptrErrorCodeDescription) +{ + // using callback to share seMedia error + if (_lpaEventExecutionErrorCallback != NULL) + { + LPA_EVENT_EXECUTION_ERROR_INFO eventExecutionErrorInfo; + char errorSubjectCode[16]; + snprintf(errorSubjectCode, sizeof(errorSubjectCode), "0x%lx", scErrorCode); + + eventExecutionErrorInfo.executionErrorType = LPA_EVENT_EXECUTION_SEMEDIA_DRIVER_ERROR_TYPE; + eventExecutionErrorInfo.detailErrorMask = LPA_EVENT_EXECUTION_ERROR_SUBJECT_CODE_MASK; + eventExecutionErrorInfo.ptrErrorReasonCode = NULL; + eventExecutionErrorInfo.ptrErrorSubjectCode = errorSubjectCode; + + if (ptrErrorCodeDescription != NULL) + { + eventExecutionErrorInfo.detailErrorMask |= LPA_EVENT_EXECUTION_ERROR_EXTRA_INFO_MASK; + eventExecutionErrorInfo.ptrErrorExtraInfo = ptrErrorCodeDescription; + } + + _lpaEventExecutionErrorCallback(NULL, &eventExecutionErrorInfo); + } +} + +#if defined(LPA_SDK__PLATFORM_WIN) +void _seMediaGenericModemWriteOnLogWindowsError(DWORD windowsError) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Windows error: 0x%lx", windowsError); +} +#endif // LPA_SDK__PLATFORM_WIN + +#endif // LPA_SDK__SEMEDIA_DRIVER_GENERIC_MODEM diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/driver/semedia_winscard.c b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/driver/semedia_winscard.c new file mode 100755 index 000000000..2d2b15c35 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/driver/semedia_winscard.c @@ -0,0 +1,1093 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + + +#include "lpasdk/driver/semedia_winscard.h" +#include "lpasdk/core/lpa_log.h" +#include "lpasdk/core/lpa_memory.h" +#include "lpasdk/core/util.h" + +// This driver is compiled only if LPA_SDK__SEMEDIA_DRIVER_WINSCARD build option exist +#ifdef LPA_SDK__SEMEDIA_DRIVER_WINSCARD + +#ifdef LPA_SDK__PLATFORM_RASPBIAN +#include +#endif // LPA_SDK__PLATFORM_RASPBIAN + +// Functions needed for SE Media driver +bool _seMediaWinSCardSetCallbackEventExecutionError(const struct TSEMedia* ptrTSEMedia, LPA_EVENT_EXECUTION_ERROR lpaEventExecutionErrorCallback); + +bool _seMediaWinSCardEstablishContext(const struct TSEMedia* ptrTSEMedia); +bool _seMediaWinSCardReleaseContext(const struct TSEMedia* ptrTSEMedia); +bool _seMediaWinSCardIsValidContext(const struct TSEMedia* ptrTSEMedia); +bool _seMediaWinSCardIsContextEstablished(const struct TSEMedia* ptrTSEMedia); + +bool _seMediaWinSCardListReader(const struct TSEMedia* ptrTSEMedia, LPA_SE_MEDIA_READER_NAME_INFO * ptrReaderNameInfoList, size_t readerNameInfoMax, size_t* ptrCountReader); +bool _seMediaWinSCardConnect(const struct TSEMedia* ptrTSEMedia, const char *ptrReaderName); +bool _seMediaWinSCardTransmitApdu(const struct TSEMedia* ptrTSEMedia, const unsigned char* ptrApduCommandBytes, size_t apduCommandSize, unsigned char* ptrApduResponseBytes, size_t* ptrApduResponseMaxSize); +bool _seMediaWinSCardIsConnected(const struct TSEMedia* ptrTSEMedia); +bool _seMediaWinSCardDisconnect(const struct TSEMedia* ptrTSEMedia); +bool _seMediaWinSCardDisconnectWithReset(const struct TSEMedia* ptrTSEMedia); + +bool _seMediaWinSCardGetStatus(const struct TSEMedia* ptrTSEMedia, SE_MEDIA_CARD_STATUS* ptrStatus); + +// Internals functions +char* _seMediaWinSCardInternalGetSCErrorDescription(DWORD scErrorCode); +bool _seMediaWinSCardInternalDisconnect(const struct TSEMedia* ptrTSEMedia, SE_MEDIA_DISCONNECT_CARD_PARAM disconnectCardParam); +void _seMediaWinSCardInternalSendLpaEventExecutionError(long scErrorCode, const char* ptrErrorCodeDescription); +bool _seMediaWinSCardInternalTransmitApdu(const struct TSEMedia* ptrTSEMedia, const unsigned char* ptrApduCommandBytes, size_t apduCommandSize, unsigned char* ptrApduResponseBytes, size_t* ptrApduResponseMaxSize); +bool _seMediaWinSCardInternalOpenUICCChannel(const struct TSEMedia* ptrTSEMedia); +bool _seMediaWinSCardInternalCloseUICCChannel(const struct TSEMedia* ptrTSEMedia); + +#define SCARD_INVALID_HANDLE 0L +#define WC_APDU_COMMAND_INTERNAL_BUFFER_SIZE 265 // Normally 261 shall be enough (APDU command + max payload + le = 5 + 255 + 1) +#define WC_COMMMAND_RESPONSE_SIZE_FOR_LOGICAL_CHANNEL 4 + +static char _bufferFormatLogMessage[1024]; + +static const unsigned char WC_APDU_OPEN_SIM_CHANNEL [] = {0x00, 0x70, 0x00, 0x00, 0x01}; +static const unsigned char WC_APDU_CLOSE_SIM_CHANNEL_PREFIX [] = {0x00, 0x70, 0x80}; + +// Event execution error callback +static LPA_EVENT_EXECUTION_ERROR _lpaEventExecutionErrorCallback = NULL; + +typedef struct +{ + DWORD _errorValue; + char* _ptrErrorString; +} SCARD_ERROR_INFO; + + +SCARD_ERROR_INFO _scardErrorList[] = +{ + { ERROR_BROKEN_PIPE, "ERROR_BROKEN_PIPE" }, + { SCARD_E_CANCELLED, "SCARD_E_CANCELLED" }, + { SCARD_E_CANT_DISPOSE, "SCARD_E_CANT_DISPOSE" }, + { SCARD_E_CARD_UNSUPPORTED, "SCARD_E_CARD_UNSUPPORTED" }, + { SCARD_E_DUPLICATE_READER, "SCARD_E_DUPLICATE_READER" }, + { SCARD_E_FILE_NOT_FOUND, "SCARD_E_FILE_NOT_FOUND" }, + { SCARD_E_INSUFFICIENT_BUFFER, "SCARD_E_INSUFFICIENT_BUFFER" }, + { SCARD_E_INVALID_ATR, "SCARD_E_INVALID_ATR" }, + { SCARD_E_INVALID_HANDLE, "SCARD_E_INVALID_HANDLE" }, + { SCARD_E_INVALID_PARAMETER, "SCARD_E_INVALID_PARAMETER" }, + { SCARD_E_INVALID_TARGET, "SCARD_E_INVALID_TARGET" }, + { SCARD_E_INVALID_VALUE, "SCARD_E_INVALID_VALUE" }, + { SCARD_E_NO_MEMORY, "SCARD_E_NO_MEMORY" }, + { SCARD_E_NO_READERS_AVAILABLE, "SCARD_E_NO_READERS_AVAILABLE" }, + { SCARD_E_NO_SMARTCARD, "SCARD_E_NO_SMARTCARD" }, + { SCARD_E_NOT_READY, "SCARD_E_NOT_READY" }, + { SCARD_E_PROTO_MISMATCH, "SCARD_E_PROTO_MISMATCH" }, + { SCARD_E_READER_UNAVAILABLE, "SCARD_E_READER_UNAVAILABLE" }, + { SCARD_E_READER_UNSUPPORTED, "SCARD_E_READER_UNSUPPORTED" }, + { SCARD_E_SERVER_TOO_BUSY, "SCARD_E_SERVER_TOO_BUSY" }, + { SCARD_E_SERVICE_STOPPED, "SCARD_E_SERVICE_STOPPED" }, + { SCARD_E_SHARING_VIOLATION, "SCARD_E_SHARING_VIOLATION" }, + { SCARD_E_SYSTEM_CANCELLED, "SCARD_E_SYSTEM_CANCELLED" }, + { SCARD_E_TIMEOUT, "SCARD_E_TIMEOUT" }, + { SCARD_E_UNEXPECTED, "SCARD_E_UNEXPECTED" }, + { SCARD_E_UNKNOWN_CARD, "SCARD_E_UNKNOWN_CARD" }, + { SCARD_E_UNKNOWN_READER, "SCARD_E_UNKNOWN_READER" }, + { SCARD_W_REMOVED_CARD, "SCARD_W_REMOVED_CARD" }, + { SCARD_W_RESET_CARD, "SCARD_W_RESET_CARD" }, + { SCARD_W_UNSUPPORTED_CARD, "SCARD_W_UNSUPPORTED_CARD" }, + { SCARD_W_UNRESPONSIVE_CARD, "SCARD_W_UNRESPONSIVE_CARD" }, + { SCARD_E_COMM_DATA_LOST, "SCARD_E_COMM_DATA_LOST" }, + { SCARD_E_NO_SERVICE, "SCARD_E_NO_SERVICE"}, + + // Latest record + { 0, NULL } +}; + +/** + * Initializes a structure type "TSEMediaWinSCard", affect TSEMediaWinSCard->ptrBase to a pointer type "TSEMedia" object and return it. + * Elements stored points on functions defined below and elsewhere. + * + * @return Pointer on object type TSEMedia + */ +TSEMedia* New_SEMediaWinSCard() +{ + TSEMedia* ptrTSEMedia = NULL; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_winscard :> New_SEMediaWinSCard()"); + + TSEMediaWinSCard* seMediaWinSCard = (TSEMediaWinSCard*) lpaCoreMemoryAlloc(sizeof(TSEMediaWinSCard)); + if (seMediaWinSCard != NULL) + { + seMediaWinSCard->_ptrBase = New_SEMediaBase(); // See "semedia_base.c". Allocate memory bloc size of TSEMedia for TESMedia object + if(seMediaWinSCard->_ptrBase != NULL) + { + seMediaWinSCard->_ptrBase->_childStruct = seMediaWinSCard; // Points on seMediaWinSCard to allow find it through TSEMedia pointer + + seMediaWinSCard->_ptrBase->seMediaSetCallbackEventExecutionError = _seMediaWinSCardSetCallbackEventExecutionError; // Function defined below + + seMediaWinSCard->_ptrBase->seMediaEstablishContext = _seMediaWinSCardEstablishContext; // Function defined below + seMediaWinSCard->_ptrBase->seMediaReleaseContext = _seMediaWinSCardReleaseContext; // Function defined below + seMediaWinSCard->_ptrBase->seMediaIsValidContext = _seMediaWinSCardIsValidContext; // Function defined below + seMediaWinSCard->_ptrBase->seMediaIsContextEstablished = _seMediaWinSCardIsContextEstablished; // Function defined below + + seMediaWinSCard->_ptrBase->seMediaListReader = _seMediaWinSCardListReader; // Function defined below + seMediaWinSCard->_ptrBase->seMediaConnect = _seMediaWinSCardConnect; // Function defined below + seMediaWinSCard->_ptrBase->seMediaIsConnected = _seMediaWinSCardIsConnected; // Function defined below + seMediaWinSCard->_ptrBase->seMediaTransmitApdu = _seMediaWinSCardTransmitApdu; // Function defined below + seMediaWinSCard->_ptrBase->seMediaDisconnect = _seMediaWinSCardDisconnect; // Function defined below + seMediaWinSCard->_ptrBase->seMediaDisconnectWithReset = _seMediaWinSCardDisconnectWithReset; // Function defined below + + seMediaWinSCard->_ptrBase->seMediaGetStatus = _seMediaWinSCardGetStatus; // Function defined below + + // Next 4 elements will be reachable through _childStruct pointer + seMediaWinSCard->_contextEstablished = false; // Context establishment flag + seMediaWinSCard->_scardContext = SCARD_INVALID_HANDLE; // Pointer to reader context + seMediaWinSCard->_scardHandle = SCARD_INVALID_HANDLE; // Pointer to reader handle + seMediaWinSCard->_apduChannel = 0; // Specific APDU channel + + ptrTSEMedia = (TSEMedia*)seMediaWinSCard->_ptrBase; // Will return base of TSEMedia object contained in seMediaWinSCard + + // Manage default driver Configuration + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_disconnectParam = SE_MEDIA_DISCONNECT_LEAVE_CARD"); + seMediaWinSCard->_disconnectParam = SE_MEDIA_DISCONNECT_LEAVE_CARD; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_connectSharedMode = SCARD_SHARE_SHARED"); + seMediaWinSCard->_connectSharedMode = SCARD_SHARE_SHARED; + } + else + { + // Free memory if allocation for seMediaWinSCard->_ptrBase failed + lpaCoreMemoryFree(seMediaWinSCard); + seMediaWinSCard = NULL; + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "New_SEMediaWinSCard(): Cannot allocate memory for _ptrBase object!"); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "New_SEMediaWinSCard(): Cannot allocate memory for TSEMediaWinSCard object!"); + + // By default, No callback available for LPA Event Execution error + _lpaEventExecutionErrorCallback = NULL; + + return ptrTSEMedia; +} + +/** + * Delete and free memory for TSEMedia object, including "parent" TSEMediaWinSCard structure linked through _childStruct. + * + * @param ptrTSEMedia - Pointer on TSEMedia object to delete + */ +void Delete_SEMediaWinSCard(TSEMedia* ptrTSEMedia) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_winscard :> Delete_SEMediaWinSCard()"); + + if (ptrTSEMedia != NULL) + { + TSEMediaWinSCard* ptrTSEMediaWinSCard = (TSEMediaWinSCard*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaWinSCard != NULL) + lpaCoreMemoryFree(ptrTSEMediaWinSCard); + + lpaCoreMemoryFree(ptrTSEMedia); + ptrTSEMedia = NULL; + } +} + +/** + * Set LPA_EVENT_EXECUTION_ERROR callback + * + * @param ptrTSEMedia - TSEMedia object pointer + * @param LPA_EVENT_EXECUTION_ERROR - callback + * @return true if set callback successfully, otherwise false + */ + +bool _seMediaWinSCardSetCallbackEventExecutionError(const struct TSEMedia* ptrTSEMedia, LPA_EVENT_EXECUTION_ERROR lpaEventExecutionErrorCallback) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_winscard :> _seMediaWinSCardSetCallbackEventExecutionError()"); + + bool res = false; + + if (lpaEventExecutionErrorCallback != NULL) + { + if (_lpaEventExecutionErrorCallback != lpaEventExecutionErrorCallback) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, " registering lpaEventExecutionErrorCallback..."); + _lpaEventExecutionErrorCallback = lpaEventExecutionErrorCallback; + res = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, " LpaEventExecutionErrorCallback already registered!"); + } + else + { + if (_lpaEventExecutionErrorCallback != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, " unregistering lpaEventExecutionErrorCallback..."); + _lpaEventExecutionErrorCallback = NULL; + res = true; + } + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- semedia_winscard :> _seMediaWinSCardSetCallbackEventExecutionError() return res=%s", (res ? "true" : "false")); + + return res; +} + +/** + * Try to establish TSEMedia object "context" through SCardEstablishContext() referred "extern" in "winscard.h" + * And update "context" status in TSEMedia object + * + * @param ptrTSEMedia - TSEMedia object pointer + * @return Status of "context established" state, boolean, true if established successfully + */ +bool _seMediaWinSCardEstablishContext(const struct TSEMedia* ptrTSEMedia) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "+ semedia_winscard :> _seMediaWinSCardEstablishContext()"); + bool res = false; + + if (ptrTSEMedia != NULL) + { + TSEMediaWinSCard* ptrTSEMediaWinSCard = (TSEMediaWinSCard*)ptrTSEMedia->_childStruct; + + if (!ptrTSEMediaWinSCard->_contextEstablished) + { + long scReturnCode = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &ptrTSEMediaWinSCard->_scardContext); + if (scReturnCode == SCARD_S_SUCCESS) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "SCardEstablishContext() return SCARD_S_SUCCESS"); + + ptrTSEMediaWinSCard->_contextEstablished = true; + res = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "SCardEstablishContext() return error 0x%08lx (%s)", + scReturnCode, _seMediaWinSCardInternalGetSCErrorDescription(scReturnCode)); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "SCardEstablishContext() already established"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "seMedia is NULL!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- semedia_winscard :> _seMediaWinSCardEstablishContext() return res=%s", (res ? "true" : "false")); + + return res; +} + + + +/** + * Return status of "context established" state stored in TSEMedia object + * + * @param ptrTSEMedia - TSEMedia object pointer + * @return Boolean, true or false + */ +bool _seMediaWinSCardIsContextEstablished(const struct TSEMedia* ptrTSEMedia) +{ + bool isContextEstablished = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_winscard :> _seMediaWinSCardIsContextEstablished()"); + if (ptrTSEMedia != NULL) + { + TSEMediaWinSCard* ptrTSEMediaWinSCard = (TSEMediaWinSCard*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaWinSCard != NULL) + isContextEstablished = ptrTSEMediaWinSCard->_contextEstablished; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "seMedia is NULL!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- semedia_winscard :> _seMediaWinSCardIsContextEstablished() return res=%s", (isContextEstablished ? "true" : "false")); + + return isContextEstablished; +} + +/** + * Try to release TSEMedia object "context" through SCardReleaseContext() referred "extern" in "winscard.h" + * And update "context" status in TSEMedia object + * + * @param ptrTSEMedia - TSEMedia object pointer + * @return True if "context" released successfully, boolean + */ +bool _seMediaWinSCardReleaseContext(const struct TSEMedia* ptrTSEMedia) +{ + bool res = false; + TSEMediaWinSCard* ptrTSEMediaWinSCard = NULL; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_winscard :> _seMediaWinSCardReleaseContext()"); + + if (ptrTSEMedia != NULL) + { + ptrTSEMediaWinSCard = (TSEMediaWinSCard*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaWinSCard->_contextEstablished) + { + // Check if ISDR applet selected + if (_seMediaWinSCardIsConnected(ptrTSEMedia)) + _seMediaWinSCardDisconnect(ptrTSEMedia); + + long scReturnCode = SCardReleaseContext(ptrTSEMediaWinSCard->_scardContext); + if (scReturnCode == SCARD_S_SUCCESS) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "SCardReleaseContext() return SCARD_S_SUCCESS"); + + ptrTSEMediaWinSCard->_scardContext = SCARD_INVALID_HANDLE; + ptrTSEMediaWinSCard->_contextEstablished = false; + ptrTSEMediaWinSCard->_scardHandle = SCARD_INVALID_HANDLE; + + res = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "SCardReleaseContext() return error 0x%08lx (%s)", + scReturnCode, _seMediaWinSCardInternalGetSCErrorDescription(scReturnCode)); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "SCardReleaseContext() : Context not established"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "seMedia is NULL!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- semedia_winscard :> _seMediaWinSCardReleaseContext() return res=%s", (res ? "true" : "false")); + + return res; +} + +/** + * Try to get status of "Media Valid" through SCardIsValidContext() referred "extern" in "winscard.h" + * + * @param ptrTSEMedia - TSEMedia object pointer + * @return True if "Media Valid" status is verified successfully, boolean + */ +bool _seMediaWinSCardIsValidContext(const struct TSEMedia* ptrTSEMedia) +{ + bool isValidContext = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_winscard :> _seMediaWinSCardIsValidContext()"); + + if (ptrTSEMedia == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "seMedia is NULL!"); + return false; + } + + TSEMediaWinSCard* ptrTSEMediaWinSCard = (TSEMediaWinSCard*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaWinSCard != NULL) + { + long scReturnCode = SCardIsValidContext(ptrTSEMediaWinSCard->_scardContext); + if (scReturnCode == SCARD_S_SUCCESS) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "SCardIsValidContext() return SCARD_S_SUCCESS"); + isValidContext = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "SCardIsValidContext() return error 0x%08lx (%s)", + scReturnCode, _seMediaWinSCardInternalGetSCErrorDescription(scReturnCode)); + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- semedia_winscard :> _seMediaWinSCardIsValidContext() return res=%s", (isValidContext ? "true" : "false")); + + return isValidContext; +} + +/** + * Try to get reader list through "SCardListReaders" defined in "winscard.h", itself defined by "__MINGW_NAME_AW" defined in "_minggw_unicode.h" + * + * @param ptrTSEMedia - TSEMedia object pointer + * @param readerNameInfoList - Structure LPA_SE_MEDIA_READER_NAME_INFO defined in "lpasdk_api.h" containing "readerName" char array. + * @param readerNameInfoMax - Maximum number of readers that can be reported in list, size_t + * @param countReader - Return number of readers found, size_t + * @return True if reader list retrieving finished successfully. + */ +bool _seMediaWinSCardListReader(const struct TSEMedia* ptrTSEMedia, LPA_SE_MEDIA_READER_NAME_INFO * ptrReaderNameInfoList, size_t readerNameInfoMax, size_t* ptrCountReader) +{ + bool readListReader = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_winscard :> _seMediaWinSCardListReader()"); + + if (ptrTSEMedia != NULL && ptrReaderNameInfoList != NULL && ptrCountReader != NULL) + { + *ptrCountReader = 0; + + TSEMediaWinSCard* ptrTSEMediaWinSCard = (TSEMediaWinSCard*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaWinSCard != NULL) + { + LPTSTR mszReaders = NULL; + DWORD dwReaders = SCARD_AUTOALLOCATE; + + long scReturnCode = SCardListReaders(ptrTSEMediaWinSCard->_scardContext, SCARD_ALL_READERS, (LPTSTR)&mszReaders, &dwReaders); + if (scReturnCode == SCARD_S_SUCCESS) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "SCardListReaders() return SCARD_S_SUCCESS"); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "dwReaders: %ld", dwReaders); + + readListReader = true; + if (mszReaders != NULL && dwReaders > 0) + { + LPTSTR pReader = mszReaders; + while ('\0' != *pReader) + { + // Manage JIRA DMSIMCE-362 + if (((DWORD)(pReader - mszReaders)) >= dwReaders) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "End of reader list detected"); + break; + } + + if (*ptrCountReader < readerNameInfoMax) + { + // Display the value. + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Reader found: <%s>", pReader); + if (strlen(pReader) < LPA_CFG_READER_NAME_MAX_SIZE) + { + snprintf(ptrReaderNameInfoList[(*ptrCountReader)].readerName, LPA_CFG_READER_NAME_MAX_SIZE, "%s", pReader); + + // Advance to the next value. + (*ptrCountReader)++; + pReader = pReader + strlen(pReader) + 1; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Reader name too long! (max size: %u, current size: %llu)", LPA_CFG_READER_NAME_MAX_SIZE, (long long unsigned)strlen(pReader)); + readListReader = false; + break; + } + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Too many detected readers (Maximum set to %llu through parameter \"readerNameInfoMax\" )", (long long unsigned)readerNameInfoMax); + readListReader = false; + break; + } + } + + // Free the memory. + SCardFreeMemory(ptrTSEMediaWinSCard->_scardContext, mszReaders); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "SCardListReaders() return error 0x%08lx (%s)", scReturnCode, _seMediaWinSCardInternalGetSCErrorDescription(scReturnCode)); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "NULL parameter detected!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- semedia_winscard :> _seMediaWinSCardListReader() return res=%s", (readListReader ? "true" : "false")); + + return readListReader; +} + +/** + * Try to perform "Connect" operation on a reader using reader name to identify it. + * Done through "SCardConnect" defined in "winscard.h", itself defined by "__MINGW_NAME_AW" defined in "_minggw_unicode.h" + * Update "connection" status in TSEMedia object + * + * @param ptrTSEMedia - TSEMedia object pointer + * @param ptrReaderName - Reader name, string, coming from reader list retrieved with seMediaListReader() + * @return True if connection operation was successful + */ + +bool _seMediaWinSCardConnect(const struct TSEMedia* ptrTSEMedia, const char *ptrReaderName) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_winscard :> _seMediaWinSCardConnect()"); + + if (ptrTSEMedia != NULL && ptrReaderName != NULL ) + { + TSEMediaWinSCard* ptrTSEMediaWinSCard = (TSEMediaWinSCard*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaWinSCard != NULL) + { + DWORD dwActiveProtocol = 0; + ptrTSEMediaWinSCard->_apduChannel = 0; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "ReaderName='%s'", ptrReaderName); + + long scReturnCode = SCardConnect(ptrTSEMediaWinSCard->_scardContext, ptrReaderName, ptrTSEMediaWinSCard->_connectSharedMode, + SCARD_PROTOCOL_T0, &ptrTSEMediaWinSCard->_scardHandle, &dwActiveProtocol); + + if (scReturnCode == SCARD_S_SUCCESS) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "SCardConnect() return SCARD_S_SUCCESS"); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "active protocol used: %s", (dwActiveProtocol == SCARD_PROTOCOL_T0 ? "T0" : (dwActiveProtocol == SCARD_PROTOCOL_T1 ? "T1" : "N/A"))); + + res = true; + } + else + { + const char* ptrWinscardErrorDescription = _seMediaWinSCardInternalGetSCErrorDescription(scReturnCode); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "SCardConnect() return error 0x%08lx (%s)", scReturnCode, ptrWinscardErrorDescription); + + _seMediaWinSCardInternalSendLpaEventExecutionError(scReturnCode, ptrWinscardErrorDescription); + } + } + } + else + { + if (ptrTSEMedia == NULL) + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "seMedia is NULL!"); + + if (ptrReaderName == NULL) + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "ptrReaderName is NULL!"); + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- semedia_winscard :> _seMediaWinSCardConnect() return res=%s", (res ? "true" : "false")); + + return res; +} + +/** + * Return connection status of reader linked to TSEMedia object. + * + * @param ptrTSEMedia - TSEMedia object pointer + * @return True if reader connection status is verified successfully, boolean + */ +bool _seMediaWinSCardIsConnected(const struct TSEMedia* ptrTSEMedia) +{ + bool isConnected = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_winscard :> _seMediaWinSCardIsConnected()"); + + if (ptrTSEMedia != NULL) + { + TSEMediaWinSCard* ptrTSEMediaWinSCard = (TSEMediaWinSCard*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaWinSCard != NULL) + { + if (ptrTSEMediaWinSCard->_scardHandle != SCARD_INVALID_HANDLE) + isConnected = true; + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "seMedia is NULL!"); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- semedia_winscard :> _seMediaWinSCardIsConnected() return res=%s", (isConnected ? "true" : "false")); + + return isConnected; +} + +/** + * Try perform sending of APDU on reader linked to TSEMedia object and retrieve response, with management of Logical Channel + * + * @param ptrTSEMedia - TSEMedia object pointer + * @param apduCommandBytes - APDU command to send - bytes format + * @param apduCommandSize - Size of ADPDU command to send, size_t + * @param apduResponseBytes - Store command response returned by reader - bytes format + * @param apduResponseMaxSize - Size of command response, size_t + * @return True if reader reported that exchange was successful. + */ +bool _seMediaWinSCardTransmitApdu(const struct TSEMedia* ptrTSEMedia, const unsigned char* apduCommandBytes, size_t apduCommandSize, unsigned char* apduResponseBytes, size_t* apduResponseMaxSize) +{ + bool res = false; + unsigned char apduCommandBytesWithLogicalChannel[WC_APDU_COMMAND_INTERNAL_BUFFER_SIZE]; + unsigned char apduLogicalChannel = 0; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_winscard :> _seMediaWinSCardTransmitApdu()"); + + if (ptrTSEMedia == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "seMedia is NULL!"); + return false; + } + + if (apduCommandBytes != NULL && apduResponseBytes != NULL && apduCommandSize >= 4 && apduCommandSize < WC_APDU_COMMAND_INTERNAL_BUFFER_SIZE && apduResponseMaxSize != NULL && *apduResponseMaxSize >= 2) + { + TSEMediaWinSCard* ptrTSEMediaWinSCard = (TSEMediaWinSCard*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaWinSCard != NULL) + { + // Check if logical channel has been opened. If not, try to open it + if(ptrTSEMediaWinSCard->_apduChannel == 0) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Logical channel not yet opened, opening it..."); + + if(_seMediaWinSCardInternalOpenUICCChannel(ptrTSEMedia)) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Logical channel opening succeed"); + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Logical channel opening failed! APDU transmit will abort"); + // Code 0x70 not used in errors returned by Winscard driver. It is a reference to Manage Channel APDU INS. + _seMediaWinSCardInternalSendLpaEventExecutionError(0x70, "Failed to open logical channel"); + } + } + + // Do not perform transmit and return error if logical channel has not been opened or invalid (Memory corruption, attack...) + if(ptrTSEMediaWinSCard->_apduChannel > 0 && ptrTSEMediaWinSCard->_apduChannel < 20) + { + // Class management. Set Logical Channel to be used to communicate with eUICC + // Cannot modify original apdu command buffer so copy it in another buffer. + memcpy(apduCommandBytesWithLogicalChannel, apduCommandBytes, apduCommandSize); + + // Set coding of Logical Channel to apply to APDU class byte depending we work on normal or extended Logical Channel + if(ptrTSEMediaWinSCard->_apduChannel < 4) + apduLogicalChannel = ptrTSEMediaWinSCard->_apduChannel; + else + apduLogicalChannel = (ptrTSEMediaWinSCard->_apduChannel - 4) + 0x40; + // Note: Coding of bits relative to Secure Messaging (See GP chapters 11.1.4.1 / 11.1.4.2) are not implemented here because no Secure Messaging + // is used for LPA operations. Could be added in the future. + apduCommandBytesWithLogicalChannel[0] = apduCommandBytesWithLogicalChannel[0] | apduLogicalChannel; + + // Send command to reader an recover response + res = _seMediaWinSCardInternalTransmitApdu(ptrTSEMedia, apduCommandBytesWithLogicalChannel, apduCommandSize, apduResponseBytes, apduResponseMaxSize); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaWinSCardTransmitApdu(): Invalid or out of context logical channel: %u", ptrTSEMediaWinSCard->_apduChannel); + } + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- semedia_winscard :> _seMediaWinSCardTransmitApdu() return res=%s", (res ? "true" : "false")); + + return res; +} + +/** + * Try perform sending of APDU on reader linked to TSEMedia object and retrieve response, without any change in APDU command and no check of logical channel + * Uses SCardTransmit() referred "extern" in "winscard.h" + * + * @param ptrTSEMedia - TSEMedia object pointer + * @param apduCommandBytes - APDU command to send - bytes format + * @param apduCommandSize - Size of ADPDU command to send, size_t + * @param apduResponseBytes - Store command response returned by reader - bytes format + * @param apduResponseMaxSize - Size of command response, size_t + * @return True if reader reported that exchange was successful. + */ +bool _seMediaWinSCardInternalTransmitApdu(const struct TSEMedia* ptrTSEMedia, const unsigned char* apduCommandBytes, size_t apduCommandSize, unsigned char* apduResponseBytes, size_t* apduResponseMaxSize) +{ + bool res = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_winscard :> _seMediaWinSCardInternalTransmitApdu()"); + + if (ptrTSEMedia == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "seMedia is NULL!"); + return false; + } + + if (apduCommandBytes != NULL && apduResponseBytes != NULL && apduCommandSize >= 4 && apduResponseMaxSize != NULL && *apduResponseMaxSize >= 2) + { + TSEMediaWinSCard* ptrTSEMediaWinSCard = (TSEMediaWinSCard*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaWinSCard != NULL) + { + // manage the APDU + if (formatBytesToHexaString(apduCommandBytes, apduCommandSize, _bufferFormatLogMessage, sizeof(_bufferFormatLogMessage)) > 0) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "APDU Command (%llu): %s", (long long unsigned)apduCommandSize, _bufferFormatLogMessage); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "APDU Command (%llu): ...", (long long unsigned)apduCommandSize); + + DWORD cbRecvLength = (DWORD) (*apduResponseMaxSize); + long scReturnCode = SCardTransmit(ptrTSEMediaWinSCard->_scardHandle, SCARD_PCI_T0, apduCommandBytes, apduCommandSize, NULL, apduResponseBytes, &cbRecvLength); + if (scReturnCode == SCARD_S_SUCCESS) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "SCardTransmit() return SCARD_S_SUCCESS"); + + if (formatBytesToHexaString(apduResponseBytes, cbRecvLength, _bufferFormatLogMessage, sizeof(_bufferFormatLogMessage)) > 0) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "APDU Response (%ld): %s", cbRecvLength, _bufferFormatLogMessage); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "APDU Response (%ld): ...", cbRecvLength); + + res = true; + *apduResponseMaxSize = (size_t) cbRecvLength; + } + else + { + const char* ptrWinscardErrorDescription = _seMediaWinSCardInternalGetSCErrorDescription(scReturnCode); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "SCardTransmit() return error 0x%08lx (%s)", scReturnCode, ptrWinscardErrorDescription); + *apduResponseMaxSize = 0L; + + _seMediaWinSCardInternalSendLpaEventExecutionError(scReturnCode, ptrWinscardErrorDescription); + } + } + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- semedia_winscard :> _seMediaWinSCardInternalTransmitApdu() return res=%s", (res ? "true" : "false")); + + return res; +} + +/** + * Try to perform "Disconnect" operation on reader linked to TSEMedia object. + * + * @param ptrTSEMedia - TSEMedia object pointer + * @return True if disconnect operation was successful. + */ + +bool _seMediaWinSCardDisconnect(const struct TSEMedia* ptrTSEMedia) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_winscard :> _seMediaWinSCardDisconnect()"); + + bool res = false; + + if (ptrTSEMedia != NULL) + { + TSEMediaWinSCard* ptrTSEMediaWinSCard = (TSEMediaWinSCard*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaWinSCard != NULL) + { + // Close logical channel if needed + // Reader will be disconnected whatever will be the status of logical channel closing, by all the way it is not recoverable + if(ptrTSEMediaWinSCard->_apduChannel != 0) + { + if(_seMediaWinSCardInternalCloseUICCChannel(ptrTSEMedia)) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_seMediaWinSCardDisconnect(): Successful closing of current logical channel"); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaWinSCardDisconnect(): Failed to close current logical channel!"); + } + + // Disconnect reader + res = _seMediaWinSCardInternalDisconnect(ptrTSEMedia, ptrTSEMediaWinSCard->_disconnectParam); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaWinSCardDisconnect(): Failed to get ptrTSEMediaWinSCard!"); + } + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- semedia_winscard :> _seMediaWinSCardDisconnect() return res=%s", (res ? "true" : "false")); + + return res; +} + +/** + * Try to perform "Disconnect" with Reset operation on reader linked to TSEMedia object. + * + * @param ptrTSEMedia - TSEMedia object pointer + * @return True if disconnect operation was successful. + */ + +bool _seMediaWinSCardDisconnectWithReset(const struct TSEMedia* ptrTSEMedia) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_winscard :> _seMediaWinSCardDisconnectWithReset()"); + + res = _seMediaWinSCardInternalDisconnect(ptrTSEMedia, SE_MEDIA_DISCONNECT_RESET_CARD); + + // Logical channel management if needed + TSEMediaWinSCard* ptrTSEMediaWinSCard = (TSEMediaWinSCard*)ptrTSEMedia->_childStruct; + // Note: If failed to get ptrTSEMediaWinSCard, channel number will be reset on next opening attempt + if (ptrTSEMediaWinSCard != NULL) + { + if(ptrTSEMediaWinSCard->_apduChannel != 0) + { + // If card reset is successful, logical channel is marked closed, else try perform logical channel close to avoid leaving unused logical channel + if(res) + { + ptrTSEMediaWinSCard->_apduChannel = 0; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaWinSCardDisconnectWithReset(): Error detected during reader reset. Try to close current logical channel..."); + if(_seMediaWinSCardInternalCloseUICCChannel(ptrTSEMedia)) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_seMediaWinSCardDisconnectWithReset(): Successful closing of current logical channel after failed reader reset"); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaWinSCardDisconnectWithReset(): Failed to close current logical channel after failed reader reset!"); + } + } + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- semedia_winscard :> _seMediaWinSCardDisconnectWithReset() return res=%s", (res ? "true" : "false")); + + return res; +} + +/** + * Try to perform "Disconnect" operation on reader linked to TSEMedia object. + * Done through "SCardDisconnect" referred "extern" in "winscard.h" + * + * @param ptrTSEMedia - TSEMedia object pointer + * @param disconnectCardParam - disconnect parameter + * @return True if disconnect operation was successful. + */ + +bool _seMediaWinSCardInternalDisconnect(const struct TSEMedia* ptrTSEMedia, SE_MEDIA_DISCONNECT_CARD_PARAM disconnectCardParam) +{ + bool disconnected = false; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_winscard :> _seMediaWinSCardInternalDisconnect()"); + + if (ptrTSEMedia == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "seMedia is NULL!"); + return false; + } + + TSEMediaWinSCard* ptrTSEMediaWinSCard = (TSEMediaWinSCard*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaWinSCard != NULL) + { + long scReturnCode = SCardDisconnect(ptrTSEMediaWinSCard->_scardHandle, disconnectCardParam); + if (scReturnCode == SCARD_S_SUCCESS) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "SCardDisconnect() return SCARD_S_SUCCESS"); + ptrTSEMediaWinSCard->_scardHandle = SCARD_INVALID_HANDLE; + disconnected = true; + } + else + { + const char* ptrWinscardErrorDescription = _seMediaWinSCardInternalGetSCErrorDescription(scReturnCode); + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "SCardDisconnect() return error 0x%08lx (%s)", + scReturnCode, ptrWinscardErrorDescription); + + _seMediaWinSCardInternalSendLpaEventExecutionError(scReturnCode, ptrWinscardErrorDescription); + } + } + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- semedia_winscard :> _seMediaWinSCardInternalDisconnect() return res=%s", (disconnected ? "true" : "false")); + + return disconnected; +} + +/** +* Get current status of reader linked to TSEMedia object. +* Done through "SCardStatus" defined in "winscard.h", itself defined by "__MINGW_NAME_AW" defined in "_minggw_unicode.h" +* Status will be returned only if condition SCARD_S_SUCCESS, SCARD_W_REMOVED_CARD or SCARD_W_RESET_CARD is returned by SCardStatus() +* +* @param ptrTSEMedia - TSEMedia object pointer +* @param ptrStatus - Return reader status in pointer on enum object type SE_MEDIA_CARD_STATUS defined in "semedia_base.h". +* @return True if condition SCARD_S_SUCCESS, SCARD_W_REMOVED_CARD or SCARD_W_RESET_CARD is returned by SCardStatus() +*/ +bool _seMediaWinSCardGetStatus(const struct TSEMedia* ptrTSEMedia, SE_MEDIA_CARD_STATUS* ptrStatus) +{ + bool res = false; + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ semedia_winscard :> _seMediaWinSCardGetStatus()"); + + // ptrStatus NULL is managed at the end + if (ptrTSEMedia == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "seMedia is NULL!"); + return false; + } + + TSEMediaWinSCard* ptrTSEMediaWinSCard = (TSEMediaWinSCard*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaWinSCard != NULL) + { + if (ptrTSEMediaWinSCard->_scardHandle != SCARD_INVALID_HANDLE) + { + DWORD dwState = 0, dwProtocol = 0, dwReaderLen = 0, dwAtrLen = 0; + SE_MEDIA_CARD_STATUS cardStatus = SE_MEDIA_STATUS_SCARD_UNKNOWN; + + long scReturnCode = SCardStatus(ptrTSEMediaWinSCard->_scardHandle, NULL, &dwReaderLen, &dwState, &dwProtocol, NULL, &dwAtrLen); + if (scReturnCode == SCARD_S_SUCCESS) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "SCardStatus() return SCARD_S_SUCCESS"); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "SCardStatus: dwState = 0x%04X - dwProtocol = 0x%04X", dwState, dwProtocol); + + cardStatus = dwState; + res = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "SCardStatus() return error 0x%08lx (%s)", + scReturnCode, _seMediaWinSCardInternalGetSCErrorDescription(scReturnCode)); + + if (scReturnCode == SCARD_W_REMOVED_CARD) + { + cardStatus = SE_MEDIA_STATUS_REMOVED_CARD; + res = true; + } + + if (scReturnCode == SCARD_W_RESET_CARD) + { + cardStatus = SE_MEDIA_RESET_CARD; + res = true; + } + } + + if (ptrStatus != NULL && res == true) + *ptrStatus = cardStatus; + } + } + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- semedia_winscard :> _seMediaWinSCardGetStatus() return res=%s", (res ? "true" : "false")); + + return res; +} + +/** + * Translate error code in user readable message. + * Error code and readable message matching are defined in _scardErrorList data defined in the beginning of "semedia_winscard.c" (So here). + * + * @param scErrorCode - Error code to translate, DWORD + * @return String containing user readable error message. + */ +char* _seMediaWinSCardInternalGetSCErrorDescription(DWORD scErrorCode) +{ + char *ptrErrorDescription = "Unknown SmartCard error code"; + SCARD_ERROR_INFO* ptrSCardErrorList = _scardErrorList; + + while( true) + { + if (ptrSCardErrorList == NULL || ptrSCardErrorList->_ptrErrorString == NULL) + break; + + if (ptrSCardErrorList->_errorValue == scErrorCode) + { + ptrErrorDescription = ptrSCardErrorList->_ptrErrorString; + break; + } + + ptrSCardErrorList++; + } + + return ptrErrorDescription; +} + +/** + * send LPA Event execution error. + * + * @param scErrorCode - Error code + * @param ptrErrorCodeDescription - String containing user readable error message + */ + +void _seMediaWinSCardInternalSendLpaEventExecutionError(long scErrorCode, const char* ptrErrorCodeDescription) +{ + // using callback to share seMedia error + if (_lpaEventExecutionErrorCallback != NULL) + { + LPA_EVENT_EXECUTION_ERROR_INFO eventExecutionErrorInfo; + char errorSubjectCode[16]; + snprintf(errorSubjectCode, sizeof(errorSubjectCode), "0x%lx", scErrorCode); + + eventExecutionErrorInfo.executionErrorType = LPA_EVENT_EXECUTION_SEMEDIA_DRIVER_ERROR_TYPE; + eventExecutionErrorInfo.detailErrorMask = LPA_EVENT_EXECUTION_ERROR_SUBJECT_CODE_MASK; + eventExecutionErrorInfo.ptrErrorReasonCode = NULL; + eventExecutionErrorInfo.ptrErrorSubjectCode = errorSubjectCode; + + if (ptrErrorCodeDescription != NULL) + { + eventExecutionErrorInfo.detailErrorMask |= LPA_EVENT_EXECUTION_ERROR_EXTRA_INFO_MASK; + eventExecutionErrorInfo.ptrErrorExtraInfo = ptrErrorCodeDescription; + } + + _lpaEventExecutionErrorCallback(NULL, &eventExecutionErrorInfo); + } +} + +/** + * Sends "open logical channel" APDU command to the module and retrieve logical channel ID in seMedia structure + * + * @param ptrTSEMedia - TSEMedia object pointer + * @return true if the command was successfully achieved. + */ +bool _seMediaWinSCardInternalOpenUICCChannel(const struct TSEMedia* ptrTSEMedia) +{ + bool res = false; + size_t commandResponseMaxSize = WC_COMMMAND_RESPONSE_SIZE_FOR_LOGICAL_CHANNEL; + unsigned char commandResponseBytes[WC_COMMMAND_RESPONSE_SIZE_FOR_LOGICAL_CHANNEL]; // To get logical channel and Status Word returned by Open Channel command, 3 shall be enough + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_seMediaWinSCardInternalOpenUICCChannel()..."); + + if (ptrTSEMedia == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaWinSCardInternalOpenUICCChannel(): ptrTSEMedia is NULL!"); + return false; + } + + TSEMediaWinSCard* ptrTSEMediaWinSCard = (TSEMediaWinSCard*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaWinSCard != NULL) + { + ptrTSEMediaWinSCard->_apduChannel = 0; + memset(commandResponseBytes, 0, WC_COMMMAND_RESPONSE_SIZE_FOR_LOGICAL_CHANNEL); + + // Send Open channel command + if(_seMediaWinSCardInternalTransmitApdu(ptrTSEMedia, WC_APDU_OPEN_SIM_CHANNEL, sizeof(WC_APDU_OPEN_SIM_CHANNEL), commandResponseBytes, &commandResponseMaxSize)) + { + // Check Open Logical Channel Status Word, 0x9000 and 0x91xx are accepted, and only if logical channel has been returned, so 3 bytes with SW + if(commandResponseMaxSize == 3 && ((commandResponseBytes[1] == 0x90 && commandResponseBytes[2] == 0x00) || commandResponseBytes[1] == 0x91)) + { + ptrTSEMediaWinSCard->_apduChannel = commandResponseBytes[0]; + + // Extended logical channels also managed (So 1 to 19 range) + if((ptrTSEMediaWinSCard->_apduChannel > 0) && (ptrTSEMediaWinSCard->_apduChannel < 20)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_seMediaWinSCardInternalOpenUICCChannel(): Logical channel #%u opened", ptrTSEMediaWinSCard->_apduChannel); + res = true; + } + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaWinSCardInternalOpenUICCChannel(): Logical channel out of bounds or incorrect: %u", ptrTSEMediaWinSCard->_apduChannel); + ptrTSEMediaWinSCard->_apduChannel = 0; + } + } + else + { + if(commandResponseMaxSize >1 && commandResponseMaxSize <4) + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaWinSCardInternalOpenUICCChannel(): Open Logical Channel returned invalid Status Word 0x%02X%02X", + commandResponseBytes[commandResponseMaxSize - 2], commandResponseBytes[commandResponseMaxSize - 1]); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaWinSCardInternalOpenUICCChannel(): Unexpected response length returned by Open Channel command: %llu", (long long unsigned)commandResponseMaxSize); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaWinSCardInternalOpenUICCChannel(): Problem while sending logical channel opening command!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaWinSCardInternalOpenUICCChannel(): ptrTSEMediaWinSCard is NULL!"); + + return res; +} + + +/** + * Sends "close logical channel" APDU command to the module. Channel to close will be current one described in TSEmedia structures + * + * @param ptrTSEMedia - TSEMedia object pointer + * @return true if the command was successfully achieved. + */ +bool _seMediaWinSCardInternalCloseUICCChannel(const struct TSEMedia* ptrTSEMedia) +{ + bool res = false; + unsigned char apduCommand[5]; + size_t commandResponseMaxSize = WC_COMMMAND_RESPONSE_SIZE_FOR_LOGICAL_CHANNEL; + unsigned char commandResponseBytes[WC_COMMMAND_RESPONSE_SIZE_FOR_LOGICAL_CHANNEL]; // To get Status Word returned by Close Channel command, 2 shall be enough + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_seMediaWinSCardInternalCloseUICCChannel()..."); + + if (ptrTSEMedia == NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaWinSCardInternalCloseUICCChannel(): ptrTSEMedia is NULL!"); + return false; + } + + TSEMediaWinSCard* ptrTSEMediaWinSCard = (TSEMediaWinSCard*)ptrTSEMedia->_childStruct; + if (ptrTSEMediaWinSCard != NULL) + { + // Check logical channel defined + if(ptrTSEMediaWinSCard->_apduChannel != 0) + { + if(ptrTSEMediaWinSCard->_apduChannel > 0 && ptrTSEMediaWinSCard->_apduChannel < 20) + { + memset(commandResponseBytes, 0, WC_COMMMAND_RESPONSE_SIZE_FOR_LOGICAL_CHANNEL); + // Considering we are using Winscard interface, there a few chances that a third party application could have reset eUICC in the meanwhile + // But if it happened there is still a risk that a third party application could have re-opened this Logical Channel for another use. + // This will be not managed in this version + + // Build APDU Command + memcpy(apduCommand, WC_APDU_CLOSE_SIM_CHANNEL_PREFIX, 3); // Prefix shall be equal to 3 bytes + apduCommand[3] = ptrTSEMediaWinSCard->_apduChannel; // Channel to close + apduCommand[4] = 0x00; // APDU length + + // Despite this is a driver internal operation, Status Word will be not checked to avoid false errors in case a third party interact with eUICC + // If an issue really occurred with Logical Channel closing, it will be detected on next operations attempts when Open will fail. + // This version will not include eventual status query from Winscard driver + if(_seMediaWinSCardInternalTransmitApdu(ptrTSEMedia, apduCommand, 5, commandResponseBytes, &commandResponseMaxSize)) + { + ptrTSEMediaWinSCard->_apduChannel = 0; + res = true; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaWinSCardInternalCloseUICCChannel(): Problem while sending logical channel closing command!"); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaWinSCardInternalCloseUICCChannel(): Invalid logical channel number: %u", ptrTSEMediaWinSCard->_apduChannel); + } + else + { + // If the logical channel has not been opened, there is no reason to exit on error + res = true; + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "_seMediaWinSCardInternalCloseUICCChannel(): No logical channel currently opened"); + } + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "_seMediaWinSCardInternalCloseUICCChannel(): ptrTSEMediaWinSCard is NULL!"); + + return res; +} + +#endif //LPA_SDK__SEMEDIA_DRIVER_WINSCARD diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/lpasdk_api.c b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/lpasdk_api.c new file mode 100755 index 000000000..a90131887 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/lpasdk_api.c @@ -0,0 +1,1000 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + + +#include "lpasdk/api/lpasdk_api.h" +#include "lpasdk/lpasdk_internal_api.h" + +#include "lpasdk/core/lpa_log.h" +#include "lpasdk/core/lpa_memory.h" + +#include "lpasdk/core/lpa_manager_api.h" // For main API +#include "lpasdk/core/lpa_manager.h" + +#include "lpasdk/core/lpa_core.h" +#include "lpasdk/core/lpa_config_file.h" + +// Since API 1.5, Extended API is always compiled +// check done on API entry point code to verify access right +#include "lpasdk/api/lpasdk_ex_api.h" + +#include "lpasdk/lpasdk_version.h" + +#include +#include +#include +#include +#include + +static bool _lpaInit = false; +static LPA_API_ERROR _errorCode = LPA_NO_ERROR; +static char _lpaLogFileName[LPA_MAX_PATH]; +static char _lpaLogBackupFileName[LPA_MAX_PATH]; +static char _lpaConfigFileName[LPA_MAX_PATH]; + +#define LPA_FUNCTION_NAME_MAX_SIZE 64 + + +/** +* \fn const LPA_API_VERSION* lpaGetApiVersion() +* \brief Managing API Versionning. +* +* \return Structure that contains all API version information (Major, Minor). +* +* Do not free this structure +*/ + +EXPORT_DLL const LPA_API_VERSION* lpaGetApiVersion() +{ + static LPA_API_VERSION _lpaApiVersion = { LPA_API_MAJOR_VERSION, LPA_API_MINOR_VERSION }; + return &_lpaApiVersion; +} + +//////////////////////////////////////////// +// Managing API function + +void _lpaBeginApiFunction(const char* ptrApiFunctionName, bool resetErrorCode); +void _lpaEndApiFunction(bool displayAPIError); + +static char _currentAPIFunctionName[LPA_FUNCTION_NAME_MAX_SIZE]; + +void _lpaBeginApiFunction(const char* ptrApiFunctionName, bool resetErrorCode) +{ + if (ptrApiFunctionName != NULL) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKAPI] <%s> started", ptrApiFunctionName); + snprintf(_currentAPIFunctionName, LPA_FUNCTION_NAME_MAX_SIZE, "%s", ptrApiFunctionName); + } + else + memset(_currentAPIFunctionName, 0x0, LPA_FUNCTION_NAME_MAX_SIZE); + + if (resetErrorCode) + lpaResetErrorCode(); +} + +void _lpaEndApiFunction(bool displayAPIError) +{ + if (strlen(_currentAPIFunctionName) > 0) + { + if (!displayAPIError || _errorCode == LPA_NO_ERROR) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKAPI] <%s> terminated", _currentAPIFunctionName); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "[LPASDKAPI] <%s> terminated (API error: 0x%lx) ", _currentAPIFunctionName, _errorCode); + } + lpaCoreLogFlush(); +} + +/** +* \fn bool lpaInitialize(const char* ptrLpaFolder) +* \brief Initialize LPA SDK module (log module, lpaManager). +* +* \param ptrLpaFolder must contain full path of LPA as a text +* +* \return false (but GetLastErrorCode() may return LPA_NO_ERROR if called), if an error occurred, otherwise return true. +* +* This function, or lpaInitializeWithInputOutputFolder() function, must be called one time before using the LPA SDK. +* SE Media and HTTP Media components are initialized by this function. +*/ + +EXPORT_DLL bool lpaInitialize(const char* ptrLpaFolder) +{ + return lpaInitializeWithInputOutputFolder(ptrLpaFolder, ptrLpaFolder); +} + +/** +* \fn bool lpaInitializeWithInputOutputFolder(const char* ptrLpaIntputFolder, const char* ptrLpaOutputFolder) +* \since API 1.6 +* \brief Initialize LPA SDK module (log module, lpaManager). +* +* \param ptrLpaIntputFolder must contain full path, as a text, of LPA Input folder (configuration file...) +* \param ptrLpaOutputFolder must contain full path, as a text, of LPA Output folder (log files) +* +* \return false (but GetLastErrorCode() return LPA_NO_ERROR is called), if an error occured, otherwise return true. +* +* This function,or lpaInitialize() function, must be called one time before using the LPA SDK. +* SE Media and HTTP Media components are initialized by this function. +*/ + +EXPORT_DLL bool lpaInitializeWithInputOutputFolder(const char* ptrLpaIntputFolder, const char* ptrLpaOutputFolder) +{ + bool res = false; + + if (!_lpaInit) + { + LPA_API_ERROR lpaErrorCode = LPA_NO_ERROR; + + memset(_lpaLogFileName, 0x00, sizeof(_lpaLogFileName)); + memset(_lpaLogBackupFileName, 0x00, sizeof(_lpaLogBackupFileName)); + memset(_lpaLogFileName, 0x00, sizeof(_lpaLogFileName)); + + + if (ptrLpaIntputFolder == NULL || strlen(ptrLpaIntputFolder) >= LPA_MAX_PATH) + lpaErrorCode = LPA_ERROR_INVALID_PARAMETER; + + if (ptrLpaOutputFolder == NULL || strlen(ptrLpaOutputFolder) >= LPA_MAX_PATH) + lpaErrorCode = LPA_ERROR_INVALID_PARAMETER; + + if (lpaErrorCode == LPA_NO_ERROR) + { +#ifdef LPA_SDK__PLATFORM_RASPBIAN + if (snprintf(_lpaLogFileName, sizeof(_lpaLogFileName), "%s//%s", ptrLpaOutputFolder, "./lpa.log") >= LPA_MAX_PATH || + snprintf(_lpaLogBackupFileName, sizeof(_lpaLogBackupFileName), "%s//%s", ptrLpaOutputFolder, "./lpa.backup.log") >= LPA_MAX_PATH) +#else + if (snprintf( _lpaLogFileName, sizeof( _lpaLogFileName), "%s//%s", ptrLpaOutputFolder, "lpa.log") >= LPA_MAX_PATH || + snprintf(_lpaLogBackupFileName, sizeof(_lpaLogBackupFileName), "%s//%s", ptrLpaOutputFolder, "lpa.backup.log") >= LPA_MAX_PATH) +#endif + lpaErrorCode = LPA_ERROR_INSUFFICIENT_BUFFER; // Note: This line is triggered by one the conditional "if(snprintf..." above + } + + if (lpaErrorCode == LPA_NO_ERROR) + { + // Initialize Memory Manager + lpaCoreMemoryInitialize(); + + // Check if LPA log already initialized (UT use case...) + bool lpaLogInitialized = lpaCoreLogIsInitialized(); + if (!lpaLogInitialized) + lpaLogInitialized = lpaCoreLogInit(); + + if (lpaLogInitialized) + { + if( !lpaCoreLogIsOpen()) + lpaCoreLogOpen(_lpaLogFileName, _lpaLogBackupFileName); + + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "---==========================---"); + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "--------------------------------"); + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "LPA Module release %u.%u.%u.%u", LPA_SDK_VERSION_MAJOR, LPA_SDK_VERSION_MINOR, LPA_SDK_VERSION_PATCH, LPA_SDK_VERSION_BUILD); + +#if LPA_SDK_VERSION_BUILD == 0 + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "LPA Module build : %s", LPA_SDK_EXTRA_VERSION ); +#endif // LPA_SDK_VERSION_BUILD + + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "LPA API : %u.%u", LPA_API_MAJOR_VERSION, LPA_API_MINOR_VERSION); + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "Build option(s):"); + +#ifdef LPA_SDK__PLATFORM_CYGWIN + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, " - LPA_SDK__PLATFORM_CYGWIN"); +#endif // LPA_SDK__PLATFORM_CYGWIN + +#ifdef LPA_SDK__PLATFORM_RASPBIAN + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, " - LPA_SDK__PLATFORM_RASPBIAN"); +#endif // LPA_SDK__PLATFORM_RASPBIAN + +#ifdef LPA_SDK__PLATFORM_WIN + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, " - LPA_SDK__PLATFORM_WIN"); +#endif // LPA_SDK__PLATFORM_WIN + +#ifdef LPA_SDK__USING_EX_API + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, " - LPA_SDK__USING_EX_API"); +#endif // LPA_SDK__USING_EX_API + +#ifdef LPA_SDK__MEMORY + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, " - LPA_SDK__MEMORY"); +#endif // LPA_SDK__MEMORY + +#ifdef LPA_SDK__MEMORY_MONITORING + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, " - LPA_SDK__MEMORY_MONITORING"); +#endif // LPA_SDK__MEMORY_MONITORING + +#ifdef LPA_SDK__UT_MODE + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, " - LPA_SDK__UT_MODE"); +#endif // LPA_SDK__UT_MODE + +#ifdef LPA_SDK__PAMPERS + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, " - LPA_SDK__PAMPERS"); +#endif // LPA_SDK__PAMPERS + +#ifdef LPA_SDK__CURL_MEMORY + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, " - LPA_SDK__CURL_MEMORY"); +#endif // LPA_SDK__CURL_MEMORY + +#ifdef LPA_SDK__CURL_MEMORY_MONITORING + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, " - LPA_SDK__CURL_MEMORY_MONITORING"); +#endif // LPA_SDK__CURL_MEMORY_MONITORING + +#ifdef LPA_SDK__SEMEDIA_DRIVER_WINSCARD + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, " - LPA_SDK__SEMEDIA_DRIVER_WINSCARD"); +#endif // LPA_SDK__SEMEDIA_DRIVER_WINSCARD + +#ifdef LPA_SDK__SEMEDIA_DRIVER_GENERIC_MODEM + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, " - LPA_SDK__SEMEDIA_DRIVER_GENERIC_MODEM"); +#endif // LPA_SDK__SEMEDIA_DRIVER_GENERIC_MODEM + +#ifdef LPA_SDK__SEMEDIA_DRIVER_EXTERNAL + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, " - LPA_SDK__SEMEDIA_DRIVER_EXTERNAL"); +#endif // LPA_SDK__SEMEDIA_DRIVER_EXTERNAL + +#ifdef LPA_SDK__NUMBER_OF_RETRY_FOR_CHAINED_GET_RESPONSE + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, " - LPA_SDK__NUMBER_OF_RETRY_FOR_CHAINED_GET_RESPONSE - Value: %d", LPA_SDK__NUMBER_OF_RETRY_FOR_CHAINED_GET_RESPONSE); +#endif // LPA_SDK__NUMBER_OF_RETRY_FOR_CHAINED_GET_RESPONSE + +#ifdef LPA_SDK__MAX_SIZE_OF_DATA_IN_STORE_DATA_APDU + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, " - LPA_SDK__MAX_SIZE_OF_DATA_IN_STORE_DATA_APDU - Value: %d", LPA_SDK__MAX_SIZE_OF_DATA_IN_STORE_DATA_APDU); +#endif // LPA_SDK__MAX_SIZE_OF_DATA_IN_STORE_DATA_APDU + +#ifdef LPA_SDK__LOG_MAX_SIZE + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, " - LPA_SDK__LOG_MAX_SIZE - Value: %ld", LPA_SDK__LOG_MAX_SIZE); +#endif // LPA_SDK__LOG_MAX_SIZE + +#ifdef GM_SERIAL_PORT_NAME + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, " - GM_SERIAL_PORT_NAME - Value: %s", GM_SERIAL_PORT_NAME); +#endif // GM_SERIAL_PORT_NAME + +#ifdef _DEBUG + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, " - _DEBUG"); +#endif // _DEBUG + + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "--------------------------------"); + } + else + lpaErrorCode = LPA_ERROR_UNABLE_TO_INIT_LOG; + } + + if (lpaErrorCode == LPA_NO_ERROR) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "------ LPA Initialize ------"); + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "LPAManager initialization..."); + + if (!lpaManagerApiInitialize(ptrLpaIntputFolder)) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Error occurred during lpaManagerInitialize() " ); + lpaErrorCode = LPA_ERROR_UNABLE_TO_INITIALIZE_LPA_MANAGER; + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "LPAManager initialization done successfully"); + } + + // Initialize SE Media component + if (lpaErrorCode == LPA_NO_ERROR) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "---- ===================== ----"); + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "Initialize SE Media ()..."); + if(!lpaManagerInitializeSEMedia()) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_ERROR, "Error occurred during SE Media initialization"); + lpaErrorCode = LPA_ERROR_SE_MEDIA_NOT_INITIALIZED; + } + } + + if (lpaErrorCode == LPA_NO_ERROR) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "---- ===================== ----"); + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "Initialize HTTP Media ()..."); + + if (!lpaManagerInitializeHttpMedia()) + lpaErrorCode = LPA_ERROR_UNABLE_TO_INITIALIZE_HTTP_MEDIA; + } + + // Load and apply configuration file + if (lpaErrorCode == LPA_NO_ERROR) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "---- ===================== ----"); + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "Manage Configuration file..."); + + if (snprintf(_lpaConfigFileName, sizeof(_lpaConfigFileName), "%s%s%s", ptrLpaIntputFolder, LPA_PATH_SEPARATOR, "lpa_config.ini") >= sizeof(_lpaConfigFileName)) + lpaErrorCode = LPA_ERROR_INSUFFICIENT_BUFFER; + else + { + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "Loading configuration file (If present)..."); + bool isConfigurationFileOpened = false; + + if (lpaConfigFileLoad(_lpaConfigFileName, &isConfigurationFileOpened)) + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "Configuration file loaded"); + else + { + if (! isConfigurationFileOpened) + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "Did not succeed to open configuration file, default configuration will be used"); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_WARNING, "Unattended error occurred while loading configuration file, default configuration will be used"); + } + } + } + + if (lpaErrorCode == LPA_NO_ERROR) + { + _lpaInit = true; + res = true; + } + else + lpaSetErrorCode(lpaErrorCode); + + // At the end of init process, activate log limitation mechanism + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "Activate log limitation mechanism..."); + lpaCoreActivateLogLimitation(true); + } + + lpaCoreLogAppend(SDK_LOG_LEVEL_INFO, "--------------------------------"); + lpaCoreLogFlush(); + return res; +} + +//////////////////////////////////////////////////// +// +//////////////////////////////////////////////////// + + +/** +* \fn bool lpaUninitialize() +* \brief Uninitialize LPA SDK module. +* +* \return false (but GetLastErrorCode() return LPA_NO_ERROR is called), if an error occured, otherwise return true. +* +* After calling this function, LPA function are unvailable until calling again lpaInitialize() function. +* If SEMedia is initialized, uninitialize it. +* If log is opened, close it. +*/ + +EXPORT_DLL bool lpaUninitialize() +{ + bool res = false; + + if (_lpaInit) + { + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "------ LPA Uninitialize ------"); + bool isError = false; + + if (lpaManagerApiSEMediaManagerIsInitialized()) + { + if (!lpaManagerApiSEMediaManagerUninitialize()) + isError = true; + } + + if (lpaManagerApiHttpMediaManagerIsInitialized()) + { + if ( !lpaManagerApiHttpMediaManagerDelete() ) + isError = true; + } + + // Closing Log + lpaCoreLogClose(); + + _lpaInit = false; + + if (!isError) + res = true; + } + + return res; +} + +/** +* \fn bool lpaIsInitialized() +* \brief Return LPA SDK module initialization status. +* +* \return true if initialized, FALSE otherwise. +* +*/ + +EXPORT_DLL bool lpaIsInitialized() +{ + return _lpaInit; +} + +void lpaResetErrorCode() +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaResetErrorCode()..."); + _errorCode = LPA_NO_ERROR; +} + +bool lpaIsError() +{ + return _errorCode != LPA_NO_ERROR; +} + +LPA_API_ERROR lpaGetErrorCodeNoClear() +{ + // Internal function that does not reset ErrorCode compared to lpaGetErrorCode() + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaGetErrorCodeNoClear(): ErrorCode=0x%06X", _errorCode); + + return _errorCode; +} + +// this function is not available from application +// only LPA SDK library (LPA Manager) could use it + +void lpaSetErrorCode(LPA_API_ERROR errorCode) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "lpaSetLastErrorCode(0x%06X)", errorCode); + + // Only first error code managed + if (_errorCode == LPA_NO_ERROR) + { + _errorCode = errorCode; + const char* ptrErrorCodeDescription = NULL; + + if (_errorCode != LPA_NO_ERROR) + ptrErrorCodeDescription = lpaGetErrorCodeDescription(_errorCode); + + if (ptrErrorCodeDescription != NULL) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_errorCode=0x%06X => %s", _errorCode, ptrErrorCodeDescription); + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "_errorCode=0x%06X", _errorCode); + } + else + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "errorCode already defined to 0x%06X (error code requested:0x%06X)", _errorCode, errorCode); +} + +// this function is not available from application +// only LPA SDK library (LPA Manager) could use it + +void lpaWriteErrorMessageOnLog(LPA_API_ERROR errorCode) +{ + if (LPA_NO_ERROR != errorCode) + { + const char* ptrErrorCodeDescription = lpaGetErrorCodeDescription(errorCode); + + if (ptrErrorCodeDescription != NULL) + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "%s (errorCode 0x%06X)", ptrErrorCodeDescription, errorCode); + } +} + +/** +* \fn LPA_API_ERROR lpaGetErrorCode() +* \brief Get LPA error. +* +* \return lPA_API_ERROR. +* +* This function is used to get LPA_API_ERROR after using a LPA function() that return a boolean type. +* Calling it reset LPA_API_ERROR to LPA_NO_ERROR. +*/ + +EXPORT_DLL LPA_API_ERROR lpaGetErrorCode() +{ + // Reset ErrorCode not requested when calling _lpaBeginApiFunction(), else error code will be lost + _lpaBeginApiFunction("lpaGetErrorCode", false); + + LPA_API_ERROR errorCode = _errorCode; + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "return _errorCode=0x%06X", _errorCode); + _errorCode = LPA_NO_ERROR; + + _lpaEndApiFunction(false); + + + return errorCode; +} + + +EXPORT_DLL bool lpaGetVersion(LPA_VERSION* ptrLpaVersion) +{ + bool res = false; + _lpaBeginApiFunction("lpaGetVersion", true); + + if (ptrLpaVersion != NULL) + { + ptrLpaVersion->major = LPA_SDK_VERSION_MAJOR; + ptrLpaVersion->minor = LPA_SDK_VERSION_MINOR; + ptrLpaVersion->patch = LPA_SDK_VERSION_PATCH; + ptrLpaVersion->build = LPA_SDK_VERSION_BUILD; + + res = true; + } + + _lpaEndApiFunction(true); + return res; +} + + + +EXPORT_DLL bool lpaSetConfigParameter(const char* ptrParameterName, LPA_PARAMETER_TYPE parameterType, const void* ptrParameterValue) +{ + bool res = false; + _lpaBeginApiFunction("lpaSetConfigParameter", true); + + res = lpaManagerApiSetConfigParameter(ptrParameterName, parameterType, ptrParameterValue, false); + + _lpaEndApiFunction(true); + return res; +} + +EXPORT_DLL bool lpaGetConfigParameter(const char* ptrParameterName, LPA_PARAMETER_TYPE parameterType, void* ptrParameterValue, size_t parameterValueMaxSize) +{ + bool res = false; + _lpaBeginApiFunction("lpaGetConfigParameter", true); + + res = lpaManagerApiGetConfigParameter(ptrParameterName, parameterType, ptrParameterValue, parameterValueMaxSize); + + _lpaEndApiFunction(true); + return res; +} + +EXPORT_DLL bool lpaIsConfigParameterExist(const char* ptrParameterName, LPA_PARAMETER_TYPE* ptrParameterType, bool* ptrIsExist) +{ + bool res = false; + _lpaBeginApiFunction("lpaIsConfigParameterExist", true); + + res = lpaManagerApiIsConfigParameterExist(ptrParameterName, ptrParameterType, ptrIsExist); + + _lpaEndApiFunction(true); + return res; +} + +/** +* \fn bool lpaGetReaderList(LPA_SE_MEDIA_READER_NAME_INFO * ptrReaderNameInfoList, size_t readerNameInfoMax, size_t* ptrCountReader) +* \brief Get list of reader available. +* +* \param ptrReaderNameInfoList pointer on LPA_SE_MEDIA_READER_NAME_INFO array +* \param readerNameInfoMax Number of LPA_SE_MEDIA_READER_NAME_INFO item +* \param ptrCountReader Number of reader detected +* +* \return true if no error detected during reader list generation otherwise return false. +* +*/ + +EXPORT_DLL bool lpaGetReaderList(LPA_SE_MEDIA_READER_NAME_INFO * ptrReaderNameInfoList, size_t readerNameInfoMax, size_t* ptrCountReader) +{ + bool res = false; + _lpaBeginApiFunction("lpaGetReaderList", true); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaGetReaderList()"); + res = lpaManagerApiGetReaderList(ptrReaderNameInfoList, readerNameInfoMax, ptrCountReader); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaGetReaderList() return %s", (res ? "true" : "false")); + + _lpaEndApiFunction(true); + return res; +} + +/** + * Perform ES10C GetProfilesInfo request and fill LPA_GET_PROFILES_INFO structure with profiles informations returned by eUICC + * @param ptrLpaGetProfilesInfo Pointer on LPA_GET_PROFILES_INFO structure to fill with profiles informations + * @return true if operation is successful + */ +EXPORT_DLL bool lpaGetProfilesInfo(LPA_GET_PROFILES_INFO* ptrGetProfilesInfo) +{ + bool res = false; + _lpaBeginApiFunction("lpaGetProfilesInfo", true); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaGetProfilesInfo()"); + res = lpaManagerApiGetProfilesInfo(ptrGetProfilesInfo); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaGetProfilesInfo() return %s", (res ? "true" : "false")); + + _lpaEndApiFunction(true); + return res; +} + +/** + * Uses ES10C GetProfilesInfo request to retrieve number of profiles available on eUICC + * @param ptrLpaGetProfilesInfo Pointer on variable were number of profile will be returned, size_t type + * @return true if operation is successful + */ +EXPORT_DLL bool lpaGetProfilesNumber(size_t * ptrNumberOfProfiles) +{ + bool res = false; + _lpaBeginApiFunction("lpaGetProfilesNumber", true); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaGetProfilesNumber()"); + res = lpaManagerApiGetProfilesNumber(ptrNumberOfProfiles); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaGetProfilesNumber() return %s", (res ? "true" : "false")); + + _lpaEndApiFunction(true); + return res; +} + +EXPORT_DLL bool lpaGetEID(LPA_GET_EID* ptrGetEID) +{ + bool res = false; + _lpaBeginApiFunction("lpaGetEID", true); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaGetEID()"); + res = lpaManagerApiGetEID(ptrGetEID); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaGetEID() return %s", (res ? "true" : "false")); + + _lpaEndApiFunction(true); + return res; +} + +EXPORT_DLL bool lpaGetEUICCInfo(LPA_GET_EUICC_INFO* ptrGetEUICCInfo) +{ + bool res = false; + _lpaBeginApiFunction("lpaGetEUICCInfo", true); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaGetEUICCInfo()"); + res = lpaManagerApiGetEUICCInfo(ptrGetEUICCInfo); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaGetEUICCInfo() return %s", (res ? "true" : "false")); + + _lpaEndApiFunction(true); + return res; +} + +EXPORT_DLL bool lpaMemoryReset(const unsigned char* memoryResetOptionParameter, const size_t memoryResetOptionSize) +{ + bool res = false; + _lpaBeginApiFunction("lpaMemoryReset", true); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaMemoryReset()"); + res = lpaManagerApiMemoryReset(memoryResetOptionParameter, memoryResetOptionSize); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaMemoryReset() return %s", (res ? "true" : "false")); + + _lpaEndApiFunction(true); + return res; +} + +EXPORT_DLL bool lpaSendPendingNotification(LPA_EventCallback* ptrLpaEventCallback, LPA_SENDING_NOTIFICATION_RESULT* ptrSendingNotificationResult) +{ + bool res = false; + _lpaBeginApiFunction("lpaSendPendingNotification", true); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaSendPendingNotification()"); + res = lpaManagerApiSendPendingNotification(ptrLpaEventCallback, ptrSendingNotificationResult); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaSendPendingNotification() return %s", (res ? "true" : "false")); + + _lpaEndApiFunction(true); + return res; +} + +EXPORT_DLL bool lpaEnableProfileByIccid(const unsigned char* ptrProfileId, size_t profileIdSize) +{ + bool res = false; + _lpaBeginApiFunction("lpaEnableProfileByIccid", true); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaEnableProfileByIccid()"); + res = lpaManagerApiEnableProfileByIccid(ptrProfileId, profileIdSize); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaEnableProfileByIccid() return %s", (res ? "true" : "false")); + + _lpaEndApiFunction(true); + return res; +} + +EXPORT_DLL bool lpaDisableProfileByIccid(const unsigned char* ptrProfileId, size_t profileIdSize) +{ + bool res = false; + _lpaBeginApiFunction("lpaDisableProfileByIccid", true); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaDisableProfileByIccid()"); + res = lpaManagerApiDisableProfileByIccid(ptrProfileId, profileIdSize); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaDisableProfileByIccid() return %s", (res ? "true" : "false")); + + _lpaEndApiFunction(true); + return res; +} + +EXPORT_DLL bool lpaDeleteProfileByIccid(const unsigned char* ptrProfileId, size_t profileIdSize) +{ + bool res = false; + _lpaBeginApiFunction("lpaDeleteProfileByIccid", true); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaDeleteProfileByIccid()"); + res = lpaManagerApiDeleteProfileByIccid(ptrProfileId, profileIdSize); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaDeleteProfileByIccid() return %s", (res ? "true" : "false")); + + _lpaEndApiFunction(true); + return res; +} + +EXPORT_DLL bool lpaDownloadProfile(const char * ptrActivationCodeStr, const LPA_EventCallback* ptrLpaEventCallback, LPA_DOWNLOAD_PROFILE_RESULT* ptrDownloadProfileResult) +{ + bool res = false; + _lpaBeginApiFunction("lpaDownloadProfile", true); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaDownloadProfile()"); + res = lpaManagerApiDownloadProfile(ptrActivationCodeStr, ptrLpaEventCallback, ptrDownloadProfileResult); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaDownloadProfile() return %s", (res ? "true" : "false")); + + _lpaEndApiFunction(true); + return res; +} + + +EXPORT_DLL bool lpaDownloadProfileWithConfirmationCode(const char * ptrActivationCodeStr, const char * ptrConfirmationCodeStr, const LPA_EventCallback* ptrLpaEventCallback, LPA_DOWNLOAD_PROFILE_RESULT* ptrDownloadProfileResult) +{ + bool res = false; + _lpaBeginApiFunction("lpaDownloadProfileWithConfirmationCode", true); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaDownloadProfileWithConfirmationCode()"); + res = lpaManagerApiDownloadProfileWithConfirmationCode(ptrActivationCodeStr, ptrConfirmationCodeStr, ptrLpaEventCallback, ptrDownloadProfileResult); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaDownloadProfileWithConfirmationCode() return %s", (res ? "true" : "false")); + + _lpaEndApiFunction(true); + return res; +} + + +EXPORT_DLL bool lpaDownloadProfileWithDefaultSMDPAddress(const LPA_EventCallback* ptrLpaEventCallback, LPA_DOWNLOAD_PROFILE_RESULT* ptrDownloadProfileResult) +{ + bool res = false; + _lpaBeginApiFunction("lpaDownloadProfileWithDefaultSMDPAddress", true); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaDownloadProfileWithDefaultSMDPAddress()"); + res = lpaManagerApiDownloadProfileWithDefaultSMDPAddress(ptrLpaEventCallback, ptrDownloadProfileResult); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaDownloadProfileWithDefaultSMDPAddress() return %s", (res ? "true" : "false")); + + _lpaEndApiFunction(true); + return res; +} + + +EXPORT_DLL bool lpaDownloadProfileWithSMDSAddress( const LPA_EventCallback* ptrLpaEventCallback, LPA_DOWNLOAD_PROFILE_RESULT* ptrDownloadProfileResult) +{ + bool res = false; + _lpaBeginApiFunction("lpaDownloadProfileWithSMDSAddress", true); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaDownloadProfileWithSMDSAddress()"); + res = lpaManagerApiDownloadProfileWithSMDSAddress( ptrLpaEventCallback, ptrDownloadProfileResult); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaDownloadProfileWithSMDSAddress() return %s", (res ? "true" : "false")); + + _lpaEndApiFunction(true); + return res; +} + + + +EXPORT_DLL bool lpaSetDefaultSMDPAddress(const char* ptrSMDPAddr) +{ + bool res = false; + _lpaBeginApiFunction("lpaSetDefaultSMDPAddress", true); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaSetDefaultSMDPAddress()"); + res = lpaManagerApiSetDefaultSMDPAddress(ptrSMDPAddr); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaSetDefaultSMDPAddress() return %s", (res ? "true" : "false")); + + _lpaEndApiFunction(true); + return res; +} + + +EXPORT_DLL bool lpaGetSMDPAddress(ADDRESS_DATA* ptrAddressData) +{ + bool res = false; + _lpaBeginApiFunction("lpaGetSMDPAddress", true); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaGetSMDPAddress()"); + res = lpaManagerApiGetSMDPAddress(ptrAddressData); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaGetSMDPAddress() return %s", (res ? "true" : "false")); + + _lpaEndApiFunction(true); + return res; +} + + +EXPORT_DLL bool lpaGetSMDSAddress(ADDRESS_DATA* ptrAddressData) +{ + bool res = false; + _lpaBeginApiFunction("lpaGetSMDSAddress", true); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaGetSMDSAddress()"); + res = lpaManagerApiGetSMDSAddress(ptrAddressData); + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaGetSMDSAddress() return %s", (res ? "true" : "false")); + + _lpaEndApiFunction(true); + return res; +} + + +/** + * Set new Nickname field in profile identified by ICCID. + * @param ptrProfileID Profile ICCI size, raw format + * @param profileIdSize Profile ICCID size, size_t + * @param ptrNickname New Nickname to set, raw hex format + * @param nickNameSize New Nickname size, size_t + * @return true is nickname change operation successful + */ +EXPORT_DLL bool lpaSetNicknameByIccid(const unsigned char* ptrProfileId, size_t profileIdSize, const unsigned char* ptrNickname, size_t nickNameSize) +{ + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaSetNicknameByIccid()"); + + _lpaBeginApiFunction("lpaSetNicknameByIccid", true); + bool res = lpaManagerApiSetNickname(ptrProfileId, profileIdSize, ptrNickname, nickNameSize); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaSetNicknameByIccid() return %s", (res ? "true" : "false")); + _lpaEndApiFunction(true); + + return res; +} + + +//////////////////////////////////////////////////////////// +// Extended API PART +//////////////////////////////////////////////////////////// + +EXPORT_DLL bool lpaExGetFullParametersList(LPA_PARAMETERS_LIST * ptrLpaParametersList) +{ + bool res = false; + _lpaBeginApiFunction("lpaExGetFullParametersList", true); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaExGetFullParametersList()"); + +#if defined(LPA_SDK__USING_EX_API) + res = lpaManagerApiGetFullParametersList(ptrLpaParametersList); +#else + lpaSetErrorCode(LPA_ERROR_EXTENDED_API_UNAVAILABLE); +#endif // LPA_SDK__USING_EX_API + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaExGetFullParametersList() return %s", (res ? "true" : "false")); + + _lpaEndApiFunction(true); + return res; +} + +EXPORT_DLL bool lpaExClearProfileNotification(uint16_t sequenceNumber) +{ + bool res = false; + _lpaBeginApiFunction("lpaExClearProfileNotification", true); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaExClearProfileNotification()"); + +#if defined(LPA_SDK__USING_EX_API) + res = lpaManagerApiClearProfileNotification(sequenceNumber); +#else + lpaSetErrorCode(LPA_ERROR_EXTENDED_API_UNAVAILABLE); +#endif // LPA_SDK__USING_EX_API + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaExClearProfileNotification() return %s", (res ? "true" : "false")); + + _lpaEndApiFunction(true); + return res; +} + +EXPORT_DLL bool lpaExGetProfileNotificationList(LPA_PROFILE_NOTIFICATION_LIST* ptrProfileNotificationList) +{ + bool res = false; + _lpaBeginApiFunction("lpaExGetProfileNotificationList", true); + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "++ lpaExGetProfileNotificationList()"); + +#if defined(LPA_SDK__USING_EX_API) + res = lpaManagerApiGetProfileNotificationList(ptrProfileNotificationList); +#else + lpaSetErrorCode(LPA_ERROR_EXTENDED_API_UNAVAILABLE); +#endif // LPA_SDK__USING_EX_API + + lpaCoreLogAppend(SDK_LOG_LEVEL_DEBUG, "-- lpaExGetProfileNotificationList() return %s", (res ? "true" : "false")); + + _lpaEndApiFunction(true); + return res; +} + +EXPORT_DLL bool lpaExCardReset() +{ + bool res = false; + _lpaBeginApiFunction("lpaExCardReset", true); + +#if defined(LPA_SDK__USING_EX_API) + res = lpaManagerApiSEMediaCardReset(); +#else + lpaSetErrorCode(LPA_ERROR_EXTENDED_API_UNAVAILABLE); +#endif // LPA_SDK__USING_EX_API + + _lpaEndApiFunction(true); + return res; +} + +EXPORT_DLL bool lpaExGetExtraVersion(char* ptrVersionBuffer, size_t versionBufferMaxSize) +{ + bool res = false; + _lpaBeginApiFunction("lpaExGetExtraVersion", true); + +#if defined(LPA_SDK__USING_EX_API) + if (ptrVersionBuffer != NULL && versionBufferMaxSize > strlen(LPA_SDK_EXTRA_VERSION)) + { + snprintf(ptrVersionBuffer, versionBufferMaxSize, "%s", LPA_SDK_EXTRA_VERSION); + res = true; + } +#else + lpaSetErrorCode(LPA_ERROR_EXTENDED_API_UNAVAILABLE); +#endif // LPA_SDK__USING_EX_API + + _lpaEndApiFunction(true); + return res; +} + +EXPORT_DLL bool lpaExWriteMemoryStatusDumpToLog() +{ + bool res = false; + _lpaBeginApiFunction("lpaExWriteMemoryStatusDumpToLog", true); + +#if defined(LPA_SDK__USING_EX_API) + #ifdef LPA_SDK__MEMORY + if (_lpaInit) + { + lpaCoreMemoryDumpStatusIntoLog(); + res = true; + } + else + lpaSetErrorCode(LPA_NOT_INITIALIZED); + #else + lpaSetErrorCode(LPA_ERROR_PARAMETER_NOT_AUTHORIZED); + #endif // LPA_SDK__MEMORY +#else + lpaSetErrorCode(LPA_ERROR_EXTENDED_API_UNAVAILABLE); +#endif // LPA_SDK__USING_EX_API + + + _lpaEndApiFunction(true); + return res; +} + +EXPORT_DLL bool lpaExGetMemoryStatus(LPA_MEMORY_STATUS* prtMemoryStatus) +{ + bool res = false; + _lpaBeginApiFunction("lpaExGetMemoryStatus", true); + +#if defined(LPA_SDK__USING_EX_API) + #ifdef LPA_SDK__MEMORY + if (_lpaInit) + { + if (prtMemoryStatus != NULL) + res = lpaCoreGetMemoryStatus(prtMemoryStatus); + else + lpaSetErrorCode(LPA_ERROR_INVALID_PARAMETER); + } + else + lpaSetErrorCode(LPA_NOT_INITIALIZED); + #else + lpaSetErrorCode(LPA_ERROR_PARAMETER_NOT_AUTHORIZED); + #endif // LPA_SDK__MEMORY +#else + lpaSetErrorCode(LPA_ERROR_EXTENDED_API_UNAVAILABLE); +#endif // LPA_SDK__USING_EX_API + + _lpaEndApiFunction(true); + return res; +} + +EXPORT_DLL bool lpaExCheckMemoryAllocated() +{ + bool res = false; + _lpaBeginApiFunction("lpaExCheckMemoryAllocated", true); + +#if defined(LPA_SDK__USING_EX_API) + #if defined(LPA_SDK__MEMORY) && defined(LPA_SDK__MEMORY_MONITORING) + if (_lpaInit) + { + lpaCoreMemoryCheckMemoryAllocated(); + res = true; + } + else + lpaSetErrorCode(LPA_NOT_INITIALIZED); + #else + lpaSetErrorCode(LPA_ERROR_PARAMETER_NOT_AUTHORIZED); + #endif // LPA_SDK__MEMORY && LPA_SDK__MEMORY_MONITORING +#else + lpaSetErrorCode(LPA_ERROR_EXTENDED_API_UNAVAILABLE); +#endif // LPA_SDK__USING_EX_API + + _lpaEndApiFunction(true); + return res; +} + + +EXPORT_DLL void lpaSetLogLevel(unsigned char logLevel) +{ + lpaCoreSetLogLevel(logLevel); +} + + diff --git a/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/lpasdk_api_error.c b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/lpasdk_api_error.c new file mode 100755 index 000000000..43c1593a3 --- /dev/null +++ b/code/application/source/sf_app/code/source/sf_lpa/LPA_SDK/src/lpasdk_api_error.c @@ -0,0 +1,203 @@ +/* +* Copyright 2018-2021 THALES group. All Rights Reserved. +* +* Project name: LPASDK. +* Platform: Windows, Linux. +* Language: C/C++ +* +* Except if otherwise stated in a NOTICE file provided by Thales together with the software, below conditions are applicable by default. +* +* This computer program includes confidential and proprietary information of Thales and is a trade secret of +* Thales. All use, disclosure, and/or reproduction is prohibited unless authorized in writing by Thales. +* +* The computer program is provided "AS IS" without warranty of any kind. Thales makes no +* warranties to any person or entity with respect to the computer program and disclaims all other warranties, +* expressed or implied. Thales expressly disclaims any implied warranty of merchantability, fitness for particular +* purpose and any warranty which may arise from course of performance, course of dealing, or usage of trade. Further +* Thales does not warrant that the computer program will meet requirements or that operation of the computer program +* will be uninterrupted or error-free. +* +*/ + + +#include "lpasdk/api/lpasdk_api.h" + +static LPA_API_ERROR_DESCRIPTION _apiErrorDescriptionList[] = +{ + { LPA_NO_ERROR, "LPA_NO_ERROR" }, + + // { LPA_ERROR_CFG_SE_MEDIA_INCORRECT_READER_NAME_SIZE, "LPA_ERROR_CFG_SE_MEDIA_INCORRECT_READER_NAME_SIZE" }, + // { LPA_ERROR_CFG_SE_MEDIA_READER_NAME_IS_NULL, "LPA_ERROR_CFG_SE_MEDIA_READER_NAME_IS_NULL" }, + { LPA_NOT_INITIALIZED, "LPA_NOT_INITIALIZED" }, + + { LPA_ERROR_INVALID_PARAMETER, "LPA_ERROR_INVALID_PARAMETER" }, + { LPA_ERROR_INSUFFICIENT_BUFFER, "LPA_ERROR_INSUFFICIENT_BUFFER" }, + { LPA_ERROR_INVALID_SW, "LPA_ERROR_INVALID_SW" }, + { LPA_ERROR_ISDR_NOT_SELECTED, "LPA_ERROR_ISDR_NOT_SELECTED" }, + { LPA_ERROR_SE_MEDIA_NOT_INITIALIZED, "LPA_ERROR_SE_MEDIA_NOT_INITIALIZED" }, + { LPA_ERROR_SE_MEDIA_CONTEXT_NOT_ESTABLISHED, "LPA_ERROR_SE_MEDIA_CONTEXT_NOT_ESTABLISHED" }, + { LPA_ERROR_SE_MEDIA_READER_CONNECTION, "LPA_ERROR_SE_MEDIA_READER_CONNECTION" }, + { LPA_ERROR_SE_MEDIA_CONTEXT_NOT_RELEASED, "LPA_ERROR_SE_MEDIA_CONTEXT_NOT_RELEASED" }, + { LPA_ERROR_SE_MEDIA_READER_NOT_DISCONNECTED, "LPA_ERROR_SE_MEDIA_READER_NOT_DISCONNECTED" }, + { LPA_ERROR_SE_MEDIA_UNABLE_TO_SELECT_ISDR, "LPA_ERROR_SE_MEDIA_UNABLE_TO_SELECT_ISDR" }, + { LPA_ERROR_INVALID_GET_PROFILES_INFO_EXCHANGE, "LPA_ERROR_INVALID_GET_PROFILES_INFO_EXCHANGE" }, + { LPA_ERROR_INVALID_GET_EID_EXCHANGE, "LPA_ERROR_INVALID_GET_EID_EXCHANGE" }, + { LPA_ERROR_INVALID_MEMORY_RESET_EXCHANGE, "LPA_ERROR_INVALID_MEMORY_RESET_EXCHANGE" }, + { LPA_ERROR_INVALID_SET_DEFAULT_SMDP_ADDRESS, "LPA_ERROR_INVALID_SET_DEFAULT_SMDP_ADDRESS" }, + { LPA_ERROR_PARAMETER_NOT_AUTHORIZED, "LPA_ERROR_PARAMETER_NOT_AUTHORIZED" }, + { LPA_ERROR_UNKNOWN_PARAMETER, "LPA_ERROR_UNKNOWN_PARAMETER" }, + { LPA_ERROR_INVALID_PARAMETER_TYPE, "LPA_ERROR_INVALID_PARAMETER_TYPE" }, + { LPA_ERROR_INCORRECT_PARAMETER_TYPE, "LPA_ERROR_INCORRECT_PARAMETER_TYPE" }, + { LPA_ERROR_PARAMETER_INTERNAL_ERROR, "LPA_ERROR_PARAMETER_INTERNAL_ERROR" }, + { LPA_ERROR_UNABLE_TO_INIT_LOG, "LPA_ERROR_UNABLE_TO_INIT_LOG" }, + { LPA_ERROR_MISSING_CONFIG_FILE, "LPA_ERROR_MISSING_CONFIG_FILE" }, + { LPA_ERROR_UNABLE_TO_LOAD_CONFIG_FILE, "LPA_ERROR_UNABLE_TO_LOAD_CONFIG_FILE" }, + { LPA_ERROR_CONFIG_FILE_MISSING_MANDATORY_KEY, "LPA_ERROR_CONFIG_FILE_MISSING_MANDATORY_KEY" }, + { LPA_ERROR_CONFIG_FILE_INCORRECT_KEY_VALUE, "LPA_ERROR_CONFIG_FILE_INCORRECT_KEY_VALUE" }, + { LPA_ERROR_UNABLE_TO_INITIALIZE_LPA_MANAGER, "LPA_ERROR_UNABLE_TO_INITIALIZE_LPA_MANAGER" }, + { LPA_ERROR_UNABLE_TO_INITIALIZE_HTTP_MEDIA , "LPA_ERROR_UNABLE_TO_INITIALIZE_HTTP_MEDIA" }, + { LPA_ERROR_EXTENDED_API_UNAVAILABLE, "LPA_ERROR_EXTENDED_API_UNAVAILABLE" }, + { LPA_ERROR_PROCESSING_ERROR, "LPA_ERROR_PROCESSING_ERROR" }, + + // Local Profile Management + { LPA_ERROR_LOCAL_PROFILE_NOT_FOUND, "LPA_ERROR_LOCAL_PROFILE_NOT_FOUND" }, + { LPA_ERROR_LOCAL_PROFILE_INCORRECT_STATE, "LPA_ERROR_LOCAL_PROFILE_INCORRECT_STATE" }, + { LPA_ERROR_LOCAL_PROFILE_CAT_BUSY, "LPA_ERROR_LOCAL_PROFILE_CAT_BUSY" }, + { LPA_ERROR_LOCAL_PROFILE_UNKNOWN_ERROR, "LPA_ERROR_LOCAL_PROFILE_UNKNOWN_ERROR" }, + { LPA_ERROR_LOCAL_PROFILE_INCORRECT_CARD_RESPONSE, "LPA_ERROR_LOCAL_PROFILE_INCORRECT_CARD_RESPONSE" }, + { LPA_ERROR_LOCAL_PROFILE_NOTHING_TO_DELETE, "LPA_ERROR_LOCAL_PROFILE_NOTHING_TO_DELETE" }, + { LPA_ERROR_LOCAL_PROFILE_UNDEFINED_ERROR, "LPA_ERROR_LOCAL_PROFILE_UNDEFINED_ERROR" }, + { LPA_ERROR_LOCAL_PROFILE_UNABLE_TO_EXTRACT_DATA, "LPA_ERROR_LOCAL_PROFILE_UNABLE_TO_EXTRACT_DATA" }, + + { LPA_ERROR_LOCAL_PROFILE_ICCID_OR_AID_NOT_FOUND, "LPA_ERROR_LOCAL_PROFILE_ICCID_OR_AID_NOT_FOUND" }, + { LPA_ERROR_LOCAL_PROFILE_NOT_IN_DISABLE_STATE, "LPA_ERROR_LOCAL_PROFILE_NOT_IN_DISABLE_STATE" }, + { LPA_ERROR_LOCAL_PROFILE_DISALLOWED_BY_POLICY, "LPA_ERROR_LOCAL_PROFILE_DISALLOWED_BY_POLICY" }, + { LPA_ERROR_LOCAL_PROFILE_WRONG_PROFILE_REENABLING, "LPA_ERROR_LOCAL_PROFILE_WRONG_PROFILE_REENABLING" }, + { LPA_ERROR_LOCAL_PROFILE_NOT_IN_ENABLE_STATE, "LPA_ERROR_LOCAL_PROFILE_NOT_IN_ENABLE_STATE" }, + + { LPA_ERROR_LOCAL_PROFILE_INVALID_DATA_EXCHANGE, "LPA_ERROR_LOCAL_PROFILE_INVALID_DATA_EXCHANGE" }, + + // Notification Management + { LPA_ERROR_NOTIFICATION_INCORRECT_CARD_RESPONSE, "LPA_ERROR_NOTIFICATION_INCORRECT_CARD_RESPONSE" }, + { LPA_ERROR_NOTIFICATION_NOTHING_TO_DELETE, "LPA_ERROR_NOTIFICATION_NOTHING_TO_DELETE" }, + { LPA_ERROR_NOTIFICATION_UNDEFINED_ERROR, "LPA_ERROR_NOTIFICATION_UNDEFINED_ERROR" }, + { LPA_ERROR_NOTIFICATION_UNKNOWN_ERROR, "LPA_ERROR_NOTIFICATION_UNKNOWN_ERROR" }, + { LPA_ERROR_NOTIFICATION_INVALID_CARD_DATA, "LPA_ERROR_NOTIFICATION_INVALID_CARD_DATA" }, + + + { LPA_ERROR_DOWNLOAD_PROFILE_PARAMETER_ERROR, "LPA_ERROR_DOWNLOAD_PROFILE_PARAMETER_ERROR" }, + { LPA_ERROR_INVALID_GET_EUICC_INFO, "LPA_ERROR_INVALID_GET_EUICC_INFO" }, + { LPA_ERROR_INVALID_GET_UICC_CHALLENGE, "LPA_ERROR_INVALID_GET_UICC_CHALLENGE" }, + { LPA_ERROR_FAILED_INITIAL_AUTHENTICATION, "LPA_ERROR_FAILED_INITIAL_AUTHENTICATION" }, + { LPA_ERROR_FAILED_AUTHENTICATE_SERVER, "LPA_ERROR_FAILED_AUTHENTICATE_SERVER" }, + { LPA_ERROR_FAILED_AUTHENTICATE_CLIENT, "LPA_ERROR_FAILED_AUTHENTICATE_CLIENT" }, + { LPA_ERROR_AUTHENTICATE_CLIENT_EXCHANGE, "LPA_ERROR_AUTHENTICATE_CLIENT_EXCHANGE" }, + { LPA_ERROR_FAILED_PREPARE_DOWNLOAD, "LPA_ERROR_FAILED_PREPARE_DOWNLOAD" }, + { LPA_ERROR_INVALID_CTX_PARAM, "LPA_ERROR_INVALID_CTX_PARAM" }, + { LPA_ERROR_INVALID_AUTHENTICATE_SERVER_RESPONSE, "LPA_ERROR_INVALID_AUTHENTICATE_SERVER_RESPONSE" }, + { LPA_ERROR_INVALID_PREPARE_DOWNLOAD_RESPONSE, "LPA_ERROR_INVALID_PREPARE_DOWNLOAD_RESPONSE" }, + { LPA_ERROR_FAILED_LOAD_BPP, "LPA_ERROR_FAILED_LOAD_BPP" }, + { LPA_ERROR_INVALID_PIR_RESPONSE, "LPA_ERROR_INVALID_PIR_RESPONSE" }, + { LPA_ERROR_CJSON_PARSE_FAILURE, "LPA_ERROR_CJSON_PARSE_FAILURE" }, + { LPA_ERROR_FAILED_INITIAL_SECURITY_CHANNEL, "LPA_ERROR_FAILED_INITIAL_SECURITY_CHANNEL" }, + { LPA_ERROR_FAILED_CONFIGURE_ISDP, "LPA_ERROR_FAILED_CONFIGURE_ISDP" }, + { LPA_ERROR_FAILED_STORE_META_DATA, "LPA_ERROR_FAILED_STORE_META_DATA" }, + { LPA_ERROR_FAILED_REPLACE_SESSION_KEY, "LPA_ERROR_FAILED_REPLACE_SESSION_KEY" }, + { LPA_ERROR_FAILED_LOAD_PROFILE_ELEMENTS, "LPA_ERROR_FAILED_LOAD_PROFILE_ELEMENTS" }, + { LPA_ERROR_FAILED_GET_BOUND_PROFILE_PACKAGE, "LPA_ERROR_FAILED_GET_BOUND_PROFILE_PACKAGE" }, + { LPA_ERROR_FAILED_SEND_NOTIFICATION_OR_NOT_GET_STATUS_CODE, "LPA_ERROR_FAILED_SEND_NOTIFICATION_OR_NOT_GET_STATUS_CODE" }, + { LPA_ERROR_FAILED_GET_DATA_FROM_ACTIVATION_CODE, "LPA_ERROR_FAILED_GET_DATA_FROM_ACTIVATION_CODE" }, + { LPA_ERROR_GET_INTERNAL_SERVER_ERROR, "LPA_ERROR_GET_INTERNAL_SERVER_ERROR" }, + { LPA_ERROR_INVALID_TRANSACTIONID, "LPA_ERROR_INVALID_TRANSACTIONID" }, + { LPA_ERROR_INVALID_SERVERSIGNED1, "LPA_ERROR_INVALID_SERVERSIGNED1" }, + { LPA_ERROR_INVALID_SERVERSIGNATURE1, "LPA_ERROR_INVALID_SERVERSIGNATURE1" }, + { LPA_ERROR_INVALID_EUICCCIPKIDTOBEUSED, "LPA_ERROR_INVALID_EUICCCIPKIDTOBEUSED" }, + { LPA_ERROR_INVALID_SERVERCERTIFICATE, "LPA_ERROR_INVALID_SERVERCERTIFICATE" }, + { LPA_ERROR_INVALID_SERVER_RESPONSE, "LPA_ERROR_INVALID_SERVER_RESPONSE" }, + { LPA_ERROR_FAILED_CANCEL_SESSION, "LPA_ERROR_FAILED_CANCEL_SESSION" }, + { LPA_ERROR_INVALID_PROFILE_METADATA, "LPA_ERROR_INVALID_PROFILE_METADATA" }, + { LPA_ERROR_INVALID_GET_RAT, "LPA_ERROR_INVALID_GET_RAT" }, + { LPA_ERROR_PPR_NOT_ALLOWED, "LPA_ERROR_PPR_NOT_ALLOWED" }, + { LPA_ERROR_DOWNLOAD_SESSION_CANCELED_BY_USER, "LPA_ERROR_DOWNLOAD_SESSION_CANCELED_BY_USER" }, + { LPA_ERROR_OID_MISMATCH, "LPA_ERROR_OID_MISMATCH" }, + { LPA_ERROR_INVALID_BPP_DATA, "LPA_ERROR_INVALID_BPP_DATA" }, + + + { LPA_ERROR_SERVER_COMMUNICATION_ISSUE,"LPA_ERROR_SERVER_COMMUNICATION_ISSUE"}, + { LPA_ERROR_INVALID_ACTIVATION_CODE,"LPA_ERROR_INVALID_ACTIVATION_CODE"}, + { LPA_ERROR_INVALID_MATCHINGID_OR_DEVICE_INFO_TLV,"LPA_ERROR_INVALID_MATCHINGID_OR_DEVICE_INFO_TLV" }, + { LPA_ERROR_INVALID_DEVICE_INFO_TLV,"LPA_ERROR_INVALID_DEVICE_INFO_TLV" }, + { LPA_ERROR_INVALID_GET_EUICC_ADDRESS,"LPA_ERROR_INVALID_GET_EUICC_ADDRESS" }, + { LPA_ERROR_INVALID_GET_SMDP_ADDRESS,"LPA_ERROR_INVALID_GET_SMDP_ADDRESS" }, + { LPA_ERROR_INVALID_SERVER_ADDRESS,"LPA_ERROR_INVALID_SERVER_ADDRESS" }, + { LPA_ERROR_INVALID_GET_SMDS_ADDRESS,"LPA_ERROR_INVALID_GET_SMDS_ADDRESS" }, + { LPA_ERROR_INVALID_EVENT_ID,"LPA_ERROR_INVALID_EVENT_ID" }, + { LPA_ERROR_INVALID_RSP_SERVER_ADDRESS,"LPA_ERROR_INVALID_RSP_SERVER_ADDRESS" }, + { LPA_ERROR_INVALID_EVENT_ENTRIES,"LPA_ERROR_INVALID_EVENT_ENTRIES" }, + { LPA_ERROR_NO_EVENT_RECORD_FOUND,"LPA_ERROR_NO_EVENT_RECORD_FOUND" }, // This error code is now obsolete since V1.6 + { LPA_ERROR_CONFIRMATION_CODE_MISSING_OR_EMPTY,"LPA_ERROR_CONFIRMATION_CODE_MISSING_OR_EMPTY" }, + { LPA_ERROR_SERVER_RETURN_404_STATUS_CODE, "LPA_ERROR_SERVER_RETURN_404_STATUS_CODE" }, + { LPA_ERROR_SERVER_RETURN_500_STATUS_CODE, "LPA_ERROR_SERVER_RETURN_500_STATUS_CODE" }, + { LPA_ERROR_SERVER_RETURN_ERROR_STATUS, "LPA_ERROR_SERVER_RETURN_ERROR_STATUS" }, + + + { SE_MEDIA_ERROR_BROKEN_PIPE, "SE_MEDIA_ERROR_BROKEN_PIPE" }, + { SE_MEDIA_E_CANCELLED, "SE_MEDIA_E_CANCELLED" }, + { SE_MEDIA_E_CANT_DISPOSE, "SE_MEDIA_E_CANT_DISPOSE" }, + { SE_MEDIA_E_CARD_UNSUPPORTED, "SE_MEDIA_E_CARD_UNSUPPORTED" }, + { SE_MEDIA_E_DUPLICATE_READER, "SE_MEDIA_E_DUPLICATE_READER" }, + { SE_MEDIA_E_FILE_NOT_FOUND, "SE_MEDIA_E_FILE_NOT_FOUND" }, + { SE_MEDIA_E_INSUFFICIENT_BUFFER, "SE_MEDIA_E_INSUFFICIENT_BUFFER" }, + { SE_MEDIA_E_INVALID_ATR, "SE_MEDIA_E_INVALID_ATR" }, + { SE_MEDIA_E_INVALID_HANDLE, "SE_MEDIA_E_INVALID_HANDLE" }, + { SE_MEDIA_E_INVALID_PARAMETER, "SE_MEDIA_E_INVALID_PARAMETER" }, + { SE_MEDIA_E_INVALID_TARGET, "SE_MEDIA_E_INVALID_TARGET" }, + { SE_MEDIA_E_INVALID_VALUE, "SE_MEDIA_E_INVALID_VALUE" }, + { SE_MEDIA_E_NO_MEMORY, "SE_MEDIA_E_NO_MEMORY" }, + { SE_MEDIA_E_NO_READERS_AVAILABLE, "SE_MEDIA_E_NO_READERS_AVAILABLE" }, + { SE_MEDIA_E_NO_SMARTCARD, "SE_MEDIA_E_NO_SMARTCARD" }, + { SE_MEDIA_E_NOT_READY, "SE_MEDIA_E_NOT_READY" }, + { SE_MEDIA_E_PROTO_MISMATCH, "SE_MEDIA_E_PROTO_MISMATCH" }, + { SE_MEDIA_E_READER_UNAVAILABLE, "SE_MEDIA_E_READER_UNAVAILABLE" }, + { SE_MEDIA_E_READER_UNSUPPORTED, "SE_MEDIA_E_READER_UNSUPPORTED" }, + { SE_MEDIA_E_SERVER_TOO_BUSY, "SE_MEDIA_E_SERVER_TOO_BUSY" }, + { SE_MEDIA_E_SERVICE_STOPPED, "SE_MEDIA_E_SERVICE_STOPPED" }, + { SE_MEDIA_E_SHARING_VIOLATION, "SE_MEDIA_E_SHARING_VIOLATION" }, + { SE_MEDIA_E_SYSTEM_CANCELLED, "SE_MEDIA_E_SYSTEM_CANCELLED" }, + { SE_MEDIA_E_TIMEOUT, "SE_MEDIA_E_TIMEOUT" }, + { SE_MEDIA_E_UNEXPECTED, "SE_MEDIA_E_UNEXPECTED" }, + { SE_MEDIA_E_UNKNOWN_CARD, "SE_MEDIA_E_UNKNOWN_CARD" }, + { SE_MEDIA_E_UNKNOWN_READER, "SE_MEDIA_E_UNKNOWN_READER" }, + { SE_MEDIA_W_REMOVED_CARD, "SE_MEDIA_W_REMOVED_CARD" }, + { SE_MEDIA_W_RESET_CARD, "SE_MEDIA_W_RESET_CARD" }, + { SE_MEDIA_W_UNSUPPORTED_CARD, "SE_MEDIA_W_UNSUPPORTED_CARD" }, + { SE_MEDIA_E_CHAINING_GET_RESPONSE, "SE_MEDIA_E_CHAINING_GET_RESPONSE" }, + + + // Latest entry + { 0, NULL} // Must be NULL +}; + +EXPORT_DLL LPA_API_ERROR_DESCRIPTION* lpaExGetListErrorCodeDescription() +{ + return _apiErrorDescriptionList; +} + +const char* lpaGetErrorCodeDescription(LPA_API_ERROR apiErrorcode) +{ + char* errorCodeDescription = "Unknown LPA API Error Code"; + size_t index = 0; + + while (_apiErrorDescriptionList[index].ptrApiErrorDescription != NULL) + { + if (_apiErrorDescriptionList[index].apiErrorCode == apiErrorcode ) + { + errorCodeDescription = _apiErrorDescriptionList[index].ptrApiErrorDescription; + break; + } + + index++; + } + + return errorCodeDescription; +} diff --git a/code/application/source/sf_app/code/source/systemMng/sf_commu_mcu_reg.c b/code/application/source/sf_app/code/source/systemMng/sf_commu_mcu_reg.c index 9e49e20ae..00c697923 100755 --- a/code/application/source/sf_app/code/source/systemMng/sf_commu_mcu_reg.c +++ b/code/application/source/sf_app/code/source/systemMng/sf_commu_mcu_reg.c @@ -343,6 +343,49 @@ unsigned char sf_mcu_analog_pir_sen_convert(unsigned char pirs) return pirlevel; } +/************************************************* + Function: sf_McuResetPir + Description: When DailyRerpot ,Reset the Pir hardware + Input: attrId:which kind of para want to get + Output: N/A + Return: N/A + Others: N/A +*************************************************/ +S32 sf_mcu_rebootall(U8 McuPoweroffVal) +{ + U8 i=0; + U8 regsize =0; + U8 Mcuset[4]; + U8 Mcupara[4]; + U8 val=0; + + + /*Parameter Setting.*/ + val = McuPoweroffVal; + val |= 0x20; + + Mcupara[i] = SYS_STATUS; + Mcuset[i++] =val; + + Mcupara[i] = DSP_WRITE_FLG; + Mcuset[i++]=1; + + regsize=i; + + for(i=0; i