/**
 * 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_receiver.c
 * @author
 * @date
 * @brief This file contains definition of all the functions used in receiver in SWD side
 */

#include <stdlib.h>
#include <stdarg.h>
#include <time.h>

#include "tz_hdcp2_crypto.h"
#include "tlapi_secdrv.h"
#include "TlApi/TlApi.h"

#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;

/**
 * @fn int TZ_SPSPPS_COPY(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief sps_pps header is copied to secure memory
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request containing CIP_DATA_SPSPPS 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_SPSPPS_COPY(const u8 command, u8 *request, u32 req_size,
			u8 *response, u32 *res_size)
{
	int ret = HDCP2_OK;
	uint8_t *spspps_buffer = NULL;
	struct secMemcpy_t secMemcpy;

	NULL_ERR(request, HDCP2_TZ_NULL_REQUEST);
	if (req_size != sizeof(CIP_DATA_SPSPPS) || response != NULL || res_size == NULL || *res_size != 0) {
		LOGE("Error, SPSPPS data size (%d)\n", req_size);
		return HDCP2_ERR;
	}

	CIP_DATA_SPSPPS *data = (CIP_DATA_SPSPPS *) request;
	*res_size = 0;

	if (data->size > MAX_SPS_BUFFER - 1 || data->size <= 0) {
		LOGE("Error, SPS data size (%d)\n", data->size);
		return -1;
	}

	spspps_buffer = (uint8_t *)tlApiMalloc(data->size, 0);
	if (!spspps_buffer) {
		LOGE("Fail to alloc secure buffer. data->size[%d]\n", data->size);
		return HDCP2_ERR_SPSPPS_COPY_FAIL;
	}

	LOGD("spspps_buffer[0x%x]   data->size[%d]\n", spspps_buffer,data->size);

	memset(spspps_buffer, 0, data->size);
	memcpy(spspps_buffer, data->spspps, data->size);

	secMemcpy.src = spspps_buffer;
	secMemcpy.dst = data->phy_out;
	secMemcpy.len = data->size;

	TZ_LOG_HEX("inside spspps_copy: data recved on swd side : ", secMemcpy.src, 100);

	ret = tlApiVirt2PhysMemcpy(&secMemcpy);
	if (ret != HDCP2_OK) {
		LOGE("Vir2PhysMemcpy is failed ret[%d]\n",ret);
		tlApiFree(spspps_buffer);
		return HDCP2_ERR_SPSPPS_COPY_FAIL;
	}

	LOGD("tlApiVirt2PhysMemcpy value returned is %d \n", ret);

	if(spspps_buffer) {
		memset(spspps_buffer, 0, data->size);
		tlApiFree(spspps_buffer);
		spspps_buffer = NULL;
	}

	return ret;
}

/**
 * @fn int TZ_HW_Init_R(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 and sets the hdcp2 flag by initializing the trustzone
 * @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_Init_R(const u8 command, u8 *request, const u32 req_size,
			u8 *response, u32 *res_size)
{
	return TZ_HW_Init_T(command, request, req_size, response, res_size);
}

/**
 * @fn int TZ_HW_Reset_R(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function resets the trustzone, releasing all the secure resources.
 * @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_Reset_R(const u8 command, u8 *request, const u32 req_size,
			u8 *response, u32 *res_size)
{
	tlApiResult_t ret_dr;
	*res_size = 0;

	if (hdcp2_ctx.is_buffer_protection) {
		ret_dr = HDCP2_OK;

		if (ret_dr != TLAPI_OK) {
			LOGE("[ERROR]tlApiSecStopContentPathProtection error. [return value] = %d \n", ret_dr);
			return HDCP2_ERR_HW_RESET;
		}
		hdcp2_ctx.is_buffer_protection = 0;
		hdcp2_ctx.is_video_played = 0;
		LOGI("OBP Stop\n");
	}

	*res_size = 0;

	return HDCP2_OK;
}

/**
 * @fn int TZ_HW_Close_R(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_R(const u8 command, u8 *request, const u32 req_size,
			u8 *response, u32 *res_size)
{
	if (TZ_HW_Reset_R(command, request, req_size, response, res_size) != HDCP2_OK)
		return HDCP2_ERR_HW_RESET;

	return TZ_HW_Close_T(command, request, req_size, response, res_size);
}

/**
 * @fn int TZ_HDCP2_LOADKEY_R(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_R(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_SET_HDCP_VERSION_R(const u8 command, u8 *request, const 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_R: Error, Invalid Req size (%d)\n", req_size);
		return HDCP2_ERR_INVALID_INPUT;
	}

	hdcp2_ctx.version = request[1];
	LOGI("TZ_SET_HDCP_VERSION_R : HDCP %d.%d version is setuped \n", hdcp2_ctx.version / 10, hdcp2_ctx.version % 10);

	return HDCP2_OK;
}

/**
 * @fn int TZ_AKE_Init_R(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function Copies rtx sent by transmitter to the TZ HDCP Context.
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request containing AKE_INIT 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_Init_R(const uint8_t command, uint8_t *request, const u32 req_size,
			uint8_t *response, uint32_t *res_size)
{
	AKE_INIT *p = (AKE_INIT *) request;

	NULL_ERR(p, HDCP2_TZ_NULL_RESPONSE);
	if (req_size != sizeof(AKE_INIT)) {
		LOGE("TZ_AKE_Init_R: Error, Invalid Req size (%d)\n", req_size);
		return HDCP2_ERR_INVALID_INPUT;
	}

	/* Reset Context */
	memset(&hdcp2_ctx, 0, sizeof(TZ_HDCP2_CTX));
	memcpy(hdcp2_ctx.rtx, p->rtx, sizeof(hdcp2_ctx.rtx));

	return HDCP2_OK;
}

