# Exynos Secure Log
obj-$(CONFIG_EXYNOS_SECURE_LOG) += exynos-seclog.o
+
+# HDCP
+obj-$(CONFIG_EXYNOS_HDCP2) += exynos-hdcp/
--- /dev/null
+#
+# HDCP driver configuration
+#
+
+menuconfig EXYNOS_HDCP2
+ bool "HDCP2 driver support"
+ default y
+ help
+ Enable HDCP2 support
+
+if EXYNOS_HDCP2
+
+config HDCP2_EMULATION_MODE
+ bool "HDCP2 emulation mode support"
+ default n
+ help
+ Enable HDCP2 emulation mode support
+
+config HDCP2_DP_ENABLE
+ bool "HDCP2 DP protocol support"
+ default y
+ help
+ Enable HDCP2 DP protocol support
+
+config HDCP2_IIA_ENABLE
+ bool "HDCP2 HDCP protocol support"
+ default n
+ help
+ Enable HDCP2 DP protocol support
+
+config HDCP2_FUNC_TEST_MODE
+ bool "HDCP2 DP Default Enabled"
+ default n
+ help
+ Enable HDCP2 DP Function test mode.
+
+endif
--- /dev/null
+#
+# Exynos HDCP drivers
+#
+
+# HDCP
+obj-$(CONFIG_EXYNOS_HDCP2) += exynos-hdcp2-session.o
+obj-$(CONFIG_EXYNOS_HDCP2) += exynos-hdcp2-teeif.o
+obj-$(CONFIG_EXYNOS_HDCP2) += exynos-hdcp2.o
+obj-$(CONFIG_EXYNOS_HDCP2) += exynos-hdcp2-misc.o
+obj-$(CONFIG_EXYNOS_HDCP2) += exynos-hdcp2-encrypt.o
+obj-$(CONFIG_EXYNOS_HDCP2) += exynos-hdcp2-crypto.o
+obj-$(CONFIG_EXYNOS_HDCP2) += exynos-hdcp2-protocol-msg.o
+obj-$(CONFIG_EXYNOS_HDCP2) += iia_link/exynos-hdcp2-iia-auth.o
+obj-$(CONFIG_EXYNOS_HDCP2) += iia_link/exynos-hdcp2-iia.o
+obj-$(CONFIG_EXYNOS_HDCP2) += iia_link/exynos-hdcp2-iia-selftest.o
+obj-$(CONFIG_EXYNOS_HDCP2) += dp_link/exynos-hdcp2-dplink.o
+obj-$(CONFIG_EXYNOS_HDCP2) += dp_link/exynos-hdcp2-dplink-if.o
+obj-$(CONFIG_EXYNOS_HDCP2) += dp_link/exynos-hdcp2-dplink-auth.o
+obj-$(CONFIG_EXYNOS_HDCP2) += dp_link/exynos-hdcp2-dplink-protocol-msg.o
+obj-$(CONFIG_EXYNOS_HDCP2) += dp_link/exynos-hdcp2-dplink-selftest.o
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* drivers/soc/samsung/exynos-hdcp/dplink/exynos-hdcp2-dplink-auth.h
+ *
+ * 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.
+*/
+#ifndef __EXYNOS_HDCP2_DPLINK_AUTH_H__
+#define __EXYNOS_HDCP2_DPLINK_AUTH_H__
+
+#include "exynos-hdcp2-dplink-protocol-msg.h"
+
+int dplink_determine_rx_hdcp_cap(struct hdcp_link_data *lk);
+int dplink_exchange_master_key(struct hdcp_link_data *lk);
+int dplink_locality_check(struct hdcp_link_data *lk);
+int dplink_exchange_session_key(struct hdcp_link_data *lk);
+int dplink_evaluate_repeater(struct hdcp_link_data *lk);
+int dplink_wait_for_receiver_id_list(struct hdcp_link_data *lk);
+int dplink_verify_receiver_id_list(struct hdcp_link_data *lk);
+int dplink_send_receiver_id_list_ack(struct hdcp_link_data *lk);
+int dplink_stream_manage(struct hdcp_link_data *lk);
+int dplink_get_rxstatus(uint8_t *status);
+int dplink_set_paring_available(void);
+int dplink_set_hprime_available(void);
+int dplink_set_rp_ready(void);
+int dplink_set_reauth_req(void);
+int dplink_set_integrity_fail(void);
+void dplink_clear_irqflag_all(void);
+
+#endif
--- /dev/null
+/*
+ * drivers/soc/samsung/exynos_hdcp/dp_link/exynos-hdcp2-dplink-if.c
+ *
+ * Copyright (c) 2015 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 <net/sock.h>
+#include <linux/netlink.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include "../exynos-hdcp2-log.h"
+#include "exynos-hdcp2-dplink-reg.h"
+#include "exynos-hdcp2-dplink-if.h"
+
+#if defined(CONFIG_HDCP2_EMULATION_MODE)
+#define NETLINK_HDCP 31
+#define SOCK_BUF_SIZE (1024 * 512)
+#define NETLINK_PORT 1000
+
+struct sock *nl_sk = NULL;
+struct sk_buff sk_buf;
+uint8_t dplink_wait;
+uint8_t *nl_data;
+struct nlmsghdr *nlh;
+
+void cb_hdcp_nl_recv_msg(struct sk_buff *skb);
+
+int hdcp_dplink_init(void)
+{
+ struct netlink_kernel_cfg cfg = {
+ .input = cb_hdcp_nl_recv_msg,
+ };
+
+ nl_sk = netlink_kernel_create(&init_net, NETLINK_HDCP, &cfg);
+ if (!nl_sk) {
+ hdcp_err("Error creating socket.\n");
+ return -EINVAL;
+ }
+
+ nl_data = (uint8_t *)kzalloc(SOCK_BUF_SIZE, GFP_KERNEL);
+ if (!nl_data) {
+ hdcp_err("Netlink Socket buffer alloc fail\n");
+ return -EINVAL;
+ }
+
+ dplink_wait = 1;
+
+ return 0;
+}
+
+/* callback for netlink driver */
+void cb_hdcp_nl_recv_msg(struct sk_buff *skb)
+{
+ nlh = (struct nlmsghdr *)skb->data;
+
+ memcpy(nl_data, (uint8_t *)nlmsg_data(nlh), nlmsg_len(nlh));
+ dplink_wait = 0;
+}
+
+static void nl_recv_msg(uint8_t *data, uint32_t size)
+{
+ /* todo: change to not a busy wait */
+ while (dplink_wait) {
+ hdcp_err("wait dplink_wait\n");
+ msleep(1000);
+ }
+
+ memcpy(data, nl_data, size);
+
+ dplink_wait = 1;
+}
+
+int hdcp_dplink_recv(uint32_t msg_name, uint8_t *data, uint32_t size)
+{
+ nl_recv_msg(data, size);
+ return 0;
+}
+
+int hdcp_dplink_send(uint32_t msg_name, uint8_t *data, uint32_t size)
+{
+ struct sk_buff *skb_out;
+ int ret;
+
+ skb_out = nlmsg_new(size, 0);
+ if (!skb_out) {
+ hdcp_err("Failed to allocate new skb\n");
+ return -1;
+ }
+ nlh = nlmsg_put(skb_out, 0, 0, 2, size, NLM_F_REQUEST);
+ if (!nlh) {
+ hdcp_err("fail to nlmsg_put()\n");
+ return -1;
+ }
+
+ NETLINK_CB(skb_out).dst_group = 0; /* not in mcast group */
+ memcpy(nlmsg_data(nlh), data, size);
+
+ ret = nlmsg_unicast(nl_sk, skb_out, NETLINK_PORT);
+ if (ret < 0) {
+ hdcp_err("Error while sending bak to user\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int hdcp_dplink_is_enabled_hdcp22(void)
+{
+ /* todo: check hdcp22 enable */
+ return 1;
+}
+
+void hdcp_dplink_config(int en)
+{
+ /* dummy function */
+}
+#else
+
+
+/* Address define for HDCP within DPCD address space */
+uint32_t dpcd_addr[NUM_HDCP22_MSG_NAME] = {
+ DPCD_ADDR_HDCP22_Rtx,
+ DPCD_ADDR_HDCP22_TxCaps,
+ DPCD_ADDR_HDCP22_cert_rx,
+ DPCD_ADDR_HDCP22_Rrx,
+ DPCD_ADDR_HDCP22_RxCaps,
+ DPCD_ADDR_HDCP22_Ekpub_km,
+ DPCD_ADDR_HDCP22_Ekh_km_w,
+ DPCD_ADDR_HDCP22_m,
+ DPCD_ADDR_HDCP22_Hprime,
+ DPCD_ADDR_HDCP22_Ekh_km_r,
+ DPCD_ADDR_HDCP22_rn,
+ DPCD_ADDR_HDCP22_Lprime,
+ DPCD_ADDR_HDCP22_Edkey0_ks,
+ DPCD_ADDR_HDCP22_Edkey1_ks,
+ DPCD_ADDR_HDCP22_riv,
+ DPCD_ADDR_HDCP22_RxInfo,
+ DPCD_ADDR_HDCP22_seq_num_V,
+ DPCD_ADDR_HDCP22_Vprime,
+ DPCD_ADDR_HDCP22_Rec_ID_list,
+ DPCD_ADDR_HDCP22_V,
+ DPCD_ADDR_HDCP22_seq_num_M,
+ DPCD_ADDR_HDCP22_k,
+ DPCD_ADDR_HDCP22_stream_IDtype,
+ DPCD_ADDR_HDCP22_Mprime,
+ DPCD_ADDR_HDCP22_RxStatus,
+ DPCD_ADDR_HDCP22_Type,
+};
+
+#if defined(CONFIG_EXYNOS_DISPLAYPORT)
+extern int displayport_dpcd_read_for_hdcp22(u32 address, u32 length, u8 *data);
+extern int displayport_dpcd_write_for_hdcp22(u32 address, u32 length, u8 *data);
+extern void displayport_hdcp22_enable(u32 en);
+
+#else
+int displayport_dpcd_read_for_hdcp22(u32 address, u32 length, u8 *data)
+{
+ return 0;
+}
+int displayport_dpcd_write_for_hdcp22(u32 address, u32 length, u8 *data)
+{
+ return 0;
+}
+void displayport_hdcp22_enable(u32 en)
+{
+ return;
+}
+#endif
+
+int hdcp_dplink_init(void)
+{
+ /* todo */
+ return 0;
+}
+
+void hdcp_dplink_config(int en)
+{
+ displayport_hdcp22_enable(en);
+}
+
+int hdcp_dplink_is_enabled_hdcp22(void)
+{
+ /* todo: check hdcp22 enable */
+ return 1;
+}
+
+/* todo: get stream info from DP */
+#define HDCP_DP_STREAM_NUM 0x01
+static uint8_t stream_id[1] = {0x00};
+int hdcp_dplink_get_stream_info(uint16_t *num, uint8_t *strm_id)
+{
+ *num = HDCP_DP_STREAM_NUM;
+ memcpy(strm_id, stream_id, sizeof(uint8_t) * (*num));
+
+ return 0;
+}
+
+int hdcp_dplink_recv(uint32_t msg_name, uint8_t *data, uint32_t size)
+{
+ int i;
+ int ret;
+ int remain;
+
+ if (size > DPCD_PACKET_SIZE) {
+ for (i = 0; i < (size / DPCD_PACKET_SIZE); i++) {
+ ret = displayport_dpcd_read_for_hdcp22(
+ dpcd_addr[msg_name] + i * DPCD_PACKET_SIZE,
+ DPCD_PACKET_SIZE,
+ &data[i * DPCD_PACKET_SIZE]);
+ if (ret) {
+ hdcp_err("dpcd read fail. ret(%d)\n", ret);
+ return ret;
+ }
+ }
+
+ remain = size % DPCD_PACKET_SIZE;
+ if (remain) {
+ ret = displayport_dpcd_read_for_hdcp22(
+ dpcd_addr[msg_name] + i * DPCD_PACKET_SIZE,
+ remain,
+ &data[i * DPCD_PACKET_SIZE]);
+ if (ret) {
+ hdcp_err("dpcd read fail. ret(%d)\n", ret);
+ return ret;
+ }
+ }
+ return 0;
+ } else
+ return displayport_dpcd_read_for_hdcp22(dpcd_addr[msg_name], size, data);
+}
+
+int hdcp_dplink_send(uint32_t msg_name, uint8_t *data, uint32_t size)
+{
+ int i;
+ int ret;
+
+ if (size > DPCD_PACKET_SIZE) {
+ for (i = 0; i < (size / DPCD_PACKET_SIZE); i++) {
+ ret = displayport_dpcd_write_for_hdcp22(
+ dpcd_addr[msg_name] + i * DPCD_PACKET_SIZE,
+ DPCD_PACKET_SIZE,
+ &data[i * DPCD_PACKET_SIZE]);
+ if (ret) {
+ hdcp_err("dpcd write fail. ret(%d)\n", ret);
+ return ret;
+ }
+ }
+ return 0;
+ }
+ else
+ return displayport_dpcd_write_for_hdcp22(dpcd_addr[msg_name], size, data);
+}
+#endif
--- /dev/null
+/* driver/soc/samsung/exynos-hdcp/dplink/exynos-hdcp2-dplink-if.h
+ *
+ * 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.
+*/
+#ifndef __EXYNOS_HDCP2_DPLINK_IF_H__
+#define __EXYNOS_HDCP2_DPLINK_IF_H__
+
+enum hdcp22_msg_name {
+ HDCP22_MSG_RTX_W,
+ HDCP22_MSG_TXCAPS_W,
+ HDCP22_MSG_CERT_RX_R,
+ HDCP22_MSG_RRX_R,
+ HDCP22_MSG_RXCAPS_R,
+ HDCP22_MSG_EKPUB_KM_W,
+ HDCP22_MSG_EKH_KM_W,
+ HDCP22_MSG_M_W,
+ HDCP22_MSG_HPRIME_R,
+ HDCP22_MSG_EKH_KM_R,
+ HDCP22_MSG_RN_W,
+ HDCP22_MSG_LPRIME_R,
+ HDCP22_MSG_EDKEY_KS0_W,
+ HDCP22_MSG_EDKEY_KS1_W,
+ HDCP22_MSG_RIV_W,
+ HDCP22_MSG_RXINFO_R,
+ HDCP22_MSG_SEQ_NUM_V_R,
+ HDCP22_MSG_VPRIME_R,
+ HDCP22_MSG_RECV_ID_LIST_R,
+ HDCP22_MSG_V_W,
+ HDCP22_MSG_SEQ_NUM_M_W,
+ HDCP22_MSG_K_W,
+ HDCP22_MSG_STREAMID_TYPE_W,
+ HDCP22_MSG_MPRIME_R,
+ HDCP22_MSG_RXSTATUS_R,
+ HDCP22_MSG_TYPE_W,
+ NUM_HDCP22_MSG_NAME,
+};
+
+#define DP_HDCP22_ENABLE 1
+#define DP_HDCP22_DISABLE 0
+
+int hdcp_dplink_init(void);
+void hdcp_dplink_config(int en);
+int hdcp_dplink_is_enabled_hdcp22(void);
+int hdcp_dplink_recv(uint32_t msg_name, uint8_t *data, uint32_t size);
+int hdcp_dplink_send(uint32_t msg_name, uint8_t *data, uint32_t size);
+int hdcp_dplink_get_stream_info(uint16_t *num, uint8_t *strm_id);
+
+#endif
--- /dev/null
+/*
+ * drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-protocol-msg.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 "../exynos-hdcp2-config.h"
+#include "../exynos-hdcp2-protocol-msg.h"
+#include "../exynos-hdcp2.h"
+#include "../exynos-hdcp2-misc.h"
+#include "../exynos-hdcp2-log.h"
+#include "exynos-hdcp2-dplink-protocol-msg.h"
+#include "exynos-hdcp2-dplink-if.h"
+
+/* HDCP protocol message capulate & decapulate functions for DP */
+static int dp_cap_ake_init(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int dp_cap_ake_no_stored_km(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int dp_cap_ake_stored_km(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int dp_decap_ake_send_cert(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int dp_decap_ake_send_h_prime(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int dp_decap_ake_send_pairing_info(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int dp_cap_lc_init(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int dp_decap_lc_send_l_prime(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int dp_cap_ske_send_eks(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int dp_decap_rpauth_send_recvid_list(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int dp_cap_rpauth_send_ack(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int dp_cap_rpauth_stream_manage(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int dp_decap_rpauth_stream_ready(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+int (*proto_dp[])(uint8_t *, size_t *,
+ struct hdcp_tx_ctx *,
+ struct hdcp_rx_ctx *) = {
+ dp_cap_ake_init,
+ dp_decap_ake_send_cert,
+ dp_cap_ake_no_stored_km,
+ dp_cap_ake_stored_km,
+ NULL, /* not defined in HDCP2.2 DP spec */
+ dp_decap_ake_send_h_prime,
+ dp_decap_ake_send_pairing_info,
+ dp_cap_lc_init,
+ dp_decap_lc_send_l_prime,
+ dp_cap_ske_send_eks,
+ dp_decap_rpauth_send_recvid_list,
+ NULL, /* not defined in HDCP2.2 DP spec */
+ NULL, /* not defined in HDCP2.2 DP spec */
+ dp_cap_rpauth_send_ack,
+ dp_cap_rpauth_stream_manage,
+ dp_decap_rpauth_stream_ready,
+ NULL, /* to do */
+ NULL, /* not defined in HDCP2.2 DP spec */
+ NULL, /* not defined in HDCP2.2 DP spec */
+};
+
+static int dp_rp_verify_stream_ready(uint8_t *m_prime)
+{
+ int ret;
+
+ ret = teei_verify_m_prime(m_prime, NULL, 0);
+ if (ret) {
+ hdcp_err("teei_verify_m_prime() is failed with %x\n", ret);
+ return ERR_RP_INVALID_M_PRIME;
+ }
+
+ return 0;
+}
+
+static int dp_rp_gen_stream_manage(struct dp_stream_info *strm)
+{
+ int ret;
+
+ ret = teei_gen_stream_manage(strm->stream_num,
+ strm->streamid,
+ strm->seq_num_m,
+ strm->k,
+ strm->streamid_type);
+ if (ret) {
+ hdcp_err("teei_gen_stream_manage() is failed with %x\n", ret);
+ return ERR_RP_GEN_STREAM_MG;
+ }
+
+ return 0;
+}
+
+static int dp_rp_set_rcvid_list(struct hdcp_rpauth_info *rp)
+{
+ int ret;
+
+ ret = teei_set_rcvlist_info(rp->rx_info,
+ rp->seq_num_v,
+ rp->v_prime,
+ rp->u_rcvid.lst,
+ rp->v,
+ &rp->valid);
+ if (ret) {
+ hdcp_err("teei_set_rcvid_list() is failed with %x\n", ret);
+ return ERR_RP_VERIFY_RCVLIST;
+ }
+
+ return 0;
+}
+
+static int dp_ake_generate_rtx(uint8_t *rtx, size_t rtx_len,
+ uint8_t *caps, uint32_t caps_len)
+{
+ int ret;
+
+ ret = teei_gen_rtx(HDCP_LINK_TYPE_DP, rtx, rtx_len, caps, caps_len);
+ if (ret) {
+ hdcp_err("generate_none_secret_key() is failed with %x\n", ret);
+ return ERR_GENERATE_NON_SECKEY;
+ }
+
+ return 0;
+}
+
+static int dp_cap_ake_init(uint8_t *m, size_t *m_len, struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ size_t rtx_len;
+ uint32_t caps_len;
+ int ret;
+
+ /* Buffer Check */
+ if ((m == NULL) || (m_len == NULL) || (tx_ctx == NULL))
+ return ERR_WRONG_BUFFER;
+
+ rtx_len = HDCP_AKE_RTX_BYTE_LEN;
+ caps_len = HDCP_CAPS_BYTE_LEN;
+
+ /* Generate rtx */
+ ret = dp_ake_generate_rtx(tx_ctx->rtx, rtx_len,
+ tx_ctx->caps, caps_len);
+ if (ret) {
+ hdcp_err("failed to generate rtx. ret(%d)\n", ret);
+ return ERR_GENERATE_RTX;
+ }
+
+ /* Make Message */
+ memcpy(&m[0], tx_ctx->rtx, rtx_len);
+ memcpy(&m[rtx_len], tx_ctx->caps, HDCP_CAPS_BYTE_LEN);
+ *m_len = rtx_len + HDCP_CAPS_BYTE_LEN;
+
+#ifdef HDCP_AKE_DEBUG
+ hdcp_debug("cap_ake_init(%lu) \n", *m_len);
+ hdcp_hexdump(m, *m_len);
+#endif
+ return 0;
+}
+
+static int dp_cap_ake_no_stored_km(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ uint8_t enc_mkey[HDCP_AKE_ENCKEY_BYTE_LEN];
+ int ret;
+
+ if ((m == NULL) || (m_len == NULL) ||
+ (tx_ctx == NULL) || (rx_ctx == NULL))
+ return ERR_WRONG_BUFFER;
+
+ /* Generate/Encrypt master key */
+ ret = ake_generate_masterkey(HDCP_LINK_TYPE_DP,
+ enc_mkey,
+ sizeof(enc_mkey));
+ /* Generate/Encrypt master key */
+ if (ret)
+ return ret;
+
+ /* Make Message */
+ memcpy(m, enc_mkey, HDCP_AKE_ENCKEY_BYTE_LEN);
+ *m_len = HDCP_AKE_ENCKEY_BYTE_LEN;
+
+#ifdef HDCP_AKE_DEBUG
+ hdcp_debug("cap_ake_no_stored_km(%lu) \n", *m_len);
+ hdcp_hexdump(m, *m_len);
+#endif
+ return 0;
+}
+
+static int dp_cap_ake_stored_km(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ int found_km;
+ int ret;
+
+ if ((m == NULL) || (m_len == NULL) ||
+ (tx_ctx == NULL) || (rx_ctx == NULL))
+ return ERR_WRONG_BUFFER;
+
+ 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 || !found_km) {
+ hdcp_err("find_masterkey() is failed with ret(0x%x). found(%d)\n", ret, found_km);
+ return -1;
+ }
+
+ /* Make Message */
+ memcpy(m, tx_ctx->ekh_mkey, HDCP_AKE_EKH_MKEY_BYTE_LEN);
+ memcpy(&m[HDCP_AKE_EKH_MKEY_BYTE_LEN], tx_ctx->m, HDCP_AKE_M_BYTE_LEN);
+ *m_len = HDCP_AKE_EKH_MKEY_BYTE_LEN + HDCP_AKE_M_BYTE_LEN;
+
+#ifdef HDCP_AKE_DEBUG
+ hdcp_debug("cap_ake_stored_km(%lu) \n", *m_len);
+ hdcp_hexdump(m, *m_len);
+#endif
+ return 0;
+}
+
+static int dp_decap_ake_send_cert(uint8_t *m, size_t *m_len, struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ int ret;
+
+ ret = dp_check_received_msg(m, *m_len, HDCP_RX_CERT_LEN +
+ HDCP_RRX_BYTE_LEN +
+ HDCP_CAPS_BYTE_LEN);
+ if (ret)
+ return ret;
+
+ ret = ake_verify_cert(m, HDCP_RX_CERT_LEN,
+ &m[HDCP_RX_CERT_LEN], HDCP_RRX_BYTE_LEN,
+ &m[HDCP_RX_CERT_LEN + HDCP_RRX_BYTE_LEN], HDCP_CAPS_BYTE_LEN);
+ if (ret) {
+ hdcp_err("teei_verify_cert is failed with %x\n", ret);
+ return ERR_VERIFY_CERT;
+ }
+
+ return 0;
+}
+
+static int dp_decap_ake_send_h_prime(uint8_t *m, size_t *m_len, struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ int ret;
+
+ /* compare H == H' */
+ ret = ake_compare_hmac(m, HDCP_HMAC_SHA256_LEN);
+ if (ret) {
+ hdcp_err("decap_ake_send_h_prime is failed. ret(%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int dp_decap_ake_send_pairing_info(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ int ret;
+
+ memcpy(tx_ctx->ekh_mkey, &m[0], HDCP_AKE_EKH_MKEY_BYTE_LEN);
+
+ /* Store the Key */
+ ret = ake_store_master_key(tx_ctx->ekh_mkey, HDCP_AKE_EKH_MKEY_BYTE_LEN);
+ if (ret) {
+ hdcp_err("failed to store master key. ret(%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int dp_cap_lc_init(uint8_t *m, size_t *m_len, struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ int ret;
+
+ if ((m == NULL) || (m_len == NULL) || (tx_ctx == NULL) ||
+ (rx_ctx == NULL))
+ return ERR_WRONG_BUFFER;
+
+ /* Generate rn */
+ ret = lc_generate_rn(tx_ctx->rn, HDCP_RTX_BYTE_LEN);
+ if (ret) {
+ hdcp_err("failed to generate rtx. ret(%d)\n", ret);
+ return ret;
+ }
+
+ /* Make Message */
+ memcpy(m, tx_ctx->rn, HDCP_RTX_BYTE_LEN);
+ *m_len = HDCP_RTX_BYTE_LEN;
+
+ return 0;
+}
+
+static int dp_decap_lc_send_l_prime(uint8_t *m, size_t *m_len, struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ uint8_t *rx_hmac;
+ size_t len;
+ int ret;
+
+ len = HDCP_HMAC_SHA256_LEN;
+
+ /* No_precomputation: compare hmac
+ precomputation: compare the most significant 128bits of L & L' */
+ rx_hmac = m;
+ ret = lc_compare_hmac(rx_hmac, len);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int dp_cap_ske_send_eks(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ int ret;
+ uint8_t enc_skey[HDCP_AKE_MKEY_BYTE_LEN];
+
+ if ((m == NULL) || (m_len == NULL) || (tx_ctx == NULL) ||
+ (rx_ctx == NULL))
+ return ERR_WRONG_BUFFER;
+
+ /* Generate riv */
+ if (!tx_ctx->share_skey) {
+ ret = ske_generate_riv(tx_ctx->riv);
+ if (ret)
+ return ERR_GENERATE_RIV;
+ }
+
+ /* Generate encrypted Session Key */
+ ret = ske_generate_sessionkey(HDCP_LINK_TYPE_DP,
+ enc_skey,
+ tx_ctx->share_skey);
+ if (ret)
+ return ret;
+
+ /* Make Message */
+ memcpy(m, enc_skey, HDCP_AKE_MKEY_BYTE_LEN);
+ memcpy(&m[HDCP_AKE_MKEY_BYTE_LEN], tx_ctx->riv, HDCP_RTX_BYTE_LEN);
+ *m_len = HDCP_AKE_MKEY_BYTE_LEN + HDCP_RTX_BYTE_LEN;
+
+#ifdef HDCP_SKE_DEBUG
+ hdcp_debug("SKE_Send_Eks(%lu)\n", *m_len);
+ hdcp_hexdump(m, *m_len);
+#endif
+ return 0;
+}
+
+static int dp_decap_rpauth_send_recvid_list(uint8_t *m,
+ size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ int ret;
+ struct hdcp_rpauth_info *rp;
+
+#ifdef HDCP_AKE_DEBUG
+ hdcp_debug("RepeaterAuth_Send_ReceiverID_List(%lu):\n", *m_len);
+ hdcp_hexdump(m, *m_len);
+#endif
+
+ rp = &tx_ctx->rpauth_info;
+
+ memcpy(rp->rx_info, &m[0], HDCP_RP_RX_INFO_LEN);
+ memcpy(rp->seq_num_v, &m[HDCP_RP_RX_INFO_LEN], HDCP_RP_SEQ_NUM_V_LEN);
+ memcpy(rp->v_prime, &m[HDCP_RP_RX_INFO_LEN + HDCP_RP_SEQ_NUM_V_LEN],
+ HDCP_RP_HMAC_V_LEN / 2);
+ memcpy(rp->u_rcvid.lst,
+ &m[HDCP_RP_RX_INFO_LEN + HDCP_RP_SEQ_NUM_V_LEN + (HDCP_RP_HMAC_V_LEN / 2)],
+ HDCP_RP_RCVID_LIST_LEN);
+
+ /* set receiver id list */
+ ret = dp_rp_set_rcvid_list(rp);
+ if (ret) {
+ hdcp_err("failed to set receiver id list. ret(%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int dp_cap_rpauth_send_ack(uint8_t *m,
+ size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ /* Make Message */
+ if (tx_ctx->rpauth_info.valid == 0) {
+ memcpy(m, tx_ctx->rpauth_info.v, HDCP_RP_HMAC_V_LEN / 2);
+ *m_len = HDCP_RP_HMAC_V_LEN / 2;
+ } else {
+ *m_len = 0;
+ return ERR_SEND_ACK;
+ }
+
+#ifdef HDCP_TX_REPEATER_DEBUG
+ hdcp_debug("RepeaterAuth_Send_Ack(%u)\n", *m_len);
+ hdcp_hexdump(m, *m_len);
+#endif
+
+ return 0;
+}
+
+static int dp_cap_rpauth_stream_manage(uint8_t *m,
+ size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ struct dp_stream_info *strm;
+ int ret;
+
+ strm = &tx_ctx->strm.dp;
+
+ hdcp_dplink_get_stream_info(&strm->stream_num, strm->streamid);
+
+ /* set receiver id list */
+ ret = dp_rp_gen_stream_manage(strm);
+ if (ret) {
+ hdcp_err("failed to gen stream manage. ret(%d)\n", ret);
+ return ret;
+ }
+
+ /* Make Message */
+ memcpy(m, strm->seq_num_m, HDCP_RP_SEQ_NUM_M_LEN);
+ memcpy(&m[HDCP_RP_SEQ_NUM_M_LEN], strm->k, HDCP_RP_K_LEN);
+ memcpy(&m[HDCP_RP_SEQ_NUM_M_LEN + HDCP_RP_K_LEN],
+ strm->streamid_type, HDCP_RP_STREAMID_TYPE_LEN * strm->stream_num);
+
+ *m_len = HDCP_RP_SEQ_NUM_M_LEN + \
+ HDCP_RP_K_LEN + \
+ (HDCP_RP_STREAMID_TYPE_LEN * strm->stream_num);
+
+#ifdef HDCP_TX_REPEATER_DEBUG
+ hdcp_debug("RepeaterAuth_Stream_Manage(%u)\n", *m_len);
+ hdcp_hexdump(m, *m_len);
+#endif
+ return 0;
+}
+
+static int dp_decap_rpauth_stream_ready(uint8_t *m,
+ size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ uint8_t *m_prime;
+ int ret;
+
+ m_prime = m;
+ ret = dp_rp_verify_stream_ready(m_prime);
+ if (ret)
+ return 0;
+
+ return 0;
+}
+
--- /dev/null
+/* driver/soc/samsung/exynos-hdcp/dplink/exynos-hdcp2-protocol-msg.h
+ *
+ * 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.
+*/
+#ifndef __EXYNOS_HDCP2_DPLINK_PROTOCOL_MSG_H__
+#define __EXYNOS_HDCP2_DPLINK_PROTOCOL_MSG_H__
+
+#include <linux/types.h>
+
+enum dp_msg_id {
+ DP_AKE_INIT = 2,
+ 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_AKE,
+ DP_REPEATERAUTH_STREAM_MANAGE,
+ DP_REPEATERAUTH_STREAM_READY,
+ DP_RECEIVER_AUTHSTATUS,
+ DP_AKE_TRANSMITTER_INFO,
+ DP_AKE_RECEIVER_INFO,
+};
+
+#define DP_RXSTATUS_READY (0x1 << 0)
+#define DP_RXSTATUS_HPRIME_AVAILABLE (0x1 << 1)
+#define DP_RXSTATUS_PAIRING_AVAILABLE (0x1 << 2)
+#define DP_RXSTATUS_REAUTH_REQ (0x1 << 3)
+#define DP_RXSTATUS_LINK_INTEGRITY_FAIL (0x1 << 4)
+
+#define DP_RXCAPS_HDCP_CAPABLE (0x1 << 1)
+#define DP_RXCAPS_REPEATER (0x1 << 0)
+#define DP_RXCAPS_HDCP_VERSION_2 (0x2)
+
+/* RxInfo */
+#define DEPTH_SHIFT (9)
+#define DEPTH_MASK (0x7)
+#define DEV_COUNT_SHIFT (4)
+#define DEV_COUNT_MASK (0x1F)
+#define DEV_EXD_SHIFT (3)
+#define DEV_EXD_MASK (0x1)
+#define CASCADE_EXD_SHIFT (2)
+#define CASCADE_EXD_MASK (0x1)
+#define HDCP20_DOWN_SHIFT (1)
+#define HDCP20_DOWN_MASK (0x1)
+#define HDCP1X_DOWN_SHIFT (0)
+#define HDCP1X_DOWN_MASK (0x1)
+
+#define dp_check_received_msg(m, m_len, len) \
+ ((m == NULL) ? ERR_WRONG_BUFFER : \
+ ((m_len < len) ? ERR_WRONG_MESSAGE_LENGTH : 0))
+
+#endif
--- /dev/null
+/* driver/soc/samsung/exynos-hdcp/dplink/exynos-hdcp2-dplink-reg.h
+ *
+ * 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.
+*/
+#ifndef __EXYNOS_HDCP2_DPLINK_REG_H__
+#define __EXYNOS_HDCP2_DPLINK_REG_H__
+
+#define DPCD_PACKET_SIZE (8)
+
+#define DPCD_ADDR_HDCP22_Rtx 0x69000
+#define DPCD_ADDR_HDCP22_TxCaps 0x69008
+#define DPCD_ADDR_HDCP22_cert_rx 0x6900B
+#define DPCD_ADDR_HDCP22_Rrx 0x69215
+#define DPCD_ADDR_HDCP22_RxCaps 0x6921D
+#define DPCD_ADDR_HDCP22_Ekpub_km 0x69220
+#define DPCD_ADDR_HDCP22_Ekh_km_w 0x692A0
+#define DPCD_ADDR_HDCP22_m 0x692B0
+#define DPCD_ADDR_HDCP22_Hprime 0x692C0
+#define DPCD_ADDR_HDCP22_Ekh_km_r 0x692E0
+#define DPCD_ADDR_HDCP22_rn 0x692F0
+#define DPCD_ADDR_HDCP22_Lprime 0x692F8
+#define DPCD_ADDR_HDCP22_Edkey0_ks 0x69318
+#define DPCD_ADDR_HDCP22_Edkey1_ks 0x69320
+#define DPCD_ADDR_HDCP22_riv 0x69328
+#define DPCD_ADDR_HDCP22_RxInfo 0x69330
+#define DPCD_ADDR_HDCP22_seq_num_V 0x69332
+#define DPCD_ADDR_HDCP22_Vprime 0x69335
+#define DPCD_ADDR_HDCP22_Rec_ID_list 0x69345
+#define DPCD_ADDR_HDCP22_V 0x693E0
+#define DPCD_ADDR_HDCP22_seq_num_M 0x693F0
+#define DPCD_ADDR_HDCP22_k 0x693F3
+#define DPCD_ADDR_HDCP22_stream_IDtype 0x693F5
+#define DPCD_ADDR_HDCP22_Mprime 0x69473
+#define DPCD_ADDR_HDCP22_RxStatus 0x69493
+#define DPCD_ADDR_HDCP22_Type 0x69494
+
+#endif
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/* todo: include/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-selftest.h
+ *
+ * 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.
+*/
+#ifndef __EXYNOS_HDCP2_DPLINK_SELFTEST_H__
+#define __EXYNOS_HDCP2_DPLINK_SELFTEST_H__
+
+int dp_hdcp_protocol_self_test(void);
+
+#endif
--- /dev/null
+/*
+ * drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink.c
+ *
+ * Copyright (c) 2015 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/module.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/smc.h>
+#include <asm/cacheflush.h>
+#include <linux/exynos_ion.h>
+#include <linux/smc.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+
+#include "../exynos-hdcp2.h"
+#include "../exynos-hdcp2-log.h"
+#include "exynos-hdcp2-dplink.h"
+#include "exynos-hdcp2-dplink-if.h"
+#include "exynos-hdcp2-dplink-auth.h"
+
+#define HDCP_AUTH_RETRY_COUNT 5
+#define HDCP_AUTH_REAUTH_COUNT 2
+
+#define RECVID_WIAT_RETRY_COUNT 5
+
+#if defined(CONFIG_HDCP2_EMULATION_MODE)
+int dplink_emul_handler(int cmd)
+{
+ /* todo: support hdcp22 emulator */
+ return 0;
+}
+#endif
+
+/* current link data */
+static struct hdcp_link_data *lk_data;
+
+extern struct hdcp_session_list g_hdcp_session_list;
+extern uint8_t rp_ready;
+uint8_t auth_end_flag;
+int drm_flag;
+int dp_link_flag;
+struct hdcp_sess_info ss_info;
+struct hdcp_link_info lk_info;
+
+static char *hdcp_link_st_str[] = {
+ "ST_INIT",
+ "ST_H0_NO_RX_ATTACHED",
+ "ST_H1_TX_LOW_VALUE_CONTENT",
+ "ST_A0_DETERMINE_RX_HDCP_CAP",
+ "ST_A1_EXCHANGE_MASTER_KEY",
+ "ST_A2_LOCALITY_CHECK",
+ "ST_A3_EXCHANGE_SESSION_KEY",
+ "ST_A4_TEST_REPEATER",
+ "ST_A5_AUTHENTICATED",
+ "ST_A6_WAIT_RECEIVER_ID_LIST",
+ "ST_A7_VERIFY_RECEIVER_ID_LIST",
+ "ST_A8_SEND_RECEIVER_ID_LIST_ACK",
+ "ST_A9_CONTENT_STREAM_MGT",
+ "ST_END",
+ NULL
+};
+
+int do_dplink_auth(struct hdcp_link_info *lk_handle)
+{
+ struct hdcp_session_node *ss_node;
+ struct hdcp_link_node *lk_node;
+ int ret = HDCP_SUCCESS;
+ int rval = TX_AUTH_SUCCESS;
+ uint32_t retry_recvid = 0;
+ int hdcp_enabled = 0;
+
+ /* find Session node which contains the Link */
+
+ if (!rp_ready) {
+ ss_node = hdcp_session_list_find(lk_handle->ss_id, &g_hdcp_session_list);
+ if (!ss_node)
+ return HDCP_ERROR_INVALID_INPUT;
+
+ lk_node = hdcp_link_list_find(lk_handle->lk_id, &ss_node->ss_data->ln);
+ if (!lk_node)
+ return HDCP_ERROR_INVALID_INPUT;
+
+ lk_data = lk_node->lk_data;
+ if (!lk_data)
+ return HDCP_ERROR_INVALID_INPUT;
+
+ if (lk_data->state != LINK_ST_H1_TX_LOW_VALUE_CONTENT)
+ return HDCP_ERROR_INVALID_STATE;
+ }
+ /**
+ * if Upstream Content Control Function call this API,
+ * it changes state to ST_A0_DETERMINE_RX_HDCP_CAP automatically.
+ * HDCP library do not check CP desire.
+ */
+
+ if (!lk_data) {
+ hdcp_info("DP HDCP2.2 Session is not opened.\n");
+ return HDCP_ERROR_INVALID_INPUT;
+ }
+
+ if (rp_ready)
+ UPDATE_LINK_STATE(lk_data, LINK_ST_A7_VERIFY_RECEIVER_ID_LIST);
+ else
+ UPDATE_LINK_STATE(lk_data, LINK_ST_A0_DETERMINE_RX_HDCP_CAP);
+
+ do {
+ switch (lk_data->state) {
+ case LINK_ST_H1_TX_LOW_VALUE_CONTENT:
+ hdcp_dplink_config(DP_HDCP22_DISABLE);
+ return ret;
+ case LINK_ST_A0_DETERMINE_RX_HDCP_CAP:
+ if (dplink_determine_rx_hdcp_cap(lk_data) < 0) {
+ ret = HDCP_ERROR_RX_NOT_HDCP_CAPABLE;
+ UPDATE_LINK_STATE(lk_data, LINK_ST_H1_TX_LOW_VALUE_CONTENT);
+ } else
+ UPDATE_LINK_STATE(lk_data, LINK_ST_A1_EXCHANGE_MASTER_KEY);
+ break;
+ case LINK_ST_A1_EXCHANGE_MASTER_KEY:
+ rval = dplink_exchange_master_key(lk_data);
+ if (rval == TX_AUTH_SUCCESS) {
+ UPDATE_LINK_STATE(lk_data, LINK_ST_A2_LOCALITY_CHECK);
+ } else {
+ /* todo: consider connection retry */
+ ret = HDCP_ERROR_EXCHANGE_KM;
+ UPDATE_LINK_STATE(lk_data, LINK_ST_H1_TX_LOW_VALUE_CONTENT);
+ }
+ break;
+ case LINK_ST_A2_LOCALITY_CHECK:
+ rval = dplink_locality_check(lk_data);
+ if (rval == TX_AUTH_SUCCESS) {
+ UPDATE_LINK_STATE(lk_data, LINK_ST_A3_EXCHANGE_SESSION_KEY);
+ } else {
+ /* todo: consider connection retry */
+ ret = HDCP_ERROR_LOCALITY_CHECK;
+ UPDATE_LINK_STATE(lk_data, LINK_ST_H1_TX_LOW_VALUE_CONTENT);
+ }
+ break;
+ case LINK_ST_A3_EXCHANGE_SESSION_KEY:
+ if (dplink_exchange_session_key(lk_data) < 0) {
+ ret = HDCP_ERROR_EXCHANGE_KS;
+ UPDATE_LINK_STATE(lk_data, LINK_ST_H1_TX_LOW_VALUE_CONTENT);
+ } else {
+ UPDATE_LINK_STATE(lk_data, LINK_ST_A4_TEST_REPEATER);
+ }
+ break;
+ case LINK_ST_A4_TEST_REPEATER:
+ if (dplink_evaluate_repeater(lk_data) == TRUE) {
+ /* if it is a repeater, verify Rcv ID list */
+ UPDATE_LINK_STATE(lk_data, LINK_ST_A6_WAIT_RECEIVER_ID_LIST);
+ hdcp_info("It`s repeater link !\n");
+#if defined(CONFIG_HDCP2_FUNC_TEST_MODE)
+ hdcp_enabled = 1;
+ hdcp_info("it`s func test mode.\n");
+#else
+ hdcp_enabled = 0;
+#endif
+ } else {
+ /* if it is not a repeater, complete authentication */
+ UPDATE_LINK_STATE(lk_data, LINK_ST_A5_AUTHENTICATED);
+ hdcp_info("It`s Rx link !\n");
+ hdcp_enabled = 1;
+ }
+ break;
+ case LINK_ST_A5_AUTHENTICATED:
+ /* HDCP2.2 spec defined 200ms */
+ msleep(200);
+ if (hdcp_enabled)
+ hdcp_dplink_config(DP_HDCP22_ENABLE);
+ /* Transmitter has completed the authentication protocol */
+ ret = exynos_smc(SMC_DRM_HDCP_AUTH_INFO, DP_HDCP22_ENABLE, 0, 0);
+ return HDCP_SUCCESS;
+ case LINK_ST_A6_WAIT_RECEIVER_ID_LIST:
+ rval = dplink_wait_for_receiver_id_list(lk_data);
+ if (rval == -TX_AUTH_ERROR_TIME_EXCEED) {
+ if (retry_recvid < RECVID_WIAT_RETRY_COUNT) {
+ /* retry hdcp authentication in case of timeout */
+ hdcp_dplink_config(DP_HDCP22_DISABLE);
+ UPDATE_LINK_STATE(lk_data, LINK_ST_A0_DETERMINE_RX_HDCP_CAP);
+ hdcp_info("retry authentication. (%d)\n", retry_recvid);
+ retry_recvid++;
+ } else {
+ hdcp_info("exceed retry count. (%d)\n", retry_recvid);
+ ret = HDCP_ERROR_VERIFY_RECEIVER_ID_LIST;
+ UPDATE_LINK_STATE(lk_data, LINK_ST_H1_TX_LOW_VALUE_CONTENT);
+ }
+ } else if (rval == HDCP_SUCCESS) {
+ UPDATE_LINK_STATE(lk_data, LINK_ST_A7_VERIFY_RECEIVER_ID_LIST);
+ retry_recvid = 0;
+ } else {
+ /* error on recevier id list wait */
+ ret = HDCP_ERROR_VERIFY_RECEIVER_ID_LIST;
+ UPDATE_LINK_STATE(lk_data, LINK_ST_H1_TX_LOW_VALUE_CONTENT);
+ }
+ break;
+ case LINK_ST_A7_VERIFY_RECEIVER_ID_LIST:
+ if (dplink_verify_receiver_id_list(lk_data) < 0) {
+ ret = HDCP_ERROR_VERIFY_RECEIVER_ID_LIST;
+ UPDATE_LINK_STATE(lk_data, LINK_ST_H1_TX_LOW_VALUE_CONTENT);
+ } else {
+ UPDATE_LINK_STATE(lk_data, LINK_ST_A8_SEND_RECEIVER_ID_LIST_ACK);
+ }
+ break;
+ case LINK_ST_A8_SEND_RECEIVER_ID_LIST_ACK:
+ rval = dplink_send_receiver_id_list_ack(lk_data);
+ if (rval < 0) {
+ ret = HDCP_ERROR_VERIFY_RECEIVER_ID_LIST;
+ UPDATE_LINK_STATE(lk_data, LINK_ST_H1_TX_LOW_VALUE_CONTENT);
+ } else {
+ UPDATE_LINK_STATE(lk_data, LINK_ST_A9_CONTENT_STREAM_MGT);
+ }
+ break;
+ case LINK_ST_A9_CONTENT_STREAM_MGT:
+ rval = dplink_stream_manage(lk_data);
+ if (rval < 0) {
+ ret = HDCP_ERROR_STREAM_MANAGE;
+ UPDATE_LINK_STATE(lk_data, LINK_ST_H1_TX_LOW_VALUE_CONTENT);
+ } else {
+ UPDATE_LINK_STATE(lk_data, LINK_ST_A5_AUTHENTICATED);
+ }
+ break;
+ default:
+ ret = HDCP_ERROR_INVALID_STATE;
+ UPDATE_LINK_STATE(lk_data, LINK_ST_H1_TX_LOW_VALUE_CONTENT);
+ break;
+ }
+ } while (1);
+}
+
+/* todo: support multi link & multi session */
+int hdcp_dplink_authenticate(void)
+{
+ int ret;
+ static int retry_cnt;
+
+ auth_end_flag = HDCP_AUTH_PROCESS_ON;
+ for (; retry_cnt < HDCP_AUTH_RETRY_COUNT; retry_cnt++) {
+ if (!rp_ready) {
+ hdcp_clear_session(ss_info.ss_id);
+ if (hdcp_session_open(&ss_info))
+ return -ENOMEM;
+
+ lk_info.ss_id = ss_info.ss_id;
+ if (hdcp_link_open(&lk_info, HDCP_LINK_TYPE_DP)) {
+ hdcp_session_close(&ss_info);
+ return -ENOMEM;
+ }
+
+ /* if hdcp is enabled, disable it while hdcp authentication */
+ if (hdcp_dplink_is_enabled_hdcp22())
+ hdcp_dplink_config(DP_HDCP22_DISABLE);
+
+ dplink_clear_irqflag_all();
+ }
+
+ ret = do_dplink_auth(&lk_info);
+ if (ret == HDCP_SUCCESS) {
+ hdcp_info("Success HDCP authenticate done.\n");
+ retry_cnt = 0;
+ return 0;
+ } else {
+ /* auth_end_flag flag check */
+ if (auth_end_flag == HDCP_AUTH_PROCESS_STOP) {
+ hdcp_info("Stop authenticate.\n");
+ auth_end_flag = HDCP_AUTH_PROCESS_ON;
+ break;
+ }
+ /* retry */
+ dplink_clear_irqflag_all();
+ hdcp_err("HDCP auth failed. retry(%d)!\n", retry_cnt);
+ retry_cnt++;
+ if (retry_cnt == HDCP_AUTH_REAUTH_COUNT) {
+ reset_dp_hdcp_module();
+ } else if (retry_cnt > HDCP_AUTH_REAUTH_COUNT) {
+ retry_cnt = 0;
+ break;
+ }
+ }
+ }
+
+ retry_cnt = 0;
+ return -EACCES;
+}
+
+int hdcp_dplink_auth_check(void)
+{
+ int ret;
+
+ if (drm_flag && dp_link_flag) {
+ ret = exynos_smc(SMC_DRM_HDCP_AUTH_INFO, DP_HDCP22_DISABLE, 0, 0);
+ dplink_clear_irqflag_all();
+ ret = hdcp_dplink_authenticate();
+ if (ret == 0)
+ dp_link_flag = HDCP_AUTH_PROCESS_DONE;
+
+ return ret;
+ }
+
+ return 1;
+}
+
+int hdcp_dplink_drm_flag_check(int flag)
+{
+ int ret = 0;
+ int i = 0;
+
+ if (flag == DRM_OFF) {
+ drm_flag = DRM_OFF;
+ return 0;
+ }
+
+ for (i = 0; i < 1000; i++) {
+ drm_flag = exynos_smc(SMC_CHECK_STREAM_TYPE_FALG, 0, 0, 0);
+ if (drm_flag)
+ break;
+ msleep(500);
+ }
+
+ if (drm_flag == DRM_SAME_STREAM_TYPE && dp_link_flag == HDCP_AUTH_PROCESS_DONE)
+ return 0;
+
+ ret = hdcp_dplink_auth_check();
+ return ret;
+}
+
+int hdcp_dplink_dp_link_flag_check(int flag)
+{
+ int ret = 0;
+
+ dp_link_flag = flag;
+#if defined(CONFIG_HDCP2_FUNC_TEST_MODE)
+ drm_flag = DRM_ON;
+#endif
+ ret = hdcp_dplink_auth_check();
+
+ return ret;
+}
+
+void hdcp_clear_session(uint32_t id)
+{
+ struct hdcp_sess_info ss;
+ struct hdcp_link_info lk;
+
+ ss.ss_id = id;
+ lk.ss_id = id;
+ lk.lk_id = id;
+ hdcp_link_close(&lk);
+ hdcp_session_close(&ss);
+}
+
+int hdcp_dplink_stream_manage(void)
+{
+ hdcp_info("stream manage updated.\n");
+ /* todo: update stream manage information */
+ return 0;
+}
+
+int hdcp_dplink_get_rxstatus(uint8_t *status)
+{
+ int ret = 0;
+
+ ret = hdcp_dplink_recv(HDCP22_MSG_RXSTATUS_R, status, sizeof(uint8_t));
+#if defined(HDCP_DEBUG)
+ hdcp_info("RxStatus: %x\n", *status);
+#endif
+ return ret;
+}
+
+int hdcp_dplink_set_paring_available(void)
+{
+ hdcp_info("pairing avaible\n");
+ return dplink_set_paring_available();
+}
+
+int hdcp_dplink_set_hprime_available(void)
+{
+ hdcp_info("h-prime avaible\n");
+ return dplink_set_hprime_available();
+}
+
+int hdcp_dplink_set_rp_ready(void)
+{
+ hdcp_info("ready avaible\n");
+ return dplink_set_rp_ready();
+}
+
+int hdcp_dplink_set_reauth(void)
+{
+ uint32_t ret = 0;
+
+ hdcp_info("reauth requested.\n");
+ ret = exynos_smc(SMC_DRM_HDCP_AUTH_INFO, DP_HDCP22_DISABLE, 0, 0);
+ return dplink_set_reauth_req();
+}
+
+int hdcp_dplink_set_integrity_fail(void)
+{
+ uint32_t ret = 0;
+
+ hdcp_info("integrity check fail.\n");
+ ret = exynos_smc(SMC_DRM_HDCP_AUTH_INFO, DP_HDCP22_DISABLE, 0, 0);
+ return dplink_set_integrity_fail();
+}
+
+int hdcp_dplink_cancel_auth(void)
+{
+ uint32_t ret = 0;
+
+ hdcp_info("Cancel authenticate.\n");
+ ret = exynos_smc(SMC_DRM_HDCP_AUTH_INFO, DP_HDCP22_DISABLE, 0, 0);
+ auth_end_flag = HDCP_AUTH_PROCESS_STOP;
+
+ return dplink_set_integrity_fail();
+}
+
+int hdcp_dplink_is_auth_state(void)
+{
+ return 0;
+ /* todo: check link auth status */
+ #if 0
+ if (lk_data->state == LINK_ST_A5_AUTHENTICATED)
+ return 1;
+ else
+ return 0;
+ #endif
+}
+
--- /dev/null
+/* driver/soc/samsung/exynos-hdcp/dplink/exynos-hdcp2-dplink.h
+ *
+ * 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.
+*/
+#ifndef __EXYNOS_HDCP2_DPLINK_H__
+#define __EXYNOS_HDCP2_DPLINK_H__
+
+#if defined(CONFIG_HDCP2_EMULATION_MODE)
+int dplink_emul_handler(int cmd);
+#endif
+
+enum {
+ HDCP_AUTH_PROCESS_ON = 0x0,
+ HDCP_AUTH_PROCESS_STOP = 0x1,
+ HDCP_AUTH_PROCESS_DONE = 0x2
+};
+
+enum {
+ DRM_OFF = 0x0,
+ DRM_ON = 0x1,
+ DRM_SAME_STREAM_TYPE = 0x2 /* If the previous contents and stream_type id are the same flag */
+};
+
+/* Do hdcp2.2 authentication with DP Receiver
+ * and enable encryption if authentication is succeed.
+ * @return
+ * - 0: Success
+ * - ENOMEM: hdcp context open fail
+ * - EACCES: authentication fail
+ */
+int hdcp_dplink_authenticate(void);
+
+int do_dplink_auth(struct hdcp_link_info *lk_handle);
+int hdcp_dplink_get_rxstatus(uint8_t *status);
+int hdcp_dplink_set_paring_available(void);
+int hdcp_dplink_set_hprime_available(void);
+int hdcp_dplink_set_rp_ready(void);
+int hdcp_dplink_set_reauth(void);
+int hdcp_dplink_set_integrity_fail(void);
+int hdcp_dplink_cancel_auth(void);
+int hdcp_dplink_stream_manage(void);
+int hdcp_dplink_is_auth_state(void);
+int hdcp_dplink_auth_check(void);
+int hdcp_dplink_drm_flag_check(int flag);
+int hdcp_dplink_dp_link_flag_check(int flag);
+void hdcp_clear_session(uint32_t id);
+
+extern void reset_dp_hdcp_module(void);
+#endif
--- /dev/null
+/* todo: include/soc/samsung/exynos-hdcp2-config.h
+ *
+ * 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.
+*/
+#ifndef __EXYNOS_HDCP2_CONFIG_H__
+#define __EXYNOS_HDCP2_CONFIG_H__
+
+#define TEST_HDCP
+
+#undef TEST_VECTOR_1
+#define TEST_VECTOR_2
+#undef HDCP_AKE_DEBUG
+#undef HDCP_SKE_DEBUG
+#undef HDCP_TX_REPEATER_DEBUG
+
+#define HDCP_TX_VERSION_2_1
+#define HDCP_TX_LC_PRECOMPUTE_SUPPORT
+
+#endif
--- /dev/null
+/* drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-crypto.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/err.h>
+#include <linux/crypto.h>
+#include <linux/ctype.h>
+#include <crypto/hash.h>
+#include <crypto/sha.h>
+
+struct sdesc {
+ struct shash_desc shash;
+ char ctx[];
+};
+
+static struct sdesc *alloc_sdesc(struct crypto_shash *alg)
+{
+ struct sdesc *sdesc;
+ int size;
+
+ size = sizeof(struct shash_desc) + crypto_shash_descsize(alg);
+ sdesc = kmalloc(size, GFP_KERNEL);
+ if (!sdesc)
+ return ERR_PTR(-ENOMEM);
+ sdesc->shash.tfm = alg;
+ sdesc->shash.flags = 0x0;
+ return sdesc;
+}
+
+int hdcp_calc_sha1(u8 *digest, const u8 *buf, unsigned int buflen)
+{
+ struct crypto_shash *hashalg;
+ const char hash_alg[] = "sha1";
+ struct sdesc *sdesc;
+ int ret;
+
+ hashalg = crypto_alloc_shash(hash_alg, 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(hashalg)) {
+ pr_info("encrypted_key: could not allocate crypto %s\n",
+ hash_alg);
+ return PTR_ERR(hashalg);
+ }
+
+ sdesc = alloc_sdesc(hashalg);
+ if (IS_ERR(sdesc)) {
+ pr_err("alloc_sdesc: can't alloc %s\n", hash_alg);
+ if (hashalg)
+ crypto_free_shash(hashalg);
+ return PTR_ERR(sdesc);
+ }
+
+ ret = crypto_shash_digest(&sdesc->shash, buf, buflen, digest);
+ kfree(sdesc);
+
+ if (hashalg)
+ crypto_free_shash(hashalg);
+
+ return ret;
+}
--- /dev/null
+/*
+ * drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-crypto.h
+ *
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __EXYNOS_HDCP2_CRYPTO_H__
+#define __EXYNOS_HDCP2_CRYPTO_H__
+
+#define HDCP_SHA1_SIZE (160 / 8)
+
+int hdcp_calc_sha1(u8 *digest, const u8 *buf, unsigned int buflen);
+
+#endif
--- /dev/null
+/*
+ * drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-encrypt.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 "exynos-hdcp2-protocol-msg.h"
+#include "exynos-hdcp2-log.h"
+
+static void OS2BN(uint32_t *pdRes, uint8_t *pbSrc, size_t uSrcLen)
+{
+ int i;
+
+ for (i = 0; i < uSrcLen; i += 4)
+ pdRes[i/4] = pbSrc[uSrcLen-i-1] ^ (pbSrc[uSrcLen-i-2]<<8)
+ ^ (pbSrc[uSrcLen-i-3]<<16)
+ ^ (pbSrc[uSrcLen-i-4]<<24);
+}
+
+static void BN2OS(uint8_t *pbRes, uint32_t *pdSrc, size_t uSrcLen)
+{
+ int i;
+
+ for (i = 0; i < uSrcLen; i++) {
+ pbRes[4*i+0] = (uint8_t) (pdSrc[uSrcLen-1-i] >> 24);
+ pbRes[4*i+1] = (uint8_t) (pdSrc[uSrcLen-1-i] >> 16);
+ pbRes[4*i+2] = (uint8_t) (pdSrc[uSrcLen-1-i] >> 8);
+ pbRes[4*i+3] = (uint8_t) (pdSrc[uSrcLen-1-i]);
+ }
+}
+
+static uint32_t sec_bn_Add(uint32_t *pdDst, uint32_t *pdSrc1, size_t uSrcLen1,
+ uint32_t *pdSrc2, size_t uSrcLen2)
+{
+ int i;
+ uint32_t carry, tmp;
+
+ for (carry = i = 0; i < uSrcLen2; i++) {
+ if ((pdSrc2[i] == 0xff) && (carry == 1))
+ pdDst[i] = pdSrc1[i];
+ else {
+ tmp = pdSrc2[i] + carry;
+ pdDst[i] = pdSrc1[i] + tmp;
+ carry = ((pdDst[i]) < tmp) ? 1 : 0;
+ }
+ }
+
+ for (i = uSrcLen2; i < uSrcLen1; i++) {
+ pdDst[i] += carry;
+ if (pdDst[i] >= carry)
+ carry = 0;
+ else
+ carry = 1;
+ }
+
+ return carry;
+}
+
+static int make_priv_data(uint8_t *priv_data, uint8_t *str_ctr, uint8_t *input_ctr)
+{
+ uint8_t marker_bit;
+
+ marker_bit = 0x1;
+
+ priv_data[0] = 0x0;
+ priv_data[1] = (str_ctr[0] >> 5) | marker_bit;
+ priv_data[2] = (str_ctr[0] << 2) ^ (str_ctr[1] >> 6);
+ priv_data[3] = ((str_ctr[1] << 2) ^ (str_ctr[2] >> 6)) | marker_bit;
+ priv_data[4] = (str_ctr[2] << 1) ^ (str_ctr[3] >> 7);
+ priv_data[5] = (str_ctr[3] << 1) | marker_bit;
+ priv_data[6] = 0x0;
+ priv_data[7] = (input_ctr[0] >> 3) | marker_bit;
+ priv_data[8] = (input_ctr[0] << 4) ^ (input_ctr[1] >> 4);
+ priv_data[9] = ((input_ctr[1] << 4) ^ (input_ctr[2] >> 4)) | marker_bit;
+ priv_data[10] = (input_ctr[2] << 3) ^ (input_ctr[3] >> 5);
+ priv_data[11] = ((input_ctr[3] << 3) ^ (input_ctr[4] >> 5)) | marker_bit;
+ priv_data[12] = (input_ctr[4] << 2) ^ (input_ctr[5] >> 6);
+ priv_data[13] = ((input_ctr[5] << 2) ^ (input_ctr[6] >> 6)) | marker_bit;
+ priv_data[14] = (input_ctr[6] << 1) ^ (input_ctr[7] >> 7);
+ priv_data[15] = (input_ctr[7] << 1) | marker_bit;
+
+ return 0;
+}
+
+int encrypt_packet(uint8_t *priv_data,
+ u64 input_addr, size_t input_len,
+ u64 output_addr, size_t output_len,
+ struct hdcp_tx_ctx *tx_ctx)
+{
+ uint32_t bn_str_ctr;
+ uint32_t bn_input_ctr[HDCP_INPUT_CTR_LEN / 4];
+ uint32_t tmp;
+ int ret;
+
+ /* make private data including counters for PES header */
+ make_priv_data(priv_data, tx_ctx->str_ctr, tx_ctx->input_ctr);
+
+ /* HDCP Encryption */
+ /* todo: consider 32bit address. currently only support 64bit address */
+ ret = teei_encrypt_packet((uint8_t *)input_addr, input_len,
+ (uint8_t *)output_addr, output_len,
+ tx_ctx->str_ctr, HDCP_STR_CTR_LEN,
+ tx_ctx->input_ctr, HDCP_INPUT_CTR_LEN);
+ if (ret) {
+ hdcp_err("hdcp_encryption() is failed with %x\n", ret);
+ return ERR_HDCP_ENCRYPTION;
+ }
+
+ /* Update strCtr/inputCtr in tx_ctx */
+ OS2BN(&bn_str_ctr, tx_ctx->str_ctr, HDCP_STR_CTR_LEN);
+ OS2BN(bn_input_ctr, tx_ctx->input_ctr, HDCP_INPUT_CTR_LEN);
+
+ bn_str_ctr++;
+
+ tmp = input_len / 16;
+ if (input_len % 16)
+ tmp++;
+ sec_bn_Add(bn_input_ctr, bn_input_ctr, HDCP_INPUT_CTR_LEN/4, &tmp, 1);
+
+ BN2OS(tx_ctx->str_ctr, &bn_str_ctr, HDCP_STR_CTR_LEN/4);
+ BN2OS(tx_ctx->input_ctr, bn_input_ctr, HDCP_INPUT_CTR_LEN/4);
+
+#ifdef HDCP_ENC_DEBUG
+ hdcp_debug("[strCtr]:\n");
+ hdcp_hexdump(tx_ctx->str_ctr, HDCP_STR_CTR_LEN);
+
+ hdcp_debug("[inputCtr]:\n");
+ hdcp_hexdump(tx_ctx->input_ctr, HDCP_INPUT_CTR_LEN);
+#endif
+ return 0;
+}
+
--- /dev/null
+/* drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-encrypt.h
+ *
+ * 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.
+*/
+#ifndef __EXYNOS_HDCP2_ENCRYPT_H__
+#define __EXYNOS_HDCP2_ENCRYPT_H__
+
+#include <linux/types.h>
+
+#define HDCP_PRIVATE_DATA_LEN 16 /* PES priv_data length */
+
+int encrypt_packet(uint8_t *priv_data,
+ u64 input_addr, size_t input_len,
+ u64 output_addr, size_t output_len,
+ struct hdcp_tx_ctx *tx_ctx);
+
+#endif
--- /dev/null
+/*
+ * drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-log.h
+ *
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __EXYNOS_HDCP2_LOG_H__
+#define __EXYNOS_HDCP2_LOG_H__
+
+#undef HDCP_DEBUG
+
+#ifdef HDCP_DEBUG
+#define hdcp_debug(fmt, args...) \
+ do { \
+ printk(KERN_ERR "[HDCP2]%s:%d: " fmt, \
+ __func__, __LINE__, ##args); \
+ } while (0)
+#else
+#define hdcp_debug(fmt, args...)
+#endif
+
+#define hdcp_err(fmt, args...) \
+ do { \
+ printk(KERN_ERR "[HDCP2]%s:%d: " fmt, \
+ __func__, __LINE__, ##args); \
+ } while (0)
+
+#define hdcp_info(fmt, args...) \
+ do { \
+ printk(KERN_INFO "[HDCP2]%s:%d: " fmt, \
+ __func__, __LINE__, ##args); \
+ } while (0)
+#endif
--- /dev/null
+/*
+ * drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-misc.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>
+
+void hdcp_hexdump(uint8_t *buf, size_t len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (i > 0 && !(i % 16))
+ printk(KERN_ERR "\n");
+ printk(KERN_ERR "%02x ", buf[i]);
+ }
+ printk(KERN_ERR "\n");
+}
--- /dev/null
+/* drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-misc.h
+ *
+ * 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.
+*/
+#ifndef __EXYNOS_HDCP2_MISC_H__
+#define __EXYNOS_HDCP2_MISC_H__
+
+void hdcp_hexdump(uint8_t *buf, size_t len);
+
+#endif
--- /dev/null
+/*
+ * drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-protocol-msg.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 "exynos-hdcp2-config.h"
+#include "exynos-hdcp2-protocol-msg.h"
+#include "exynos-hdcp2-teeif.h"
+#include "exynos-hdcp2.h"
+#include "exynos-hdcp2-log.h"
+#include "exynos-hdcp2-misc.h"
+#include "dp_link/exynos-hdcp2-dplink-protocol-msg.h"
+
+/* HDCP protocol message capulate & decapulate functions for IIA */
+static int cap_ake_init(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int cap_ake_transmitter_info(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int cap_ake_no_stored_km(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int cap_ake_stored_km(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int decap_ake_send_cert(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int decap_ake_receiver_info(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int decap_ake_send_rrx(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int decap_ake_send_h_prime(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int decap_ake_send_pairing_info(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int cap_lc_init(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int cap_rtt_challenge(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int decap_lc_send_l_prime(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int decap_rtt_ready(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int cap_ske_send_eks(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int decap_RepeaterAuth_send_ReceiverID_List(uint8_t *m,size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int cap_RepeaterAuth_Send_Ack(uint8_t *m,size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int decap_Receiver_AuthStatus(uint8_t *m,size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int cap_RepeaterAuth_Stream_Manage(uint8_t *m,size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+static int decap_RepeaterAuth_Stream_Ready(uint8_t *m,size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+int (*proto_iia[])(uint8_t *, size_t *,
+ struct hdcp_tx_ctx *,
+ struct hdcp_rx_ctx *) = {
+ cap_ake_init,
+ decap_ake_send_cert,
+ cap_ake_no_stored_km,
+ cap_ake_stored_km,
+ decap_ake_send_rrx,
+ decap_ake_send_h_prime,
+ decap_ake_send_pairing_info,
+ cap_lc_init,
+ decap_lc_send_l_prime,
+ cap_ske_send_eks,
+ decap_RepeaterAuth_send_ReceiverID_List,
+ decap_rtt_ready,
+ cap_rtt_challenge,
+ cap_RepeaterAuth_Send_Ack,
+ cap_RepeaterAuth_Stream_Manage,
+ decap_RepeaterAuth_Stream_Ready,
+ decap_Receiver_AuthStatus,
+ cap_ake_transmitter_info,
+ decap_ake_receiver_info,
+};
+
+/* HDCP protocol message capulate & decapulate functions for DP_LINK */
+extern int (*proto_dp[])(uint8_t *, size_t *,
+ struct hdcp_tx_ctx *,
+ struct hdcp_rx_ctx *);
+
+int ske_generate_sessionkey(uint32_t lk_type, uint8_t *enc_skey, int share_skey)
+{
+ int ret;
+
+ ret = teei_generate_skey(lk_type,
+ enc_skey, HDCP_SKE_SKEY_LEN,
+ share_skey);
+ if (ret) {
+ hdcp_err("generate_session_key() is failed with %x\n", ret);
+ return ERR_GENERATE_SESSION_KEY;
+ }
+
+ return 0;
+}
+
+int ske_generate_riv(uint8_t *out)
+{
+ int ret;
+
+ ret = teei_generate_riv(out, HDCP_RTX_BYTE_LEN);
+ if (ret) {
+ hdcp_err("teei_generate_riv() is failed with %x\n", ret);
+ return ERR_GENERATE_NON_SECKEY;
+ }
+
+ return 0;
+}
+
+int lc_generate_rn(uint8_t *out, size_t out_len)
+{
+ int ret;
+
+ ret = teei_gen_rn(out, out_len);
+ if (ret) {
+ hdcp_err("lc_generate_rn() is failed with %x\n", ret);
+ return ERR_GENERATE_NON_SECKEY;
+ }
+
+ return 0;
+}
+
+int lc_make_hmac(struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx, uint32_t lk_type)
+{
+ int ret;
+
+ if ((rx_ctx->version != HDCP_VERSION_2_0) &&
+ tx_ctx->lc_precomp && rx_ctx->lc_precomp) {
+ ret = teei_gen_lc_hmac(lk_type,
+ tx_ctx->lsb16_hmac);
+ if (ret) {
+ hdcp_err("compute_lc_whmac() is failed with %x\n", ret);
+ return ERR_COMPUTE_LC_HMAC;
+ }
+ } else {
+ hdcp_err("LC precomp is not supported\n");
+ return ERR_COMPUTE_LC_HMAC;
+ }
+
+ return ret;
+}
+
+int lc_compare_hmac(uint8_t *rx_hmac, size_t hmac_len)
+{
+ int ret;
+
+ ret = teei_compare_lc_hmac(rx_hmac, hmac_len);
+ if (ret) {
+ hdcp_err("compare_lc_hmac_val() is failed with %x\n", ret);
+ return ERR_COMPARE_LC_HMAC;
+ }
+
+ return ret;
+}
+
+
+static int ake_generate_rtx(uint32_t lk_type, uint8_t *out, size_t out_len)
+{
+ int ret;
+
+ /* IIA Spec does not use TxCaps */
+ ret = teei_gen_rtx(lk_type, out, out_len, NULL, 0);
+ if (ret) {
+ hdcp_err("generate rtx is failed with 0x%x\n", ret);
+ return ERR_GENERATE_NON_SECKEY;
+ }
+
+ return 0;
+}
+
+static int ake_set_tx_info(struct hdcp_tx_ctx *tx_ctx)
+{
+ int ret;
+ uint8_t version[HDCP_VERSION_LEN];
+ uint8_t caps_mask[HDCP_CAPABILITY_MASK_LEN];
+
+ /* Init Version & Precomputation */
+ ret = teei_get_txinfo(version, HDCP_VERSION_LEN,
+ caps_mask, HDCP_CAPABILITY_MASK_LEN);
+ if (ret) {
+ hdcp_err("Get Tx info is failed with 0x%x\n", ret);
+ return ERR_GET_TX_INFO;
+ }
+ hdcp_debug("Tx: version(0x%02x) Caps_maks(0x%02x%02x)\n",
+ version[0], caps_mask[0], caps_mask[1]);
+
+ tx_ctx->version = version[0];
+ tx_ctx->lc_precomp = caps_mask[1];
+
+ /* todo: check seq_num_M init position*/
+ tx_ctx->seq_num_M = 0;
+ return 0;
+}
+
+static int ake_set_rx_info(struct hdcp_rx_ctx *rx_ctx)
+{
+ int ret;
+ uint8_t version[HDCP_VERSION_LEN];
+ uint8_t caps_mask[HDCP_CAPABILITY_MASK_LEN];
+
+
+ version[0] = rx_ctx->version;
+ caps_mask[0] = 0x00; /* reserved field in IIA spec */
+ caps_mask[1] = rx_ctx->lc_precomp;
+
+ /* Init Version & Precomputation */
+ ret = teei_set_rxinfo(version, HDCP_VERSION_LEN,
+ caps_mask, HDCP_CAPABILITY_MASK_LEN);
+ if (ret) {
+ hdcp_err("Get Tx info is failed with 0x%x\n", ret);
+ return ERR_SET_RX_INFO;
+ }
+
+ return 0;
+}
+
+static int ake_set_rrx(uint8_t *rrx, size_t rrx_len)
+{
+ int ret;
+
+ /* set Rrx value */
+ ret = teei_set_rrx(rrx, rrx_len);
+ if (ret) {
+ hdcp_err("set rrx is failed with 0x%x\n", ret);
+ return ERR_SET_RRX;
+ }
+
+ return 0;
+}
+
+int ake_verify_cert(uint8_t *cert, size_t cert_len,
+ uint8_t *rrx, size_t rrx_len,
+ uint8_t *rx_caps, size_t rx_caps_len)
+{
+ int ret;
+
+ ret = teei_verify_cert(cert, cert_len,
+ rrx, rrx_len,
+ rx_caps, rx_caps_len);
+ if (ret) {
+ hdcp_err("teei_verify_cert() is failed with %x\n", ret);
+ return ERR_VERIFY_CERT;
+ }
+
+ return 0;
+}
+
+int ake_generate_masterkey(uint32_t lk_type, uint8_t *enc_mkey, size_t elen)
+{
+ int ret;
+
+ /* Generate Encrypted & Wrapped Master Key */
+ ret = teei_generate_master_key(lk_type, enc_mkey, elen);
+ if (ret) {
+ hdcp_err("generate_master_key() is failed with %x\n", ret);
+ return ERR_GENERATE_MASTERKEY;
+ }
+
+ return ret;
+}
+
+int ake_compare_hmac(uint8_t *rx_hmac, size_t rx_hmac_len)
+{
+ int ret;
+
+ ret = teei_compare_ake_hmac(rx_hmac, rx_hmac_len);
+ if (ret) {
+ hdcp_err("teei_compare_hmac() is failed with %x\n", ret);
+ return ERR_COMPUTE_AKE_HMAC;
+ }
+
+ return 0;
+}
+
+int ake_store_master_key(uint8_t *ekh_mkey, size_t ekh_mkey_len)
+{
+ int ret;
+
+ ret = teei_set_pairing_info(ekh_mkey, ekh_mkey_len);
+ if (ret) {
+ hdcp_err("teei_store_pairing_info() is failed with %x\n", ret);
+ return ERR_STORE_MASTERKEY;
+ }
+
+ return 0;
+}
+
+int ake_find_masterkey(int *found_km,
+ uint8_t *ekh_mkey, size_t ekh_mkey_len,
+ uint8_t *m, size_t m_len)
+{
+ int ret;
+
+ ret = teei_get_pairing_info(ekh_mkey, ekh_mkey_len, m, m_len);
+ if (ret) {
+ if (ret == E_HDCP_PRO_INVALID_RCV_ID) {
+ hdcp_info("RCV id is not found\n");
+ *found_km = 0;
+ return 0;
+ } else {
+ *found_km = 0;
+ hdcp_err("teei_store_pairing_info() is failed with %x\n", ret);
+ return ERR_FIND_MASTERKEY;
+ }
+ }
+
+ *found_km = 1;
+
+ return 0;
+}
+
+static int cap_ake_init(uint8_t *m, size_t *m_len, struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ size_t rtx_len;
+ int ret;
+
+ /* Buffer Check */
+ if ((m == NULL) || (m_len == NULL) || (tx_ctx == NULL))
+ return ERR_WRONG_BUFFER;
+
+ rtx_len = HDCP_AKE_RTX_BYTE_LEN;
+
+ /* Generate rtx */
+ ret = ake_generate_rtx(HDCP_LINK_TYPE_IIA, tx_ctx->rtx, rtx_len);
+ if (ret) {
+ hdcp_err("failed to generate rtx\n");
+ return ERR_GENERATE_RTX;
+ }
+
+ /* Make Message */
+ m[0] = AKE_INIT;
+ memcpy(&m[1], tx_ctx->rtx, rtx_len);
+ *m_len = 1 + rtx_len;
+
+#ifdef HDCP_AKE_DEBUG
+ hdcp_debug("HDCP: cap_ake_init(%lu) \n", *m_len);
+ hdcp_hexdump(m, *m_len);
+#endif
+ return 0;
+}
+
+static int cap_ake_transmitter_info(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ int ret;
+
+ if ((m == NULL) || (m_len == NULL) || (tx_ctx == NULL))
+ return ERR_WRONG_BUFFER;
+
+ /* Set info */
+ ret = ake_set_tx_info(tx_ctx);
+ if (ret) {
+ hdcp_err("failed to set info\n");
+ return ERR_SET_INFO;
+ }
+
+
+ /* Make Message */
+ m[0] = AKE_TRANSMITTER_INFO;
+ m[1] = 0x0;
+ m[2] = 0x06;
+ m[3] = tx_ctx->version;
+ m[4] = 0x0;
+ m[5] = tx_ctx->lc_precomp;
+ *m_len = 6;
+
+#ifdef HDCP_AKE_DEBUG
+ hdcp_debug("cap_ake_transmitter_info(%lu) \n", *m_len);
+ hdcp_hexdump(m, *m_len);
+#endif
+ return 0;
+}
+
+static int cap_ake_no_stored_km(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ uint8_t enc_mkey[HDCP_AKE_ENCKEY_BYTE_LEN];
+ int ret;
+
+ if ((m == NULL) || (m_len == NULL) || (tx_ctx == NULL) ||
+ (rx_ctx == NULL))
+ return ERR_WRONG_BUFFER;
+
+ /* Verify Certificate */
+ /* IIA spec does not define rrx and RxCaps with Cert message */
+ ret = ake_verify_cert(rx_ctx->cert, sizeof(rx_ctx->cert),
+ NULL, 0,
+ &(rx_ctx->repeater), HDCP_RX_CAPS_LEN);
+ if (ret)
+ /* authentication failure &
+ * aborts the authentication protocol */
+ return ret;
+
+ /* Generate/Encrypt master key */
+ ret = ake_generate_masterkey(HDCP_LINK_TYPE_IIA,
+ enc_mkey, sizeof(enc_mkey));
+ /* Generate/Encrypt master key */
+ if (ret)
+ return ret;
+
+ /* Make Message */
+ m[0] = AKE_NO_STORED_KM;
+ memcpy(&m[1], enc_mkey, HDCP_AKE_ENCKEY_BYTE_LEN);
+ *m_len = 1 + HDCP_AKE_ENCKEY_BYTE_LEN;
+
+#ifdef HDCP_AKE_DEBUG
+ hdcp_debug("cap_ake_no_stored_km(%lu)\n", *m_len);
+ hdcp_hexdump(m, *m_len);
+#endif
+ return 0;
+}
+
+static int cap_ake_stored_km(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ int ret;
+ int found_km;
+
+ if ((m == NULL) || (m_len == NULL) || (tx_ctx == NULL))
+ return ERR_WRONG_BUFFER;
+
+ /* Generate/Encrypt master key */
+ 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 || !found_km) {
+ hdcp_err("find_masterkey() is failed with 0x%x\n", ret);
+ return -1;
+ }
+
+ /* Make Message */
+ m[0] = AKE_STORED_KM;
+ memcpy(&m[1], tx_ctx->ekh_mkey, HDCP_AKE_EKH_MKEY_BYTE_LEN);
+ memcpy(&m[1] + HDCP_AKE_EKH_MKEY_BYTE_LEN, tx_ctx->m, HDCP_AKE_M_BYTE_LEN);
+ *m_len = 1 + HDCP_AKE_EKH_MKEY_BYTE_LEN + HDCP_AKE_M_BYTE_LEN;
+
+#ifdef HDCP_AKE_DEBUG
+ hdcp_debug("cap_ake_stored_km(%lu) \n", *m_len);
+ hdcp_hexdump(m, *m_len);
+#endif
+ return 0;
+}
+
+static int decap_ake_send_cert(uint8_t *m, size_t *m_len, struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ int ret;
+
+ ret = check_received_msg(m, *m_len, 2 + HDCP_RX_CERT_LEN, AKE_SEND_CERT);
+ if (ret)
+ return ret;
+
+ rx_ctx->repeater = m[1];
+ memcpy(rx_ctx->cert, &m[2], HDCP_RX_CERT_LEN);
+
+#ifdef HDCP_AKE_DEBUG
+ hdcp_debug("decap_ake_send_cert(%lu) \n", *m_len);
+ hdcp_hexdump(m, *m_len);
+#endif
+ return 0;
+}
+
+static int decap_ake_receiver_info(uint8_t *m, size_t *m_len, struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ int ret;
+
+ ret = check_received_msg(m, *m_len, 6, AKE_RECEIVER_INFO);
+ if (ret)
+ return ret;
+
+ if ((m[2] < 6) && (m[1] == 0)) {
+ hdcp_err("AKE_Receiver_Info, send wrong length\n");
+ return ERR_WRONG_MESSAGE_LENGTH;
+ }
+
+ rx_ctx->version = m[3];
+ rx_ctx->lc_precomp = m[5];
+
+ ret = ake_set_rx_info(rx_ctx);
+ if (ret) {
+ hdcp_err("AKE set rx info failed. ret(0x%x)\n", ret);
+ return ret;
+ }
+
+#ifdef HDCP_AKE_DEBUG
+ hdcp_debug("decap_ake_receiver_info()\n");
+ hdcp_debug("version: 0x%02x\n", rx_ctx->version);
+ hdcp_debug("HDCP lc_precomp: 0x%02x\n", rx_ctx->lc_precomp);
+#endif
+ return 0;
+}
+
+static int decap_ake_send_rrx(uint8_t *m, size_t *m_len, struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ int ret;
+ uint8_t rrx[HDCP_RRX_BYTE_LEN] = {0};
+
+ ret = check_received_msg(m, *m_len, 1 + HDCP_RRX_BYTE_LEN, AKE_SEND_RRX);
+ if (ret)
+ return ret;
+
+ memcpy(rx_ctx->rrx, &m[1], HDCP_RRX_BYTE_LEN);
+ memcpy(rrx, &m[1], HDCP_RRX_BYTE_LEN);
+ ret = ake_set_rrx(rrx, HDCP_RRX_BYTE_LEN);
+ if (ret)
+ return ret;
+
+#ifdef HDCP_AKE_DEBUG
+ hdcp_debug("decap_ake_send_rrx\n");
+ hdcp_hexdump(rx_ctx->rrx, HDCP_RRX_BYTE_LEN);
+#endif
+ return 0;
+}
+
+static int decap_ake_send_h_prime(uint8_t *m, size_t *m_len, struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ int ret;
+
+ ret = check_received_msg(m, *m_len, 1 + HDCP_HMAC_SHA256_LEN,
+ AKE_SEND_H_PRIME);
+ if (ret)
+ return ret;
+
+ /* compare H == H' */
+ ret = ake_compare_hmac(&m[1], HDCP_HMAC_SHA256_LEN);
+ if (ret)
+ return ret;
+
+#ifdef HDCP_AKE_DEBUG
+ hdcp_debug("decap_ake_send_h_prime\n");
+ hdcp_debug("given hmac:\n");
+ hdcp_hexdump(&m[1], HDCP_HMAC_SHA256_LEN);
+#endif
+ return 0;
+}
+
+static int decap_ake_send_pairing_info(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ int ret;
+
+ ret = check_received_msg(m, *m_len, 1 + HDCP_AKE_EKH_MKEY_BYTE_LEN,
+ AKE_SEND_PAIRING_INFO);
+ if (ret)
+ return ret;
+
+ memcpy(tx_ctx->ekh_mkey, &m[1], HDCP_AKE_EKH_MKEY_BYTE_LEN);
+
+ /* Store the Key */
+ ret = ake_store_master_key(tx_ctx->ekh_mkey, HDCP_AKE_EKH_MKEY_BYTE_LEN);
+ if (ret)
+ return ret;
+
+#ifdef HDCP_AKE_DEBUG
+ hdcp_debug("decap_ake_send_pairing_info(%lu)\n", *m_len);
+ hdcp_debug("rx_ctx->ekh_mkey:\n");
+ hdcp_hexdump(tx_ctx->ekh_mkey, HDCP_AKE_MKEY_BYTE_LEN);
+#endif
+
+ return 0;
+}
+
+static int cap_lc_init(uint8_t *m, size_t *m_len, struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ int ret;
+
+ if ((m == NULL) || (m_len == NULL) || (tx_ctx == NULL) || (rx_ctx ==
+ NULL))
+ return ERR_WRONG_BUFFER;
+
+ /* Generate rn */
+ ret = lc_generate_rn(tx_ctx->rn, HDCP_RTX_BYTE_LEN);
+ if (ret) {
+ hdcp_err("failed to generate rtx\n");
+ return ERR_GENERATE_RN;
+ }
+
+ /* Make Message */
+ m[0] = LC_INIT;
+ memcpy(&m[1], tx_ctx->rn, HDCP_RTX_BYTE_LEN);
+ *m_len = 1 + HDCP_RTX_BYTE_LEN;
+
+ if ((rx_ctx->version != HDCP_VERSION_2_0) &&
+ tx_ctx->lc_precomp &&
+ rx_ctx->lc_precomp) {
+ /* compute HMAC,
+ * return the least significant 128-bits,
+ * the most significant 128-bits wrapped */
+ ret = lc_make_hmac(tx_ctx, rx_ctx, 0); // last param 0 have to be checked, PKY
+ if (ret)
+ return ret;
+ }
+
+#ifdef HDCP_LC_DEBUG
+ hdcp_debug("LC_Init(%u)\n", *m_len);
+ hdcp_hexdump(m, *m_len);
+#endif
+ return 0;
+}
+
+static int cap_rtt_challenge(uint8_t *m, size_t *m_len, struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ if ((m == NULL) || (m_len == NULL) || (tx_ctx == NULL))
+ return ERR_WRONG_BUFFER;
+
+ /* Make Message */
+ m[0] = RTT_CHALLENGE;
+ memcpy(&m[1], tx_ctx->lsb16_hmac, HDCP_HMAC_SHA256_LEN / 2);
+ *m_len = 1 + (HDCP_HMAC_SHA256_LEN / 2);
+
+#ifdef HDCP_LC_DEBUG
+ hdcp_debug("RTT_Challenge(%lu)\n", *m_len);
+ hdcp_hexdump(m, *m_lne);
+#endif
+
+ return 0;
+}
+
+static int decap_lc_send_l_prime(uint8_t *m, size_t *m_len, struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ uint8_t *rx_hmac;
+ size_t len;
+ int ret;
+
+ /* find length depending precomputation */
+ if ((rx_ctx->version == HDCP_VERSION_2_0) || !tx_ctx->lc_precomp ||
+ !rx_ctx->lc_precomp)
+ len = HDCP_HMAC_SHA256_LEN;
+ else
+ len = HDCP_HMAC_SHA256_LEN/2;
+
+ ret = check_received_msg(m, *m_len, 1 + len, LC_SEND_L_PRIME);
+ if (ret)
+ return ret;
+
+ /* No_precomputation: compare hmac
+ precomputation: compare the most significant 128bits of L & L' */
+ rx_hmac = &m[1];
+ ret = lc_compare_hmac(rx_hmac, len);
+ if (ret)
+ return ret;
+
+#ifdef HDCP_LC_DEBUG
+ hdcp_debug("LC_Send_L_prime\n");
+ hdcp_debug("rx_hmac:\n");
+ hdcp_hexdump(rx_hmac, len);
+#endif
+
+ return 0;
+}
+
+static int decap_rtt_ready(uint8_t *m, size_t *m_len, struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ int ret;
+
+ ret = check_received_msg(m, *m_len, 1, RTT_READY);
+ if (ret)
+ return ret;
+
+#ifdef HDCP_LC_DEBUG
+ hdcp_debug("RTT_Ready\n");
+#endif
+
+ return 0;
+}
+
+static int cap_ske_send_eks(uint8_t *m, size_t *m_len, struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ int ret;
+
+ uint8_t enc_skey[HDCP_AKE_MKEY_BYTE_LEN];
+
+ if ((m == NULL) || (m_len == NULL) || (tx_ctx == NULL) ||
+ (rx_ctx == NULL))
+ return ERR_WRONG_BUFFER;
+
+ /* Generate riv */
+ if (!tx_ctx->share_skey) {
+ ret = ske_generate_riv(tx_ctx->riv);
+ if (ret)
+ return ERR_GENERATE_RIV;
+ }
+
+ /* Generate encrypted Session Key */
+ ret = ske_generate_sessionkey(0, enc_skey, tx_ctx->share_skey);
+ if (ret)
+ return ret;
+
+ /* Make Message */
+ m[0] = SKE_SEND_EKS;
+ memcpy(&m[1], enc_skey, HDCP_AKE_MKEY_BYTE_LEN);
+ memcpy(&m[1 + HDCP_AKE_MKEY_BYTE_LEN], tx_ctx->riv, HDCP_RTX_BYTE_LEN);
+ *m_len = 1 + HDCP_AKE_MKEY_BYTE_LEN + HDCP_RTX_BYTE_LEN;
+
+#ifdef HDCP_SKE_DEBUG
+ hdcp_debug("SKE_Send_Eks(%lu)\n", *m_len);
+ hdcp_hexdump(m, *m_len);
+#endif
+ return 0;
+}
+
+#ifdef TEST_HDCP_V2_0
+int parse_rcvid_list(uint8_t *msg, struct hdcp_tx_ctx *tx_ctx)
+{
+ /* get PRE META values */
+ tx_ctx->rcv_list.devs_exd = (uint8_t)*msg;
+ tx_ctx->rcv_list.cascade_exd = (uint8_t)*(msg + 1);
+
+ /* get META values */
+ msg += HDCP_RP_RCV_LIST_PRE_META_LEN;
+ tx_ctx->rcv_list.devs_count = (uint8_t)*msg;
+ tx_ctx->rcv_list.depth = (uint8_t)*(msg + 1);
+ memcpy(tx_ctx->rcv_list.hmac_prime, (uint8_t *)(msg + 2), 32);
+
+ /* get receiver ID list */
+ msg += 34;
+ memcpy(tx_ctx->rcv_list.rcv_id, msg, tx_ctx->rcv_list.devs_count * HDCP_RCV_ID_LEN);
+
+ return 0;
+}
+
+void convert_rcvlist2authmsg(struct hdcp_rcvlist *rcv_list, uint8_t *src_msg, size_t *msg_len)
+{
+ int i;
+ *msg_len = 0;
+
+ for (i = 0; i < rcv_list->devs_count; i++) {
+ memcpy(src_msg + *msg_len, rcv_list->rcv_id[i], HDCP_RCV_ID_LEN);
+ *msg_len += HDCP_RCV_ID_LEN;
+ }
+
+ /* concatinate DEPTH */
+ memcpy(src_msg + *msg_len, &rcv_list->depth, 1);
+ *msg_len += 1;
+
+ /* concatinate DEVICE COUNT */
+ memcpy(src_msg + *msg_len, &rcv_list->devs_count, 1);
+ *msg_len += 1;
+
+ /* concatinate MAX DEVS EXCEEDED */
+ memcpy(src_msg + *msg_len, &rcv_list->devs_exd, 1);
+ *msg_len += 1;
+
+ /* concatinate MAX CASCADE EXCEEDED */
+ memcpy(src_msg + *msg_len, &rcv_list->cascade_exd, 1);
+ *msg_len += 1;
+}
+#else
+int parse_rcvid_list(uint8_t *msg, struct hdcp_tx_ctx *tx_ctx)
+{
+ /* get PRE META values */
+ tx_ctx->rpauth_info.devs_exd = (uint8_t)*msg;
+ tx_ctx->rpauth_info.cascade_exd = (uint8_t)*(msg + 1);
+
+ /* get META values */
+ msg += HDCP_RP_RCV_LIST_PRE_META_LEN;
+ tx_ctx->rpauth_info.devs_count = (uint8_t)*msg;
+ tx_ctx->rpauth_info.depth = (uint8_t)*(msg + 1);
+ tx_ctx->rpauth_info.hdcp2_down = (uint8_t)*(msg + 2);
+ tx_ctx->rpauth_info.hdcp1_down = (uint8_t)*(msg + 3);
+ memcpy(tx_ctx->rpauth_info.seq_num_v, (uint8_t *)(msg + 4), 3);
+ memcpy(tx_ctx->rpauth_info.v_prime, (uint8_t *)(msg + 7), 16);
+
+ /* get receiver ID list */
+ msg += HDCP_RP_RCV_LIST_META_LEN;
+ if (tx_ctx->rpauth_info.devs_count > HDCP_RCV_DEVS_COUNT_MAX) {
+ hdcp_err("invalid DEVS count (%d)\n", tx_ctx->rpauth_info.devs_count);
+ return -1;
+ }
+
+ memcpy(tx_ctx->rpauth_info.u_rcvid.arr, msg, tx_ctx->rpauth_info.devs_count * HDCP_RCV_ID_LEN);
+
+ return 0;
+}
+
+void convert_rcvlist2authmsg(struct hdcp_rpauth_info *rpauth_info, uint8_t *src_msg, size_t *msg_len)
+{
+ int i;
+ *msg_len = 0;
+
+ for (i = 0; i < rpauth_info->devs_count; i++) {
+ memcpy(src_msg + *msg_len, rpauth_info->u_rcvid.arr[i], HDCP_RCV_ID_LEN);
+ *msg_len += HDCP_RCV_ID_LEN;
+ }
+
+ /* concatinate DEPTH */
+ memcpy(src_msg + *msg_len, &rpauth_info->depth, 1);
+ *msg_len += 1;
+
+ /* concatinate DEVICE COUNT */
+ memcpy(src_msg + *msg_len, &rpauth_info->devs_count, 1);
+ *msg_len += 1;
+
+ /* concatinate MAX DEVS EXCEEDED */
+ memcpy(src_msg + *msg_len, &rpauth_info->devs_exd, 1);
+ *msg_len += 1;
+
+ /* concatinate MAX CASCADE EXCEEDED */
+ memcpy(src_msg + *msg_len, &rpauth_info->cascade_exd, 1);
+ *msg_len += 1;
+
+ /* concatinate HDCP2 REPEATER DOWNSTREAM */
+ memcpy(src_msg + *msg_len, &rpauth_info->hdcp2_down, 1);
+ *msg_len += 1;
+
+ /* concatinate HDCP1 DEVICE DOWNSTREAM */
+ memcpy(src_msg + *msg_len, &rpauth_info->hdcp1_down, 1);
+ *msg_len += 1;
+
+ /* concatinate seq_num_v */
+ memcpy(src_msg + *msg_len, &rpauth_info->seq_num_v, 3);
+ *msg_len += 3;
+}
+#endif
+
+static int decap_RepeaterAuth_send_ReceiverID_List(uint8_t *m,
+ size_t *m_len, struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ size_t hmac_prime_len;
+ size_t msg_len;
+ uint8_t source_msg[256];
+ int ret;
+
+ if (rx_ctx->version == HDCP_VERSION_2_0)
+ hmac_prime_len = HDCP_HMAC_SHA256_LEN;
+ else
+ hmac_prime_len = HDCP_HMAC_SHA256_LEN/2;
+
+ ret = check_received_msg(m, *m_len, 0, REPEATERAUTH_SEND_RECEIVERID_LIST);
+ if (ret)
+ return ret;
+
+ if (parse_rcvid_list(m + 1, tx_ctx))
+ return -1;
+
+ convert_rcvlist2authmsg(&tx_ctx->rpauth_info, source_msg, &msg_len);
+
+ ret = teei_set_rcvlist_info(NULL, NULL, tx_ctx->rpauth_info.v_prime,
+ source_msg, tx_ctx->rpauth_info.v, &(tx_ctx->rpauth_info.valid));
+
+ tx_ctx->rpauth_info.valid = 0;
+ if (ret) {
+ tx_ctx->rpauth_info.valid = 1;
+ return ret;
+ }
+
+#ifdef HDCP_TX_REPEATER_DEBUG
+ hdcp_debug("decap_RepeaterAuth_send_ReceiverID_List valid (%u)\n", tx_ctx->rpauth_info.valid);
+ hdcp_hexdump(tx_ctx->rpauth_info.v, HDCP_RP_HMAC_V_LEN / 2);
+#endif
+ return 0;
+}
+
+static int cap_RepeaterAuth_Send_Ack(uint8_t *m, size_t *m_len, struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ if ((m == NULL) || (m_len == NULL) || (tx_ctx == NULL))
+ return ERR_WRONG_BUFFER;
+
+ /* Make Message */
+ m[0] = REPEATERAUTH_SEND_ACK;
+ if(tx_ctx->rpauth_info.valid == 0)
+ memcpy(&m[1], tx_ctx->rpauth_info.v, HDCP_RP_HMAC_V_LEN / 2);
+ else
+ return ERR_SEND_ACK;
+
+ *m_len = 1 + (HDCP_RP_HMAC_V_LEN / 2);
+
+#ifdef HDCP_TX_REPEATER_DEBUG
+ hdcp_debug("make_RepeaterAuth_Send_Ack(%u)\n", *m_len);
+ hdcp_hexdump(m, *m_len);
+#endif
+ return 0;
+}
+
+static int decap_Receiver_AuthStatus(uint8_t *m,
+ size_t *m_len, struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ int ret;
+
+ ret = check_received_msg(m, (int)*m_len, 0, RECEIVER_AUTHSTATUS);
+ if (ret)
+ return ret;
+
+ tx_ctx->rp_reauth = m[3];
+#ifdef HDCP_TX_REPEATER_DEBUG
+ hdcp_debug("get_Receiver_AuthStatus(%u)\n", *m_len);
+ hdcp_debug("receiver reauth req: %u\n", tx_ctx->rp_reauth);
+#endif
+ return 0;
+}
+
+int cap_RepeaterAuth_Stream_Manage(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ int i;
+ uint8_t *dst;
+ uint16_t stmp;
+ uint32_t itmp;
+
+ if ((m == NULL) || (m_len == NULL) || (tx_ctx == NULL))
+ return ERR_WRONG_BUFFER;
+
+ if (tx_ctx->stream_ctrl.str_num > HDCP_TX_REPEATER_MAX_STREAM)
+ return ERR_EXCEED_MAX_STREAM;
+
+ /* Make Message */
+ m[0] = REPEATERAUTH_STREAM_MANAGE;
+ itmp = htonl(tx_ctx->seq_num_M);
+ memcpy(&m[1], (uint8_t *)&itmp + 1, 3);
+ stmp = htons(tx_ctx->stream_ctrl.str_num);
+ memcpy(&m[4], &stmp, sizeof(stmp));
+
+ for (i = 0; i < tx_ctx->stream_ctrl.str_num; i++) {
+ dst = (uint8_t *)(&m[6] + STREAM_INFO_SIZE * i);
+ itmp = htonl(tx_ctx->stream_ctrl.str_info[i].ctr);
+ memcpy(dst, &itmp, sizeof(itmp));
+ stmp = htons(tx_ctx->stream_ctrl.str_info[i].pid);
+ memcpy(dst + sizeof(itmp), &stmp, sizeof(stmp));
+ dst[STREAM_INFO_SIZE - 1] = tx_ctx->stream_ctrl.str_info[i].type;
+ }
+
+ *m_len = HDCP_PROTO_MSG_ID_LEN + STREAM_ELEM_SIZE + STREAM_INFO_SIZE * i;
+
+ /* seq_num_M++ */
+ tx_ctx->seq_num_M++;
+
+ /* save message to make M */
+ memcpy(tx_ctx->strmsg, &m[6], *m_len - 6);
+ memcpy(tx_ctx->strmsg + *m_len - 6, &m[1], 3);
+ tx_ctx->strmsg_len = *m_len - 3;
+
+#ifdef HDCP_TX_REPEATER_DEBUG
+ hdcp_debug("strmsg(len: %d): \n", tx_ctx->strmsg_len);
+ hdcp_hexdump(tx_ctx->strmsg, tx_ctx->strmsg_len);
+
+ hdcp_debug("message(len: %d): \n", *m_len);
+ hdcp_hexdump(m, *m_len);
+
+ hdcp_debug("seq_num_M: %d\n", tx_ctx->seq_num_M);
+#endif
+ return 0;
+}
+
+int decap_RepeaterAuth_Stream_Ready(uint8_t *m, size_t *m_len,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ int ret = 0;
+ /* Not support yet*/
+#if 0
+ ret = check_received_msg(m, *m_len, 1 + HDCP_HMAC_SHA256_LEN, REPEATERAUTH_STREAM_READY);
+ if (ret)
+ return ret;
+
+ /* compute M and compare M == M' */
+ ret = teei_verify_m_prime(&m[1], tx_ctx->strmsg, tx_ctx->strmsg_len);
+ if (ret)
+ return ret;
+#endif
+ return ret;
+}
+
+int cap_protocol_msg(uint8_t msg_id,
+ uint8_t *msg,
+ size_t *msg_len,
+ uint32_t lk_type,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ /* todo: check upper boundary */
+ int ret = 0;
+ int (**proto_func)(uint8_t *, size_t *,
+ struct hdcp_tx_ctx *,
+ struct hdcp_rx_ctx *);
+
+ if (lk_type == HDCP_LINK_TYPE_IIA)
+ proto_func = proto_iia;
+#if defined(CONFIG_HDCP2_DP_ENABLE)
+ else if(lk_type == HDCP_LINK_TYPE_DP)
+ proto_func = proto_dp;
+#endif
+ else {
+ hdcp_err("invalid link type(%d)\n", lk_type);
+ return -1;
+ }
+
+ if (msg_id > 1) {
+ ret = proto_func[msg_id - 2](msg, msg_len, tx_ctx, rx_ctx);
+ return ret;
+ }
+ else
+ return -1;
+}
+
+int decap_protocol_msg(uint8_t msg_id,
+ uint8_t *msg,
+ size_t msg_len,
+ uint32_t lk_type,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ int ret = 0;
+ int (**proto_func)(uint8_t *, size_t *,
+ struct hdcp_tx_ctx *,
+ struct hdcp_rx_ctx *);
+
+ /* todo: check upper boundary */
+ if (lk_type == HDCP_LINK_TYPE_IIA)
+ proto_func = proto_iia;
+#if defined(CONFIG_HDCP2_DP_ENABLE)
+ else if(lk_type == HDCP_LINK_TYPE_DP)
+ proto_func = proto_dp;
+#endif
+ else {
+ hdcp_err("HDCP: invalid link type(%d)\n", lk_type);
+ return -1;
+ }
+
+ if (msg_id > 1) {
+ ret = proto_func[msg_id - 2](msg, &msg_len, tx_ctx, rx_ctx);
+ return ret;
+ }
+
+ else
+ return -1;
+}
--- /dev/null
+/* drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-protocol-msg.h
+ *
+ * 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.
+ */
+#ifndef __EXYNOS_HDCP2_PROTOCOL_MSG_H__
+#define __EXYNOS_HDCP2_PROTOCOL_MSG_H__
+
+#include <linux/types.h>
+#include "exynos-hdcp2-teeif.h"
+
+/* Error */
+#define ERR_TLC_CONNECT 0x1001
+#define ERR_WRONG_BUFFER 0x1002
+#define ERR_WRONG_MESSAGE_LENGTH 0x1003
+#define ERR_WRONG_MESSAGE_ID 0x1004
+#define ERR_GENERATE_NON_SECKEY 0x1005
+#define ERR_FILE_OPEN 0x1006
+
+#define ERR_GENERATE_RTX 0x2001
+#define ERR_VERIFY_CERT 0x2002
+#define ERR_GENERATE_MASTERKEY 0x2003
+#define ERR_COMPUTE_AKE_HMAC 0x2004
+#define ERR_COMPARE_AKE_HMAC 0x2005
+#define ERR_STORE_MASTERKEY 0x2006
+#define ERR_CHECK_SRM 0x2007
+#define ERR_WRAP_SRM 0x2008
+#define ERR_SET_INFO 0x2009
+#define ERR_MEMORY_ALLOCATION 0x200A
+#define ERR_GET_TX_INFO 0x200B
+#define ERR_SET_RX_INFO 0x200C
+#define ERR_SET_RRX 0x200D
+#define ERR_FIND_MASTERKEY 0x200E
+
+#define ERR_GENERATE_RN 0x3001
+#define ERR_COMPUTE_LC_HMAC 0x3002
+#define ERR_COMPARE_LC_HMAC 0x3003
+
+#define ERR_GENERATE_RIV 0x4001
+#define ERR_GENERATE_SESSION_KEY 0x4002
+
+#define ERR_HDCP_ENCRYPTION 0x5001
+
+#define ERR_RP_VERIFY_RCVLIST 0x6001
+#define ERR_EXCEED_MAX_STREAM 0x6002
+#define ERR_VALIDATE_M 0x6003
+#define ERR_SEND_ACK 0x6004
+#define ERR_RP_GEN_STREAM_MG 0x6005
+#define ERR_RP_INVALID_M_PRIME 0x6006
+
+#define HDCP_RP_RCV_LIST_PRE_META_LEN 2
+#define HDCP_RP_RCV_LIST_META_LEN 23
+
+#define HDCP_PROTO_MSG_ID_LEN 1
+#define HDCP_TX_REPEATER_MAX_STREAM 32
+#define STREAM_ELEM_SIZE 5
+#define STREAM_INFO_SIZE 7
+#define STREAM_MAX_LEN 1024
+
+enum {
+ HDCP_VERSION_2_0 = 0x00,
+ HDCP_VERSION_2_1 = 0x01,
+ HDCP_VERSION_2_2 = 0x01,
+};
+
+enum {
+ LC_PRECOMPUTE_NOT_SUPPORT = 0x00,
+ LC_PRECOMPUTE_SUPPORT = 0x01,
+};
+
+enum msg_id {
+ AKE_INIT = 2,
+ 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,
+};
+
+struct stream_info {
+ uint8_t type;
+ uint16_t pid;
+ uint32_t ctr;
+};
+
+struct contents_info {
+ uint8_t str_num;
+ struct stream_info str_info[HDCP_TX_REPEATER_MAX_STREAM];
+};
+
+struct hdcp_rpauth_info {
+ uint8_t devs_exd;
+ uint8_t cascade_exd;
+ uint8_t devs_count;
+ uint8_t depth;
+ uint8_t hdcp2_down;
+ uint8_t hdcp1_down;
+ 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];
+ union {
+ uint8_t arr[HDCP_RCV_DEVS_COUNT_MAX][HDCP_RCV_ID_LEN];
+ uint8_t lst[HDCP_RP_RCVID_LIST_LEN];
+ } u_rcvid;
+ /* repeater auth result */
+ uint8_t v[HDCP_RP_HMAC_V_LEN / 2];
+ uint8_t valid;
+};
+
+struct dp_stream_info {
+ uint16_t stream_num;
+ uint8_t streamid[HDCP_RP_MAX_STREAMID_NUM];
+ 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];
+};
+
+union stream_manage {
+ struct dp_stream_info dp;
+ /* todo: add IIA */
+};
+
+struct hdcp_tx_ctx {
+ uint8_t version;
+ uint8_t lc_precomp;
+
+ /* master key */
+ uint8_t wrap_mkey[HDCP_AKE_WKEY_BYTE_LEN];
+ uint8_t caps[HDCP_CAPS_BYTE_LEN];
+ uint8_t ekh_mkey[HDCP_AKE_EKH_MKEY_BYTE_LEN];
+ uint8_t m[HDCP_AKE_M_BYTE_LEN];
+
+ uint8_t rtx[HDCP_AKE_RTX_BYTE_LEN];
+ uint8_t rn[HDCP_AKE_RTX_BYTE_LEN];
+ uint8_t riv[HDCP_AKE_RTX_BYTE_LEN];
+ uint8_t lsb16_hmac[HDCP_HMAC_SHA256_LEN / 2];
+
+ /* session key */
+ uint8_t str_ctr[HDCP_STR_CTR_LEN];
+ uint8_t input_ctr[HDCP_INPUT_CTR_LEN];
+
+ /* receiver list */
+ struct hdcp_rpauth_info rpauth_info;
+
+ /* stream manage info */
+ union stream_manage strm;
+
+ /* repeater reauth request */
+ uint8_t rp_reauth;
+
+ /* todo: move stream_ctrl */
+ struct contents_info stream_ctrl;
+
+ int share_skey;
+ uint32_t seq_num_M;
+ uint8_t strmsg[HDCP_TX_REPEATER_MAX_STREAM * 8];
+ size_t strmsg_len;
+};
+
+struct hdcp_rx_ctx {
+ uint8_t version;
+ uint8_t lc_precomp;
+ uint8_t repeater;
+ uint8_t caps[HDCP_CAPS_BYTE_LEN]; /* only for DP */
+ uint8_t receiver_id[RECEIVER_ID_BYTE_LEN];
+ uint8_t rrx[HDCP_AKE_RTX_BYTE_LEN];
+ uint8_t cert[HDCP_RX_CERT_LEN];
+};
+
+int cap_protocol_msg(uint8_t msg_id,
+ uint8_t *msg,
+ size_t *msg_len,
+ uint32_t lk_type,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+
+int decap_protocol_msg(uint8_t msg_id,
+ uint8_t *msg,
+ size_t msg_len,
+ uint32_t lk_type,
+ struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx);
+
+int ake_find_masterkey(int *found_km,
+ uint8_t *ekh_mkey, size_t ekh_mkey_len,
+ uint8_t *m, size_t m_len);
+
+#define check_received_msg(m, m_len, len, func_id) \
+ ((m == NULL) ? ERR_WRONG_BUFFER : \
+ ((m_len < len) ? ERR_WRONG_MESSAGE_LENGTH : \
+ ((m[0] != func_id) ? ERR_WRONG_MESSAGE_ID : 0)))
+
+#endif
+
+int ake_verify_cert(uint8_t *cert, size_t cert_len,
+ uint8_t *rrx, size_t rrx_len,
+ uint8_t *rx_caps, size_t rx_caps_len);
+int ake_generate_masterkey(uint32_t lk_type,
+ uint8_t *enc_mkey, size_t elen);
+int ake_make_hmac(uint8_t *whmac, uint8_t *wrap_mkey,
+ uint8_t *rtx, uint8_t repeater,
+ uint8_t *hmac_append);
+int ake_make_hmac_with_caps(uint8_t *whmac, uint8_t *wrap_mkey,
+ uint8_t *rtx, uint8_t *rrx,
+ uint8_t *tx_caps, uint8_t *rx_caps);
+int ake_compare_hmac(uint8_t *rx_hmac, size_t rx_hmac_len);
+int ake_store_master_key(uint8_t *ekh_mkey, size_t ekh_mkey_len);
+
+int lc_make_hmac(struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx, uint32_t lk_type);
+int lc_generate_rn(uint8_t *out, size_t out_len);
+int lc_compare_hmac(uint8_t *rx_hmac, size_t hmac_len);
+
+int ske_generate_riv(uint8_t *out);
+int ske_generate_sessionkey(uint32_t lk_type, uint8_t *enc_skey,
+ int share_skey);
--- /dev/null
+/*
+ * drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-tx-session.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/slab.h>
+
+#include "exynos-hdcp2.h"
+#include "exynos-hdcp2-log.h"
+
+/**
+ * generate data for a session data
+ */
+
+struct hdcp_session_data *hdcp_session_data_create(void)
+{
+ struct hdcp_session_data *new_ss_data = NULL;
+ static int count = 0; /* TODO change session id creation method */
+
+ new_ss_data = (struct hdcp_session_data *)kzalloc(sizeof(struct hdcp_session_data), GFP_KERNEL);
+ if (!new_ss_data) {
+ return NULL;
+ }
+
+ /* init session data */
+ new_ss_data->id = count++;
+
+ new_ss_data->wrap_skey_store = WRAP_SKEY_EMPTY;
+ memset(new_ss_data->riv, 0x00, sizeof(new_ss_data->riv));
+ hdcp_link_list_init(&(new_ss_data->ln));
+
+ new_ss_data->state = SESS_ST_INIT;
+
+ return new_ss_data;
+}
+
+/**
+ * destroy a session data
+ */
+void hdcp_session_data_destroy(struct hdcp_session_data **ss_data)
+{
+ if (!(*ss_data) || !ss_data)
+ return;
+
+ /* clear session key and riv */
+ memset((*ss_data)->wrap_skey, 0x00, sizeof((*ss_data)->wrap_skey));
+ memset((*ss_data)->riv, 0x00, sizeof((*ss_data)->riv));
+ /* clear link list */
+ hdcp_link_list_destroy(&((*ss_data)->ln));
+
+ if (*ss_data) {
+ kfree(*ss_data);
+ *ss_data = NULL;
+ }
+}
+
+/**
+ * generate data for a link data
+ */
+struct hdcp_link_data *hdcp_link_data_create(void)
+{
+ struct hdcp_link_data *new_lk_data = NULL;
+ static int count = 0; /* TODO: change link id creation method */
+
+ new_lk_data = (struct hdcp_link_data *)kzalloc(sizeof(struct hdcp_link_data), GFP_KERNEL);
+ if (!new_lk_data) {
+ return NULL;
+ }
+
+ /* init link data */
+ new_lk_data->id = count++;
+ new_lk_data->state = LINK_ST_INIT;
+
+ /* set HDCP version */
+#ifdef HDCP_TX_VERSION_2_2
+ new_lk_data->tx_ctx.version = HDCP_VERSION_2_2;
+#endif
+
+ return new_lk_data;
+}
+
+/**
+ * destroy a link data
+ */
+void hdcp_link_data_destroy(struct hdcp_link_data **lk_data)
+{
+ if (!(*lk_data) || !lk_data)
+ return;
+
+ (*lk_data)->ss_ptr = NULL;
+
+ if (*lk_data) {
+ kfree(*lk_data);
+ *lk_data = NULL;
+ }
+}
+
+/**
+ * init a Session list
+ * @ss_list: list head to add it after
+ */
+void hdcp_session_list_init(struct hdcp_session_list *ss_list)
+{
+ struct hdcp_session_node *ss_head;
+
+ if (!ss_list)
+ return;
+
+ /* hdcp session list mutex init */
+ mutex_init(&ss_list->ss_mutex);
+
+ ss_head = &(ss_list->hdcp_session_head);
+ ss_head->next = ss_head;
+ ss_head->prev = ss_head;
+ ss_head->ss_data = NULL;
+}
+
+/**
+ * add a new entry to the Session list
+ * @new_ent: new entry to be added
+ * @ss_list: list head to add it after
+ *
+ * Insert a new entry after the specified head
+ */
+void hdcp_session_list_add(struct hdcp_session_node *new_ent, struct hdcp_session_list *ss_list)
+{
+ struct hdcp_session_node *ss_head;
+
+ if (!new_ent || !ss_list)
+ return;
+
+ mutex_lock(&(ss_list->ss_mutex));
+ ss_head = &(ss_list->hdcp_session_head);
+
+ ss_head->next->prev = new_ent;
+ new_ent->next = ss_head->next;
+
+ new_ent->prev = ss_head;
+ ss_head->next = new_ent;
+ mutex_unlock(&(ss_list->ss_mutex));
+
+ return;
+
+}
+
+/**
+ * delete a entry form the Session list
+ * @del_ent: a entry to be deleted
+ * @ss_list: session list to remove the session node
+ */
+void hdcp_session_list_del(struct hdcp_session_node *del_ent, struct hdcp_session_list *ss_list)
+{
+ if (!del_ent || !ss_list)
+ return;
+
+ mutex_lock(&ss_list->ss_mutex);
+ del_ent->prev->next = del_ent->next;
+ del_ent->next->prev = del_ent->prev;
+ mutex_unlock(&ss_list->ss_mutex);
+}
+
+/**
+ * print all entries in the Session list
+ * @ss_list: session list to print all nodes
+ */
+void hdcp_session_list_print_all(struct hdcp_session_list *ss_list)
+{
+ struct hdcp_session_node *pos;
+ struct hdcp_session_node *ss_head;
+
+ if (!ss_list)
+ return;
+
+ mutex_lock(&ss_list->ss_mutex);
+ ss_head = &(ss_list->hdcp_session_head);
+ for (pos = ss_head->next; pos != ss_head && pos != NULL; pos = pos->next)
+ hdcp_info("SessionID: %d\n", pos->ss_data->id);
+ mutex_unlock(&ss_list->ss_mutex);
+}
+
+/**
+ * Find an entry from the Session list
+ * @id: session id to find session node
+ * @ss_list: session list contain the session node
+ */
+struct hdcp_session_node *hdcp_session_list_find(uint32_t id, struct hdcp_session_list *ss_list)
+{
+ struct hdcp_session_node *pos;
+ struct hdcp_session_node *ss_head;
+
+
+ if (!ss_list)
+ return NULL;
+
+ mutex_lock(&ss_list->ss_mutex);
+ ss_head = &ss_list->hdcp_session_head;
+ for (pos = ss_head->next; pos != ss_head && pos != NULL; pos = pos->next) {
+ if (pos->ss_data->id == id) {
+ mutex_unlock(&ss_list->ss_mutex);
+ return pos;
+ }
+ }
+ mutex_unlock(&ss_list->ss_mutex);
+
+ return NULL;
+}
+
+/**
+ * close all links in the session and remove all session nodes
+ * @ss_list: session list to remove all
+ */
+void hdcp_session_list_destroy(struct hdcp_session_list *ss_list)
+{
+ struct hdcp_session_node *pos;
+ struct hdcp_session_node *ss_head;
+
+ if (!ss_list)
+ return;
+
+ mutex_lock(&ss_list->ss_mutex);
+ ss_head = &ss_list->hdcp_session_head;
+ for (pos = ss_head->next; pos != ss_head && pos != NULL;) {
+ if (pos) {
+ /* remove session node from the list*/
+ pos->prev->next = pos->next;
+ pos->next->prev = pos->prev;
+
+ /* remove session data */
+ /* TODO : remove all links */
+ hdcp_session_data_destroy(&pos->ss_data);
+ if (pos)
+ kfree(pos);
+ pos = ss_head->next;
+ }
+ }
+ ss_head->next = ss_head;
+ ss_head->prev = ss_head;
+ mutex_unlock(&ss_list->ss_mutex);
+}
+
+/**
+ * init a Link list
+ * @lk_list: list head to add it after
+ */
+void hdcp_link_list_init(struct hdcp_link_list *lk_list)
+{
+ struct hdcp_link_node *lk_head;
+
+ if (!lk_list)
+ return;
+
+ /* initialize link list mutex */
+ mutex_init(&lk_list->lk_mutex);
+
+ mutex_lock(&lk_list->lk_mutex);
+ lk_head = &(lk_list->hdcp_link_head);
+ lk_head->next = lk_head;
+ lk_head->prev = lk_head;
+ lk_head->lk_data = NULL;
+ mutex_unlock(&lk_list->lk_mutex);
+}
+
+/**
+ * add a new entry to the Link list
+ * @new_ent: new entry to be added
+ * @ss_list: list head to add it after
+ *
+ * Insert a new entry after the specified head
+ */
+void hdcp_link_list_add(struct hdcp_link_node *new_ent, struct hdcp_link_list *lk_list)
+{
+ struct hdcp_link_node *lk_head;
+
+ if (!new_ent || !lk_list)
+ return;
+
+ mutex_lock(&lk_list->lk_mutex);
+ lk_head = &(lk_list->hdcp_link_head);
+ lk_head->next->prev = new_ent;
+ new_ent->next = lk_head->next;
+ new_ent->prev = lk_head;
+ lk_head->next = new_ent;
+ mutex_unlock(&lk_list->lk_mutex);
+}
+
+/**
+ * delete a entry form the Link list
+ * @del_ent: a entry to be deleted
+ * @ss_list: session list to remove the session node
+ */
+void hdcp_link_list_del(struct hdcp_link_node *del_ent, struct hdcp_link_list *lk_list)
+{
+ if (!del_ent || !lk_list)
+ return;
+
+ mutex_lock(&lk_list->lk_mutex);
+ del_ent->prev->next = del_ent->next;
+ del_ent->next->prev = del_ent->prev;
+ mutex_unlock(&lk_list->lk_mutex);
+}
+
+/**
+ * print all entries in the Link list
+ * @ss_list: session list to print all nodes
+ */
+void hdcp_link_list_print_all(struct hdcp_link_list *lk_list)
+{
+ struct hdcp_link_node *pos;
+ struct hdcp_link_node *lk_head;
+
+ if (!lk_list)
+ return;
+
+ mutex_lock(&lk_list->lk_mutex);
+ lk_head = &lk_list->hdcp_link_head;
+ for (pos = lk_head->next; pos != lk_head && pos != NULL; pos = pos->next)
+ hdcp_info("Link: %d\n", pos->lk_data->id);
+ mutex_unlock(&lk_list->lk_mutex);
+}
+
+/**
+ * Find an entry from the Link list
+ * @id: Link handle to find link node
+ * @lk_list: link list contain the link node
+ */
+struct hdcp_link_node *hdcp_link_list_find(uint32_t id, struct hdcp_link_list *lk_list)
+{
+ struct hdcp_link_node *pos;
+ struct hdcp_link_node *lk_head;
+
+ if (!lk_list)
+ return NULL;
+
+ mutex_lock(&lk_list->lk_mutex);
+ lk_head = &lk_list->hdcp_link_head;
+ for (pos = lk_head->next; pos != lk_head && pos != NULL; pos = pos->next) {
+ if (pos->lk_data->id == id) {
+ mutex_unlock(&lk_list->lk_mutex);
+ return pos;
+ }
+ }
+ mutex_unlock(&lk_list->lk_mutex);
+ return NULL;
+}
+
+/**
+ * close all Links and remove all Link nodes
+ * @ss_list: session list to remove all
+ */
+void hdcp_link_list_destroy(struct hdcp_link_list *lk_list)
+{
+ struct hdcp_link_node *pos;
+ struct hdcp_link_node *lk_head;
+
+ if (!lk_list)
+ return;
+
+ mutex_lock(&lk_list->lk_mutex);
+ lk_head = &(lk_list->hdcp_link_head);
+ for (pos = lk_head->next; pos != lk_head && pos != NULL;) {
+ /* remove link node from the list*/
+ pos->prev->next = pos->next;
+ pos->next->prev = pos->prev;
+
+ /* remove link data */
+ /* TODO : remove all data */
+ if (pos)
+ kfree(pos);
+ pos = lk_head->next;
+ }
+ lk_head->next = lk_head;
+ lk_head->prev = lk_head;
+ mutex_unlock(&lk_list->lk_mutex);
+}
--- /dev/null
+/*
+ * drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-tx-session.h
+ *
+ * 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.
+ */
+#ifndef __HDCP_TX_SESSION_H__
+#define __HDCP_TX_SESSION_H__
+
+#include "exynos-hdcp2-protocol-msg.h"
+
+#define WRAP_SKEY_EMPTY 0
+#define WRAP_SKEY_STORED 1
+
+#define HDCP_WITHOUT_STORED_KM 0
+#define HDCP_WITH_STORED_KM 1
+
+#define MAX_IP_LEN 15 /* IP address format is "xxx.xxx.xxx.xxx" */
+#define RECEIVER_ID_BYTE_LEN (40 / 8)
+#define HDCP_PRIVATE_DATA_LEN 16
+#define HDCP_WRAPPED_HMAC_LEN 124
+#define REPEATER 1
+#define NO_RECEIVER 0
+
+
+/**
+ * HDCP Link state & data structure
+ */
+typedef enum hdcp_tx_hdcp_link_state {
+ LINK_ST_INIT = 0,
+ LINK_ST_H0_NO_RX_ATTATCHED,
+ LINK_ST_H1_TX_LOW_VALUE_CONTENT,
+ LINK_ST_A0_DETERMINE_RX_HDCP_CAP,
+ LINK_ST_A1_EXCHANGE_MASTER_KEY,
+ LINK_ST_A2_LOCALITY_CHECK,
+ LINK_ST_A3_EXCHANGE_SESSION_KEY,
+ LINK_ST_A4_TEST_REPEATER,
+ LINK_ST_A5_AUTHENTICATED,
+ LINK_ST_A6_WAIT_RECEIVER_ID_LIST,
+ LINK_ST_A7_VERIFY_RECEIVER_ID_LIST,
+ LINK_ST_A8_SEND_RECEIVER_ID_LIST_ACK,
+ LINK_ST_A9_CONTENT_STREAM_MGT,
+ LINK_ST_END
+} hdcp_tx_hdcp_link_state;
+
+struct hdcp_session_node {
+ struct hdcp_session_data *ss_data;
+ struct hdcp_session_node *next;
+ struct hdcp_session_node *prev;
+};
+
+struct hdcp_session_list {
+ struct hdcp_session_node hdcp_session_head;
+ struct mutex ss_mutex;
+};
+
+struct hdcp_timer {
+ struct timeval start;
+ struct timeval end;
+ uint32_t timeout; /* millisecond */
+ uint32_t elapsed_time; /* millisecond */
+};
+
+struct hdcp_link_data {
+ uint32_t id;
+ uint32_t state;
+ uint8_t stored_km;
+ uint32_t errno; /* error code */
+ uint32_t lk_type; /* link type */
+ struct hdcp_tx_ctx tx_ctx; /* Transmitter context data */
+ struct hdcp_rx_ctx rx_ctx; /* Receiver context data */
+ struct hdcp_timer timer; /* to check timeout */
+ struct hdcp_session_node *ss_ptr; /* session pointer link belong */
+};
+
+struct hdcp_link_node {
+ struct hdcp_link_data *lk_data;
+ struct hdcp_link_node *next;
+ struct hdcp_link_node *prev;
+};
+
+struct hdcp_link_list {
+ struct hdcp_link_node hdcp_link_head;
+ struct mutex lk_mutex;
+};
+
+/**
+ * HDCP Session status & data structure
+ */
+typedef enum hdcp_tx_ss_state {
+ SESS_ST_INIT = 0,
+ SESS_ST_LINK_SETUP,
+ SESS_ST_END
+} hdcp_tx_ss_state;
+
+struct hdcp_session_data {
+ uint32_t id;
+ hdcp_tx_ss_state state;
+ uint8_t wrap_skey_store;
+ uint8_t riv[HDCP_AKE_RTX_BYTE_LEN];
+ uint8_t wrap_skey[HDCP_AKE_WKEY_BYTE_LEN];
+ struct hdcp_link_list ln;
+};
+
+struct hdcp_session_data *hdcp_session_data_create(void);
+void hdcp_session_data_destroy(struct hdcp_session_data **ss_data);
+struct hdcp_link_data *hdcp_link_data_create(void);
+void hdcp_link_data_destroy(struct hdcp_link_data **lk_data);
+
+/* Session list APIs */
+void hdcp_session_list_init(struct hdcp_session_list *ss_list);
+void hdcp_session_list_add(struct hdcp_session_node *new_ent, struct hdcp_session_list *ss_list);
+void hdcp_session_list_del(struct hdcp_session_node *del_ent, struct hdcp_session_list *ss_list);
+void hdcp_session_list_print_all(struct hdcp_session_list *ss_list);
+void hdcp_session_list_destroy(struct hdcp_session_list *ss_list);
+struct hdcp_session_node *hdcp_session_list_find(uint32_t id, struct hdcp_session_list *ss_list);
+
+/* Link list APIs */
+void hdcp_link_list_init(struct hdcp_link_list *lk_list);
+void hdcp_link_list_add(struct hdcp_link_node *new_ent, struct hdcp_link_list *lk_list);
+void hdcp_link_list_del(struct hdcp_link_node *del_ent, struct hdcp_link_list *lk_list);
+void hdcp_link_list_print_all(struct hdcp_link_list *lk_list);
+void hdcp_link_list_destroy(struct hdcp_link_list *lk_list);
+struct hdcp_link_node *hdcp_link_list_find(uint32_t id, struct hdcp_link_list *lk_list);
+#endif
+
--- /dev/null
+/*
+ * drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-teeif.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/smc.h>
+#include <linux/slab.h>
+#include <asm/cacheflush.h>
+
+#include "exynos-hdcp2-teeif.h"
+#include "exynos-hdcp2.h"
+#include "exynos-hdcp2-log.h"
+
+extern void __inval_cache_range(const void *start, const void *end);
+
+static struct hci_ctx hctx = {
+ .msg = NULL,
+ .state = HCI_DISCONNECTED
+};
+
+int hdcp_tee_open(void)
+{
+ int ret = 0;
+ u64 phys_addr = 0;
+
+ if (hctx.state == HCI_CONNECTED) {
+ hdcp_info("HCI is already connected\n");
+ return 0;
+ }
+
+ /* Allocate WSM for HDCP commnad interface */
+ hctx.msg = (struct hci_message *)kzalloc(sizeof(struct hci_message), GFP_KERNEL);
+ if (!hctx.msg) {
+ hdcp_err("alloc wsm for HDCP SWd is failed\n");
+ return -ENOMEM;
+ }
+
+ /* send WSM address to SWd */
+ phys_addr = virt_to_phys((void *)hctx.msg);
+ ret = exynos_smc(SMC_HDCP_INIT, phys_addr, sizeof(struct hci_message), 0);
+ if (ret) {
+ hdcp_err("Fail to set up connection with SWd. ret(%d)\n", ret);
+ kfree(hctx.msg);
+ hctx.msg = NULL;
+ return -ECONNREFUSED;
+ }
+
+ hctx.state = HCI_CONNECTED;
+
+ return 0;
+}
+
+int hdcp_tee_close()
+{
+ int ret;
+
+ if (hctx.state == HCI_DISCONNECTED) {
+ hdcp_info("HCI is already disconnected\n");
+ return 0;
+ }
+
+ if (hctx.msg) {
+ kfree(hctx.msg);
+ hctx.msg = NULL;
+ }
+
+ /* send terminate command to SWd */
+ ret = exynos_smc(SMC_HDCP_TERMINATE, 0, 0, 0);
+ if (ret) {
+ hdcp_err("HDCP: Fail to set up connection with SWd. ret(%d)\n", ret);
+ return -EFAULT;
+ }
+
+ hctx.state = HCI_DISCONNECTED;
+
+ return 0;
+}
+
+int hdcp_tee_comm(struct hci_message *hci)
+{
+ int ret;
+
+ if (!hci)
+ return -EINVAL;
+
+ /**
+ * kernel & TEE does not share cache.
+ * So, cache should be flushed before sending data to TEE
+ * and invalidate after come back to kernel
+ */
+ __flush_dcache_area((void *)hci, sizeof(struct hci_message));
+ ret = exynos_smc(SMC_HDCP_PROT_MSG, 0, 0, 0);
+ __inval_cache_range((void *)hci, (void *)((uint8_t *)hci + sizeof(struct hci_message)));
+
+ if (ret) {
+ hdcp_info("SWd returned(%x)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int teei_gen_rtx(uint32_t lk_type,
+ uint8_t *rtx, size_t rtx_len,
+ uint8_t *caps, uint32_t caps_len)
+{
+ int ret = 0;
+ struct hci_message *hci = hctx.msg;
+
+ /* todo: input check */
+
+ /* Update TCI buffer */
+ hci->cmd_id = HDCP_TEEI_GEN_RTX;
+ hci->genrtx.lk_type = lk_type;
+ hci->genrtx.len = rtx_len;
+
+ if ((ret = hdcp_tee_comm(hci)) < 0)
+ return ret;
+
+ /* check returned message from SWD */
+ if (rtx && rtx_len)
+ memcpy(rtx, hci->genrtx.rtx, rtx_len);
+ if (caps && caps_len)
+ memcpy(caps, hci->genrtx.tx_caps, caps_len);
+
+ return ret;
+}
+
+int teei_get_txinfo(uint8_t *version, size_t version_len,
+ uint8_t *caps_mask, uint32_t caps_mask_len)
+{
+ int ret = 0;
+ struct hci_message *hci = hctx.msg;
+
+ /* todo: input check */
+
+ /* Update TCI buffer */
+ hci->cmd_id = HDCP_TEEI_GET_TXINFO;
+
+ /* send command to swd */
+ if ((ret = hdcp_tee_comm(hci)) < 0)
+ return ret;
+
+ /* check returned message from SWD */
+ memcpy(version, hci->gettxinfo.version, version_len);
+ memcpy(caps_mask, hci->gettxinfo.caps_mask, caps_mask_len);
+
+ return ret;
+}
+
+int teei_set_rxinfo(uint8_t *version, size_t version_len,
+ uint8_t *caps_mask, uint32_t caps_mask_len)
+{
+ int ret = 0;
+ struct hci_message *hci = hctx.msg;
+
+ /* todo: input check */
+
+ /* Update TCI buffer */
+ hci->cmd_id = HDCP_TEEI_SET_RXINFO;
+ memcpy(hci->setrxinfo.version, version, version_len);
+ memcpy(hci->setrxinfo.caps_mask, caps_mask, caps_mask_len);
+
+ /* send command to swd */
+ if ((ret = hdcp_tee_comm(hci)) < 0)
+ return ret;
+
+ return ret;
+}
+
+int teei_verify_cert(uint8_t *cert, size_t cert_len,
+ uint8_t *rrx, size_t rrx_len,
+ uint8_t *rx_caps, size_t rx_caps_len)
+{
+ int ret = 0;
+ struct hci_message *hci = hctx.msg;
+ /* todo: input check */
+
+ /* Update TCI buffer */
+ hci->cmd_id = HDCP_TEEI_VERIFY_CERT;
+ hci->vfcert.len = cert_len;
+ memcpy(hci->vfcert.cert, cert, cert_len);
+ if (rrx && rrx_len)
+ memcpy(hci->vfcert.rrx, rrx, rrx_len);
+ if (rx_caps && rx_caps_len)
+ memcpy(hci->vfcert.rx_caps, rx_caps, rx_caps_len);
+
+ if ((ret = hdcp_tee_comm(hci)) < 0)
+ return ret;
+
+ /* return verification result */
+ return ret;
+}
+
+int teei_generate_master_key(uint32_t lk_type, uint8_t *emkey, size_t emkey_len)
+{
+ int ret = 0;
+ struct hci_message *hci = hctx.msg;
+ /* todo: input check */
+
+ /* Update TCI buffer */
+ hci->cmd_id = HDCP_TEEI_GEN_MKEY;
+ hci->genmkey.lk_type = lk_type;
+ hci->genmkey.emkey_len = emkey_len;
+
+ if ((ret = hdcp_tee_comm(hci)) < 0)
+ return ret;
+
+ /* copy encrypted mkey & wrapped mkey to hdcp ctx */
+ memcpy(emkey, hci->genmkey.emkey, hci->genmkey.emkey_len);
+
+ /* check returned message from SWD */
+
+ return 0;
+}
+
+int teei_set_rrx(uint8_t *rrx, size_t rrx_len)
+{
+ int ret = 0;
+ struct hci_message *hci = hctx.msg;
+
+ /* todo: input check */
+
+ /* Update TCI buffer */
+ hci->cmd_id = HDCP_TEEI_SET_RRX;
+ memcpy(hci->setrrx.rrx, rrx, rrx_len);
+
+ /* send command to swd */
+ if ((ret = hdcp_tee_comm(hci)) < 0)
+ return ret;
+
+ return ret;
+}
+
+int teei_compare_ake_hmac(uint8_t *rx_hmac, size_t rx_hmac_len)
+{
+ int ret = 0;
+ struct hci_message *hci = hctx.msg;
+ /* todo: input check */
+
+ /* Update TCI buffer */
+ hci->cmd_id = HDCP_TEEI_COMPARE_AKE_HMAC;
+ hci->comphmac.rx_hmac_len = rx_hmac_len;
+ memcpy(hci->comphmac.rx_hmac, rx_hmac, rx_hmac_len);
+
+ if ((ret = hdcp_tee_comm(hci)) < 0)
+ return ret;
+
+ return ret;
+}
+
+int teei_set_pairing_info(uint8_t *ekh_mkey, size_t ekh_mkey_len)
+{
+ int ret = 0;
+ struct hci_message *hci = hctx.msg;
+
+ /* todo: input check */
+
+ /* Update TCI buffer */
+ hci->cmd_id = HDCP_TEEI_SET_PAIRING_INFO;
+ memcpy(hci->setpairing.ekh_mkey, ekh_mkey, ekh_mkey_len);
+
+ /* send command to swd */
+ if ((ret = hdcp_tee_comm(hci)) < 0)
+ return ret;
+
+ return ret;
+}
+
+int teei_get_pairing_info(uint8_t *ekh_mkey, size_t ekh_mkey_len,
+ uint8_t *m, size_t m_len)
+{
+ int ret = 0;
+ struct hci_message *hci = hctx.msg;
+
+ /* todo: input check */
+
+ /* Update TCI buffer */
+ hci->cmd_id = HDCP_TEEI_GET_PAIRING_INFO;
+
+ /* send command to swd */
+ if ((ret = hdcp_tee_comm(hci)) < 0)
+ return ret;
+
+ memcpy(ekh_mkey, hci->getpairing.ekh_mkey, ekh_mkey_len);
+ memcpy(m, hci->getpairing.m, m_len);
+
+ return ret;
+}
+
+int teei_gen_rn(uint8_t *out, size_t len)
+{
+ int ret = 0;
+ struct hci_message *hci = hctx.msg;
+
+ /* todo: input check */
+
+ /* Update TCI buffer */
+ hci->cmd_id = HDCP_TEEI_GEN_RN;
+ hci->genrn.len = len;
+
+ if ((ret = hdcp_tee_comm(hci)) < 0)
+ return ret;
+
+ /* check returned message from SWD */
+
+ memcpy(out, hci->genrn.rn, len);
+
+ return ret;
+}
+
+int teei_gen_lc_hmac(uint32_t lk_type, uint8_t *lsb16_hmac)
+{
+ int ret = 0;
+ struct hci_message *hci = hctx.msg;
+ /* todo: input check */
+
+ /* Update TCI buffer */
+ hci->cmd_id = HDCP_TEEI_GEN_LC_HMAC;
+ hci->genlchmac.lk_type = lk_type;
+ if ((ret = hdcp_tee_comm(hci)) < 0)
+ return ret;
+
+ /* Send LSB 16bytes to Rx */
+ if (lsb16_hmac)
+ memcpy(lsb16_hmac, hci->genlchmac.lsb16_hmac, (HDCP_HMAC_SHA256_LEN / 2));
+
+ /* todo: check returned message from SWD */
+
+ return 0;
+}
+
+int teei_compare_lc_hmac(uint8_t *rx_hmac, size_t rx_hmac_len)
+{
+ int ret = 0;
+ struct hci_message *hci = hctx.msg;
+ /* todo: input check */
+
+ /* Update TCI buffer */
+ hci->cmd_id = HDCP_TEEI_COMPARE_LC_HMAC;
+ hci->complchmac.rx_hmac_len = rx_hmac_len;
+ memcpy(hci->complchmac.rx_hmac, rx_hmac, rx_hmac_len);
+
+ if ((ret = hdcp_tee_comm(hci)) < 0)
+ return ret;
+
+ return ret;
+}
+
+int teei_generate_riv(uint8_t *out, size_t len)
+{
+ int ret = 0;
+ struct hci_message *hci = hctx.msg;
+
+ /* todo: input check */
+
+ /* Update TCI buffer */
+ hci->cmd_id = HDCP_TEEI_GEN_RIV;
+ hci->genriv.len = len;
+
+ if ((ret = hdcp_tee_comm(hci)) < 0)
+ return ret;
+
+ memcpy(out, hci->genriv.riv, len);
+
+ /* todo: check returned message from SWD */
+
+ return ret;
+}
+
+int teei_generate_skey(uint32_t lk_type,
+ uint8_t *eskey, size_t eskey_len,
+ int share_skey)
+{
+ int ret = 0;
+ struct hci_message *hci = hctx.msg;
+ /* todo: input check */
+
+ /* Update TCI buffer */
+ hci->cmd_id = HDCP_TEEI_GEN_SKEY;
+ hci->genskey.lk_type = lk_type;
+ hci->genskey.eskey_len = eskey_len;
+ hci->genskey.share_skey = share_skey;
+
+ if ((ret = hdcp_tee_comm(hci)) < 0)
+ return ret;
+
+ /* copy encrypted mkey & wrapped mkey to hdcp ctx */
+ memcpy(eskey, hci->genskey.eskey, hci->genskey.eskey_len);
+
+ /* todo: check returned message from SWD */
+
+ return 0;
+}
+
+int teei_encrypt_packet(uint8_t *input, size_t input_len,
+ uint8_t *output, size_t output_len,
+ uint8_t *str_ctr, size_t str_ctr_len,
+ uint8_t *input_ctr, size_t input_ctr_len)
+{
+ int ret = 0;
+ struct hci_message *hci = hctx.msg;
+ /* todo: input check */
+
+ /* Update TCI buffer */
+ hci->cmd_id = HDCP_TEEI_ENC_PACKET;
+ hci->encpacket.input_len = input_len;
+ hci->encpacket.output_len = output_len;
+ hci->encpacket.input_addr = (uint64_t)input;
+ hci->encpacket.output_addr = (uint64_t)output;
+ memcpy(hci->encpacket.str_ctr, str_ctr, str_ctr_len);
+ memcpy(hci->encpacket.input_ctr, input_ctr, input_ctr_len);
+
+ hdcp_debug("teeif command(%x)\n", hci->cmd_id);
+ hdcp_debug("input(%llx), output(%llx)\n", hci->encpacket.input_addr, hci->encpacket.output_addr);
+
+ if ((ret = hdcp_tee_comm(hci)) < 0)
+ return ret;
+
+ return 0;
+}
+
+int teei_set_rcvlist_info(uint8_t *rx_info,
+ uint8_t *seq_num_v,
+ uint8_t *v_prime,
+ uint8_t *rcvid_list,
+ uint8_t *v,
+ uint8_t *valid)
+{
+ int ret = 0;
+ struct hci_message *hci = hctx.msg;
+ /* todo: input check */
+
+ hci->cmd_id = HDCP_TEEI_SET_RCV_ID_LIST;
+
+ memcpy(hci->setrcvlist.rcvid_lst, rcvid_list, HDCP_RP_RCVID_LIST_LEN);
+ memcpy(hci->setrcvlist.v_prime, v_prime, HDCP_RP_HMAC_V_LEN / 2);
+ /* Only used DP */
+ if (rx_info != NULL && seq_num_v != NULL) {
+ memcpy(hci->setrcvlist.rx_info, rx_info, HDCP_RP_RX_INFO_LEN);
+ memcpy(hci->setrcvlist.seq_num_v, seq_num_v, HDCP_RP_SEQ_NUM_V_LEN);
+ }
+
+
+ ret = hdcp_tee_comm(hci);
+ if (ret != 0) {
+ *valid = 1;
+ return ret;
+ }
+ memcpy(v, hci->setrcvlist.v, HDCP_RP_HMAC_V_LEN / 2);
+ *valid = 0;
+
+ return 0;
+}
+
+int teei_gen_stream_manage(uint16_t stream_num,
+ uint8_t *streamid,
+ uint8_t *seq_num_m,
+ uint8_t *k,
+ uint8_t *streamid_type)
+{
+ int ret = 0;
+ struct hci_message *hci = hctx.msg;
+ /* todo: input check */
+
+ /* Update TCI buffer */
+
+ hci->cmd_id = HDCP_TEEI_GEN_STREAM_MANAGE;
+ hci->genstrminfo.stream_num = stream_num;
+ memcpy(hci->genstrminfo.streamid, streamid, sizeof(uint8_t) * stream_num);
+
+ if ((ret = hdcp_tee_comm(hci)) < 0)
+ return ret;
+
+ memcpy(seq_num_m, hci->genstrminfo.seq_num_m, HDCP_RP_SEQ_NUM_M_LEN);
+ memcpy(k, hci->genstrminfo.k, HDCP_RP_K_LEN);
+ memcpy(streamid_type, hci->genstrminfo.streamid_type, HDCP_RP_STREAMID_TYPE_LEN);
+
+ /* check returned message from SWD */
+
+ /* return verification result */
+ return ret;
+}
+
+int teei_verify_m_prime(uint8_t *m_prime, uint8_t *input, size_t input_len)
+{
+ int ret = 0;
+ struct hci_message *hci = hctx.msg;
+
+ hci->cmd_id = HDCP_TEEI_VERIFY_M_PRIME;
+ memcpy(hci->verifymprime.m_prime, m_prime, HDCP_RP_HMAC_M_LEN);
+ if (input && input_len < sizeof(hci->verifymprime.strmsg)) {
+ memcpy(hci->verifymprime.strmsg, input, input_len);
+ hci->verifymprime.str_len = input_len;
+ }
+
+ ret = hdcp_tee_comm(hci);
+
+ return ret;
+}
+
+int teei_wrapped_key(uint8_t *key, uint32_t wrapped, uint32_t key_len)
+{
+ int ret = 0;
+ struct hci_message *hci = hctx.msg;
+
+ hci->cmd_id = HDCP_TEEI_WRAP_KEY;
+
+ if (key_len > (sizeof(hci->wrap_key.enc_key) - HDCP_WRAP_AUTH_TAG)) {
+ hdcp_err("(un)wraaping key size is wrong. 0x%x\n", key_len);
+ return HDCP_ERROR_WRONG_SIZE;
+ }
+
+ if (key_len < HDCP_WRAP_AUTH_TAG || key_len > HDCP_WRAP_MAX_SIZE - HDCP_WRAP_AUTH_TAG)
+ return HDCP_ERROR_WRONG_SIZE;
+
+ if (wrapped == UNWRAP)
+ memcpy(hci->wrap_key.enc_key, key, key_len + HDCP_WRAP_AUTH_TAG);
+ else
+ memcpy(hci->wrap_key.key, key, key_len);
+
+ hci->wrap_key.wrapped = wrapped;
+ hci->wrap_key.key_len = key_len;
+
+ if ((ret = hdcp_tee_comm(hci)) < 0)
+ return ret;
+
+ if (hci->wrap_key.wrapped == WRAP) {
+ memcpy(key, hci->wrap_key.enc_key, key_len + HDCP_WRAP_AUTH_TAG);
+ }
+
+ return ret;
+}
--- /dev/null
+/* drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-teeif.h
+ *
+ * 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.
+ */
+#ifndef __EXYNOS_HDCP2_TEEIF_H__
+#define __EXYNOS_HDCP2_TEEIF_H__
+
+/* SMC list for HDCP functions */
+#define SMC_HDCP_INIT ((unsigned int)0x82004010)
+#define SMC_HDCP_TERMINATE ((unsigned int)0x82004011)
+#define SMC_HDCP_PROT_MSG ((unsigned int)0x82004012)
+#define SMC_CHECK_STREAM_TYPE_FALG ((unsigned int)0x82004022)
+
+#define SMC_DRM_HDCP_AUTH_INFO ((unsigned int)0x82002140)
+
+/**
+ * HDCP TEE service commands
+ */
+enum {
+ HDCP_TEEI_GEN_RTX = 0x0,
+ HDCP_TEEI_VERIFY_CERT,
+ HDCP_TEEI_GEN_MKEY,
+ HDCP_TEEI_GEN_AKE_HMAC,
+ HDCP_TEEI_COMPARE_AKE_HMAC,
+ HDCP_TEEI_GEN_RN,
+ HDCP_TEEI_GEN_LC_HMAC,
+ HDCP_TEEI_COMPARE_LC_HMAC,
+ HDCP_TEEI_GEN_RIV,
+ HDCP_TEEI_GEN_SKEY,
+ HDCP_TEEI_ENC_PACKET,
+ HDCP_TEEI_GET_TXINFO,
+ HDCP_TEEI_SET_RXINFO,
+ HDCP_TEEI_SET_RRX,
+ HDCP_TEEI_SET_PAIRING_INFO,
+ HDCP_TEEI_GET_PAIRING_INFO,
+ HDCP_TEEI_SET_RCV_ID_LIST,
+ HDCP_TEEI_GEN_STREAM_MANAGE,
+ HDCP_TEEI_VERIFY_M_PRIME,
+ HDCP_TEEI_WRAP_KEY,
+ HDCP_TEEI_MSG_END
+};
+
+#define HCI_DISCONNECTED 0
+#define HCI_CONNECTED 1
+
+#define HDCP_WSM_SIZE (1024)
+#define AKE_INFO_SIZE (128)
+
+#define HDCP_RX_MODULUS_LEN (1024 / 8)
+#define HDCP_RX_PUB_EXP_LEN (24 / 8)
+#define HDCP_AKE_ENCKEY_BYTE_LEN (1024 / 8)
+#define HDCP_AKE_MKEY_BYTE_LEN (128 / 8)
+#define HDCP_AKE_M_BYTE_LEN HDCP_AKE_MKEY_BYTE_LEN
+#define HDCP_AKE_EKH_MKEY_BYTE_LEN HDCP_AKE_MKEY_BYTE_LEN
+#define HDCP_AKE_RTX_BYTE_LEN (64 / 8)
+#define HDCP_AKE_HMAC_APPEND (6)
+#define HDCP_STR_CTR_LEN (4)
+#define HDCP_INPUT_CTR_LEN (8)
+#define RECEIVER_ID_BYTE_LEN (40 / 8)
+#define HDCP_RRX_BYTE_LEN (64 / 8)
+#define HDCP_RTX_BYTE_LEN HDCP_RRX_BYTE_LEN
+#define HDCP_HMAC_SHA256_LEN (256 / 8)
+#define HDCP_WRAP_APPEND_LEN (92)
+#define HDCP_RX_CERT_LEN (522)
+#define HDCP_AKE_WRAPPED_HMAC_LEN (32)
+#define HDCP_AKE_WKEY_BYTE_LEN (32)
+#define HDCP_SKE_SKEY_LEN (128 / 8)
+#define HDCP_SKE_WSKEY_BYTE_LEN (32)
+#define MKEY_LEN (16)
+#define CERT_LEN (128)
+#define HMAC_LEN (32)
+#define HDCP_RX_CERT_INFO_LEN (138)
+#define HDCP_CERT_SIGLEN (384)
+#define HDCP_RN_BYTE_LEN (64 / 8)
+#define HDCP_RIV_BYTE_LEN (64 / 8)
+#define HDCP_CAPS_BYTE_LEN (3)
+#define HDCP_VERSION_LEN (1)
+#define HDCP_CAPABILITY_MASK_LEN (2)
+#define HDCP_RP_HMAC_V_LEN HDCP_HMAC_SHA256_LEN
+#define HDCP_RP_HMAC_M_LEN HDCP_HMAC_SHA256_LEN
+#define HDCP_RP_RX_INFO_LEN (2)
+#define HDCP_RP_SEQ_NUM_V_LEN (3)
+#define HDCP_RCV_ID_LEN (5)
+#define HDCP_RCV_DEVS_COUNT_MAX (32)
+#define HDCP_RP_RCVID_LIST_LEN (HDCP_RCV_ID_LEN * HDCP_RCV_DEVS_COUNT_MAX)
+#define HDCP_RP_SEQ_NUM_M_LEN (3)
+#define HDCP_RP_K_LEN (2)
+#define HDCP_RP_MAX_STREAMID_NUM (63)
+#define HDCP_RP_TYPE_LEN (1)
+#define HDCP_RP_STREAMID_LEN (1)
+#define HDCP_RP_STREAM_MSG_MAX_LEN (32 * 8)
+#define HDCP_RP_STREAMID_TYPE_LEN (HDCP_RP_STREAMID_LEN + HDCP_RP_TYPE_LEN)
+#define HDCP_RP_MAX_STREAMID_TYPE_LEN (HDCP_RP_STREAMID_TYPE_LEN * HDCP_RP_MAX_STREAMID_NUM)
+#define HDCP_STATIC_KEY (16)
+#define HDCP_WRAP_KEY (16)
+#define HDCP_WRAP_MAX_SIZE (128)
+#define HDCP_WRAP_AUTH_TAG (16)
+#define HDCP_RX_CAPS_LEN (1)
+
+/* TEEI error code */
+enum hdcp_rv_t {
+ HDCP_OK = 0x0000,
+ E_HDCP_PRO_INVALID_RCV_ID = 0x3015,
+};
+
+enum kw_mode {
+ WRAP,
+ UNWRAP,
+};
+
+typedef struct {
+ uint32_t id;
+ uint32_t len;
+ uint32_t lk_type;
+ uint8_t rtx[HDCP_RTX_BYTE_LEN];
+ uint8_t tx_caps[HDCP_CAPS_BYTE_LEN];
+} hci_genrtx_t;
+
+typedef struct {
+ uint32_t id;
+ uint8_t version[HDCP_VERSION_LEN];
+ uint8_t caps_mask[HDCP_CAPABILITY_MASK_LEN];
+} hci_gettxinfo_t;
+
+typedef struct {
+ uint32_t id;
+ uint32_t len;
+ uint8_t cert[HDCP_RX_CERT_LEN];
+ uint8_t rrx[HDCP_RRX_BYTE_LEN];
+ uint8_t rx_caps[HDCP_CAPS_BYTE_LEN];
+} hci_verifycert_t;
+
+typedef struct {
+ uint32_t id;
+ uint8_t version[HDCP_VERSION_LEN];
+ uint8_t caps_mask[HDCP_CAPABILITY_MASK_LEN];
+} hci_setrxinfo_t;
+
+typedef struct {
+ uint32_t id;
+ uint32_t lk_type;
+ uint32_t emkey_len;
+ uint8_t emkey[HDCP_AKE_ENCKEY_BYTE_LEN];
+} hci_genmkey_t;
+
+typedef struct {
+ uint32_t id;
+ uint8_t rrx[HDCP_RRX_BYTE_LEN];
+} hci_setrrx_t;
+
+typedef struct {
+ uint32_t id;
+ uint32_t rx_hmac_len;
+ uint8_t rx_hmac[HDCP_HMAC_SHA256_LEN];
+} hci_comphmac_t;
+
+typedef struct {
+ uint32_t id;
+ uint8_t ekh_mkey[HDCP_AKE_EKH_MKEY_BYTE_LEN];
+} hci_setpairing_t;
+
+typedef struct {
+ uint32_t id;
+ uint8_t ekh_mkey[HDCP_AKE_EKH_MKEY_BYTE_LEN];
+ uint8_t m[HDCP_AKE_M_BYTE_LEN];
+} hci_getpairing_t;
+
+typedef struct {
+ uint32_t id;
+ uint32_t len;
+ uint8_t rn[HDCP_RN_BYTE_LEN];
+} hci_genrn_t;
+
+typedef struct {
+ uint32_t id;
+ uint32_t lk_type;
+ uint8_t lsb16_hmac[16];
+} hci_genlchmac_t;
+
+typedef struct {
+ uint32_t id;
+ uint32_t rx_hmac_len;
+ uint8_t rx_hmac[HDCP_HMAC_SHA256_LEN];
+} hci_complchmac_t;
+
+typedef struct {
+ uint32_t id;
+ uint32_t len;
+ uint8_t riv[HDCP_RIV_BYTE_LEN];
+} hci_genriv_t;
+
+typedef struct {
+ uint32_t id;
+ uint32_t lk_type;
+ uint8_t eskey[HDCP_SKE_SKEY_LEN];
+ uint32_t eskey_len;
+ int share_skey;
+} hci_genskey_t;
+
+typedef struct {
+ uint32_t id;
+ uint8_t str_ctr[HDCP_STR_CTR_LEN];
+ uint8_t input_ctr[HDCP_INPUT_CTR_LEN];
+ uint64_t input_addr;
+ uint32_t input_len;
+ uint64_t output_addr;
+ uint32_t output_len;
+} hci_encpacket_t;
+
+typedef struct {
+ uint32_t id;
+ 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_lst[HDCP_RP_RCVID_LIST_LEN];
+ uint8_t v[HDCP_RP_HMAC_V_LEN / 2];
+} hci_setrcvlist_t;
+
+typedef struct {
+ uint32_t id;
+ uint16_t stream_num;
+ uint8_t streamid[HDCP_RP_MAX_STREAMID_NUM];
+ uint8_t seq_num_m[HDCP_RP_SEQ_NUM_M_LEN];
+ uint8_t k[HDCP_RP_K_LEN];
+ uint8_t streamid_type[HDCP_RP_STREAMID_TYPE_LEN];
+} hci_genstreaminfo_t;
+
+typedef struct {
+ uint32_t id;
+ uint8_t m_prime[HDCP_RP_HMAC_M_LEN];
+ uint8_t strmsg[HDCP_RP_STREAM_MSG_MAX_LEN];
+ uint32_t str_len;
+} hci_verifymprime_t;
+
+typedef struct {
+ uint32_t id;
+ uint8_t key[HDCP_WRAP_KEY];
+ uint8_t enc_key[HDCP_WRAP_MAX_SIZE];
+ uint32_t wrapped;
+ uint32_t key_len;
+} hci_wrap_key_t;
+
+/* todo: define WSM message format for AKE */
+struct hci_message {
+ union {
+ uint32_t cmd_id;
+ hci_genrtx_t genrtx;
+ hci_gettxinfo_t gettxinfo;
+ hci_verifycert_t vfcert;
+ hci_setrxinfo_t setrxinfo;
+ hci_setrrx_t setrrx;
+ hci_genmkey_t genmkey;
+ hci_comphmac_t comphmac;
+ hci_setpairing_t setpairing;
+ hci_getpairing_t getpairing;
+ hci_genrn_t genrn;
+ hci_genlchmac_t genlchmac;
+ hci_complchmac_t complchmac;
+ hci_genriv_t genriv;
+ hci_genskey_t genskey;
+ hci_encpacket_t encpacket;
+ hci_setrcvlist_t setrcvlist;
+ hci_genstreaminfo_t genstrminfo;
+ hci_verifymprime_t verifymprime;
+ hci_wrap_key_t wrap_key;
+ uint8_t data[HDCP_WSM_SIZE];
+ };
+};
+
+struct hci_ctx {
+ struct hci_message *msg;
+ uint8_t state;
+};
+
+int hdcp_tee_open(void);
+int hdcp_tee_close(void);
+int hdcp_tee_comm(struct hci_message *hci);
+
+/* HDCP TEE interfaces */
+int teei_gen_rtx(uint32_t lk_type,
+ uint8_t *rtx,
+ size_t rtx_len,
+ uint8_t *caps,
+ uint32_t caps_len);
+int teei_get_txinfo(uint8_t *version, size_t version_len,
+ uint8_t *caps_mask, uint32_t caps_mask_len);
+int teei_verify_cert(uint8_t *cert, size_t cert_len,
+ uint8_t *rrx, size_t rrx_len,
+ uint8_t *rx_caps, size_t rx_caps_len);
+int teei_set_rxinfo(uint8_t *version, size_t version_len,
+ uint8_t *caps_mask, uint32_t caps_mask_len);
+int teei_set_rrx(uint8_t *rrx, size_t rrx_len);
+int teei_generate_master_key(uint32_t lk_type,
+ uint8_t *emkey, size_t emkey_len);
+int teei_compare_ake_hmac(uint8_t *hmac, size_t hamc_len);
+int teei_set_pairing_info(uint8_t *ekh_mkey, size_t ekh_mkey_len);
+int teei_get_pairing_info(uint8_t *ekh_mkey, size_t ekh_mkey_len,
+ uint8_t *m, size_t m_len);
+
+/* LC interface */
+int teei_gen_rn(uint8_t *out, size_t len);
+int teei_gen_lc_hmac(uint32_t lk_type, uint8_t *lsb128_hmac);
+int teei_compare_lc_hmac(uint8_t *rx_hmac, size_t rx_hmac_len);
+int teei_generate_riv(uint8_t *out, size_t len);
+int teei_generate_skey(uint32_t lk_type,
+ uint8_t *eskey, size_t eskey_len,
+ int share_skey);
+int teei_encrypt_packet(uint8_t *input, size_t input_len,
+ uint8_t *output, size_t output_len,
+ uint8_t *str_ctr, size_t str_ctr_len,
+ uint8_t *input_ctr, size_t input_ctr_len);
+
+/* Repeater Auth interface */
+int teei_set_rcvlist_info(uint8_t *rx_info,
+ uint8_t *seq_num_v,
+ uint8_t *v_prime,
+ uint8_t *rcvid_list,
+ uint8_t *v,
+ uint8_t *valid);
+int teei_gen_stream_manage(uint16_t stream_num,
+ uint8_t *streamid,
+ uint8_t *seq_num_m,
+ uint8_t *k,
+ uint8_t *streamid_type);
+int teei_verify_m_prime(uint8_t *m_prime, uint8_t *input, size_t input_len);
+int teei_wrapped_key(uint8_t *key_str, uint32_t wrraped, uint32_t key_len);
+#endif
--- /dev/null
+/* soc/samsung/exynos-hdcp/exynos-hdcp2-testvector.h
+ *
+ * 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.
+*/
+
+#ifndef __EXYNOS_HDCP2_TEST_VECTOR_H__
+#define __EXYNOS_HDCP2_TEST_VECTOR_H__
+
+#include "exynos-hdcp2-config.h"
+#include "exynos-hdcp2-protocol-msg.h"
+
+#ifdef TEST_VECTOR_1
+unsigned char cert[522] = {
+ 0x74, 0x5b, 0xb8, 0xbd, 0x04, 0xbc, 0x83, 0xc7,
+ 0x95, 0x78, 0xf9, 0x0c, 0x91, 0x4b, 0x89, 0x38,
+ 0x05, 0x5a, 0xa4, 0xac, 0x1f, 0xa8, 0x03, 0x93,
+ 0x82, 0x79, 0x75, 0xaf, 0x66, 0x22, 0xde, 0x43,
+ 0x80, 0x8d, 0xcd, 0x5d, 0x90, 0xb8, 0x3c, 0xb3,
+ 0xd8, 0x9e, 0xb0, 0x0d, 0x09, 0x44, 0xf4, 0x3f,
+ 0x5f, 0xab, 0xb9, 0xc4, 0xc9, 0x96, 0xef, 0x78,
+ 0xb5, 0x8f, 0x69, 0x77, 0xb4, 0x7d, 0x08, 0x14,
+ 0x9c, 0x81, 0xa0, 0x8f, 0x04, 0x1f, 0xa0, 0x88,
+ 0xe1, 0x20, 0xc7, 0x34, 0x4a, 0x49, 0x35, 0x65,
+ 0x99, 0xcf, 0x53, 0x19, 0xf0, 0xc6, 0x81, 0x76,
+ 0x05, 0x5c, 0xb9, 0xde, 0xdd, 0xab, 0x3d, 0xb0,
+ 0x92, 0xa1, 0x23, 0x4f, 0x0c, 0x71, 0x30, 0x42,
+ 0x78, 0xf6, 0x55, 0xae, 0xbd, 0x36, 0x25, 0x8e,
+ 0x25, 0x0d, 0x4e, 0x5e, 0x8e, 0x77, 0x6a, 0x60,
+ 0xe3, 0xc1, 0xe9, 0xee, 0xcd, 0x2b, 0x9e, 0x18,
+ 0x63, 0x97, 0xd4, 0xe6, 0x75, 0x01, 0x00, 0x01,
+ 0x00, 0x00, 0x1d, 0x0a, 0x61, 0xea, 0xab, 0xf8,
+ 0xa8, 0x2b, 0x02, 0x69, 0xa1, 0x34, 0xfd, 0x91,
+ 0xac, 0x2b, 0xf2, 0x8f, 0x34, 0x8b, 0xd4, 0x84,
+ 0xfa, 0x62, 0xbc, 0x01, 0x4a, 0x4a, 0xa2, 0xb2,
+ 0x14, 0xbf, 0xb5, 0xf4, 0xdf, 0xac, 0x80, 0x93,
+ 0x0d, 0x13, 0xec, 0x9c, 0xe5, 0xd8, 0x34, 0x70,
+ 0x51, 0x9a, 0x66, 0x80, 0xeb, 0xbe, 0xcc, 0x7e,
+ 0x45, 0xf0, 0xe6, 0x39, 0x63, 0x84, 0xc9, 0xb9,
+ 0x8e, 0x8c, 0xaf, 0x9c, 0xa9, 0xd4, 0x0e, 0xeb,
+ 0x9a, 0x57, 0x2a, 0x17, 0x41, 0xca, 0x97, 0xf3,
+ 0x19, 0x96, 0xb5, 0x5d, 0x0f, 0x30, 0xa3, 0x84,
+ 0xe5, 0x73, 0xa2, 0xed, 0x05, 0x69, 0x7a, 0x22,
+ 0xce, 0x84, 0x1f, 0x3e, 0x39, 0x9e, 0x28, 0x76,
+ 0xc9, 0xbc, 0x89, 0x5b, 0x70, 0xb1, 0x7b, 0xf4,
+ 0xed, 0xb6, 0x74, 0x12, 0xab, 0x48, 0x29, 0x64,
+ 0xce, 0x6c, 0x60, 0x04, 0xeb, 0xa9, 0x7a, 0xa2,
+ 0x15, 0xa6, 0x58, 0x9a, 0xad, 0x32, 0xc7, 0x53,
+ 0x39, 0xe5, 0xfe, 0xf0, 0x37, 0xa7, 0xa0, 0xc5,
+ 0xff, 0xec, 0xd9, 0xb0, 0x05, 0xbb, 0x25, 0x13,
+ 0xa0, 0xa4, 0xc7, 0x0b, 0x2a, 0x5d, 0xc6, 0x8f,
+ 0x51, 0x11, 0xcb, 0x36, 0xed, 0x5c, 0x17, 0x7e,
+ 0x22, 0x20, 0xc3, 0xeb, 0x40, 0x8c, 0x67, 0xbb,
+ 0x1c, 0xd2, 0x47, 0xb0, 0xe0, 0xbd, 0xe7, 0x4c,
+ 0xcd, 0x5d, 0xd5, 0x23, 0x12, 0xf8, 0x3b, 0x1d,
+ 0x91, 0x3b, 0xf3, 0xc7, 0x60, 0xea, 0x90, 0x24,
+ 0x48, 0xe5, 0x92, 0x21, 0x6c, 0xf6, 0xd9, 0x5e,
+ 0x76, 0x8d, 0x2b, 0x86, 0xa6, 0x7c, 0x16, 0xae,
+ 0xa8, 0x36, 0x08, 0xa0, 0x37, 0x14, 0x1a, 0xd7,
+ 0x03, 0xe1, 0x40, 0x31, 0xca, 0x6c, 0x95, 0xe0,
+ 0x10, 0xb0, 0x43, 0xcf, 0xb7, 0xe0, 0x30, 0x05,
+ 0xb9, 0xac, 0xb7, 0x08, 0x68, 0xcd, 0x7e, 0x11,
+ 0x47, 0x2a, 0x03, 0x3b, 0xeb, 0x74, 0xc8, 0x19,
+ 0x62, 0x8b, 0x2f, 0x11, 0x91, 0xb6, 0x06, 0x4f,
+ 0xe0, 0x2a, 0x44, 0x20, 0x43, 0x29, 0x13, 0x1f,
+ 0xdd, 0xd0, 0x4a, 0x11, 0x6c, 0x0e, 0x83, 0xbf,
+ 0x22, 0x62, 0x3b, 0xeb, 0xec, 0xd7, 0x76, 0x28,
+ 0xba, 0x64, 0x88, 0x42, 0xc8, 0x73, 0xa7, 0x9e,
+ 0x4a, 0x69, 0x3a, 0xb2, 0x0c, 0x4b, 0x3a, 0xd9,
+ 0x50, 0xdb, 0x7c, 0x51, 0xee, 0x15, 0xe0, 0x6b,
+ 0x2c, 0x63, 0xa6, 0x91, 0x57, 0xdd, 0xbf, 0x17,
+ 0x47, 0x23, 0xad, 0x15, 0xcb, 0xb9, 0x91, 0x18,
+ 0x0b, 0x51, 0x8f, 0xf9, 0x1c, 0x51, 0x67, 0xc1,
+ 0x0b, 0x78, 0xf5, 0xd9, 0x55, 0xdc, 0x48, 0xe4,
+ 0xc0, 0x83, 0xa5, 0xdf, 0x75, 0xe2, 0xdc, 0x88,
+ 0xd2, 0xc6, 0xdd, 0xdf, 0x1f, 0x37, 0x90, 0x35,
+ 0xf6, 0xfd, 0xda, 0xe0, 0x04, 0x32, 0x69, 0xc1,
+ 0xaf, 0xd9, 0xf9, 0x11, 0xc5, 0xaa, 0x74, 0x58,
+ 0x32, 0x1c, 0x71, 0xaa, 0xa7, 0x14, 0xfb, 0x23,
+ 0x17, 0x22};
+
+/* HDCP2.2 R1 */
+unsigned char cert_v22[522] = {
+ 0x74, 0x5b, 0xb8, 0xbd, 0x04, 0xaf, 0xb5, 0xc5,
+ 0xc6, 0x7b, 0xc5, 0x3a, 0x34, 0x90, 0xa9, 0x54,
+ 0xc0, 0x8f, 0xb7, 0xeb, 0xa1, 0x54, 0xd2, 0x4f,
+ 0x22, 0xde, 0x83, 0xf5, 0x03, 0xa6, 0xc6, 0x68,
+ 0x46, 0x9b, 0xc0, 0xb8, 0xc8, 0x6c, 0xdb, 0x26,
+ 0xf9, 0x3c, 0x49, 0x2f, 0x02, 0xe1, 0x71, 0xdf,
+ 0x4e, 0xf3, 0x0e, 0xc8, 0xbf, 0x22, 0x9d, 0x04,
+ 0xcf, 0xbf, 0xa9, 0x0d, 0xff, 0x68, 0xab, 0x05,
+ 0x6f, 0x1f, 0x12, 0x8a, 0x68, 0x62, 0xeb, 0xfe,
+ 0xc9, 0xea, 0x9f, 0xa7, 0xfb, 0x8c, 0xba, 0xb1,
+ 0xbd, 0x65, 0xac, 0x35, 0x9c, 0xa0, 0x33, 0xb1,
+ 0xdd, 0xa6, 0x05, 0x36, 0xaf, 0x00, 0xa2, 0x7f,
+ 0xbc, 0x07, 0xb2, 0xdd, 0xb5, 0xcc, 0x57, 0x5c,
+ 0xdc, 0xc0, 0x95, 0x50, 0xe5, 0xff, 0x1f, 0x20,
+ 0xdb, 0x59, 0x46, 0xfa, 0x47, 0xc4, 0xed, 0x12,
+ 0x2e, 0x9e, 0x22, 0xbd, 0x95, 0xa9, 0x85, 0x59,
+ 0xa1, 0x59, 0x3c, 0xc7, 0x83, 0x01, 0x00, 0x01,
+ 0x10, 0x00, 0x0b, 0xa3, 0x73, 0x77, 0xdd, 0x03,
+ 0x18, 0x03, 0x8a, 0x91, 0x63, 0x29, 0x1e, 0xa2,
+ 0x95, 0x74, 0x42, 0x90, 0x78, 0xd0, 0x67, 0x25,
+ 0xb6, 0x32, 0x2f, 0xcc, 0x23, 0x2b, 0xad, 0x21,
+ 0x39, 0x3d, 0x14, 0xba, 0x37, 0xa3, 0x65, 0x14,
+ 0x6b, 0x9c, 0xcf, 0x61, 0x20, 0x44, 0xa1, 0x07,
+ 0xbb, 0xcf, 0xc3, 0x4e, 0x95, 0x5b, 0x10, 0xcf,
+ 0xc7, 0x6f, 0xf1, 0xc3, 0x53, 0x7c, 0x63, 0xa1,
+ 0x8c, 0xb2, 0xe8, 0xab, 0x2e, 0x96, 0x97, 0xc3,
+ 0x83, 0x99, 0x70, 0xd3, 0xdc, 0x21, 0x41, 0xf6,
+ 0x0a, 0xd1, 0x1a, 0xee, 0xf4, 0xcc, 0xeb, 0xfb,
+ 0xa6, 0xaa, 0xb6, 0x9a, 0xaf, 0x1d, 0x16, 0x5e,
+ 0xe2, 0x83, 0xa0, 0x4a, 0x41, 0xf6, 0x7b, 0x07,
+ 0xbf, 0x47, 0x85, 0x28, 0x6c, 0xa0, 0x77, 0xa6,
+ 0xa3, 0xd7, 0x85, 0xa5, 0xc4, 0xa7, 0xe7, 0x6e,
+ 0xb5, 0x1f, 0x40, 0x72, 0x97, 0xfe, 0xc4, 0x81,
+ 0x23, 0xa0, 0xc2, 0x90, 0xb3, 0x49, 0x24, 0xf5,
+ 0xb7, 0x90, 0x2c, 0xbf, 0xfe, 0x04, 0x2e, 0x00,
+ 0xa9, 0x5f, 0x86, 0x04, 0xca, 0xc5, 0x3a, 0xcc,
+ 0x26, 0xd9, 0x39, 0x7e, 0xa9, 0x2d, 0x28, 0x6d,
+ 0xc0, 0xcc, 0x6e, 0x81, 0x9f, 0xb9, 0xb7, 0x11,
+ 0x33, 0x32, 0x23, 0x47, 0x98, 0x43, 0x0d, 0xa5,
+ 0x1c, 0x59, 0xf3, 0xcd, 0xd2, 0x4a, 0xb7, 0x3e,
+ 0x69, 0xd9, 0x21, 0x53, 0x9a, 0xf2, 0x6e, 0x77,
+ 0x62, 0xae, 0x50, 0xda, 0x85, 0xc6, 0xaa, 0xc4,
+ 0xb5, 0x1c, 0xcd, 0xa8, 0xa5, 0xdd, 0x6e, 0x62,
+ 0x73, 0xff, 0x5f, 0x7b, 0xd7, 0x3c, 0x17, 0xba,
+ 0x47, 0x0c, 0x89, 0x0e, 0x62, 0x79, 0x43, 0x94,
+ 0xaa, 0xa8, 0x47, 0xf4, 0x4c, 0x38, 0x89, 0xa8,
+ 0x81, 0xad, 0x23, 0x13, 0x27, 0x0c, 0x17, 0xcf,
+ 0x3d, 0x83, 0x84, 0x57, 0x36, 0xe7, 0x22, 0x26,
+ 0x2e, 0x76, 0xfd, 0x56, 0x80, 0x83, 0xf6, 0x70,
+ 0xd4, 0x5c, 0x91, 0x48, 0x84, 0x7b, 0x18, 0xdb,
+ 0x0e, 0x15, 0x3b, 0x49, 0x26, 0x23, 0xe6, 0xa3,
+ 0xe2, 0xc6, 0x3a, 0x23, 0x57, 0x66, 0xb0, 0x72,
+ 0xb8, 0x12, 0x17, 0x4f, 0x86, 0xfe, 0x48, 0x0d,
+ 0x53, 0xea, 0xfe, 0x31, 0x48, 0x7d, 0x86, 0xde,
+ 0xeb, 0x82, 0x86, 0x1e, 0x62, 0x03, 0x98, 0x59,
+ 0x00, 0x37, 0xeb, 0x61, 0xe9, 0xf9, 0x7a, 0x40,
+ 0x78, 0x1c, 0xba, 0xbc, 0x0b, 0x88, 0xfb, 0xfd,
+ 0x9d, 0xd5, 0x01, 0x11, 0x94, 0xe0, 0x35, 0xbe,
+ 0x33, 0xe8, 0xe5, 0x36, 0xfb, 0x9c, 0x45, 0xcb,
+ 0x75, 0xaf, 0xd6, 0x35, 0xff, 0x78, 0x92, 0x7f,
+ 0xa1, 0x7c, 0xa8, 0xfc, 0xb7, 0xf7, 0xa8, 0x52,
+ 0xa9, 0xc6, 0x84, 0x72, 0x3d, 0x1c, 0xc9, 0xdf,
+ 0x35, 0xc6, 0xe6, 0x00, 0xe1, 0x48, 0x72, 0xce,
+ 0x83, 0x1b, 0xcc, 0xf8, 0x33, 0x2d, 0x4f, 0x98,
+ 0x75, 0x00, 0x3c, 0x41, 0xdf, 0x7a, 0xed, 0x38,
+ 0x53, 0xb1};
+#else
+unsigned char cert[522] = {
+ 0x8b, 0xa4, 0x47, 0x42, 0xfb, 0xc9, 0x1b, 0x82,
+ 0xe2, 0x76, 0x7f, 0x90, 0x4f, 0xe9, 0x12, 0x33,
+ 0x7c, 0x21, 0x1f, 0x7b, 0x25, 0xda, 0x76, 0xde,
+ 0xae, 0x59, 0x70, 0xf7, 0xc2, 0xe7, 0xe0, 0x4a,
+ 0xcf, 0xbd, 0x5b, 0xba, 0x1c, 0x36, 0x4e, 0xe3,
+ 0x78, 0x4c, 0x92, 0x6a, 0x3c, 0xd8, 0xc1, 0xe9,
+ 0x51, 0xa9, 0x35, 0xeb, 0xd8, 0xe8, 0xd5, 0x3e,
+ 0x3b, 0x1d, 0x00, 0xc1, 0x16, 0x16, 0xd0, 0x58,
+ 0xeb, 0x2a, 0x4b, 0xa0, 0x76, 0x9c, 0xd0, 0xe4,
+ 0xb2, 0x23, 0xdc, 0xaa, 0x37, 0x07, 0xe5, 0x85,
+ 0x1a, 0xaa, 0x13, 0x55, 0x01, 0x4e, 0xed, 0x88,
+ 0xca, 0x3f, 0xfb, 0xc5, 0x58, 0x46, 0x91, 0xec,
+ 0x35, 0x99, 0x08, 0x1c, 0xa1, 0x22, 0x64, 0xe8,
+ 0x3c, 0x2e, 0x70, 0xdf, 0xa9, 0x10, 0x14, 0x81,
+ 0x46, 0xa2, 0x38, 0x08, 0xef, 0x1b, 0xd2, 0x46,
+ 0xee, 0x38, 0x0d, 0x6d, 0x92, 0xd3, 0xf2, 0x02,
+ 0xe7, 0xe4, 0x29, 0xad, 0x0d, 0x01, 0x00, 0x01,
+ 0x00, 0x00, 0x91, 0x18, 0x81, 0xa5, 0xcd, 0xab,
+ 0x78, 0x50, 0xad, 0x1d, 0x3b, 0x77, 0xbe, 0x51,
+ 0x32, 0x9f, 0x04, 0xe6, 0x3e, 0xf7, 0x01, 0x39,
+ 0xf2, 0x59, 0x98, 0x75, 0x9d, 0x29, 0x12, 0x33,
+ 0x39, 0xb4, 0x80, 0x91, 0x9d, 0x6a, 0xff, 0x0d,
+ 0x5c, 0x59, 0x22, 0x43, 0x77, 0xfc, 0xed, 0xc2,
+ 0x40, 0x9d, 0xe2, 0xd1, 0x4b, 0xff, 0x02, 0x78,
+ 0x36, 0xd3, 0xad, 0xcb, 0xa6, 0xd3, 0xd3, 0x9d,
+ 0xcc, 0xff, 0xcb, 0x3c, 0xa3, 0xcb, 0xfd, 0xdf,
+ 0xcf, 0xe2, 0x85, 0xa8, 0xbd, 0xa2, 0xf6, 0x60,
+ 0x06, 0xb2, 0x9b, 0x53, 0xc4, 0xd6, 0x22, 0xbd,
+ 0x65, 0x3c, 0x6f, 0x40, 0x01, 0x7c, 0x2c, 0x78,
+ 0x89, 0x31, 0x70, 0x47, 0x56, 0x88, 0xf5, 0x56,
+ 0x33, 0xf2, 0x0a, 0x91, 0x27, 0xb1, 0x68, 0x5f,
+ 0x84, 0x98, 0x1d, 0x37, 0xbd, 0x69, 0x11, 0x6d,
+ 0x60, 0xca, 0x01, 0x44, 0xbe, 0xfa, 0x92, 0x1f,
+ 0xec, 0x15, 0xbe, 0x37, 0x68, 0xd1, 0xdc, 0xcc,
+ 0x66, 0x7c, 0xc4, 0x8b, 0x78, 0x51, 0xd9, 0x81,
+ 0xdf, 0xaa, 0xe2, 0x70, 0x2f, 0x02, 0x59, 0x10,
+ 0x64, 0xb2, 0x93, 0x6d, 0x09, 0x23, 0xa9, 0x7d,
+ 0x0a, 0xdb, 0x8a, 0x34, 0x53, 0xca, 0xe2, 0x6a,
+ 0x6d, 0x39, 0xfb, 0x25, 0x5e, 0x38, 0x86, 0xeb,
+ 0x4d, 0xa1, 0xc1, 0xea, 0xbd, 0xac, 0x1d, 0x14,
+ 0x46, 0xac, 0x58, 0x86, 0x55, 0xec, 0x40, 0x9f,
+ 0xdc, 0x4f, 0x80, 0xf2, 0x68, 0x0c, 0x81, 0xa3,
+ 0xdf, 0x01, 0xa0, 0x62, 0x44, 0x9e, 0x20, 0x42,
+ 0x89, 0x88, 0x24, 0xb2, 0x6a, 0x40, 0x11, 0x4b,
+ 0x96, 0x33, 0xba, 0x0d, 0xae, 0x49, 0x98, 0x4b,
+ 0x24, 0x16, 0x5f, 0xff, 0x85, 0x86, 0x4a, 0x09,
+ 0xcd, 0xce, 0x30, 0xf2, 0xfa, 0xff, 0x74, 0x28,
+ 0x40, 0x97, 0xa5, 0x56, 0x29, 0x74, 0x53, 0xa2,
+ 0x34, 0xe4, 0xee, 0xe0, 0x45, 0xb6, 0xd8, 0xa7,
+ 0x9b, 0xa0, 0x1a, 0x00, 0x2d, 0xff, 0x8d, 0x2f,
+ 0xed, 0x70, 0x15, 0xc5, 0xe0, 0x11, 0xbb, 0xc8,
+ 0xef, 0x5b, 0x2c, 0xb3, 0x12, 0x0f, 0xbe, 0x88,
+ 0x7c, 0x98, 0x44, 0x3c, 0x65, 0x45, 0xbc, 0x20,
+ 0xac, 0x07, 0xe2, 0x4c, 0x74, 0x2a, 0xb4, 0xb1,
+ 0x0e, 0x47, 0x2a, 0xd6, 0x20, 0x19, 0xce, 0x75,
+ 0x18, 0x45, 0x28, 0x90, 0x4f, 0x84, 0x42, 0x81,
+ 0x37, 0xed, 0x1d, 0x0b, 0x48, 0xf7, 0x53, 0xe3,
+ 0x92, 0xf2, 0xeb, 0xdf, 0x7a, 0x91, 0xdf, 0xe8,
+ 0xdb, 0xb1, 0xc4, 0xfd, 0xfd, 0xc1, 0xad, 0x4e,
+ 0xcc, 0xbe, 0x11, 0xe2, 0x76, 0x9b, 0x78, 0x2b,
+ 0xb8, 0xf4, 0x0e, 0x9d, 0x05, 0xd6, 0x08, 0xd0,
+ 0x76, 0x2c, 0xe8, 0x4d, 0xee, 0x3d, 0x31, 0xda,
+ 0xc4, 0xf7, 0x01, 0x12, 0x8f, 0x5d, 0x94, 0xe6,
+ 0xcb, 0x15, 0xfe, 0x53, 0x42, 0xb2, 0x51, 0x8c,
+ 0x5d, 0xc7, 0x64, 0xde, 0x14, 0x8f, 0xaf, 0xc1,
+ 0xaf, 0x36};
+
+/* HDCP 2.2 R2 */
+unsigned char cert_v22[522] = {
+ 0x8b, 0xa4, 0x47, 0x42, 0xfb, 0xe4, 0x68, 0x63,
+ 0x8a, 0xda, 0x97, 0x2d, 0xde, 0x9a, 0x8d, 0x1c,
+ 0xb1, 0x65, 0x4b, 0x85, 0x8d, 0xe5, 0x46, 0xd6,
+ 0xdb, 0x95, 0xa5, 0xf6, 0x66, 0x74, 0xea, 0x81,
+ 0x0b, 0x9a, 0x58, 0x58, 0x66, 0x26, 0x86, 0xa6,
+ 0xb4, 0x56, 0x2b, 0x29, 0x43, 0xe5, 0xbb, 0x81,
+ 0x74, 0x86, 0xa7, 0xb7, 0x16, 0x2f, 0x07, 0xec,
+ 0xd1, 0xb5, 0xf9, 0xae, 0x4f, 0x98, 0x89, 0xa9,
+ 0x91, 0x7d, 0x58, 0x5b, 0x8d, 0x20, 0xd5, 0xc5,
+ 0x08, 0x40, 0x3b, 0x86, 0xaf, 0xf4, 0xd6, 0xb9,
+ 0x20, 0x95, 0xe8, 0x90, 0x3b, 0x8f, 0x9f, 0x36,
+ 0x5b, 0x46, 0xb6, 0xd4, 0x1e, 0xf5, 0x05, 0x88,
+ 0x80, 0x14, 0xe7, 0x2c, 0x77, 0x5d, 0x6e, 0x54,
+ 0xe9, 0x65, 0x81, 0x5a, 0x68, 0x92, 0xa5, 0xd6,
+ 0x40, 0x78, 0x11, 0x97, 0x65, 0xd7, 0x64, 0x36,
+ 0x5e, 0x8d, 0x2a, 0x87, 0xa8, 0xeb, 0x7d, 0x06,
+ 0x2c, 0x10, 0xf8, 0x0a, 0x7d, 0x01, 0x00, 0x01,
+ 0x10, 0x00, 0x06, 0x40, 0x99, 0x8f, 0x5a, 0x54,
+ 0x71, 0x23, 0xa7, 0x6a, 0x64, 0x3f, 0xbd, 0xdd,
+ 0x52, 0xb2, 0x79, 0x6f, 0x88, 0x26, 0x94, 0x9e,
+ 0xaf, 0xa4, 0xde, 0x7d, 0x8d, 0x88, 0x10, 0xc8,
+ 0xf6, 0x56, 0xf0, 0x8f, 0x46, 0x28, 0x48, 0x55,
+ 0x51, 0xc5, 0xaf, 0xa1, 0xa9, 0x9d, 0xac, 0x9f,
+ 0xb1, 0x26, 0x4b, 0xeb, 0x39, 0xad, 0x88, 0x46,
+ 0xaf, 0xbc, 0x61, 0xa8, 0x7b, 0xf9, 0x7b, 0x3e,
+ 0xe4, 0x95, 0xd9, 0xa8, 0x79, 0x48, 0x51, 0x00,
+ 0xbe, 0xa4, 0xb6, 0x96, 0x7f, 0x3d, 0xfd, 0x76,
+ 0xa6, 0xb7, 0xbb, 0xb9, 0x77, 0xdc, 0x54, 0xfb,
+ 0x52, 0x9c, 0x79, 0x8f, 0xed, 0xd4, 0xb1, 0xbc,
+ 0x0f, 0x7e, 0xb1, 0x7e, 0x70, 0x6d, 0xfc, 0xb9,
+ 0x7e, 0x66, 0x9a, 0x86, 0x23, 0x3a, 0x98, 0x5e,
+ 0x32, 0x8d, 0x75, 0x18, 0x54, 0x64, 0x36, 0xdd,
+ 0x92, 0x01, 0x39, 0x90, 0xb9, 0xe3, 0xaf, 0x6f,
+ 0x98, 0xa5, 0xc0, 0x80, 0xc6, 0x2f, 0xa1, 0x02,
+ 0xad, 0x8d, 0xf4, 0xd6, 0x66, 0x7b, 0x45, 0xe5,
+ 0x74, 0x18, 0xb1, 0x27, 0x24, 0x01, 0x1e, 0xea,
+ 0xd8, 0xf3, 0x79, 0x92, 0xe9, 0x03, 0xf5, 0x57,
+ 0x8d, 0x65, 0x2a, 0x8d, 0x1b, 0xf0, 0xda, 0x58,
+ 0x3f, 0x58, 0xa0, 0xf4, 0xb4, 0xbe, 0xcb, 0x21,
+ 0x66, 0xe9, 0x21, 0x7c, 0x76, 0xf3, 0xc1, 0x7e,
+ 0x2e, 0x7c, 0x3d, 0x61, 0x20, 0x1d, 0xc5, 0xc0,
+ 0x71, 0x28, 0x2e, 0xb7, 0x0f, 0x1f, 0x7a, 0xc1,
+ 0xd3, 0x6a, 0x1e, 0xa3, 0x54, 0x34, 0x8e, 0x0d,
+ 0xd7, 0x96, 0x93, 0x78, 0x50, 0xc1, 0xee, 0x27,
+ 0x72, 0x3a, 0xbd, 0x57, 0x22, 0xf0, 0xd7, 0x6d,
+ 0x9d, 0x65, 0xc4, 0x07, 0x9c, 0x82, 0xa6, 0xd4,
+ 0xf7, 0x6b, 0x9a, 0xe9, 0xc0, 0x6c, 0x4a, 0x4f,
+ 0x6f, 0xbe, 0x8e, 0x01, 0x37, 0x50, 0x3a, 0x66,
+ 0xd9, 0xe9, 0xd9, 0xf9, 0x06, 0x9e, 0x00, 0xa9,
+ 0x84, 0xa0, 0x18, 0xb3, 0x44, 0x21, 0x24, 0xa3,
+ 0x6c, 0xcd, 0xb7, 0x0f, 0x31, 0x2a, 0xe8, 0x15,
+ 0xb6, 0x93, 0x6f, 0xb9, 0x86, 0xe5, 0x28, 0x01,
+ 0x1a, 0x5e, 0x10, 0x3f, 0x1f, 0x4d, 0x35, 0xa2,
+ 0x8d, 0xb8, 0x54, 0x26, 0x68, 0x3a, 0xcd, 0xcb,
+ 0x5f, 0xfa, 0x37, 0x4a, 0x60, 0x10, 0xb1, 0x0a,
+ 0xfe, 0xba, 0x9b, 0x96, 0x5d, 0x7e, 0x99, 0xcf,
+ 0x01, 0x98, 0x65, 0x87, 0xad, 0x40, 0xd5, 0x82,
+ 0x1d, 0x61, 0x54, 0xa2, 0xd3, 0x16, 0x3e, 0xf7,
+ 0xe3, 0x05, 0x89, 0x8d, 0x8a, 0x50, 0x87, 0x47,
+ 0xbe, 0x29, 0x18, 0x01, 0xb7, 0xc3, 0xdd, 0x43,
+ 0x23, 0x7a, 0xcd, 0x85, 0x1d, 0x4e, 0xa9, 0xc0,
+ 0x1a, 0xa4, 0x77, 0xab, 0xe7, 0x31, 0x9a, 0x33,
+ 0x1b, 0x7a, 0x86, 0xe1, 0xe5, 0xca, 0x0c, 0x43,
+ 0x1a, 0xfa, 0xec, 0x4c, 0x05, 0xc6, 0xd1, 0x43,
+ 0x12, 0xf9, 0x4d, 0x3e, 0xf7, 0xd6, 0x05, 0x9c,
+ 0x1c, 0xdd, /* end of cert_rx */
+ };
+#endif
+
+#define REPEATER 1
+#define NO_REPEATER 0
+
+/* Message Vector */
+/* Transmitter */
+#ifdef TEST_VECTOR_1
+uint8_t msg_rx_send_cert[524] = {
+ AKE_SEND_CERT,
+ REPEATER,
+ 0x74, 0x5b, 0xb8, 0xbd, 0x04, 0xbc, 0x83, 0xc7,
+ 0x95, 0x78, 0xf9, 0x0c, 0x91, 0x4b, 0x89, 0x38,
+ 0x05, 0x5a, 0xa4, 0xac, 0x1f, 0xa8, 0x03, 0x93,
+ 0x82, 0x79, 0x75, 0xaf, 0x66, 0x22, 0xde, 0x43,
+ 0x80, 0x8d, 0xcd, 0x5d, 0x90, 0xb8, 0x3c, 0xb3,
+ 0xd8, 0x9e, 0xb0, 0x0d, 0x09, 0x44, 0xf4, 0x3f,
+ 0x5f, 0xab, 0xb9, 0xc4, 0xc9, 0x96, 0xef, 0x78,
+ 0xb5, 0x8f, 0x69, 0x77, 0xb4, 0x7d, 0x08, 0x14,
+ 0x9c, 0x81, 0xa0, 0x8f, 0x04, 0x1f, 0xa0, 0x88,
+ 0xe1, 0x20, 0xc7, 0x34, 0x4a, 0x49, 0x35, 0x65,
+ 0x99, 0xcf, 0x53, 0x19, 0xf0, 0xc6, 0x81, 0x76,
+ 0x05, 0x5c, 0xb9, 0xde, 0xdd, 0xab, 0x3d, 0xb0,
+ 0x92, 0xa1, 0x23, 0x4f, 0x0c, 0x71, 0x30, 0x42,
+ 0x78, 0xf6, 0x55, 0xae, 0xbd, 0x36, 0x25, 0x8e,
+ 0x25, 0x0d, 0x4e, 0x5e, 0x8e, 0x77, 0x6a, 0x60,
+ 0xe3, 0xc1, 0xe9, 0xee, 0xcd, 0x2b, 0x9e, 0x18,
+ 0x63, 0x97, 0xd4, 0xe6, 0x75, 0x01, 0x00, 0x01,
+ 0x00, 0x00, 0x1d, 0x0a, 0x61, 0xea, 0xab, 0xf8,
+ 0xa8, 0x2b, 0x02, 0x69, 0xa1, 0x34, 0xfd, 0x91,
+ 0xac, 0x2b, 0xf2, 0x8f, 0x34, 0x8b, 0xd4, 0x84,
+ 0xfa, 0x62, 0xbc, 0x01, 0x4a, 0x4a, 0xa2, 0xb2,
+ 0x14, 0xbf, 0xb5, 0xf4, 0xdf, 0xac, 0x80, 0x93,
+ 0x0d, 0x13, 0xec, 0x9c, 0xe5, 0xd8, 0x34, 0x70,
+ 0x51, 0x9a, 0x66, 0x80, 0xeb, 0xbe, 0xcc, 0x7e,
+ 0x45, 0xf0, 0xe6, 0x39, 0x63, 0x84, 0xc9, 0xb9,
+ 0x8e, 0x8c, 0xaf, 0x9c, 0xa9, 0xd4, 0x0e, 0xeb,
+ 0x9a, 0x57, 0x2a, 0x17, 0x41, 0xca, 0x97, 0xf3,
+ 0x19, 0x96, 0xb5, 0x5d, 0x0f, 0x30, 0xa3, 0x84,
+ 0xe5, 0x73, 0xa2, 0xed, 0x05, 0x69, 0x7a, 0x22,
+ 0xce, 0x84, 0x1f, 0x3e, 0x39, 0x9e, 0x28, 0x76,
+ 0xc9, 0xbc, 0x89, 0x5b, 0x70, 0xb1, 0x7b, 0xf4,
+ 0xed, 0xb6, 0x74, 0x12, 0xab, 0x48, 0x29, 0x64,
+ 0xce, 0x6c, 0x60, 0x04, 0xeb, 0xa9, 0x7a, 0xa2,
+ 0x15, 0xa6, 0x58, 0x9a, 0xad, 0x32, 0xc7, 0x53,
+ 0x39, 0xe5, 0xfe, 0xf0, 0x37, 0xa7, 0xa0, 0xc5,
+ 0xff, 0xec, 0xd9, 0xb0, 0x05, 0xbb, 0x25, 0x13,
+ 0xa0, 0xa4, 0xc7, 0x0b, 0x2a, 0x5d, 0xc6, 0x8f,
+ 0x51, 0x11, 0xcb, 0x36, 0xed, 0x5c, 0x17, 0x7e,
+ 0x22, 0x20, 0xc3, 0xeb, 0x40, 0x8c, 0x67, 0xbb,
+ 0x1c, 0xd2, 0x47, 0xb0, 0xe0, 0xbd, 0xe7, 0x4c,
+ 0xcd, 0x5d, 0xd5, 0x23, 0x12, 0xf8, 0x3b, 0x1d,
+ 0x91, 0x3b, 0xf3, 0xc7, 0x60, 0xea, 0x90, 0x24,
+ 0x48, 0xe5, 0x92, 0x21, 0x6c, 0xf6, 0xd9, 0x5e,
+ 0x76, 0x8d, 0x2b, 0x86, 0xa6, 0x7c, 0x16, 0xae,
+ 0xa8, 0x36, 0x08, 0xa0, 0x37, 0x14, 0x1a, 0xd7,
+ 0x03, 0xe1, 0x40, 0x31, 0xca, 0x6c, 0x95, 0xe0,
+ 0x10, 0xb0, 0x43, 0xcf, 0xb7, 0xe0, 0x30, 0x05,
+ 0xb9, 0xac, 0xb7, 0x08, 0x68, 0xcd, 0x7e, 0x11,
+ 0x47, 0x2a, 0x03, 0x3b, 0xeb, 0x74, 0xc8, 0x19,
+ 0x62, 0x8b, 0x2f, 0x11, 0x91, 0xb6, 0x06, 0x4f,
+ 0xe0, 0x2a, 0x44, 0x20, 0x43, 0x29, 0x13, 0x1f,
+ 0xdd, 0xd0, 0x4a, 0x11, 0x6c, 0x0e, 0x83, 0xbf,
+ 0x22, 0x62, 0x3b, 0xeb, 0xec, 0xd7, 0x76, 0x28,
+ 0xba, 0x64, 0x88, 0x42, 0xc8, 0x73, 0xa7, 0x9e,
+ 0x4a, 0x69, 0x3a, 0xb2, 0x0c, 0x4b, 0x3a, 0xd9,
+ 0x50, 0xdb, 0x7c, 0x51, 0xee, 0x15, 0xe0, 0x6b,
+ 0x2c, 0x63, 0xa6, 0x91, 0x57, 0xdd, 0xbf, 0x17,
+ 0x47, 0x23, 0xad, 0x15, 0xcb, 0xb9, 0x91, 0x18,
+ 0x0b, 0x51, 0x8f, 0xf9, 0x1c, 0x51, 0x67, 0xc1,
+ 0x0b, 0x78, 0xf5, 0xd9, 0x55, 0xdc, 0x48, 0xe4,
+ 0xc0, 0x83, 0xa5, 0xdf, 0x75, 0xe2, 0xdc, 0x88,
+ 0xd2, 0xc6, 0xdd, 0xdf, 0x1f, 0x37, 0x90, 0x35,
+ 0xf6, 0xfd, 0xda, 0xe0, 0x04, 0x32, 0x69, 0xc1,
+ 0xaf, 0xd9, 0xf9, 0x11, 0xc5, 0xaa, 0x74, 0x58,
+ 0x32, 0x1c, 0x71, 0xaa, 0xa7, 0x14, 0xfb, 0x23,
+ 0x17, 0x22};
+
+uint8_t msg_rx_send_cert_v22[533] = {
+ 0x74, 0x5b, 0xb8, 0xbd, 0x04, 0xaf, 0xb5, 0xc5,
+ 0xc6, 0x7b, 0xc5, 0x3a, 0x34, 0x90, 0xa9, 0x54,
+ 0xc0, 0x8f, 0xb7, 0xeb, 0xa1, 0x54, 0xd2, 0x4f,
+ 0x22, 0xde, 0x83, 0xf5, 0x03, 0xa6, 0xc6, 0x68,
+ 0x46, 0x9b, 0xc0, 0xb8, 0xc8, 0x6c, 0xdb, 0x26,
+ 0xf9, 0x3c, 0x49, 0x2f, 0x02, 0xe1, 0x71, 0xdf,
+ 0x4e, 0xf3, 0x0e, 0xc8, 0xbf, 0x22, 0x9d, 0x04,
+ 0xcf, 0xbf, 0xa9, 0x0d, 0xff, 0x68, 0xab, 0x05,
+ 0x6f, 0x1f, 0x12, 0x8a, 0x68, 0x62, 0xeb, 0xfe,
+ 0xc9, 0xea, 0x9f, 0xa7, 0xfb, 0x8c, 0xba, 0xb1,
+ 0xbd, 0x65, 0xac, 0x35, 0x9c, 0xa0, 0x33, 0xb1,
+ 0xdd, 0xa6, 0x05, 0x36, 0xaf, 0x00, 0xa2, 0x7f,
+ 0xbc, 0x07, 0xb2, 0xdd, 0xb5, 0xcc, 0x57, 0x5c,
+ 0xdc, 0xc0, 0x95, 0x50, 0xe5, 0xff, 0x1f, 0x20,
+ 0xdb, 0x59, 0x46, 0xfa, 0x47, 0xc4, 0xed, 0x12,
+ 0x2e, 0x9e, 0x22, 0xbd, 0x95, 0xa9, 0x85, 0x59,
+ 0xa1, 0x59, 0x3c, 0xc7, 0x83, 0x01, 0x00, 0x01,
+ 0x10, 0x00, 0x0b, 0xa3, 0x73, 0x77, 0xdd, 0x03,
+ 0x18, 0x03, 0x8a, 0x91, 0x63, 0x29, 0x1e, 0xa2,
+ 0x95, 0x74, 0x42, 0x90, 0x78, 0xd0, 0x67, 0x25,
+ 0xb6, 0x32, 0x2f, 0xcc, 0x23, 0x2b, 0xad, 0x21,
+ 0x39, 0x3d, 0x14, 0xba, 0x37, 0xa3, 0x65, 0x14,
+ 0x6b, 0x9c, 0xcf, 0x61, 0x20, 0x44, 0xa1, 0x07,
+ 0xbb, 0xcf, 0xc3, 0x4e, 0x95, 0x5b, 0x10, 0xcf,
+ 0xc7, 0x6f, 0xf1, 0xc3, 0x53, 0x7c, 0x63, 0xa1,
+ 0x8c, 0xb2, 0xe8, 0xab, 0x2e, 0x96, 0x97, 0xc3,
+ 0x83, 0x99, 0x70, 0xd3, 0xdc, 0x21, 0x41, 0xf6,
+ 0x0a, 0xd1, 0x1a, 0xee, 0xf4, 0xcc, 0xeb, 0xfb,
+ 0xa6, 0xaa, 0xb6, 0x9a, 0xaf, 0x1d, 0x16, 0x5e,
+ 0xe2, 0x83, 0xa0, 0x4a, 0x41, 0xf6, 0x7b, 0x07,
+ 0xbf, 0x47, 0x85, 0x28, 0x6c, 0xa0, 0x77, 0xa6,
+ 0xa3, 0xd7, 0x85, 0xa5, 0xc4, 0xa7, 0xe7, 0x6e,
+ 0xb5, 0x1f, 0x40, 0x72, 0x97, 0xfe, 0xc4, 0x81,
+ 0x23, 0xa0, 0xc2, 0x90, 0xb3, 0x49, 0x24, 0xf5,
+ 0xb7, 0x90, 0x2c, 0xbf, 0xfe, 0x04, 0x2e, 0x00,
+ 0xa9, 0x5f, 0x86, 0x04, 0xca, 0xc5, 0x3a, 0xcc,
+ 0x26, 0xd9, 0x39, 0x7e, 0xa9, 0x2d, 0x28, 0x6d,
+ 0xc0, 0xcc, 0x6e, 0x81, 0x9f, 0xb9, 0xb7, 0x11,
+ 0x33, 0x32, 0x23, 0x47, 0x98, 0x43, 0x0d, 0xa5,
+ 0x1c, 0x59, 0xf3, 0xcd, 0xd2, 0x4a, 0xb7, 0x3e,
+ 0x69, 0xd9, 0x21, 0x53, 0x9a, 0xf2, 0x6e, 0x77,
+ 0x62, 0xae, 0x50, 0xda, 0x85, 0xc6, 0xaa, 0xc4,
+ 0xb5, 0x1c, 0xcd, 0xa8, 0xa5, 0xdd, 0x6e, 0x62,
+ 0x73, 0xff, 0x5f, 0x7b, 0xd7, 0x3c, 0x17, 0xba,
+ 0x47, 0x0c, 0x89, 0x0e, 0x62, 0x79, 0x43, 0x94,
+ 0xaa, 0xa8, 0x47, 0xf4, 0x4c, 0x38, 0x89, 0xa8,
+ 0x81, 0xad, 0x23, 0x13, 0x27, 0x0c, 0x17, 0xcf,
+ 0x3d, 0x83, 0x84, 0x57, 0x36, 0xe7, 0x22, 0x26,
+ 0x2e, 0x76, 0xfd, 0x56, 0x80, 0x83, 0xf6, 0x70,
+ 0xd4, 0x5c, 0x91, 0x48, 0x84, 0x7b, 0x18, 0xdb,
+ 0x0e, 0x15, 0x3b, 0x49, 0x26, 0x23, 0xe6, 0xa3,
+ 0xe2, 0xc6, 0x3a, 0x23, 0x57, 0x66, 0xb0, 0x72,
+ 0xb8, 0x12, 0x17, 0x4f, 0x86, 0xfe, 0x48, 0x0d,
+ 0x53, 0xea, 0xfe, 0x31, 0x48, 0x7d, 0x86, 0xde,
+ 0xeb, 0x82, 0x86, 0x1e, 0x62, 0x03, 0x98, 0x59,
+ 0x00, 0x37, 0xeb, 0x61, 0xe9, 0xf9, 0x7a, 0x40,
+ 0x78, 0x1c, 0xba, 0xbc, 0x0b, 0x88, 0xfb, 0xfd,
+ 0x9d, 0xd5, 0x01, 0x11, 0x94, 0xe0, 0x35, 0xbe,
+ 0x33, 0xe8, 0xe5, 0x36, 0xfb, 0x9c, 0x45, 0xcb,
+ 0x75, 0xaf, 0xd6, 0x35, 0xff, 0x78, 0x92, 0x7f,
+ 0xa1, 0x7c, 0xa8, 0xfc, 0xb7, 0xf7, 0xa8, 0x52,
+ 0xa9, 0xc6, 0x84, 0x72, 0x3d, 0x1c, 0xc9, 0xdf,
+ 0x35, 0xc6, 0xe6, 0x00, 0xe1, 0x48, 0x72, 0xce,
+ 0x83, 0x1b, 0xcc, 0xf8, 0x33, 0x2d, 0x4f, 0x98,
+ 0x75, 0x00, 0x3c, 0x41, 0xdf, 0x7a, 0xed, 0x38,
+ 0x53, 0xb1, /* end of Cert Rx */
+ 0x3b, 0xa0, 0xbe, 0xde, 0x0c, 0x46, 0xa9, 0x91, /* rrx */
+ 0x02, 0x00, 0x03 /* RxCaps */
+ };
+
+/* Receiver Publickey Certificate */
+#else
+uint8_t msg_rx_send_cert[524] = {
+ AKE_SEND_CERT,
+ NO_REPEATER,
+ /* Receiver Publickey Certificate */
+ 0x8b, 0xa4, 0x47, 0x42, 0xfb, 0xc9, 0x1b, 0x82,
+ 0xe2, 0x76, 0x7f, 0x90, 0x4f, 0xe9, 0x12, 0x33,
+ 0x7c, 0x21, 0x1f, 0x7b, 0x25, 0xda, 0x76, 0xde,
+ 0xae, 0x59, 0x70, 0xf7, 0xc2, 0xe7, 0xe0, 0x4a,
+ 0xcf, 0xbd, 0x5b, 0xba, 0x1c, 0x36, 0x4e, 0xe3,
+ 0x78, 0x4c, 0x92, 0x6a, 0x3c, 0xd8, 0xc1, 0xe9,
+ 0x51, 0xa9, 0x35, 0xeb, 0xd8, 0xe8, 0xd5, 0x3e,
+ 0x3b, 0x1d, 0x00, 0xc1, 0x16, 0x16, 0xd0, 0x58,
+ 0xeb, 0x2a, 0x4b, 0xa0, 0x76, 0x9c, 0xd0, 0xe4,
+ 0xb2, 0x23, 0xdc, 0xaa, 0x37, 0x07, 0xe5, 0x85,
+ 0x1a, 0xaa, 0x13, 0x55, 0x01, 0x4e, 0xed, 0x88,
+ 0xca, 0x3f, 0xfb, 0xc5, 0x58, 0x46, 0x91, 0xec,
+ 0x35, 0x99, 0x08, 0x1c, 0xa1, 0x22, 0x64, 0xe8,
+ 0x3c, 0x2e, 0x70, 0xdf, 0xa9, 0x10, 0x14, 0x81,
+ 0x46, 0xa2, 0x38, 0x08, 0xef, 0x1b, 0xd2, 0x46,
+ 0xee, 0x38, 0x0d, 0x6d, 0x92, 0xd3, 0xf2, 0x02,
+ 0xe7, 0xe4, 0x29, 0xad, 0x0d, 0x01, 0x00, 0x01,
+ 0x00, 0x00, 0x91, 0x18, 0x81, 0xa5, 0xcd, 0xab,
+ 0x78, 0x50, 0xad, 0x1d, 0x3b, 0x77, 0xbe, 0x51,
+ 0x32, 0x9f, 0x04, 0xe6, 0x3e, 0xf7, 0x01, 0x39,
+ 0xf2, 0x59, 0x98, 0x75, 0x9d, 0x29, 0x12, 0x33,
+ 0x39, 0xb4, 0x80, 0x91, 0x9d, 0x6a, 0xff, 0x0d,
+ 0x5c, 0x59, 0x22, 0x43, 0x77, 0xfc, 0xed, 0xc2,
+ 0x40, 0x9d, 0xe2, 0xd1, 0x4b, 0xff, 0x02, 0x78,
+ 0x36, 0xd3, 0xad, 0xcb, 0xa6, 0xd3, 0xd3, 0x9d,
+ 0xcc, 0xff, 0xcb, 0x3c, 0xa3, 0xcb, 0xfd, 0xdf,
+ 0xcf, 0xe2, 0x85, 0xa8, 0xbd, 0xa2, 0xf6, 0x60,
+ 0x06, 0xb2, 0x9b, 0x53, 0xc4, 0xd6, 0x22, 0xbd,
+ 0x65, 0x3c, 0x6f, 0x40, 0x01, 0x7c, 0x2c, 0x78,
+ 0x89, 0x31, 0x70, 0x47, 0x56, 0x88, 0xf5, 0x56,
+ 0x33, 0xf2, 0x0a, 0x91, 0x27, 0xb1, 0x68, 0x5f,
+ 0x84, 0x98, 0x1d, 0x37, 0xbd, 0x69, 0x11, 0x6d,
+ 0x60, 0xca, 0x01, 0x44, 0xbe, 0xfa, 0x92, 0x1f,
+ 0xec, 0x15, 0xbe, 0x37, 0x68, 0xd1, 0xdc, 0xcc,
+ 0x66, 0x7c, 0xc4, 0x8b, 0x78, 0x51, 0xd9, 0x81,
+ 0xdf, 0xaa, 0xe2, 0x70, 0x2f, 0x02, 0x59, 0x10,
+ 0x64, 0xb2, 0x93, 0x6d, 0x09, 0x23, 0xa9, 0x7d,
+ 0x0a, 0xdb, 0x8a, 0x34, 0x53, 0xca, 0xe2, 0x6a,
+ 0x6d, 0x39, 0xfb, 0x25, 0x5e, 0x38, 0x86, 0xeb,
+ 0x4d, 0xa1, 0xc1, 0xea, 0xbd, 0xac, 0x1d, 0x14,
+ 0x46, 0xac, 0x58, 0x86, 0x55, 0xec, 0x40, 0x9f,
+ 0xdc, 0x4f, 0x80, 0xf2, 0x68, 0x0c, 0x81, 0xa3,
+ 0xdf, 0x01, 0xa0, 0x62, 0x44, 0x9e, 0x20, 0x42,
+ 0x89, 0x88, 0x24, 0xb2, 0x6a, 0x40, 0x11, 0x4b,
+ 0x96, 0x33, 0xba, 0x0d, 0xae, 0x49, 0x98, 0x4b,
+ 0x24, 0x16, 0x5f, 0xff, 0x85, 0x86, 0x4a, 0x09,
+ 0xcd, 0xce, 0x30, 0xf2, 0xfa, 0xff, 0x74, 0x28,
+ 0x40, 0x97, 0xa5, 0x56, 0x29, 0x74, 0x53, 0xa2,
+ 0x34, 0xe4, 0xee, 0xe0, 0x45, 0xb6, 0xd8, 0xa7,
+ 0x9b, 0xa0, 0x1a, 0x00, 0x2d, 0xff, 0x8d, 0x2f,
+ 0xed, 0x70, 0x15, 0xc5, 0xe0, 0x11, 0xbb, 0xc8,
+ 0xef, 0x5b, 0x2c, 0xb3, 0x12, 0x0f, 0xbe, 0x88,
+ 0x7c, 0x98, 0x44, 0x3c, 0x65, 0x45, 0xbc, 0x20,
+ 0xac, 0x07, 0xe2, 0x4c, 0x74, 0x2a, 0xb4, 0xb1,
+ 0x0e, 0x47, 0x2a, 0xd6, 0x20, 0x19, 0xce, 0x75,
+ 0x18, 0x45, 0x28, 0x90, 0x4f, 0x84, 0x42, 0x81,
+ 0x37, 0xed, 0x1d, 0x0b, 0x48, 0xf7, 0x53, 0xe3,
+ 0x92, 0xf2, 0xeb, 0xdf, 0x7a, 0x91, 0xdf, 0xe8,
+ 0xdb, 0xb1, 0xc4, 0xfd, 0xfd, 0xc1, 0xad, 0x4e,
+ 0xcc, 0xbe, 0x11, 0xe2, 0x76, 0x9b, 0x78, 0x2b,
+ 0xb8, 0xf4, 0x0e, 0x9d, 0x05, 0xd6, 0x08, 0xd0,
+ 0x76, 0x2c, 0xe8, 0x4d, 0xee, 0x3d, 0x31, 0xda,
+ 0xc4, 0xf7, 0x01, 0x12, 0x8f, 0x5d, 0x94, 0xe6,
+ 0xcb, 0x15, 0xfe, 0x53, 0x42, 0xb2, 0x51, 0x8c,
+ 0x5d, 0xc7, 0x64, 0xde, 0x14, 0x8f, 0xaf, 0xc1,
+ 0xaf, 0x36};
+
+uint8_t msg_rx_send_cert_v22[533] = {
+ 0x8b, 0xa4, 0x47, 0x42, 0xfb, 0xe4, 0x68, 0x63,
+ 0x8a, 0xda, 0x97, 0x2d, 0xde, 0x9a, 0x8d, 0x1c,
+ 0xb1, 0x65, 0x4b, 0x85, 0x8d, 0xe5, 0x46, 0xd6,
+ 0xdb, 0x95, 0xa5, 0xf6, 0x66, 0x74, 0xea, 0x81,
+ 0x0b, 0x9a, 0x58, 0x58, 0x66, 0x26, 0x86, 0xa6,
+ 0xb4, 0x56, 0x2b, 0x29, 0x43, 0xe5, 0xbb, 0x81,
+ 0x74, 0x86, 0xa7, 0xb7, 0x16, 0x2f, 0x07, 0xec,
+ 0xd1, 0xb5, 0xf9, 0xae, 0x4f, 0x98, 0x89, 0xa9,
+ 0x91, 0x7d, 0x58, 0x5b, 0x8d, 0x20, 0xd5, 0xc5,
+ 0x08, 0x40, 0x3b, 0x86, 0xaf, 0xf4, 0xd6, 0xb9,
+ 0x20, 0x95, 0xe8, 0x90, 0x3b, 0x8f, 0x9f, 0x36,
+ 0x5b, 0x46, 0xb6, 0xd4, 0x1e, 0xf5, 0x05, 0x88,
+ 0x80, 0x14, 0xe7, 0x2c, 0x77, 0x5d, 0x6e, 0x54,
+ 0xe9, 0x65, 0x81, 0x5a, 0x68, 0x92, 0xa5, 0xd6,
+ 0x40, 0x78, 0x11, 0x97, 0x65, 0xd7, 0x64, 0x36,
+ 0x5e, 0x8d, 0x2a, 0x87, 0xa8, 0xeb, 0x7d, 0x06,
+ 0x2c, 0x10, 0xf8, 0x0a, 0x7d, 0x01, 0x00, 0x01,
+ 0x10, 0x00, 0x06, 0x40, 0x99, 0x8f, 0x5a, 0x54,
+ 0x71, 0x23, 0xa7, 0x6a, 0x64, 0x3f, 0xbd, 0xdd,
+ 0x52, 0xb2, 0x79, 0x6f, 0x88, 0x26, 0x94, 0x9e,
+ 0xaf, 0xa4, 0xde, 0x7d, 0x8d, 0x88, 0x10, 0xc8,
+ 0xf6, 0x56, 0xf0, 0x8f, 0x46, 0x28, 0x48, 0x55,
+ 0x51, 0xc5, 0xaf, 0xa1, 0xa9, 0x9d, 0xac, 0x9f,
+ 0xb1, 0x26, 0x4b, 0xeb, 0x39, 0xad, 0x88, 0x46,
+ 0xaf, 0xbc, 0x61, 0xa8, 0x7b, 0xf9, 0x7b, 0x3e,
+ 0xe4, 0x95, 0xd9, 0xa8, 0x79, 0x48, 0x51, 0x00,
+ 0xbe, 0xa4, 0xb6, 0x96, 0x7f, 0x3d, 0xfd, 0x76,
+ 0xa6, 0xb7, 0xbb, 0xb9, 0x77, 0xdc, 0x54, 0xfb,
+ 0x52, 0x9c, 0x79, 0x8f, 0xed, 0xd4, 0xb1, 0xbc,
+ 0x0f, 0x7e, 0xb1, 0x7e, 0x70, 0x6d, 0xfc, 0xb9,
+ 0x7e, 0x66, 0x9a, 0x86, 0x23, 0x3a, 0x98, 0x5e,
+ 0x32, 0x8d, 0x75, 0x18, 0x54, 0x64, 0x36, 0xdd,
+ 0x92, 0x01, 0x39, 0x90, 0xb9, 0xe3, 0xaf, 0x6f,
+ 0x98, 0xa5, 0xc0, 0x80, 0xc6, 0x2f, 0xa1, 0x02,
+ 0xad, 0x8d, 0xf4, 0xd6, 0x66, 0x7b, 0x45, 0xe5,
+ 0x74, 0x18, 0xb1, 0x27, 0x24, 0x01, 0x1e, 0xea,
+ 0xd8, 0xf3, 0x79, 0x92, 0xe9, 0x03, 0xf5, 0x57,
+ 0x8d, 0x65, 0x2a, 0x8d, 0x1b, 0xf0, 0xda, 0x58,
+ 0x3f, 0x58, 0xa0, 0xf4, 0xb4, 0xbe, 0xcb, 0x21,
+ 0x66, 0xe9, 0x21, 0x7c, 0x76, 0xf3, 0xc1, 0x7e,
+ 0x2e, 0x7c, 0x3d, 0x61, 0x20, 0x1d, 0xc5, 0xc0,
+ 0x71, 0x28, 0x2e, 0xb7, 0x0f, 0x1f, 0x7a, 0xc1,
+ 0xd3, 0x6a, 0x1e, 0xa3, 0x54, 0x34, 0x8e, 0x0d,
+ 0xd7, 0x96, 0x93, 0x78, 0x50, 0xc1, 0xee, 0x27,
+ 0x72, 0x3a, 0xbd, 0x57, 0x22, 0xf0, 0xd7, 0x6d,
+ 0x9d, 0x65, 0xc4, 0x07, 0x9c, 0x82, 0xa6, 0xd4,
+ 0xf7, 0x6b, 0x9a, 0xe9, 0xc0, 0x6c, 0x4a, 0x4f,
+ 0x6f, 0xbe, 0x8e, 0x01, 0x37, 0x50, 0x3a, 0x66,
+ 0xd9, 0xe9, 0xd9, 0xf9, 0x06, 0x9e, 0x00, 0xa9,
+ 0x84, 0xa0, 0x18, 0xb3, 0x44, 0x21, 0x24, 0xa3,
+ 0x6c, 0xcd, 0xb7, 0x0f, 0x31, 0x2a, 0xe8, 0x15,
+ 0xb6, 0x93, 0x6f, 0xb9, 0x86, 0xe5, 0x28, 0x01,
+ 0x1a, 0x5e, 0x10, 0x3f, 0x1f, 0x4d, 0x35, 0xa2,
+ 0x8d, 0xb8, 0x54, 0x26, 0x68, 0x3a, 0xcd, 0xcb,
+ 0x5f, 0xfa, 0x37, 0x4a, 0x60, 0x10, 0xb1, 0x0a,
+ 0xfe, 0xba, 0x9b, 0x96, 0x5d, 0x7e, 0x99, 0xcf,
+ 0x01, 0x98, 0x65, 0x87, 0xad, 0x40, 0xd5, 0x82,
+ 0x1d, 0x61, 0x54, 0xa2, 0xd3, 0x16, 0x3e, 0xf7,
+ 0xe3, 0x05, 0x89, 0x8d, 0x8a, 0x50, 0x87, 0x47,
+ 0xbe, 0x29, 0x18, 0x01, 0xb7, 0xc3, 0xdd, 0x43,
+ 0x23, 0x7a, 0xcd, 0x85, 0x1d, 0x4e, 0xa9, 0xc0,
+ 0x1a, 0xa4, 0x77, 0xab, 0xe7, 0x31, 0x9a, 0x33,
+ 0x1b, 0x7a, 0x86, 0xe1, 0xe5, 0xca, 0x0c, 0x43,
+ 0x1a, 0xfa, 0xec, 0x4c, 0x05, 0xc6, 0xd1, 0x43,
+ 0x12, 0xf9, 0x4d, 0x3e, 0xf7, 0xd6, 0x05, 0x9c,
+ 0x1c, 0xdd, /* end of cert_rx */
+
+ 0xe1, 0x7a, 0xb0, 0xfd, 0x0f, 0x54, 0x40, 0x52, /* rrx */
+ 0x02, 0x00, 0x02 /* RxCaps */
+};
+#endif
+
+#ifdef TEST_VECTOR_1
+uint8_t msg_rx_receiver_info[6] = {
+ AKE_RECEIVER_INFO,
+ 0x00, 0x06,
+ 0x01,
+ 0x00,
+ LC_PRECOMPUTE_SUPPORT
+};
+#else
+uint8_t msg_rx_receiver_info[6] = {
+ AKE_RECEIVER_INFO,
+ 0x00, 0x06,
+ 0x01,
+ 0x00,
+ LC_PRECOMPUTE_SUPPORT
+ /* LC_PRECOMPUTE_NOT_SUPPORT */
+};
+#endif
+
+#ifdef TEST_VECTOR_1
+uint8_t msg_rx_send_rrx[9] = {
+ AKE_SEND_RRX,
+ 0x3b, 0xa0, 0xbe, 0xde, 0x0c, 0x46, 0xa9, 0x91};
+#else
+uint8_t msg_rx_send_rrx[9] = {
+ AKE_SEND_RRX,
+ 0xe1, 0x7a, 0xb0, 0xfd, 0x0f, 0x54, 0x40, 0x52};
+#endif
+
+#ifdef TEST_VECTOR_1
+uint8_t msg_rx_send_h_prime[33] = {
+ AKE_SEND_H_PRIME,
+ 0xc3, 0xc0, 0x39, 0x2d, 0xc8, 0x66, 0xa2, 0xc3,
+ 0x98, 0x07, 0xb4, 0xbc, 0x3c, 0xbb, 0x7a, 0xd0,
+ 0xe6, 0x1f, 0x49, 0xd5, 0xe7, 0x04, 0x7e, 0x9a,
+ 0xea, 0x8c, 0xac, 0xf9, 0xd7, 0xc8, 0xcd, 0x89};
+
+uint8_t msg_rx_send_h_prime_v22[32] = {
+ 0x2e, 0xf5, 0xed, 0xf8, 0x7f, 0xd8, 0xa3, 0xd0,
+ 0xf4, 0xa9, 0xd8, 0xac, 0x3a, 0xd0, 0xb4, 0x56,
+ 0x2e, 0x32, 0x19, 0x11, 0x41, 0x16, 0xf1, 0xef,
+ 0x0f, 0x02, 0x3d, 0x3a, 0x78, 0xe2, 0x2a, 0xc6};
+#else
+uint8_t msg_rx_send_h_prime[33] = {
+ AKE_SEND_H_PRIME,
+ 0xee, 0x6f, 0x40, 0x74, 0xeb, 0x1b, 0xd0, 0x7b,
+ 0x35, 0x15, 0xb0, 0xf8, 0x28, 0x6a, 0xb5, 0x66,
+ 0x96, 0xe9, 0x39, 0x2b, 0xd7, 0x62, 0xbe, 0xd4,
+ 0x6a, 0x92, 0xd8, 0xd0, 0xa4, 0x18, 0x4d, 0x42};
+
+uint8_t msg_rx_send_h_prime_v22[32] = {
+ 0x82, 0xb8, 0x1a, 0xca, 0xed, 0xfc, 0x87, 0x72,
+ 0x7d, 0x17, 0x23, 0x53, 0xcb, 0x81, 0x83, 0xbf,
+ 0xdb, 0xba, 0xfb, 0x90, 0xb2, 0x4e, 0x96, 0xfe,
+ 0xba, 0x6d, 0xad, 0x67, 0xaa, 0x2b, 0x2a, 0x56};
+#endif
+
+#ifdef TEST_VECTOR_1
+uint8_t msg_rx_send_pairing_info[17] = {
+ AKE_SEND_PAIRING_INFO,
+ 0xce, 0x82, 0xf8, 0x36, 0x56, 0xcb, 0xbb, 0xaf,
+ 0x40, 0xba, 0x83, 0x17, 0x8c, 0xd3, 0xa4, 0xa6};
+
+uint8_t msg_rx_send_pairing_info_v22[16] = {
+ 0xb8, 0x9f, 0xf9, 0x72, 0x6a, 0x6f, 0x2c, 0x1e,
+ 0x29, 0xb6, 0x44, 0x8d, 0xdc, 0xa3, 0x10, 0xbd};
+#else
+uint8_t msg_rx_send_pairing_info[17] = {
+ AKE_SEND_PAIRING_INFO,
+ 0x2e, 0xec, 0xe5, 0x58, 0xe7, 0x8f, 0x1a, 0x96,
+ 0xd3, 0xbd, 0x40, 0x14, 0xa6, 0x7e, 0x29, 0x3a};
+
+uint8_t msg_rx_send_pairing_info_v22[16] = {
+ 0xe6, 0x57, 0x8e, 0xbc, 0xc7, 0x68, 0x44, 0x87,
+ 0x88, 0x8a, 0x9b, 0xd7, 0xd6, 0xae, 0x38, 0xbe};
+#endif
+
+#ifdef TEST_VECTOR_1
+uint8_t msg_rx_lc_send_l_prime[33] = {
+ LC_SEND_L_PRIME,
+ 0x1b, 0x57, 0x26, 0xde, 0xb5, 0x65, 0x1c, 0x77,
+ 0x31, 0x70, 0xd0, 0x09, 0x4a, 0x14, 0xeb, 0x0d,
+ 0x1f, 0x1c, 0xab, 0xa9, 0xfe, 0x84, 0xfd, 0xd4,
+ 0xeb, 0x17, 0x52, 0xe3, 0xe8, 0xd0, 0xd6, 0x36};
+
+uint8_t msg_rx_lc_send_l_prime_v22[32] = {
+ 0xbc, 0x20, 0x92, 0x33, 0x54, 0x91, 0xc1, 0x9e,
+ 0xa4, 0xde, 0x8b, 0x30, 0x49, 0xc2, 0x06, 0x6a,
+ 0xd8, 0x11, 0xa2, 0x2a, 0xb1, 0x46, 0xdf, 0x74,
+ 0x58, 0x47, 0x05, 0xa8, 0xb7, 0x67, 0xfb, 0xdd};
+#else
+uint8_t msg_rx_lc_send_l_prime[33] = {
+ LC_SEND_L_PRIME,
+ 0x19, 0x16, 0xb1, 0x59, 0x73, 0xbe, 0xe3, 0x67,
+ 0xf0, 0x56, 0x50, 0x51, 0x44, 0x0f, 0x53, 0xa2,
+ 0xdf, 0x53, 0x8d, 0xce, 0xe2, 0x58, 0x1f, 0x65,
+ 0xf3, 0xbf, 0x03, 0x0e, 0x68, 0x14, 0xe0, 0xe4};
+
+uint8_t msg_rx_lc_send_l_prime_v22[32] = {
+ 0xf2, 0x0f, 0x13, 0x6e, 0x85, 0x53, 0xc1, 0x0c,
+ 0xd3, 0xdd, 0xb2, 0xf9, 0x6d, 0x33, 0x31, 0xf9,
+ 0xcb, 0x6e, 0x97, 0x8c, 0xcd, 0x5e, 0xda, 0x13,
+ 0xdd, 0xea, 0x41, 0x44, 0x10, 0x9b, 0x51, 0xb0};
+#endif
+
+#ifdef TEST_VECTOR_1
+uint8_t msg_rx_rtt_ready[1] = {RTT_READY};
+#else
+uint8_t msg_rx_rtt_ready[1] = {RTT_READY};
+#endif
+
+#ifdef TEST_VECTOR_1
+/* should enter the test vector of master key in trustlet */
+uint8_t tv_emkey[128] = {
+ 0x75, 0xd1, 0x07, 0xf6, 0x9b, 0x7f, 0x1e, 0xbd,
+ 0x84, 0x2a, 0x33, 0xe2, 0x89, 0x03, 0x75, 0xb1,
+ 0x27, 0x3c, 0xc2, 0xf1, 0xda, 0xf8, 0x76, 0x94,
+ 0x9b, 0xe0, 0x5e, 0x35, 0xa4, 0xb3, 0x32, 0xa0,
+ 0xb5, 0xea, 0x75, 0xef, 0x6f, 0x3a, 0xd8, 0x31,
+ 0x3a, 0xdd, 0xc5, 0x9b, 0xde, 0xa3, 0xbb, 0x00,
+ 0x39, 0x29, 0x48, 0x93, 0x76, 0x2a, 0xe9, 0xe1,
+ 0xb5, 0x17, 0x0c, 0x64, 0x6b, 0xd4, 0x12, 0x8f,
+ 0x9b, 0xe1, 0x07, 0xb5, 0xa7, 0x9e, 0xd6, 0xfd,
+ 0x6e, 0x28, 0xc8, 0x5b, 0xd0, 0xc4, 0x01, 0xe7,
+ 0x69, 0xf4, 0x70, 0xab, 0xb8, 0x91, 0x2a, 0x31,
+ 0x4b, 0x86, 0xfd, 0x96, 0x80, 0x20, 0x19, 0x7b,
+ 0x73, 0xad, 0x7e, 0x78, 0xae, 0xe1, 0x71, 0x07,
+ 0x07, 0x50, 0x2d, 0x3f, 0x43, 0xff, 0xd4, 0x50,
+ 0x4e, 0xd7, 0x70, 0xfe, 0xcf, 0xf2, 0x25, 0x82,
+ 0xba, 0x43, 0x9e, 0x61, 0xd6, 0xf5, 0x02, 0x84};
+
+uint8_t tv_rrx[8] = {
+ 0x3b, 0xa0, 0xbe, 0xde, 0x0c, 0x46, 0xa9, 0x91};
+
+uint8_t tv_hmac_rrx[32] = {
+ 0xc3, 0xc0, 0x39, 0x2d, 0xc8, 0x66, 0xa2, 0xc3,
+ 0x98, 0x07, 0xb4, 0xbc, 0x3c, 0xbb, 0x7a, 0xd0,
+ 0xe6, 0x1f, 0x49, 0xd5, 0xe7, 0x04, 0x7e, 0x9a,
+ 0xea, 0x8c, 0xac, 0xf9, 0xd7, 0xc8, 0xcd, 0x89};
+
+uint8_t tv_pairing_ekh[16] = {
+ 0xce, 0x82, 0xf8, 0x36, 0x56, 0xcb, 0xbb, 0xaf,
+ 0x40, 0xba, 0x83, 0x17, 0x8c, 0xd3, 0xa4, 0xa6};
+
+/* todo: need to check */
+uint8_t tv_pairing_m[16] = {
+ 0x18, 0xfa, 0xe4, 0x20, 0x6a, 0xfb, 0x51, 0x49,
+ 0x3b, 0xa0, 0xbe, 0xde, 0x0c, 0x46, 0xa9, 0x91};
+
+uint8_t tv_lc_hmac[32] = {
+ 0x1b, 0x57, 0x26, 0xde, 0xb5, 0x65, 0x1c, 0x77,
+ 0x31, 0x70, 0xd0, 0x09, 0x4a, 0x14, 0xeb, 0x0d,
+ 0x1f, 0x1c, 0xab, 0xa9, 0xfe, 0x84, 0xfd, 0xd4,
+ 0xeb, 0x17, 0x52, 0xe3, 0xe8, 0xd0, 0xd6, 0x36};
+
+uint8_t tv_lc_lsb16_hmac[32] = {
+ 0x1f, 0x1c, 0xab, 0xa9, 0xfe, 0x84, 0xfd, 0xd4,
+ 0xeb, 0x17, 0x52, 0xe3, 0xe8, 0xd0, 0xd6, 0x36};
+
+uint8_t tv_eskey[16] = {
+ 0xcb, 0x92, 0xf6, 0x2a, 0x0a, 0x24, 0x29, 0x4f,
+ 0x7e, 0x5f, 0x6a, 0x69, 0xc7, 0xa2, 0xeb, 0x05};
+
+uint8_t tv_plain[32] = {
+ 0x00, 0x00, 0x01, 0x00, 0x01, 0x1b, 0x3c, 0x5b,
+ 0xb8, 0x00, 0x00, 0x00, 0x01, 0xb5, 0x85, 0x44,
+ 0x3b, 0x98, 0x00, 0x00, 0x00, 0x00, 0x01, 0xb2,
+ 0x44, 0x54, 0x47, 0x31, 0x41, 0xfe, 0x00, 0x00};
+
+uint8_t tv_cipher[32] = {
+ 0x21, 0x8b, 0x92, 0xa3, 0x28, 0xc9, 0x84, 0x36,
+ 0x17, 0x46, 0x4e, 0xd8, 0x68, 0x7a, 0x67, 0xb0,
+ 0xeb, 0x66, 0x72, 0x30, 0x24, 0x5b, 0x70, 0x2a,
+ 0x25, 0x86, 0xab, 0x4a, 0x7a, 0x9a, 0x3a, 0x4f};
+
+uint8_t tv_emkey_v22[128] = {
+ 0x9b, 0x9f, 0x80, 0x19, 0xad, 0x0e, 0xa2, 0xf0,
+ 0xdd, 0xa0, 0x29, 0x33, 0xd9, 0x6d, 0x1c, 0x77,
+ 0x31, 0x37, 0x57, 0xe0, 0xe5, 0xb2, 0xbd, 0xdd,
+ 0x36, 0x3e, 0x38, 0x4e, 0x7d, 0x40, 0x78, 0x66,
+ 0x97, 0x7a, 0x4c, 0xce, 0xc5, 0xc7, 0x5d, 0x01,
+ 0x57, 0x26, 0xcc, 0xa2, 0xf6, 0xde, 0x34, 0xdd,
+ 0x29, 0xbe, 0x5e, 0x31, 0xe8, 0xf1, 0x34, 0xe8,
+ 0x1a, 0x63, 0xa3, 0x6d, 0x46, 0xdc, 0x0a, 0x06,
+ 0x08, 0x99, 0x9d, 0xdb, 0x3c, 0xa2, 0x9c, 0x04,
+ 0xdd, 0x4e, 0xd9, 0x02, 0x7d, 0x20, 0x54, 0xec,
+ 0xca, 0x86, 0x42, 0x1b, 0x18, 0xda, 0x30, 0x9c,
+ 0xc4, 0xcb, 0xac, 0xb4, 0x54, 0xde, 0x84, 0x68,
+ 0x71, 0x53, 0x6d, 0x92, 0x17, 0xca, 0x08, 0x8a,
+ 0x7a, 0xf9, 0x98, 0x9a, 0xb6, 0x7b, 0x22, 0x92,
+ 0xac, 0x7d, 0x0d, 0x6b, 0xd6, 0x7f, 0x31, 0xab,
+ 0xf0, 0x10, 0xc5, 0x2a, 0x0f, 0x6d, 0x27, 0xa0};
+
+uint8_t tv_pairing_ekh_v22[16] = {
+ 0xb8, 0x9f, 0xf9, 0x72, 0x6a, 0x6f, 0x2c, 0x1e,
+ 0x29, 0xb6, 0x44, 0x8d, 0xdc, 0xa3, 0x10, 0xbd};
+
+uint8_t tv_pairing_m_v22[16] = {
+ 0x18, 0xfa, 0xe4, 0x20, 0x6a, 0xfb, 0x51, 0x49,
+ 0x3b, 0xa0, 0xbe, 0xde, 0x0c, 0x46, 0xa9, 0x91};
+
+uint8_t tv_ske_eskey_v22[16] = {
+ 0x4c, 0x32, 0x47, 0x12, 0xc4, 0xbe, 0xc6, 0x69,
+ 0x0a, 0xc2, 0x19, 0x64, 0xde, 0x91, 0xf1, 0x83};
+
+uint8_t tv_rcvid_list_v22[36] = {
+ 0x02, 0x31, /* RxInfo */
+ 0x00, 0x00, 0x00, /* seq_num_V */
+ 0xbc, 0xcc, 0x7d, 0x16, 0xe6, 0xbc, 0xb9, 0x02, /* V' */
+ 0x60, 0x08, 0x1d, 0xf7, 0x4a, 0xb4, 0x5c, 0x8a,
+ 0x47, 0x8e, 0x71, 0xe2, 0x0f, 0x35, 0x79, 0x6a, /* Receiver id */
+ 0x17, 0x0e, 0x74, 0xe8, 0x53, 0x97, 0xa2};
+
+uint8_t tv_rpauth_v_v22[16] = {
+ 0x63, 0x6d, 0xc5, 0x08, 0x4d, 0x6c, 0xb1, 0x0e,
+ 0x93, 0xa5, 0x28, 0x67, 0x0f, 0x34, 0x1f, 0x88};
+
+uint8_t tv_rpauth_stream_manage_v22[7] = {
+ 0x00, 0x00, 0x00, /* seq_num_M */
+ 0x00, 0x01, /* k */
+ 0x00, 0x01};
+
+uint8_t tv_rpauth_stream_ready_v22[32] = {
+ 0xdd, 0x26, 0xe9, 0x52, 0x6e, 0x0e, 0x1d, 0x69,
+ 0xc8, 0x84, 0xe4, 0xcc, 0xc8, 0x09, 0xaa, 0xc7,
+ 0x71, 0xe9, 0x97, 0xb5, 0x61, 0x89, 0x09, 0x6e,
+ 0x4d, 0x94, 0x24, 0xc2, 0x1b, 0x64, 0x58, 0xc6};
+#else
+uint8_t tv_emkey[128] = {
+ 0x78, 0x73, 0x6b, 0x24, 0xd6, 0x26, 0xfd, 0x11,
+ 0x36, 0xb5, 0x55, 0x5a, 0xa8, 0xbe, 0x46, 0x9e,
+ 0x69, 0xa1, 0xef, 0x19, 0xde, 0xd2, 0x43, 0x33,
+ 0x7b, 0xe7, 0xe8, 0x88, 0xe2, 0x8e, 0xd1, 0x6f,
+ 0x95, 0xb3, 0x56, 0xb7, 0xa0, 0xac, 0x62, 0x26,
+ 0x57, 0x03, 0x69, 0x03, 0xf9, 0x5c, 0x8b, 0x1d,
+ 0x6a, 0xd5, 0xab, 0xf9, 0x8f, 0x7a, 0x71, 0x51,
+ 0xd6, 0x73, 0x22, 0x9a, 0xcd, 0x51, 0x7a, 0x72,
+ 0x29, 0x3f, 0xd3, 0xfe, 0xfb, 0xbf, 0xf0, 0x74,
+ 0x89, 0x09, 0xcb, 0xc9, 0xcd, 0x57, 0xbb, 0x4a,
+ 0x83, 0x94, 0x01, 0xf1, 0x9e, 0x1f, 0x97, 0xe1,
+ 0x50, 0x84, 0x5c, 0xd8, 0xb5, 0xb0, 0xe1, 0xab,
+ 0xf1, 0x15, 0x19, 0x63, 0x29, 0x4f, 0x37, 0x3b,
+ 0xa1, 0xec, 0x14, 0x40, 0xbf, 0xdb, 0x33, 0xbb,
+ 0x46, 0xda, 0xf8, 0x3c, 0xa4, 0x73, 0x7e, 0xba,
+ 0x97, 0x2a, 0x18, 0x57, 0x6b, 0xd6, 0xf8, 0x58};
+
+uint8_t tv_rrx[8] = {
+ 0xe1, 0x7a, 0xb0, 0xfd, 0x0f, 0x54, 0x40, 0x52};
+
+uint8_t tv_hmac_rrx[32] = {
+ 0xee, 0x6f, 0x40, 0x74, 0xeb, 0x1b, 0xd0, 0x7b,
+ 0x35, 0x15, 0xb0, 0xf8, 0x28, 0x6a, 0xb5, 0x66,
+ 0x96, 0xe9, 0x39, 0x2b, 0xd7, 0x62, 0xbe, 0xd4,
+ 0x6a, 0x92, 0xd8, 0xd0, 0xa4, 0x18, 0x4d, 0x42};
+
+uint8_t tv_pairing_ekh[16] = {
+ 0x2e, 0xec, 0xe5, 0x58, 0xe7, 0x8f, 0x1a, 0x96,
+ 0xd3, 0xbd, 0x40, 0x14, 0xa6, 0x7e, 0x29, 0x3a};
+
+uint8_t tv_pairing_m[16] = {
+ 0xf9, 0xf1, 0x30, 0xa8, 0x2d, 0x5b, 0xe5, 0xc3,
+ 0xe1, 0x7a, 0xb0, 0xfd, 0x0f, 0x54, 0x40, 0x52};
+
+uint8_t tv_lc_hmac[32] = {
+ 0x19, 0x16, 0xb1, 0x59, 0x73, 0xbe, 0xe3, 0x67,
+ 0xf0, 0x56, 0x50, 0x51, 0x44, 0x0f, 0x53, 0xa2,
+ 0xdf, 0x53, 0x8d, 0xce, 0xe2, 0x58, 0x1f, 0x65,
+ 0xf3, 0xbf, 0x03, 0x0e, 0x68, 0x14, 0xe0, 0xe4};
+
+uint8_t tv_lc_lsb16_hmac[32] = {
+ 0xdf, 0x53, 0x8d, 0xce, 0xe2, 0x58, 0x1f, 0x65,
+ 0xf3, 0xbf, 0x03, 0x0e, 0x68, 0x14, 0xe0, 0xe4};
+
+uint8_t tv_eskey[16] = {
+ 0xa5, 0xdb, 0xc5, 0x98, 0x50, 0xb1, 0xe4, 0x62,
+ 0x09, 0x7d, 0x14, 0x49, 0xcb, 0x01, 0x44, 0x24};
+
+uint8_t tv_plain[32] = {
+ 0x00, 0x00, 0x01, 0x00, 0x01, 0x1b, 0x3c, 0x5b,
+ 0xb8, 0x00, 0x00, 0x00, 0x01, 0xb5, 0x85, 0x44,
+ 0x3b, 0x98, 0x00, 0x00, 0x00, 0x00, 0x01, 0xb2,
+ 0x44, 0x54, 0x47, 0x31, 0x41, 0xfe, 0x00, 0x00};
+
+uint8_t tv_cipher[32] = {
+ 0x21, 0x8b, 0x92, 0xa3, 0x28, 0xc9, 0x84, 0x36,
+ 0x17, 0x46, 0x4e, 0xd8, 0x68, 0x7a, 0x67, 0xb0,
+ 0xeb, 0x66, 0x72, 0x30, 0x24, 0x5b, 0x70, 0x2a,
+ 0x25, 0x86, 0xab, 0x4a, 0x7a, 0x9a, 0x3a, 0x4f};
+
+uint8_t tv_emkey_v22[128] = {
+ 0xa8, 0x55, 0xc2, 0xc4, 0xc6, 0xbe, 0xef, 0xcd,
+ 0xcb, 0x9f, 0xe3, 0x9f, 0x2a, 0xb7, 0x29, 0x76,
+ 0xfe, 0xd8, 0xda, 0xc9, 0x38, 0xfa, 0x39, 0xf0,
+ 0xab, 0xca, 0x8a, 0xed, 0x95, 0x7b, 0x93, 0xb2,
+ 0xdf, 0xd0, 0x7d, 0x09, 0x9d, 0x05, 0x96, 0x66,
+ 0x03, 0x6e, 0xba, 0xe0, 0x63, 0x0f, 0x30, 0x77,
+ 0xc2, 0xbb, 0xe2, 0x11, 0x39, 0xe5, 0x27, 0x78,
+ 0xee, 0x64, 0xf2, 0x85, 0x36, 0x57, 0xc3, 0x39,
+ 0xd2, 0x7b, 0x79, 0x03, 0xb7, 0xcc, 0x82, 0xcb,
+ 0xf0, 0x62, 0x82, 0x43, 0x38, 0x09, 0x9b, 0x71,
+ 0xaa, 0x38, 0xa6, 0x3f, 0x48, 0x12, 0x6d, 0x8c,
+ 0x5e, 0x07, 0x90, 0x76, 0xac, 0x90, 0x99, 0x51,
+ 0x5b, 0x06, 0xa5, 0xfa, 0x50, 0xe4, 0xf9, 0x25,
+ 0xc3, 0x07, 0x12, 0x37, 0x64, 0x92, 0xd7, 0xdb,
+ 0xd3, 0x34, 0x1c, 0xe4, 0xfa, 0xdd, 0x09, 0xe6,
+ 0x28, 0x3d, 0x0c, 0xad, 0xa9, 0xd8, 0xe1, 0xb5};
+
+uint8_t tv_pairing_ekh_v22[16] = {
+ 0xe6, 0x57, 0x8e, 0xbc, 0xc7, 0x68, 0x44, 0x87,
+ 0x88, 0x8a, 0x9b, 0xd7, 0xd6, 0xae, 0x38, 0xbe};
+
+uint8_t tv_pairing_m_v22[16] = {
+ 0xf9, 0xf1, 0x30, 0xa8, 0x2d, 0x5b, 0xe5, 0xc3,
+ 0xe1, 0x7a, 0xb0, 0xfd, 0x0f, 0x54, 0x40, 0x52};
+
+uint8_t tv_ske_eskey_v22[16] = {
+ 0xb6, 0x8b, 0x8a, 0xa4, 0xd2, 0xcb, 0xba, 0xff,
+ 0x53, 0x33, 0xc1, 0xd9, 0xbb, 0xb7, 0x10, 0xa9};
+
+#endif
+
+#endif
+
--- /dev/null
+/*
+ * drivers/soc/samsung/exynos-hdcp/exynos-hdcp.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/module.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/smc.h>
+#include <asm/cacheflush.h>
+#include <linux/exynos_ion.h>
+#include <linux/smc.h>
+#if defined(CONFIG_ION)
+#include <linux/ion.h>
+#endif
+#include "iia_link/exynos-hdcp2-iia-auth.h"
+#include "exynos-hdcp2-teeif.h"
+#include "iia_link/exynos-hdcp2-iia-selftest.h"
+#include "exynos-hdcp2-encrypt.h"
+#include "exynos-hdcp2-log.h"
+#include "dp_link/exynos-hdcp2-dplink-if.h"
+#include "dp_link/exynos-hdcp2-dplink.h"
+#include "dp_link/exynos-hdcp2-dplink-selftest.h"
+
+#define EXYNOS_HDCP_DEV_NAME "hdcp2"
+
+struct miscdevice hdcp;
+static DEFINE_MUTEX(hdcp_lock);
+struct hdcp_session_list g_hdcp_session_list;
+enum hdcp_result hdcp_link_ioc_authenticate(void);
+
+
+static uint32_t inst_num;
+
+static long hdcp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int rval;
+
+ switch (cmd) {
+#if defined(CONFIG_HDCP2_IIA_ENABLE)
+ case (uint32_t)HDCP_IOC_SESSION_OPEN:
+ {
+ struct hdcp_sess_info ss_info;
+
+ rval = copy_from_user(&ss_info, (void __user *)arg, sizeof(struct hdcp_sess_info));
+ if (rval) {
+ hdcp_err("Session open copy from user fail. (%x)\n", rval);
+ return HDCP_ERROR_COPY_FROM_USER_FAILED;
+ }
+
+ rval = hdcp_session_open(&ss_info);
+ if (rval) {
+ hdcp_err("Session open fail. (%x)\n", rval);
+ return rval;
+ }
+
+ rval = copy_to_user((void __user *)arg, &ss_info, sizeof(struct hdcp_sess_info));
+ if (rval) {
+ hdcp_err("Session open copy to user fail. (%x)\n", rval);
+ return HDCP_ERROR_COPY_TO_USER_FAILED;
+ }
+ break;
+ }
+ case (uint32_t)HDCP_IOC_SESSION_CLOSE:
+ {
+ /* todo: session close */
+ struct hdcp_sess_info ss_info;
+
+ rval = copy_from_user(&ss_info, (void __user *)arg, sizeof(struct hdcp_sess_info));
+ if (rval) {
+ hdcp_err("Session close copy from user fail. (%x)\n", rval);
+ return HDCP_ERROR_COPY_FROM_USER_FAILED;
+ }
+
+ rval = hdcp_session_close(&ss_info);
+ if (rval) {
+ hdcp_err("hdcp_session close fail (0x%08x)\n", rval);
+ return HDCP_ERROR_SESSION_CLOSE_FAILED;
+ }
+
+ break;
+ }
+ case (uint32_t)HDCP_IOC_LINK_OPEN:
+ {
+ struct hdcp_link_info lk_info;
+
+ rval = copy_from_user(&lk_info, (void __user *)arg, sizeof(struct hdcp_link_info));
+ if (rval) {
+ hdcp_err("hdcp_link open copy from user fail (0x%08x)\n", rval);
+ return HDCP_ERROR_COPY_FROM_USER_FAILED;
+ }
+
+ rval = hdcp_link_open(&lk_info, HDCP_LINK_TYPE_IIA);
+ if (rval) {
+ hdcp_err("hdcp_link open fail (0x%08x)\n", rval);
+ return HDCP_ERROR_LINK_OPEN_FAILED;
+ }
+
+ rval = copy_to_user((void __user *)arg, &lk_info, sizeof(struct hdcp_link_info));
+ if (rval) {
+ hdcp_err("hdcp_link open copy to user fail (0x%08x)\n", rval);
+ return HDCP_ERROR_COPY_TO_USER_FAILED;
+ }
+ break;
+ }
+ case (uint32_t)HDCP_IOC_LINK_CLOSE:
+ {
+ struct hdcp_link_info lk_info;
+
+ /* find Session node which contain the Link */
+ rval = copy_from_user(&lk_info, (void __user *)arg, sizeof(struct hdcp_link_info));
+ if (rval) {
+ hdcp_err("hdcp_link close copy from user fail (0x%08x)\n", rval);
+ return HDCP_ERROR_COPY_FROM_USER_FAILED;
+ }
+
+ rval = hdcp_link_close(&lk_info);
+ if (rval) {
+ hdcp_err("hdcp_link close fail (0x%08x)\n", rval);
+ return HDCP_ERROR_LINK_CLOSE_FAILED;
+ }
+
+ break;
+ }
+ case (uint32_t)HDCP_IOC_LINK_AUTH:
+ {
+ struct hdcp_msg_info msg_info;
+
+ rval = copy_from_user(&msg_info, (void __user *)arg, sizeof(struct hdcp_msg_info));
+ if (rval) {
+ hdcp_err("hdcp_authenticate fail (0x%08x)\n", rval);
+ return HDCP_ERROR_COPY_FROM_USER_FAILED;
+ }
+
+ rval = hdcp_link_authenticate(&msg_info);
+ if (rval) {
+ hdcp_err("hdcp_authenticate fail (0x%08x)\n", rval);
+ return HDCP_ERROR_AUTHENTICATE_FAILED;
+ }
+
+ rval = copy_to_user((void __user *)arg, &msg_info, sizeof(struct hdcp_msg_info));
+ if (rval) {
+ hdcp_err("hdcp_authenticate fail (0x%08x)\n", rval);
+ return HDCP_ERROR_COPY_TO_USER_FAILED;
+ }
+ break;
+ }
+ case (uint32_t)HDCP_IOC_LINK_ENC:
+ {
+ /* todo: link close */
+ struct hdcp_enc_info enc_info;
+ size_t packet_len = 0;
+ uint8_t pes_priv[HDCP_PRIVATE_DATA_LEN];
+ ion_phys_addr_t input_phys, output_phys;
+ struct hdcp_session_node *ss_node;
+ struct hdcp_link_node *lk_node;
+ struct hdcp_link_data *lk_data;
+ uint8_t *input_virt, *output_virt;
+ int ret = HDCP_SUCCESS;
+
+ /* find Session node which contain the Link */
+ rval = copy_from_user(&enc_info, (void __user *)arg, sizeof(struct hdcp_enc_info));
+ if (rval) {
+ hdcp_err("hdcp_encrypt copy from user fail (0x%08x)\n", rval);
+ return HDCP_ERROR_COPY_FROM_USER_FAILED;
+ }
+
+ /* find Session node which contains the Link */
+ ss_node = hdcp_session_list_find(enc_info.id, &g_hdcp_session_list);
+ if (!ss_node)
+ return HDCP_ERROR_INVALID_INPUT;
+
+ lk_node = hdcp_link_list_find(enc_info.id, &ss_node->ss_data->ln);
+ if (!lk_node)
+ return HDCP_ERROR_INVALID_INPUT;
+
+ lk_data = lk_node->lk_data;
+
+ if (!lk_data)
+ return HDCP_ERROR_INVALID_INPUT;
+
+ input_phys = (ion_phys_addr_t)enc_info.input_phys;
+ output_phys = (ion_phys_addr_t)enc_info.output_phys;
+
+ /* set input counters */
+ memset(&(lk_data->tx_ctx.input_ctr), 0x00, HDCP_INPUT_CTR_LEN);
+ /* set output counters */
+ memset(&(lk_data->tx_ctx.str_ctr), 0x00, HDCP_STR_CTR_LEN);
+
+ packet_len = (size_t)enc_info.input_len;
+ input_virt = (uint8_t *)phys_to_virt(input_phys);
+ output_virt = (uint8_t *)phys_to_virt(output_phys);
+
+ __flush_dcache_area(input_virt, packet_len);
+ __flush_dcache_area(output_virt, packet_len);
+
+ ret = encrypt_packet(pes_priv,
+ input_phys, packet_len,
+ output_phys, packet_len,
+ &(lk_data->tx_ctx));
+
+ if (ret) {
+ hdcp_err("encrypt_packet() is failed with 0x%x\n", ret);
+ return -1;
+ }
+
+ rval = copy_to_user((void __user *)arg, &enc_info, sizeof(struct hdcp_enc_info));
+ if (rval) {
+ hdcp_err("hdcp_encrypt copy to user fail (0x%08x)\n", rval);
+ return HDCP_ERROR_COPY_TO_USER_FAILED;
+ }
+ break;
+ }
+ case (uint32_t)HDCP_IOC_STREAM_MANAGE:
+ {
+ struct hdcp_stream_info stream_info;
+
+ rval = copy_from_user(&stream_info, (void __user *)arg, sizeof(struct hdcp_stream_info));
+ if (rval) {
+ hdcp_err("hdcp_link stream manage copy from user fail (0x%08x)\n", rval);
+ return HDCP_ERROR_COPY_FROM_USER_FAILED;
+ }
+
+ rval = hdcp_link_stream_manage(&stream_info);
+ if (rval) {
+ hdcp_err("hdcp_link stream manage fail (0x%08x)\n", rval);
+ return HDCP_ERROR_LINK_STREAM_FAILED;
+ }
+
+ rval = copy_to_user((void __user *)arg, &stream_info, sizeof(struct hdcp_stream_info));
+ if (rval) {
+ hdcp_err("hdcp_link stream manage copy to user fail (0x%08x)\n", rval);
+ return HDCP_ERROR_COPY_TO_USER_FAILED;
+ }
+ break;
+ }
+#endif
+#if defined(CONFIG_HDCP2_EMULATION_MODE)
+ case (uint32_t)HDCP_IOC_EMUL_DPLINK_TX:
+ {
+ uint32_t emul_cmd;
+
+ if (copy_from_user(&emul_cmd, (void __user *)arg, sizeof(uint32_t)))
+ return -EINVAL;
+
+ return dplink_emul_handler(emul_cmd);
+ }
+#endif
+ case (uint32_t)HDCP_IOC_DPLINK_TX_AUTH:
+ {
+#if defined(CONFIG_HDCP2_DP_ENABLE)
+ rval = dp_hdcp_protocol_self_test();
+ if (rval) {
+ hdcp_err("DP self_test fail. errno(%d)\n", rval);
+ return rval;
+ }
+ hdcp_err("DP self_test success!!\n");
+#endif
+#if defined(TEST_VECTOR_2)
+ /* todo: support test vector 1 */
+ rval = iia_hdcp_protocol_self_test();
+ if (rval) {
+ hdcp_err("IIA self_test failed. errno(%d)\n", rval);
+ return rval;
+ }
+ hdcp_err("IIA self_test success!!\n");
+#endif
+ rval = 0;
+ return rval;
+ }
+ case (uint32_t)HDCP_IOC_WRAP_KEY:
+ {
+ struct hdcp_wrapped_key key_info;
+
+ rval = copy_from_user(&key_info, (void __user *)arg, sizeof(struct hdcp_wrapped_key));
+ if (rval) {
+ hdcp_err("hdcp_wrap_key copy from user fail (0x%08x)\n", rval);
+ return HDCP_ERROR_COPY_FROM_USER_FAILED;
+ }
+
+ if (hdcp_wrap_key(&key_info))
+ return HDCP_ERROR_WRAP_FAIL;
+
+ rval = copy_to_user((void __user *)arg, &key_info, sizeof(struct hdcp_wrapped_key));
+ if (rval) {
+ hdcp_err("hdcp_wrap_key copy to user fail (0x%08x)\n", rval);
+ return HDCP_ERROR_COPY_TO_USER_FAILED;
+ }
+ break;
+ }
+
+ default:
+ hdcp_err("HDCP: Invalid IOC num(%d)\n", cmd);
+ return -ENOTTY;
+ }
+
+ return 0;
+}
+
+static int hdcp_open(struct inode *inode, struct file *file)
+{
+ struct miscdevice *miscdev = file->private_data;
+ struct device *dev = miscdev->this_device;
+ struct hdcp_info *info;
+
+ info = kzalloc(sizeof(struct hdcp_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->dev = dev;
+ file->private_data = info;
+
+ mutex_lock(&hdcp_lock);
+ inst_num++;
+ /* todo: hdcp device initialize ? */
+ mutex_unlock(&hdcp_lock);
+
+ return 0;
+}
+
+static int hdcp_release(struct inode *inode, struct file *file)
+{
+ struct hdcp_info *info = file->private_data;
+
+ /* disable drm if we were the one to turn it on */
+ mutex_lock(&hdcp_lock);
+ inst_num--;
+ /* todo: hdcp device finalize ? */
+ mutex_unlock(&hdcp_lock);
+
+ kfree(info);
+ return 0;
+}
+
+static int __init hdcp_init(void)
+{
+ int ret;
+
+ hdcp_info("hdcp2 driver init\n");
+
+ ret = misc_register(&hdcp);
+ if (ret) {
+ hdcp_err("hdcp can't register misc on minor=%d\n",
+ MISC_DYNAMIC_MINOR);
+ return ret;
+ }
+
+ /* todo: do initialize sequence */
+ hdcp_session_list_init(&g_hdcp_session_list);
+#if defined(CONFIG_HDCP2_DP_ENABLE)
+ if (hdcp_dplink_init() < 0) {
+ hdcp_err("hdcp_dplink_init fail\n");
+ return -EINVAL;
+ }
+#endif
+ ret = hdcp_tee_open();
+ if (ret) {
+ hdcp_err("hdcp_tee_open fail\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void __exit hdcp_exit(void)
+{
+ /* todo: do clear sequence */
+
+ misc_deregister(&hdcp);
+ hdcp_session_list_destroy(&g_hdcp_session_list);
+ hdcp_tee_close();
+}
+
+static const struct file_operations hdcp_fops = {
+ .owner = THIS_MODULE,
+ .open = hdcp_open,
+ .release = hdcp_release,
+ .compat_ioctl = hdcp_ioctl,
+ .unlocked_ioctl = hdcp_ioctl,
+};
+
+struct miscdevice hdcp = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = EXYNOS_HDCP_DEV_NAME,
+ .fops = &hdcp_fops,
+};
+
+module_init(hdcp_init);
+module_exit(hdcp_exit);
--- /dev/null
+/* driver/soc/samsung/exynos-hdcp/exynos-hdcp2.h
+ *
+ * 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.
+*/
+#ifndef __EXYNOS_HDCP2_H__
+#define __EXYNOS_HDCP2_H__
+
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+
+#include "exynos-hdcp2-session.h"
+
+#define HDCP_CMD_SESSION_OPEN 0x0001
+#define HDCP_CMD_SESSION_CLOSE 0x0002
+#define HDCP_CMD_LINK_OPEN 0x0003
+#define HDCP_CMD_LINK_CLOSE 0x0004
+#define HDCP_CMD_LINK_AUTH 0x0005
+#define HDCP_CMD_LINK_ENC 0x0006
+
+/* todo: define max message length based on HDCP spec */
+#define HDCP_PROTO_MSG_LEN_MAX 1024
+
+/* HDCP Link types */
+#define HDCP_LINK_TYPE_IIA 0
+#define HDCP_LINK_TYPE_DP 1
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define TEMP_ERROR -ENOTTY
+
+#define UPDATE_SESSION_STATE(sess, st) do { \
+ printk("[HDCP2]HDCP Session(%d): %s -> %s\n", sess->id, hdcp_session_st_str[sess->state], hdcp_session_st_str[st]); \
+ sess->state = st; \
+ } while (0)
+
+#define UPDATE_LINK_STATE(link, st) do { \
+ printk("[HDCP2]HDCP Link(%d): %s -> %s\n", link->id, hdcp_link_st_str[link->state], hdcp_link_st_str[st]); \
+ link->state = st; \
+ } while (0)
+
+#define UPDATE_STEP_STATE(step, st) do { \
+ printk("[HDCP2]HDCP STEP(%d): %s -> %s\n", st, hdcp_msgid_str[step], hdcp_msgid_str[st]); \
+ step = st; \
+ } while (0)
+
+enum {
+ SEND_MSG = 0,
+ RECIEVE_MSG = 1,
+ RP_SEND_MSG = 2,
+ RP_RECIEVE_MSG = 3,
+ ST_SEND_MSG = 4,
+ ST_RECIEVE_MSG = 5,
+ DONE = 6,
+ AUTH_FINISHED = 7,
+ RP_FINISHED = 8,
+ WAIT_STATE = 100
+};
+
+enum {
+ TX_AUTH_SUCCESS = 0,
+ TX_AUTH_ERROR_CONNECT_TEE,
+ TX_AUTH_ERROR_MAKE_PROTO_MSG,
+ TX_AUTH_ERROR_SEND_PROTO_MSG,
+ TX_AUTH_ERROR_RECV_PROTO_MSG,
+ TX_AUTH_ERROR_TIME_EXCEED,
+ TX_AUTH_ERROR_NET_TIMEOUT,
+ TX_AUTH_ERROR_NET_CONN_CLOSED,
+ TX_AUTH_ERROR_CRYPTO,
+ TX_AUTH_ERROR_WRONG_MSG_ID,
+ TX_AUTH_ERROR_WRONG_MSG,
+ TX_AUTH_ERROR_WRONG_MSG_SIZE,
+ TX_AUTH_ERROR_STORE_SKEY,
+ TX_AUTH_ERRRO_RESTORE_SKEY,
+ TX_AUTH_ERROR_BUFFER_OVERFLLOW,
+ TX_AUTH_ERROR_RETRYCOUNT_EXCEED,
+ TX_AUTH_ERROR_ABORT,
+};
+
+typedef enum hdcp_result {
+ HDCP_SUCCESS = 0,
+ HDCP_ERROR_INIT_FAILED,
+ HDCP_ERROR_TERMINATE_FAILED,
+ HDCP_ERROR_SESSION_OPEN_FAILED,
+ HDCP_ERROR_SESSION_CLOSE_FAILED,
+ HDCP_ERROR_LINK_OPEN_FAILED,
+ HDCP_ERROR_LINK_CLOSE_FAILED,
+ HDCP_ERROR_LINK_STREAM_FAILED,
+ HDCP_ERROR_AUTHENTICATE_FAILED,
+ HDCP_ERROR_COPY_TO_USER_FAILED,
+ HDCP_ERROR_COPY_FROM_USER_FAILED,
+ HDCP_ERROR_USER_FAILED,
+ HDCP_ERROR_RX_NOT_HDCP_CAPABLE,
+ HDCP_ERROR_EXCHANGE_KM,
+ HDCP_ERROR_LOCALITY_CHECK,
+ HDCP_ERROR_EXCHANGE_KS,
+ HDCP_ERROR_WAIT_RECEIVER_ID_LIST,
+ HDCP_ERROR_VERIFY_RECEIVER_ID_LIST,
+ HDCP_ERROR_WAIT_AKE_INIT,
+ HDCP_ERROR_MALLOC_FAILED = 0x1000,
+ HDCP_ERROR_INVALID_HANDLE,
+ HDCP_ERROR_INVALID_INPUT,
+ HDCP_ERROR_INVALID_STATE,
+ HDCP_ERROR_NET_UNREACHABLE,
+ HDCP_ERROR_NET_CLOSED,
+ HDCP_ERROR_ENCRYPTION,
+ HDCP_ERROR_DECRYPTION,
+ HDCP_ERROR_STREAM_MANAGE,
+ HDCP_ERROR_WRAP_FAIL,
+ HDCP_ERROR_UNWRAP_FAIL,
+ HDCP_ERROR_WRONG_SIZE,
+ HDCP_ERROR_DO_NOT_SUPPORT_YET,
+ HDCP_ERROR_IOCTL_OPEN,
+ HDCP_ERROR_END
+} hdcp_result;
+
+enum {
+ HDCP_ERROR_INVALID_SESSION_HANDLE = 0x2000,
+ HDCP_ERROR_INVALID_SESSION_STATE,
+ HDCP_ERROR_INVALID_STREAM_LEN,
+};
+
+struct hdcp_info {
+ struct device *dev;
+ struct hdcp_session_list ss_list;
+};
+
+struct hdcp_sess_info {
+ uint32_t ss_id;
+ uint8_t wkey[HDCP_WRAP_MAX_SIZE];
+};
+
+struct hdcp_link_info {
+ uint32_t ss_id;
+ uint32_t lk_id;
+};
+
+struct hdcp_link_auth {
+ uint32_t ss_id;
+ uint32_t lk_id;
+};
+
+struct hdcp_link_enc {
+ uint32_t ss_id;
+ uint32_t lk_id;
+};
+
+struct hdcp_msg_info {
+ uint32_t ss_handle;
+ uint32_t lk_id;
+ uint8_t msg[1024];
+ uint32_t msg_len;
+ uint32_t next_step;
+};
+
+struct hdcp_stream_info {
+ uint32_t ss_id;
+ uint32_t lk_id;
+ uint32_t num;
+ uint8_t type;
+ uint16_t stream_pid;
+ uint32_t stream_ctr;
+ uint8_t msg[1024];
+ uint32_t msg_len;
+ uint32_t next_step;
+};
+
+struct hdcp_enc_info {
+ uint32_t id;
+ uint8_t pes_private[16];
+ uint32_t priv_len;
+ uint8_t str_ctr[4];
+ uint8_t input_ctr[8];
+ uint64_t input;
+ unsigned long input_phys;
+ uint32_t input_len;
+ uint64_t output;
+ unsigned long output_phys;
+ uint32_t output_len;
+};
+
+struct hdcp_wrapped_key {
+ uint8_t key[16];
+ uint8_t enc_key[128];
+ uint32_t wrapped;
+ uint32_t key_len;
+};
+
+#define HDCP_IOC_SESSION_OPEN _IOWR('S', 1, struct hdcp_sess_info)
+#define HDCP_IOC_SESSION_CLOSE _IOWR('S', 2, struct hdcp_sess_info)
+#define HDCP_IOC_LINK_OPEN _IOWR('S', 3, struct hdcp_link_info)
+#define HDCP_IOC_LINK_CLOSE _IOWR('S', 4, struct hdcp_link_info)
+#define HDCP_IOC_LINK_AUTH _IOWR('S', 5, struct hdcp_msg_info)
+#define HDCP_IOC_LINK_ENC _IOWR('S', 6, struct hdcp_enc_info)
+#define HDCP_IOC_RESERVED_0 _IO('S', 7)
+#define HDCP_IOC_STREAM_MANAGE _IOWR('S', 8, struct hdcp_stream_info)
+#define HDCP_IOC_IIA_TX_SELFTEST _IOWR('S', 90, int)
+#define HDCP_IOC_DPLINK_TX_AUTH _IOWR('S', 100, int)
+#define HDCP_IOC_DPLINK_TX_EMUL _IOWR('S', 110, int)
+#define HDCP_IOC_DPLINK_TX_SELFTEST _IOWR('S', 120, int)
+#define HDCP_IOC_WRAP_KEY _IOWR('S', 200, struct hdcp_wrapped_key)
+
+typedef struct hdcp_tx_link_handle {
+ uint32_t ss_handle;
+ uint32_t lk_id;
+} hdcp_tx_link_handle_t;
+
+enum hdcp_result hdcp_session_open(struct hdcp_sess_info *ss_info);
+enum hdcp_result hdcp_session_close(struct hdcp_sess_info *ss_info);
+enum hdcp_result hdcp_link_open(struct hdcp_link_info *link_info, uint32_t lk_type);
+enum hdcp_result hdcp_link_close(struct hdcp_link_info *link_info);
+enum hdcp_result hdcp_link_authenticate(struct hdcp_msg_info *msg_info);
+enum hdcp_result hdcp_link_stream_manage(struct hdcp_stream_info *stream_info);
+enum hdcp_result hdcp_wrap_key(struct hdcp_wrapped_key *key_info);
+enum hdcp_result hdcp_unwrap_key(char *wkey);
+#endif
--- /dev/null
+/* todo: include/soc/samsung/hdcp2-if.h
+ *
+ * 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.
+*/
+#ifndef __HDCP2_IF_H__
+#define __HDCP2_IF_H__
+
+int exynos_hdcp2_authenticate(uint32_t *lk_id);
+int exynos_hdcp2_encrypt(uint32_t link_id);
+
+#endif
+
--- /dev/null
+/*
+ * 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 {
+ next_step++;
+ 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;
+}
--- /dev/null
+/*
+ * drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-tx-auth.h
+ *
+ * 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.
+ */
+#ifndef __HDCP_TX_AUTH_H__
+#define __HDCP_TX_AUTH_H__
+
+#include "../exynos-hdcp2.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ERR_WRONG_MESSAGE_LENGTH 0x1003
+#define ERR_WRONG_MESSAGE_ID 0x1004
+#define ERR_GENERATE_NON_SECKEY 0x1005
+#define ERR_FILE_OPEN 0x1006
+
+int determine_rx_hdcp_cap(struct hdcp_link_data *);
+int exchange_master_key(struct hdcp_link_data *, struct hdcp_msg_info *);
+int locality_check(struct hdcp_link_data *, struct hdcp_msg_info *);
+int exchange_hdcp_session_key(struct hdcp_link_data *, struct hdcp_msg_info *);
+int evaluate_repeater(struct hdcp_link_data *);
+int wait_for_receiver_id_list(struct hdcp_link_data *, struct hdcp_msg_info *);
+int send_receiver_id_list_ack(struct hdcp_link_data *, struct hdcp_msg_info *);
+int manage_content_stream(struct hdcp_link_data *lk, struct contents_info *stream_ctrl, struct hdcp_stream_info *stream_info);
+int unwrapped_key(char *key, int wrapped);
+
+/* todo */
+int determine_rx_hdcp_cap(struct hdcp_link_data *lk);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/*
+ * drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-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-testvector.h"
+#include "../exynos-hdcp2-misc.h"
+#include "../exynos-hdcp2-encrypt.h"
+#include "../exynos-hdcp2.h"
+#include "../exynos-hdcp2-log.h"
+
+#define AKE_INIT_LEN 9
+#define AKE_TRANSMITTER_INFO_LEN 6
+#define AKE_NO_STORED_KM_LEN 129
+#define AKE_STORED_KM_LEN 33
+#define AKE_SEND_PAIRING_INFO_LEN 17
+#define LC_INIT_LEN 9
+#define LC_RTT_CHALLENGE_LEN 17
+#define SKE_SEND_EKS_LEN 25
+
+struct hdcp_tx_ctx uc_tx_ctx;
+struct hdcp_rx_ctx uc_rx_ctx;
+
+/* Test HDCP Encryption */
+static int utc_encryption(struct hdcp_tx_ctx *tx_ctx, struct hdcp_rx_ctx *rx_ctx)
+{
+ uint8_t *input = NULL;
+ u64 input_phy = 0;
+ uint8_t *output = NULL;
+ u64 output_phy = 0;
+ int ret = 0;
+ size_t packet_len;
+ uint8_t pes_priv[HDCP_PRIVATE_DATA_LEN];
+
+ packet_len = sizeof(tv_plain);
+
+ /* Allocate enc in/out buffer for test */
+ input = (uint8_t *)kzalloc(packet_len, GFP_KERNEL);
+ if (!input) {
+ hdcp_err("alloc enc input buffer is failed\n");
+ return -ENOMEM;
+ }
+
+ output = (uint8_t *)kzalloc(packet_len, GFP_KERNEL);
+ if (!output) {
+ kfree(input);
+ hdcp_err("alloc enc input buffer is failed\n");
+ return -ENOMEM;
+ }
+
+ /* send physical address to SWd */
+ input_phy = virt_to_phys((void *)input);
+ output_phy = virt_to_phys((void *)output);
+
+ /* set input param */
+ memcpy(input, tv_plain, packet_len);
+ /* set input counters */
+ memset(&tx_ctx->input_ctr, 0x00, HDCP_INPUT_CTR_LEN);
+ /* set output counters */
+ memset(&tx_ctx->str_ctr, 0x00, HDCP_STR_CTR_LEN);
+
+ __flush_dcache_area(input, packet_len);
+ __flush_dcache_area(output, packet_len);
+ ret = encrypt_packet(pes_priv,
+ input_phy, packet_len,
+ output_phy, packet_len,
+ tx_ctx);
+ if (ret) {
+ kfree(input);
+ kfree(output);
+ hdcp_err("encrypt_packet() is failed with 0x%x\n", ret);
+ return -1;
+ }
+
+ if (memcmp(output, tv_cipher, packet_len)) {
+ hdcp_err("Wrong encrypted value.\n");
+ hdcp_err("expected:\n");
+ hdcp_hexdump(tv_cipher, packet_len);
+
+ hdcp_err("actual:\n");
+ hdcp_hexdump(output, packet_len);
+
+ kfree(input);
+ kfree(output);
+ return -1;
+ } else
+ hdcp_info("HDCP:Encryption success.\n");
+
+ kfree(input);
+ kfree(output);
+ return 0;
+}
+
+static int 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_IIA, tx_ctx, rx_ctx);
+ if (ret) {
+ hdcp_err("SKE_Send_Eks() is failed with 0x%x\n", ret);
+ return -1;
+ }
+
+ /* check message ID & length */
+ if (m[0] != 11) {
+ hdcp_err("Message ID ERROR\n");
+ return -1;
+ }
+
+ if (m_len != 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_eskey[i] != m[1+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 utc_ske(struct hdcp_tx_ctx *tx_ctx, struct hdcp_rx_ctx *rx_ctx, int *cnt, int *fail)
+{
+ return utc_ske_send_eks(tx_ctx, rx_ctx);
+}
+
+static int 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,
+ sizeof(msg_rx_send_h_prime),
+ HDCP_LINK_TYPE_IIA,
+ 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 utc_rtt_challenge(struct hdcp_tx_ctx *tx_ctx, struct hdcp_rx_ctx *rx_ctx)
+{
+ uint8_t m[525];
+ size_t m_len;
+ int ret;
+ int i;
+
+ ret = cap_protocol_msg(RTT_CHALLENGE, m, &m_len, HDCP_LINK_TYPE_IIA, tx_ctx, rx_ctx);
+ if (ret) {
+ hdcp_err("RTT_Challenge() is failed with 0x%x\n", ret);
+ return -1;
+ }
+
+ /* check message ID & length */
+ if (m[0] != 14) {
+ hdcp_err("Message ID ERROR\n");
+ return -1;
+ }
+
+ if (m_len != LC_RTT_CHALLENGE_LEN) {
+ hdcp_err("Message LENGTH ERROR\n");
+ return -1;
+ }
+
+ /* check ls128_hmac */
+ for (i = 0; i < HDCP_HMAC_SHA256_LEN/2; i++)
+ if (m[i+1] != tv_lc_lsb16_hmac[i])
+ break;
+
+ if (i != HDCP_HMAC_SHA256_LEN/2) {
+ hdcp_err("failed to compare ls128 hmac\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int utc_rtt_ready(struct hdcp_tx_ctx *tx_ctx, struct hdcp_rx_ctx *rx_ctx)
+{
+ int ret;
+
+ ret = decap_protocol_msg(RTT_READY, msg_rx_rtt_ready,
+ sizeof(msg_rx_rtt_ready),
+ HDCP_LINK_TYPE_IIA,
+ tx_ctx,
+ rx_ctx);
+ if (ret) {
+ hdcp_err("RTT_Ready() is failed with 0x%x\n", ret);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int 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;
+ int i;
+
+ ret = cap_protocol_msg(LC_INIT, m, &m_len, HDCP_LINK_TYPE_IIA, tx_ctx, rx_ctx);
+ if (ret) {
+ hdcp_err("LC_Init() is failed with 0x%x\n", ret);
+ return -1;
+ }
+
+ /* check message ID & length */
+ if (m[0] != 9) {
+ hdcp_err("Message ID ERROR\n");
+ return -1;
+ }
+
+ if (m_len != LC_INIT_LEN) {
+ hdcp_err("Message LENGTH ERROR\n");
+ return -1;
+ }
+
+ if ((rx_ctx->version != HDCP_VERSION_2_0)
+ && tx_ctx->lc_precomp
+ && rx_ctx->lc_precomp) {
+ for (i = 0; i < HDCP_HMAC_SHA256_LEN/2; i++)
+ if (tx_ctx->lsb16_hmac[i] != tv_lc_hmac[i+16])
+ break;
+ if (i != HDCP_HMAC_SHA256_LEN/2) {
+ hdcp_err("failed to compare lsb16 hmac\n");
+ return -1;
+ }
+ } else {
+ return 0;
+ }
+
+ return 0;
+}
+
+/* Test LC APIs */
+static int utc_lc(struct hdcp_tx_ctx *tx_ctx, struct hdcp_rx_ctx *rx_ctx,
+ int *cnt, int *fail)
+{
+ int ret;
+
+ ret = utc_lc_init(tx_ctx, rx_ctx);
+ if (ret < 0)
+ return ret;
+
+ ret = utc_lc_send_l_prime(tx_ctx, rx_ctx);
+ if (ret < 0)
+ return ret;
+
+ ret = utc_rtt_ready(tx_ctx, rx_ctx);
+ if (ret < 0)
+ return ret;
+
+ ret = utc_rtt_challenge(tx_ctx, rx_ctx);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int 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,
+ sizeof(msg_rx_send_h_prime),
+ HDCP_LINK_TYPE_IIA,
+ 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 utc_ake_send_rrx(struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ int ret;
+ int i;
+
+ ret = decap_protocol_msg(AKE_SEND_RRX, msg_rx_send_rrx, sizeof(msg_rx_send_rrx),
+ HDCP_LINK_TYPE_IIA, tx_ctx, rx_ctx);
+ if (ret) {
+ hdcp_err("make_AKE_Send_rrx() is failed with 0x%x\n", ret);
+ return -1;
+ }
+
+ /* compare rrx with test vector */
+ for (i = 0; i < HDCP_RRX_BYTE_LEN; i++)
+ if (rx_ctx->rrx[i] != tv_rrx[i])
+ break;
+
+ if (i != HDCP_RRX_BYTE_LEN) {
+ hdcp_err("rrx doesn't match (%dth)\n", i);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int utc_ake_stored_km(struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+#if 0
+ uint8_t m[525];
+ size_t m_len;
+ int ret;
+ int i;
+
+ ret = cap_protocol_msg(AKE_STORED_KM, m, &m_len, HDCP_LINK_TYPE_IIA, tx_ctx, rx_ctx);
+ if (ret) {
+ hdcp_err("AKE_Stored_km() is failed with 0x%x\n", ret);
+ return -1;
+ }
+
+ if (m[0] != 5) {
+ hdcp_err("Message ID ERROR, it has %d\n", m[0]);
+ return -1;
+ }
+
+ if (m_len != AKE_STORED_KM_LEN) {
+ hdcp_err("Message LENGTH ERROR\n");
+ return -1;
+ }
+
+
+ for (i = 0; i < HDCP_AKE_MKEY_BYTE_LEN; i++)
+ if (tv_pairing_ekh[i] != m[i+1])
+ break;
+
+ if (i != HDCP_AKE_MKEY_BYTE_LEN) {
+ hdcp_err("ekh(m) doesn't match (%dth)\n", i);
+ return -1;
+ }
+
+
+ for (i = 0; i < HDCP_AKE_MKEY_BYTE_LEN; i++)
+ if (tv_pairing_m[i] != m[i + 1 + HDCP_AKE_MKEY_BYTE_LEN])
+ break;
+
+ if (i != HDCP_AKE_MKEY_BYTE_LEN) {
+ hdcp_err("m doesn't match (%dth)\n", i);
+ return -1;
+ }
+#endif
+
+ return 0;
+}
+
+static int utc_ake_send_pairing_info(struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ int ret;
+ int i;
+ int found_km;
+
+ /* Extract Receiver ID */
+ for (i = 0; i < RECEIVER_ID_BYTE_LEN; i++)
+ rx_ctx->receiver_id[i] = rx_ctx->cert[i];
+
+ ret = decap_protocol_msg(AKE_SEND_PAIRING_INFO, msg_rx_send_pairing_info,
+ sizeof(msg_rx_send_pairing_info),
+ HDCP_LINK_TYPE_IIA,
+ 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[i + 1])
+ 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 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, HDCP_RX_CERT_LEN);
+
+ ret = cap_protocol_msg(AKE_NO_STORED_KM, m, &m_len, HDCP_LINK_TYPE_IIA, tx_ctx, rx_ctx);
+ if (ret) {
+ hdcp_err("make_AKE_No_Stored_km() is failed with 0x%x\n", ret);
+ return -1;
+ }
+
+ if (m[0] != 4) {
+ hdcp_err("Message ID ERROR, it has %d\n", m[0]);
+ return -1;
+ }
+
+ if (m_len != AKE_NO_STORED_KM_LEN) {
+ hdcp_err("Message LENGTH ERROR\n");
+ return -1;
+ }
+
+
+ for (i = 0; i < 128; i++)
+ if (m[i + 1] != tv_emkey[i])
+ break;
+
+ if (i != 128) {
+ hdcp_err("Encryption Master Key ERROR\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int utc_ake_receiver_info(struct hdcp_tx_ctx *tx_ctx,
+ struct hdcp_rx_ctx *rx_ctx)
+{
+ int ret;
+
+ ret = decap_protocol_msg(AKE_RECEIVER_INFO,
+ msg_rx_receiver_info,
+ sizeof(msg_rx_receiver_info),
+ HDCP_LINK_TYPE_IIA,
+ tx_ctx, rx_ctx);
+ if (ret) {
+ hdcp_err("get_Receiver_Info() is failed with %x\n", ret);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int 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,
+ sizeof(msg_rx_send_cert),
+ HDCP_LINK_TYPE_IIA,
+ tx_ctx, rx_ctx);
+ if (ret) {
+ hdcp_err("get_AKE_Send_Cert() is failed with ret, 0x%x\n",
+ ret);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int utc_ake_transmitter_info(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(AKE_TRANSMITTER_INFO, m, &m_len, HDCP_LINK_TYPE_IIA, tx_ctx, NULL);
+ if (ret) {
+ hdcp_err("cap_ake_transmitter_info() is failed with 0x%x\n", ret);
+ return -1;
+ }
+
+ /* check message ID & length */
+ if (m[0] != 19) {
+ hdcp_err("Message ID ERROR\n");
+ return -1;
+ }
+
+ if ((m_len != AKE_TRANSMITTER_INFO_LEN) || (m[2] < 6)) {
+ hdcp_err("Message LENGTH ERROR\n");
+ return -1;
+ }
+
+ /* Version & Precompuation Check */
+#ifdef HDCP_TX_VERSION_2_1
+ if (m[3] != HDCP_VERSION_2_1) {
+#else
+ if (m[3] == HDCP_VERSION_2_1) {
+#endif
+ hdcp_err("Version set wrong\n");
+ return -1;
+ }
+
+ /* precomputation check */
+#ifdef HDCP_TX_LC_PRECOMPUTE_SUPPORT
+ if ((m[4] != 0) || (m[5] != 0x01)) {
+#else
+ if ((m[4] != 0) || (m[5] != 0)) {
+#endif
+ hdcp_err("Precomputation ERROR, it has 0x%x%x\n", m[4], m[5]);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int 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(AKE_INIT, m, &m_len, HDCP_LINK_TYPE_IIA, tx_ctx, NULL);
+ if (ret) {
+ hdcp_err("cap_ake_init() is failed with 0x%x\n", ret);
+ return -1;
+ }
+
+ /* check message ID & length */
+ if (m[0] != 2) {
+ hdcp_err("Message ID ERROR\n");
+ return -1;
+ }
+
+ if (m_len != AKE_INIT_LEN) {
+ hdcp_err("Message LENGTH ERROR\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Test AKE APIs */
+static int utc_ake(struct hdcp_tx_ctx *tx_ctx, struct hdcp_rx_ctx *rx_ctx,
+ int *cnt, int *fail)
+{
+ int ret;
+
+ ret = utc_ake_init(tx_ctx, rx_ctx);
+ if (ret < 0)
+ return ret;
+
+ ret = utc_ake_transmitter_info(tx_ctx, rx_ctx);
+ if (ret < 0)
+ return ret;
+
+ ret = utc_ake_send_cert(tx_ctx, rx_ctx);
+ if (ret < 0)
+ return ret;
+
+ ret = utc_ake_receiver_info(tx_ctx, rx_ctx);
+ if (ret < 0)
+ return ret;
+
+ ret = utc_ake_no_stored_km(tx_ctx, rx_ctx);
+ if (ret < 0)
+ return ret;
+
+ ret = utc_ake_send_rrx(tx_ctx, rx_ctx);
+ if (ret < 0)
+ return ret;
+
+ ret = utc_ake_send_h_prime(tx_ctx, rx_ctx);
+ if (ret < 0)
+ return ret;
+
+ ret = utc_ake_send_pairing_info(tx_ctx, rx_ctx);
+ if (ret < 0)
+ return ret;
+
+ ret = utc_ake_stored_km(tx_ctx, rx_ctx);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/* Test HDCP API functions */
+int iia_hdcp_protocol_self_test(void)
+{
+ int ake_cnt = 0, ake_fail = 0;
+ int lc_cnt = 0, lc_fail = 0;
+ int ske_cnt = 0, ske_fail = 0;
+ int ret;
+
+ hdcp_info("[ AKE UTC]\n");
+ ret = utc_ake(&uc_tx_ctx, &uc_rx_ctx, &ake_cnt, &ake_fail);
+ if (ret < 0) {
+ hdcp_info("AKE UTC: fail\n");
+ return ret;
+ } else {
+ hdcp_info("AKE UTC: success\n");
+ }
+
+ hdcp_info("\n[ LC UTC]\n");
+ ret = utc_lc(&uc_tx_ctx, &uc_rx_ctx, &lc_cnt, &lc_fail);
+ if (ret < 0) {
+ hdcp_info("LC UTC: fail\n");
+ return ret;
+ } else {
+ hdcp_info("LC UTC: success\n");
+ }
+
+ hdcp_info("\n[ SKE UTC]\n");
+ ret = utc_ske(&uc_tx_ctx, &uc_rx_ctx, &ske_cnt, &ske_fail);
+ if (ret < 0) {
+ hdcp_info("SKE UTC: fail\n");
+ return ret;
+ } else {
+ hdcp_info("SKE UTC: success\n");
+ }
+
+ hdcp_info("\n[ Encryption UTC]\n");
+ ret = utc_encryption(&uc_tx_ctx, &uc_rx_ctx);
+ if (ret < 0) {
+ hdcp_info("Encrypt UTC: fail\n");
+ return ret;
+ } else {
+ hdcp_info("Encrypt UTC: success\n");
+ }
+
+ return 0;
+}
--- /dev/null
+/* drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-selftest.h
+ *
+ * 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.
+*/
+#ifndef __EXYNOS_HDCP2_SELFTEST_H__
+#define __EXYNOS_HDCP2_SELFTEST_H__
+
+int iia_hdcp_protocol_self_test(void);
+
+#endif
--- /dev/null
+/*
+ * drivers/soc/samsung/exynos-hdcp/exynos-hdcp.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/module.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/smc.h>
+#include <asm/cacheflush.h>
+#include <linux/exynos_ion.h>
+#include <linux/smc.h>
+#if defined(CONFIG_ION)
+#include <linux/ion.h>
+#endif
+#include "exynos-hdcp2-iia-auth.h"
+#include "../exynos-hdcp2-teeif.h"
+#include "exynos-hdcp2-iia-selftest.h"
+#include "../exynos-hdcp2-encrypt.h"
+#include "../exynos-hdcp2-log.h"
+#include "../dp_link/exynos-hdcp2-dplink-if.h"
+#include "../dp_link/exynos-hdcp2-dplink.h"
+#include "../dp_link/exynos-hdcp2-dplink-selftest.h"
+
+#define EXYNOS_HDCP_DEV_NAME "hdcp2"
+
+extern struct hdcp_session_list g_hdcp_session_list;
+enum hdcp_result hdcp_link_ioc_authenticate(void);
+static char *hdcp_session_st_str[] = {
+ "ST_INIT",
+ "ST_LINK_SETUP",
+ "ST_END",
+ NULL
+};
+
+static char *hdcp_link_st_str[] = {
+ "ST_INIT",
+ "ST_H0_NO_RX_ATTACHED",
+ "ST_H1_TX_LOW_VALUE_CONTENT",
+ "ST_A0_DETERMINE_RX_HDCP_CAP",
+ "ST_A1_EXCHANGE_MASTER_KEY",
+ "ST_A2_LOCALITY_CHECK",
+ "ST_A3_EXCHANGE_SESSION_KEY",
+ "ST_A4_TEST_REPEATER",
+ "ST_A5_AUTHENTICATED",
+ "ST_A6_WAIT_RECEIVER_ID_LIST",
+ "ST_A7_VERIFY_RECEIVER_ID_LIST",
+ "ST_A8_SEND_RECEIVER_ID_LIST_ACK",
+ "ST_A9_CONTENT_STREAM_MGT",
+ "ST_END",
+ NULL
+};
+
+int state_init_flag;
+
+enum hdcp_result hdcp_unwrap_key(char *wkey)
+{
+
+ int rval = TX_AUTH_SUCCESS;
+
+ rval = teei_wrapped_key(wkey, UNWRAP, HDCP_STATIC_KEY);
+ if (rval < 0) {
+ hdcp_err("Wrap(%d) key failed (0x%08x)\n", UNWRAP, rval);
+ return HDCP_ERROR_UNWRAP_FAIL;
+ }
+
+ return 0;
+}
+
+enum hdcp_result hdcp_session_open(struct hdcp_sess_info *ss_info)
+{
+ struct hdcp_session_data *new_ss = NULL;
+ struct hdcp_session_node *new_ss_node = NULL;
+
+ /* do open session */
+ new_ss_node = (struct hdcp_session_node *)kzalloc(sizeof(struct hdcp_session_node), GFP_KERNEL);
+
+ if (!new_ss_node) {
+ return HDCP_ERROR_INVALID_HANDLE;
+ }
+
+ new_ss = hdcp_session_data_create();
+ if (!new_ss) {
+ kfree(new_ss_node);
+ return HDCP_ERROR_INVALID_HANDLE;
+ }
+
+ /* send session info to SWD */
+ /* todo: add error check */
+
+ UPDATE_SESSION_STATE(new_ss, SESS_ST_LINK_SETUP);
+ ss_info->ss_id = new_ss->id;
+ new_ss_node->ss_data = new_ss;
+
+ hdcp_session_list_add((struct hdcp_session_node *)new_ss_node, (struct hdcp_session_list *)&g_hdcp_session_list);
+
+/* TODO: Only for IIA */
+#if 0
+ if (hdcp_unwrap_key(ss_info->wkey))
+ return HDCP_ERROR_WRAP_FAIL;
+#endif
+
+ return HDCP_SUCCESS;
+}
+
+enum hdcp_result hdcp_session_close(struct hdcp_sess_info *ss_info)
+{
+ struct hdcp_session_node *ss_node;
+ struct hdcp_session_data *ss_data;
+ uint32_t ss_handle;
+
+ ss_handle = ss_info->ss_id;
+
+ ss_node = hdcp_session_list_find(ss_handle, &g_hdcp_session_list);
+ if (!ss_node) {
+ return HDCP_ERROR_INVALID_HANDLE;
+ }
+
+ ss_data = ss_node->ss_data;
+ if (ss_data->state != SESS_ST_LINK_SETUP)
+ return HDCP_ERROR_INVALID_STATE;
+
+ ss_handle = ss_info->ss_id;
+ UPDATE_SESSION_STATE(ss_data, SESS_ST_END);
+
+ hdcp_session_list_del(ss_node, &g_hdcp_session_list);
+ hdcp_session_data_destroy(&(ss_node->ss_data));
+
+ return HDCP_SUCCESS;
+}
+
+enum hdcp_result hdcp_link_open(struct hdcp_link_info *link_info, uint32_t lk_type)
+{
+ struct hdcp_session_node *ss_node = NULL;
+ struct hdcp_link_node *new_lk_node = NULL;
+ struct hdcp_link_data *new_lk_data = NULL;
+ int ret = HDCP_SUCCESS;
+ uint32_t ss_handle;
+
+ ss_handle = link_info->ss_id;
+
+ do {
+ /* find Session node which will contain new Link */
+ ss_node = hdcp_session_list_find(ss_handle, &g_hdcp_session_list);
+ if (!ss_node) {
+ ret = HDCP_ERROR_INVALID_INPUT;
+ break;
+ }
+
+ /* make a new link node and add it to the session */
+ new_lk_node = (struct hdcp_link_node *)kzalloc(sizeof(struct hdcp_link_node), GFP_KERNEL);
+ if (!new_lk_node) {
+ ret = HDCP_ERROR_MALLOC_FAILED;
+ break;
+ }
+ new_lk_data = hdcp_link_data_create();
+ if (!new_lk_data) {
+ ret = HDCP_ERROR_MALLOC_FAILED;
+ break;
+ }
+
+ UPDATE_LINK_STATE(new_lk_data, LINK_ST_H0_NO_RX_ATTATCHED);
+
+ new_lk_data->ss_ptr = ss_node;
+ new_lk_data->lk_type = lk_type;
+ new_lk_node->lk_data = new_lk_data;
+
+ hdcp_link_list_add(new_lk_node, &ss_node->ss_data->ln);
+
+ link_info->ss_id = ss_node->ss_data->id;
+ link_info->lk_id = new_lk_data->id;
+ } while (0);
+
+ if (ret != HDCP_SUCCESS) {
+ if (new_lk_node)
+ kfree(new_lk_node);
+ if (new_lk_data)
+ hdcp_link_data_destroy(&new_lk_data);
+
+ return HDCP_ERROR_LINK_OPEN_FAILED;
+ }
+ else {
+ UPDATE_LINK_STATE(new_lk_data, LINK_ST_H1_TX_LOW_VALUE_CONTENT);
+ }
+
+ return HDCP_SUCCESS;
+}
+
+enum hdcp_result hdcp_link_close(struct hdcp_link_info *lk_info)
+{
+ struct hdcp_session_node *ss_node = NULL;
+ struct hdcp_link_node *lk_node = NULL;
+
+ /* find Session node which contain the Link */
+ ss_node = hdcp_session_list_find(lk_info->ss_id, &g_hdcp_session_list);
+
+ if (!ss_node)
+ return HDCP_ERROR_INVALID_INPUT;
+
+ lk_node = hdcp_link_list_find(lk_info->lk_id, &ss_node->ss_data->ln);
+ if (!lk_node)
+ return HDCP_ERROR_INVALID_INPUT;
+
+ UPDATE_LINK_STATE(lk_node->lk_data, LINK_ST_H0_NO_RX_ATTATCHED);
+
+ hdcp_link_list_del(lk_node, &ss_node->ss_data->ln);
+ hdcp_link_data_destroy(&(lk_node->lk_data));
+
+ return HDCP_SUCCESS;
+}
+
+enum hdcp_result hdcp_link_authenticate(struct hdcp_msg_info *msg_info)
+{
+ struct hdcp_session_node *ss_node;
+ struct hdcp_link_node *lk_node;
+ struct hdcp_link_data *lk_data;
+ int ret = HDCP_SUCCESS;
+ int rval = TX_AUTH_SUCCESS;
+ int ake_retry = 0;
+ int lc_retry = 0;
+
+ /* find Session node which contains the Link */
+ ss_node = hdcp_session_list_find(msg_info->ss_handle, &g_hdcp_session_list);
+ if (!ss_node)
+ return HDCP_ERROR_INVALID_INPUT;
+
+ lk_node = hdcp_link_list_find(msg_info->lk_id, &ss_node->ss_data->ln);
+ if (!lk_node)
+ return HDCP_ERROR_INVALID_INPUT;
+
+ lk_data = lk_node->lk_data;
+
+ if (!lk_data)
+ return HDCP_ERROR_INVALID_INPUT;
+
+ /**
+ * if Upstream Content Control Function call this API,
+ * it changes state to ST_A0_DETERMINE_RX_HDCP_CAP automatically.
+ * HDCP library do not check CP desire.
+ */
+
+ if (state_init_flag == 0){
+ UPDATE_LINK_STATE(lk_data, LINK_ST_A0_DETERMINE_RX_HDCP_CAP);
+ }
+
+ if (lk_data->state == LINK_ST_A0_DETERMINE_RX_HDCP_CAP){
+ if (determine_rx_hdcp_cap(lk_data) < 0) {
+ ret = HDCP_ERROR_RX_NOT_HDCP_CAPABLE;
+ UPDATE_LINK_STATE(lk_data, LINK_ST_H1_TX_LOW_VALUE_CONTENT);
+ } else
+ UPDATE_LINK_STATE(lk_data, LINK_ST_A1_EXCHANGE_MASTER_KEY);
+ }
+
+ switch (lk_data->state) {
+ case LINK_ST_H1_TX_LOW_VALUE_CONTENT:
+ break;
+ case LINK_ST_A1_EXCHANGE_MASTER_KEY:
+ rval = exchange_master_key(lk_data, msg_info);
+ if (rval == TX_AUTH_SUCCESS) {
+ if (msg_info->next_step == DONE) {
+ ake_retry = 0;
+ UPDATE_LINK_STATE(lk_data, LINK_ST_A2_LOCALITY_CHECK);
+ msg_info->next_step = SEND_MSG;
+ state_init_flag = 1;
+ }
+ } else {
+ ret = HDCP_ERROR_EXCHANGE_KM;
+ UPDATE_LINK_STATE(lk_data, LINK_ST_H1_TX_LOW_VALUE_CONTENT);
+ }
+ break;
+ case LINK_ST_A2_LOCALITY_CHECK:
+ rval = locality_check(lk_data, msg_info);
+ if (rval == TX_AUTH_SUCCESS) {
+ if (msg_info->next_step == DONE) {
+ lc_retry = 0;
+ UPDATE_LINK_STATE(lk_data, LINK_ST_A3_EXCHANGE_SESSION_KEY);
+ msg_info->next_step = SEND_MSG;
+ }
+ } else {
+ UPDATE_LINK_STATE(lk_data, LINK_ST_H1_TX_LOW_VALUE_CONTENT);
+ }
+ break;
+ case LINK_ST_A3_EXCHANGE_SESSION_KEY:
+ if (exchange_hdcp_session_key(lk_data, msg_info) < 0) {
+ ret = HDCP_ERROR_EXCHANGE_KS;
+ UPDATE_LINK_STATE(lk_data, LINK_ST_H1_TX_LOW_VALUE_CONTENT);
+ } else{
+ msg_info->next_step = WAIT_STATE;
+ UPDATE_LINK_STATE(lk_data, LINK_ST_A4_TEST_REPEATER);
+ }
+ break;
+ case LINK_ST_A4_TEST_REPEATER:
+ if (evaluate_repeater(lk_data) == TRUE){
+ /* HACK: when we supports repeater, it should be removed */
+ UPDATE_LINK_STATE(lk_data, LINK_ST_A6_WAIT_RECEIVER_ID_LIST);
+ msg_info->next_step = RP_RECIEVE_MSG;
+ }
+ else{
+ /* if it is not a repeater, complete authentication */
+ UPDATE_LINK_STATE(lk_data, LINK_ST_A5_AUTHENTICATED);
+ }
+ break;
+ case LINK_ST_A5_AUTHENTICATED:
+ msg_info->next_step = AUTH_FINISHED;
+ state_init_flag = 0;
+ return HDCP_SUCCESS;
+ case LINK_ST_A6_WAIT_RECEIVER_ID_LIST:
+ ret = wait_for_receiver_id_list(lk_data, msg_info);
+ if (ret < 0) {
+ ret = HDCP_ERROR_WAIT_RECEIVER_ID_LIST;
+ UPDATE_LINK_STATE(lk_data, LINK_ST_H1_TX_LOW_VALUE_CONTENT);
+ } else {
+ UPDATE_LINK_STATE(lk_data, LINK_ST_A7_VERIFY_RECEIVER_ID_LIST);
+ msg_info->next_step = WAIT_STATE;
+ }
+ break;
+ case LINK_ST_A7_VERIFY_RECEIVER_ID_LIST:
+ UPDATE_LINK_STATE(lk_data, LINK_ST_A8_SEND_RECEIVER_ID_LIST_ACK);
+ msg_info->next_step = RP_SEND_MSG;
+ break;
+ case LINK_ST_A8_SEND_RECEIVER_ID_LIST_ACK:
+ rval = send_receiver_id_list_ack(lk_data, msg_info);
+ if (rval == TX_AUTH_SUCCESS) {
+ if (msg_info->next_step == DONE) {
+ UPDATE_LINK_STATE(lk_data, LINK_ST_A5_AUTHENTICATED);
+ state_init_flag = 0;
+ msg_info->next_step = AUTH_FINISHED;
+ }
+ } else {
+ UPDATE_LINK_STATE(lk_data, LINK_ST_H1_TX_LOW_VALUE_CONTENT);
+ }
+ break;
+ case LINK_ST_A9_CONTENT_STREAM_MGT:
+ /* do not support yet */
+ ret = HDCP_ERROR_DO_NOT_SUPPORT_YET;
+ break;
+ default:
+ ret = HDCP_ERROR_INVALID_STATE;
+ UPDATE_LINK_STATE(lk_data, LINK_ST_H1_TX_LOW_VALUE_CONTENT);
+ break;
+ }
+
+ return ret;
+}
+
+enum hdcp_result hdcp_link_stream_manage(struct hdcp_stream_info *stream_info)
+{
+ struct hdcp_session_node *ss_node;
+ struct hdcp_link_node *lk_node;
+ struct hdcp_link_data *lk_data;
+ struct contents_info stream_ctrl;
+ int rval = TX_AUTH_SUCCESS;
+ int i;
+
+ /* find Session node which contain the Link */
+ ss_node = hdcp_session_list_find(stream_info->ss_id, &g_hdcp_session_list);
+ if (!ss_node)
+ return HDCP_ERROR_INVALID_INPUT;
+
+ lk_node = hdcp_link_list_find(stream_info->lk_id, &ss_node->ss_data->ln);
+ if (!lk_node)
+ return HDCP_ERROR_INVALID_INPUT;
+
+ lk_data = lk_node->lk_data;
+ if (!lk_data)
+ return HDCP_ERROR_INVALID_INPUT;
+
+ if (lk_data->state < LINK_ST_A4_TEST_REPEATER)
+ return HDCP_ERROR_INVALID_STATE;
+
+ stream_ctrl.str_num = stream_info->num;
+ if (stream_info->num > HDCP_TX_REPEATER_MAX_STREAM)
+ return HDCP_ERROR_INVALID_INPUT;
+
+ for (i = 0; i < stream_info->num; i++) {
+ stream_ctrl.str_info[i].ctr = stream_info->stream_ctr;
+ stream_ctrl.str_info[i].type = stream_info->type;
+ stream_ctrl.str_info[i].pid = stream_info->stream_pid;
+ }
+
+ rval = manage_content_stream(lk_data, &stream_ctrl, stream_info);
+ if (rval < 0) {
+ hdcp_err("manage_content_stream fail(0x%08x)\n", rval);
+ return HDCP_ERROR_STREAM_MANAGE;
+
+ }
+
+ return HDCP_SUCCESS;
+}
+
+enum hdcp_result hdcp_wrap_key(struct hdcp_wrapped_key *key_info)
+{
+ int rval = TX_AUTH_SUCCESS;
+ char key_str[HDCP_WRAP_MAX_SIZE];
+
+ if (key_info->key_len <= HDCP_WRAP_KEY)
+ memcpy(key_str, key_info->key, HDCP_WRAP_KEY);
+ else
+ return HDCP_ERROR_WRONG_SIZE;
+
+ rval = teei_wrapped_key(key_str, key_info->wrapped, key_info->key_len);
+ if (rval < 0) {
+ hdcp_err("Wrap(%d) key failed (0x%08x)\n",key_info->wrapped, rval);
+ return HDCP_ERROR_WRAP_FAIL;
+ }
+
+ if (key_info->wrapped == WRAP)
+ memcpy(key_info->enc_key, key_str, HDCP_WRAP_KEY + HDCP_WRAP_AUTH_TAG);
+
+ return 0;
+}