/**
 * Copyright (C) 2011 Samsung Electronics Co., Ltd. All rights reserved.
 *
 * Mobile Communication Division,
 * Digital Media & Communications Business, Samsung Electronics Co., Ltd.
 *
 * This software and its documentation are confidential and proprietary
 * information of Samsung Electronics Co., Ltd.  No part of the software and
 * documents may be copied, reproduced, transmitted, translated, or reduced to
 * any electronic medium or machine-readable form without the prior written
 * consent of Samsung Electronics.
 *
 * Samsung Electronics makes no representations with respect to the contents,
 * and assumes no responsibility for any errors that might appear in the
 * software and documents. This publication and the contents hereof are subject
 * to change without notice.
 *
 */

/**
 * @file tz_hdcp2_transmitter.c
 * @author
 * @date
 * @brief This file contains definition of all the functions used in transmitter in SWD side
 */

#include <stdlib.h>
#include <stdarg.h>
#include <time.h>
#include "tz_hdcp2_crypto.h"
#include "tlapi_secdrv.h"
#include "secdrv_hw_hal.h"
#include "fcdrv_hw_hal.h"
#include "tlapi_fcdrv.h"
#include "TlApi/TlApi.h"

#ifndef USE_HDCP2FLAG
#include "hdcp_flag.h"
#endif /* USE_HDCP2FLAG */

#ifdef USE_MTK
#include "MTK/drSecMemApi.h"
#endif /* USE_MTK */

/**
 * @def NULL_ERR(x,y)
 * This macro is assigned a value of
 * if(!x)return(y);
 * to be maintained everywhere.
 */
#define NULL_ERR(x,y)	if(!x)return(y);
#define SHA256_CALCULATION(x, y, z)	if(TZ_SHA256(x,y,z) < 0) return(HDCP2_ERR_CRYPTO);

static TZ_HDCP2_CTX hdcp2_ctx;
static HDCP2_KEY hdcp2_key;

#define HDCP2_MESSAGE_DIGEST_SIZE	32

// This is published DCP-LLC Transmitter public key .
// refer spec HDCP 2.1 specification section 2.1 ( Table 2.1)
char test_certid_r1[5] = {0x74, 0x5B, 0xB8, 0xBD, 0x04};
char test_certid_r2[5] = {0x8B, 0xA4, 0x47, 0x42, 0xFB};

// This is Test Key published by DCP-LLC Lab .
char mod_buf_test[384] = {
	0xA2,0xC7,0x55,0x57,0x54,0xCB,0xAA,0xA7,0x7A,
	0x27,0x92,0xC3,0x1A,0x6D,0xC2,0x31,0xCF,0x12,
	0xC2,0x24,0xBF,0x89,0x72,0x46,0xA4,0x8D,0x20,
	0x83,0xB2,0xDD,0x04,0xDA,0x7E,0x01,0xA9,0x19,
	0xEF,0x7E,0x8C,0x47,0x54,0xC8,0x59,0x72,0x5C,
	0x89,0x60,0x62,0x9F,0x39,0xD0,0xE4,0x80,0xCA,
	0xA8,0xD4,0x1E,0x91,0xE3,0x0E,0x2C,0x77,0x55,
	0x6D,0x58,0xA8,0x9E,0x3E,0xF2,0xDA,0x78,0x3E,
	0xBA,0xD1,0x05,0x37,0x07,0xF2,0x88,0x74,0x0C,
	0xBC,0xFB,0x68,0xA4,0x7A,0x27,0xAD,0x63,0xA5,
	0x1F,0x67,0xF1,0x45,0x85,0x16,0x49,0x8A,0xE6,
	0x34,0x1C,0x6E,0x80,0xF5,0xFF,0x13,0x72,0x85,
	0x5D,0xC1,0xDE,0x5F,0x01,0x86,0x55,0x86,0x71,
	0xE8,0x10,0x33,0x14,0x70,0x2A,0x5F,0x15,0x7B,
	0x5C,0x65,0x3C,0x46,0x3A,0x17,0x79,0xED,0x54,
	0x6A,0xA6,0xC9,0xDF,0xEB,0x2A,0x81,0x2A,0x80,
	0x2A,0x46,0xA2,0x06,0xDB,0xFD,0xD5,0xF3,0xCF,
	0x74,0xBB,0x66,0x56,0x48,0xD7,0x7C,0x6A,0x03,
	0x14,0x1E,0x55,0x56,0xE4,0xB6,0xFA,0x38,0x2B,
	0x5D,0xFB,0x87,0x9F,0x9E,0x78,0x21,0x87,0xC0,
	0x0C,0x63,0x3E,0x8D,0x0F,0xE2,0xA7,0x19,0x10,
	0x9B,0x15,0xE1,0x11,0x87,0x49,0x33,0x49,0xB8,
	0x66,0x32,0x28,0x7C,0x87,0xF5,0xD2,0x2E,0xC5,
	0xF3,0x66,0x2F,0x79,0xEF,0x40,0x5A,0xD4,0x14,
	0x85,0x74,0x5F,0x06,0x43,0x50,0xCD,0xDE,0x84,
	0xE7,0x3C,0x7D,0x8E,0x8A,0x49,0xCC,0x5A,0xCF,
	0x73,0xA1,0x8A,0x13,0xFF,0x37,0x13,0x3D,0xAD,
	0x57,0xD8,0x51,0x22,0xD6,0x32,0x1F,0xC0,0x68,
	0x4C,0xA0,0x5B,0xDD,0x5F,0x78,0xC8,0x9F,0x2D,
	0x3A,0xA2,0xB8,0x1E,0x4A,0xE4,0x08,0x55,0x64,
	0x05,0xE6,0x94,0xFB,0xEB,0x03,0x6A,0x0A,0xBE,
	0x83,0x18,0x94,0xD4,0xB6,0xC3,0xF2,0x58,0x9C,
	0x7A,0x24,0xDD,0xD1,0x3A,0xB7,0x3A,0xB0,0xBB,
	0xE5,0xD1,0x28,0xAB,0xAD,0x24,0x54,0x72,0x0E,
	0x76,0xD2,0x89,0x32,0xEA,0x46,0xD3,0x78,0xD0,
	0xA9,0x67,0x78,0xC1,0x2D,0x18,0xB0,0x33,0xDE,
	0xDB,0x27,0xCC,0xB0,0x7C,0xC9,0xA4,0xBD,0xDF,
	0x2B,0x64,0x10,0x32,0x44,0x06,0x81,0x21,0xB3,
	0xBA,0xCF,0x33,0x85,0x49,0x1E,0x86,0x4C,0xBD,
	0xF2,0x3D,0x34,0xEF,0xD6,0x23,0x7A,0x9F,0x2C,
	0xDA,0x84,0xF0,0x83,0x83,0x71,0x7D,0xDA,0x6E,
	0x44,0x96,0xCD,0x1D,0x05,0xDE,0x30,0xF6,0x1E,
	0x2F,0x9C,0x99,0x9C,0x60,0x07
};

// This is published DCP-LLC Transmitter public key .
// refer spec HDCP 2.1 specification section 2.1 ( Table 2.1)
char mod_buf[384] = {
	0xB0,0xE9,0xAA,0x45,0xF1,0x29,0xBA,0x0A,0x1C,0xBE,0x17,0x57,0x28,0xEB,0x2B,0x4E,
	0x8F,0xD0,0xC0,0x6A,0xAD,0x79,0x98,0x0F,0x8D,0x43,0x8D,0x47,0x04,0xB8,0x2B,0xF4,
	0x15,0x21,0x56,0x19,0x01,0x40,0x01,0x3B,0xD0,0x91,0x90,0x62,0x9E,0x89,0xC2,0x27,
	0x8E,0xCF,0xB6,0xDB,0xCE,0x3F,0x72,0x10,0x50,0x93,0x8C,0x23,0x29,0x83,0x7B,0x80,
	0x64,0xA7,0x59,0xE8,0x61,0x67,0x4C,0xBC,0xD8,0x58,0xB8,0xF1,0xD4,0xF8,0x2C,0x37,
	0x98,0x16,0x26,0x0E,0x4E,0xF9,0x4E,0xEE,0x24,0xDE,0xCC,0xD1,0x4B,0x4B,0xC5,0x06,
	0x7A,0xFB,0x49,0x65,0xE6,0xC0,0x00,0x83,0x48,0x1E,0x8E,0x42,0x2A,0x53,0xA0,0xF5,
	0x37,0x29,0x2B,0x5A,0xF9,0x73,0xC5,0x9A,0xA1,0xB5,0xB5,0x74,0x7C,0x06,0xDC,0x7B,
	0x7C,0xDC,0x6C,0x6E,0x82,0x6B,0x49,0x88,0xD4,0x1B,0x25,0xE0,0xEE,0xD1,0x79,0xBD,
	0x39,0x85,0xFA,0x4F,0x25,0xEC,0x70,0x19,0x23,0xC1,0xB9,0xA6,0xD9,0x7E,0x3E,0xDA,
	0x48,0xA9,0x58,0xE3,0x18,0x14,0x1E,0x9F,0x30,0x7F,0x4C,0xA8,0xAE,0x53,0x22,0x66,
	0x2B,0xBE,0x24,0xCB,0x47,0x66,0xFC,0x83,0xCF,0x5C,0x2D,0x1E,0x3A,0xAB,0xAB,0x06,
	0xBE,0x05,0xAA,0x1A,0x9B,0x2D,0xB7,0xA6,0x54,0xF3,0x63,0x2B,0x97,0xBF,0x93,0xBE,
	0xC1,0xAF,0x21,0x39,0x49,0x0C,0xE9,0x31,0x90,0xCC,0xC2,0xBB,0x3C,0x02,0xC4,0xE2,
	0xBD,0xBD,0x2F,0x84,0x63,0x9B,0xD2,0xDD,0x78,0x3E,0x90,0xC6,0xC5,0xAC,0x16,0x77,
	0x2E,0x69,0x6C,0x77,0xFD,0xED,0x8A,0x4D,0x6A,0x8C,0xA3,0xA9,0x25,0x6C,0x21,0xFD,
	0xB2,0x94,0x0C,0x84,0xAA,0x07,0x29,0x26,0x46,0xF7,0x9B,0x3A,0x19,0x87,0xE0,0x9F,
	0xEB,0x30,0xA8,0xF5,0x64,0xEB,0x07,0xF1,0xE9,0xDB,0xF9,0xAF,0x2C,0x8B,0x69,0x7E,
	0x2E,0x67,0x39,0x3F,0xF3,0xA6,0xE5,0xCD,0xDA,0x24,0x9B,0xA2,0x78,0x72,0xF0,0xA2,
	0x27,0xC3,0xE0,0x25,0xB4,0xA1,0x04,0x6A,0x59,0x80,0x27,0xB5,0xDA,0xB4,0xB4,0x53,
	0x97,0x3B,0x28,0x99,0xAC,0xF4,0x96,0x27,0x0F,0x7F,0x30,0x0C,0x4A,0xAF,0xCB,0x9E,
	0xD8,0x71,0x28,0x24,0x3E,0xBC,0x35,0x15,0xBE,0x13,0xEB,0xAF,0x43,0x01,0xBD,0x61,
	0x24,0x54,0x34,0x9F,0x73,0x3E,0xB5,0x10,0x9F,0xC9,0xFC,0x80,0xE8,0x4D,0xE3,0x32,
	0x96,0x8F,0x88,0x10,0x23,0x25,0xF3,0xD3,0x3E,0x6E,0x6D,0xBB,0xDC,0x29,0x66,0xEB
};