/**
 * @fn int TZ_AKE_Transmitter_Info_R(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief  This function Copies transmitter info received into TZ HDCP Context.
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request containing AKE_TRANSMITTER_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_Transmitter_Info_R(const uint8_t command, uint8_t *request,
			const u32 req_size, uint8_t *response, uint32_t *res_size)
{
	if (req_size != sizeof(AKE_TRANSMITTER_INFO)) {
		LOGE("Error,AKE_TRANSMITTER_INFO data size (%d)\n", req_size);
		return HDCP2_ERR;
	}
	AKE_TRANSMITTER_INFO *p = (AKE_TRANSMITTER_INFO *) request;
	NULL_ERR(p, HDCP2_TZ_NULL_REQUEST);

	memcpy(&hdcp2_ctx.transmitter_info, p, sizeof(AKE_TRANSMITTER_INFO));
	//TRANSMITTER_LOCALITY_PRECOMPUTE_SUPPORT is bit0 of TRANSMITTER_CAPABILITY_MASK
	hdcp2_ctx.Tx_LC_Precompute = p->TRANSMITTER_CAPABILITY_MASK[1] & LOCALITY_PRECOMPUTE_SUPPORT;

	return HDCP2_OK;
}

/**
 * @fn int TZ_AKE_Send_Cert_R(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function Copies and sends receiver certificate to transmitter.
 * @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_SEND_CERT 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_Cert_R(const uint8_t command, uint8_t *request,
			const u32 req_size, uint8_t *response, uint32_t *res_size)
{
	AKE_SEND_CERT *p = (AKE_SEND_CERT *) response;
	*res_size = sizeof(AKE_SEND_CERT);

	NULL_ERR(p, HDCP2_TZ_NULL_RESPONSE);
	if (req_size != 1 /* entity */ && req_size != 2048 /* HDCP2_BUFFER_LEN */) {
		LOGE("TZ_AKE_Send_Cert_R: Error, Invalid Req size (%d)\n", req_size);
		return HDCP2_ERR_INVALID_INPUT;
	}

	p->msg_id = command;
	memcpy(p->certrx, &hdcp2_key.cert, sizeof(p->certrx));

	/*
	 * To support repeater we must check this value
	 */
	if (*request == 1) {
		p->REPEATER = 0x01;
		hdcp2_ctx.REPEATER = p->REPEATER;
	} else {
		p->REPEATER = 0x00;
	}

	return HDCP2_OK;
}

