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;
}