char exp_buf[] = {0x03, };

/**
 * @def SIZE_OF_DCPLLC_SIGNATURE
 * This macro is assigned a value of 384 to be maintained everywhere.
 */
#define SIZE_OF_DCPLLC_SIGNATURE	384

/**
 * @def SIZE_OF_PUBLIC_KEY_CERTIFICATE_OF_HDCP_RECEIVER
 * This macro is assigned a value of 522 to be maintained everywhere.
 */
#define SIZE_OF_PUBLIC_KEY_CERTIFICATE_OF_HDCP_RECEIVER	522

/**
 * @def SIZE_OF_DCP_PUBLICKEY_MODULUS
 * This macro is assigned a value of 384 to be maintained everywhere.
 */
#define SIZE_OF_DCP_PUBLICKEY_MODULUS	384

/**
 * @def SIZE_OF_DCP_PUBLICKEY_EXPONENT
 * This macro is assigned a value of 1 to be maintained everywhere.
 */
#define SIZE_OF_DCP_PUBLICKEY_EXPONENT	1

/**
 * @fn int TZ_AKE_Reset_T()
 * @brief This function resets the HDCP context
 * @return int - HDCP2_OK
 */
int TZ_AKE_Reset_T()
{
	memset(&hdcp2_ctx, 0, sizeof(TZ_HDCP2_CTX));
	return HDCP2_OK;
}

/**
 * @fn int TZ_AKE_SET_PAIRING_INFO_T(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size)
 * @brief This function receives the pairing info from receiver
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request containing the HDCP2_PAIRING_INFO message
 * @param req_size - size of request
 * @param response- pointer to response
 * @param req_size - size of response
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_AKE_SET_PAIRING_INFO_T(const u8 command, u8 *request, const u32 req_size,
			u8 *response, u32 *res_size)
{
	HDCP2_PAIRING_INFO *pair_info = (HDCP2_PAIRING_INFO *) request;
	int length = MC_SO_SIZE(0, sizeof(HDCP2_PAIRING_INFO) - sizeof(pair_info->padding));

	if (req_size != sizeof(HDCP2_PAIRING_INFO)) {
		LOGE("invalid msg size [%d]\n", req_size);
		return HDCP2_ERR_INVALID_INPUT;
	}

	NULL_ERR(pair_info, HDCP2_TZ_NULL_REQUEST);
	memcpy((u8 *) &hdcp2_ctx.pairing_info, pair_info,
			sizeof(HDCP2_PAIRING_INFO));

	// decrypt pairing info
	TZ_Unwrap((u8 *) pair_info, sizeof(HDCP2_PAIRING_INFO),
			(u8 *) &hdcp2_ctx.pairing_info, &length);

	hdcp2_ctx.is_paired = 1;

	TZ_LOG_HEX("Pairing Info", (u8 *) &hdcp2_ctx.pairing_info, sizeof(HDCP2_PAIRING_INFO));

	return HDCP2_OK;
}

/**
 * @fn int TZ_HDCP2_LOADKEY_T(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function loads the key provisioning key
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request
 * @param req_size - size of request
 * @param response- pointer to response
 * @param req_size - size of response
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_HDCP2_LOADKEY_T(const uint8_t command, uint8_t *request,
			const u32 req_size, uint8_t *response, uint32_t *res_size)
{
	if (req_size != WRAPPED_KEY_SIZE) {
		LOGE("invalid wrapped key size [%d]\n", req_size);
		return HDCP2_ERR_INVALID_INPUT;
	}

	return TZ_HDCP2_LOADKEY(request, &hdcp2_key);
}

/**
 * int TZ_HW_Get_Oem_Flag()
 * @brief This function performs the integrity check
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_HW_Get_Oem_Flag()
{
	u32 value = 0;
	tlApiResult_t ret_dr;
	u32 index = 3;
#ifdef USE_MTK
	ret_dr = tlApiAtfSecGetOemFlag(index, &value);
#else
	ret_dr = tlApiFcSecGetOemFlag(index, &value);
#endif /* USE_MTK */
	if (ret_dr != TLAPI_OK) {
		LOGE("sec_get_oem_flag error. [return value] = %d\n", ret_dr);
		return HDCP2_ERR_GET_OEM_FLAG;
	}

	// Integrity Check Failed State
#ifndef DEBUG
	if (value)
		return HDCP2_ERR_INTEGRITY;
	else
#endif /* DEBUG */
	return HDCP2_OK;
}

/**
 * @fn int TZ_HW_Init_T(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function gets crypto device lock, initializes the secure memory,performs the integrity check and sets the hdcp2 flag by initializing the trustzone
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request containing SECMEM_INIT_CMD message
 * @param req_size - size of request
 * @param response- pointer to response
 * @param req_size - size of response
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_HW_Init_T(const u8 command, u8 *request, const u32 req_size,
			u8 *response, u32 *res_size)
{
#ifdef USE_MTK
	LOGI("This is MTK!!\n");

	return HDCP2_OK;
#else
	tlApiResult_t ret_dr;
	SECMEM_INIT_CMD *cmd = (SECMEM_INIT_CMD *) request;

	*res_size = 0;

	LOGI("TZ_HW_Init_R\n");

	if (request == NULL)
		return HDCP2_ERR_INVALID_INPUT;

	if (req_size != sizeof(SECMEM_INIT_CMD)) {
		LOGE("invalid msg size [%d]\n", req_size);
		return HDCP2_ERR_INVALID_INPUT;
	}

	if (TZ_HW_Get_Oem_Flag() != HDCP2_OK)
		return HDCP2_ERR_INTEGRITY;

	LOGD("cmd->chunk_num = %d\n", cmd->chunk_num);
	ret_dr = tlApiSecInitialization((struct secMem_t *)cmd->secmem, cmd->chunk_num);
	if (ret_dr != TLAPI_OK) {
		LOGE("Sec Initialization error. [return value] = %d\n", ret_dr);
		return HDCP2_ERR_HW_INIT;
	}

#ifdef WITHOUT_KEYMANDRV
	ret_dr = tlApiSecSssInit();
	if (ret_dr != TLAPI_OK) {
		LOGE("Sec H/W attach error. [return value] = %d\n", ret_dr);
		return HDCP2_ERR_HW_ATTACH_CRYPTO;
	}
#endif /* WITHOUT_KEYMANDRV */

#ifdef USE_HDCP2FLAG
	ret_dr = tlApiSecSetHdcp2Flag(0x04);
	if (ret_dr != TLAPI_OK) {
		LOGE("Sec tlApiSecSetHdcp2Flag error. [return value] = %d\n", ret_dr);
		return HDCP2_ERR_SET_HDCP2_FLAG;
	}
#endif /* USE_HDCP2FLAG */

	return HDCP2_OK;
#endif /* USE_MTK */
}

/**
 * @fn int TZ_HW_Close_T(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function closes the trustzone, releases the secure memory and  the crypto device lock
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request
 * @param req_size - size of request
 * @param response- pointer to response
 * @param req_size - size of response
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_HW_Close_T(const u8 command, u8 *request, const u32 req_size,
			u8 *response, u32 *res_size)
{
#ifdef USE_MTK
	LOGI("This is MTK!!\n");

	return 0;
#else
	tlApiResult_t ret_dr;

#ifdef USE_HDCP2FLAG
	ret_dr = tlApiSecSetHdcp2Flag(0);
#else
	ret_dr = SET_WIDI_CUR_STATUS(HDCP_NO_CONNECTION);
#endif /* USE_HDCP2FLAG */

	if (ret_dr != TLAPI_OK) {
		LOGE("Sec tlApiSecSetHdcpFlag error. [return value] = %d\n", ret_dr);
		return HDCP2_ERR_SET_HDCP2_FLAG;
	}

