
/*
 * =====================================================================================
 *
 *       Filename:  ta_hdm_main.c
 *
 *    Description:  HDM main
 *
 *        Version:  1.0
 *        Created:  09/16/2019 15:26:11 PM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *        Company:  Samsung Electronics
 *        Copyright (c) 2015 by Samsung Electronics, All rights reserved.
 *
 * =====================================================================================
 */

/** Includes */
#include "ta_hdm_main.h"

/**
 * Global In/Out messages
 */
static tci_message_t rcvMsgCopy;
static tci_message_t rspMsgCopy;
static hdmMessage_t tata_sendMsgCopy;
static hdmMessage_t tata_rspMsgCopy;

//According TLC calcule size - mc_tlc_communication_private.h
//To allow CCM server and client have a consistent view, the alignment configurations should be consistent
#define MC_ALIGN_SIZE 0x40
#define MC_ALIGN_MASK (MC_ALIGN_SIZE - 1)
#define MC_ALIGN(x) \
	((x + MC_ALIGN_SIZE) & (~MC_ALIGN_MASK))

/**
 * @brief
 * TA_CreateEntryPoint
 * @return TEE_Result
 */
TEE_Result TA_CreateEntryPoint(void) {
        HDM_LOG("CreateEntryPoint for HDM\n");
        return TEE_SUCCESS;
}

/**
 * @brief
 * TA_DestroyEntryPoint
 */
void TA_DestroyEntryPoint(void) {
        HDM_LOG("DestoryEntryPoint for HDM\n");
}

/**
 * @brief
 * TA_OpenSessionEntryPoint
 * Open session
 *
 * @param[in] paramTypes     - paramTypes
 * @param[in] params[4]      - params[4]
 * @param[in] sessionContext - session context
 *
 * @return TEE_Result
 */
TEE_Result TA_OpenSessionEntryPoint(uint32_t paramTypes, TEE_Param params[4], void **sessionContext) {
        (void) paramTypes;
        (void) params;
        (void) sessionContext;

        HDM_LOG("Open session for HDM is success\n");
        return TEE_SUCCESS;
}

/**
 * @brief
 * TA_CloseSessionEntryPoint
 * Close session
 *
 * @param[in] sessionContext - session context
 */
void TA_CloseSessionEntryPoint(void *sessionContext) {
        HDM_LOG("CloseSeesionEntryPoint for HDM is success\n");
        (void) sessionContext;
}

/**
 * @brief
 * TA_InvokeCommandEntryPoint
 * Invoke command
 *
 * @param[in] sessionContext - session context
 * @param[in] commandID      - command id
 * @param[in] paramTypes     - paramTypes
 * @param[in] params[4]      - params[4]
 *
 * @return TEE_Result
 */
