core/cmd_interface/cmd_interface_protocol_cerberus.c (82 lines of code) (raw):

// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. #include <stddef.h> #include <string.h> #include "cerberus_protocol.h" #include "cerberus_protocol_required_commands.h" #include "cmd_interface_protocol_cerberus.h" #include "common/buffer_util.h" #include "common/unused.h" int cmd_interface_protocol_cerberus_parse_message (const struct cmd_interface_protocol *protocol, struct cmd_interface_msg *message, uint32_t *message_type) { const struct cerberus_protocol_header *header; if (message == NULL) { return CMD_HANDLER_INVALID_ARGUMENT; } message->crypto_timeout = false; if ((protocol == NULL) || (message_type == NULL)) { return CMD_HANDLER_INVALID_ARGUMENT; } if (message->payload_length < sizeof (*header)) { return CMD_HANDLER_PAYLOAD_TOO_SHORT; } header = (const struct cerberus_protocol_header*) message->payload; /* TODO: These are redundant checks that are done in the MCTP layers, but until those headers * are removed before this layer of processing, this check will remain. */ if ((header->msg_type != MCTP_BASE_PROTOCOL_MSG_TYPE_VENDOR_DEF) || (header->integrity_check == 1) || (buffer_unaligned_read16 (&header->pci_vendor_id) != CERBERUS_PROTOCOL_MSFT_PCI_VID)) { return CMD_HANDLER_UNSUPPORTED_MSG; } if ((header->reserved1 != 0) || (header->reserved2 != 0)) { return CMD_HANDLER_RSVD_NOT_ZERO; } /* Encrypted messages are not supported by this handler. This check is last to allow easy * re-use by a secure protocol handler. */ if (header->crypt == 1) { return CMD_HANDLER_ENCRYPTION_UNSUPPORTED; } /* TODO: Remove the Cerberus protocol header from the payload. This requires the rest of the * command processing stack to align with the change. The command code would need to be removed * from the header definition. */ message->is_encrypted = false; *message_type = header->command; return 0; } int cmd_interface_protocol_cerberus_handle_request_result ( const struct cmd_interface_protocol *protocol, int result, uint32_t message_type, struct cmd_interface_msg *message) { struct cerberus_protocol_header *header; if ((protocol == NULL) || (message == NULL)) { return CMD_HANDLER_INVALID_ARGUMENT; } /* TODO: Just like in the pre-processing case, a Cerberus header should be added to the payload * rather than leaving the payload pointer in the same place. */ header = (struct cerberus_protocol_header*) message->payload; /* Only update the header in the case of a successful response. */ if (result == 0) { /* If the handler did not generate any response payload, create a status response indicating * that the command completed successfully. The rq bit from the request is used to * determine what value to set in the response. * * This checks both payload and data lengths to cover command handlers that don't correctly * update the payload length. */ if ((message->payload_length == 0) || (message->length == 0)) { cerberus_protocol_build_error_response (message, CERBERUS_PROTOCOL_NO_ERROR, 0, header->rq, 0); } else { /* TODO: These are MCTP components and should be updated by MCTP protocol handlers * rather then here. These will eventually be removed. */ header->msg_type = MCTP_BASE_PROTOCOL_MSG_TYPE_VENDOR_DEF; header->integrity_check = 0; buffer_unaligned_write16 (&header->pci_vendor_id, CERBERUS_PROTOCOL_MSFT_PCI_VID); /* Leave the rq bit unchanged while populating the header as this layer does not have * context about what it should be for this message. */ header->reserved1 = 0; header->crypt = 0; header->reserved2 = 0; header->command = message_type; } } else { /* Generate an error response on failure. It should not be possible to exit this handler * without a valid response generated. Use the request header data, which should not have * been modified by this point to determine the rq bit value for the response. */ cerberus_protocol_build_error_response (message, CERBERUS_PROTOCOL_ERROR_UNSPECIFIED, result, header->rq, message_type); } /* There will always be a response populated when exiting. */ return 0; } /** * Initialize a protocol handler for Cerberus messages. The handler does not have support for * encrypted messages. * * @param cerberus The Cerberus handler to initialize. * * @return 0 if the handler was initialized successfully or an error code. */ int cmd_interface_protocol_cerberus_init (struct cmd_interface_protocol_cerberus *cerberus) { if (cerberus == NULL) { return CMD_HANDLER_INVALID_ARGUMENT; } memset (cerberus, 0, sizeof (struct cmd_interface_protocol_cerberus)); cerberus->base.parse_message = cmd_interface_protocol_cerberus_parse_message; cerberus->base.handle_request_result = cmd_interface_protocol_cerberus_handle_request_result; return 0; } /** * Release the resources used by a Cerberus message protocol handler. * * @param cerberus The Cerberus handler to release. */ void cmd_interface_protocol_cerberus_release ( const struct cmd_interface_protocol_cerberus *cerberus) { UNUSED (cerberus); }