#ifdef WITHOUT_KEYMANDRV
	ret_dr = tlApiSecSssExit();
	if (ret_dr != TLAPI_OK) {
		LOGE("Sec H/W detach error. [return value] = %d\n", ret_dr);
		return HDCP2_ERR_HW_DETTACH_CRYPTO;
	}
#endif /* WITHOUT_KEYMANDRV */

	ret_dr = tlApiSecFinalization();
	if (ret_dr != TLAPI_OK) {
		LOGE("Sec Finalization error. [return value] = %d\n", ret_dr);
		return HDCP2_ERR_HW_TERMINATE;
	}

	*res_size = 0;

	// Free hdcp2_ctx & hdcp2_key
	memset(&hdcp2_ctx, 0, sizeof(hdcp2_ctx));
	memset(&hdcp2_key, 0, sizeof(hdcp2_key));
	return HDCP2_OK;
#endif /* USE_MTK */
}

/**
 * @fn int TZ_SET_HDCP_VERSION_T(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function sets the hdcp version.
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request
 * @param req_size - size of request
 * @param response- pointer to response
 * @param req_size - size of response
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_SET_HDCP_VERSION_T(const u8 command, u8 *request, u32 req_size,
			u8 *response, u32 *res_size)
{
	NULL_ERR(request, HDCP2_TZ_NULL_REQUEST);
	if (req_size != 2 /* hdcp_version */) {
		LOGE("TZ_SET_HDCP_VERSION_T: Error, Invalid Req size (%d)\n", req_size);
		return HDCP2_ERR_INVALID_INPUT;
	}

	hdcp2_ctx.version = request[1];
	LOGI("TZ_SET_HDCP_VERSION_T : HDCP %d.%d version is setuped \n", hdcp2_ctx.version / 10, hdcp2_ctx.version % 10);

	return HDCP2_OK;
}

/**
 * @fn int TZ_AKE_Init_T(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function initiates the authentication from transmitter by sending the initiation message which contains 64 bit pseudo random value
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request
 * @param req_size - size of request
 * @param response- pointer to response containing AKE_INIT message
 * @param req_size - size of response
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_AKE_Init_T(const u8 command, u8 *request, const u32 req_size,
			u8 *response, u32 *res_size)
{
	AKE_INIT *tx_payload = (AKE_INIT *) response;

	*res_size = sizeof(AKE_INIT);
	NULL_ERR(tx_payload, HDCP2_TZ_NULL_RESPONSE);

	// check integrity
	if (TZ_HW_Get_Oem_Flag() != HDCP2_OK)
		return HDCP2_ERR_INTEGRITY;

	TZ_AKE_Reset_T();
	tx_payload->msg_id = command;

	// generate a random
	if (TZ_rand(hdcp2_ctx.rtx, sizeof(hdcp2_ctx.rtx)) != sizeof(hdcp2_ctx.rtx))
		return HDCP2_ERR_CRYPTO;

	// make payload
	memcpy(tx_payload->rtx, hdcp2_ctx.rtx, sizeof(hdcp2_ctx.rtx));

	return HDCP2_OK;
}

/**
 * @fn int TZ_AKE_Transmitter_Info_T(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function sends the transmitter info to the receiver
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request
 * @param req_size - size of request
 * @param response- pointer to response containing AKE_TRANSMITTER_INFO message
 * @param req_size - size of response
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_AKE_Transmitter_Info_T(const u8 command, u8 *request, const u32 req_size,
			u8 *response, u32 *res_size)
{
	AKE_TRANSMITTER_INFO *tx_payload = (AKE_TRANSMITTER_INFO *) response;
	u8 disable_precompute = 0;

	NULL_ERR(request, HDCP2_TZ_NULL_REQUEST);
	if (req_size != 2 /* Precompute_check */) {
		LOGE("TZ_AKE_Transmitter_Info_T: Error, Invalid Req size (%d)\n", req_size);
		return HDCP2_ERR_INVALID_INPUT;
	}

	disable_precompute = request[1];

	*res_size = sizeof(AKE_TRANSMITTER_INFO);
	NULL_ERR(tx_payload, HDCP2_TZ_NULL_RESPONSE);

	tx_payload->msg_id = command;
	// length is always six bytes
	tx_payload->LENGTH[0] = 0x00;
	tx_payload->LENGTH[1] = 0x06;
	// transmitter's version is 0x01, pp.63
	tx_payload->VERSION = 0x01;
	tx_payload->TRANSMITTER_CAPABILITY_MASK[0] = 0;
	tx_payload->TRANSMITTER_CAPABILITY_MASK[1] = 0x00;

	/* TRANSMITTER_CAPABILITY_MASK[1] is 0x01 enabling precomputation of L
		TRANSMITTER_LOCALITY_PRECOMPUTE_SUPPORT is bit0 set to value 1*/
	if (disable_precompute == 0) {
		tx_payload->TRANSMITTER_CAPABILITY_MASK[1] |= LOCALITY_PRECOMPUTE_SUPPORT;
	}

	if (hdcp2_ctx.version >= HDCP2_VERSION_2_2) {
		tx_payload->VERSION = hdcp2_ctx.version - HDCP2_VERSION_2_0;
		/* Set content stream bit only if precompute, as Rx may not handle precompute and content stream bit properly.
		 * This check is for a safer side */
		//For HDcp2.2 Tx a new bit TRANSMITTER_CONTENT_CATEGORY_SUPPORT is introduced at bit1 set to value 1
		tx_payload->TRANSMITTER_CAPABILITY_MASK[1] |= CONTENT_CATEGORY_SUPPORT;
		
		hdcp2_ctx.transmitter_info.TRANSMITTER_CAPABILITY_MASK[0] = tx_payload->TRANSMITTER_CAPABILITY_MASK[0];
		hdcp2_ctx.transmitter_info.TRANSMITTER_CAPABILITY_MASK[1] = tx_payload->TRANSMITTER_CAPABILITY_MASK[1];
	}

	//TRANSMITTER_LOCALITY_PRECOMPUTE_SUPPORT is bit0 of TRANSMITTER_CAPABILITY_MASK
	hdcp2_ctx.Tx_LC_Precompute = tx_payload->TRANSMITTER_CAPABILITY_MASK[1] & LOCALITY_PRECOMPUTE_SUPPORT;

	hdcp2_ctx.transmitter_info.VERSION = tx_payload->VERSION;
	LOGI("TZ_AKE_Transmitter_Info_T : transmitter_info.VERSION : 0x%02x \n", hdcp2_ctx.transmitter_info.VERSION);

	return HDCP2_OK;
}