/**
 * @fn int TZ_AKE_Receiver_Info_R(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function Forms receiver information and sends it to transmitter.
 * @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_RECEIVER_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_Receiver_Info_R(const uint8_t command, uint8_t *request,
			const u32 req_size, uint8_t *response, uint32_t *res_size)
{
	AKE_RECEIVER_INFO *p = (AKE_RECEIVER_INFO *) response;
	*res_size = sizeof(AKE_RECEIVER_INFO);

	NULL_ERR(p, HDCP2_TZ_NULL_RESPONSE);
	memset(p, 0, *res_size);
	p->msg_id = command;
	p->LENGTH[1] = 6; // HDCP 2.1
	p->RECEIVER_CAPABILITY_MASK[0] = 0;
	p->RECEIVER_CAPABILITY_MASK[1] = 0x00;

	p->RECEIVER_CAPABILITY_MASK[1] |= LOCALITY_PRECOMPUTE_SUPPORT;

	if (hdcp2_ctx.version >= HDCP2_VERSION_2_2) {
		hdcp2_ctx.receiver_info.RECEIVER_CAPABILITY_MASK[0] = p->RECEIVER_CAPABILITY_MASK[0];
		hdcp2_ctx.receiver_info.RECEIVER_CAPABILITY_MASK[1] = p->RECEIVER_CAPABILITY_MASK[1];
	}

	p->VERSION = hdcp2_ctx.version - HDCP2_VERSION_2_0;

	hdcp2_ctx.receiver_info.VERSION = p->VERSION;
	hdcp2_ctx.Rx_LC_Precompute = p->RECEIVER_CAPABILITY_MASK[1] & LOCALITY_PRECOMPUTE_SUPPORT;

	LOGI("TZ_AKE_Receiver_Info_R : receiver_info.VERSION : 0x%02x \n", hdcp2_ctx.receiver_info.VERSION);

	return HDCP2_OK;
}

/**
 * @fn int TZ_AKE_No_Store_km_R(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function Receives Ekpub_km from transmitter and Decrypts it to get km using RSA_OAEP_decrypt and copies it to the TZ HDCP Context
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request containing AKE_NO_STORED_KM 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_No_Store_km_R(const uint8_t command, uint8_t *request,
			const u32 req_size, uint8_t *response, uint32_t *res_size)
{
	u8 dec[HDCP2_SIZE_RECEIVER_PUBKEY] = {0, };
	int ret = HDCP2_OK;

	if (req_size != sizeof(AKE_NO_STORED_KM)) {
		LOGE("Error, AKE_NO_STORED_KM data size (%d)\n", req_size);
		return HDCP2_ERR;
	}
	AKE_NO_STORED_KM *p = (AKE_NO_STORED_KM *) request;
	NULL_ERR(p, HDCP2_TZ_NULL_REQUEST);

	// 1. Decrypt Ekpub_km
	if ((ret = TZ_RSA_OAEP_decrypt(&hdcp2_ctx, &hdcp2_key, p->Ekpub_km, dec)) < 0)
		return ret;

	// 2. Copy decrypted buffer to hdcp2_ctx.pairing_info.km
	memcpy(hdcp2_ctx.pairing_info.km, dec, sizeof(hdcp2_ctx.pairing_info.km));

	TZ_LOG_HEX("km", hdcp2_ctx.pairing_info.km, sizeof(hdcp2_ctx.pairing_info.km));

	return HDCP2_OK;
}

/**
 * @fn int TZ_AKE_Store_km_R(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function Receives Ekh_km from transmitter and Decrypts it to get km and copies it to the TZ HDCP Context
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request containing AKE_STORED_KM 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_Store_km_R(const uint8_t command, uint8_t *request,
			const u32 req_size, uint8_t *response, uint32_t *res_size)
{
	int ret = HDCP2_OK;
	u32 length = 16;
	uint8_t kh[32] = {0, };

	if (req_size != sizeof(AKE_STORED_KM)) {
		LOGE("Error, AKE_STORED_KM data size (%d)\n", req_size);
		return HDCP2_ERR;
	}
	AKE_STORED_KM *p = (AKE_STORED_KM *) request;
	NULL_ERR(p, HDCP2_TZ_NULL_REQUEST);

	// 1. Copy payload
	memcpy(hdcp2_ctx.pairing_info.m, p->m, sizeof(p->m));
	memcpy(hdcp2_ctx.pairing_info.Ekm, p->Ekh_km, sizeof(p->Ekh_km));

	// 2. Decrypt and get km
	SHA256_CALCULATION(kh, (uint8_t *) &hdcp2_key.private_key, 128);

	ret = TZ_AES_ECB_decrypt(kh, 16, p->Ekh_km, 16, hdcp2_ctx.pairing_info.km, &length);

	TZ_LOG_HEX("kh", kh, 32);
	TZ_LOG_HEX("km", (uint8_t *) hdcp2_ctx.pairing_info.km, sizeof(hdcp2_ctx.pairing_info.km));

	return ret;
}

/**
 * @fn int TZ_AKE_Send_rrx_R(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function Generates and sends 8bytes of random number[rrx] to transmitter.
 * @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_SEND_RRX 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_rrx_R(const uint8_t command, uint8_t *request,
			const u32 req_size, uint8_t *response, uint32_t *res_size)
{
	AKE_SEND_RRX *p = (AKE_SEND_RRX *) response;
	*res_size = sizeof(AKE_SEND_RRX);

	NULL_ERR(p, HDCP2_TZ_NULL_RESPONSE);
	TZ_rand(hdcp2_ctx.rrx, sizeof(hdcp2_ctx.rrx));

	// Make payload
	p->msg_id = command;
	memcpy(p->rrx, hdcp2_ctx.rrx, sizeof(p->rrx));

	return HDCP2_OK;
}

/**
 * @fn int TZ_AKE_Send_h_prime_R(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function Generates H prime and send it to the transmitter as below eqn.
 * @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_SEND_H_PRIME 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_h_prime_R(const uint8_t command, uint8_t *request,
			const u32 req_size, uint8_t *response, uint32_t *res_size)
{
	uint8_t input[8] = {0, };
	AKE_SEND_H_PRIME *p = (AKE_SEND_H_PRIME *) response;
	*res_size = sizeof(AKE_SEND_H_PRIME);

	NULL_ERR(p, HDCP2_TZ_NULL_RESPONSE);

	// 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);

	if (hdcp2_ctx.version >= HDCP2_VERSION_2_2 && hdcp2_key.cert.Protocol_Descriptor == 0x01
		&& hdcp2_ctx.transmitter_info.VERSION >= 0x02) {
		u8 temp_input[14] = {0, };
		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));
		TZ_LOG_HEX("temp_input", temp_input, sizeof(temp_input));
		//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(p->H, hdcp2_ctx.kd, sizeof(hdcp2_ctx.kd), temp_input, sizeof(temp_input));
	} else {
		// input
		memcpy(input, hdcp2_ctx.rtx, sizeof(hdcp2_ctx.rtx));
		input[7] ^= hdcp2_ctx.REPEATER;
		TZ_LOG_HEX("input", input, 8);
		// HMAC-SHA256(rtx XOR REPEATER, kd)
		TZ_HMAC_SHA256(p->H, hdcp2_ctx.kd, sizeof(hdcp2_ctx.kd), input, sizeof(input));
	}

	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));
	TZ_LOG_HEX("h_prime", p->H, 32);
	p->msg_id = command;

	return HDCP2_OK;
}

/**
 * @fn int TZ_AKE_Send_Pairing_Info_R(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function Generates Ekh_km and send it to the transmitter.
 * @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_SEND_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_R(const uint8_t command, uint8_t *request,
			const u32 req_size, uint8_t *response, uint32_t *res_size)
{
	u32 length = 16;
	AKE_SEND_PAIRING_INFO *p = (AKE_SEND_PAIRING_INFO *) response;
	uint8_t kh[32] = {0, };
	*res_size = sizeof(AKE_SEND_PAIRING_INFO);

	NULL_ERR(p, HDCP2_TZ_NULL_RESPONSE);

	// make Ekh_km
	p->msg_id = command;
	
	SHA256_CALCULATION(kh, (uint8_t *) &hdcp2_key.private_key, 128);

	// encrypt
	TZ_AES_ECB_encrypt(kh, 16, hdcp2_ctx.pairing_info.km, 16, p->Ekh_Km, &length);
	//TZ_Encrypt_16(hdcp2_ctx.pairing_info.km, p->Ekh_Km, kh, 1);
	hdcp2_ctx.is_paired = 1;
	TZ_LOG_HEX("p->Ekh_km", p->Ekh_Km, sizeof(p->Ekh_Km));

	return HDCP2_OK;
}

/**
 * @fn int TZ_LC_Init_R(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function Copies received random value [rn] from transmitter
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request containing LC_INIT 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_Init_R(const uint8_t command, uint8_t *request, const u32 req_size,
			uint8_t *response, uint32_t *res_size)
{
	int i = 0;
	uint8_t key[32] = {0, };
	uint8_t L[32] = {0, };

	if (req_size != sizeof(LC_INIT)) {
		LOGE("Error, LC_INIT data size (%d)\n", req_size);
		return HDCP2_ERR;
	}
	LC_INIT *p = (LC_INIT *) request;

	NULL_ERR(p, HDCP2_TZ_NULL_REQUEST);

	// Copy payload
	memcpy(hdcp2_ctx.rn, p->rn, sizeof(p->rn));

	if (hdcp2_ctx.Rx_LC_Precompute && hdcp2_ctx.Tx_LC_Precompute && hdcp2_ctx.version >= HDCP2_VERSION_2_1) {
		// 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));
			//As per HDCP2.2 SPec: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); //L msb
		memcpy(hdcp2_ctx.L_lsb, L+16, 16);
		hdcp2_ctx.Precompute_flag = 1;
		TZ_LOG_HEX("hdcp2_ctx.L_msb", hdcp2_ctx.L_msb, sizeof(hdcp2_ctx.L_msb));
		TZ_LOG_HEX("hdcp2_ctx.L_lsb", hdcp2_ctx.L_lsb, sizeof(hdcp2_ctx.L_lsb));
	}

	return HDCP2_OK;
}

/**
 * @fn int TZ_RTT_READY_R(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function sends RTT_Ready message to transmitter when L' computation is complete.
 * @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_READY 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_READY_R(const uint8_t command, uint8_t *request,
			const u32 req_size, uint8_t *response, uint32_t *res_size)
{
	RTT_READY *p = (RTT_READY *) response;
	*res_size = sizeof(RTT_READY);
	NULL_ERR(p, HDCP2_TZ_NULL_RESPONSE);

	// Make payload
	p->msg_id = command;

	return HDCP2_OK;
}

/**
 * @fn int TZ_RTT_CHALLENGE_R(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function copies received least significant 128 bits of L from transmitter.
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request RTT_CHALLENGE message
 * @param req_size - size of request
 * @param response- pointer to response containing
 * @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_R(const uint8_t command, uint8_t *request, const u32 req_size,
			uint8_t *response, uint32_t *res_size)
{
	if (req_size != sizeof(RTT_CHALLENGE)) {
		LOGE("Error, RTT_CHALLENGE data size (%d)\n", req_size);
		return HDCP2_ERR;
	}
	RTT_CHALLENGE *rtt = (RTT_CHALLENGE *)request;
	NULL_ERR(rtt, HDCP2_TZ_NULL_REQUEST);

	if (memcmp(rtt->L_lsb, hdcp2_ctx.L_lsb, 16) != 0) //L lsb
		return HDCP2_ERR_INVALID_L;

	return HDCP2_OK;
}

/**
 * @fn int TZ_LC_Send_L_prime_R(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function calaculates L by equation : HMAC_SHA256(rn, (kd ^ rrx) )
 * @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_SEND_L_PRIME_PC 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_Send_L_prime_R(const uint8_t command, uint8_t *request,
			const u32 req_size, uint8_t *response, uint32_t *res_size)
{
	int i = 0;
	uint8_t key[32] = {0, };

	if (hdcp2_ctx.Precompute_flag == 1) {
		LC_SEND_L_PRIME_PC *p = (LC_SEND_L_PRIME_PC *) response;
		*res_size = sizeof(LC_SEND_L_PRIME_PC);

		NULL_ERR(p, HDCP2_TZ_NULL_RESPONSE);
		memcpy(p->L_msb, hdcp2_ctx.L_msb, 16);

		// Make payload
		p->msg_id = command;
	} else {
		LC_SEND_L_PRIME *p = (LC_SEND_L_PRIME *) response;
		*res_size = sizeof(LC_SEND_L_PRIME);

		NULL_ERR(p, HDCP2_TZ_NULL_RESPONSE);

		// 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];

		// Make payload
		p->msg_id = command;
		TZ_HMAC_SHA256(p->L, key, sizeof(key), hdcp2_ctx.rn,sizeof(hdcp2_ctx.rn));
	}

	return HDCP2_OK;
}

/**
 * @fn int TZ_SKE_Send_Eks_R(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function decrypts Eks using riv
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request containing SKE_SEND_EKS 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_SKE_Send_Eks_R(const uint8_t command, uint8_t *request,
			const u32 req_size, uint8_t *response, uint32_t *res_size)
{
	uint8_t H[32] = {0, };
	int i = 0;

	// check the request size according to hdcp version
	if (hdcp2_ctx.version > HDCP2_VERSION_2_3 || hdcp2_ctx.version < HDCP2_VERSION_2_0) {
		LOGE("TZ_SKE_Send_Eks_R: Can't support version (%d)\n", hdcp2_ctx.version);
		return HDCP2_ERR_INVALID_INPUT;
	}

	NULL_ERR(request, HDCP2_TZ_NULL_REQUEST);

	if (hdcp2_ctx.version == HDCP2_VERSION_2_3) {
		if (req_size != sizeof(SKE_SEND_EKS_VER23)) {
			LOGE("Error, SKE_SEND_EKS_VER23[%d] != req_size[%d]\n", sizeof(SKE_SEND_EKS_VER23), req_size);
			return HDCP2_ERR;
		}
		SKE_SEND_EKS_VER23 *p = (SKE_SEND_EKS_VER23 *) request;
		// 1. Copy request
		memcpy(hdcp2_ctx.riv, p->riv, sizeof(hdcp2_ctx.riv));
		// 2. HMAC_256 of riv
		TZ_HMAC_SHA256(H, hdcp2_ctx.kd, sizeof(hdcp2_ctx.kd), hdcp2_ctx.riv,
				sizeof(hdcp2_ctx.riv));
		TZ_LOG_HEX("HMAC_R", H, 32);
		TZ_LOG_HEX("HMAC_T", p->H, 32);

		if (memcmp(p->H, H, sizeof(H))) {
			LOGE("TZ_SKE_Send_Eks_R: Compare Hmac fail\n");
			return HDCP2_ERR_VERI_SKE;
		}
		// 3. Key Derivation (dkey2 <= ctr=2)
		TZ_Derivate_dkey(&hdcp2_ctx);
		TZ_LOG_HEX("dkey2", hdcp2_ctx.dkey, sizeof(hdcp2_ctx.dkey));

		// 4. ks = Eks ^ dkey2 ^ rrx[8-15]
		for (i = 0; i < 16; i++) {
			hdcp2_ctx.ks[i] = (i < 8) ? p->Eks[i] ^ hdcp2_ctx.dkey[i] : p->Eks[i]
					^ hdcp2_ctx.dkey[i] ^ hdcp2_ctx.rrx[i - 8];
		}
		TZ_LOG_HEX("Eks", p->Eks, sizeof(p->Eks));
	} else {
		if (req_size != sizeof(SKE_SEND_EKS)) {
			LOGE("Error, SKE_SEND_EKS[%d] != req_size[%d]\n", sizeof(SKE_SEND_EKS), req_size);
			return HDCP2_ERR;
		}
		SKE_SEND_EKS *p = (SKE_SEND_EKS *) request;
		// 1. Copy request
		memcpy(hdcp2_ctx.riv, p->riv, sizeof(hdcp2_ctx.riv));

		// 2. Key Derivation (dkey2 <= ctr=2)
		TZ_Derivate_dkey(&hdcp2_ctx);
		TZ_LOG_HEX("dkey2", hdcp2_ctx.dkey, sizeof(hdcp2_ctx.dkey));

		// 3. ks = Eks ^ dkey2 ^ rrx[8-15]
		for (i = 0; i < 16; i++) {
			hdcp2_ctx.ks[i] = (i < 8) ? p->Eks[i] ^ hdcp2_ctx.dkey[i] : p->Eks[i]
					^ hdcp2_ctx.dkey[i] ^ hdcp2_ctx.rrx[i - 8];
		}

		TZ_LOG_HEX("Eks", p->Eks, sizeof(p->Eks));
	}

	TZ_LOG_HEX("ks", hdcp2_ctx.ks, sizeof(hdcp2_ctx.ks));

	return HDCP2_OK;
}

/**
 * @fn int TZ_Is_Key_Frame(u8 *output_data, int length, int32_t *bIsKeyFrame, u32 codec_type)
 * @brief Checks whether the received frame is a key frame
 * @param output_data - pointer to the frame to be checked.
 * @param bIsKeyFrame - pointer where the value has to be set
 * @param codec_type - codec type
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int TZ_Is_Key_Frame(u8 *output_data, int length, int32_t *bIsKeyFrame, u32 codec_type)
{
	int ret = HDCP2_OK;
	int i;

	if (codec_type == 1) { // MPEG4 
		for (i = 0; i < (length - 5); i++) {
			if (output_data[i] == 0x00 && output_data[i + 1] == 0x00
				&& output_data[i + 2] == 0x01 && output_data[i + 3] == 0xb6) {
				// prefix = 0x00 0x00 0x01 , VOP start code = 0xb6
				// 2 bit mask : 0 means I FRAME
				if (((output_data[i + 4] >> 6) & 0x3) == 0) {
					*bIsKeyFrame = 1;
					break;
				} else {
					*bIsKeyFrame = 0;
					break;
				}
			}
		}
	} else if (codec_type == 2) { // 264
		for (i = 0; i < length - 5; i++) {
			// start code = 0x00 0x00 0x00 0x01
			if (output_data[i] == 0x00 && output_data[i + 1] == 0x00
				&& output_data[i + 2] == 0x00 && output_data[i + 3] == 0x01) {
				if ((output_data[i + 4] & 0x1f) == 5) { // 5 bit mask : 5 means I FRAME 
					*bIsKeyFrame = 2;
					break;
				} else {
					*bIsKeyFrame = 0;
				}
			} else if (output_data[i] == 0x00 && output_data[i + 1] == 0x00
						&& output_data[i + 2] == 0x01) { // start code = 0x00 0x00 0x01
				// 5 bit mask : 5 means I FRAME
				if ((output_data[i + 3] & 0x1f) == 5) {
					*bIsKeyFrame = 3;
					break;
				} else {
					*bIsKeyFrame = 0;
				}
			}
		}
	}

	return ret;
}

/**
 * @fn int TZ_DEC_Data(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function decrypts the encrypted data stream.
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request containing CIP_DATA_INFO_RX 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_DEC_Data(uint8_t command, uint8_t *request, const u32 req_size,
			uint8_t *response, uint32_t *res_size)
{
	int ret = 0;
	unsigned char pKey[16] = {0, };
	unsigned char p[16];
	tlApiResult_t ret_dr = 0;
#ifdef USE_HDCP2FLAG
	u32 hdmi_stat = 0;
#endif /* USE_HDCP2FLAG */
	CIP_DATA_INFO_RX *data = (CIP_DATA_INFO_RX *) request;

