/**
 * @file    bfAgentMain.c
 * @brief   WSM BF trustlet entry point
 * @author  Sergii Sidorov (s.sidorov@samsung.com)
 * @version 1.0.1
 * @date Created Oct 09, 2015 11:00 AM
 * @par In Samsung Ukraine R&D Center (SURC) under a contract between
 * @par LLC "Samsung Electronics Ukraine Company" (Kyiv, Ukraine) and "Samsung Electronics Co", Ltd (Seoul, Republic of Korea)
 * @par Copyright: (c) Samsung Electronics Co, Ltd 2015-2017. All rights reserved.
 **/

#include <tee_internal_api.h>
#include <tees_extension.h>
#include <stdio.h>

#include "bfAgentMain.h"

#include "wsm_types.h"

#include "wsm_log.h"
#include "tl_tlcApi.h"
#include "version_info.h"
#include "tl_handler.h"

#include "openssl/mem.h"

#include "tz_proca_handler.h"

#define USED_PARAM_INDEX    0

static tciMessage_t msg_buffer;

TEE_Result TA_InvokeCommandEntryPoint(void *sessionContext, uint32_t commandID,
                                      uint32_t param_types, TEE_Param param[4])
{
    (void)sessionContext;

    tciMessage_t *tciBuffer;
    uint32_t tciBufferLen = 0;
    int32_t ret_value;
    tciReturnCode_t ret_app;

    WSM_LOG_EN(LOG_TAG, "[%s] Called\n", "ta.te");

    // Parameter Type
    // (see: http://mosaic.sec.samsung.net/kms/comty.do?comtyId=3012074&menuId=3012077&postId=356019566&page=view&type=LIST)
    if (TEE_PARAM_TYPE_MEMREF_INOUT != (TEE_PARAM_TYPE_GET(param_types, USED_PARAM_INDEX)))
    {
        WSM_LOG_E(LOG_TAG, WSM_RET_E_TA_BF_WRONG_INPUT_PARAM, "[%s] Input Param Type are wrong \n",
                  __func__);
        return RET_ERR;
    }

#if (TEEGRIS_SDK_VER_MAJOR > 2)
    // TA access right on buffer
    // (see: http://mosaic.sec.samsung.net/kms/comty.do?comtyId=3012074&menuId=3012077&postId=356019566&page=view&type=LIST)
    if (TEE_SUCCESS != TEES_IsREESharedMemory(
            TEE_MEMORY_ACCESS_READ | TEE_MEMORY_ACCESS_WRITE,
            param[USED_PARAM_INDEX].memref.buffer,
            param[USED_PARAM_INDEX].memref.size))
    {
        WSM_LOG_E(LOG_TAG, WSM_RET_E_TA_BF_WRONG_INPUT_PARAM,
                  "[%s] Input TA access right on buffer wrong \n", __func__);
        return RET_ERR;
    }
#endif /* if (TEEGRIS_SDK_VER_MAJOR > 2) */

    tciBuffer = (tciMessage_t *)(param[USED_PARAM_INDEX].memref.buffer);
    tciBufferLen = param[USED_PARAM_INDEX].memref.size;

    if (NULL == tciBuffer)
    {
        WSM_LOG_E(LOG_TAG, WSM_RET_E_NULL_POINTER, "[%s] ERROR. Invalid TCI \n", __func__);
        return RET_ERR;
    }

    if (sizeof(tciMessage_t) != tciBufferLen)
    {
        WSM_LOG_E(LOG_TAG, WSM_RET_E_LENGTH_MISMATCH,
                  "[%s] ERROR. Invalid TCI buffer len, sizeof(tciMessage_t) = %zu, tciBufferLen = %d\n",
                  __func__, sizeof(tciMessage_t), tciBufferLen);
        return RET_ERR;
    }

    // Copy TCI msg from shared memory to TL memory
    TEE_MemFill(&msg_buffer, 0, sizeof(msg_buffer));
    TEE_MemMove(&msg_buffer, tciBuffer, tciBufferLen);

    do
    {
        // PROCA->check Daemon
        return_t pa_result_daemon;

        pa_result_daemon = proca_tz_auth();
        if ((WSM_RET_SUC != pa_result_daemon))
        {
            ret_value = pa_result_daemon;
            ret_app = RET_OK;
            break;
        }
        // PROCESS the command
        ret_value = TZ_COMMAND((void *)msg_buffer.msgData.buffer);
        ret_app = (ret_value == WSM_RET_SUC) ? RET_OK : RET_ERR;
    } while (0);

    msg_buffer.response.status = ret_value;
    msg_buffer.response.header.responseId = RSP_ID(commandID);
    msg_buffer.response.header.returnCode = ret_app;

    TEE_MemMove(tciBuffer, &msg_buffer, sizeof(msg_buffer));

    WSM_LOG_EN(LOG_TAG, "[%s] End\n", "ta.te");

    return (msg_buffer.response.header.returnCode == RET_OK) ? TEE_SUCCESS : TEE_ERROR_GENERIC;
}

TEE_Result TA_CreateEntryPoint(void)
{
    WSM_LOG_EN(LOG_TAG, "[%s] Create\n", "ta.te");

    return TEE_SUCCESS;
}

void TA_DestroyEntryPoint(void)
{
    WSM_LOG_EN(LOG_TAG, "[%s] Destroy\n", "ta.te");

#if defined(MALLOC_WRAPPER) && !defined(WSM_IOS)
    extern void malloc_wrapper_destructor();
    malloc_wrapper_destructor();
#endif // defined(MALLOC_WRAPPER) && !defined(WSM_IOS)
}

TEE_Result TA_OpenSessionEntryPoint(uint32_t paramTypes, TEE_Param params[4], void **sessionContext)
{
    (void)params;
    (void)paramTypes;
    (void)sessionContext;

    /* print vesrion info */
    print_version_info(MODULE_IDENTITY_TA);

    /* print trustlet name and version */
    WSM_LOG(err_level_info, LOG_TAG, "================================================\n");
    WSM_LOG(err_level_info, LOG_TAG, "  WSM trustlet version   : %s\n", VERSION_NUMBER);
    WSM_LOG(err_level_info, LOG_TAG, "  WSM trustlet stack size: 0x%x\n", TA_PROP_STACKSIZE);
    WSM_LOG(err_level_info, LOG_TAG, "================================================\n");

    return TEE_SUCCESS;
}

void TA_CloseSessionEntryPoint(void *sessionContext)
{
    (void)sessionContext;
    WSM_LOG(err_level_info, LOG_TAG, "[%s] Entry  \n", __func__);
}
