in core/mctp/mctp_interface.c [816:972]
int mctp_interface_process_packet (const struct mctp_interface *mctp, struct cmd_packet *rx_packet,
struct cmd_message **tx_message)
{
const uint8_t *payload;
uint8_t src_eid = 0;
uint8_t dest_eid = 0;
uint8_t msg_tag = 0;
uint8_t packet_seq;
uint8_t crc = 0;
uint8_t response_addr = 0;
uint8_t tag_owner;
uint8_t msg_type;
size_t payload_len;
bool som;
bool eom;
int self_eid;
int status;
if ((mctp == NULL) || (rx_packet == NULL) || (tx_message == NULL)) {
return MCTP_BASE_PROTOCOL_INVALID_ARGUMENT;
}
*tx_message = NULL;
self_eid = device_manager_get_device_eid (mctp->device_manager, DEVICE_MANAGER_SELF_DEVICE_NUM);
if (ROT_IS_ERROR (self_eid)) {
return self_eid;
}
/* Parse the received packet. */
status = mctp_base_protocol_interpret (rx_packet->data, rx_packet->pkt_size,
rx_packet->dest_addr, &response_addr, &som, &eom, &src_eid, &dest_eid, &payload,
&payload_len, &msg_tag, &packet_seq, &crc, &msg_type, &tag_owner);
if (status == 0) {
/* If the packet is not destined for this device, ignore it. */
if ((dest_eid != self_eid) && (dest_eid != MCTP_BASE_PROTOCOL_NULL_EID)) {
return 0;
}
if (tag_owner == MCTP_BASE_PROTOCOL_TO_RESPONSE) {
if (!mctp_interface_is_expected_response (mctp, msg_tag, som, msg_type)) {
/* Unexpected response packets must not interrupt message assembly and should be
* ignored. */
return 0;
}
}
else if (som) {
/* MCTP message assembly should not be interrupted by packets for an unsupported message
* type. The message type is only present in the SOM packet. For request messages,
* check the request handler to see if the message type is supported. */
status = mctp->req_handler->is_message_type_supported (mctp->req_handler, msg_type);
if (status == CMD_HANDLER_UNKNOWN_MESSAGE_TYPE) {
status = MCTP_BASE_PROTOCOL_UNSUPPORTED_MSG;
}
}
}
if (status != 0) {
/* Drop the packet if it's invalid in some way. This must not impact any active message
* assembly. */
return mctp_interface_drop_packet (mctp, rx_packet, status, src_eid, dest_eid, msg_tag,
crc);
}
/* Check message assembly state relative to the new packet that was received. */
if (som) {
if (mctp->state->start_packet_len != 0) {
/* A new message is being started before the previous one has completed. This is
* considered an error scenario by MCTP, so it's logged. */
debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_MCTP,
MCTP_LOGGING_CHANNEL, mctp->state->channel_id, 0);
debug_log_create_entry (DEBUG_LOG_SEVERITY_ERROR, DEBUG_LOG_COMPONENT_MCTP,
MCTP_LOGGING_RESTART_MESSAGE,
((mctp->state->req_buffer.source_eid << 24) | (mctp->state->msg_tag << 16) |
(mctp->state->tag_owner << 8) | mctp->state->msg_type),
((src_eid << 24) | (msg_tag << 16) | (tag_owner << 8) | msg_type));
}
cmd_interface_msg_new_message (&mctp->state->req_buffer, src_eid, response_addr, dest_eid,
mctp->state->channel_id);
mctp->state->start_packet_len = payload_len;
mctp->state->packet_seq = packet_seq;
mctp->state->msg_tag = msg_tag;
mctp->state->msg_type = msg_type;
mctp->state->tag_owner = tag_owner;
}
else if (mctp->state->start_packet_len == 0) {
/* Drop the packet if this packet is not a SOM and there is no message currently being
* assembled. */
return mctp_interface_drop_packet (mctp, rx_packet, MCTP_BASE_PROTOCOL_NO_SOM, src_eid,
dest_eid, msg_tag, 0);
}
else if ((msg_tag != mctp->state->msg_tag) || (tag_owner != mctp->state->tag_owner)) {
/* This is a special case of the no SOM handling. In this case, a packet was received for a
* message terminus that is different from the message currently being assembled.
*
* Drop the packet and do not interrupt message assembly. */
return mctp_interface_drop_packet (mctp, rx_packet, MCTP_BASE_PROTOCOL_UNEXPECTED_PKT,
src_eid, dest_eid, msg_tag, 0);
}
else if (src_eid != mctp->state->req_buffer.source_eid) {
/* This is the same special case for no SOM handling, but in this case the message terminus
* is different because of the source EID. This is handled separately only so that a
* different error can be logged.
*
* Drop the packet and do not interrupt message assembly. */
return mctp_interface_drop_packet (mctp, rx_packet, MCTP_BASE_PROTOCOL_INVALID_EID, src_eid,
dest_eid, msg_tag, 0);
}
else if (packet_seq != mctp->state->packet_seq) {
/* The packet sequence number is wrong. Reset message assembly and drop the packet. */
mctp_interface_reset_message_assembly (mctp);
return mctp_interface_drop_packet (mctp, rx_packet, MCTP_BASE_PROTOCOL_OUT_OF_SEQUENCE,
src_eid, dest_eid, msg_tag, 0);
}
else if ((payload_len != mctp->state->start_packet_len) &&
!(eom && (payload_len < mctp->state->start_packet_len))) {
/* Middle packets must be the same size as the first packet. Reset message assembly and
* drop the packet.
*
* Last packets can be smaller, but not larger, than the first packet. */
mctp_interface_reset_message_assembly (mctp);
return mctp_interface_drop_packet (mctp, rx_packet, MCTP_BASE_PROTOCOL_MIDDLE_PKT_LENGTH,
src_eid, dest_eid, msg_tag, payload_len);
}
/* Add the new packet data to the message being assembled. */
if ((payload_len + mctp->state->req_buffer.length) > MCTP_BASE_PROTOCOL_MAX_MESSAGE_BODY) {
/* The request has grown too large for the message buffer. Reset message assembly and
* drop the packet. */
payload_len += mctp->state->req_buffer.length;
mctp_interface_reset_message_assembly (mctp);
return mctp_interface_drop_packet (mctp, rx_packet, MCTP_BASE_PROTOCOL_MSG_TOO_LARGE,
src_eid, dest_eid, msg_tag, payload_len);
}
cmd_interface_msg_add_payload_data (&mctp->state->req_buffer, payload, payload_len);
mctp->state->packet_seq = (mctp->state->packet_seq + 1) % 4;
/* If this is the last packet in the message, process the complete message. */
if (eom) {
if (tag_owner == MCTP_BASE_PROTOCOL_TO_RESPONSE) {
/* The message contains response data. */
return mctp_interface_handle_response_message (mctp);
}
else {
/* The message contains request data. */
return mctp_interface_handle_request_message (mctp, rx_packet, tx_message);
}
}
return 0;
}