#ifdef USE_MTK
	uint64_t output_pa;
	uint64_t output_phys_fd = 0;
	uint64_t pool_pa, pool_size;
#endif /* USE_MTK */

	if (!data || !data->input || !data->length || !data->output) {
		LOGE("TZ_DEC_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_RX)) {
		LOGE("TZ_DEC_Data: Error, Invalid Req size (%d)\n", req_size);
		return HDCP2_ERR_INVALID_INPUT;
	}

	*res_size = data->length;

#ifdef USE_HDCP2FLAG
	// HDMI Cable Check
	// We allow decryption in Receiver only if HDMI is disconnected
	if (!hdcp2_ctx.REPEATER) {
		if (tlApiProtectionCheck(&hdmi_stat) != TLAPI_OK) {
			return HDCP2_ERR_HDMI;
		}
		if (hdmi_stat) {
			return HDCP2_ERR_HDMI;
		}
	}
#endif /* USE_HDCP2FLAG */

	if (TZ_Get_ContentKey(hdcp2_ctx.ks, hdcp2_key.lc128, pKey) != 0)
		return HDCP2_ERR_CRYPTO;

	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);

	if (!hdcp2_ctx.is_buffer_protection) {
		ret_dr = HDCP2_OK;

		if (ret_dr != TLAPI_OK) {
			return HDCP2_ERR_BUFFER_PROTECTION;
		}
		hdcp2_ctx.is_buffer_protection = 1;
	}

	if (hdcp2_ctx.type1_stream != 0x01) {
#ifdef USE_MTK
		output_phys_fd = data->output;

		if (drMemPAQueryByType(output_phys_fd, &output_pa, MEM_SEC) != 0) {
			LOGE("TZ_DEC_Data: Error, mapping error\n");
			return HDCP2_ERR_INVALID_INPUT;
		}
		if (output_pa == 0) {
			LOGE("TZ_DEC_Data: Error, input address error (%llx)\n", output_pa);
			return HDCP2_ERR_INVALID_INPUT;
		}

		if (drMemPoolQueryByType(&pool_pa, &pool_size, MEM_SEC) != 0) {
			LOGE("TZ_DEC_Data: Error, mapping size error\n");
			return HDCP2_ERR_INVALID_INPUT;
		}
		if (!(pool_pa <= output_pa && output_pa < (pool_pa + pool_size))) {
			LOGE("TZ_ENC_Data: Error, address error (%llx)/(%llx)/(%llx)\n",
						output_pa, pool_pa, pool_size);
//			return HDCP2_ERR_INVALID_INPUT;
		}

		LOGD("output pa= %llx, pool_pa = %x, pool_size = %x\n", output_pa, pool_pa, pool_size); 
		ret = TZ_Cipher_AES_CTR_Decrypt((u8 *)(request + req_size), data->length, output_pa, res_size, pKey, p);
#else
		ret = TZ_Cipher_AES_CTR_Decrypt(data->input, data->length, data->output, res_size, pKey, p);
#endif /* USE_MTK */
	}

	LOGD("Decrypted.. type=%d, inlen=%d, ret=%d\n", data->dec_type, data->length, ret);

	return ret;
}

