/**
 * 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 hdcp2_transmitter.cpp
 * @author
 * @date
 * @brief This file contains Authentication messages functions for Transmitter which interact with TrustZone.
 */

#include <hdcp2.h>
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <unistd.h>
#include <sys/time.h>

#ifdef USE_MTK
#include "properties.h"
#endif /* USE_MTK */

#ifdef HDCP2_PROFILE_ENCRYPT_TIME
extern unsigned long long total_duration;
extern unsigned long long enc_count;
extern unsigned long long total_lengh;
#endif /* HDCP2_PROFILE_ENCRYPT_TIME */

/**
 * @def SRM_ENABLED
 *
 * This macro is assigned value 0 to indicate SRM is not enabled.
 */
//#define SRM_ENABLED 0

/**
 * @fn int AKE_Init_T(HDCP2_Ctx *hdcp, u8 *payload)
 * @brief This function initiates the authentication from transmitter by sending the initiation message which contains 64 bit pseudo random value
 * @param hdcp - pointer to HDCP context
 * @param payload - pointer to the buffer containing  AKE_INIT message to be sent to receiver
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int AKE_Init_T(HDCP2_Ctx *hdcp, u8 *payload)
{
	int length = 0, ret = 0;

	if (HDCP2_IsClosed(hdcp))
		return HDCP2_ERR_CLOSED;

	length = TZ_COMMAND_T(CMD_AKE_INIT, NULL, 0, payload, sizeof(AKE_INIT));

	//setting swd version corresponding to nwd
	ret = HDCP2_SetVersion(hdcp);

	if (ret != HDCP2_OK) {
		HDCP2_Log(" Tx CMD_SET_HDCP_VERSION Failed [%d]!!!",hdcp->entity);
		return HDCP2_ERR;
	}

	HDCP2_LogHex("[T>>>R] AKE_Init", payload, sizeof(AKE_INIT));
	return length;
}

/**
 * @fn int AKE_Tramsmitter_Info_T(HDCP2_Ctx *hdcp, u8 *payload);
 * @brief This function sends the transmitter info to the receiver
 * @param hdcp - pointer to HDCP context
 * @param payload - pointer to the buffer containing  AKE_TRANSMITTER_INFO message to be sent to receiver
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int AKE_Tramsmitter_Info_T(HDCP2_Ctx *hdcp, u8 *payload)
{
	int ret = 0;

	u8 Precompute_check[2] = {0} ;

	/* Note: Pre-compute is disabled because of issue with 2013 TV */
	hdcp->disable_Precompute = 1;

	Precompute_check[0] = CMD_AKE_TRANSMITTER_INFO;
	Precompute_check[1] = hdcp->disable_Precompute;

	if (HDCP2_IsClosed(hdcp))
		return HDCP2_ERR_CLOSED;

	ret = TZ_COMMAND_T(CMD_AKE_TRANSMITTER_INFO,
			Precompute_check,
			sizeof(Precompute_check),
			payload,
			sizeof(AKE_TRANSMITTER_INFO));

	HDCP2_LogHex("[T>>>R] AKE_Tramsmitter_Info", payload,
			sizeof(AKE_TRANSMITTER_INFO));

	AKE_TRANSMITTER_INFO *ake_tx_info = (AKE_TRANSMITTER_INFO *) payload;
	//TRANSMITTER_LOCALITY_PRECOMPUTE_SUPPORT is bit0 of TRANSMITTER_CAPABILITY_MASK
	hdcp->Tx_LC_Precompute = ake_tx_info->TRANSMITTER_CAPABILITY_MASK[1] & LOCALITY_PRECOMPUTE_SUPPORT;

	return ret;
}

