
/*
 * =====================================================================================
 *
 *       Filename:  hdm_jws.c
 *
 *    Description:  HDM JWS manipulation
 *
 *        Version:  1.0
 *        Created:  09/16/2019 15:26:11 PM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *        Company:  Samsung Electronics
 *        Copyright (c) 2015 by Samsung Electronics, All rights reserved.
 *
 * =====================================================================================
 */

/** Includes */
#include "hdm_jws.h"

/**
 * Definitions
 */
#define CHARACTER_INT_MAX  10

/**
 * Static functions prototypes
 */
static hdm_return_code_t header_x5c_value(uint8_t *value, int len);
static hdm_return_code_t set_string_value(uint8_t *src, int src_len, uint8_t *dest, int dest_max_len);
static hdm_return_code_t header_service_name_value(uint8_t *service_name, int len);
static hdm_return_code_t header_req_id_value(uint8_t *request_id, int len);
static hdm_return_code_t header_alg_value(uint8_t *alg, int len);
static hdm_return_code_t header_protocol_version_value(uint8_t *protocol_version, int len);
static hdm_return_code_t payload_device_block_value(uint8_t *device_block, int len);
static hdm_return_code_t payload_compromise_block_value(uint8_t *compromise_block, int len);
static hdm_return_code_t payload_policy_version_value(uint8_t *policy_version, int len);
static hdm_return_code_t payload_server_nonce_value(uint8_t *server_nonce, int len);
static hdm_return_code_t payload_device_id_value(uint8_t *device_id, int len);
static hdm_return_code_t compare_device_id(uint8_t *device_id, uint32_t compared_len, uint8_t *compared);
static hdm_return_code_t validate_tag(uint8_t *tag, uint32_t tag_len, uint32_t *tag_index, uint32_t msg_type, hdm_hashmap_value_t *map);

/**
 * JWS header hashmap
 */
hdm_hashmap_value_t hdm_header_values[] = {
        // TAG                        Value
        {JWS_HEADER_SERVICE_NAME,     header_service_name_value},
        {JWS_HEADER_REQ_ID,           header_req_id_value},
        {JWS_HEADER_ALG,              header_alg_value},
        {JWS_HEADER_PROTOCOL_VERSION, header_protocol_version_value},
        {JWS_HEADER_X5C,              header_x5c_value}
};

/**
 * JWS payload hashmap
 */
hdm_hashmap_value_t hdm_payload_values[] = {
        // TAG                        Value
        {JWS_PAYLOAD_DEVICE_BLOCK,     payload_device_block_value},
        {JWS_PAYLOAD_COMPROMISE_BLOCK, payload_compromise_block_value},
        {JWS_PAYLOAD_POLICY_VERSION,   payload_policy_version_value},
        {JWS_PAYLOAD_SERVER_NONCE,     payload_server_nonce_value},
        {JWS_PAYLOAD_DEVICE_ID,        payload_device_id_value}
};

/**
 * @brief
 * split_b64_jws
 * Split base64 policy JWS to fill structs
 *
 * @param[in]  *tci_msg                           - tci message
 * @param[out] *jwsB64                            - JWS base64 global struct
 * @param[out] *size_header_payload_for_signature - length for signature
 *
 * @return HDM status code
 */
