int tpm_comm_submit_command()

in src/tpm_comm_linux.c [372:508]


int tpm_comm_submit_command(TPM_COMM_HANDLE handle, const unsigned char* cmd_bytes, uint32_t bytes_len, unsigned char* response, uint32_t* resp_len)
{
    int result;
    if (handle == NULL || cmd_bytes == NULL || response == NULL || resp_len == NULL)
    {
        LogError("Invalid argument specified handle: %p, cmd_bytes: %p, response: %p, resp_len: %p.", handle, cmd_bytes, response, resp_len);
        result = MU_FAILURE;
    }
    else if (*resp_len < 10)
    {
        LogError("Response buffer must be at least 10 bytes long %d", *resp_len);
        result = MU_FAILURE;
    }
    else if (handle->conn_info & TCI_SYS_DEV)
    {
        // Send to TPM
        if (write_data_to_tpm(handle, (const unsigned char*)cmd_bytes, bytes_len) != 0)
        {
            LogError("Failure setting locality to TPM");
            result = MU_FAILURE;
        }
        else
        {
            if (read_data_from_tpm(handle, response, resp_len) != 0)
            {
                LogError("Failure reading bytes from tpm");
                result = MU_FAILURE;
            }
            else
            {
                result = 0;
            }
        }
    }
    else if (handle->conn_info & TCI_TCTI)
    {
        void* ctx_handle = handle->dev_info.tcti.ctx_handle;
        TCTI_CTX *tcti_ctx = (TCTI_CTX*)ctx_handle;
        uint32_t rc = tcti_ctx->transmit(ctx_handle, bytes_len, cmd_bytes);
        if (rc != 0)
        {
            LogError("TCTI_CTX::transmit() failed: 0x%08X\n", rc);
            result = MU_FAILURE;
        }
        else
        {
            size_t  bytes_returned = *resp_len;
            // abrmd has a bug of not setting the returned size when the TPM command fails.
            // So we have to look into that actual TPM response buffer.
            memset(response, 0, 10);
            rc = tcti_ctx->receive(ctx_handle, &bytes_returned, response, 5 * 60 * 1000);
            if (rc == 0)
            {
                uint32_t tpm_response_size = ntohl(*((uint32_t*)(response + 2)));
                *resp_len = tpm_response_size < bytes_returned ? tpm_response_size : (uint32_t)bytes_returned;
                result = 0;
            }
            else
            {
                LogError("TCTI_CTX::receive() failed: 0x%08X\n", rc);
                result = MU_FAILURE;
            }
        }
    }
    else if (handle->conn_info & TCI_SOCKET)
    {
        unsigned char locality = 0;
        if (send_sync_cmd(handle, REMOTE_SEND_COMMAND) != 0)
        {
            LogError("Failure preparing sending Remote Command");
            result = MU_FAILURE;
        }
        else if (send_sync_bytes(handle, (const unsigned char*)&locality, 1) != 0)
        {
            LogError("Failure setting locality to TPM");
            result = MU_FAILURE;
        }
        else if (send_old_um_trm_data(handle) != 0)
        {
            LogError("Failure communicating with old user mode TPM");
            result = MU_FAILURE;
        }
        else if (send_sync_cmd(handle, bytes_len) != 0)
        {
            LogError("Failure writing command bit to tpm");
            result = MU_FAILURE;
        }
        else if (send_sync_bytes(handle, cmd_bytes, bytes_len))
        {
            LogError("Failure writing data to tpm");
            result = MU_FAILURE;
        }
        else
        {
            uint32_t length_byte;

            if (read_sync_cmd(handle, &length_byte) != 0)
            {
                LogError("Failure reading length data from tpm");
                result = MU_FAILURE;
            }
            else if (length_byte > *resp_len)
            {
                LogError("Bytes read are greater then bytes expected len_bytes:%u expected: %u", length_byte, *resp_len);
                result = MU_FAILURE;
            }
            else
            {
                *resp_len = length_byte;
                if (read_sync_bytes(handle, response, &length_byte) != 0)
                {
                    LogError("Failure reading bytes");
                    result = MU_FAILURE;
                }
                else
                {
                    // check the Ack
                    if ( !is_ack_ok(handle) )
                    {
                        LogError("Failure reading TRM ack");
                        result = MU_FAILURE;
                    }
                    else
                    {
                        result = 0;
                    }
                }
            }
        }
    }
    else
    {
        LogError("Submitting command to an uninitialized TPM_COMM_HANDLE");
        result = MU_FAILURE;
    }
    return result;
}