/**
 * @fn int TZ_DEC_Data_Vir(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function decrypts the encrypted non secure data.
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request containing CIP_DATA_INFO_VIR 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_DEC_Data_Vir(uint8_t command, uint8_t *request, const u32 req_size,
			uint8_t *response, uint32_t *res_size)
{
	int ret = 0;
	unsigned char pKey[16] = {0, };
	unsigned char p[16];
	int bIsKeyFrame = 0;
	u32 length = 0;

	CIP_DATA_INFO_VIR *data = (CIP_DATA_INFO_VIR *) request;
	if (data->dec_type != DEC_TYPE_CHECK_KEY_FRAME && data->dec_type != DEC_TYPE_AUDIO)
		return HDCP2_ERR_INVALID_INPUT;

	if (data->dec_type == DEC_TYPE_CHECK_KEY_FRAME)
		LOGD("type=%d, length=%d, code_type=%d\n", data->dec_type, data->length, data->codec_type);

	ret = TZ_Get_ContentKey(hdcp2_ctx.ks, hdcp2_key.lc128, pKey);
	if (ret != 0) {
		return HDCP2_ERR_CRYPTO;
	}

	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);

	// decrypt frame header
	ret = TZ_SW_AES_CTR(data->input, data->length, data->output, &length, pKey, p);

	if (data->dec_type == DEC_TYPE_CHECK_KEY_FRAME) {
		TZ_Is_Key_Frame(data->output, data->length, &bIsKeyFrame, data->codec_type);
		if (bIsKeyFrame >= 0)
			ret = bIsKeyFrame;

		LOGD("END....bIsKeyFrame = %d, ret = %d\n", bIsKeyFrame, ret);
	}

	return ret;
}

/**
 * @fn int TZ_DEC_Data_Audio(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function decrypts the encrypted audio.
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request containing CIP_DATA_INFO_RX 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_DEC_Data_Audio(uint8_t command, uint8_t *request, const u32 req_size,
			uint8_t *response, uint32_t *res_size)
{
	int ret = 0;
	unsigned char pKey[16] = {0, };
	unsigned char p[16];
	u32 length = 0;

	CIP_DATA_INFO_RX *data = (CIP_DATA_INFO_RX *) request;
	if (data->dec_type != DEC_TYPE_AUDIO)
		return HDCP2_ERR_INVALID_INPUT;


	ret = TZ_Get_ContentKey(hdcp2_ctx.ks, hdcp2_key.lc128, pKey);
	if (ret != 0) {
		return HDCP2_ERR_CRYPTO;
	}

	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);

	/* decrypt frame header
	 * decryption is same as encryption for AES CTR mode, but
	 * S.LSI decryption checks whether the output is secure or not
	 * so we skip the buffer check by using encrypt function*/