hdm_return_code_t split_b64_jws(tci_message_t *tci_msg, tz_hdm_jws_t *jwsB64, uint32_t *size_header_payload_for_signature) {
        HDM_LOG_DEBUG("split_b64_jws()");

        hdm_return_code_t ret = HDM_STATUS_SUCCESS;
        int32_t i = 0;

        if(tci_msg->jws_message.len == 0) {
                HDM_LOG_DEBUG("tci_msg->len is 0");
                ret = HDM_JWS_NULL;
                goto exit;
        }

        for(i = 0; i < tci_msg->jws_message.len; i++) {
                /*split jws base64 */
                /* HEADER */
                int32_t init = i;
                while((char)(tci_msg->jws_message.data[i]) != '.' && (i < tci_msg->jws_message.len)){
                        i++;
                }

                if(i >= tci_msg->jws_message.len){
                        HDM_LOG_DEBUG("JWS has invalid format");
                        ret = HDM_JWS_INVALID_FORMAT;
                        goto exit;
                }

                if((i - init) > HEADER_LEN - 1){
                        HDM_LOG_DEBUG("Header has invalid length");
                        ret = HDM_JWS_INVALID_LENGTH;
                        goto exit;
                }

                TEE_MemMove(jwsB64->header,&tci_msg->jws_message.data[init], (i - init));
                jwsB64->header[(i - init) + 1] = '\0';
                jwsB64->header_len = (i - init);

                /* PAYLOAD */
                init = ++i;
                while((char)(tci_msg->jws_message.data[i]) != '.' && (i < tci_msg->jws_message.len)){
                        i++;
                }

                if(i >= tci_msg->jws_message.len){
                        HDM_LOG_DEBUG("JWS has invalid format");
                        ret = HDM_JWS_INVALID_FORMAT;
                        goto exit;
                }

                if((i - init) > PAYLOAD_LEN -1){
                        HDM_LOG_DEBUG("Payload has invalid length");
                        ret = HDM_JWS_INVALID_LENGTH;
                        goto exit;
                }

                TEE_MemMove(jwsB64->payload, &tci_msg->jws_message.data[init], i - init);
                jwsB64->payload[(i-init) + 1] = '\0';
                jwsB64->payload_len = (i - init);

                *size_header_payload_for_signature = i;

                /* SIGNATURE */
                if((tci_msg->jws_message.len - (i + 1)) > SIGNATURE_LEN - 1){
                        HDM_LOG_DEBUG("Signature has invalid length");
                        ret = HDM_JWS_INVALID_LENGTH;
                        goto exit;
                }

                TEE_MemMove(jwsB64->signature, &tci_msg->jws_message.data[i + 1], tci_msg->jws_message.len - (i + 1));
                jwsB64->signature[tci_msg->jws_message.len - (i + 1)] = '\0';
                jwsB64->signature_len = tci_msg->jws_message.len - (i + 1);
                break;
        }

        ret = HDM_STATUS_SUCCESS;
exit:
        return ret;
}