/**
 * @fn int TZ_AKE_Send_Cert_T(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief A certificate is  received from the receiver which indicates whether the connected receiver is an HDCP receiver and also extracts Receiver ID
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request containing AKE_SEND_CERT message
 * @param req_size - size of request
 * @param response- pointer to response
 * @param req_size - size of response
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_AKE_Send_Cert_T(const u8 command, u8 *request, const u32 req_size,
			u8 *response, u32 *res_size)
{
	if (req_size != sizeof(AKE_SEND_CERT)) {
		LOGE("Error, AKE CERT data size (%d)\n", req_size);
		return HDCP2_ERR;
	}
	AKE_SEND_CERT *cert = (AKE_SEND_CERT *) request;

	NULL_ERR(cert, HDCP2_TZ_NULL_REQUEST);
	memcpy(&hdcp2_key.cert, cert->certrx, sizeof(HDCP2_RECEIVER_CERTIFICATE));
	hdcp2_ctx.REPEATER = cert->REPEATER;

	return HDCP2_OK;
}

/**
 * @fn int TZ_AKE_Receiver_Info_T(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function gets the information regarding compliance of receiver with various hdcp versions
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request containing AKE_RECEIVER_INFO message
 * @param req_size - size of request
 * @param response- pointer to response
 * @param req_size - size of response
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_AKE_Receiver_Info_T(const u8 command, u8 *request, const u32 req_size,
			u8 *response, u32 *res_size)
{
	if (req_size != sizeof(AKE_RECEIVER_INFO)) {
		LOGE("Error, AKE_RECEIVER_INFO data size (%d)\n", req_size);
		return HDCP2_ERR;
	}
	AKE_RECEIVER_INFO *receiver_info = (AKE_RECEIVER_INFO *) request;

	NULL_ERR(receiver_info, HDCP2_TZ_NULL_REQUEST);

	//updating the hdcp transmitter version as per the receiver Info version.
	if (HDCP2_VERSION_2_0 + receiver_info->VERSION < hdcp2_ctx.version) {
		hdcp2_ctx.version = HDCP2_VERSION_2_0 + receiver_info->VERSION;
		LOGI("TZ_AKE_Receiver_Info_T : HDCP version is changed to %d.%d \n", hdcp2_ctx.version / 10, hdcp2_ctx.version % 10);
	}
	memcpy(&hdcp2_ctx.receiver_info, receiver_info, sizeof(AKE_RECEIVER_INFO));

	hdcp2_ctx.Rx_LC_Precompute = receiver_info->RECEIVER_CAPABILITY_MASK[1] & LOCALITY_PRECOMPUTE_SUPPORT;

	return HDCP2_OK;
	}

/**
 * @fn int TZ_AKE_No_Store_km_T(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function is called when transmitter does not have 128 bit master key stored corresponding to the receiver ID.
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request
 * @param req_size - size of request
 * @param response- pointer to response containing AKE_NO_STORED_KM message
 * @param req_size - size of response
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_AKE_No_Store_km_T(const u8 command, u8 *request, const u32 req_size,
			u8 *response, u32 *res_size)
{
	LOGD("DCP:TZ_AKE_No_Store_km_T called ...#\n");

	tlApiCrSession_t crSession = -1;
	tlApiKey_t key = {0, };
	tlApiRsaKey_t rsa_key = {0, };
	bool validity = 0;
	uint8_t szoutdataHASH[HDCP2_MESSAGE_DIGEST_SIZE] = {0, };
	uint8_t dcp_llc_sign[SIZE_OF_DCPLLC_SIGNATURE] = {0, };
	uint8_t recv_Id[SIZE_OF_PUBLIC_KEY_CERTIFICATE_OF_HDCP_RECEIVER - SIZE_OF_DCPLLC_SIGNATURE] = {0, };
	int retrn=0;

	AKE_NO_STORED_KM *no_stored_km = (AKE_NO_STORED_KM *) response;

	if (memcmp(hdcp2_key.cert.receiver_id, test_certid_r1, 5) == 0 || memcmp(hdcp2_key.cert.receiver_id, test_certid_r2, 5) == 0) {
		LOGI("Cert Verification using Test Key\n");
		memcpy(mod_buf, mod_buf_test, SIZE_OF_DCPLLC_SIGNATURE);
	} else {
		LOGI("Cert Verification using  Production key\n");
	}

	*res_size = sizeof(AKE_NO_STORED_KM);
	NULL_ERR(no_stored_km, HDCP2_TZ_NULL_RESPONSE);

	key.rsaKey = &rsa_key;
	rsa_key.modulus.value = mod_buf;
	rsa_key.modulus.len = SIZE_OF_DCP_PUBLICKEY_MODULUS;
	rsa_key.exponent.value = exp_buf;
	rsa_key.exponent.len = SIZE_OF_DCP_PUBLICKEY_EXPONENT;

	memcpy(dcp_llc_sign, hdcp2_key.cert.dcp_llc_sign, SIZE_OF_DCPLLC_SIGNATURE);
	memcpy(recv_Id, (const uint8_t *)&hdcp2_key.cert, SIZE_OF_PUBLIC_KEY_CERTIFICATE_OF_HDCP_RECEIVER - SIZE_OF_DCPLLC_SIGNATURE);
	retrn = TZ_SHA256(szoutdataHASH, recv_Id, sizeof(recv_Id));
	if (retrn != HDCP2_MESSAGE_DIGEST_SIZE) {
		LOGE("DCP:TZ_SHA256 failed: = %d\n", retrn);
		retrn = HDCP2_ERR_DCP_VERIFICATION;
		goto cleanup;
	}

	tlApiSignatureInit(&crSession, &key, TLAPI_MODE_VERIFY, TLAPI_SIG_RSA_SHA_PKCS1);
	retrn = tlApiSignatureVerify(crSession, szoutdataHASH, HDCP2_MESSAGE_DIGEST_SIZE, dcp_llc_sign, SIZE_OF_DCPLLC_SIGNATURE, &validity);
	if (retrn != HDCP2_OK) {
		LOGE("DCP:tlApiSignatureVerify fail : 0x%x\n", retrn);
		retrn = HDCP2_ERR_DCP_VERIFICATION;
		goto cleanup;
	} else {
		LOGD("DCP:tlApiSignatureVerify success : 0x%x\n", retrn);
	}

cleanup:
	if (retrn != HDCP2_OK)
		return retrn;

	// 1. randomly choose hdcp2_ctx->km
	TZ_rand((u8 *) hdcp2_ctx.pairing_info.km,
			sizeof(hdcp2_ctx.pairing_info.km));
	TZ_LOG_HEX("km", hdcp2_ctx.pairing_info.km, sizeof(hdcp2_ctx.pairing_info.km));

	// 2. Encrypt hdcp2_ctx->km using receiver's public key
	no_stored_km->msg_id = command;

	if (TZ_RSA_OAEP_encrypt(&hdcp2_ctx, &hdcp2_key, hdcp2_ctx.pairing_info.km,
			no_stored_km->Ekpub_km) != sizeof(no_stored_km->Ekpub_km))
		return HDCP2_ERR_OAEP_ENCRYPTION;

	TZ_LOG_HEX("Ekm", no_stored_km->Ekpub_km, sizeof(no_stored_km->Ekpub_km));

	return HDCP2_OK;
}

/**
 * @fn int TZ_AKE_Store_km_T(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function is called when transmitter has 128 bit master key corresponding to the receiver ID.
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request
 * @param req_size - size of request
 * @param response- pointer to response containing AKE_STORED_KM message
 * @param req_size - size of response
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_AKE_Store_km_T(const u8 command, u8 *request, const u32 req_size,
			u8 *response, u32 *res_size)
{
	AKE_STORED_KM *stored_km = (AKE_STORED_KM *) response;

	*res_size = sizeof(AKE_STORED_KM);
	NULL_ERR(stored_km, HDCP2_TZ_NULL_RESPONSE);

	if (!hdcp2_ctx.is_paired)
		return HDCP2_ERR_STORED_KM_NOT_PAIRED;

	stored_km->msg_id = command;
	memcpy(stored_km->m, hdcp2_ctx.pairing_info.m, sizeof(stored_km->m));
	memcpy(stored_km->Ekh_km, hdcp2_ctx.pairing_info.Ekm, sizeof(stored_km->Ekh_km));

	return HDCP2_OK;
}

/**
 * @fn int TZ_AKE_Send_rrx_T(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function receives AKE_Send_rrx message from receiver containing the 64 bit pseudo random value
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request containing AKE_SEND_RRX message
 * @param req_size - size of request
 * @param response- pointer to response
 * @param req_size - size of response
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_AKE_Send_rrx_T(const u8 command, u8 *request, const u32 req_size,
			u8 *response, u32 *res_size)
{
	if (req_size != sizeof(AKE_SEND_RRX)) {
		LOGE("Error, AKE_SEND_RRX data size (%d)\n", req_size);
		return HDCP2_ERR;
	}
	AKE_SEND_RRX *rrx = (AKE_SEND_RRX *) request;

	NULL_ERR(rrx, HDCP2_TZ_NULL_REQUEST);
	memcpy(hdcp2_ctx.rrx, rrx->rrx, sizeof(rrx->rrx));

	return HDCP2_OK;
}

/**
 * @fn int TZ_AKE_Send_h_prime_T(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function receives AKE_SEND_H_PRIME message from the receiver which contains 256-bit H-prime. This message has to be received within 200ms in case of stored_km and within 1s in case of no_stored_km.
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request containing AKE_SEND_H_PRIME message
 * @param req_size - size of request
 * @param response- pointer to response
 * @param req_size - size of response
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_AKE_Send_h_prime_T(const u8 command, u8 *request, const u32 req_size,
			u8 *response, u32 *res_size)
{
	u8 H[32] = {0, };
	u8 input[8] = {0, };

	if (req_size != sizeof(AKE_SEND_H_PRIME)) {
		LOGE("Error, AKE_SEND_H_PRIME data size (%d)\n", req_size);
		return HDCP2_ERR;
	}
	AKE_SEND_H_PRIME *h_prime = (AKE_SEND_H_PRIME *) request;

	NULL_ERR(h_prime, HDCP2_TZ_NULL_REQUEST);

	// Derivate kd = dkey0 || dkey1
	TZ_Derivate_dkey(&hdcp2_ctx);
	memcpy(hdcp2_ctx.kd, hdcp2_ctx.dkey, 16);
	TZ_Derivate_dkey(&hdcp2_ctx);
	memcpy(hdcp2_ctx.kd + 16, hdcp2_ctx.dkey, 16);

	LOGI("TZ_AKE_Send_h_prime_T : cert.Protocol_Descriptor : %d \n", hdcp2_key.cert.Protocol_Descriptor);

	if (hdcp2_key.cert.Protocol_Descriptor == 0x01 && hdcp2_ctx.version >= HDCP2_VERSION_2_2) {
		u8 temp_input[14];
		memset(temp_input, 0, sizeof(temp_input));
		memcpy(temp_input, hdcp2_ctx.rtx, sizeof(hdcp2_ctx.rtx));
		temp_input[7] ^= hdcp2_ctx.REPEATER;
		temp_input[8] = hdcp2_ctx.receiver_info.VERSION;
		memcpy(temp_input + 9, hdcp2_ctx.receiver_info.RECEIVER_CAPABILITY_MASK, sizeof(hdcp2_ctx.receiver_info.RECEIVER_CAPABILITY_MASK));
		temp_input[11] = hdcp2_ctx.transmitter_info.VERSION;
		memcpy(temp_input + 12, hdcp2_ctx.transmitter_info.TRANSMITTER_CAPABILITY_MASK, sizeof(hdcp2_ctx.transmitter_info.TRANSMITTER_CAPABILITY_MASK));
			//Compute H
			// HMAC-SHA256(rtx XOR REPEATER || receiver_info.VERSION || receiver_info.RECEIVER_CAPABILITY_MASK ||
			// transmitter_info.VERSION || transmitter_info.TRANSMITTER_CAPABILITY_MASK, kd)
		TZ_HMAC_SHA256(H, hdcp2_ctx.kd, sizeof(hdcp2_ctx.kd), temp_input, sizeof(temp_input));
		TZ_LOG_HEX("H", H, 32);
		TZ_LOG_HEX("h_prime", h_prime->H, 32);
	} else {
		// input
		memcpy(input, hdcp2_ctx.rtx, sizeof(hdcp2_ctx.rtx));
		input[7] ^= hdcp2_ctx.REPEATER;
		TZ_LOG_HEX("input", input, 8);
		TZ_LOG_HEX("rn", hdcp2_ctx.rn, sizeof(hdcp2_ctx.rn));
		TZ_LOG_HEX("km", hdcp2_ctx.pairing_info.km, sizeof(hdcp2_ctx.pairing_info.km));
		TZ_LOG_HEX("kd", hdcp2_ctx.kd, sizeof(hdcp2_ctx.kd));

		// HMAC-SHA256(rtx XOR REPEATER, kd)
		TZ_HMAC_SHA256(H, hdcp2_ctx.kd, sizeof(hdcp2_ctx.kd), input, sizeof(input));
		TZ_LOG_HEX("H", H, 32);
		TZ_LOG_HEX("h_prime", h_prime->H, 32);
	}

	if (memcmp(h_prime->H, H, sizeof(H)))
		return HDCP2_ERR_INVALID_H;

	return HDCP2_OK;
}

/**
 * @fn int TZ_AKE_Send_Pairing_Info_T(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function receives AKE_SEND_PAIRING_INFO message from receiver which contains 128 bit Ekh(km).
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request containing AKE_SEND_PAIRING_INFO message
 * @param req_size - size of request
 * @param response- pointer to response containing HDCP2_PAIRING_INFO message
 * @param req_size - size of response
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_AKE_Send_Pairing_Info_T(const u8 command, u8 *request,
			const u32 req_size, u8 *response, u32 *res_size)
{
	if (req_size != sizeof(AKE_SEND_PAIRING_INFO)) {
		LOGE("Error, AKE pairing data size (%d)\n", req_size);
		return HDCP2_ERR;
	}
	AKE_SEND_PAIRING_INFO *pairing_info = (AKE_SEND_PAIRING_INFO *) request;
	HDCP2_PAIRING_INFO *p = (HDCP2_PAIRING_INFO *) response;
	int length = MC_SO_SIZE(0, sizeof(HDCP2_PAIRING_INFO) - sizeof(p->padding));

	*res_size = sizeof(HDCP2_PAIRING_INFO);
	NULL_ERR(request, HDCP2_TZ_NULL_REQUEST);
	NULL_ERR(response, HDCP2_TZ_NULL_RESPONSE);

	// clear pairing info
	memset(p, 0, sizeof(HDCP2_PAIRING_INFO));

	// copy pairing info
	memcpy(p->Ekm, pairing_info->Ekh_Km, sizeof(pairing_info->Ekh_Km));
	memcpy(p->km, hdcp2_ctx.pairing_info.km, sizeof(hdcp2_ctx.pairing_info.km));
	if (hdcp2_ctx.version >= HDCP2_VERSION_2_2) {
		//Spec HDCP2.2 page:20
		//TBD:From the spec, if the receiver is 2.0 complaint(i.e.,receiverInfo version=0x01
		//Transmitter must not store pairing info m, km, ekm and receiver ID corresponding to the receiver.
		if (hdcp2_ctx.transmitter_info.VERSION != 0x01) {
			memcpy(p->m, hdcp2_ctx.rtx, sizeof(hdcp2_ctx.rtx));
			memcpy(p->m + sizeof(hdcp2_ctx.rtx), hdcp2_ctx.rrx, sizeof(hdcp2_ctx.rrx));
			TZ_LOG_HEX("Master Key", p->m, sizeof(p->m));
		}
	} else {
		memcpy(p->m, hdcp2_ctx.rtx, sizeof(hdcp2_ctx.rtx)); //as spec 2.1
	}

	memcpy(p->receiver_id, hdcp2_key.cert.receiver_id,
								sizeof(hdcp2_key.cert.receiver_id));

	// encrypt pairing info
	TZ_LOG_HEX("Pairing Info", response, sizeof(HDCP2_PAIRING_INFO));

	TZ_Wrap(response, sizeof(HDCP2_PAIRING_INFO) - sizeof(p->padding), response, &length);

	TZ_LOG_HEX("Encrypted Pairing Info", response, sizeof(HDCP2_PAIRING_INFO));

	hdcp2_ctx.is_paired = 1;

	return HDCP2_OK;
}

/**
 * @fn int TZ_LC_Init_T(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function initiates locality check by sending a message containing 64 bit pseudo random number to hdcp receiver
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request
 * @param req_size - size of request
 * @param response- pointer to response containing LC_INIT message
 * @param req_size - size of response
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_LC_Init_T(const u8 command, u8 *request, const u32 req_size,
			u8 *response, u32 *res_size)
{
	int i=0;
	u8 key[32] = {0, };
	u8 L[32] = {0, };
	LC_INIT *lc_init = (LC_INIT *) response;
	*res_size = sizeof(LC_INIT);

	NULL_ERR(lc_init, HDCP2_TZ_NULL_RESPONSE);

	// 1. randomly choose hdcp2_ctx->rn
	TZ_rand(hdcp2_ctx.rn, sizeof(hdcp2_ctx.rn));

	// 2. Copy to payload
	lc_init->msg_id = command;
	memcpy(lc_init->rn, hdcp2_ctx.rn, sizeof(hdcp2_ctx.rn));

	if (hdcp2_ctx.Tx_LC_Precompute && hdcp2_ctx.Rx_LC_Precompute) {
		// key = kd ^ rrx
		memcpy(key, hdcp2_ctx.kd, sizeof(hdcp2_ctx.kd));
		for (i = 24; i < 32; i++)
			key[i] ^= hdcp2_ctx.rrx[i - 24];

		if (hdcp2_ctx.version >= HDCP2_VERSION_2_2 && hdcp2_ctx.transmitter_info.VERSION != 0x01) {
			u8 temp_rn[16] = {0, };
			memcpy(temp_rn, hdcp2_ctx.rn, sizeof(hdcp2_ctx.rn));
			memcpy(temp_rn+sizeof(hdcp2_ctx.rn), hdcp2_ctx.rn, sizeof(hdcp2_ctx.rn));
			//HMAC-SHA256(rn || rn, kd XOR rrx)
			TZ_HMAC_SHA256(L, key, sizeof(key), temp_rn,
					sizeof(temp_rn));
		} else {
			TZ_HMAC_SHA256(L, key, sizeof(key), hdcp2_ctx.rn, sizeof(hdcp2_ctx.rn));
		}

		memcpy(hdcp2_ctx.L_msb, L, 16);
		memcpy(hdcp2_ctx.L_lsb, L + 16, 16);
		TZ_LOG_HEX("hdcp2_ctx.L_msb Tx", hdcp2_ctx.L_msb, sizeof(hdcp2_ctx.L_msb));
		TZ_LOG_HEX("hdcp2_ctx.L_lsb Tx", hdcp2_ctx.L_lsb, sizeof(hdcp2_ctx.L_lsb));
	}

	return HDCP2_OK;
}

/**
 * @fn int TZ_RTT_Challenge_T(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function sends the message containing the least significant 128 bits of L to the receiver
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request
 * @param req_size - size of request
 * @param response- pointer to response containing RTT_CHALLENGE message
 * @param req_size - size of response
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_RTT_Challenge_T(const uint8_t command, uint8_t *request,
			const u32 req_size, uint8_t *response, uint32_t *res_size)
{
	RTT_CHALLENGE *rtt = (RTT_CHALLENGE *) response;
	*res_size = sizeof(RTT_CHALLENGE);

	NULL_ERR(rtt, HDCP2_TZ_NULL_RESPONSE);

	rtt->msg_id = command;
	memcpy(rtt->L_lsb, hdcp2_ctx.L_lsb, sizeof(hdcp2_ctx.L_lsb));

	return HDCP2_OK;
}

/**
 * @fn int TZ_LC_Send_L_prime_T(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function receives a message containing most significant bits of L- prime from receiver. This is compared with L. The time elapsed between sending RTT_Challenge_T and receiving L-prime must be less than 7ms.
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request containing LC_SEND_L_PRIME_PC message
 * @param req_size - size of request
 * @param response- pointer to response
 * @param req_size - size of response
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_LC_Send_L_prime_T(const u8 command, u8 *request, const u32 req_size,
			u8 *response, u32 *res_size)
{
	u8 key[32] = {0, };
	u8 L[32] = {0, };

	if (hdcp2_ctx.Tx_LC_Precompute && hdcp2_ctx.Rx_LC_Precompute) {
		if (req_size != sizeof(LC_SEND_L_PRIME_PC)) {
			LOGE("Error, LC_SEND_L_PRIME_PC data size (%d)\n", req_size);
			return HDCP2_ERR;
		}
		LC_SEND_L_PRIME_PC *l_prime = (LC_SEND_L_PRIME_PC *) request;
		NULL_ERR(request, HDCP2_TZ_NULL_REQUEST);

		if (memcmp(l_prime->L_msb, hdcp2_ctx.L_msb, sizeof(hdcp2_ctx.L_msb)))
			return HDCP2_ERR_INVALID_L;
	} else {
		if (req_size != sizeof(LC_SEND_L_PRIME)) {
			LOGE("Error, LC_SEND_L_PRIME data size (%d)\n", req_size);
			return HDCP2_ERR;
		}
		int i = 0;
		LC_SEND_L_PRIME *l_prime = (LC_SEND_L_PRIME *) request;

		NULL_ERR(request, HDCP2_TZ_NULL_REQUEST);

		// key = kd ^ rrx
		memcpy(key, hdcp2_ctx.kd, sizeof(hdcp2_ctx.kd));
		for (i = 24; i < 32; i++)
			key[i] ^= hdcp2_ctx.rrx[i - 24];

		TZ_HMAC_SHA256(L, key, sizeof(key), hdcp2_ctx.rn, sizeof(hdcp2_ctx.rn));

		if (memcmp(l_prime->L, L, sizeof(L)))
			return HDCP2_ERR_INVALID_L;
	}

	return HDCP2_OK;
}

/**
 * @fn int TZ_SKE_Send_Eks_T(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function sends a message containing Edkey(ks) and a 64 bit pseudo random number to the hdcp receiver
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request
 * @param req_size - size of request
 * @param response- pointer to response containing SKE_SEND_EKS message
 * @param req_size - size of response
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_SKE_Send_Eks_T(const u8 command, u8 *request, const u32 req_size,
			u8 *response, u32 *res_size)
{
	int ret = 0;
	int i = 0;
#ifdef USE_WFD_TS_MUX_HW
	uint32_t sessionKey[8] = {0, };
	uint32_t riv[2] = {0, };

	struct secHDCPKeyInfo_t secHDCPKey;
	memset(&secHDCPKey, 0, sizeof(struct secHDCPKeyInfo_t));
#endif /* USE_WFD_TS_MUX_HW */

	NULL_ERR(response, HDCP2_TZ_NULL_RESPONSE);

	if (hdcp2_ctx.version == HDCP2_VERSION_2_3) {
		SKE_SEND_EKS_VER23 *eks = (SKE_SEND_EKS_VER23 *) response;
		*res_size = sizeof(SKE_SEND_EKS_VER23);

		// 1. Generate random ks and riv
		TZ_rand(hdcp2_ctx.ks, sizeof(hdcp2_ctx.ks));
		TZ_rand(hdcp2_ctx.riv, sizeof(hdcp2_ctx.riv));

		// HDCP v2.3: calculate HMAC of riv
		TZ_HMAC_SHA256(eks->H, hdcp2_ctx.kd, sizeof(hdcp2_ctx.kd), hdcp2_ctx.riv,
				sizeof(hdcp2_ctx.riv));

		// 2. Key Derivation (dkey2 <= ctr=2)
		TZ_Derivate_dkey(&hdcp2_ctx);

		// 3. Eks = ks ^ dkey2 ^ rrx[8-15]
		for (i = 0; i < 16; i++) {
			eks->Eks[i] = (i < 8) ? hdcp2_ctx.ks[i] ^ hdcp2_ctx.dkey[i] :
							hdcp2_ctx.ks[i] ^ hdcp2_ctx.dkey[i] ^ hdcp2_ctx.rrx[i - 8];
		}

		TZ_LOG_HEX("eks->Eks", eks->Eks, sizeof(eks->Eks));
		TZ_LOG_HEX("eks->H", eks->H, sizeof(eks->H));

		// 4. Make payload
		eks->msg_id = command;
		memcpy(eks->riv, hdcp2_ctx.riv, sizeof(hdcp2_ctx.riv));
	} else {
		SKE_SEND_EKS *eks = (SKE_SEND_EKS *) response;
		*res_size = sizeof(SKE_SEND_EKS);

		// 1. Generate random ks and riv
		TZ_rand(hdcp2_ctx.ks, sizeof(hdcp2_ctx.ks));
		TZ_rand(hdcp2_ctx.riv, sizeof(hdcp2_ctx.riv));

		// 2. Key Derivation (dkey2 <= ctr=2)
		TZ_Derivate_dkey(&hdcp2_ctx);

		// 3. Eks = ks ^ dkey2 ^ rrx[8-15]
		for (i = 0; i < 16; i++) {
			eks->Eks[i] = (i < 8) ? hdcp2_ctx.ks[i] ^ hdcp2_ctx.dkey[i] :
							hdcp2_ctx.ks[i] ^ hdcp2_ctx.dkey[i] ^ hdcp2_ctx.rrx[i - 8];
		}

		TZ_LOG_HEX("eks->Eks", eks->Eks, sizeof(eks->Eks));

		// 4. Make payload
		eks->msg_id = command;
		memcpy(eks->riv, hdcp2_ctx.riv, sizeof(hdcp2_ctx.riv));
	}

	TZ_LOG_HEX("riv", hdcp2_ctx.riv, sizeof(hdcp2_ctx.riv));
	TZ_LOG_HEX("ks", hdcp2_ctx.ks, sizeof(hdcp2_ctx.ks));

