/*
 * icccOperations.c
 */

#ifdef ICCC_v4

#include <stdio.h>

#include <tee_internal_api.h>

#include "icccOperations_v4.h"
#include "iccc_tata_common.h"

#define TAG "icccOperations_v40: "

uint32_t Iccc_tata_communication(iccc_tata_message_t *sendmsg, iccc_tata_message_t *respmsg, uint32_t commandID)
{
    TEE_Result ret = ICCC_SUCCESS;
    TEE_UUID selected = ICCC_UUID;
    TEE_TASessionHandle session;
    TEE_Param params[4];
    uint32_t returnOrigin = 0;
    uint32_t requestTimeout = 300;
    uint32_t paramTypes = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, TEE_PARAM_TYPE_MEMREF_OUTPUT, TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE);
    
    printf(TAG "Start TA-to-TA communication \n");

    ret = TEE_OpenTASession(&selected, requestTimeout, 0, NULL, &session, &returnOrigin);
    printf(TAG "TEE_OpenTASession - returnOrigin = %x \n", returnOrigin);
    if (ret != TEE_SUCCESS) {
        printf(TAG "TEE_OpenTASession - Error to open Session ret = %x \n", ret);
        ret = ICCC_ERROR_SESSION_FAILED;
    } else {
        params[0].memref.buffer = sendmsg;
        params[0].memref.size = sizeof(iccc_tata_message_t);
        params[1].memref.buffer = respmsg;
        params[1].memref.size = sizeof(iccc_tata_message_t);

        ret = TEE_InvokeTACommand(session, requestTimeout, commandID, paramTypes, params, &returnOrigin);
        respmsg = params[1].memref.buffer;
        if (ret != TEE_SUCCESS) {
            printf(TAG "TEE_InvokeTACommand - Error to send TA Command ret = %x \n", ret);
            ret = ICCC_ERROR_COMMAND_FAILED;
        }

        TEE_CloseTASession(session);
        printf(TAG "TEE_CloseTASession \n");
    }

    return ret;
}

size_t get_type_size(uint32_t type)
{
    size_t type_size = 0;

    switch(type) {
        case ATN_BLOB_HASH:
            type_size = sizeof(uint32_t) * 8;
            break;
        case VERIFIEDBOOT_HASH:
            type_size = sizeof(uint32_t) * 8;
            break;
        case VERIFIEDBOOTKEY_FLAG:
            type_size = sizeof(uint32_t) * 8;
            break;
        case ROT_STRUCT:
            type_size = sizeof(rot_secure_info_t) - sizeof(secure_param_header_t);
            break;
        default:
            type_size = sizeof(uint32_t);
            break;
    }

    return type_size;
}

uint32_t Iccc_SaveData_TA(uint32_t type, uint32_t value)
{
    TEE_Result ret = ICCC_ERROR_WRITE_FAILED;
    iccc_tata_message_t* sendmsg = NULL;
    iccc_tata_message_t* respmsg = NULL;

    sendmsg = TEE_Malloc(sizeof(iccc_tata_message_t), 0);
    respmsg = TEE_Malloc(sizeof(iccc_tata_message_t), 0);
    sendmsg->payload.tata_generic.content.iccc_common_req.type = type;
    sendmsg->payload.tata_generic.content.iccc_common_req.value = value;
    //ICCC_LOG_DEBUG(TAG "Iccc_SaveData_TA : type - (%8x) \n", sendmsg->payload.tata_generic.content.iccc_common_req.type);
    //ICCC_LOG_DEBUG(TAG "Iccc_SaveData_TA : value - (%d) \n", sendmsg->payload.tata_generic.content.iccc_common_req.value);

    ret = Iccc_tata_communication(sendmsg, respmsg, CMD_ICCC_SAVEDATA_TA);
    if (ret != ICCC_ERROR_SESSION_FAILED && ret != ICCC_ERROR_COMMAND_FAILED) {
        ret = respmsg->header.status;
    }
    printf(TAG "Iccc_SaveData_TA : ret - (%d) \n", ret);

    TEE_Free(sendmsg);
    TEE_Free(respmsg);

    return ret;
}