/**
 * @brief
 * fill_jws_msg
 * Extracts information on received JSON and set related fields on the corresponding structures.
 * The lexer works as a FSM.
 *
 * @param[in] msg_decoded - JSON in string format
 * @param[in] msg_len     - JSON lenght in decimal
 * @param[in] msg_type    - HEADER_TYPE or PAYLOAD_TYPE
 *
 * @return HDM status code
*/
hdm_return_code_t fill_jws_msg(uint8_t *msg_decoded, uint32_t msg_len, uint32_t msg_type) {
        HDM_LOG_DEBUG("fill_jws_msg()");

        hdm_return_code_t ret = HDM_STATUS_SUCCESS;
        jws_lex_states_t state = START;
        hdm_malloc_values_func_t fill_value_ptr = NULL;
        hdm_hashmap_value_t *map = (msg_type == HEADER_TYPE) ? hdm_header_values : hdm_payload_values;

        uint32_t begin_TAG_idx   = 0;
        uint32_t end_TAG_idx     = 0;
        uint32_t begin_VALUE_idx = 0;
        uint32_t end_VALUE_idx   = 0;

        for (uint32_t i = 0; i < msg_len; i++) {
                switch (state) {
                        case START:
                                if (msg_decoded[i] == (uint8_t) '{') {
                                        state = BODY;
                                }
                                break;

                        case BODY:
                                if (msg_decoded[i] == (uint8_t) '"') {
                                        state = BEGIN_TAG;
                                }
                                break;

                        case BEGIN_TAG:
                                if (msg_decoded[i] == (uint8_t) '"') {
                                        ret = HDM_JWS_INVALID_FORMAT;
                                        goto exit;
                                }

                                begin_TAG_idx = i;
                                state = BUILD_TAG;
                                break;

                        case BUILD_TAG:
                                if (msg_decoded[i] == (uint8_t) '"') {
                                        end_TAG_idx = i;
                                        state = FINAL_TAG;
                                }
                                break;

                        case FINAL_TAG:
                                {
                                        uint32_t len = end_TAG_idx - begin_TAG_idx;
                                        uint32_t tag_index = 0;

                                        if(validate_tag(&msg_decoded[begin_TAG_idx], len, &tag_index, msg_type, map) == HDM_STATUS_SUCCESS) {
                                                fill_value_ptr = map[tag_index].value;

                                        } else {
                                                ret = HDM_JWS_INVALID_FORMAT;
                                                goto exit;
                                        }

                                        if(msg_decoded[i] == (uint8_t) ':') {
                                                state = CHECKPOINT;
                                        }
                                }
                                break;

                        case CHECKPOINT:
                                if (msg_decoded[i] == (uint8_t) '"') {
                                        state = BEGIN_VALUE;
                                } else if (msg_decoded[i] == (uint8_t) '[') {
                                        state = BEGIN_ARR_BODY;
                                }
                                break;

                        case BEGIN_ARR_BODY:
                                if (msg_decoded[i] == (uint8_t) '"') {
                                        state = BEGIN_ARR_ITEM;
                                }
                                break;

                        case BEGIN_ARR_ITEM:
                                if (msg_decoded[i] == (uint8_t) '"') {
                                        ret = HDM_JWS_INVALID_FORMAT;
                                        goto exit;
                                }

                                begin_VALUE_idx = i;
                                state = BUILD_ARR_ITEM;
                                break;

                        case BUILD_ARR_ITEM:
                                if (msg_decoded[i] == (uint8_t) '"') {
                                        end_VALUE_idx = i;
                                        state = FINAL_ARR_ITEM;
                                }
                                break;

                        case FINAL_ARR_ITEM:
                                {
                                        if (msg_decoded[i] == (uint8_t) ' ') {
                                                continue;
                                        } else if (msg_decoded[i] == (uint8_t) '\n') {
                                                continue;
                                        }
                                        uint32_t value_len = end_VALUE_idx - begin_VALUE_idx;

                                        if (fill_value_ptr != NULL) {
                                                ret = fill_value_ptr(&msg_decoded[begin_VALUE_idx], value_len);
                                                if( ret != HDM_STATUS_SUCCESS){
                                                        ret = HDM_JWS_INVALID_FORMAT;
                                                        goto exit;
                                                }
                                        }

                                        if (msg_decoded[i] == (uint8_t) ',') {
                                                state = BEGIN_ARR_BODY;

                                        } else if (msg_decoded[i] == (uint8_t) ']') {
                                                state = FINAL_ARR_BODY;
                                        }
                                }
                                break;

                        case FINAL_ARR_BODY:
                                if (msg_decoded[i] == (uint8_t) ',') {
                                        state = BODY;
                                } else if (msg_decoded[i] == (uint8_t) '}') {
                                        state = END;
                                }
                                break;

                        case BEGIN_VALUE:
                                if (msg_decoded[i] == (uint8_t) '"') {
                                        ret = HDM_JWS_INVALID_FORMAT;
                                        goto exit;
                                }

                                begin_VALUE_idx = i;
                                state = BUILD_VALUE;
                                break;

                        case BUILD_VALUE:
                                if (msg_decoded[i] == (uint8_t) '"') {
                                        end_VALUE_idx = i;
                                        state = FINAL_VALUE;
                                }
                                break;

                        case FINAL_VALUE:
                                {
                                        uint32_t value_len = end_VALUE_idx - begin_VALUE_idx;

                                        if (fill_value_ptr != NULL) {
                                                ret = fill_value_ptr(&msg_decoded[begin_VALUE_idx], value_len);
                                                if( ret != HDM_STATUS_SUCCESS){
                                                        ret = HDM_JWS_INVALID_FORMAT;
                                                        goto exit;
                                                }
                                        }

                                        if (msg_decoded[i] == (uint8_t) ',') {
                                                state = BODY;

                                        } else if (msg_decoded[i] == (uint8_t) '}') {
                                                state = END;
                                        }
                                }
                                break;

                        case END:
                        default:
                                break;
                }
        }

        if (state != END) {
                ret = HDM_JWS_INVALID_FORMAT;
                goto exit;
        }

        ret = HDM_STATUS_SUCCESS;
exit:
        return ret;
}

/**
 * @brief
 * fill_jws_msg_signature
 * Fills signature global struct signature field.
 *
 * @param[in] *signature_decoded - decoded signature
 * @param[in] signature_len      - signature length
 *
 * @return HDM status code
*/
hdm_return_code_t fill_jws_msg_signature(uint8_t *signature_decoded, uint32_t signature_len){
        HDM_LOG_DEBUG("fill_jws_msg_signature()");

        if(signature_len > SIGNATURE_LEN - 1){
                HDM_LOG_DEBUG("signature_len(%d) > SIGNATURE_LEN(%d)", signature_len, SIGNATURE_LEN);
                return HDM_INVALID_JWS;
        }

        TEE_MemMove(signature.signature, signature_decoded, signature_len);
        signature.signature_len = signature_len;

        return HDM_STATUS_SUCCESS;
}

