int mctp_interface_process_packet()

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