uint32_t Iccc_ReadData_TA(uint32_t type, uint32_t *value)
{
    TEE_Result ret = ICCC_ERROR_READ_FAILED;
    iccc_tata_message_t* sendmsg = NULL;
    iccc_tata_message_t* respmsg = NULL;
    size_t size;

    sendmsg = TEE_Malloc(sizeof(iccc_tata_message_t), 0);
    respmsg = TEE_Malloc(sizeof(iccc_tata_message_t), 0);
    sendmsg->payload.tata_generic.content.iccc_common_req.type = type;
    //ICCC_LOG_DEBUG(TAG "Iccc_ReadData_TA : type - (%8x) \n", sendmsg->payload.tata_generic.content.iccc_common_req.type);

    ret = Iccc_tata_communication(sendmsg, respmsg, CMD_ICCC_READDATA_TA);
    if (ret != ICCC_ERROR_SESSION_FAILED && ret != ICCC_ERROR_COMMAND_FAILED) {
        ret = respmsg->header.status;
        //ICCC_LOG_DEBUG(TAG "Iccc_ReadData_TA : value - (%d) \n", respmsg->payload.tata_generic.content.iccc_common_rsp.value);
        size = get_type_size(type);
        TEE_MemMove(value, &respmsg->payload.tata_generic.content.iccc_common_rsp.value, size);
        //ICCC_LOG_DEBUG(TAG "Iccc_ReadData_TA : value - (%d) \n", *value);
    }

    printf(TAG "Iccc_ReadData_TA : ret - (%d) \n", ret);

    TEE_Free(sendmsg);
    TEE_Free(respmsg);

    return ret;
}

/**
  * API to check device integrity by analyzing a set of ICCC flags
  *
  * @param comp_type each component type will check a different set of ICCC flags
  * @param resp_msg_buf buffer where the result message is copied
  * @param resp_msg_buf_size the size of resp_msg_buf buffer
  * @param resp_msg_len the length of the result message that was copied to resp_msg_buf
  * @param result_code is 0 if device is secure, otherwise it is a bitwise value indicating which ICCC flags are not secure. Flag bit positions are defined in ICCC User Guide.
  * @return the operation status can be ICCC_ERROR_DEVICE_STATUS_FAILED or ICCC_SUCCESS
  *
  */
uint32_t Iccc_DeviceStatus_TA(uint32_t comp_type, uint8_t *resp_msg_buf, uint32_t resp_msg_buf_size, uint32_t *resp_msg_len, uint32_t *result_code)
{
    TEE_Result ret = ICCC_ERROR_DEVICE_STATUS_FAILED;
    iccc_tata_message_t* sendmsg = NULL;
    iccc_tata_message_t* respmsg = NULL;

    sendmsg = TEE_Malloc(sizeof(iccc_tata_message_t), 0);
    respmsg = TEE_Malloc(sizeof(iccc_tata_message_t), 0);
    sendmsg->payload.tata_status.comp_type = comp_type;
    sendmsg->payload.tata_status.resp_msg_buf_size = resp_msg_buf_size;
    //ICCC_LOG_DEBUG(TAG "Iccc_DeviceStatus_TA : comp_type - (%d) \n", sendmsg->payload.tata_status.comp_type);
    //ICCC_LOG_DEBUG(TAG "Iccc_DeviceStatus_TA : resp_msg_buf_size - (%d) \n", sendmsg->payload.tata_status.resp_msg_buf_size);

    ret = Iccc_tata_communication(sendmsg, respmsg, CMD_ICCC_DEVICE_STATUS_TA);
    if (ret != ICCC_ERROR_SESSION_FAILED && ret != ICCC_ERROR_COMMAND_FAILED) {
        ret = respmsg->header.status;
        *resp_msg_len = respmsg->payload.tata_status.resp_msg_len;
        //ICCC_LOG_DEBUG(TAG "Iccc_DeviceStatus_TA : resp_msg_len - (%d) \n", *resp_msg_len);
        *result_code = respmsg->payload.tata_status.result_code;
        //ICCC_LOG(TAG "Iccc_DeviceStatus_TA : result_code - (%d) \n", *result_code);
        TEE_MemMove(resp_msg_buf, respmsg->payload.tata_status.resp_msg_buf, *resp_msg_len);
        //ICCC_LOG_DEBUG(TAG "Iccc_DeviceStatus_TA : resp_msg_buf - (%s) \n", resp_msg_buf);
    }

    printf(TAG "Iccc_DeviceStatus_TA : ret - (%d) \n", ret);
        
    TEE_Free(sendmsg);
    TEE_Free(respmsg);

    return ret; 
}

#endif // ICCC_v4
