/**
 * 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.
 *
 */
 /* insthk.c
 *
 *  HDCP key provisioning and checking functions for HDCP2
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <android/log.h>
#include <dirent.h>
#include <errno.h>

#include "hdcp2.h"
#include "version.h"
#include "properties.h"

#define LOG_TAG				"INSTHK"
#define LOG_E(...)			__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define LOG_D(...)			__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)

#ifdef LDU_DEVICE
#define QC_PERMISSION_CMD	"chmod 644 /efs/cpk/h2k.dat"
#define QC_PERMISSION_CMD2	"chown radio.radio /efs/cpk/h2k.dat"
#define QC_PERMISSION_CMD3	"chmod 644 /efs/cpk/odmh2k.dat"
#define QC_PERMISSION_CMD4	"chown radio.radio /efs/cpk/odmh2k.dat"
#endif /* LDU_DEVICE */

#define CPK_PATH			"/efs/cpk"

#define ENC_KEY_PATH_CPK	"/efs/cpk/redata.bin"
#define H2K_PATH_CPK		"/efs/cpk/h2k.dat"

#define ENC_KEY_PATH_ODM	"/efs/cpk/odmtedata.bin"
#define H2K_PATH_ODM		"/efs/cpk/odmh2k.dat"

#define ENC_KEY_PATH_EFS	"/efs/redata.bin"
#define H2K_PATH_EFS		"/efs/h2k.dat"

#define CHECK_OK						0
#define CHECK_NO_KEY_DATA				1
#define CHECK_KEY_VALUE_ERROR			2
#define CHECK_KEY_INSTALL_ERROR			3
#define CHECK_INVALID_INPUT_PARAM		4
#define CHECK_LOAD_HDCP_LIBRARY_FAIL	5

#define MAX_BUF							255


int WriteFile(const char* path, const char* buf, const int size)
{
	int fd = 0;
	int written = 0;

	fd = open(path, O_WRONLY|O_CREAT|O_SYNC|O_TRUNC, 0644);
	if (fd < 0) {
		LOG_E("Failed to open %s\n", path);
		return -1;
	}

	if ((written = write(fd, buf, size)) != size) {
		LOG_E("Cannot write file (length = %d, written = %d)", size, written);
		close(fd);
		return -1;
	}

	close(fd);
	return 0;
}

int is_symlink(const char* filepath)
{
	struct stat stbuf;

	if (lstat(filepath,&stbuf) < 0) {
		LOG_D("Fail to get file info");
		return -1;
	}

	if (S_ISLNK(stbuf.st_mode)) {
		LOG_D("The file is symbolic link");
		return 1;
	}

	return 0;
}

int main(int argc, char* argv[])
{
	int res = CHECK_OK;
	char buf[MAX_BUF] = {0, };
	char sys_prop[10] = {0, };

	const char* h2k_path = NULL;
	HDCP2_Ctx hdcp = {0, };

	LOG_D("version = %s", SW_VERSION);
	if (access(CPK_PATH, 0) == 0)
		h2k_path = (access(H2K_PATH_CPK, 0) == 0)?H2K_PATH_CPK:H2K_PATH_ODM;
	else
		h2k_path = (access(H2K_PATH_EFS, 0) == 0)?H2K_PATH_EFS:H2K_PATH_ODM;

	LOG_D("h2k_path = %s", h2k_path);

#ifdef USE_QSEE
	if (argc >= 2) {
		if ((access(H2K_PATH_EFS, 0) == 0) || (access(H2K_PATH_CPK, 0) == 0) || (access(H2K_PATH_ODM, 0) == 0)) {
			LOG_D("Checked...");
			if ((!unlink(ENC_KEY_PATH_EFS)) || (!unlink(ENC_KEY_PATH_CPK)) || (!unlink(ENC_KEY_PATH_ODM)))
				LOG_D("R Removed...");

			exit(CHECK_OK);
		} else {
			LOG_E("V Fail ...");
			exit(CHECK_NO_KEY_DATA);
		}
	}
#endif /* USE_QSEE */

	if ((res = HDCP2_Init(&hdcp, HDCP2_FACTORY, HDCP2_VERSION_2_1)) < 0) {
		LOG_E("I Fail (%d)...", res);
		exit(CHECK_LOAD_HDCP_LIBRARY_FAIL);
	}

	if ((res = HDCP2_IsKeyboxValid(&hdcp)) == 0) {
		LOG_D("Checked...");
		if ((!unlink(ENC_KEY_PATH_EFS)) || (!unlink(ENC_KEY_PATH_CPK)) || (!unlink(ENC_KEY_PATH_ODM)))
			LOG_D("R Removed...");

#ifdef USE_QSEE
		if ((access(H2K_PATH_EFS, 0) != 0) && (access(H2K_PATH_CPK, 0) != 0) && (access(H2K_PATH_ODM, 0) != 0)) {
			memset(buf, 0x00, MAX_BUF);
			WriteFile(h2k_path, buf, 16);

			if (!is_symlink(h2k_path)) {
				chown(h2k_path, 1001, 1001);
				chmod(h2k_path, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
			}

			LOG_D("H made...");
		}
#endif /* USE_QSEE */
	} else {
		LOG_E("V Fail (%d)...", res);

		do {
			if ((access(ENC_KEY_PATH_EFS, 0) != 0) && (access(ENC_KEY_PATH_CPK, 0) != 0) && (access(ENC_KEY_PATH_ODM, 0) != 0)) {
				LOG_E("EK Fail ...");
				res = CHECK_NO_KEY_DATA;
				break;
			}

			if ((res = HDCP2_WrapKey(&hdcp)) != 0) {
				LOG_E("W Fail (%d)...", res);
				res = CHECK_KEY_INSTALL_ERROR;
				break;
			}

			if ((res = HDCP2_IsKeyboxValid(&hdcp)) != 0) {
				LOG_E("V Fail (%d)...", res);
				res = CHECK_KEY_VALUE_ERROR;
				break;
			} else {
				LOG_D("H Success...");
#ifdef USE_QSEE
				property_get(INSTHK_SYS_PROP, sys_prop, PROP_DEFAULT);
				if (strcmp(sys_prop, PROP_QC_WRAP)) {
					memset(buf, 0x00, MAX_BUF);
					LOG_D("h2k_path %s...",h2k_path);
					WriteFile(h2k_path, buf, 16);
				}

#ifdef LDU_DEVICE
				system(QC_PERMISSION_CMD);
				system(QC_PERMISSION_CMD2);

				if (access(H2K_PATH_ODM, 0) == 0) {
					system(QC_PERMISSION_CMD3);
					system(QC_PERMISSION_CMD4);
				}
#endif /* LDU_DEVICE */
#endif /* USE_QSEE */
			}
		} while(0);
	}

	HDCP2_Close(&hdcp);

	sync();
	exit(res);

	return res;
}
