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

1204 lines
28 KiB
C
Raw Normal View History

2023-06-18 22:53:49 +00:00
/* drivers/soc/samsung/exynos-hdcp/dplink/exynos-hdcp2-dplink-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 <linux/delay.h>
#include "../exynos-hdcp2.h"
#include "../exynos-hdcp2-misc.h"
#include "../exynos-hdcp2-log.h"
#include "exynos-hdcp2-dplink-auth.h"
#include "exynos-hdcp2-dplink-if.h"
#include "exynos-hdcp2-dplink.h"
#define MAX_LC_RETRY 10
static uint8_t pairing_ready;
static uint8_t hprime_ready;
uint8_t rp_ready;
uint8_t rp_ready_s;
static uint8_t reauth_req;
static uint8_t integrity_fail;
static char *hdcp_msgid_str[] = {
NULL,
"Null message",
"DP_AKE_Init",
"DP_AKE_Send_Cert",
"DP_AKE_No_Stored_km",
"DP_AKE_Stored_km",
"DP_AKE_Send_rrx",
"DP_AKE_Send_H_prime",
"DP_AKE_Send_Pairing_Info",
"DP_LC_Init",
"DP_LC_Send_L_prime",
"DP_SKE_Send_Eks",
"DP_RepeaterAuth_Send_ReceiverID_List",
"DP_RTT_Ready",
"DP_RTT_Challenge",
"DP_RepeaterAuth_Send_Ack",
"DP_RepeaterAuth_Stream_Manage",
"DP_RepeaterAuth_Stream_Ready",
"DP_Receiver_AuthStatus",
"DP_AKE_Transmitter_Info",
"DPAKE_Receiver_Info",
NULL
};
struct dp_ake_init {
uint8_t rtx[HDCP_AKE_RTX_BYTE_LEN];
uint8_t txcaps[HDCP_CAPS_BYTE_LEN];
};
struct dp_ake_send_cert {
uint8_t cert_rx[HDCP_RX_CERT_LEN];
uint8_t rrx[HDCP_RRX_BYTE_LEN];
uint8_t rxcaps[HDCP_CAPS_BYTE_LEN];
};
struct dp_ake_no_stored_km {
uint8_t ekpub_km[HDCP_AKE_ENCKEY_BYTE_LEN];
};
struct dp_ake_stored_km {
uint8_t ekh_km[HDCP_AKE_EKH_MKEY_BYTE_LEN];
uint8_t m[HDCP_AKE_M_BYTE_LEN];
};
struct dp_ake_send_h_prime {
uint8_t h_prime[HDCP_HMAC_SHA256_LEN];
};
struct dp_ake_send_pairing_info {
uint8_t ekh_km[HDCP_AKE_MKEY_BYTE_LEN];
};
struct dp_lc_init {
uint8_t rn[HDCP_RTX_BYTE_LEN];
};
struct dp_lc_send_l_prime {
uint8_t l_prime[HDCP_HMAC_SHA256_LEN];
};
struct dp_ske_send_eks {
uint8_t edkey_ks[HDCP_AKE_MKEY_BYTE_LEN];
uint8_t riv[HDCP_RTX_BYTE_LEN];
};
struct dp_rp_send_rcvid_list {
uint8_t rx_info[HDCP_RP_RX_INFO_LEN];
uint8_t seq_num_v[HDCP_RP_SEQ_NUM_V_LEN];
uint8_t v_prime[HDCP_RP_HMAC_V_LEN / 2];
uint8_t rcvid_list[HDCP_RP_RCVID_LIST_LEN];
};
struct dp_rp_send_ack {
uint8_t v[HDCP_RP_HMAC_V_LEN / 2];
};
struct dp_rp_stream_manage {
uint8_t seq_num_m[HDCP_RP_SEQ_NUM_M_LEN];
uint8_t k[HDCP_RP_K_LEN];
uint8_t streamid_type[HDCP_RP_MAX_STREAMID_TYPE_LEN];
};
struct dp_rp_stream_ready {
uint8_t m_prime[HDCP_RP_HMAC_M_LEN];
};
struct rxinfo {
uint8_t depth;
uint8_t dev_count;
uint8_t max_dev_exd;
uint8_t max_cascade_exd;
uint8_t hdcp20_downstream;
uint8_t hdcp1x_downstream;
};
static uint16_t dp_htons(uint16_t x)
{
return (
((x & 0x00FF) << 8) |
((x & 0xFF00) >> 8)
);
}
static void rxinfo_convert_arr2st(uint8_t *arr, struct rxinfo *st)
{
uint16_t rxinfo_val;
memcpy((uint8_t *)&rxinfo_val, arr, sizeof(rxinfo_val));
/* convert to little endian */
rxinfo_val = dp_htons(rxinfo_val);
st->depth = (rxinfo_val >> DEPTH_SHIFT) & DEPTH_MASK;
st->dev_count = (rxinfo_val >> DEV_COUNT_SHIFT) & DEV_COUNT_MASK;
st->max_dev_exd = (rxinfo_val >> DEV_EXD_SHIFT) & DEV_EXD_MASK;
st->max_cascade_exd = (rxinfo_val >> CASCADE_EXD_SHIFT) & CASCADE_EXD_MASK;
st->hdcp20_downstream = (rxinfo_val >> HDCP20_DOWN_SHIFT) & HDCP20_DOWN_MASK;
st->hdcp1x_downstream = (rxinfo_val >> HDCP1X_DOWN_SHIFT) & HDCP1X_DOWN_MASK;
}
#if defined(HDCP_DEBUG)
static void rxinfo_print_all_info(struct rxinfo *rx)
{
hdcp_info("RxInfo:\n");
hdcp_info("rxinfo.depth(%d)\n", rx->depth);
hdcp_info("rxinfo.dev_count(%d)\n", rx->dev_count);
hdcp_info("rxinfo.dev_exd(%d)\n", rx->max_dev_exd);
hdcp_info("rxinfo.cascade_exd(%d)\n", rx->max_cascade_exd);
hdcp_info("rxinfo.hdcp20_down(%d)\n", rx->hdcp20_downstream);
hdcp_info("rxinfo.hdcp1x_down(%d)\n", rx->hdcp1x_downstream);
}
#endif
static int is_auth_aborted(void)
{
/* todo: need mutex */
if (integrity_fail || reauth_req) {
/* clear flag */
dplink_clear_irqflag_all();
hdcp_err("Authentication is aborted\n");
return 1;
}
return 0;
}
static int dp_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,
HDCP_LINK_TYPE_DP,
&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;
}
int dp_recv_protocol_msg(struct hdcp_link_data *lk, uint8_t msg_id, struct hdcp_msg_info *msg_info)
{
int ret = TX_AUTH_SUCCESS;
if (msg_info->msg_len > 0) {
/* parsing received message */
ret = decap_protocol_msg(msg_id,
msg_info->msg,
msg_info->msg_len,
HDCP_LINK_TYPE_DP,
&lk->tx_ctx,
&lk->rx_ctx);
if (ret) {
hdcp_err("decap_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 dp_ake_find_masterkey(int *found)
{
int ret = TX_AUTH_SUCCESS;
uint8_t ekh_mkey[HDCP_AKE_EKH_MKEY_BYTE_LEN] = {0};
uint8_t m[HDCP_AKE_M_BYTE_LEN] = {0};
ret = ake_find_masterkey(found,
ekh_mkey, HDCP_AKE_EKH_MKEY_BYTE_LEN,
m, HDCP_AKE_M_BYTE_LEN);
if (ret) {
hdcp_err("fail to find stored km: ret(%d)\n", ret);
return -1;
}
return 0;
}
static int dp_get_hdcp_session_key(struct hdcp_link_data *lk)
{
return 0;
}
static int dp_put_hdcp_session_key(struct hdcp_link_data *lk)
{
return 0;
}
static int do_send_ake_init(struct hdcp_link_data *lk)
{
int ret;
struct hdcp_msg_info msg_info;
struct dp_ake_init *m_init;
/* check abort state firstly,
* if session is abored by Rx, Tx stops Authentication process
*/
if (is_auth_aborted())
return -TX_AUTH_ERROR_ABORT;
ret = dp_send_protocol_msg(lk, DP_AKE_INIT, &msg_info);
if (ret < 0) {
hdcp_err("AKE_Init failed: ret(%d)\n", ret);
return -1;
}
m_init = (struct dp_ake_init *)msg_info.msg;
ret = hdcp_dplink_send(HDCP22_MSG_RTX_W,
m_init->rtx,
sizeof(m_init->rtx));
if (ret) {
hdcp_err("rtx send fail: ret(%d)\n", ret);
return -1;
}
ret = hdcp_dplink_send(HDCP22_MSG_TXCAPS_W,
m_init->txcaps,
sizeof(m_init->txcaps));
if (ret) {
hdcp_err("txcaps send fail: ret(%d)\n", ret);
return -1;
}
return 0;
}
void parse_rxcaps_info(uint8_t *rxcaps, struct hdcp_link_data *lk)
{
memcpy(lk->rx_ctx.caps, rxcaps, sizeof(lk->rx_ctx.caps));
if (rxcaps[2] & DP_RXCAPS_REPEATER) {
hdcp_info("Rx is Repeater. rxcaps(0x%02x%02x%02x)\n",
rxcaps[0], rxcaps[1], rxcaps[2]);
lk->rx_ctx.repeater = 1;
} else {
hdcp_info("Rx is NOT Repeater. rxcaps(0x%02x%02x%02x)\n",
rxcaps[0], rxcaps[1], rxcaps[2]);
lk->rx_ctx.repeater = 0;
}
}
static int do_recv_ake_send_cert(struct hdcp_link_data *lk)
{
int ret;
struct hdcp_msg_info msg_info;
struct dp_ake_send_cert m_send_cert;
/* check abort state firstly,
* if session is abored by Rx, Tx stops Authentication process
*/
if (is_auth_aborted())
return -TX_AUTH_ERROR_ABORT;
ret = hdcp_dplink_recv(HDCP22_MSG_CERT_RX_R,
m_send_cert.cert_rx,
sizeof(m_send_cert.cert_rx));
if (ret) {
hdcp_err("ake_send_cert cert recv fail. ret(%d)\n", ret);
return -1;
}
#if defined(HDCP_DEBUG)
hdcp_debug("rx cert:\n");
hdcp_hexdump(m_send_cert.cert_rx, sizeof(m_send_cert.cert_rx));
#endif
ret = hdcp_dplink_recv(HDCP22_MSG_RRX_R,
m_send_cert.rrx,
sizeof(m_send_cert.rrx));
if (ret) {
hdcp_err("HDCP : ake_send_cert rrx recv fail: ret(%d)\n", ret);
return -1;
}
#if defined(HDCP_DEBUG)
hdcp_debug("rx rrx:\n");
hdcp_hexdump(m_send_cert.rrx, sizeof(m_send_cert.rrx));
#endif
ret = hdcp_dplink_recv(HDCP22_MSG_RXCAPS_R,
m_send_cert.rxcaps,
sizeof(m_send_cert.rxcaps));
if (ret) {
hdcp_err("ake_send_cert rxcaps recv fail: ret(%d)\n", ret);
return -1;
}
parse_rxcaps_info(m_send_cert.rxcaps, lk);
#if defined(HDCP_DEBUG)
hdcp_debug("rx caps\n");
hdcp_hexdump(m_send_cert.rxcaps, sizeof(m_send_cert.rxcaps));
#endif
memcpy(msg_info.msg, &m_send_cert, sizeof(struct dp_ake_send_cert));
msg_info.msg_len = sizeof(struct dp_ake_send_cert);
ret = dp_recv_protocol_msg(lk, DP_AKE_SEND_CERT, &msg_info);
if (ret < 0) {
hdcp_err("recv AKE_Send_Cert failed\n");
return -1;
}
return 0;
}
static int do_send_ake_nostored_km(struct hdcp_link_data *lk)
{
int ret;
struct hdcp_msg_info msg_info;
struct dp_ake_no_stored_km *m_nostored_km;
/* check abort state firstly,
* if session is abored by Rx, Tx stops Authentication process
*/
if (is_auth_aborted())
return -TX_AUTH_ERROR_ABORT;
ret = dp_send_protocol_msg(lk, DP_AKE_NO_STORED_KM, &msg_info);
if (ret < 0) {
hdcp_err("send AKE_No_Stored_km failed. ret(%d)\n", ret);
return -1;
}
m_nostored_km = (struct dp_ake_no_stored_km *)msg_info.msg;
ret = hdcp_dplink_send(HDCP22_MSG_EKPUB_KM_W,
m_nostored_km->ekpub_km,
sizeof(m_nostored_km->ekpub_km));
if (ret) {
hdcp_err("ake_no_stored_km send fail: ret(%d)\n", ret);
return -1;
}
return 0;
}
static int do_send_ake_stored_km(struct hdcp_link_data *lk)
{
int ret;
struct hdcp_msg_info msg_info;
struct dp_ake_stored_km *m_stored_km;
/* check abort state firstly,
* if session is abored by Rx, Tx stops Authentication process
*/
if (is_auth_aborted())
return -TX_AUTH_ERROR_ABORT;
ret = dp_send_protocol_msg(lk, DP_AKE_STORED_KM, &msg_info);
if (ret < 0) {
hdcp_err("send AKE_stored_km failed. ret(%d)\n", ret);
return -1;
}
m_stored_km = (struct dp_ake_stored_km *)msg_info.msg;
ret = hdcp_dplink_send(HDCP22_MSG_EKH_KM_W,
m_stored_km->ekh_km,
sizeof(m_stored_km->ekh_km));
if (ret) {
hdcp_err("ake_stored_km send fail: ret(%d)\n", ret);
return -1;
}
ret = hdcp_dplink_send(HDCP22_MSG_M_W,
m_stored_km->m,
sizeof(m_stored_km->m));
if (ret) {
hdcp_err("ake_stored_km send fail: ret(%d)\n", ret);
return -1;
}
return 0;
}
static int do_recv_ake_send_h_prime(struct hdcp_link_data *lk)
{
int ret;
struct hdcp_msg_info msg_info;
struct dp_ake_send_h_prime m_hprime;
/* check abort state firstly,
* if session is abored by Rx, Tx stops Authentication process
*/
if (is_auth_aborted())
return -TX_AUTH_ERROR_ABORT;
ret = hdcp_dplink_recv(HDCP22_MSG_HPRIME_R,
m_hprime.h_prime,
sizeof(m_hprime.h_prime));
if (ret) {
hdcp_err("ake_send_h_prime recv fail: ret(%d)\n", ret);
return -1;
}
#if defined(HDCP_DEBUG)
hdcp_debug("h_prime\n");
hdcp_hexdump(m_hprime.h_prime, sizeof(m_hprime.h_prime));
#endif
memcpy(msg_info.msg, &m_hprime, sizeof(struct dp_ake_send_h_prime));
msg_info.msg_len = sizeof(struct dp_ake_send_h_prime);
ret = dp_recv_protocol_msg(lk, DP_AKE_SEND_H_PRIME, &msg_info);
if (ret < 0) {
hdcp_err("recv AKE_Send_H_Prime failed. ret(%d)\n", ret);
return -1;
}
return 0;
}
static int do_recv_ake_send_pairing_info(struct hdcp_link_data *lk)
{
int ret;
struct hdcp_msg_info msg_info;
struct dp_ake_send_pairing_info m_pairing;
/* check abort state firstly,
* if session is abored by Rx, Tx stops Authentication process
*/
if (is_auth_aborted())
return -TX_AUTH_ERROR_ABORT;
ret = hdcp_dplink_recv(HDCP22_MSG_EKH_KM_R,
m_pairing.ekh_km,
sizeof(m_pairing.ekh_km));
if (ret) {
hdcp_err("ake_send_pairing_info recv fail: ret(%d)\n", ret);
return -1;
}
memcpy(msg_info.msg, &m_pairing, sizeof(struct dp_ake_send_pairing_info));
msg_info.msg_len = sizeof(struct dp_ake_send_pairing_info);
ret = dp_recv_protocol_msg(lk, DP_AKE_SEND_PAIRING_INFO, &msg_info);
if (ret < 0) {
hdcp_err("recv AKE_Send_Pairing_Info failed. ret(%d)\n", ret);
return -1;
}
return 0;
}
static int do_send_lc_init(struct hdcp_link_data *lk)
{
int ret;
struct hdcp_msg_info msg_info;
struct dp_lc_init *m_lc_init;
/* check abort state firstly,
* if session is abored by Rx, Tx stops Authentication process
*/
if (is_auth_aborted())
return -TX_AUTH_ERROR_ABORT;
ret = dp_send_protocol_msg(lk, DP_LC_INIT, &msg_info);
if (ret < 0) {
hdcp_err("send LC_init failed. ret(%d)\n", ret);
return -1;
}
m_lc_init = (struct dp_lc_init *)msg_info.msg;
ret = hdcp_dplink_send(HDCP22_MSG_RN_W,
m_lc_init->rn,
sizeof(m_lc_init->rn));
if (ret) {
hdcp_err("lc_init send fail: ret(%d)\n", ret);
return -1;
}
return 0;
}
static int do_recv_lc_send_l_prime(struct hdcp_link_data *lk)
{
int ret;
struct hdcp_msg_info msg_info;
struct dp_lc_send_l_prime m_lprime;
/* check abort state firstly,
* if session is abored by Rx, Tx stops Authentication process
*/
if (is_auth_aborted())
return -TX_AUTH_ERROR_ABORT;
ret = hdcp_dplink_recv(HDCP22_MSG_LPRIME_R,
m_lprime.l_prime,
sizeof(m_lprime.l_prime));
if (ret) {
hdcp_err("lc_send_l_prime recv fail. ret(%d)\n", ret);
return -1;
}
memcpy(msg_info.msg, &m_lprime, sizeof(struct dp_lc_send_l_prime));
msg_info.msg_len = sizeof(struct dp_lc_send_l_prime);
ret = dp_recv_protocol_msg(lk, DP_LC_SEND_L_PRIME, &msg_info);
if (ret < 0) {
hdcp_err("HDCP recv LC_Send_L_prime failed. ret(%d)\n", ret);
return -1;
}
return 0;
}
static int do_send_ske_send_eks(struct hdcp_link_data *lk)
{
int ret;
struct hdcp_msg_info msg_info;
struct dp_ske_send_eks *m_ske;
/* todo:
* Currently, SST mode only use 0x00 as type value
* MST mode, HDCP driver get type value from DP driver
*/
/* uint8_t type = 0x00; */
/* check abort state firstly,
* if session is abored by Rx, Tx stops Authentication process
*/
if (is_auth_aborted())
return -TX_AUTH_ERROR_ABORT;
ret = dp_send_protocol_msg(lk, DP_SKE_SEND_EKS, &msg_info);
if (ret < 0) {
hdcp_err("send SKE_SEND_EKS failed. ret(%d)\n", ret);
return -1;
}
m_ske = (struct dp_ske_send_eks *)msg_info.msg;
ret = hdcp_dplink_send(HDCP22_MSG_EDKEY_KS0_W,
&m_ske->edkey_ks[0],
sizeof(m_ske->edkey_ks)/2);
if (ret) {
hdcp_err("SKE_send_eks send fail. ret(%d)\n", ret);
return -1;
}
ret = hdcp_dplink_send(HDCP22_MSG_EDKEY_KS1_W,
&m_ske->edkey_ks[8],
sizeof(m_ske->edkey_ks)/2);
if (ret) {
hdcp_err("SKE_send_eks send fail. ret(%x)\n", ret);
return -1;
}
ret = hdcp_dplink_send(HDCP22_MSG_RIV_W,
m_ske->riv,
sizeof(m_ske->riv));
if (ret) {
hdcp_err("SKE_send_eks send fail. ret(%x)\n", ret);
return -1;
}
#if 0 /* todo: configure type */
/* HDCP errata defined stream type.
* type info is send only for receiver
*/
if (!lk->rx_ctx.repeater) {
ret = hdcp_dplink_send(HDCP22_MSG_TYPE_W,
&type,
sizeof(uint8_t));
if (ret) {
hdcp_err("HDCP : SKE_send_eks type send fail: %x\n", ret);
return -1;
}
}
#endif
return 0;
}
static int cal_rcvid_list_size(uint8_t *rxinfo, uint32_t *rcvid_size)
{
struct rxinfo rx;
int ret = 0;
rxinfo_convert_arr2st(rxinfo, &rx);
#if defined(HDCP_DEBUG)
rxinfo_print_all_info();
#endif
/* rx_list check */
if (rx.max_dev_exd || rx.max_cascade_exd)
return 1;
*rcvid_size = rx.dev_count * HDCP_RCV_ID_LEN;
return ret;
}
static int do_recv_rcvid_list(struct hdcp_link_data *lk)
{
int ret;
struct dp_rp_send_rcvid_list m_rcvid;
uint32_t rcvid_size = 0;
struct hdcp_msg_info msg_info;
/* check abort state firstly,
* if session is abored by Rx, Tx stops Authentication process
*/
if (is_auth_aborted())
return -TX_AUTH_ERROR_ABORT;
memset(&m_rcvid, 0x00, sizeof(m_rcvid));
ret = hdcp_dplink_recv(HDCP22_MSG_RXINFO_R,
m_rcvid.rx_info,
sizeof(m_rcvid.rx_info));
if (ret) {
hdcp_err("verify_receiver_id_list rx_info rcv fail: ret(%d)\n", ret);
return -1;
}
ret = hdcp_dplink_recv(HDCP22_MSG_SEQ_NUM_V_R,
m_rcvid.seq_num_v,
sizeof(m_rcvid.seq_num_v));
if (ret) {
hdcp_err("verify_receiver_id_list seq_num_v rcv fail: ret(%d)\n", ret);
return -1;
}
if ((m_rcvid.seq_num_v[0] || m_rcvid.seq_num_v[1] || m_rcvid.seq_num_v[2]) && rp_ready < 2) {
hdcp_err("Initial seq_num_v is non_zero.\n");
return -1;
}
ret = hdcp_dplink_recv(HDCP22_MSG_VPRIME_R,
m_rcvid.v_prime,
sizeof(m_rcvid.v_prime));
if (ret) {
hdcp_err("verify_receiver_id_list seq_num_v rcv fail: ret(%d)\n", ret);
return -1;
}
ret = cal_rcvid_list_size(m_rcvid.rx_info, &rcvid_size);
if (ret) {
hdcp_err("Cal_rcvid_list Fail ! (%d)\n", ret);
return -1;
}
ret = hdcp_dplink_recv(HDCP22_MSG_RECV_ID_LIST_R,
m_rcvid.rcvid_list,
rcvid_size);
if (ret) {
hdcp_err("verify_receiver_id_list rcvid_list rcv fail: ret(%d)\n", ret);
return -1;
}
memcpy(msg_info.msg, &m_rcvid, sizeof(struct dp_rp_send_rcvid_list));
msg_info.msg_len = sizeof(struct dp_rp_send_rcvid_list);
ret = dp_recv_protocol_msg(lk, DP_REPEATERAUTH_SEND_RECEIVERID_LIST, &msg_info);
if (ret < 0) {
hdcp_err("recv RepeaterAuth_Send_ReceiverID_List failed\n");
return -1;
}
return 0;
}
static int do_send_rp_ack(struct hdcp_link_data *lk)
{
int ret;
struct hdcp_msg_info msg_info;
struct dp_rp_send_ack *m_ack;
/* check abort state firstly,
* if session is abored by Rx, Tx stops Authentication process
*/
if (is_auth_aborted())
return -TX_AUTH_ERROR_ABORT;
ret = dp_send_protocol_msg(lk, DP_REPEATERAUTH_SEND_AKE, &msg_info);
if (ret < 0) {
hdcp_err("send RepeaterAuth_Send_Ack failed. ret(%d)\n", ret);
return -1;
}
m_ack = (struct dp_rp_send_ack *)msg_info.msg;
ret = hdcp_dplink_send(HDCP22_MSG_V_W,
m_ack->v,
sizeof(m_ack->v));
if (ret) {
hdcp_err("V send fail: ret(%d)\n", ret);
return -1;
}
return 0;
}
static int do_send_rp_stream_manage(struct hdcp_link_data *lk)
{
int ret;
struct hdcp_msg_info msg_info;
struct dp_rp_stream_manage *m_strm;
uint16_t stream_num;
/* check abort state firstly,
* if session is abored by Rx, Tx stops Authentication process
*/
if (is_auth_aborted())
return -TX_AUTH_ERROR_ABORT;
ret = dp_send_protocol_msg(lk, DP_REPEATERAUTH_STREAM_MANAGE, &msg_info);
if (ret < 0) {
hdcp_err("send RepeaterAuth_Stream_Manage. ret(%d)\n", ret);
return -1;
}
m_strm = (struct dp_rp_stream_manage *)msg_info.msg;
ret = hdcp_dplink_send(HDCP22_MSG_SEQ_NUM_M_W,
m_strm->seq_num_m,
sizeof(m_strm->seq_num_m));
if (ret) {
hdcp_err("seq_num_M send fail. ret(%d)\n", ret);
return -1;
}
ret = hdcp_dplink_send(HDCP22_MSG_K_W,
m_strm->k,
sizeof(m_strm->k));
if (ret) {
hdcp_err("k send fail. ret(%x)\n", ret);
return -1;
}
stream_num = lk->tx_ctx.strm.dp.stream_num;
ret = hdcp_dplink_send(HDCP22_MSG_STREAMID_TYPE_W,
m_strm->streamid_type,
stream_num * HDCP_RP_STREAMID_TYPE_LEN);
if (ret) {
hdcp_err("Streamid_Type send fail. ret(%x)\n", ret);
return -1;
}
return 0;
}
static int do_recv_rp_stream_ready(struct hdcp_link_data *lk)
{
int ret;
struct hdcp_msg_info msg_info;
struct dp_rp_stream_ready m_strm_ready;
/* check abort state firstly,
* if session is abored by Rx, Tx stops Authentication process
*/
if (is_auth_aborted())
return -TX_AUTH_ERROR_ABORT;
ret = hdcp_dplink_recv(HDCP22_MSG_MPRIME_R,
m_strm_ready.m_prime,
sizeof(m_strm_ready.m_prime));
if (ret) {
hdcp_err("M' recv fail. ret(%d)\n", ret);
return -1;
}
memcpy(msg_info.msg, &m_strm_ready, sizeof(struct dp_rp_stream_ready));
msg_info.msg_len = sizeof(struct dp_rp_stream_ready);
ret = dp_recv_protocol_msg(lk, DP_REPEATERAUTH_STREAM_READY, &msg_info);
if (ret < 0) {
hdcp_err("HDCP recv RepeaterAuth_Stream_Ready failed. ret(%d)\n", ret);
return -1;
}
return 0;
}
static int check_h_prime_ready(void)
{
int i = 0;
uint8_t status = 0;
/* check abort state firstly,
* if session is abored by Rx, Tx stops Authentication process
*/
if (is_auth_aborted())
return -TX_AUTH_ERROR_ABORT;
msleep(100);
/* HDCP spec is 1 sec. but we give margin 100ms */
while (i < 10) {
/* check abort state firstly,
* if session is abored by Rx, Tx stops Authentication process
*/
if (is_auth_aborted())
return -TX_AUTH_ERROR_ABORT;
/* received from CP_IRQ */
if (hprime_ready) {
/* reset flag */
hprime_ready = 0;
return 0;
}
/* check as polling mode */
hdcp_dplink_get_rxstatus(&status);
if (status & DP_RXSTATUS_HPRIME_AVAILABLE) {
/* reset flag */
hprime_ready = 0;
return 0;
}
msleep(100);
i++;
}
hdcp_err("hprime timeout(%dms)\n", (100 * i));
return -1;
}
static int check_pairing_ready(void)
{
int i = 0;
uint8_t status = 0;
/* check abort state firstly,
* if session is abored by Rx, Tx stops Authentication process
*/
if (is_auth_aborted())
return -TX_AUTH_ERROR_ABORT;
msleep(200);
/* HDCP spec is 200ms. but we give margin 100ms */
while (i < 2) {
/* check abort state firstly,
* if session is abored by Rx, Tx stops Authentication process
*/
if (is_auth_aborted())
return -TX_AUTH_ERROR_ABORT;
/* received from CP_IRQ */
if (pairing_ready) {
/* reset flag */
pairing_ready = 0;
return 0;
}
/* check as polling mode */
hdcp_dplink_get_rxstatus(&status);
if (status & DP_RXSTATUS_PAIRING_AVAILABLE) {
/* reset flag */
pairing_ready = 0;
return 0;
}
msleep(100);
i++;
}
hdcp_err("pairing timeout(%dms)\n", (100 * i));
return -1;
}
static int check_rcvidlist_ready(void)
{
int i = 0;
uint8_t status = 0;
/* HDCP spec is 3 sec */
while (i < 30) {
/* check abort state firstly,
* if session is abored by Rx, Tx stops Authentication process
*/
if (is_auth_aborted())
return -TX_AUTH_ERROR_ABORT;
/* received from CP_IRQ */
if (rp_ready > rp_ready_s) {
/* reset flag */
rp_ready_s = rp_ready;
return 0;
}
/* check as polling mode */
hdcp_dplink_get_rxstatus(&status);
if (status & DP_RXSTATUS_READY) {
rp_ready++;
return 0;
}
msleep(100);
i++;
}
hdcp_err("receiver ID list timeout(%dms)\n", (100 * i));
return -TX_AUTH_ERROR_TIME_EXCEED;
}
int dplink_exchange_master_key(struct hdcp_link_data *lk)
{
int rval = TX_AUTH_SUCCESS;
int key_found;
do {
/* send Tx -> Rx: AKE_init */
if (do_send_ake_init(lk) < 0) {
hdcp_err("send_ake_int fail\n");
rval = -TX_AUTH_ERROR_SEND_PROTO_MSG;
break;
}
/* HDCP spec defined 100ms as min delay after write AKE_Init */
msleep(100);
/* recv Rx->Tx: AKE_Send_Cert message */
if (do_recv_ake_send_cert(lk) < 0) {
hdcp_err("recv_ake_send_cert fail\n");
rval = -TX_AUTH_ERROR_RECV_PROTO_MSG;
break;
}
/* send Tx->Rx: AKE_Stored_km or AKE_No_Stored_km message */
if (dp_ake_find_masterkey(&key_found) < 0) {
hdcp_err("find master key fail\n");
rval = -TX_AUTH_ERROR_MAKE_PROTO_MSG;
break;
}
if (!key_found) {
if (do_send_ake_nostored_km(lk) < 0) {
hdcp_err("ake_send_nostored_km fail\n");
rval = -TX_AUTH_ERROR_SEND_PROTO_MSG;
break;
}
lk->stored_km = HDCP_WITHOUT_STORED_KM;
} else {
if (do_send_ake_stored_km(lk) < 0) {
hdcp_err("ake_send_stored_km fail\n");
rval = -TX_AUTH_ERROR_SEND_PROTO_MSG;
break;
}
lk->stored_km = HDCP_WITH_STORED_KM;
}
if (check_h_prime_ready() < 0) {
hdcp_err("Cannot read H prime\n");
rval = -TX_AUTH_ERROR_RECV_PROTO_MSG;
break;
}
/* recv Rx->Tx: AKE_Send_H_Prime message */
if (do_recv_ake_send_h_prime(lk) < 0) {
hdcp_err("recv_ake_send_h_prime fail\n");
rval = -TX_AUTH_ERROR_RECV_PROTO_MSG;
break;
}
if (lk->stored_km == HDCP_WITHOUT_STORED_KM) {
if (check_pairing_ready() < 0) {
hdcp_err("Cannot read pairing info\n");
rval = -TX_AUTH_ERROR_RECV_PROTO_MSG;
break;
}
/* recv Rx->Tx: AKE_Send_Pairing_Info message */
if (do_recv_ake_send_pairing_info(lk) < 0) {
hdcp_err("recv_ake_send_h_prime fail\n");
rval = -TX_AUTH_ERROR_RECV_PROTO_MSG;
break;
}
}
} while (0);
return rval;
}
int dplink_locality_check(struct hdcp_link_data *lk)
{
int i;
for (i = 0; i < MAX_LC_RETRY; i++) {
/* send Tx -> Rx: LC_init */
if (do_send_lc_init(lk) < 0) {
hdcp_err("send_lc_init fail\n");
return -TX_AUTH_ERROR_SEND_PROTO_MSG;
}
/* wait until max dealy */
msleep(7);
/* recv Rx -> Tx: LC_Send_L_Prime */
if (do_recv_lc_send_l_prime(lk) < 0) {
hdcp_err("recv_lc_send_l_prime fail\n");
/* retry */
continue;
} else {
hdcp_debug("LC success. retryed(%d)\n", i);
break;
}
}
if (i == MAX_LC_RETRY) {
hdcp_err("LC check fail. exceed retry count(%d)\n", i);
return -TX_AUTH_ERROR_RETRYCOUNT_EXCEED;
}
return TX_AUTH_SUCCESS;
}
int dplink_exchange_session_key(struct hdcp_link_data *lk)
{
/* find session key from the session data */
if (dp_get_hdcp_session_key(lk) < 0) {
hdcp_err("dp_get_hdcp_session_key() failed\n");
return -TX_AUTH_ERRRO_RESTORE_SKEY;
}
/* Send Tx -> Rx: SKE_Send_Eks */
if (do_send_ske_send_eks(lk) < 0) {
hdcp_err("send_ske_send_eks fail\n");
return -TX_AUTH_ERROR_SEND_PROTO_MSG;
}
if (dp_put_hdcp_session_key(lk) < 0) {
hdcp_err("put_hdcp_session_key() failed\n");
return -TX_AUTH_ERROR_STORE_SKEY;
}
return TX_AUTH_SUCCESS;
}
int dplink_evaluate_repeater(struct hdcp_link_data *lk)
{
if (lk->rx_ctx.repeater)
return TRUE;
else
return FALSE;
}
int dplink_wait_for_receiver_id_list(struct hdcp_link_data *lk)
{
int ret;
ret = check_rcvidlist_ready();
if (ret < 0)
return ret;
else
return TX_AUTH_SUCCESS;
}
int dplink_verify_receiver_id_list(struct hdcp_link_data *lk)
{
/* recv Rx->Tx: RepeaterAuth_ReceiverID_List message */
if (do_recv_rcvid_list(lk) < 0) {
hdcp_err("recv_receiverID_list fail\n");
return -TX_AUTH_ERROR_RECV_PROTO_MSG;
}
return TX_AUTH_SUCCESS;
}
int dplink_send_receiver_id_list_ack(struct hdcp_link_data *lk)
{
/* Send Tx -> Rx: RepeaterAuth_Send_Ack */
if (do_send_rp_ack(lk) < 0) {
hdcp_err("send_rp_ack fail\n");
return -TX_AUTH_ERROR_SEND_PROTO_MSG;
}
return TX_AUTH_SUCCESS;
}
int dplink_determine_rx_hdcp_cap(struct hdcp_link_data *lk)
{
int ret;
uint8_t rxcaps[HDCP_CAPS_BYTE_LEN];
ret = hdcp_dplink_recv(HDCP22_MSG_RXCAPS_R,
rxcaps,
sizeof(rxcaps));
if (ret) {
hdcp_err("check rx caps recv fail: ret(%d)\n", ret);
return -1;
}
#if defined(HDCP_DEBUG)
hdcp_debug("rx caps\n");
hdcp_hexdump(rxcaps, sizeof(rxcaps));
#endif
if (!(rxcaps[2] & DP_RXCAPS_HDCP_CAPABLE)) {
hdcp_err("Rx is not support HDCP. rxcaps(0x%02x%02x%02x)\n",
rxcaps[0], rxcaps[1], rxcaps[2]);
return -1;
}
if (rxcaps[0] != DP_RXCAPS_HDCP_VERSION_2) {
hdcp_err("Rx is not HDCP2.x. rxcaps(0x%02x%02x%02x)\n",
rxcaps[0], rxcaps[1], rxcaps[2]);
return -1;
}
return 0;
}
int dplink_stream_manage(struct hdcp_link_data *lk)
{
/* Send Tx -> Rx: RepeaterAuth_Stream_Manage */
if (do_send_rp_stream_manage(lk) < 0) {
hdcp_err("send_rp_stream_manage fail\n");
return -TX_AUTH_ERROR_SEND_PROTO_MSG;
}
/* HDCP spec define 100ms as min delay. But we give 100ms margin */
msleep(200);
/* recv Rx->Tx: RepeaterAuth_Stream_Ready message */
if (do_recv_rp_stream_ready(lk) < 0) {
hdcp_err("recv_rp_stream_ready fail\n");
return -TX_AUTH_ERROR_RECV_PROTO_MSG;
}
return TX_AUTH_SUCCESS;
}
int dplink_set_paring_available(void)
{
pairing_ready = 1;
return 0;
}
int dplink_set_hprime_available(void)
{
hprime_ready = 1;
return 0;
}
int dplink_set_rp_ready(void)
{
rp_ready++;
return 0;
}
int dplink_set_reauth_req(void)
{
reauth_req = 1;
return 0;
}
int dplink_set_integrity_fail(void)
{
dplink_clear_irqflag_all();
integrity_fail = 1;
return 0;
}
void dplink_clear_irqflag_all(void)
{
pairing_ready = 0;
hprime_ready = 0;
rp_ready = 0;
rp_ready_s = 0;
reauth_req = 0;
integrity_fail = 0;
}