/**
 * @brief
 * validate_tag
 * Checks if received tag value is valid or not.
 * If valid, return the index of the corresponging action in the list.
 *
 * @param[in]     tag       - tag to be checked
 * @param[in]     tag_len   - length of the tag
 * @param[in,out] tag_index - index of the tag in the array
 * @param[in]     msg_type  - HEADER_TYPE or PAYLOAD_TYPE
 * @param[in,out] map       - the map to be checked on
 *
 * @return HDM status code
*/
static hdm_return_code_t validate_tag(uint8_t *tag, uint32_t tag_len, uint32_t *tag_index, uint32_t msg_type, hdm_hashmap_value_t *map) {
        HDM_LOG_DEBUG("validate_tag()");

        hdm_return_code_t ret = HDM_STATUS_SUCCESS;
        uint32_t hashmap_values_len = 0;

        switch(msg_type) {
                case HEADER_TYPE:
                        hashmap_values_len = sizeof(hdm_header_values) / sizeof(hdm_hashmap_value_t);
                        break;
                case PAYLOAD_TYPE:
                        hashmap_values_len = sizeof(hdm_payload_values) / sizeof(hdm_hashmap_value_t);
                        break;
                default:
                        HDM_LOG_DEBUG("Invalid msg_type [%d]", msg_type);
                        ret = HDM_JWS_INVALID_FORMAT;
                        goto exit;
        }

        for (int i = 0; i < hashmap_values_len; i++) {
                if (TEE_MemCompare(tag, map[i].tag, tag_len) == 0) {
                        *tag_index = i;
                        ret = HDM_STATUS_SUCCESS;
                        goto exit;
                }
        }

        ret = HDM_JWS_INVALID_FORMAT;
exit:
        return ret;
}

/**
 * @brief
 * header_x5c_value
 * Fills header global struct.
 *
 * @param[in] *value - x5c value
 * @param[in] len    - value length
*/
static hdm_return_code_t header_x5c_value(uint8_t *value, int len) {
        HDM_LOG_DEBUG("header_x5c_value()");

        if(len > JWS_HEADER_X5C_LEN - sizeof('\0')) {
                return HDM_STATUS_FAIL;
        }

        TEE_MemMove(&header.x5c[header.x5c_count].certificate, value, len);
        header.x5c[header.x5c_count].certificate[len] = '\0';
        header.x5c[header.x5c_count].certificate_len = strlen((const char*)header.x5c[header.x5c_count].certificate);
        settle_certificate_to_openssl(header.x5c[header.x5c_count].certificate);
        if(header.x5c[header.x5c_count].certificate[len-1] != '-'){
                header.x5c[header.x5c_count].certificate[len-2] = '\0';
                header.x5c[header.x5c_count].certificate_len = strlen((const char*)header.x5c[header.x5c_count].certificate);
        }

        header.x5c_count++;

        return HDM_STATUS_SUCCESS;
}

/**
 * @brief
 * set_string_value
 * Fills header struct
 *
 * @param[in] *src          - source
 * @param[in]  src_len      - source length
 * @param[in] *dest         - destine
 * @param[in]  dest_max_len - destine length
*/
static hdm_return_code_t set_string_value(uint8_t *src, int src_len, uint8_t *dest, int dest_max_len) {
        if( src_len > dest_max_len -1 ) {
                HDM_LOG_DEBUG("Failed to set header value");
                return HDM_STATUS_FAIL;
        }
        TEE_MemFill(dest, 0, dest_max_len);
        TEE_MemMove(dest, src, src_len);
        dest[src_len] = '\0';

        return HDM_STATUS_SUCCESS;
}

/**
 * @brief
 * header_service_name_value
 * Set header service name value on global struct
 *
 * @param[in] *service_name - service name
 * @param[in]  len          - service name length
*/
static hdm_return_code_t header_service_name_value(uint8_t *service_name, int len) {
        return set_string_value(service_name, len, header.service_name, JWS_HEADER_SERVICE_NAME_LEN);
}

