463 lines
11 KiB
C
463 lines
11 KiB
C
|
/*
|
||
|
* drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-tx-auth.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 "exynos-hdcp2-iia-auth.h"
|
||
|
#include "../exynos-hdcp2-log.h"
|
||
|
|
||
|
#define HDCP_TX_VERSION_2_2 HDCP_TX_VERSION_2_1
|
||
|
|
||
|
static int next_step;
|
||
|
static int key_found;
|
||
|
static char *hdcp_msgid_str[] = {
|
||
|
NULL,
|
||
|
"Null message",
|
||
|
"AKE_Init",
|
||
|
"AKE_Send_Cert",
|
||
|
"AKE_No_Stored_km",
|
||
|
"AKE_Stored_km",
|
||
|
"AKE_Send_rrx",
|
||
|
"AKE_Send_H_prime",
|
||
|
"AKE_Send_Pairing_Info",
|
||
|
"LC_Init",
|
||
|
"LC_Send_L_prime",
|
||
|
"SKE_Send_Eks",
|
||
|
"RepeaterAuth_Send_ReceiverID_List",
|
||
|
"RTT_Ready",
|
||
|
"RTT_Challenge",
|
||
|
"RepeaterAuth_Send_Ack",
|
||
|
"RepeaterAuth_Stream_Manage",
|
||
|
"RepeaterAuth_Stream_Ready",
|
||
|
"Receiver_AuthStatus",
|
||
|
"AKE_Transmitter_Info",
|
||
|
"AKE_Receiver_Info",
|
||
|
NULL
|
||
|
};
|
||
|
|
||
|
#define is_precomput(lk) \
|
||
|
((lk->rx_ctx.version != HDCP_VERSION_2_0) && \
|
||
|
lk->tx_ctx.lc_precomp && \
|
||
|
lk->rx_ctx.lc_precomp)
|
||
|
|
||
|
|
||
|
static int send_protocol_msg(struct hdcp_link_data *lk, uint8_t msg_id, struct hdcp_msg_info *msg_info)
|
||
|
{
|
||
|
int ret = TX_AUTH_SUCCESS;
|
||
|
|
||
|
hdcp_info("Tx->Rx: %s\n", hdcp_msgid_str[msg_id]);
|
||
|
ret = cap_protocol_msg(msg_id, msg_info->msg, (size_t *)&msg_info->msg_len, lk->lk_type, &lk->tx_ctx, &lk->rx_ctx);
|
||
|
|
||
|
if (ret) {
|
||
|
hdcp_err("cap_protocol_msg() failed. ret(0x%08x)\n", ret);
|
||
|
return -TX_AUTH_ERROR_MAKE_PROTO_MSG;
|
||
|
}
|
||
|
|
||
|
return TX_AUTH_SUCCESS;
|
||
|
}
|
||
|
|
||
|
static int recv_protocol_msg(struct hdcp_link_data *lk, uint8_t msg_id, struct hdcp_msg_info *msg_info)
|
||
|
{
|
||
|
int ret = TX_AUTH_SUCCESS;
|
||
|
if (ret >= 0 && msg_info->msg_len > 0) {
|
||
|
/* parsing received message */
|
||
|
ret = decap_protocol_msg(msg_id, msg_info->msg, msg_info->msg_len, lk->lk_type, &lk->tx_ctx, &lk->rx_ctx);
|
||
|
|
||
|
if (ret) {
|
||
|
hdcp_err("dcap_protocol_msg() failed. msg_id(%d), ret(0x%08x)\n", msg_id, ret);
|
||
|
ret = -TX_AUTH_ERROR_WRONG_MSG;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hdcp_info("Rx->Tx: %s\n", hdcp_msgid_str[msg_id]);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static int hdcp_ake_find_masterkey(struct hdcp_tx_ctx *tx_ctx,
|
||
|
struct hdcp_rx_ctx *rx_ctx)
|
||
|
{
|
||
|
/* todo */
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
static int get_hdcp_session_key(struct hdcp_link_data *lk)
|
||
|
{
|
||
|
/* todo */
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int put_hdcp_session_key(struct hdcp_link_data *lk)
|
||
|
{
|
||
|
/* todo */
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int exchange_master_key(struct hdcp_link_data *lk, struct hdcp_msg_info *msg_info)
|
||
|
{
|
||
|
int rval = TX_AUTH_SUCCESS;
|
||
|
|
||
|
if (next_step < AKE_INIT)
|
||
|
UPDATE_STEP_STATE(next_step, AKE_INIT);
|
||
|
|
||
|
switch (next_step) {
|
||
|
case AKE_INIT:
|
||
|
{
|
||
|
rval = send_protocol_msg(lk, AKE_INIT, msg_info);
|
||
|
if (rval < 0) {
|
||
|
hdcp_err("send AKE_Init failed. rval(%d)\n", rval);
|
||
|
} else {
|
||
|
UPDATE_STEP_STATE(next_step, AKE_TRANSMITTER_INFO);
|
||
|
#ifdef HDCP_TX_VERSION_2_2
|
||
|
msg_info->next_step = SEND_MSG;
|
||
|
#else
|
||
|
msg_info->next_step = RECIEVE_MSG;
|
||
|
#endif
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case AKE_TRANSMITTER_INFO:
|
||
|
{
|
||
|
#ifdef HDCP_TX_VERSION_2_2
|
||
|
rval = send_protocol_msg(lk, AKE_TRANSMITTER_INFO, msg_info);
|
||
|
if (rval < 0) {
|
||
|
hdcp_err("send AKE_Transmitter_Info failed. rval(%d)\n", rval);
|
||
|
} else {
|
||
|
UPDATE_STEP_STATE(next_step, AKE_SEND_CERT);
|
||
|
msg_info->next_step = RECIEVE_MSG;
|
||
|
}
|
||
|
break;
|
||
|
#endif
|
||
|
}
|
||
|
case AKE_SEND_CERT:
|
||
|
{
|
||
|
rval = recv_protocol_msg(lk, AKE_SEND_CERT, msg_info);
|
||
|
if (rval < 0) {
|
||
|
hdcp_err("recv AKE_Send_Cert failed. rval(%d)\n", rval);
|
||
|
} else {
|
||
|
UPDATE_STEP_STATE(next_step, AKE_RECEIVER_INFO);
|
||
|
msg_info->next_step = RECIEVE_MSG;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case AKE_RECEIVER_INFO:
|
||
|
{
|
||
|
rval = recv_protocol_msg(lk, AKE_RECEIVER_INFO, msg_info);
|
||
|
if (rval < 0) {
|
||
|
hdcp_err("recv AKE_Receiver_Info failed. rval(%d)\n", rval);
|
||
|
} else {
|
||
|
UPDATE_STEP_STATE(next_step, AKE_NO_STORED_KM);
|
||
|
msg_info->next_step = SEND_MSG;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case AKE_NO_STORED_KM:
|
||
|
{
|
||
|
key_found = hdcp_ake_find_masterkey(&lk->tx_ctx, &lk->rx_ctx);
|
||
|
if ((key_found < 0)) {
|
||
|
rval = send_protocol_msg(lk, AKE_NO_STORED_KM, msg_info);
|
||
|
if (rval < 0) {
|
||
|
hdcp_err("send AKE_No_Stored_km failed. rval(%d)\n", rval);
|
||
|
} else {
|
||
|
UPDATE_STEP_STATE(next_step, AKE_SEND_RRX);
|
||
|
msg_info->next_step = RECIEVE_MSG;
|
||
|
}
|
||
|
lk->stored_km = HDCP_WITHOUT_STORED_KM;
|
||
|
} else {
|
||
|
rval = send_protocol_msg(lk, AKE_STORED_KM, msg_info);
|
||
|
if (rval < 0) {
|
||
|
hdcp_err("send AKE_Stored_km failed. rval(%d)\n", rval);
|
||
|
} else {
|
||
|
UPDATE_STEP_STATE(next_step, AKE_SEND_RRX);
|
||
|
msg_info->next_step = RECIEVE_MSG;
|
||
|
}
|
||
|
lk->stored_km = HDCP_WITH_STORED_KM;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case AKE_SEND_RRX:
|
||
|
{
|
||
|
rval = recv_protocol_msg(lk, AKE_SEND_RRX, msg_info);
|
||
|
if (rval < 0) {
|
||
|
hdcp_err("recv AKE_Send_rrx failed. rval(%d)\n", rval);
|
||
|
} else {
|
||
|
UPDATE_STEP_STATE(next_step, AKE_SEND_H_PRIME);
|
||
|
msg_info->next_step = RECIEVE_MSG;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case AKE_SEND_H_PRIME:
|
||
|
{
|
||
|
rval = recv_protocol_msg(lk, AKE_SEND_H_PRIME, msg_info);
|
||
|
if (rval < 0) {
|
||
|
hdcp_err("recv AKE_Send_H_Prime failed. rval(%d)\n", rval);
|
||
|
} else {
|
||
|
UPDATE_STEP_STATE(next_step, AKE_SEND_PAIRING_INFO);
|
||
|
if(key_found == -1){
|
||
|
hdcp_debug("Key found\n");
|
||
|
msg_info->next_step = RECIEVE_MSG;
|
||
|
}
|
||
|
else {
|
||
|
hdcp_debug("Key not found\n");
|
||
|
msg_info->next_step = DONE;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case AKE_SEND_PAIRING_INFO:
|
||
|
{
|
||
|
if (key_found == -1) {
|
||
|
rval = recv_protocol_msg(lk, AKE_SEND_PAIRING_INFO, msg_info);
|
||
|
if (rval < 0) {
|
||
|
hdcp_err("recv AKE_Send_Pairing_Info failed. rval(%d)\n", rval);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
msg_info->next_step = DONE;
|
||
|
UPDATE_STEP_STATE(next_step, LC_INIT);
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
return -ENOTTY;
|
||
|
}
|
||
|
|
||
|
if (rval != TX_AUTH_SUCCESS)
|
||
|
next_step = AKE_INIT;
|
||
|
|
||
|
return rval;
|
||
|
}
|
||
|
|
||
|
int locality_check(struct hdcp_link_data *lk, struct hdcp_msg_info *msg_info)
|
||
|
{
|
||
|
int rval = TX_AUTH_SUCCESS;
|
||
|
|
||
|
switch (next_step) {
|
||
|
case LC_INIT:
|
||
|
{
|
||
|
rval = send_protocol_msg(lk, LC_INIT, msg_info);
|
||
|
if (rval < 0) {
|
||
|
hdcp_err("send LC_Init failed. rval(%d)\n", rval);
|
||
|
break;
|
||
|
}
|
||
|
else {
|
||
|
UPDATE_STEP_STATE(next_step, RTT_READY);
|
||
|
msg_info->next_step = RECIEVE_MSG;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
case RTT_READY:
|
||
|
{
|
||
|
/* if no precompute */
|
||
|
if (!is_precomput(lk)) {
|
||
|
hdcp_debug("LC with no precompute\n");
|
||
|
rval = recv_protocol_msg(lk, LC_SEND_L_PRIME, msg_info);
|
||
|
if (rval == TX_AUTH_SUCCESS) {
|
||
|
UPDATE_STEP_STATE(next_step, AKE_INIT);
|
||
|
msg_info->next_step = DONE;
|
||
|
}
|
||
|
else {
|
||
|
hdcp_err("recv LC_Send_L_prime failed. rval(%d)\n", rval);
|
||
|
}
|
||
|
break;
|
||
|
} else {
|
||
|
/* if precompute */
|
||
|
rval = recv_protocol_msg(lk, RTT_READY, msg_info);
|
||
|
if (rval < 0) {
|
||
|
hdcp_err("recv RTT_Ready failed. rval(%d)\n", rval);
|
||
|
}
|
||
|
else {
|
||
|
UPDATE_STEP_STATE(next_step, RTT_CHALLENGE);
|
||
|
msg_info->next_step = SEND_MSG;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
case RTT_CHALLENGE:
|
||
|
{
|
||
|
rval = send_protocol_msg(lk, RTT_CHALLENGE, msg_info);
|
||
|
if (rval < 0) {
|
||
|
hdcp_err("send RTT_Challenge failed. rval(%d)\n", rval);
|
||
|
}
|
||
|
else {
|
||
|
UPDATE_STEP_STATE(next_step, LC_SEND_L_PRIME);
|
||
|
msg_info->next_step = RECIEVE_MSG;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case LC_SEND_L_PRIME:
|
||
|
{
|
||
|
rval = recv_protocol_msg(lk, LC_SEND_L_PRIME, msg_info);
|
||
|
if (rval == TX_AUTH_SUCCESS){
|
||
|
msg_info->next_step = DONE;
|
||
|
if (evaluate_repeater(lk))
|
||
|
UPDATE_STEP_STATE(next_step, REPEATERAUTH_SEND_RECEIVERID_LIST);
|
||
|
else
|
||
|
UPDATE_STEP_STATE(next_step, AKE_INIT);
|
||
|
}
|
||
|
else {
|
||
|
hdcp_err("recv LC_Send_L_prime failed. rval(%d)\n", rval);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
return -ENOTTY;
|
||
|
}
|
||
|
|
||
|
return rval;
|
||
|
}
|
||
|
|
||
|
int exchange_hdcp_session_key(struct hdcp_link_data *lk, struct hdcp_msg_info *msg_info)
|
||
|
{
|
||
|
int rval = TX_AUTH_SUCCESS;
|
||
|
|
||
|
/* find session key from the session data */
|
||
|
if (get_hdcp_session_key(lk) < 0) {
|
||
|
hdcp_err("get_hdcp_session_key() failed\n");
|
||
|
rval = -TX_AUTH_ERRRO_RESTORE_SKEY;
|
||
|
}
|
||
|
|
||
|
rval = send_protocol_msg(lk, SKE_SEND_EKS, msg_info);
|
||
|
if (rval < 0)
|
||
|
hdcp_err("send SKE_Send_Eks() failed\n");
|
||
|
|
||
|
if (put_hdcp_session_key(lk) < 0) {
|
||
|
hdcp_err("put_hdcp_session_key() failed\n");
|
||
|
rval = -TX_AUTH_ERROR_STORE_SKEY;
|
||
|
}
|
||
|
|
||
|
return rval;
|
||
|
}
|
||
|
|
||
|
int evaluate_repeater(struct hdcp_link_data *lk)
|
||
|
{
|
||
|
if (lk->rx_ctx.repeater == REPEATER)
|
||
|
return TRUE;
|
||
|
else
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
int wait_for_receiver_id_list(struct hdcp_link_data *lk, struct hdcp_msg_info *msg_info)
|
||
|
{
|
||
|
int rval = TX_AUTH_SUCCESS;
|
||
|
|
||
|
rval = recv_protocol_msg(lk, REPEATERAUTH_SEND_RECEIVERID_LIST, msg_info);
|
||
|
if (rval < 0) {
|
||
|
hdcp_err("recv RepeaterAuth_Send_ReceiverID_List failed. rval(%d)\n", rval);
|
||
|
return rval;
|
||
|
}
|
||
|
|
||
|
UPDATE_STEP_STATE(next_step, REPEATERAUTH_SEND_ACK);
|
||
|
return rval;
|
||
|
}
|
||
|
|
||
|
int send_receiver_id_list_ack(struct hdcp_link_data *lk, struct hdcp_msg_info *msg_info)
|
||
|
{
|
||
|
int rval = TX_AUTH_SUCCESS;
|
||
|
|
||
|
switch (next_step) {
|
||
|
case REPEATERAUTH_SEND_ACK:
|
||
|
{
|
||
|
rval = send_protocol_msg(lk, REPEATERAUTH_SEND_ACK, msg_info);
|
||
|
if (rval < 0) {
|
||
|
hdcp_err("send RepeaterAuth_Send_Ack() failed. rval(%d)\n", rval);
|
||
|
}
|
||
|
else {
|
||
|
UPDATE_STEP_STATE(next_step, RECEIVER_AUTHSTATUS);
|
||
|
msg_info->next_step = RP_RECIEVE_MSG;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case RECEIVER_AUTHSTATUS:
|
||
|
{
|
||
|
rval = recv_protocol_msg(lk, RECEIVER_AUTHSTATUS, msg_info);
|
||
|
if (rval < 0) {
|
||
|
hdcp_err("send Receiver_AuthStatus() failed. rval(%d)\n", rval);
|
||
|
}
|
||
|
else {
|
||
|
UPDATE_STEP_STATE(next_step, REPEATERAUTH_STREAM_MANAGE);
|
||
|
msg_info->next_step = DONE;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
return -ENOTTY;
|
||
|
}
|
||
|
|
||
|
if (lk->tx_ctx.rp_reauth) {
|
||
|
hdcp_err("receiver request reauthentication\n");
|
||
|
return -TX_AUTH_ERROR_TIME_EXCEED;
|
||
|
}
|
||
|
else
|
||
|
hdcp_err("Repeater send reAuth value:: %d\n", lk->tx_ctx.rp_reauth);
|
||
|
|
||
|
return rval;
|
||
|
}
|
||
|
|
||
|
int manage_content_stream(struct hdcp_link_data *lk, struct contents_info *stream_ctrl, struct hdcp_stream_info *stream_info)
|
||
|
{
|
||
|
|
||
|
int rval = TX_AUTH_SUCCESS;
|
||
|
struct hdcp_msg_info msg_info;
|
||
|
|
||
|
if (stream_info->msg_len < sizeof(msg_info.msg) && stream_info->msg_len > 0)
|
||
|
msg_info.msg_len = stream_info->msg_len;
|
||
|
else
|
||
|
return HDCP_ERROR_INVALID_STREAM_LEN;
|
||
|
|
||
|
memcpy(msg_info.msg, stream_info->msg, stream_info->msg_len);
|
||
|
switch (next_step) {
|
||
|
case REPEATERAUTH_STREAM_MANAGE:
|
||
|
{
|
||
|
memcpy(&lk->tx_ctx.stream_ctrl, stream_ctrl, sizeof(struct contents_info));
|
||
|
rval = send_protocol_msg(lk, REPEATERAUTH_STREAM_MANAGE, &msg_info);
|
||
|
if (rval < 0) {
|
||
|
hdcp_err("send RepeaterAuth_stream_manage() failed. rval(%d)\n", rval);
|
||
|
break;
|
||
|
}
|
||
|
else {
|
||
|
UPDATE_STEP_STATE(next_step, REPEATERAUTH_STREAM_READY);
|
||
|
stream_info->next_step = ST_RECIEVE_MSG;
|
||
|
if (msg_info.msg_len > STREAM_MAX_LEN) {
|
||
|
hdcp_err("send RepeaterAuth_stream_manage() failed. rval(%d)\n", rval);
|
||
|
return TX_AUTH_ERROR_WRONG_MSG;
|
||
|
}
|
||
|
|
||
|
memcpy(stream_info->msg, msg_info.msg, msg_info.msg_len);
|
||
|
stream_info->msg_len = msg_info.msg_len;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
case REPEATERAUTH_STREAM_READY:
|
||
|
{
|
||
|
rval = recv_protocol_msg(lk, REPEATERAUTH_STREAM_READY, &msg_info);
|
||
|
if (rval < 0) {
|
||
|
hdcp_err("send Receiver_AuthStatus() failed. rval(%d)\n", rval);
|
||
|
break;
|
||
|
}
|
||
|
else {
|
||
|
UPDATE_STEP_STATE(next_step, AKE_INIT);
|
||
|
stream_info->next_step = RP_FINISHED;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (msg_info.msg_len < sizeof(stream_info->msg) && msg_info.msg_len > 0)
|
||
|
memcpy(stream_info->msg, msg_info.msg, msg_info.msg_len);
|
||
|
}
|
||
|
default:
|
||
|
return -ENOTTY;
|
||
|
}
|
||
|
|
||
|
return TX_AUTH_SUCCESS;
|
||
|
}
|
||
|
|
||
|
int determine_rx_hdcp_cap(struct hdcp_link_data *lk)
|
||
|
{
|
||
|
/* todo */
|
||
|
return 0;
|
||
|
}
|