From 0e4fe0cda015b3dd50825235cc439877e9ee5d21 Mon Sep 17 00:00:00 2001 From: "Taein, An" Date: Wed, 23 May 2018 08:23:55 +0900 Subject: [PATCH] [9610] hdcp: add initial hdcp2 Change-Id: I1af03165b61d864b38e7993db3158f413072ea90 Signed-off-by: Taein, An --- drivers/soc/samsung/Makefile | 3 + drivers/soc/samsung/exynos-hdcp/Kconfig | 37 + drivers/soc/samsung/exynos-hdcp/Makefile | 20 + .../dp_link/exynos-hdcp2-dplink-auth.c | 1203 +++++++++++++++++ .../dp_link/exynos-hdcp2-dplink-auth.h | 32 + .../dp_link/exynos-hdcp2-dplink-if.c | 258 ++++ .../dp_link/exynos-hdcp2-dplink-if.h | 53 + .../exynos-hdcp2-dplink-protocol-msg.c | 483 +++++++ .../exynos-hdcp2-dplink-protocol-msg.h | 65 + .../dp_link/exynos-hdcp2-dplink-reg.h | 42 + .../dp_link/exynos-hdcp2-dplink-selftest.c | 470 +++++++ .../dp_link/exynos-hdcp2-dplink-selftest.h | 15 + .../exynos-hdcp/dp_link/exynos-hdcp2-dplink.c | 432 ++++++ .../exynos-hdcp/dp_link/exynos-hdcp2-dplink.h | 54 + .../samsung/exynos-hdcp/exynos-hdcp2-config.h | 24 + .../samsung/exynos-hdcp/exynos-hdcp2-crypto.c | 64 + .../samsung/exynos-hdcp/exynos-hdcp2-crypto.h | 20 + .../exynos-hdcp/exynos-hdcp2-encrypt.c | 138 ++ .../exynos-hdcp/exynos-hdcp2-encrypt.h | 22 + .../samsung/exynos-hdcp/exynos-hdcp2-log.h | 39 + .../samsung/exynos-hdcp/exynos-hdcp2-misc.c | 24 + .../samsung/exynos-hdcp/exynos-hdcp2-misc.h | 15 + .../exynos-hdcp/exynos-hdcp2-protocol-msg.c | 1070 +++++++++++++++ .../exynos-hdcp/exynos-hdcp2-protocol-msg.h | 233 ++++ .../exynos-hdcp/exynos-hdcp2-session.c | 379 ++++++ .../exynos-hdcp/exynos-hdcp2-session.h | 130 ++ .../samsung/exynos-hdcp/exynos-hdcp2-teeif.c | 538 ++++++++ .../samsung/exynos-hdcp/exynos-hdcp2-teeif.h | 332 +++++ .../exynos-hdcp/exynos-hdcp2-testvector.h | 909 +++++++++++++ .../soc/samsung/exynos-hdcp/exynos-hdcp2.c | 394 ++++++ .../soc/samsung/exynos-hdcp/exynos-hdcp2.h | 228 ++++ drivers/soc/samsung/exynos-hdcp/hdcp2_if.h | 17 + .../iia_link/exynos-hdcp2-iia-auth.c | 463 +++++++ .../iia_link/exynos-hdcp2-iia-auth.h | 42 + .../iia_link/exynos-hdcp2-iia-selftest.c | 662 +++++++++ .../iia_link/exynos-hdcp2-iia-selftest.h | 15 + .../exynos-hdcp/iia_link/exynos-hdcp2-iia.c | 416 ++++++ 37 files changed, 9341 insertions(+) create mode 100755 drivers/soc/samsung/exynos-hdcp/Kconfig create mode 100644 drivers/soc/samsung/exynos-hdcp/Makefile create mode 100644 drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-auth.c create mode 100644 drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-auth.h create mode 100644 drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-if.c create mode 100644 drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-if.h create mode 100644 drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-protocol-msg.c create mode 100644 drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-protocol-msg.h create mode 100644 drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-reg.h create mode 100644 drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-selftest.c create mode 100644 drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-selftest.h create mode 100644 drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink.c create mode 100644 drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink.h create mode 100755 drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-config.h create mode 100644 drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-crypto.c create mode 100644 drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-crypto.h create mode 100755 drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-encrypt.c create mode 100755 drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-encrypt.h create mode 100644 drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-log.h create mode 100755 drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-misc.c create mode 100755 drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-misc.h create mode 100755 drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-protocol-msg.c create mode 100755 drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-protocol-msg.h create mode 100755 drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-session.c create mode 100755 drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-session.h create mode 100755 drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-teeif.c create mode 100755 drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-teeif.h create mode 100644 drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-testvector.h create mode 100755 drivers/soc/samsung/exynos-hdcp/exynos-hdcp2.c create mode 100755 drivers/soc/samsung/exynos-hdcp/exynos-hdcp2.h create mode 100755 drivers/soc/samsung/exynos-hdcp/hdcp2_if.h create mode 100755 drivers/soc/samsung/exynos-hdcp/iia_link/exynos-hdcp2-iia-auth.c create mode 100755 drivers/soc/samsung/exynos-hdcp/iia_link/exynos-hdcp2-iia-auth.h create mode 100644 drivers/soc/samsung/exynos-hdcp/iia_link/exynos-hdcp2-iia-selftest.c create mode 100755 drivers/soc/samsung/exynos-hdcp/iia_link/exynos-hdcp2-iia-selftest.h create mode 100755 drivers/soc/samsung/exynos-hdcp/iia_link/exynos-hdcp2-iia.c diff --git a/drivers/soc/samsung/Makefile b/drivers/soc/samsung/Makefile index f2722d59bcb0..ee2ec4119f43 100644 --- a/drivers/soc/samsung/Makefile +++ b/drivers/soc/samsung/Makefile @@ -48,3 +48,6 @@ obj-$(CONFIG_ARCH_EXYNOS) += exynos-pm.o # Exynos Secure Log obj-$(CONFIG_EXYNOS_SECURE_LOG) += exynos-seclog.o + +# HDCP +obj-$(CONFIG_EXYNOS_HDCP2) += exynos-hdcp/ diff --git a/drivers/soc/samsung/exynos-hdcp/Kconfig b/drivers/soc/samsung/exynos-hdcp/Kconfig new file mode 100755 index 000000000000..1a355716d5ec --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/Kconfig @@ -0,0 +1,37 @@ +# +# 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 diff --git a/drivers/soc/samsung/exynos-hdcp/Makefile b/drivers/soc/samsung/exynos-hdcp/Makefile new file mode 100644 index 000000000000..090abed17dc0 --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/Makefile @@ -0,0 +1,20 @@ +# +# 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 diff --git a/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-auth.c b/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-auth.c new file mode 100644 index 000000000000..59f0fea6e4df --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-auth.c @@ -0,0 +1,1203 @@ +/* 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 +#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; +} diff --git a/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-auth.h b/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-auth.h new file mode 100644 index 000000000000..b7733a9f94ce --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-auth.h @@ -0,0 +1,32 @@ +/* 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 diff --git a/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-if.c b/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-if.c new file mode 100644 index 000000000000..2a285e3bfa2d --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-if.c @@ -0,0 +1,258 @@ +/* + * 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 +#include +#include +#include +#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 diff --git a/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-if.h b/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-if.h new file mode 100644 index 000000000000..90e0e92e8d5a --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-if.h @@ -0,0 +1,53 @@ +/* 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 diff --git a/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-protocol-msg.c b/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-protocol-msg.c new file mode 100644 index 000000000000..ddb865c0e9e1 --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-protocol-msg.c @@ -0,0 +1,483 @@ +/* + * 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 + +#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; +} + diff --git a/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-protocol-msg.h b/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-protocol-msg.h new file mode 100644 index 000000000000..4832677faec1 --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-protocol-msg.h @@ -0,0 +1,65 @@ +/* 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 + +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 diff --git a/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-reg.h b/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-reg.h new file mode 100644 index 000000000000..afd0bca8b6ba --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-reg.h @@ -0,0 +1,42 @@ +/* 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 diff --git a/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-selftest.c b/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-selftest.c new file mode 100644 index 000000000000..159ab7a992e5 --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-selftest.c @@ -0,0 +1,470 @@ +/* + * 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 +#include +#include + +#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; +} diff --git a/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-selftest.h b/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-selftest.h new file mode 100644 index 000000000000..08129e16fa86 --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink-selftest.h @@ -0,0 +1,15 @@ +/* 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 diff --git a/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink.c b/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink.c new file mode 100644 index 000000000000..ccfab782f24f --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink.c @@ -0,0 +1,432 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +} + diff --git a/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink.h b/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink.h new file mode 100644 index 000000000000..e2fdec074e43 --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/dp_link/exynos-hdcp2-dplink.h @@ -0,0 +1,54 @@ +/* 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 diff --git a/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-config.h b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-config.h new file mode 100755 index 000000000000..0a6a4498b408 --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-config.h @@ -0,0 +1,24 @@ +/* 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 diff --git a/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-crypto.c b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-crypto.c new file mode 100644 index 000000000000..88aedd38f511 --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-crypto.c @@ -0,0 +1,64 @@ +/* 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 +#include +#include +#include +#include + +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; +} diff --git a/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-crypto.h b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-crypto.h new file mode 100644 index 000000000000..38440f9d8fe9 --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-crypto.h @@ -0,0 +1,20 @@ +/* + * 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 diff --git a/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-encrypt.c b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-encrypt.c new file mode 100755 index 000000000000..73d554dbca8a --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-encrypt.c @@ -0,0 +1,138 @@ +/* + * 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 +#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; +} + diff --git a/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-encrypt.h b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-encrypt.h new file mode 100755 index 000000000000..05dfad14b9d9 --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-encrypt.h @@ -0,0 +1,22 @@ +/* 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 + +#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 diff --git a/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-log.h b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-log.h new file mode 100644 index 000000000000..3c78c17e2fbe --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-log.h @@ -0,0 +1,39 @@ +/* + * 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 diff --git a/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-misc.c b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-misc.c new file mode 100755 index 000000000000..7c1dfe0c174e --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-misc.c @@ -0,0 +1,24 @@ +/* + * 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 + +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"); +} diff --git a/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-misc.h b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-misc.h new file mode 100755 index 000000000000..4f71247a2c9c --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-misc.h @@ -0,0 +1,15 @@ +/* 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 diff --git a/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-protocol-msg.c b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-protocol-msg.c new file mode 100755 index 000000000000..414357431af5 --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-protocol-msg.c @@ -0,0 +1,1070 @@ +/* + * 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 + +#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; +} diff --git a/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-protocol-msg.h b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-protocol-msg.h new file mode 100755 index 000000000000..fe36de90a939 --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-protocol-msg.h @@ -0,0 +1,233 @@ +/* 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 +#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); diff --git a/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-session.c b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-session.c new file mode 100755 index 000000000000..7250c7c4a6fd --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-session.c @@ -0,0 +1,379 @@ +/* + * 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 + +#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); +} diff --git a/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-session.h b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-session.h new file mode 100755 index 000000000000..02cbdac2f02a --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-session.h @@ -0,0 +1,130 @@ +/* + * 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 + diff --git a/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-teeif.c b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-teeif.c new file mode 100755 index 000000000000..981bdccf71ed --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-teeif.c @@ -0,0 +1,538 @@ +/* + * 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 +#include +#include + +#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; +} diff --git a/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-teeif.h b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-teeif.h new file mode 100755 index 000000000000..cba21876b780 --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-teeif.h @@ -0,0 +1,332 @@ +/* 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 diff --git a/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-testvector.h b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-testvector.h new file mode 100644 index 000000000000..fd738be15118 --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2-testvector.h @@ -0,0 +1,909 @@ +/* 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 + diff --git a/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2.c b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2.c new file mode 100755 index 000000000000..3217ccd2a259 --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2.c @@ -0,0 +1,394 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_ION) +#include +#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); diff --git a/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2.h b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2.h new file mode 100755 index 000000000000..a68edb4f1027 --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/exynos-hdcp2.h @@ -0,0 +1,228 @@ +/* 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 +#include +#include +#include + +#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 diff --git a/drivers/soc/samsung/exynos-hdcp/hdcp2_if.h b/drivers/soc/samsung/exynos-hdcp/hdcp2_if.h new file mode 100755 index 000000000000..049cf4a35613 --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/hdcp2_if.h @@ -0,0 +1,17 @@ +/* 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 + diff --git a/drivers/soc/samsung/exynos-hdcp/iia_link/exynos-hdcp2-iia-auth.c b/drivers/soc/samsung/exynos-hdcp/iia_link/exynos-hdcp2-iia-auth.c new file mode 100755 index 000000000000..ca7a59665a19 --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/iia_link/exynos-hdcp2-iia-auth.c @@ -0,0 +1,463 @@ +/* + * 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; +} diff --git a/drivers/soc/samsung/exynos-hdcp/iia_link/exynos-hdcp2-iia-auth.h b/drivers/soc/samsung/exynos-hdcp/iia_link/exynos-hdcp2-iia-auth.h new file mode 100755 index 000000000000..b13398991f43 --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/iia_link/exynos-hdcp2-iia-auth.h @@ -0,0 +1,42 @@ +/* + * 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 diff --git a/drivers/soc/samsung/exynos-hdcp/iia_link/exynos-hdcp2-iia-selftest.c b/drivers/soc/samsung/exynos-hdcp/iia_link/exynos-hdcp2-iia-selftest.c new file mode 100644 index 000000000000..385561b47afc --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/iia_link/exynos-hdcp2-iia-selftest.c @@ -0,0 +1,662 @@ +/* + * 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 +#include +#include + +#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; +} diff --git a/drivers/soc/samsung/exynos-hdcp/iia_link/exynos-hdcp2-iia-selftest.h b/drivers/soc/samsung/exynos-hdcp/iia_link/exynos-hdcp2-iia-selftest.h new file mode 100755 index 000000000000..63b3ffa168f9 --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/iia_link/exynos-hdcp2-iia-selftest.h @@ -0,0 +1,15 @@ +/* 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 diff --git a/drivers/soc/samsung/exynos-hdcp/iia_link/exynos-hdcp2-iia.c b/drivers/soc/samsung/exynos-hdcp/iia_link/exynos-hdcp2-iia.c new file mode 100755 index 000000000000..e15f71cc4e21 --- /dev/null +++ b/drivers/soc/samsung/exynos-hdcp/iia_link/exynos-hdcp2-iia.c @@ -0,0 +1,416 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_ION) +#include +#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; +} -- 2.20.1