#ifdef SRM_ENABLED
/**
 * @fn int HDCP2_SRM_Check(u8 *receiverID)
 * @brief This function checks if the receiver ID is blacklisted
 * @param receiverID - pointer to receiver ID
 * @param device_count - no. of devices attached
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int HDCP2_SRM_Check(u8 *receiverID, u8 device_count )
{

	FILE *pfile = NULL;
	int result = HDCP2_OK;
	long lSize;
	u8 * pbuffer = NULL;
	u32 no_of_REc_Ids;
	u32 offset = 0;
	int i;

	//SRM file in the location /system/etc/srm.bin
	pfile = fopen(HDCP_SRM_FILE, "rb");

	if (pfile == NULL) {
		HDCP2_Log("[T] SRM_Check: error opening the file");
		return HDCP2_ERR_NO_SRM_FILE;
	}

	fseek(pfile, 0, SEEK_END); //to calculate the entire file size
	lSize = ftell(pfile);
	if (lSize == -1) {
		fclose(pfile);
		return -1;
	}
	//HDCP2_Log("[T] SRM_Check: lSize=%ld", lSize);
	rewind(pfile);

	// allocate memory to contain the whole file:
	pbuffer = (u8*) malloc(sizeof(u8) * lSize);

	if (pbuffer == NULL) {
		HDCP2_Log("[T] SRM_Check: error in memory allocation");
		result = HDCP2_ERR_SRM_BUFFER_MEMORY_FAIL;
		goto done;
	}

	// copy the file into the buffer:
	result = fread(pbuffer, 1, lSize, pfile);

	if (result != lSize) {
		HDCP2_Log("[T] SRM_Check: error in fread");
		result = HDCP2_ERR_SRM_CHECK_FAIL;
		goto done;
	}

	/* the whole file is now loaded in the memory buffer. */

	// No of receivers ids which are blacklisted
	no_of_REc_Ids = (((*(pbuffer + 8)) << 2) & 0xfffc)
			| (((*(pbuffer + 9)) >> 6) & 0x03);
	//HDCP2_Log("[T] SRM_Check: no_of_REc_Ids=%d", no_of_REc_Ids);

	//trying to compare the receiver ID which are blacklisted
	offset += 12;
	int j;

	for (j = 0; j < device_count ; j++){
		for (i = 0; i < no_of_REc_Ids; i++) {
			if (memcmp(pbuffer + offset, receiverID + j*5, 5) == 0) {
				HDCP2_Log("[T] SW_SRM_Check: ERROR: Receiver ID blacklisted");
				result = HDCP2_ERR_SRM_CHECK_FAIL;
				goto done;
			}
			offset += 5;
		}
	}

	HDCP2_Log("[T] SRM_Check: Receiver ID valid");

done:
	// terminate
	if (pfile)
		fclose(pfile);
	if (pbuffer)
		free(pbuffer);

	return result;
}
#endif /* SRM_ENABLED */

/**
 * @fn int AKE_Send_Cert_T(HDCP2_Ctx *hdcp, u8 *payload, u8 *received);
 * @brief A certificate is  received from the receiver which indicates whether the connected receiver is an HDCP receiver and also extracts Receiver ID
 * @param hdcp - pointer to HDCP context
 * @param payload - pointer to the buffer which is populated in transmitter, but here it is not being used and thus is always assigned NULL
 * @param received - pointer to the buffer containing AKE_SEND_CERT message
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int AKE_Send_Cert_T(HDCP2_Ctx *hdcp, u8 *payload, u8 *received)
{
	int ret = 0;
	AKE_SEND_CERT *cert = (AKE_SEND_CERT *) received;
	HDCP2_RECEIVER_CERTIFICATE *rc = (HDCP2_RECEIVER_CERTIFICATE *) cert->certrx;

	if (HDCP2_IsClosed(hdcp))
		return HDCP2_ERR_CLOSED;

#ifdef SRM_ENABLED
	ret = HDCP2_SRM_Check(rc->receiver_id,1);

	if ((ret == HDCP2_ERR_SRM_CHECK_FAIL)
		|| (ret == HDCP2_ERR_NO_SRM_FILE)
		|| (ret == HDCP2_ERR_SRM_BUFFER_MEMORY_FAIL))
		return ret;
#endif /* SRM_ENABLED */

	HDCP2_LogHex("[T<<<R] AKE_Send_Cert", received, sizeof(AKE_SEND_CERT));
	HDCP2_Log("[T] Protocol Descriptor : %d", rc->Protocol_Descriptor);
	ret = TZ_COMMAND_T(CMD_AKE_SEND_CERT, received, sizeof(AKE_SEND_CERT), NULL, 0);

	if (ret < HDCP2_OK)
		return ret;

	memcpy(hdcp->receiver_id, rc->receiver_id, sizeof(hdcp->receiver_id));

	HDCP2_DEBUG("[T] ID = %.2x%.2x%.2x%.2x%.2x",
			hdcp->receiver_id[0], hdcp->receiver_id[1],
			hdcp->receiver_id[2], hdcp->receiver_id[3], hdcp->receiver_id[4]);

#ifdef USE_QSEE_WRAP_WITH_SFS
	ret = TZ_COMMAND_T(CMD_AKE_SET_PAIRING_INFO, NULL, 0, NULL, 0);
	if (ret == HDCP2_OK) {
		HDCP2_Log("[T] Pairing Information is set");
		hdcp->is_paired = 1;
	}
	HDCP2_LogHex("[T] hdcp->encrypted_pairing", hdcp->encrypted_pairing, sizeof(hdcp->encrypted_pairing));
#else
	if (HDCP2_LoadPairingInfo(hdcp) == HDCP2_OK) {
		HDCP2_Log("[T] Pairing Information Loading");
		if (TZ_COMMAND_T(CMD_AKE_SET_PAIRING_INFO, hdcp->encrypted_pairing, sizeof(hdcp->encrypted_pairing), NULL, 0)) {
			HDCP2_Log("[T] Pairing Information can't be loaded. Remove it");
			HDCP2_Remove_Pair(hdcp);
			return HDCP2_ERR_LOAD_PAIRING_INFO3;
		}

		HDCP2_LogHex("[T] AKE_Set_Pairing_Info", hdcp->encrypted_pairing, sizeof(hdcp->encrypted_pairing));
	}