#ifdef USE_MTK
	ret = TZ_Cipher_AES_CTR_Encrypt(data->input, data->length, request, &length, pKey, p);
#else
	ret = TZ_Cipher_AES_CTR_Encrypt(data->input, data->length, data->output, &length, pKey, p);
#endif /* USE_MTK */
	*res_size = length;

	return ret;
}

/**
 * @fn int TZ_RepeaterAuth_Send_ReceiverId_List_Rep(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 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_Rep(const u8 command, u8 *request,
			const u32 req_size, u8 *response, u32 *res_size)
{
	int ret;

	if (hdcp2_ctx.version >= HDCP2_VERSION_2_1)
		ret = TZ_RepeaterAuth_Send_ReceiverId_List21_Rep(response,res_size);
	else
		ret = TZ_RepeaterAuth_Send_ReceiverId_List20_Rep(response,res_size);

	return ret;
}

/**
 * @fn int TZ_RepeaterAuth_Send_ReceiverId_List20_Rep(uint8_t *response, u32 *res_size)
 * @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
 * @param req_size - size of request
 * @param response- pointer to response containing REPEATERAUTH_SEND_RECEIVER_ID_LIST20 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_ReceiverId_List20_Rep(uint8_t *response, u32 *res_size)
{
	u8 V[32] = {0, };
	u8 input[159] = {0, };
	u8 offset=0;
	u8 totalSize = 0;
	tlApiResult_t ret_dr;

	REPEATERAUTH_SEND_RECEIVER_ID_LIST20 *recidinfo = (REPEATERAUTH_SEND_RECEIVER_ID_LIST20 *) response;
	NULL_ERR(response, HDCP2_ERR_NULL_REQUEST);

	recidinfo->msg_id = 0x0c;

	/*
	 * hardcoding below parameters since present requirement
	 * of a single Tx-Repeater-Rx communication.
	 * can be updated real time when we can count the number
	 * for sessions created from repeater.
	 * */
	recidinfo->DEVICE_COUNT = 0x01;
	recidinfo->DEPTH = 0x01;

	//max 31 devices
	if ((recidinfo->DEVICE_COUNT) <= 0x1F) {
		recidinfo->MAX_DEVS_EXCEEDED = 0x00;
	} else {
		recidinfo->MAX_DEVS_EXCEEDED = 0x01;
	}

	*res_size =  HDCP_FIXED_SIZE_REPEATERAUTH_SEND_RECEIVERID_LIST20 + (recidinfo->DEVICE_COUNT)*RECEIVER_ID_SIZE;

	// max 4 level of devices
	if ((recidinfo->DEPTH) <= 0x04) {
		recidinfo->MAX_CASCADE_EXCEEDED = 0x00;
	} else {
		recidinfo->MAX_CASCADE_EXCEEDED = 0x01;
	}

	ret_dr = tlApiSecHdcpBksv(recidinfo->RECEIVER_IDs[0].RECEIVER_IDj);
	if (ret_dr != TLAPI_OK) {
		return HDCP2_ERR_BKSV_READ_FAIL;
	}

	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);

	memcpy(recidinfo->V_PRIME, V, sizeof(V));

	return HDCP2_OK;
}

