lineage_kernel_xcoverpro/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-selftest.c

471 lines
9.9 KiB
C
Executable File

/*
* drivers/soc/samsung/exynos-hdcp/dplink/exynos-hdcp2-dplink-selftest.c
*
* Copyright (c) 2016 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <asm/cacheflush.h>
#include "../exynos-hdcp2-config.h"
#include "../exynos-hdcp2-protocol-msg.h"
#include "../exynos-hdcp2-misc.h"
#include "../exynos-hdcp2-encrypt.h"
#include "../exynos-hdcp2.h"
#include "../exynos-hdcp2-log.h"
#include "exynos-hdcp2-dplink-protocol-msg.h"
#define DP_AKE_INIT_LEN 11
#define DP_AKE_NO_STORED_KM_LEN 128
#define DP_LC_INIT_LEN 8
#define DP_SKE_SEND_EKS_LEN 24
/* todo: define DP test vector */
extern uint8_t msg_rx_lc_send_l_prime_v22[32];
extern uint8_t msg_rx_send_h_prime_v22[32];
extern uint8_t msg_rx_send_pairing_info_v22[16];
extern uint8_t msg_rx_send_cert_v22[533];
extern unsigned char cert_v22[522];
extern uint8_t tv_emkey_v22[128];
extern uint8_t tv_ske_eskey_v22[16];
extern uint8_t tv_rcvid_list_v22[36];
extern uint8_t tv_rpauth_v_v22[16];
extern uint8_t tv_rpauth_stream_manage_v22[7];
extern uint8_t tv_rpauth_stream_ready_v22[32];
static struct hdcp_tx_ctx g_tx_ctx;
static struct hdcp_rx_ctx g_rx_ctx;
#if defined(TEST_VECTOR_1)
static int dp_utc_rpauth_stream_ready(struct hdcp_tx_ctx *tx_ctx, struct hdcp_rx_ctx *rx_ctx)
{
int ret;
ret = decap_protocol_msg(DP_REPEATERAUTH_STREAM_READY,
tv_rpauth_stream_ready_v22,
sizeof(tv_rpauth_stream_ready_v22),
HDCP_LINK_TYPE_DP,
tx_ctx, rx_ctx);
if (ret) {
hdcp_err("RPAuth_Stream_Ready is failed with 0x%x\n", ret);
return -1;
}
return 0;
}
static int dp_utc_rpauth_stream_manage(struct hdcp_tx_ctx *tx_ctx, struct hdcp_rx_ctx *rx_ctx)
{
int ret;
uint8_t m[525];
size_t m_len;
int i;
ret = cap_protocol_msg(DP_REPEATERAUTH_STREAM_MANAGE,
m,
&m_len,
HDCP_LINK_TYPE_DP,
tx_ctx,
rx_ctx);
if (ret) {
hdcp_err("RPAuth_Stream_Manage is failed with 0x%x\n", ret);
return -1;
}
/* compare V with test vector */
for (i = 0; i < m_len; i++)
if (tv_rpauth_stream_manage_v22[i] != m[i])
break;
if (i != m_len) {
hdcp_err("stream manage info doesn't match (%dth)\n", i);
hdcp_err("stream_manage:\n");
hdcp_hexdump(m, m_len);
return -1;
}
return 0;
}
static int dp_utc_rpauth_send_revid_list(struct hdcp_tx_ctx *tx_ctx, struct hdcp_rx_ctx *rx_ctx)
{
int ret;
ret = decap_protocol_msg(DP_REPEATERAUTH_SEND_RECEIVERID_LIST,
tv_rcvid_list_v22,
sizeof(tv_rcvid_list_v22),
HDCP_LINK_TYPE_DP,
tx_ctx, rx_ctx);
if (ret) {
hdcp_err("RPAuth_Send_ReceiverID_List is failed with 0x%x\n", ret);
return -1;
}
return 0;
}
static int dp_utc_rpauth_send_ack(struct hdcp_tx_ctx *tx_ctx, struct hdcp_rx_ctx *rx_ctx)
{
int ret;
uint8_t m[525];
size_t m_len;
uint32_t v_len;
int i;
v_len = HDCP_RP_HMAC_V_LEN / 2;
ret = cap_protocol_msg(DP_REPEATERAUTH_SEND_AKE,
m,
&m_len,
HDCP_LINK_TYPE_DP,
tx_ctx,
rx_ctx);
if (ret) {
hdcp_err("RPAuth_Send_AKE is failed with 0x%x\n", ret);
return -1;
}
/* compare V with test vector */
for (i = 0; i < v_len; i++)
if (tv_rpauth_v_v22[i] != m[i])
break;
if (i != v_len) {
hdcp_err("m doesn't match (%dth)\n", i);
return -1;
}
return 0;
}
#endif
static int dp_utc_ske_send_eks(struct hdcp_tx_ctx *tx_ctx, struct hdcp_rx_ctx *rx_ctx)
{
uint8_t m[525];
size_t m_len;
int ret;
int i;
tx_ctx->share_skey = 0;
ret = cap_protocol_msg(SKE_SEND_EKS, m, &m_len, HDCP_LINK_TYPE_DP, tx_ctx, rx_ctx);
if (ret) {
hdcp_err("SKE_Send_Eks is failed with 0x%x\n", ret);
return -1;
}
if (m_len != DP_SKE_SEND_EKS_LEN) {
hdcp_err("Message LENGTH ERROR\n");
return -1;
}
/* compare encrypted session key with test vector */
for (i = 0; i < HDCP_AKE_MKEY_BYTE_LEN; i++)
if (tv_ske_eskey_v22[i] != m[i])
break;
if (i != HDCP_AKE_MKEY_BYTE_LEN) {
hdcp_err("m doesn't match (%dth)\n", i);
return -1;
}
return 0;
}
/* Test SKE APIs */
static int dp_utc_ske(struct hdcp_tx_ctx *tx_ctx, struct hdcp_rx_ctx *rx_ctx, int *cnt, int *fail)
{
int ret;
ret = dp_utc_ske_send_eks(tx_ctx, rx_ctx);
if (ret) {
hdcp_err("utc_ske_send_eks() is failed with 0x%x\n", ret);
return -1;
}
return 0;
}
static int dp_utc_lc_send_l_prime(struct hdcp_tx_ctx *tx_ctx, struct hdcp_rx_ctx *rx_ctx)
{
int ret;
ret = decap_protocol_msg(LC_SEND_L_PRIME, msg_rx_lc_send_l_prime_v22,
sizeof(msg_rx_send_h_prime_v22),
HDCP_LINK_TYPE_DP,
tx_ctx, rx_ctx);
if (ret) {
hdcp_err("LC_Send_L_prime is failed with 0x%x\n", ret);
return -1;
}
return 0;
}
static int dp_utc_lc_init(struct hdcp_tx_ctx *tx_ctx, struct hdcp_rx_ctx *rx_ctx)
{
uint8_t m[525];
size_t m_len;
int ret;
ret = cap_protocol_msg(LC_INIT, m, &m_len, HDCP_LINK_TYPE_DP, tx_ctx, rx_ctx);
if (ret) {
hdcp_err("LC_Init is failed with 0x%x\n", ret);
return -1;
}
if (m_len != DP_LC_INIT_LEN) {
hdcp_err("Invalid Message length. len(%zu)\n", m_len);
return -1;
}
return 0;
}
/* Test LC APIs */
static int dp_utc_lc(struct hdcp_tx_ctx *tx_ctx, struct hdcp_rx_ctx *rx_ctx,
int *cnt, int *fail)
{
int ret;
ret = dp_utc_lc_init(tx_ctx, rx_ctx);
if (ret < 0)
return ret;
ret = dp_utc_lc_send_l_prime(tx_ctx, rx_ctx);
if (ret < 0)
return ret;
return 0;
}
static int dp_utc_ake_send_h_prime(struct hdcp_tx_ctx *tx_ctx,
struct hdcp_rx_ctx *rx_ctx)
{
int ret;
ret = decap_protocol_msg(AKE_SEND_H_PRIME, msg_rx_send_h_prime_v22,
sizeof(msg_rx_send_h_prime_v22),
HDCP_LINK_TYPE_DP,
tx_ctx, rx_ctx);
if (ret) {
hdcp_err("AKE_Send_H_prime is failed with 0x%x\n", ret);
return -1;
}
return 0;
}
static int dp_utc_ake_send_pairing_info(struct hdcp_tx_ctx *tx_ctx,
struct hdcp_rx_ctx *rx_ctx)
{
/* todo: support pairing */
int i;
int ret;
int found_km;
ret = decap_protocol_msg(AKE_SEND_PAIRING_INFO, msg_rx_send_pairing_info_v22,
sizeof(msg_rx_send_pairing_info_v22),
HDCP_LINK_TYPE_DP,
tx_ctx, rx_ctx);
if (ret) {
hdcp_err("AKE_Send_Pairing_Info is failed with 0x%x\n", ret);
return -1;
}
ret = ake_find_masterkey(&found_km,
tx_ctx->ekh_mkey, HDCP_AKE_EKH_MKEY_BYTE_LEN,
tx_ctx->m, HDCP_AKE_M_BYTE_LEN);
if (ret) {
hdcp_err("find_masterkey() is failed with 0x%x\n", ret);
return -1;
}
if (found_km) {
for (i = 0; i < HDCP_AKE_MKEY_BYTE_LEN; i++)
if (tx_ctx->ekh_mkey[i] != msg_rx_send_pairing_info_v22[i])
break;
if (i != HDCP_AKE_MKEY_BYTE_LEN) {
hdcp_err("ekh(m) doesn't match (%dth)\n", i);
return -1;
}
} else {
hdcp_err("ekh(m) is not found\n");
return -1;
}
return 0;
}
static int dp_utc_ake_no_stored_km(struct hdcp_tx_ctx *tx_ctx,
struct hdcp_rx_ctx *rx_ctx)
{
uint8_t m[525];
size_t m_len;
int ret;
int i;
memcpy(rx_ctx->cert, cert_v22, HDCP_RX_CERT_LEN);
ret = cap_protocol_msg(AKE_NO_STORED_KM, m, &m_len, HDCP_LINK_TYPE_DP, tx_ctx, rx_ctx);
if (ret) {
hdcp_err("AKE_No_Stored_km is failed with 0x%x\n", ret);
return -1;
}
if (m_len != DP_AKE_NO_STORED_KM_LEN) {
hdcp_err("Invalid Message length. len(%zu)\n", m_len);
return -1;
}
for (i = 0; i < 128; i++)
if (m[i] != tv_emkey_v22[i])
break;
if (i != 128) {
hdcp_err("Encryption Master Key ERROR\n");
return -1;
}
return 0;
}
static int dp_utc_ake_send_cert(struct hdcp_tx_ctx *tx_ctx,
struct hdcp_rx_ctx *rx_ctx)
{
int ret;
ret = decap_protocol_msg(AKE_SEND_CERT, msg_rx_send_cert_v22,
sizeof(msg_rx_send_cert_v22),
HDCP_LINK_TYPE_DP,
tx_ctx, rx_ctx);
if (ret) {
hdcp_err("AKE_Send_Cert is failed with ret, 0x%x\n", ret);
return -1;
}
return 0;
}
static int dp_utc_ake_init(struct hdcp_tx_ctx *tx_ctx, struct hdcp_rx_ctx *rx_ctx)
{
uint8_t m[525];
size_t m_len;
int ret;
ret = cap_protocol_msg(DP_AKE_INIT, m, &m_len, HDCP_LINK_TYPE_DP, tx_ctx, NULL);
if (ret) {
hdcp_err("AKE_Init is failed with 0x%x\n", ret);
return -1;
}
/* check message length */
if (m_len != DP_AKE_INIT_LEN) {
hdcp_err("Invalid Message Length. len(%zu)\n", m_len);
return -1;
}
return 0;
}
/* Test AKE APIs */
static int dp_utc_ake(struct hdcp_tx_ctx *tx_ctx, struct hdcp_rx_ctx *rx_ctx,
int *cnt, int *fail)
{
int ret;
ret = dp_utc_ake_init(tx_ctx, rx_ctx);
if (ret < 0)
return ret;
ret = dp_utc_ake_send_cert(tx_ctx, rx_ctx);
if (ret < 0)
return ret;
ret = dp_utc_ake_no_stored_km(tx_ctx, rx_ctx);
if (ret < 0)
return ret;
ret = dp_utc_ake_send_h_prime(tx_ctx, rx_ctx);
if (ret < 0)
return ret;
ret = dp_utc_ake_send_pairing_info(tx_ctx, rx_ctx);
if (ret < 0)
return ret;
return 0;
}
/* Test RP Auth APIs */
#if defined(TEST_VECTOR_1)
static int dp_utc_rpauth(struct hdcp_tx_ctx *tx_ctx, struct hdcp_rx_ctx *rx_ctx,
int *cnt, int *fail)
{
int ret;
ret = dp_utc_rpauth_send_revid_list(tx_ctx, rx_ctx);
if (ret < 0)
return ret;
ret = dp_utc_rpauth_send_ack(tx_ctx, rx_ctx);
if (ret < 0)
return ret;
ret = dp_utc_rpauth_stream_manage(tx_ctx, rx_ctx);
if (ret < 0)
return ret;
ret = dp_utc_rpauth_stream_ready(tx_ctx, rx_ctx);
if (ret < 0)
return ret;
return 0;
}
#endif
/* Test HDCP API functions */
int dp_hdcp_protocol_self_test(void)
{
int total_cnt = 0, fail_cnt = 0;
hdcp_info("[ AKE UTC]\n");
if (dp_utc_ake(&g_tx_ctx, &g_rx_ctx, &total_cnt, &fail_cnt) < 0) {
hdcp_info("AKE UTC: fail\n");
return -1;
} else {
hdcp_info("AKE UTC: success\n");
}
hdcp_info("\n[ LC UTC]\n");
if (dp_utc_lc(&g_tx_ctx, &g_rx_ctx, &total_cnt, &fail_cnt) < 0) {
hdcp_info("LC UTC: fail\n");
return -1;
} else {
hdcp_info("LC UTC: success\n");
}
hdcp_info("\n[ SKE UTC]\n");
if (dp_utc_ske(&g_tx_ctx, &g_rx_ctx, &total_cnt, &fail_cnt) < 0) {
hdcp_info("SKE UTC: fail\n");
return -1;
} else {
hdcp_info("SKE UTC: success\n");
}
#if defined(TEST_VECTOR_1)
hdcp_info("\n[ RP UTC]\n");
if (dp_utc_rpauth(&g_tx_ctx, &g_rx_ctx, &total_cnt, &fail_cnt) < 0) {
hdcp_info("RP UTC: fail\n");
return -1;
} else {
hdcp_info("RP UTC: success\n");
}
#endif
return 0;
}