#ifdef USE_WFD_TS_MUX_HW
	memcpy((void *)sessionKey, (void *)hdcp2_ctx.ks, 16);
	memcpy((void *)riv, (void *)hdcp2_ctx.riv, 8);

	secHDCPKey.session_key = sessionKey;
	secHDCPKey.riv = riv;

	TZ_LOG_HEX("secHDCPKey.session_key", (uint8_t *)secHDCPKey.session_key, 16);
	TZ_LOG_HEX("secHDCPKey.riv", (uint8_t *)secHDCPKey.riv, 8);

	if ((ret = tlApiSetHDCPKeyinfo(&secHDCPKey)) != 0)
		return HDCP2_ERR_SKE;
#endif /* USE_WFD_TS_MUX_HW */

	// 5. Set content key
	if ((ret = TZ_Get_ContentKey(hdcp2_ctx.ks, hdcp2_key.lc128, hdcp2_key.ckey))
			< 0)
		return ret;

	// 6. Finally set HDCP flag for other DRMs
#ifdef USE_HDCP2FLAG
	if ((ret = tlApiSecSetHdcp2Flag(0x04)) < 0) {
#else
	if ((ret = SET_WIDI_CUR_STATUS(HDCP_2_2_TYPE1)) < 0) {
		LOGE("tlApiSecSetHdcpFlag error. [return value] = %d\n", ret);
#endif /* USE_HDCP2FLAG */
		return HDCP2_ERR_SET_HDCP2_FLAG;
	}

	return HDCP2_OK;
}