/**
 * @fn int TZ_RepeaterAuth_Send_ReceiverId_List21_Rep(uint8_t *response, u32 *res_size)
 * @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
 * @param req_size - size of request
 * @param response- pointer to response containing REPEATERAUTH_SEND_RECEIVER_ID_LIST21 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_ReceiverId_List21_Rep(uint8_t *response, u32 *res_size)
{
	u8 V[32] = {0, };
	u8 input[164] = {0, };
	u8 totalSize = 0;
	u8 offset=0;
	tlApiResult_t ret_dr;

	REPEATERAUTH_SEND_RECEIVER_ID_LIST21 *recidinfo = (REPEATERAUTH_SEND_RECEIVER_ID_LIST21 *) response;
	NULL_ERR(response, HDCP2_ERR_NULL_REQUEST);

	hdcp2_ctx.seq_num_V[2]++;

	recidinfo->msg_id = 0x0c;

	/*
	 * hardcoding below parameters since present requirement
	 * of a single Tx-Repeater-Rx communication.
	 * can be updated real time when we can count the number
	 * for sessions created from repeater.
	 * */
	recidinfo->DEVICE_COUNT = 0x01;
	recidinfo->DEPTH = 0x01;
	//Hardcoding end

	//max 31 devices
	if ((recidinfo->DEVICE_COUNT) <= 0x1F) {
		recidinfo->MAX_DEVS_EXCEEDED = 0x00;
	} else {
		recidinfo->MAX_DEVS_EXCEEDED = 0x01;
	}

	*res_size = HDCP_FIXED_SIZE_REPEATERAUTH_SEND_RECEIVERID_LIST21 + (recidinfo->DEVICE_COUNT)*RECEIVER_ID_SIZE;
	// max 4 level of devices
	if ((recidinfo->DEPTH) <= 0x04) {
		recidinfo->MAX_CASCADE_EXCEEDED = 0x00;
	} else {
		recidinfo->MAX_CASCADE_EXCEEDED = 0x01;
	}

	//not supporting this
	recidinfo->HDCP2_LEGACY_DEVICE_DOWNSTREAM = 0x00;
	// end device is HDMI compatible, hence acts as HDCP 1.x device
	recidinfo->HDCP1_DEVICE_DOWNSTREAM = 0x01;

	ret_dr = tlApiSecHdcpBksv(recidinfo->RECEIVER_IDs[0].RECEIVER_IDj);
	if (ret_dr != TLAPI_OK) {
		return HDCP2_ERR_BKSV_READ_FAIL;
	}

	memcpy(recidinfo->seq_num_V, hdcp2_ctx.seq_num_V,
			sizeof(recidinfo->seq_num_V));

	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));
	memcpy(recidinfo->V_PRIME, V, 16);
	memcpy(hdcp2_ctx.repeater_ack, V + 16, 16);
	TZ_LOG_HEX("V' MSB to Tx", recidinfo->V_PRIME, sizeof(recidinfo->V_PRIME));

	return HDCP2_OK;
}