#endif /* USE_QSEE_WRAP_WITH_SFS */

	//Tx-Repeater Support
	hdcp->REPEATER = cert->REPEATER;
	HDCP2_Log("[T] REPEATER Flag = %x", hdcp->REPEATER);

#ifdef USE_QUALCOMM
	return HDCP2_OK;
#else
	return ret;
#endif /* USE_QUALCOMM */
}

/**
 * @fn int AKE_Receiver_Info_T(HDCP2_Ctx *hdcp, u8 *received)
 * @brief This function contains the information regarding compliance of receiver with various hdcp versions
 * @param hdcp - pointer to HDCP context
 * @param received - pointer to the buffer containing AKE_RECEIVER_INFO message received from receiver
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int AKE_Receiver_Info_T(HDCP2_Ctx *hdcp, u8 *received)
{
	int ret = HDCP2_OK;

	if (HDCP2_IsClosed(hdcp))
		return HDCP2_ERR_CLOSED;

	AKE_RECEIVER_INFO *ake_rx_info = (AKE_RECEIVER_INFO *) received;
	//RECEIVER_LOCALITY_PRECOMPUTE_SUPPORT is bit0 of RECEIVER_CAPABILITY_MASK
	hdcp->Rx_LC_Precompute = ake_rx_info->RECEIVER_CAPABILITY_MASK[1] & LOCALITY_PRECOMPUTE_SUPPORT;

	HDCP2_LogHex("[T<<<R] AKE_Receiver_Info", received,
			sizeof(AKE_RECEIVER_INFO));

	HDCP2_Log("[T] Receiver HDCP version is : 2.%d", ake_rx_info->VERSION);

	ret = TZ_COMMAND_T(CMD_AKE_RECEIVER_INFO, received, sizeof(AKE_RECEIVER_INFO), NULL, 0);

	return ret;
}

/**
 * @fn int AKE_No_Stored_km_T(HDCP2_Ctx *hdcp, u8 *payload)
 * @brief This function is called when transmitter does not have 128 bit master key stored corresponding to the receiver ID.
 * @param hdcp - pointer to HDCP context
 * @param payload - pointer to the buffer containing AKE_NO_STORED_KM message
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int AKE_No_Stored_km_T(HDCP2_Ctx *hdcp, u8 *payload)
{
	int ret = HDCP2_OK;

	if (HDCP2_IsClosed(hdcp))
		return HDCP2_ERR_CLOSED;

	ret = TZ_COMMAND_T(CMD_AKE_NO_STORED_KM, NULL, 0, payload, sizeof(AKE_NO_STORED_KM));

	HDCP2_LogHex("[T>>>R] AKE_No_Stored_km", payload, sizeof(AKE_NO_STORED_KM));
	return ret;
}

/**
 * @fn int AKE_Stored_km_T(HDCP2_Ctx *hdcp, u8 *payload)
 * @brief This function is called when transmitter has 128 bit master key corresponding to the receiver ID.
 *  Here AKE_Stored_km message is sent to receiver with 128 bit encrypted master key and 128 bit  corresponding to the Receiver ID of the receiver.
 * @param hdcp - pointer to HDCP context
 * @param payload - pointer to the buffer containing AKE_STORED_KM message
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int AKE_Stored_km_T(HDCP2_Ctx *hdcp, u8 *payload)
{
	int ret = HDCP2_OK;

	if (HDCP2_IsClosed(hdcp))
		return HDCP2_ERR_CLOSED;

	ret = TZ_COMMAND_T(CMD_AKE_STORED_KM, NULL, 0, payload, sizeof(AKE_STORED_KM));

	HDCP2_LogHex("[T>>>R] AKE_Stored_km", payload, sizeof(AKE_STORED_KM));
	return ret;
}

/**
 * @fn int AKE_Send_rrx_T(HDCP2_Ctx *hdcp, u8 *received)
 * @brief This function receives AKE_Send_rrx message from receiver containing the 64 bit pseudo random value
 * @param hdcp - pointer to HDCP context
 * @param received - pointer to the buffer containing AKE_SEND_RRX message received from receiver
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int AKE_Send_rrx_T(HDCP2_Ctx *hdcp, u8 *received)
{
	int ret = HDCP2_OK;

	if (HDCP2_IsClosed(hdcp))
		return HDCP2_ERR_CLOSED;

	HDCP2_LogHex("[T<<<R] AKE_Send_rrx", received, sizeof(AKE_SEND_RRX));

	ret = TZ_COMMAND_T(CMD_AKE_SEND_RRX, received, sizeof(AKE_SEND_RRX), NULL, 0);

	return ret;
}

/**
 * @fn int AKE_Send_H_prime_T(HDCP2_Ctx *hdcp, u8 *received)
 * @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 hdcp - pointer to HDCP context
 * @param received - pointer to the buffer containing AKE_SEND_H_PRIME message received from the receiver.
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int AKE_Send_H_prime_T(HDCP2_Ctx *hdcp, u8 *received)
{
	int ret = HDCP2_OK;

	if (HDCP2_IsClosed(hdcp))
		return HDCP2_ERR_CLOSED;

	HDCP2_LogHex("[T<<<R] AKE_Send_H_prime", received, sizeof(AKE_SEND_H_PRIME));

	ret = TZ_COMMAND_T(CMD_AKE_SEND_H_PRIME, received, sizeof(AKE_SEND_H_PRIME), NULL, 0);

	if (ret == HDCP2_ERR_INVALID_H || ret == HDCP2_ERR)
		HDCP2_Remove_Pair(hdcp);

	return ret;
}

/**
 * @fn int AKE_Send_Pairing_Info_T(HDCP2_Ctx *hdcp, u8 *received)
 * @brief This function receives AKE_SEND_PAIRING_INFO message from receiverwhich contains 128 bit Ekh(km).
 * @param hdcp - pointer to HDCP context
 * @param received - pointer to to the buffer containing AKE_SEND_PAIRING_INFO message received from the receiver.
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int AKE_Send_Pairing_Info_T(HDCP2_Ctx *hdcp, u8 *received)
{
	int ret = HDCP2_OK;

	if (HDCP2_IsClosed(hdcp))
		return HDCP2_ERR_CLOSED;

	HDCP2_LogHex("[T<<<R] AKE_Send_Pairing_Info.", received,
			sizeof(AKE_SEND_PAIRING_INFO));

	if ((ret = TZ_COMMAND_T(CMD_AKE_SEND_PAIRING_INFO, received, sizeof(AKE_SEND_PAIRING_INFO),
						hdcp->encrypted_pairing, sizeof(HDCP2_PAIRING_INFO))) < 0)
		return ret;

	HDCP2_LogHex("[T] Encrypted_Pairing_Info", hdcp->encrypted_pairing,
			sizeof(hdcp->encrypted_pairing));

	gettimeofday((struct timeval *) &hdcp->time_pairing_done, NULL);

#ifdef USE_QSEE_WRAP_WITH_SFS
	return ret;
#else
	return HDCP2_Store_Pairing_Info(hdcp);
#endif /* USE_QSEE_WRAP_WITH_SFS */
}