/**
 * @fn int TZ_RepeaterAuth_Send_ReceiverId_List_T(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function gets the message containing the information regarding the receivers connected to the repeater
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request
 * @param req_size - size of request
 * @param response- pointer to response
 * @param req_size - size of response
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_RepeaterAuth_Send_ReceiverId_List_T(const u8 command, u8 *request,
			const u32 req_size, u8 *response, u32 *res_size)
{
	int ret=0;

	// added verify for 2.2 ver also
	if (hdcp2_ctx.version >= HDCP2_VERSION_2_1)
		ret = TZ_RepeaterAuth_Send_ReceiverId_List21_T(request);
	else
		ret = TZ_RepeaterAuth_Send_ReceiverId_List20_T(request);

	return ret;
}

/**
 * @fn int TZ_RepeaterAuth_Send_ReceiverId_List20_T(uint8_t *request);
 * @brief This function gets the message containing the information regarding the hdcp2.0 compliant receivers connected to the repeater
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request containing REPEATERAUTH_SEND_RECEIVER_ID_LIST20 message
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_RepeaterAuth_Send_ReceiverId_List20_T(u8 *request)
{
	u8 V[32] = {0, };
	u8 input[159] = {0, };
	u8 totalSize = 0;
	u8 offset=0;

	REPEATERAUTH_SEND_RECEIVER_ID_LIST20 *recidinfo = (REPEATERAUTH_SEND_RECEIVER_ID_LIST20 *) request;
	NULL_ERR(request, HDCP2_ERR_NULL_REQUEST);

	if(recidinfo->DEVICE_COUNT > MAX_RECEIVER_DEVICE)
		return HDCP2_ERR_TOO_MANY_DEVICES;

	memcpy(input, recidinfo->RECEIVER_IDs[0].RECEIVER_IDj, (recidinfo->DEVICE_COUNT)*RECEIVER_ID_SIZE);
	offset = (recidinfo->DEVICE_COUNT)*RECEIVER_ID_SIZE;

	memcpy(input + offset, &(recidinfo->DEPTH),
			sizeof(recidinfo->DEPTH));
	memcpy(input + offset+ sizeof(recidinfo->DEPTH),
			&(recidinfo->DEVICE_COUNT), sizeof(recidinfo->DEVICE_COUNT));
	memcpy(input + offset + sizeof(recidinfo->DEPTH)
					+ sizeof(recidinfo->DEVICE_COUNT),
			&(recidinfo->MAX_DEVS_EXCEEDED), sizeof(recidinfo->MAX_DEVS_EXCEEDED));
	memcpy(input  + offset + sizeof(recidinfo->DEPTH)
					+ sizeof(recidinfo->DEVICE_COUNT) + sizeof(recidinfo->MAX_DEVS_EXCEEDED),
			&(recidinfo->MAX_CASCADE_EXCEEDED), sizeof(recidinfo->MAX_CASCADE_EXCEEDED));

	totalSize = offset + sizeof(recidinfo->DEPTH) + sizeof(recidinfo->DEVICE_COUNT)
					+ sizeof(recidinfo->MAX_DEVS_EXCEEDED) + sizeof(recidinfo->MAX_CASCADE_EXCEEDED);

	TZ_HMAC_SHA256(V, hdcp2_ctx.kd, sizeof(hdcp2_ctx.kd), input, totalSize);

	if (memcmp(recidinfo->V_PRIME, V, sizeof(V)))
		return HDCP2_ERR_INVALID_V;

	return HDCP2_OK;
}

/**
 * @fn int TZ_RepeaterAuth_Send_ReceiverId_List21_T(uint8_t *request);
 * @brief This function gets the message containing the information regarding the hdcp2.1 compliant receivers connected to the repeater
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request containing REPEATERAUTH_SEND_RECEIVER_ID_LIST21 message
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_RepeaterAuth_Send_ReceiverId_List21_T(u8 *request)
{
	u8 V[32] = {0, };
	u8 input[164] = {0, };
	u8 totalSize = 0;
	u8 offset=0;

	REPEATERAUTH_SEND_RECEIVER_ID_LIST21 *recidinfo = (REPEATERAUTH_SEND_RECEIVER_ID_LIST21 *) request;
	NULL_ERR(request, HDCP2_ERR_NULL_REQUEST);

	if (recidinfo->DEVICE_COUNT > MAX_RECEIVER_DEVICE)
		return HDCP2_ERR_TOO_MANY_DEVICES;

	memcpy(input, recidinfo->RECEIVER_IDs[0].RECEIVER_IDj, (recidinfo->DEVICE_COUNT)*RECEIVER_ID_SIZE);
	offset = (recidinfo->DEVICE_COUNT)*RECEIVER_ID_SIZE;

	memcpy(input + offset, &(recidinfo->DEPTH),
			sizeof(recidinfo->DEPTH));
	memcpy(input + offset + sizeof(recidinfo->DEPTH),
			&(recidinfo->DEVICE_COUNT), sizeof(recidinfo->DEVICE_COUNT));
	memcpy(input + offset + sizeof(recidinfo->DEPTH)
					+ sizeof(recidinfo->DEVICE_COUNT),
			&(recidinfo->MAX_DEVS_EXCEEDED), sizeof(recidinfo->MAX_DEVS_EXCEEDED));
	memcpy(input + offset + sizeof(recidinfo->DEPTH)
					+ sizeof(recidinfo->DEVICE_COUNT) + sizeof(recidinfo->MAX_DEVS_EXCEEDED),
			&(recidinfo->MAX_CASCADE_EXCEEDED), sizeof(recidinfo->MAX_CASCADE_EXCEEDED));
	memcpy(input + offset + sizeof(recidinfo->DEPTH)
					+ sizeof(recidinfo->DEVICE_COUNT) + sizeof(recidinfo->MAX_DEVS_EXCEEDED)
					+ sizeof(recidinfo->MAX_CASCADE_EXCEEDED),
			&(recidinfo->HDCP2_LEGACY_DEVICE_DOWNSTREAM), sizeof(recidinfo->HDCP2_LEGACY_DEVICE_DOWNSTREAM));
	memcpy(input + offset + sizeof(recidinfo->DEPTH)
					+ sizeof(recidinfo->DEVICE_COUNT) + sizeof(recidinfo->MAX_DEVS_EXCEEDED)
					+ sizeof(recidinfo->MAX_CASCADE_EXCEEDED) + sizeof(recidinfo->HDCP2_LEGACY_DEVICE_DOWNSTREAM),
			&(recidinfo->HDCP1_DEVICE_DOWNSTREAM), sizeof(recidinfo->HDCP1_DEVICE_DOWNSTREAM));
	memcpy(input + offset + sizeof(recidinfo->DEPTH)
					+ sizeof(recidinfo->DEVICE_COUNT) + sizeof(recidinfo->MAX_DEVS_EXCEEDED)
					+ sizeof(recidinfo->MAX_CASCADE_EXCEEDED) + sizeof(recidinfo->HDCP2_LEGACY_DEVICE_DOWNSTREAM)
					+ sizeof(recidinfo->HDCP1_DEVICE_DOWNSTREAM),
			recidinfo->seq_num_V, sizeof(recidinfo->seq_num_V));

	totalSize = offset + sizeof(recidinfo->DEPTH) + sizeof(recidinfo->DEVICE_COUNT) + sizeof(recidinfo->MAX_DEVS_EXCEEDED)
					+ sizeof(recidinfo->MAX_CASCADE_EXCEEDED) + sizeof(recidinfo->HDCP2_LEGACY_DEVICE_DOWNSTREAM)
					+ sizeof(recidinfo->HDCP1_DEVICE_DOWNSTREAM) + sizeof(recidinfo->seq_num_V);

	TZ_HMAC_SHA256(V, hdcp2_ctx.kd, sizeof(hdcp2_ctx.kd), input, totalSize);

	TZ_LOG_HEX("V", V, sizeof(V));
	TZ_LOG_HEX("V' MSB from Dongle", recidinfo->V_PRIME, sizeof(recidinfo->V_PRIME));

	memcpy(hdcp2_ctx.repeater_ack, V + 16, 16); //V lsb
	if (memcmp(recidinfo->V_PRIME, V, 16) != 0) //V msb
		return HDCP2_ERR_INVALID_V;

	return HDCP2_OK;
}

/**
 * @fn int TZ_RepeaterAuth_Send_Ack_T(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function sends an acknowledgment to the receiver
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request
 * @param req_size - size of request
 * @param response- pointer to response  containing REPEATERAUTH_SEND_ACK message
 * @param req_size - size of response
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_RepeaterAuth_Send_Ack_T(const u8 command, u8 *request,
			const u32 req_size, u8 *response, u32 *res_size)
{
	*res_size = sizeof(REPEATERAUTH_SEND_ACK);

	REPEATERAUTH_SEND_ACK *send_ack = (REPEATERAUTH_SEND_ACK *) response;
	NULL_ERR(send_ack, HDCP2_ERR_NULL_RESPONSE);

	send_ack->msg_id = command;
	memcpy(send_ack->V, hdcp2_ctx.repeater_ack, sizeof(hdcp2_ctx.repeater_ack));

	return HDCP2_OK;
}

/**
 * @fn int TZ_Receiver_AuthStatus_T(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function lets the transmitter know about the authentication status of receiver with the repeater
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request
 * @param req_size - size of request
 * @param response- pointer to response containing REPEATERAUTH_SEND_ACK message
 * @param req_size - size of response
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_Receiver_AuthStatus_T(const u8 command, u8 *request, const u32 req_size,
			u8 *response, u32 *res_size)
{
	RECEIVER_AUTHSTATUS *status = (RECEIVER_AUTHSTATUS *) request;
	NULL_ERR(status, HDCP2_ERR_NULL_REQUEST);

	if (status->REAUTH_Req == 1)
		//request for reauthentication
		return HDCP2_ERR_REAUTH_REQ;
	else
		return HDCP2_OK;
}

/**
 * @fn int TZ_RepeaterAuth_Stream_Manage_T(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function propagates content stream management information, which includes Type values assigned to the content streams
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request
 * @param req_size - size of request
 * @param response- pointer to response containing REPEATERAUTH_STREAM_MANAGE message
 * @param req_size - size of response
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_RepeaterAuth_Stream_Manage_T(const u8 command, u8 *request,
			const u32 req_size, u8 *response, u32 *res_size)
{
	if (req_size != sizeof(REPEATERAUTH_STREAM_INFO)) {
		LOGE("Error, RepeaterAuth data size (%d)\n", req_size);
		return HDCP2_ERR;
	}
	int i = 0;
	*res_size = sizeof(REPEATERAUTH_STREAM_MANAGE);

	REPEATERAUTH_STREAM_MANAGE *send_msg = (REPEATERAUTH_STREAM_MANAGE *) response;
	NULL_ERR(send_msg, HDCP2_ERR_NULL_RESPONSE);

	REPEATERAUTH_STREAM_INFO *send_info = (REPEATERAUTH_STREAM_INFO *) request;
	NULL_ERR(send_info, HDCP2_ERR_NULL_RESPONSE);

	memcpy(hdcp2_ctx.no_of_streams, send_info->no_of_streams,
			sizeof(hdcp2_ctx.no_of_streams));

	for (i = 0; i < hdcp2_ctx.no_of_streams[1] && hdcp2_ctx.no_of_streams[1] <= 16; i++) {
		memcpy(hdcp2_ctx.multi_stream[i].streamCtrj,
				send_info->multi_streaminfo[i].streamCtrj,
				sizeof(hdcp2_ctx.multi_stream[i].streamCtrj));
		memcpy(hdcp2_ctx.multi_stream[i].ContentStreamIDj,
				send_info->multi_streaminfo[i].ContentStreamIDj,
				sizeof(hdcp2_ctx.multi_stream[i].ContentStreamIDj));
		hdcp2_ctx.multi_stream[i].Type = send_info->multi_streaminfo[i].Type;
	}

	send_msg->msg_id = command;
	memcpy(send_msg->seq_num_M, hdcp2_ctx.seq_num_M,
			sizeof(hdcp2_ctx.seq_num_M));
	memcpy(send_msg->k, hdcp2_ctx.no_of_streams, sizeof(send_msg->k));

	//saving the multistream data to calculate RepeaterAuth_Stream_Ready message
	for (i = 0; i < hdcp2_ctx.no_of_streams[1] && hdcp2_ctx.no_of_streams[1] <= 16; i++) {
		memcpy(send_msg->max_k_info[i].streamCtrj,
				hdcp2_ctx.multi_stream[i].streamCtrj,
				sizeof(send_msg->max_k_info[i].streamCtrj));
		memcpy(send_msg->max_k_info[i].ContentStreamIDj,
				hdcp2_ctx.multi_stream[i].ContentStreamIDj,
				sizeof(send_msg->max_k_info[i].ContentStreamIDj));
		send_msg->max_k_info[i].Type = hdcp2_ctx.multi_stream[i].Type;
	}

	return HDCP2_OK;
}

/**
 * @fn int TZ_RepeaterAuth_Stream_Ready_T(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function obtains M- prime as sent by repeater
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request containing REPEATERAUTH_STREAM_READY message
 * @param req_size - size of request
 * @param response- pointer to response
 * @param req_size - size of response
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_RepeaterAuth_Stream_Ready_T(const u8 command, u8 *request,
			const u32 req_size, u8 *response, u32 *res_size)
{
	if (req_size != sizeof(REPEATERAUTH_STREAM_READY)) {
		LOGE("Error, REPEATERAUTH data size (%d)\n", req_size);
		return HDCP2_ERR_INVALID_M;
	}
	REPEATERAUTH_STREAM_READY *status = (REPEATERAUTH_STREAM_READY *) request;
	NULL_ERR(status, HDCP2_ERR_NULL_REQUEST);
	u8 kd[32] = {0, };
	u8 M[32] = {0, };
	// size = hdcp2_ctx.no_of_streams*7 + 3;
	u8 input[115] = {0, };
	u8* temp_ptr = input;
	int i = 0;

	//calculate input
	for (i = 0; i < hdcp2_ctx.no_of_streams[1] && hdcp2_ctx.no_of_streams[1] <= 16; i++) {
		memcpy(temp_ptr, hdcp2_ctx.multi_stream[i].streamCtrj,
				sizeof(hdcp2_ctx.multi_stream[i].streamCtrj));
		memcpy(temp_ptr + sizeof(hdcp2_ctx.multi_stream[i].streamCtrj),
				hdcp2_ctx.multi_stream[i].ContentStreamIDj,
				sizeof(hdcp2_ctx.multi_stream[i].ContentStreamIDj));
		memcpy(temp_ptr + sizeof(hdcp2_ctx.multi_stream[i].streamCtrj)
						+ sizeof(hdcp2_ctx.multi_stream[i].ContentStreamIDj),
				&(hdcp2_ctx.multi_stream[i].Type), sizeof(hdcp2_ctx.multi_stream[i].Type));
		temp_ptr = temp_ptr + sizeof(hdcp2_ctx.multi_stream[i].streamCtrj)
				+ sizeof(hdcp2_ctx.multi_stream[i].ContentStreamIDj)
				+ sizeof(hdcp2_ctx.multi_stream[i].Type);
	}

	memcpy(temp_ptr, hdcp2_ctx.seq_num_M, sizeof(hdcp2_ctx.seq_num_M));

	SHA256_CALCULATION(kd, (uint8_t*) &hdcp2_ctx.kd, 32);

	TZ_HMAC_SHA256(M, kd, sizeof(kd), input, (hdcp2_ctx.no_of_streams[1] * 7 + 3));

	if (memcmp(status->M_PRIME, M, 32) != 0)
		return HDCP2_ERR_INVALID_M;

	hdcp2_ctx.seq_num_M[2] += 1;

	return HDCP2_OK;
}

/**
 * @fn int TZ_ENC_Data(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function encrypts the plain text sent to it.
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request containing the data stream to be encrypted
 * @param req_size - size of request
 * @param response- pointer to response
 * @param req_size - size of response
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_ENC_Data(u8 command, u8 *request, const u32 req_size, u8 *response,
			u32 *res_size)
{
	int ret = 0;
	unsigned char p[16];
	CIP_DATA_INFO *data = (CIP_DATA_INFO *) request;

#ifdef USE_MTK
	uint64_t input_pa;
	uint64_t input_phys_fd = 0;
	uint64_t pool_pa, pool_size;
#endif /* USE_MTK */

	if (!data || !data->input || !data->length || !data->output) {
		LOGE("TZ_ENC_Data: Error, Invalid Input\n");
		return HDCP2_ERR_INVALID_INPUT;
	}

	if (data->length > MAX_ENCRYPT_BUFFER) {
		LOGE("Error, Data max size\n");
		return HDCP2_ERR_INVALID_INPUT;
	}

	if (req_size != sizeof(CIP_DATA_INFO)) {
		LOGE("TZ_ENC_Data: Error, Invalid Req size (%d)\n", req_size);
		return HDCP2_ERR_INVALID_INPUT;
	}

	*res_size = data->length;

	// p = (riv XOR streamCtr) || incputCtr (p.50)
	p[0] = hdcp2_ctx.riv[0];
	p[1] = hdcp2_ctx.riv[1];
	p[2] = hdcp2_ctx.riv[2];
	p[3] = hdcp2_ctx.riv[3];
	p[4] = hdcp2_ctx.riv[4] ^ (u8) ((data->str_ctr >> 24) & 0xff);
	p[5] = hdcp2_ctx.riv[5] ^ (u8) ((data->str_ctr >> 16) & 0xff);
	p[6] = hdcp2_ctx.riv[6] ^ (u8) ((data->str_ctr >> 8) & 0xff);
	p[7] = hdcp2_ctx.riv[7] ^ (u8) (data->str_ctr & 0xff);
	p[8] = (u8) ((data->inp_ctr >> 56) & 0xff);
	p[9] = (u8) ((data->inp_ctr >> 48) & 0xff);
	p[10] = (u8) ((data->inp_ctr >> 40) & 0xff);
	p[11] = (u8) ((data->inp_ctr >> 32) & 0xff);
	p[12] = (u8) ((data->inp_ctr >> 24) & 0xff);
	p[13] = (u8) ((data->inp_ctr >> 16) & 0xff);
	p[14] = (u8) ((data->inp_ctr >> 8) & 0xff);
	p[15] = (u8) (data->inp_ctr & 0xff);

	TZ_LOG_HEX("ks", hdcp2_ctx.ks, sizeof(hdcp2_ctx.ks));
	TZ_LOG_HEX("ckey", hdcp2_key.ckey, sizeof(hdcp2_key.ckey));
	TZ_LOG_HEX("p", p, 16);