/**
 * @brief
 * header_req_id_value
 * Set header request id name value on global struct
 *
 * @param[in] *request_id - request id
 * @param[in]  len        - request id length
*/
static hdm_return_code_t header_req_id_value(uint8_t *request_id, int len) {
        return set_string_value(request_id, len, header.request_id, JWS_HEADER_REQ_ID_LEN);
}

/**
 * @brief
 * header_alg_value
 * Set header alg value on global struct
 *
 * @param[in] *alg - alg
 * @param[in]  len - alg length
*/
static hdm_return_code_t header_alg_value(uint8_t *alg, int len) {
        return set_string_value(alg, len, header.alg, JWS_HEADER_ALG_LEN);
}

/**
 * @brief
 * header_protocol_version_value
 * Set header protocol version value on global struct
 *
 * @param[in] *protocol_version - protocol version
 * @param[in]  len              - protocol version length
*/
static hdm_return_code_t header_protocol_version_value(uint8_t *protocol_version, int len) {
        return set_string_value(protocol_version, len, header.protocol_version, JWS_HEADER_PROTOCOL_VERSION_LEN);
}

/**
 * @brief
 * payload_device_block_value
 * Set payload device block value on global struct
 *
 * @param[in] *device_block - device block
 * @param[in]  len          - device block length
*/
static hdm_return_code_t payload_device_block_value(uint8_t *device_block, int len) {
        int64_t device_block_int = hex2int(device_block);
        payload.device_block = FIT_TO_UINT32(device_block_int);
        return HDM_STATUS_SUCCESS;
}

/**
 * @brief
 * payload_device_block_value
 * Set payload compromise block value on global struct
 *
 * @param[in] *compromise_block - compromise block
 * @param[in]  len              - compromise block length
*/
static hdm_return_code_t payload_compromise_block_value(uint8_t *compromise_block, int len) {
        int64_t compromise_block_int = hex2int(compromise_block);
        payload.compromise_block = FIT_TO_UINT32(compromise_block_int);
        return HDM_STATUS_SUCCESS;
}

int64_t convert_str_to_int64(uint8_t *src, int src_len) {
        int i = 0;
        int64_t dest = 0;
        while ((i < src_len) && (src[i] >= '0' && src[i] <= '9')){
                dest = dest * 10 + (src[i] - '0');
                i++;
        }
        return dest;
}

/**
 * @brief
 * payload_policy_version_value
 * Set payload policy version value on global struct
 *
 * @param[in] *policy_version - policy version
 * @param[in]  len            - policy version length
*/
static hdm_return_code_t payload_policy_version_value(uint8_t *policy_version, int len) {
        char max_int_size[11] = {0,};
        if(len > CHARACTER_INT_MAX){
                return HDM_WRONG_POLICY_VERSION;
        }
        TEE_MemMove(max_int_size, policy_version, len);
        int64_t policy_version_int = convert_str_to_int64( max_int_size, len);
        payload.policy_version = FIT_TO_UINT32(policy_version_int);
        HDM_LOG_DEBUG("payload.policy_version = %d", payload.policy_version);
        return HDM_STATUS_SUCCESS;
}

/**
 * @brief
 * payload_server_nonce_value
 * Set payload server nonce value on global struct
 *
 * @param[in] *server_nonce - policy server_nonce
 * @param[in]  len          - server_nonce length
*/
static hdm_return_code_t payload_server_nonce_value(uint8_t *server_nonce, int len) {
        return set_string_value(server_nonce, len, payload.server_nonce, JWS_PAYLOAD_SERVER_NONCE_LEN);
}

/**
 * @brief
 * payload_device_id_value
 * Set payload device id value on global struct
 *
 * @param[in] *device_id - device id
 * @param[in]  len       - device id length
*/
static hdm_return_code_t payload_device_id_value(uint8_t *device_id, int len) {
        return set_string_value(device_id, len, payload.device_id, JWS_PAYLOAD_DEVICE_ID_LEN);
}