/**
 * @fn int LC_Init_T(HDCP2_Ctx *hdcp, u8 *payload)
 * @brief This function initiates locality check by sending a message containing 64 bit pseudo random number to hdcp receiver
 * @param hdcp - pointer to HDCP context
 * @param payload - pointer to the buffer containing LC_INIT message to be sent
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int LC_Init_T(HDCP2_Ctx *hdcp, u8 *payload)
{
	int ret = HDCP2_OK;

	if (HDCP2_IsClosed(hdcp))
		return HDCP2_ERR_CLOSED;

	ret = TZ_COMMAND_T(CMD_LC_INIT, NULL, 0, payload, sizeof(LC_INIT));

	HDCP2_LogHex("[T>>>R] LC_Init", payload, sizeof(LC_INIT));

	return ret;
}

/**
 * @fn int RTT_Ready_T(HDCP2_Ctx *hdcp, u8 *received);
 * @brief This functions function receives the message when receiver is ready to send L-prime
 * @param hdcp - pointer to HDCP context
 * @param received - pointer to buffer containg RTT_READY message received from the receiver.
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int RTT_Ready_T(HDCP2_Ctx *hdcp, u8 *received)
{
	int ret = HDCP2_OK;

	if (HDCP2_IsClosed(hdcp))
		return HDCP2_ERR_CLOSED;

	HDCP2_LogHex("[T<<<R] RTT_READY", received, sizeof(RTT_READY));

	return ret;
}


/**
 * @fn int RTT_Challenge_T(HDCP2_Ctx *hdcp, u8 *payload);
 * @brief This function sends the message containing the least significant 128 bits of L to the receiver
 * @param hdcp - pointer to HDCP context
 * @param payload - pointer to the buffer containing RTT_CHALLENGE message
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int RTT_Challenge_T(HDCP2_Ctx *hdcp, u8 *payload)
{
	int ret = HDCP2_OK;

	if (HDCP2_IsClosed(hdcp))
		return HDCP2_ERR_CLOSED;

	ret = TZ_COMMAND_T(CMD_RTT_CHALLENGE, NULL, 0, payload, sizeof(RTT_CHALLENGE));

	HDCP2_LogHex("[T>>>R] RTT_CHALLENGE", payload, sizeof(RTT_CHALLENGE));
	return ret;
}

/**
 * @fn int LC_Send_L_prime_T(HDCP2_Ctx *hdcp, u8 *received)
 * @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 hdcp - pointer to HDCP context
 * @param received - pointer to buffer containing LC_SEND_L_PRIME message received from the receiver.
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int LC_Send_L_prime_T(HDCP2_Ctx *hdcp, u8 *received)
{
	int ret = HDCP2_OK;

	if (HDCP2_IsClosed(hdcp))
		return HDCP2_ERR_CLOSED;

	if (hdcp->Tx_LC_Precompute && hdcp->Rx_LC_Precompute && hdcp->version >= HDCP2_VERSION_2_1) {
		ret = TZ_COMMAND_T(CMD_LC_SEND_L_PRIME, received,
						sizeof(LC_SEND_L_PRIME_PC), NULL, 0);

		HDCP2_LogHex("[T<<<R] LC_Send_L_prime_pc", received, sizeof(LC_SEND_L_PRIME_PC));
	} else {
		ret = TZ_COMMAND_T(CMD_LC_SEND_L_PRIME, received,
						sizeof(LC_SEND_L_PRIME), NULL, 0);

		HDCP2_LogHex("[T<<<R] LC_Send_L_prime", received, sizeof(LC_SEND_L_PRIME));
	}
	return ret;
}

/**
 * @fn int SKE_Send_Eks_T(HDCP2_Ctx *hdcp, u8 *payload)
 * @brief This function sends a message containing Edkey(ks) and a 64 bit pseudo random number to the hdcp receiver
 * @param hdcp - pointer to HDCP context
 * @param payload - pointer to SKE_SEND_EKS message sent to receiver
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int SKE_Send_Eks_T(HDCP2_Ctx *hdcp, u8 *payload)
{
	int ret = HDCP2_OK;

	if (HDCP2_IsClosed(hdcp))
		return HDCP2_ERR_CLOSED;

	if (hdcp->version == HDCP2_VERSION_2_3){
	   ret = TZ_COMMAND_T(CMD_SKE_SEND_EKS, NULL, 0, payload, sizeof(SKE_SEND_EKS_VER23)); 
	   HDCP2_LogHex("[T>>>R] SKE_Send_Eks_V23", payload, sizeof(SKE_SEND_EKS_VER23));
	} else {
	   ret = TZ_COMMAND_T(CMD_SKE_SEND_EKS, NULL, 0, payload, sizeof(SKE_SEND_EKS)); 
	   HDCP2_LogHex("[T>>>R] SKE_Send_Eks", payload, sizeof(SKE_SEND_EKS));
	}

	gettimeofday((struct timeval *) &hdcp->time_ske_done, NULL);
	return ret;
}

/**
 * @fn nt RepeaterAuth_Send_ReceiverId_List_T(HDCP2_Ctx *hdcp, u8 *received)
 * @brief This function gets the message containing the information regarding the receivers connected to the repeater
 * @param hdcp - pointer to HDCP context
 * @param received - pointer to the REPEATERAUTH_SEND_RECEIVER_ID_LIST21 message received by the transmitter
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int RepeaterAuth_Send_ReceiverId_List_T(HDCP2_Ctx *hdcp, u8 *received)
{
	int ret = HDCP2_OK;

	if (HDCP2_IsClosed(hdcp))
		return HDCP2_ERR_CLOSED;

	if (hdcp->version >= HDCP2_VERSION_2_1) {
		//changes forHDCP 2.1
		REPEATERAUTH_SEND_RECEIVER_ID_LIST21 *cert = (REPEATERAUTH_SEND_RECEIVER_ID_LIST21 *) received;
#ifdef SRM_ENABLED
		//SRM Call
		ret = HDCP2_SRM_Check((u8*)cert->RECEIVER_IDs, cert->DEVICE_COUNT);

		if ((ret == HDCP2_ERR_SRM_CHECK_FAIL) || (ret == HDCP2_ERR_NO_SRM_FILE) || (ret == HDCP2_ERR_SRM_BUFFER_MEMORY_FAIL))
			return ret;
#endif /* SRM_ENABLED */
		ret = TZ_COMMAND_T(CMD_REPEATERAUTH_SEND_RECEIVER_ID_LIST, received,
						((cert->DEVICE_COUNT)*RECEIVER_ID_SIZE) + HDCP_FIXED_SIZE_REPEATERAUTH_SEND_RECEIVERID_LIST21,
						NULL, 0);

		HDCP2_LogHex("[T<<<R] RepeaterAuth_Send_Receiver_Id_List21", received,
				sizeof(REPEATERAUTH_SEND_RECEIVER_ID_LIST21));
	} else {
		//changes forHDCP 2.0
		REPEATERAUTH_SEND_RECEIVER_ID_LIST20 *cert = (REPEATERAUTH_SEND_RECEIVER_ID_LIST20 *) received;
#ifdef SRM_ENABLED
		//SRM call
		ret = HDCP2_SRM_Check((u8*)cert->RECEIVER_IDs, cert->DEVICE_COUNT);
		if ((ret == HDCP2_ERR_SRM_CHECK_FAIL) || (ret == HDCP2_ERR_NO_SRM_FILE) || (ret == HDCP2_ERR_SRM_BUFFER_MEMORY_FAIL))
			return ret;
#endif /* SRM_ENABLED */

		ret = TZ_COMMAND_T( CMD_REPEATERAUTH_SEND_RECEIVER_ID_LIST, received,
						((cert->DEVICE_COUNT)*RECEIVER_ID_SIZE) + HDCP_FIXED_SIZE_REPEATERAUTH_SEND_RECEIVERID_LIST20,
						NULL, 0);

		HDCP2_LogHex("[T<<<R] RepeaterAuth_Send_Receiver_Id_List20", received,
				sizeof(REPEATERAUTH_SEND_RECEIVER_ID_LIST20));
	}

	hdcp->hdcp2_legacy_device_downstream = (u8) (*(received + 5));
	hdcp->hdcp1_device_downstream = (u8) (*(received + 6));

	return ret;
}