#ifdef USE_MTK
	if (data->type != -1) {
		input_phys_fd = data->input;

		if (drMemPAQueryByType(input_phys_fd, &input_pa, MEM_SEC) != 0) {
			LOGE("TZ_ENC_Data: Error, mapping error\n");
			return HDCP2_ERR_INVALID_INPUT;
		}
		if (input_pa == 0) {
			LOGE("TZ_ENC_Data: Error, input address error (%llx)\n", input_pa);
			return HDCP2_ERR_INVALID_INPUT;
		}

		if (drMemPoolQueryByType(&pool_pa, &pool_size, MEM_SEC) != 0) {
			LOGE("TZ_ENC_Data: Error, mapping size error\n");
			return HDCP2_ERR_INVALID_INPUT;
		}
		if (!(pool_pa <= input_pa && input_pa < (pool_pa + pool_size))) {
			LOGE("TZ_ENC_Data: Error, address error (%llx)/(%llx)/(%llx)\n",
						input_pa, pool_pa, pool_size);
//			return HDCP2_ERR_INVALID_INPUT;
		}
		LOGD("input pa= %llx, pool_pa = %x, pool_size = %x\n", input_pa, pool_pa, pool_size);
		ret = TZ_Cipher_AES_CTR_Encrypt(input_pa, data->length, request, res_size,
				hdcp2_key.ckey, p);
	} else {
		ret = TZ_Cipher_AES_CTR_Encrypt(data->input, data->length, request, res_size,
				hdcp2_key.ckey, p);
	}