/**
 * @brief
 * generate_signature
 * Sign using CKM_SHA256_RSA_PKCS algorithm.
 *
 * @param[in]     message     - the message to be signed
 * @param[in]     message_len - the length of the message
 * @param[out]    signature   - output buffer for the generated signature
 * @param[in]     sig_len     - length of the signature buffer must be of size RESPONSE_SIGNATURE_LEN
 * @param[in]     rsa_key     - the private used to sign
 *
 * @return Status Code
*/
hdm_return_code_t generate_signature(uint8_t *message, uint32_t message_len, uint8_t *signature,
                                        uint32_t sig_len, drk_rsa_private_key_t *rsa_key) {

        uint32_t ret = HDM_STATUS_SUCCESS;
        HDM_LOG_DEBUG("generate_signature()");

        if (sig_len != RESPONSE_SIGNATURE_LEN) {
                HDM_LOG_DEBUG("Signature buffer is not big enough.\n");
                ret = HDM_SIGNATURE_ERROR;
                goto exit;
        }

        ret = TZ_sign_CKM_SHA256_RSA_PKCS(rsa_key->modulus, rsa_key->modulus_len, rsa_key->pub_expo, rsa_key->pub_expo_len, rsa_key->priv_expo, rsa_key->priv_expo_len, message, message_len, signature, &sig_len);
        if (ret != TZ_API_OK) {
                HDM_LOG_DEBUG("Failed to sign: 0x%x\n", ret);
                ret = HDM_SIGNATURE_ERROR;
                goto exit;
        }
exit:
        return ret;
}

/**
 * @brief
 * compare_device_id
 * Compare device_id with the hash of the information
 * received (imei_0/imei_1/mac_address)
 *
 * @param[in] *device_id - device id
 * @param[in] compared_len - length of compared
 * @param[in] *compared  - element to be hashed and compared
*/
static hdm_return_code_t compare_device_id(uint8_t *device_id, uint32_t compared_len, uint8_t *compared) {
        uint8_t hash_computed[SHA256_DIGEST_LENGTH+1] = {0,};
        uint32_t hash_computed_len = SHA256_DIGEST_LENGTH;
        uint8_t b64_sha256_device_id[DEVICE_ID_B64_LEN + 1] = {0,};
        uint32_t device_id_b64_len = DEVICE_ID_B64_LEN*2;
        uint32_t ret = HDM_DEVICE_ID_CHECK_FAIL;

        HDM_LOG_DEBUG("device_id %s", device_id);
        ret = compute_hash(compared, compared_len, hash_computed, &hash_computed_len, EVP_sha256());
        if (ret == HDM_STATUS_SUCCESS)
        {
                ret = base64url_encode(hash_computed, hash_computed_len, b64_sha256_device_id, &device_id_b64_len);
                if (device_id_b64_len != DEVICE_ID_B64_LEN || ret != 0) {
                        HDM_LOG("Fail to encode hash_computed");
                        HDM_LOG_DEBUG("hash_computed %s", hash_computed);
                        HDM_LOG_DEBUG("b64_sha256_device_id %s", b64_sha256_device_id);
                        ret = HDM_DEVICE_ID_CHECK_FAIL;
                        goto exit;
                }

                ret = TEE_MemCompare(device_id, b64_sha256_device_id, DEVICE_ID_B64_LEN);
                if(ret != 0)
                {
                        ret = HDM_DEVICE_ID_CHECK_FAIL;
                }
        }
exit:
        return ret;
}

/**
 * @brief
 * check_jws_device_id
 * Checks if the device_id received is valid or not
 *
 * @param[in] *device_id - device id
 * @param[in] *nwd_info  - structure with NWd information
*/
hdm_return_code_t check_jws_device_id(uint8_t *device_id, hdm_nwd_info_t nwd_info) {
        uint32_t ret = HDM_DEVICE_ID_CHECK_FAIL;

        HDM_LOG("check_jws_device_id()");
        if (strlen((char*)device_id) != JWS_PAYLOAD_DEVICE_ID_LEN-1) {
                HDM_LOG("device_id with invalid length");
                HDM_LOG_DEBUG("device_id length: %d", strlen((char*) device_id));
                goto exit;
        }

        if (compare_device_id(device_id, IMEI_LEN, nwd_info.imei_0) == HDM_STATUS_SUCCESS){
                ret = HDM_STATUS_SUCCESS;
        } else if (compare_device_id(device_id, MAC_LEN, nwd_info.mac_addr) == HDM_STATUS_SUCCESS) {
                ret = HDM_STATUS_SUCCESS;
        }

exit:
        return ret;
}