/**
 * @fn int RepeaterAuth_Send_Ack_T(HDCP2_Ctx *hdcp, u8 *payload)
 * @brief This function sends an acknowledgment to the receiver
 * @param hdcp - pointer to HDCP context
 * @param payload - pointer to  REPEATERAUTH_SEND_ACK message that is sent by the transmitter as an acknowledgment to REPEATERAUTH_SEND_RECEIVER_ID_LIST21 received in the previous message.
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int RepeaterAuth_Send_Ack_T(HDCP2_Ctx *hdcp, u8 *payload)
{
	int ret = HDCP2_OK;

	if (HDCP2_IsClosed(hdcp))
		return HDCP2_ERR_CLOSED;

	ret = TZ_COMMAND_T(CMD_REPEATERAUTH_SEND_ACK, NULL, 0, payload, sizeof(REPEATERAUTH_SEND_ACK));
	HDCP2_LogHex("[T>>>R] RepeaterAuth_Send_Ack", payload, sizeof(REPEATERAUTH_SEND_ACK));

	return ret;
}

/**
 * @fn int Receiver_AuthStatus_T(HDCP2_Ctx *hdcp, u8 *received)
 * @brief This function lets the transmitter know about the authentication status of receiver with the repeater
 * @param hdcp - pointer to HDCP context
 * @param received - pointer to RECEIVER_AUTHSTATUS message received by the transmitter
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int Receiver_AuthStatus_T(HDCP2_Ctx *hdcp, u8 *received)
{
	int ret = HDCP2_OK;

	if (HDCP2_IsClosed(hdcp))
		return HDCP2_ERR_CLOSED;

	HDCP2_LogHex("[T<<<R] RepeaterAuth_Status", received, sizeof(RECEIVER_AUTHSTATUS));
	ret = TZ_COMMAND_T(CMD_RECEIVER_AUTHSTATUS, received, sizeof(RECEIVER_AUTHSTATUS), NULL, 0);

	return ret;
}

/**
 * @fn int RepeaterAuth_Stream_Manage_T(HDCP2_Ctx *hdcp, u8 *payload, Downstream_Params *params)
 * @brief This function propagates content stream management information, which includes Type values assigned to the content streams
 * @param hdcp - pointer to HDCP context
 * @param payload - pointer to REPEATERAUTH_STREAM_MANAGE message to be sent from transmitter
 * @param params pointer to structure Downstream_Params
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int RepeaterAuth_Stream_Manage_T(HDCP2_Ctx *hdcp, u8 *payload,
			Downstream_Params *params)
{
	int ret = HDCP2_OK;
	int i = 0;
	u8* temp_ptr = (u8*) params;

	if (HDCP2_IsClosed(hdcp))
		return HDCP2_ERR_CLOSED;

	REPEATERAUTH_STREAM_INFO stream_info = { 0, };

	memcpy(stream_info.no_of_streams, hdcp->no_of_streams,
			sizeof(hdcp->no_of_streams));
	for (i = 0; i < hdcp->no_of_streams[1]; i++) {
		memcpy(stream_info.multi_streaminfo[i].streamCtrj, temp_ptr,
				sizeof(stream_info.multi_streaminfo[i].streamCtrj));
		temp_ptr = temp_ptr + sizeof(stream_info.multi_streaminfo[i].streamCtrj);
		memcpy(stream_info.multi_streaminfo[i].ContentStreamIDj, temp_ptr,
				sizeof(stream_info.multi_streaminfo[i].ContentStreamIDj));
		temp_ptr = temp_ptr + sizeof(stream_info.multi_streaminfo[i].ContentStreamIDj);
		memcpy(&(stream_info.multi_streaminfo[i].Type), temp_ptr,
				sizeof(stream_info.multi_streaminfo[i].Type));
		temp_ptr = temp_ptr + 2; // 1 byte for Type and 1 byte padding byte.
	}

	ret = TZ_COMMAND_T(CMD_REPEATERAUTH_STREAM_MANAGE, (u8 *)&stream_info,
			sizeof(REPEATERAUTH_STREAM_INFO), payload, sizeof(REPEATERAUTH_STREAM_MANAGE));

	HDCP2_LogHex("[T>>>R] RepeaterAuth_Stream_Manage", payload,
			sizeof(REPEATERAUTH_STREAM_MANAGE));

	if (ret <= HDCP2_OK)
		return ret;
	else
		return (hdcp->no_of_streams[1] * 7 + 6);
	//size of the RepeaterAuth_Stream_Manage based on the no of streams
}

/**
 * @fn int RepeaterAuth_Stream_Ready_T(HDCP2_Ctx *hdcp, u8 *received)
 * @brief This function obtains M- prime as sent by repeater
 * @param hdcp - pointer to HDCP context
 * @param received - pointer to REPEATERAUTH_STREAM_READY message received by the transmitter
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int RepeaterAuth_Stream_Ready_T(HDCP2_Ctx *hdcp, u8 *received)
{
	int ret = HDCP2_OK;

	if (HDCP2_IsClosed(hdcp))
		return HDCP2_ERR_CLOSED;

	ret = TZ_COMMAND_T(CMD_REPEATERAUTH_STREAM_READY, received,
					sizeof(REPEATERAUTH_STREAM_READY), NULL, 0);

	HDCP2_LogHex("[T<<<R] RepeaterAuth_Stream_Ready", received,
			sizeof(REPEATERAUTH_STREAM_READY));

	return ret;
}

#ifdef HDCP2_PROFILE_ENCRYPT_TIME
/**
 * @fn static void GetTimeStamp(timestamp *ts)
 * @brief This function obtains the current timestamp of the system
 * @param ts - pointer to be populated in the function
 * @return void
 */
