Skip to main content

Crate mctp_rs

Crate mctp_rs 

Source
Expand description

§mctp-rs

A no_std Rust implementation of the DMTF Management Component Transport Protocol (MCTP) transport.

§Receiving and parsing messages

Use MctpPacketContext with your medium to assemble messages from packets.

let mut assembly_buffer = [0u8; 1024];
let medium = MyMedium { mtu: 256 };
let mut context = MctpPacketContext::new(medium, &mut assembly_buffer);

// Typically obtained from your bus
let raw_packet_data: &[u8] = &[0x01, 0x02, 0x03, 0x83];

match context.deserialize_packet(raw_packet_data) {
    Ok(Some(message)) => {
        // We received a complete MCTP message
        if let Ok((header, control)) = message.parse_as::<MctpControl>() {
            match control {
                MctpControl::GetEndpointIdRequest => {
                    // Handle control request
                    let _instance = header.instance_id;
                }
                MctpControl::GetEndpointIdResponse(bytes3) => {
                    // Use response payload (3 bytes as per spec)
                    let _eid = bytes3[0];
                }
                _ => {}
            }
        }
    }
    Ok(None) => { /* partial message; wait for more packets */ }
    Err(e) => {
        // handle protocol/medium error
        let _ = e;
    }
}

§Sending messages

Construct a header + body pair implementing MctpMessageTrait and serialize to one or more packets using serialize_packet.

let mut buf = [0u8; 1024];
let mut ctx = MctpPacketContext::new(MyMedium { mtu: 64 }, &mut buf);

let reply = MctpReplyContext {
    destination_endpoint_id: EndpointId::try_from(0x20).unwrap(),
    source_endpoint_id: EndpointId::try_from(0x21).unwrap(),
    packet_sequence_number: MctpSequenceNumber::new(0),
    message_tag: MctpMessageTag::try_from(1).unwrap(),
    medium_context: (),
};

let message = (
    VendorDefinedPciHeader(0x1234),
    VendorDefinedPci(&[0xDE, 0xAD, 0xBE, 0xEF]),
);

let mut packets = ctx.serialize_packet(reply, message).unwrap();
while let Some(packet_result) = packets.next() {
    let packet_bytes = packet_result.unwrap();
    // send `packet_bytes` via your bus
    let _ = packet_bytes;
}

§Implementing a custom medium

The crate is transport-agnostic via the MctpMedium trait. Implement it for your bus (e.g., SMBus, eSPI) and provide a frame type implementing MctpMediumFrame.

use mctp_rs::*;

#[derive(Debug, Clone, Copy)]
struct MyMedium {
    mtu: usize,
}

#[derive(Debug, Clone, Copy)]
struct MyMediumFrame {
    packet_size: usize,
}

impl MctpMedium for MyMedium {
    type Frame = MyMediumFrame;
    type Error = &'static str;
    type ReplyContext = ();
    type Encoding = PassthroughEncoding;

    fn max_message_body_size(&self) -> usize {
        self.mtu
    }

    fn deserialize<'buf>(
        &self,
        packet: &'buf [u8],
    ) -> MctpPacketResult<(Self::Frame, EncodingDecoder<'buf, Self::Encoding>), Self> {
        // Strip/validate transport headers as needed for your bus and return MCTP payload slice
        Ok((
            MyMediumFrame {
                packet_size: packet.len(),
            },
            EncodingDecoder::new(packet),
        ))
    }

    fn serialize<'buf, F>(
        &self,
        _reply_context: Self::ReplyContext,
        buffer: &'buf mut [u8],
        message_writer: F,
    ) -> MctpPacketResult<&'buf [u8], Self>
    where
        F: for<'a> FnOnce(
            &mut EncodingEncoder<'a, Self::Encoding>,
        ) -> MctpPacketResult<(), Self>,
    {
        // Prepend transport headers as needed, then ask the writer to write MCTP payload
        let written = {
            let mut encoder = EncodingEncoder::<Self::Encoding>::new(buffer);
            message_writer(&mut encoder)?;
            encoder.wire_position()
        };
        Ok(&buffer[..written])
    }
}

impl MctpMediumFrame<MyMedium> for MyMediumFrame {
    fn packet_size(&self) -> usize {
        self.packet_size
    }
    fn reply_context(&self) -> <MyMedium as MctpMedium>::ReplyContext {
        ()
    }
}

Re-exports§

pub use error::MctpPacketError;
pub use error::MctpPacketResult;

Modules§

error
mctp_completion_code
serial
DSP0253 byte-stuffed serial medium for MCTP.
smbus_espi

Structs§

EncodingDecoder
Stateful cursor over a &[u8] wire buffer that reads decoded bytes through E: BufferEncoding. Constructed by MctpMedium::deserialize and handed to higher layers so they cannot bypass the encoding by slicing the underlying buffer directly.
EncodingEncoder
Stateful cursor over a &mut [u8] wire buffer that writes decoded bytes through E: BufferEncoding. Constructed by MctpMedium::serialize and handed to the caller’s message_writer closure so the closure cannot bypass the encoding.
MctpControlHeader
MctpMessage
MctpMessageBuffer
MctpMessageTag
MctpPacketContext
Context for serializing and deserializing an MCTP message, which may be split among multiple packets.
MctpReplyContext
Represents the state needed to construct a repsonse to a request: the MCTP transport source/destination, the sequence number to use for the reply, and the medium-specific context that came with the request.
MctpSequenceNumber
MctpSerialMedium
MctpSerialMediumFrame
PassthroughEncoding
No-op encoding: wire bytes ARE payload bytes. Used by media that do not byte-stuff (SMBus/eSPI, test fixtures).
SerialEncoding
DSP0253 byte-stuffing transform. Stateless ZST.
VendorDefinedPci
VendorDefinedPciHeader

Enums§

DecodeError
EncodeError
EndpointId
MctpControl

Constants§

CONST_MTU
Maximum DSP0253 packet body size (DECODED bytes, before stuffing).
EC_EID
EC MCTP endpoint id per CONTEXT D-D-06.
SP_EID
SP MCTP endpoint id per CONTEXT D-D-06.

Traits§

BufferEncoding
Stateless byte-stuffing transform. Implementors define how a single logical (payload) byte maps to one or more wire bytes (encode) and how a wire-byte prefix maps back to a single payload byte (decode).
MctpMedium
MctpMediumFrame
MctpMessageHeaderTrait
MctpMessageTrait