#else
	ret = TZ_Cipher_AES_CTR_Encrypt(data->input, data->length,  data->output, res_size,
			hdcp2_key.ckey, p);
#endif /* USE_MTK */

	return ret;
}

/**
 * @fn int TZ_DRM_Set_HDCP2_MagicKey(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function is sets the Magic Key
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request
 * @param req_size - size of request
 * @param response- pointer to response
 * @param req_size - size of response
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_DRM_Set_HDCP2_MagicKey(const u8 command, u8 *request, const u32 req_size,
			u8 *response, u32 *res_size)
{
	return HDCP2_OK;
}

/**
 * @fn int TZ_OEM_GET_FLAG(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This functions checks for OEM information
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request
 * @param req_size - size of request
 * @param response- pointer to response
 * @param req_size - size of response
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_OEM_GET_FLAG(const u8 command, u8 *request, const u32 req_size,
			u8 *response, u32 *res_size)
{
	*res_size = 4;
	tlApiResult_t ret_dr;

	u32 index = 3;
	u32 value = 0;
	ret_dr = tlApiFcSecGetOemFlag(index, &value);

	if (ret_dr != TLAPI_OK) {
		LOGE("sec_get_oem_flag error. [return value] = %d\n", ret_dr);
		return HDCP2_ERR_GET_OEM_FLAG;
	}
	memcpy(response, (u8*) &value, 4);

	return HDCP2_OK;
}