TEE_Result TA_InvokeCommandEntryPoint(void *sessionContext, uint32_t commandID, uint32_t paramTypes, TEE_Param params[4]) {
        TEE_Result ret = TEE_SUCCESS;
        (void) sessionContext;
        (void) paramTypes;
        (void) params;

        //HDM_LOG_DEBUG("tz buildinfo: %s %s %s \n", CONFIG_BUILD_INFO, CONFIG_TARGET_CHIPSET, CONFIG_SEC_SDK);
        HDM_LOG_DEBUG("paramTypes:%d, TEE_PARAM_TYPES:%d\n", paramTypes,
                TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, TEE_PARAM_TYPE_MEMREF_OUTPUT, TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE));

        if (paramTypes != (uint32_t)TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
                                TEE_PARAM_TYPE_MEMREF_OUTPUT, TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE)) {
                HDM_LOG("Bad Parameters in HDM invoke command \n");
                HDM_LOG("min_fixdddd : skip! \n");

                return TEE_ERROR_BAD_PARAMETERS;
        }

        TEE_Identity *clnt_id = TEE_Malloc(sizeof(TEE_Identity), 0);
        if (clnt_id == NULL) {
                HDM_LOG_DEBUG(TAG "Failed to allocate mem for TEE_Identity\n");
                return TEE_ERROR_OUT_OF_MEMORY;
        }
        
        ret = TEE_GetPropertyAsIdentity(TEE_PROPSET_CURRENT_CLIENT, "gpd.client.identity", clnt_id);
        HDM_LOG_DEBUG(TAG "login %x \n", clnt_id->login);
        if (ret != TEE_SUCCESS) {
                HDM_LOG_DEBUG(TAG "Error to get Session Identity ret=%x \n",ret);
                TEE_MemFill(clnt_id, 0, sizeof(TEE_Identity));
                TEE_Free(clnt_id);
                return ret;
        } else {
                if (clnt_id->login == TEE_LOGIN_TRUSTED_APP){
                        /* Entry if session was open from another TA */
                        // We can check TA UUID requester session
                        HDM_LOG_DEBUG(TAG "Session opened from uuid=%02x%02x%02x%02x%02x%02x%02x%02x\n", clnt_id->uuid.clockSeqAndNode[0],
                        clnt_id->uuid.clockSeqAndNode[1],
                        clnt_id->uuid.clockSeqAndNode[2],
                        clnt_id->uuid.clockSeqAndNode[3],
                        clnt_id->uuid.clockSeqAndNode[4],
                        clnt_id->uuid.clockSeqAndNode[5],
                        clnt_id->uuid.clockSeqAndNode[6],
                        clnt_id->uuid.clockSeqAndNode[7]);

                        if (params[0].memref.buffer == NULL || params[1].memref.buffer == NULL ||
                        params[0].memref.size != sizeof(hdmMessage_t) || params[1].memref.size != sizeof(hdmMessage_t)) {
                                printf(TAG "Shared memory size check error \n");
                                TEE_MemFill(clnt_id, 0, sizeof(TEE_Identity));
                                TEE_Free(clnt_id);
                                return TEE_ERROR_BAD_PARAMETERS;
                        }

                        hdmMessage_t* tata_sendmsg = NULL;
                        hdmMessage_t* tata_respmsg = NULL;

                        /* Create local copy of WSM buffer to prevent Race Condition */
                        TEE_MemFill(&tata_sendMsgCopy, 0, sizeof(hdmMessage_t));
                        TEE_MemFill(&tata_rspMsgCopy, 0, sizeof(hdmMessage_t));
                        TEE_MemMove(&tata_sendMsgCopy, params[0].memref.buffer, sizeof(hdmMessage_t));

                        tata_sendmsg = &tata_sendMsgCopy;
                        tata_respmsg = &tata_rspMsgCopy;

                        ret = process_cmd_from_ta(commandID, tata_sendmsg, tata_respmsg, &clnt_id->uuid);

                        tata_respmsg->header.id = RSP_ID(commandID);
                        tata_respmsg->header.status = ret;

                        TEE_MemMove(params[1].memref.buffer, &tata_rspMsgCopy, sizeof(hdmMessage_t));
                        TEE_MemFill(&tata_sendMsgCopy, 0, sizeof(hdmMessage_t));
                        TEE_MemFill(&tata_rspMsgCopy, 0, sizeof(hdmMessage_t));

                } else { // TEE_LOGIN_PUBLIC
                        /* Entry if session was open from NW */
                        /* param[0]: INOUT */
                        if (TEES_IsREESharedMemory (TEE_MEMORY_ACCESS_READ | TEE_MEMORY_ACCESS_WRITE,
                                        params[0].memref.buffer, params[0].memref.size) != TEE_SUCCESS) {
                                HDM_LOG("Memory access check error\n");
                                TEE_Free(clnt_id);
                                return TEE_ERROR_ACCESS_DENIED;
                        }

                        /* param[1]: OUTPUT */
                        if (TEES_IsREESharedMemory (TEE_MEMORY_ACCESS_READ | TEE_MEMORY_ACCESS_WRITE,
                                        params[1].memref.buffer, params[1].memref.size) != TEE_SUCCESS) {
                                HDM_LOG("Memory access check error\n");
                                TEE_Free(clnt_id);
                                return TEE_ERROR_ACCESS_DENIED;
                        }

                        HDM_LOG("InvokeCommandEntryPoint for HDM is success\n");
                        if (params[0].memref.buffer == NULL) {
                                HDM_LOG("inBuffer is null");
                                TEE_Free(clnt_id);
                                return TEE_ERROR_BAD_PARAMETERS;
                        }
                        if (params[0].memref.size != MC_ALIGN(sizeof(tci_message_t))) {
                                HDM_LOG("inBuffer has invalid size");
                                HDM_LOG_DEBUG("inBuffer has invalid size paramSize=%d sizeof=%ld\n", params[0].memref.size, sizeof(tci_message_t));
                                TEE_Free(clnt_id);
                                return TEE_ERROR_BAD_PARAMETERS;
                        }
                        if (params[1].memref.buffer == NULL) {
                                HDM_LOG("outBuffer is null");
                                TEE_Free(clnt_id);
                                return TEE_ERROR_BAD_PARAMETERS;
                        }
                        if (params[1].memref.size != MC_ALIGN(sizeof(tci_message_t))) {
                                HDM_LOG("outBuffer has invalid size");
                                HDM_LOG_DEBUG("outBuffer has invalid size paramSize=%d sizeof=%ld\n", params[1].memref.size, sizeof(tci_message_t));
                                TEE_Free(clnt_id);
                                return TEE_ERROR_BAD_PARAMETERS;
                        }

                        tci_message_t* rcvMsg = NULL;
                        tci_message_t* respmsg = NULL;

                        /* Create local copy of WSM buffer to prevent Race Condition */
                        TEE_MemFill(&rcvMsgCopy, 0, sizeof(tci_message_t));
                        TEE_MemFill(&rspMsgCopy, 0, sizeof(tci_message_t));
                        TEE_MemMove(&rcvMsgCopy, params[0].memref.buffer, sizeof(tci_message_t));

                        rcvMsg = &rcvMsgCopy;
                        respmsg = &rspMsgCopy;

                        ret = process_cmd(commandID, rcvMsg, respmsg);

                        respmsg->header.id = RSP_ID(commandID);
                        respmsg->header.status = ret;
                        if (commandID != CMD_APPLY_POLICY) {
                                switch(device_status) {
                                        case HDM_DEVICE_OK:
                                                respmsg->jws_message.policy_value = payload.device_block;
                                                break;
                                        case HDM_DEVICE_COMPROMISED:
                                                respmsg->jws_message.policy_value = payload.compromise_block;
                                                break;
                                        case HDM_APPLY_DEFAULT_POLICY:
                                        default:
                                                respmsg->jws_message.policy_value = HDM_DEFAULT_POLICY;
                                                break;
                                }
                        }

                        HDM_LOG_DEBUG("ta_hdm_main() Policy value = %d", respmsg->jws_message.policy_value);

                        //TODO: Implement ACK to send to server
                        //generate_signature(respmsg->jws_message.data, respmsg->jws_message.len, &drk_values.drk_rsa_private_key);

                        TEE_MemMove(params[1].memref.buffer, &rspMsgCopy, sizeof(tci_message_t));
                }
        }

        TEE_MemFill(&rcvMsgCopy, 0, sizeof(tci_message_t));
        TEE_MemFill(&rspMsgCopy, 0, sizeof(tci_message_t));
        TEE_Free(clnt_id);

        return TEE_SUCCESS;
}
