core/cmd_interface/cmd_interface.h (93 lines of code) (raw):
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
#ifndef CMD_INTERFACE_H_
#define CMD_INTERFACE_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "session_manager.h"
#include "status/rot_status.h"
/**
* Container for message data.
*/
struct cmd_interface_msg {
/**
* The raw message data buffer.
*
* This contains the full message to process, including all protocol headers. If the message is
* a request, this buffer can be updated with the response data, while providing sufficient
* space before the data for any protocol headers that will need to be added.
*
* This pointer must not be changed during message processing.
*/
uint8_t *data;
/**
* Length of the data buffer contents.
*
* This doesn't necessarily equate to the maximum size of the data buffer, since a message may
* only be using part of the overall buffer.
*/
size_t length;
/**
* Maximum length allowed for a response.
*
* This indicates the maximum amount of data that should be written into the data buffer when
* constructing a response payload. When using the payload pointer for response building, this
* field should not be accessed directly, but instead should be queried using
* {@link cmd_interface_msg_get_max_response}.
*/
size_t max_response;
/**
* Payload data for the message.
*
* This is a pointer to a location in the message buffer indicating where the payload starts,
* after accounting for protocol headers. The protocol stack will move this pointer as messages
* pass through the various processing layers. This can be filled with response data without
* needing to account for protocol header space.
*/
uint8_t *payload;
/**
* Length of the message payload.
*
* This does not indicate the maximum length of the payload buffer for building responses. This
* value can be determined with {@link cmd_interface_msg_get_max_response}.
*/
size_t payload_length;
/**
* Endpoint ID that generated the message.
*/
uint8_t source_eid;
/**
* Address of the device that generated the message.
*/
uint8_t source_addr;
/**
* Endpoint ID that should process the message.
*/
uint8_t target_eid;
/**
* Flag indicating if the message is encrypted or should be encrypted.
*/
bool is_encrypted;
/**
* Flag indicating if the message is a request and required cryptographic operations. If so, it
* should be granted a longer timeout for request processing.
*
* This is set for every message, even when there is an error.
*/
bool crypto_timeout;
/**
* Channel on which the message was received.
*/
int channel_id;
};
/**
* A list of firmware versions.
*/
struct cmd_interface_fw_version {
size_t count; /**< The number of firmware identifiers. */
const char **id; /**< The list of firmware identifiers. */
};
/**
* A list of device IDs.
*/
struct cmd_interface_device_id {
uint16_t vendor_id; /**< Vendor ID */
uint16_t device_id; /**< Device ID */
uint16_t subsystem_vid; /**< Subsystem vendor ID */
uint16_t subsystem_id; /**< Subsystem ID */
};
/**
* Command interface for processing received requests.
*/
struct cmd_interface {
/**
* Process a received request.
*
* @param intf The command interface that will process the request.
* @param request The request data to process. This will be updated to contain a response, if
* necessary.
*
* @return 0 if the request was successfully processed or an error code.
*/
int (*process_request) (const struct cmd_interface *intf, struct cmd_interface_msg *request);
#ifdef CMD_ENABLE_ISSUE_REQUEST
/**
* Process a received response.
*
* TODO: Likely remove this function from this interface. The request issuing flow using
* msg_transport does not rely on this type of response handling. Removing this would make this
* interface cleaner (i.e. remove the need for the #ifdef).
*
* @param intf The command interface that will process the response.
* @param response The response data to process.
*
* @return 0 if the response was successfully processed or an error code.
*/
int (*process_response) (const struct cmd_interface *intf, struct cmd_interface_msg *response);
#endif
/* TODO: Now that the cmd_interface is used for more than Cerberus messages, this should get
* refactored out of the base interface and into some Cerberus specific handling, like the
* protocol handlers. */
struct session_manager *session; /**< Session manager for channel encryption */
};
/**
* Interface to a protocol specific handler that can be used to extract message details necessary
* for routing the message to an appropriate handler and to apply any necessary protocol handling as
* part of message processing.
*/
struct cmd_interface_protocol {
/**
* Parse a message based on protocol rules and prepare it for further message handling. Parsing
* a message can involve operations such as:
* - Checking that a message meets the minimum protocol requirements.
* - Removing protocol specific headers from the payload.
* - Adjusting the maximum allowed response message.
* - Decrypting messages.
*
* Since this call will alter the state of the message container, and possibly the payload data
* itself, it must only be called once per message for each protocol handler.
*
* @param protocol The protocol handler to use for parsing the message.
* @param message The received message to parse. Upon successful return, the message will have
* been updated based on the protocol requirements.
* @param message_type Output for the message type identifier to use for message routing.
*
* @return 0 if the message was parsed successfully or an error code. If an error response
* message was generated during processing, CMD_HANDLER_PROTO_ERROR_RESPONSE will be returned.
*/
int (*parse_message) (const struct cmd_interface_protocol *protocol,
struct cmd_interface_msg *message, uint32_t *message_type);
/**
* Execute any additional processing on a request message after it has been processed by the
* appropriate command handler(s).
*
* The specific actions that are necessary here will be determined by the protocol handler, but
* at minimum, this call will need to manage the protocol header for the response payload.
* - If the request processing was successful, meaning the message descriptor contains a
* response message, the necessary protocol header will need to be added to the response
* payload.
* - If the request processing failed, there are two ways the protocol header could be dealt
* with.
* 1. A protocol error response is generated with necessary protocol headers.
* 2. The message descriptor payload is updated to add the protocol header space without
* adding any data. This makes the space available for the next layer in the stack to
* use when handling the error.
*
* This can be set to null if a specific protocol does not need to do any additional processing.
*
* @param protocol The protocol handler to use for message processing.
* @param result Result from request message processing. This will be 0 if processing was
* successful or a response message has already been generated. Otherwise, this will be an
* error code. If no handler could be found to process the request, this result will be
* CMD_HANDLER_UNKNOWN_MESSAGE_TYPE.
* @param message_type The message type identifier of the request message.
* @param message The message descriptor for message processing. Depending on the processing
* result, this will either contain a response message or the failed request.
*
* @return 0 if the message descriptor contains a response message or an error code to return to
* the to the previous layer of the protocol stack.
*/
int (*handle_request_result) (const struct cmd_interface_protocol *protocol, int result,
uint32_t message_type, struct cmd_interface_msg *message);
};
/* Utility functions for managing messages. */
void cmd_interface_msg_new_message (struct cmd_interface_msg *message, uint8_t source_eid,
uint8_t source_addr, uint8_t target_eid, int channel_id);
void cmd_interface_msg_add_payload_data (struct cmd_interface_msg *message, const uint8_t *data,
size_t length);
void cmd_interface_msg_set_message_payload_length (struct cmd_interface_msg *message,
size_t length);
void cmd_interface_msg_remove_protocol_header (struct cmd_interface_msg *message,
size_t header_length);
void cmd_interface_msg_add_protocol_header (struct cmd_interface_msg *message,
size_t header_length);
size_t cmd_interface_msg_get_protocol_length (const struct cmd_interface_msg *message);
size_t cmd_interface_msg_get_max_response (const struct cmd_interface_msg *message);
void cmd_interface_msg_set_max_response (struct cmd_interface_msg *message, size_t max_response);
/* Internal functions for use by derived types. */
int cmd_interface_process_cerberus_protocol_message (const struct cmd_interface *intf,
struct cmd_interface_msg *message, uint8_t *command_id, uint8_t *command_set, bool decrypt,
bool rsvd_zero);
int cmd_interface_prepare_response (const struct cmd_interface *intf,
struct cmd_interface_msg *response);
#define CMD_HANDLER_ERROR(code) ROT_ERROR (ROT_MODULE_CMD_HANDLER, code)
/**
* Error codes that can be generated by the command handler.
*
* Note: Commented error codes have been deprecated.
*/
enum {
CMD_HANDLER_INVALID_ARGUMENT = CMD_HANDLER_ERROR (0x00), /**< Input parameter is null or not valid. */
CMD_HANDLER_NO_MEMORY = CMD_HANDLER_ERROR (0x01), /**< Memory allocation failed. */
CMD_HANDLER_PROCESS_FAILED = CMD_HANDLER_ERROR (0x02), /**< A general error while processing the request. */
CMD_HANDLER_PAYLOAD_TOO_SHORT = CMD_HANDLER_ERROR (0x03), /**< The request does not contain the minimum amount of data. */
CMD_HANDLER_BAD_LENGTH = CMD_HANDLER_ERROR (0x04), /**< The payload length is wrong for the request. */
CMD_HANDLER_OUT_OF_RANGE = CMD_HANDLER_ERROR (0x05), /**< A request argument is not within the valid range. */
CMD_HANDLER_UNKNOWN_REQUEST = CMD_HANDLER_ERROR (0x06), /**< A command does not represent a known request. */
//CMD_HANDLER_UNSUPPORTED_EID = CMD_HANDLER_ERROR (0x07), /**< The request was sent to an unsupported endpoint. */
CMD_HANDLER_UNSUPPORTED_INDEX = CMD_HANDLER_ERROR (0x08), /**< Request for information with an unsupported index was received. */
CMD_HANDLER_UNSUPPORTED_LEN = CMD_HANDLER_ERROR (0x09), /**< Request for information with an unsupported length was received. */
CMD_HANDLER_INVALID_DEVICE_MODE = CMD_HANDLER_ERROR (0x0A), /**< Invalid device mode. */
CMD_HANDLER_BUF_TOO_SMALL = CMD_HANDLER_ERROR (0x0B), /**< Provided buffer too small for output. */
CMD_HANDLER_UNSUPPORTED_COMMAND = CMD_HANDLER_ERROR (0x0C), /**< The command is valid but is not supported by the device. */
CMD_HANDLER_UNSUPPORTED_MSG = CMD_HANDLER_ERROR (0x0D), /**< Message type not supported. */
CMD_HANDLER_UNSUPPORTED_CHANNEL = CMD_HANDLER_ERROR (0x0E), /**< The command is received on a channel not supported by the device. */
CMD_HANDLER_UNSUPPORTED_OPERATION = CMD_HANDLER_ERROR (0x0F), /**< The requested operation is not supported. */
CMD_HANDLER_RESPONSE_TOO_SMALL = CMD_HANDLER_ERROR (0x10), /**< The maximum allowed response is too small for the output. */
CMD_HANDLER_ENCRYPTION_UNSUPPORTED = CMD_HANDLER_ERROR (0x11), /**< Channel encryption not supported on this interface. */
CMD_HANDLER_CMD_SHOULD_BE_ENCRYPTED = CMD_HANDLER_ERROR (0x12), /**< Secure command received unencrypted after establishing an encrypted channel. */
CMD_HANDLER_RSVD_NOT_ZERO = CMD_HANDLER_ERROR (0x13), /**< Reserved field is non-zero. */
CMD_HANDLER_ERROR_MESSAGE = CMD_HANDLER_ERROR (0x14), /**< The handler received an error message for processing. */
CMD_HANDLER_ISSUE_FAILED = CMD_HANDLER_ERROR (0x15), /**< Failed to generate the request message. */
CMD_HANDLER_ERROR_MSG_FAILED = CMD_HANDLER_ERROR (0x16), /**< Failed to generate an error message. */
CMD_HANDLER_UNKNOWN_RESPONSE = CMD_HANDLER_ERROR (0x17), /**< A command does not represent a known response. */
CMD_HANDLER_INVALID_ERROR_MSG = CMD_HANDLER_ERROR (0x18), /**< The handler received an invalid error message. */
CMD_HANDLER_UNKNOWN_MESSAGE_TYPE = CMD_HANDLER_ERROR (0x19), /**< The received message type is unknown to the handler. */
CMD_HANDLER_PROTO_PARSE_FAILED = CMD_HANDLER_ERROR (0x1a), /**< Failed to parse a message. */
CMD_HANDLER_PROTO_HANDLE_FAILED = CMD_HANDLER_ERROR (0x1b), /**< Failed to handle the result of request processing. */
CMD_HANDLER_PROTO_ERROR_RESPONSE = CMD_HANDLER_ERROR (0x1c), /**< The protocol generated an error response. */
};
#endif /* CMD_INTERFACE_H_ */