static void GetTimeStamp(timestamp *ts)
{
	gettimeofday((struct timeval *) ts, NULL);
}

/**
 * @fn tatic long EstimateTime(timestamp *start, timestamp *end)
 * @brief This function calculates the time elapsed between the two instances
 * @param start - pointer to the timestamp at the beginning
 * @param end - pointer to the timestamp at the end
 * @return long - time elapsed
 */
static long EstimateTime(timestamp *start, timestamp *end)
{
	return (end->tv_sec - start->tv_sec) * 1000 + (end->tv_usec - start->tv_usec) / 1000;
}
#endif /* HDCP2_PROFILE_ENCRYPT_TIME */

int HDCP2_Encrypt(HDCP2_Ctx *hdcp, u32 str_ctr, uint64_t in_ctr, u8 *input, int inlen, u8 *output, size_t offset)
{
	if (HDCP2_IsClosed(hdcp))  return HDCP2_ERR_CLOSED;

	return HDCP2_Encrypt_Drm(hdcp, str_ctr, in_ctr, input, inlen, output, offset);
}

#ifdef USE_MOBICORE
/**
 * @fn int HDCP2_Encrypt_Drm(HDCP2_Ctx *hdcp, u32 str_ctr, u64 in_ctr, u8 *input, int inlen, u8 *output, int type)
 * @brief The function is used to encrypt the Drm Content under the HDCP encryption protocol when using the chipset Mobicore or chabi .
 * @param hdcp - pointer to HDCP context
 * @param str_ctr - It is 32 bit stream counter. HDCP transmitter assigns a distinct stream counter for each Packetized Elementary Stream (PES).
 * @param in_ctr - It is 64 bit input counter. It is initialized to zero after SKE and must not be reset at any other time.
 * @param input - pointer to the data to be encrypted.
 * @param inlen - length of input data.
 * @param output - pointer to the output data, that will be populated in this function.
 * @param type - determines the type of buffer i.e. TZ buffer or Normal buffer
 * @return int - returns input length in case of success else returns error values in case of failures.
 */