/**
 * @fn int TZ_RepeaterAuth_Send_Ack_Rep(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function receives an acknowledgment from the transmitter
 * @param command - The command to be executed, sent from NWD
 * @param request- pointer to request containing REPEATERAUTH_SEND_ACK 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_Send_Ack_Rep(const u8 command, u8 *request,
			const u32 req_size, u8 *response, u32 *res_size)
{
	REPEATERAUTH_SEND_ACK *send_ack = (REPEATERAUTH_SEND_ACK *) request;
	NULL_ERR(send_ack, HDCP2_ERR_NULL_RESPONSE);

	if (memcmp(send_ack->V, hdcp2_ctx.repeater_ack, 16))
		hdcp2_ctx.reauth_request = 0x01; //request for reauthentication

	return HDCP2_OK;
}

/**
 * @fn int TZ_Receiver_AuthStatus_Rep(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 containing REPEATERAUTH_SEND_ACK 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_Receiver_AuthStatus_Rep(const u8 command, u8 *request,
			const u32 req_size, u8 *response, u32 *res_size)
{
	u8 LENGTH[2] = { 0X00, 0x04 }; //default value in HDCP 2.1
	RECEIVER_AUTHSTATUS *status = (RECEIVER_AUTHSTATUS *) response;
	NULL_ERR(status, HDCP2_ERR_NULL_REQUEST);
	*res_size = sizeof(RECEIVER_AUTHSTATUS);

	status->msg_id = command; //0x12;
	memcpy(status->LENGTH, LENGTH, sizeof(status->LENGTH));
	status->REAUTH_Req = hdcp2_ctx.reauth_request;

	return HDCP2_OK;
}

/**
 * @fn int TZ_RepeaterAuth_Stream_Manage_Rep(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 containing REPEATERAUTH_STREAM_MANAGE 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_Manage_Rep(const u8 command, u8 *request,
			const u32 req_size, u8 *response, u32 *res_size)
{
	if (req_size != sizeof(REPEATERAUTH_STREAM_MANAGE)) {
		LOGE("Error, RepeaterAuth data size (%d)\n", req_size);
		return HDCP2_ERR;
	}
	u8 kd[32] = {0, };
	u8 input[115] = {0, };
	u8* temp_ptr = input;
	int i = 0;

	//hdcp2_ctx.type1_stream = 0;
	REPEATERAUTH_STREAM_MANAGE *send_msg = (REPEATERAUTH_STREAM_MANAGE *) request;
	NULL_ERR(send_msg, HDCP2_ERR_NULL_RESPONSE);

	if (send_msg->k[1] > 16) {
		LOGE("Error, K max size\n");
		return HDCP2_ERR;
	}

	//size is hdcp2_ctx.no_of_streams*7 + 3
	//calculate input
	for (i = 0; i < send_msg->k[1]; i++) {
		memcpy(temp_ptr, send_msg->max_k_info[i].streamCtrj,
				sizeof(send_msg->max_k_info[i].streamCtrj));
		memcpy(temp_ptr + sizeof(send_msg->max_k_info[i].streamCtrj),
				send_msg->max_k_info[i].ContentStreamIDj, sizeof(send_msg->max_k_info[i].ContentStreamIDj));
		memcpy(temp_ptr + sizeof(send_msg->max_k_info[i].streamCtrj)
						+ sizeof(send_msg->max_k_info[i].ContentStreamIDj),
				&(send_msg->max_k_info[i].Type), sizeof(send_msg->max_k_info[i].Type));
		temp_ptr = temp_ptr + sizeof(send_msg->max_k_info[i].streamCtrj)
				+ sizeof(send_msg->max_k_info[i].ContentStreamIDj)
				+ sizeof(send_msg->max_k_info[i].Type);

		if (send_msg->max_k_info[i].Type == 0x01) {
			hdcp2_ctx.type1_stream = 1;
			hdcp2_ctx.type1_set = 1;
			LOGI("hdcp2_ctx.type1_stream is set to 1\n");
		} else {
			hdcp2_ctx.type1_stream = 0;
		}
	}

	memcpy(temp_ptr, send_msg->seq_num_M, sizeof(send_msg->seq_num_M));
	SHA256_CALCULATION(kd, (uint8_t*) &hdcp2_ctx.kd, 32);

	TZ_HMAC_SHA256(hdcp2_ctx.M, kd, sizeof(kd), input, (send_msg->k[1] * 7 + 3));

	return HDCP2_OK;
}

/**
 * @fn int TZ_RepeaterAuth_Stream_Ready_Rep(const uint8_t command, uint8_t *request,const u32 req_size, uint8_t *response, uint32_t *res_size);
 * @brief This function sends M- prime to the transmitter
 * @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_READY 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_Ready_Rep(const u8 command, u8 *request,
			const u32 req_size, u8 *response, u32 *res_size)
{
	REPEATERAUTH_STREAM_READY *status = (REPEATERAUTH_STREAM_READY *) response;
	NULL_ERR(status, HDCP2_ERR_NULL_REQUEST);
	*res_size = sizeof(REPEATERAUTH_STREAM_READY);

	status->msg_id = command;
	memcpy(status->M_PRIME, hdcp2_ctx.M, sizeof(hdcp2_ctx.M));

	if(hdcp2_ctx.type1_stream == 1) {
		return HDCP2_TYPE1_CONTENT;
	} else if ((hdcp2_ctx.type1_set == 1) && (hdcp2_ctx.type1_stream == 0)) {
		hdcp2_ctx.type1_set = 0;
		return HDCP2_TYPE0_CONTENT;
	} else {
		return HDCP2_OK;
	}
}