int HDCP2_Encrypt_Drm(HDCP2_Ctx *hdcp, u32 str_ctr, u64 in_ctr, u8* input,
			int inlen, u8* output, int type)
{
	int ret = HDCP2_OK;
	addr_s in_pa = 0;
	addr_s *input_physaddr = &in_pa;
	u8 *output_virtaddr = output;
	u8 *output_physaddr = 0;

#ifdef HDCP2_PROFILE_ENCRYPT_TIME
	timestamp startTime ;
	timestamp endTime;
	long duration;
#endif /* HDCP2_PROFILE_ENCRYPT_TIME */

	HDCP2_DEBUG("HDCP2_Encrypt_Drm - input : 0x%x, output : 0x%x, str_ctr : %u, in_ctr : %zu, type : %d",
				input, output, str_ctr, in_ctr, type);

	if (type != -1) { // encryptNative API
		if ((ret = HDCP2_ConvertAddrs((int)(intptr_t)input, &input_physaddr, NULL,
							(int)(intptr_t)output, &output_physaddr, &output_virtaddr, inlen)) != 0)
			return ret;
	}

#ifdef HDCP2_PROFILE_ENCRYPT_TIME
	GetTimeStamp(&startTime);
#endif /* HDCP2_PROFILE_ENCRYPT_TIME */

	if (type == -1) { // encrypt API
#ifdef USE_MTK
		ret = HDCP2_Encrypt_VV(hdcp, str_ctr, in_ctr, input, inlen, output, type);
#else
		ret = HDCP2_Encrypt_VV(hdcp, str_ctr, in_ctr, input, inlen, output);
#endif /* USE_MTK */
	} else { // encryptNative API
		ret = HDCP2_Encrypt_PV(hdcp, str_ctr, in_ctr, input_physaddr, inlen, output_virtaddr);
	}

#ifdef HDCP2_PROFILE_ENCRYPT_TIME
	GetTimeStamp(&endTime);
	duration = EstimateTime(&startTime, &endTime);

	total_duration += duration;
	enc_count++;
	total_lengh += inlen;
#endif /* HDCP2_PROFILE_ENCRYPT_TIME */

	if (ret >= 0)
		ret = HDCP2_OK;

	return ret;
}
#endif /* USE_MOBICORE */

#ifdef USE_QUALCOMM
/**
 * @fn int HDCP2_Encrypt_Drm(HDCP2_Ctx *hdcp, u32 str_ctr, u64 in_ctr, u8 *input, int inlen, u8 *output, int type)
 * @brief The function is used to encrypt the Drm Content under the HDCP encryption protocol when using chipset Qualcomm.
 * @param hdcp - pointer to HDCP context
 * @param str_ctr - It is 32 bit stream counter. HDCP transmitter assigns a distinct stream counter for each Packetized Elementary Stream (PES).
 * @param in_ctr - It is 64 bit input counter. It is initialized to zero after SKE and must not be reset at any other time.
 * @param input - pointer to the data to be encrypted.
 * @param inlen - length of input data.
 * @param output - pointer to the output data, that will be populated in this function.
 * @param type - determines the type of buffer i.e. TZ buffer or Normal buffer
 * @return int - returns input length in case of success else returns error values in case of failures.
 *  else: all packet parameters are passed to the encryption function.
 */

int HDCP2_Encrypt_Drm(HDCP2_Ctx *hdcp, u32 str_ctr, u64 in_str, u8 *input, int inlen, u8 *output, int type)
{
	int ret = 0;
	CIP_DATA_INFO_QC_TX data = {0};
#ifdef HDCP2_PROFILE_ENCRYPT_TIME
	timestamp startTime ;
	timestamp endTime;
	long duration;
#endif /* HDCP2_PROFILE_ENCRYPT_TIME */

	if (inlen <= 0 || !hdcp || !input || !output || inlen > MAX_ENCRYPT_BUFFER) {
		HDCP2_Log("HDCP2_ERR_INVALID_INPUT (inlen = %d)", inlen);
		return HDCP2_ERR_INVALID_INPUT;
	}

	data.str_ctr = (uint32_t)str_ctr;
	data.inp_ctr = (uint64_t)(in_str);
	data.input =  (uint8_t *)(input);
	data.output =  (uint8_t *)(output);
	data.length = inlen;
	data.offset = type;

#ifdef HDCP2_PROFILE_ENCRYPT_TIME
	GetTimeStamp(&startTime);
#endif /* HDCP2_PROFILE_ENCRYPT_TIME */

	if ((ret = TZ_COMMAND_T_ION(CMD_CIP_ENC_DATA, (uint8_t *)&data, sizeof(CIP_DATA_INFO_QC_TX), 0)) < 0)
		HDCP2_Log("Ignore Frame, l=%d, t=%d", data.length, type);

#ifdef HDCP2_PROFILE_ENCRYPT_TIME
	GetTimeStamp(&endTime);
	duration = EstimateTime(&startTime, &endTime);
	HDCP2_Log("HDCP2_Encrypt_Drm length %d duration = %d", inlen, duration);

	total_duration += duration;
	enc_count++;
	total_lengh += inlen;
#endif /* HDCP2_PROFILE_ENCRYPT_TIME */

	return ret;
}
#endif /* USE_QUALCOMM */

#ifdef USE_TEEGRIS
int HDCP2_Encrypt_Drm(HDCP2_Ctx *hdcp, u32 str_ctr, u64 in_ctr, u8 *input, int inlen, u8 *output, int type)
{
	int ret = 0;

	if (type == -1) { // encrypt API
		ret = HDCP2_Encrypt_VV(hdcp, str_ctr, in_ctr, input, inlen, output, type);
	} else { // encryptNative API
		ret = HDCP2_Encrypt_PV(hdcp, str_ctr, in_ctr, input, inlen, output, type);
	}

	return ret;
}
#endif /* USE_TEEGRIS */
