Skip to main content

mctp_rs/
lib.rs

1#![no_std]
2#![allow(dead_code)]
3// extern crate std;
4//! # mctp-rs
5//!
6//! A `no_std` Rust implementation of the [DMTF Management Component Transport Protocol (MCTP)](https://www.dmtf.org/sites/default/files/standards/documents/DSP0236_1.3.3.pdf)
7//! transport.
8//!
9//! ## Receiving and parsing messages
10//!
11//! Use `MctpPacketContext` with your medium to assemble messages from packets.
12//!
13//! ```rust,no_run
14//! # use mctp_rs::*;
15//! # #[derive(Debug, Clone, Copy)] struct MyMedium { mtu: usize }
16//! # #[derive(Debug, Clone, Copy)] struct MyMediumFrame { packet_size: usize }
17//! # impl MctpMedium for MyMedium { type Frame=MyMediumFrame; type Error=&'static str; type ReplyContext=(); type Encoding=PassthroughEncoding;
18//! #   fn max_message_body_size(&self)->usize{self.mtu}
19//! #   fn deserialize<'b>(&self,p:&'b [u8])->MctpPacketResult<(Self::Frame,EncodingDecoder<'b,Self::Encoding>),Self>{Ok((MyMediumFrame{packet_size:p.len()},EncodingDecoder::new(p)))}
20//! #   fn serialize<'b,F>(&self,_:Self::ReplyContext,b:&'b mut [u8],w:F)->MctpPacketResult<&'b [u8],Self> where F: for<'a> FnOnce(&mut EncodingEncoder<'a,Self::Encoding>)->MctpPacketResult<(),Self>{let n={let mut e=EncodingEncoder::<Self::Encoding>::new(b);w(&mut e)?;e.wire_position()};Ok(&b[..n])}}
21//! # impl MctpMediumFrame<MyMedium> for MyMediumFrame { fn packet_size(&self)->usize{self.packet_size} fn reply_context(&self)->(){()}}
22//! let mut assembly_buffer = [0u8; 1024];
23//! let medium = MyMedium { mtu: 256 };
24//! let mut context = MctpPacketContext::new(medium, &mut assembly_buffer);
25//!
26//! // Typically obtained from your bus
27//! let raw_packet_data: &[u8] = &[0x01, 0x02, 0x03, 0x83];
28//!
29//! match context.deserialize_packet(raw_packet_data) {
30//!     Ok(Some(message)) => {
31//!         // We received a complete MCTP message
32//!         if let Ok((header, control)) = message.parse_as::<MctpControl>() {
33//!             match control {
34//!                 MctpControl::GetEndpointIdRequest => {
35//!                     // Handle control request
36//!                     let _instance = header.instance_id;
37//!                 }
38//!                 MctpControl::GetEndpointIdResponse(bytes3) => {
39//!                     // Use response payload (3 bytes as per spec)
40//!                     let _eid = bytes3[0];
41//!                 }
42//!                 _ => {}
43//!             }
44//!         }
45//!     }
46//!     Ok(None) => { /* partial message; wait for more packets */ }
47//!     Err(e) => {
48//!         // handle protocol/medium error
49//!         let _ = e;
50//!     }
51//! }
52//! ```
53//! ## Sending messages
54//!
55//! Construct a header + body pair implementing `MctpMessageTrait` and serialize to one or
56//! more packets using `serialize_packet`.
57//!
58//! ```rust,no_run
59//! # use mctp_rs::*;
60//! # #[derive(Debug, Clone, Copy)] struct MyMedium { mtu: usize }
61//! # #[derive(Debug, Clone, Copy)] struct MyMediumFrame { packet_size: usize }
62//! # 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}
63//! #   fn deserialize<'b>(&self,p:&'b [u8])->MctpPacketResult<(Self::Frame,EncodingDecoder<'b,Self::Encoding>),Self>{Ok((MyMediumFrame{packet_size:p.len()},EncodingDecoder::new(p)))}
64//! #   fn serialize<'b,F>(&self,_:Self::ReplyContext,b:&'b mut [u8],w:F)->MctpPacketResult<&'b [u8],Self> where F: for<'a> FnOnce(&mut EncodingEncoder<'a,Self::Encoding>)->MctpPacketResult<(),Self>{let n={let mut e=EncodingEncoder::<Self::Encoding>::new(b);w(&mut e)?;e.wire_position()};Ok(&b[..n])}}
65//! # impl MctpMediumFrame<MyMedium> for MyMediumFrame { fn packet_size(&self)->usize{self.packet_size} fn reply_context(&self)->(){()}}
66//! let mut buf = [0u8; 1024];
67//! let mut ctx = MctpPacketContext::new(MyMedium { mtu: 64 }, &mut buf);
68//!
69//! let reply = MctpReplyContext {
70//!     destination_endpoint_id: EndpointId::try_from(0x20).unwrap(),
71//!     source_endpoint_id: EndpointId::try_from(0x21).unwrap(),
72//!     packet_sequence_number: MctpSequenceNumber::new(0),
73//!     message_tag: MctpMessageTag::try_from(1).unwrap(),
74//!     medium_context: (),
75//! };
76//!
77//! let message = (
78//!     VendorDefinedPciHeader(0x1234),
79//!     VendorDefinedPci(&[0xDE, 0xAD, 0xBE, 0xEF]),
80//! );
81//!
82//! let mut packets = ctx.serialize_packet(reply, message).unwrap();
83//! while let Some(packet_result) = packets.next() {
84//!     let packet_bytes = packet_result.unwrap();
85//!     // send `packet_bytes` via your bus
86//!     let _ = packet_bytes;
87//! }
88//! ```
89//!
90//! ## Implementing a custom medium
91//!
92//! The crate is transport-agnostic via the `MctpMedium` trait. Implement it for your bus
93//! (e.g., SMBus, eSPI) and provide a frame type implementing `MctpMediumFrame`.
94//!
95//! ```rust,no_run
96//! use mctp_rs::*;
97//!
98//! #[derive(Debug, Clone, Copy)]
99//! struct MyMedium {
100//!     mtu: usize,
101//! }
102//!
103//! #[derive(Debug, Clone, Copy)]
104//! struct MyMediumFrame {
105//!     packet_size: usize,
106//! }
107//!
108//! impl MctpMedium for MyMedium {
109//!     type Frame = MyMediumFrame;
110//!     type Error = &'static str;
111//!     type ReplyContext = ();
112//!     type Encoding = PassthroughEncoding;
113//!
114//!     fn max_message_body_size(&self) -> usize {
115//!         self.mtu
116//!     }
117//!
118//!     fn deserialize<'buf>(
119//!         &self,
120//!         packet: &'buf [u8],
121//!     ) -> MctpPacketResult<(Self::Frame, EncodingDecoder<'buf, Self::Encoding>), Self> {
122//!         // Strip/validate transport headers as needed for your bus and return MCTP payload slice
123//!         Ok((
124//!             MyMediumFrame {
125//!                 packet_size: packet.len(),
126//!             },
127//!             EncodingDecoder::new(packet),
128//!         ))
129//!     }
130//!
131//!     fn serialize<'buf, F>(
132//!         &self,
133//!         _reply_context: Self::ReplyContext,
134//!         buffer: &'buf mut [u8],
135//!         message_writer: F,
136//!     ) -> MctpPacketResult<&'buf [u8], Self>
137//!     where
138//!         F: for<'a> FnOnce(
139//!             &mut EncodingEncoder<'a, Self::Encoding>,
140//!         ) -> MctpPacketResult<(), Self>,
141//!     {
142//!         // Prepend transport headers as needed, then ask the writer to write MCTP payload
143//!         let written = {
144//!             let mut encoder = EncodingEncoder::<Self::Encoding>::new(buffer);
145//!             message_writer(&mut encoder)?;
146//!             encoder.wire_position()
147//!         };
148//!         Ok(&buffer[..written])
149//!     }
150//! }
151//!
152//! impl MctpMediumFrame<MyMedium> for MyMediumFrame {
153//!     fn packet_size(&self) -> usize {
154//!         self.packet_size
155//!     }
156//!     fn reply_context(&self) -> <MyMedium as MctpMedium>::ReplyContext {
157//!         ()
158//!     }
159//! }
160//! ```
161
162mod buffer_encoding;
163mod deserialize;
164mod endpoint_id;
165pub mod error;
166mod mctp_command_code;
167pub mod mctp_completion_code;
168mod mctp_message_tag;
169mod mctp_packet_context;
170mod mctp_sequence_number;
171mod mctp_transport_header;
172mod medium;
173mod message_type;
174mod serialize;
175#[cfg(test)]
176mod test_util;
177
178pub use buffer_encoding::{
179    BufferEncoding, DecodeError, EncodeError, EncodingDecoder, EncodingEncoder, PassthroughEncoding,
180};
181pub use endpoint_id::EndpointId;
182pub use error::{MctpPacketError, MctpPacketResult};
183pub use mctp_message_tag::MctpMessageTag;
184pub use mctp_packet_context::{MctpPacketContext, MctpReplyContext};
185pub use mctp_sequence_number::MctpSequenceNumber;
186#[cfg(feature = "serial")]
187pub use medium::serial::{
188    CONST_MTU, EC_EID, MctpSerialMedium, MctpSerialMediumFrame, SP_EID, SerialEncoding,
189};
190pub use medium::*;
191pub use message_type::*;
192
193#[derive(Debug, PartialEq, Eq)]
194#[cfg_attr(feature = "defmt", derive(defmt::Format))]
195pub struct MctpMessage<'buffer, M: MctpMedium> {
196    pub reply_context: MctpReplyContext<M>,
197    pub message_buffer: MctpMessageBuffer<'buffer>,
198    pub message_integrity_check: Option<u8>,
199}
200
201#[derive(Debug, PartialEq, Eq)]
202#[cfg_attr(feature = "defmt", derive(defmt::Format))]
203pub struct MctpMessageBuffer<'buffer> {
204    integrity_check: u8,
205    message_type: u8,
206    rest: &'buffer [u8],
207}
208
209impl<'buffer, M: MctpMedium> MctpMessage<'buffer, M> {
210    pub fn can_parse_as<P: MctpMessageTrait<'buffer>>(&self) -> bool {
211        self.message_buffer.message_type == P::MESSAGE_TYPE
212    }
213    pub fn parse_as<P: MctpMessageTrait<'buffer>>(&self) -> MctpPacketResult<(P::Header, P), M> {
214        if !self.can_parse_as::<P>() {
215            return Err(MctpPacketError::HeaderParseError("message type mismatch"));
216        }
217        let (header, rest) = P::Header::deserialize(self.message_buffer.rest)?;
218        let message = P::deserialize(&header, rest)?;
219        Ok((header, message))
220    }
221}
222
223#[cfg(test)]
224mod tests {
225    use pretty_assertions::assert_eq;
226
227    use super::*;
228    use crate::{
229        error::ProtocolError, mctp_command_code::MctpControlCommandCode,
230        mctp_packet_context::MctpPacketContext, test_util::*,
231    };
232
233    struct Packet(&'static [u8]);
234    const GET_ENDPOINT_ID_PACKET_NO_EOM: Packet = Packet(&[
235        // test medium frame (header + trailer): 0 bytes
236        // transport header:
237        0b0000_0001, // mctp reserved, header version
238        0b0000_1001, // destination endpoint id (9)
239        0b0001_0110, // source endpoint id (22)
240        0b1000_0011, // som, eom, seq (0), to, tag (3)
241        // message header:
242        0b0000_0000, // integrity check (off) / message type (MessageType::MctpControl)
243        0b0000_0000, // rq, d, rsvd, instance id
244        0b0000_0010, // command code (2: get endpoint id)
245        0b0000_0000, // completion code
246        // message body:
247        0b0000_1111, // endpoint id (15)
248        0b0000_0001, /* endpoint type (simple = 0b00) / endpoint id type (static eid supported =
249                      * 0b01) */
250        0b1111_0000, // medium specific
251    ]);
252
253    const EMPTY_PACKET_EOM: Packet = Packet(&[
254        // transport header:
255        0b0000_0001, // mctp reserved, header version
256        0b0000_1001, // destination endpoint id (9)
257        0b0001_0110, // source endpoint id (14)
258        0b0101_0011, // som, eom, seq (1), to, tag (3)
259    ]);
260
261    #[test]
262    fn split_over_two_packets() {
263        let mut buffer = [0; 1024];
264        let mut context = MctpPacketContext::<TestMedium>::new(TestMedium::new(), &mut buffer);
265
266        assert_eq!(
267            context
268                .deserialize_packet(GET_ENDPOINT_ID_PACKET_NO_EOM.0)
269                .unwrap(),
270            None
271        );
272
273        let message = context
274            .deserialize_packet(EMPTY_PACKET_EOM.0)
275            .unwrap()
276            .unwrap();
277
278        assert_eq!(message.can_parse_as::<MctpControl>(), true);
279        assert_eq!(message.message_integrity_check, None);
280        assert_eq!(
281            message.reply_context,
282            MctpReplyContext {
283                destination_endpoint_id: EndpointId::Id(9),
284                source_endpoint_id: EndpointId::Id(22),
285                packet_sequence_number: MctpSequenceNumber::new(1),
286                message_tag: MctpMessageTag::try_from(3).unwrap(),
287                medium_context: (),
288            }
289        );
290        assert_eq!(
291            message.parse_as().unwrap(),
292            (
293                MctpControlHeader {
294                    command_code: MctpControlCommandCode::GetEndpointId,
295                    ..Default::default()
296                },
297                MctpControl::GetEndpointIdResponse([
298                    0b0000_1111, // endpoint id (15)
299                    0b0000_0001, /* endpoint type (simple = 0b00) / endpoint id type (static eid
300                                  * supported = 0b01) */
301                    0b1111_0000, // medium specific
302                ]),
303            )
304        );
305    }
306
307    #[test]
308    fn lacking_start_of_message() {
309        let mut buffer = [0; 1024];
310        let mut context = MctpPacketContext::<TestMedium>::new(TestMedium::new(), &mut buffer);
311
312        assert_eq!(
313            context.deserialize_packet(&[
314                // transport header:
315                0b0000_0000, // mctp reserved, header version
316                0b0000_0000, // destination endpoint id
317                0b0000_0000, // source endpoint id
318                0b0000_0000, // som, eom, seq (0), to, tag
319            ]),
320            Err(MctpPacketError::ProtocolError(
321                ProtocolError::ExpectedStartOfMessage,
322            ))
323        );
324    }
325
326    #[test]
327    fn repeated_start_of_message() {
328        let mut buffer = [0; 1024];
329        let mut context = MctpPacketContext::<TestMedium>::new(TestMedium::new(), &mut buffer);
330
331        context
332            .deserialize_packet(GET_ENDPOINT_ID_PACKET_NO_EOM.0)
333            .unwrap();
334
335        assert_eq!(
336            context.deserialize_packet(&[
337                // transport header:
338                0b0000_0000, // mctp reserved, header version
339                0b0000_0000, // destination endpoint id
340                0b0000_0000, // source endpoint id
341                0b1000_0000, // som, eom, seq (0), to, tag
342            ]),
343            Err(MctpPacketError::ProtocolError(
344                ProtocolError::UnexpectedStartOfMessage,
345            ))
346        );
347    }
348
349    #[test]
350    fn message_tag_mismatch() {
351        let mut buffer = [0; 1024];
352        let mut context = MctpPacketContext::<TestMedium>::new(TestMedium::new(), &mut buffer);
353
354        // message tag = 0
355        context
356            .deserialize_packet(GET_ENDPOINT_ID_PACKET_NO_EOM.0)
357            .unwrap();
358
359        // message tag = 1
360        assert_eq!(
361            context.deserialize_packet(&[
362                // transport header:
363                0b0000_0000, // mctp reserved, header version
364                0b0000_0000, // destination endpoint id
365                0b0000_0000, // source endpoint id
366                0b0101_0010, // som, eom, seq (1), to, tag (2)
367            ]),
368            Err(MctpPacketError::ProtocolError(
369                ProtocolError::MessageTagMismatch(
370                    MctpMessageTag::try_from(3).unwrap(),
371                    MctpMessageTag::try_from(2).unwrap(),
372                ),
373            ))
374        );
375    }
376
377    #[test]
378    fn test_send_packet() {
379        let mut buffer = [0; 1024];
380        let mut context = MctpPacketContext::<TestMedium>::new(
381            TestMedium::new().with_headers(&[0xA, 0xB], &[0xC, 0xD]),
382            &mut buffer,
383        );
384
385        let reply_context = MctpReplyContext {
386            destination_endpoint_id: EndpointId::try_from(236).unwrap(),
387            source_endpoint_id: EndpointId::try_from(192).unwrap(),
388            packet_sequence_number: MctpSequenceNumber::new(1),
389            message_tag: MctpMessageTag::try_from(3).unwrap(),
390            medium_context: (),
391        };
392
393        let message = (
394            VendorDefinedPciHeader(0x1234),
395            VendorDefinedPci(&[0xA5, 0xB6]),
396        );
397
398        let mut state = context.serialize_packet(reply_context, message).unwrap();
399
400        let packet = state.next().unwrap().unwrap();
401        assert_eq!(
402            &[
403                // test header - 2 bytes
404                0xA,
405                0xB,
406                // mctp transport header
407                0b0000_0001, // mctp reserved, header version
408                192,         // destination endpoint id
409                236,         // source endpoint id
410                0b1110_0011, // som (1), eom (1), seq (2), tag owner (0), message tag (3)
411                // mctp message header - 3 bytes
412                0x7E, // integrity check (0), message type (vendor defined pci)
413                0x12, // pci vendor id - low byte
414                0x34, // pci vendor id - high byte
415                // mctp message body - 1 byte
416                0xA5,
417                0xB6,
418                // test trailer - 2 bytes
419                0xC,
420                0xD,
421            ],
422            packet
423        );
424    }
425
426    #[test]
427    fn test_send_packet_multi() {
428        const MTU_SIZE: usize = 14;
429        let mut buffer = [0; 1024];
430        let mut context = MctpPacketContext::<TestMedium>::new(
431            TestMedium::new()
432                .with_headers(&[0xA, 0xB], &[0xC, 0xD])
433                // 4 bytes transport header + 4 bytes of data
434                .with_mtu(MTU_SIZE),
435            &mut buffer,
436        );
437
438        let reply_context = MctpReplyContext {
439            destination_endpoint_id: EndpointId::try_from(236).unwrap(),
440            source_endpoint_id: EndpointId::try_from(192).unwrap(),
441            packet_sequence_number: MctpSequenceNumber::new(1),
442            message_tag: MctpMessageTag::try_from(3).unwrap(),
443            medium_context: (),
444        };
445
446        // 10 byte to send over 3 packets
447        let data_to_send = [0xA5, 0xB6, 0xC7, 0xD8, 0xE9, 0xFA, 0x0B, 0x1C, 0x2D, 0x3E];
448        let message = (
449            VendorDefinedPciHeader(0x1234),
450            VendorDefinedPci(&data_to_send),
451        );
452
453        let mut state = context.serialize_packet(reply_context, message).unwrap();
454
455        // First packet
456        let packet1 = state.next().unwrap().unwrap();
457        let expected: [u8; MTU_SIZE] = [
458            // test header - 2 bytes
459            0xA,
460            0xB,
461            // mctp transport header - 4 bytes
462            0b0000_0001, // mctp reserved, header version
463            192,         // destination endpoint id
464            236,         // source endpoint id
465            0b1010_0011, // som (1), eom (0), seq (2), tag owner (0), message tag (3)
466            // mctp message header - 3 bytes
467            0x7E, // integrity check (0), message type (vendor defined pci)
468            0x12, // pci vendor id - low byte
469            0x34, // pci vendor id - high byte
470            // mctp message body data - 1 bytes
471            0xA5,
472            0xB6,
473            0xC7,
474            // test trailer - 2 bytes
475            0xC,
476            0xD,
477        ];
478        assert_eq!(packet1, &expected[..MTU_SIZE]);
479
480        // Second packet (middle packet with 4 bytes of data)
481        let packet2 = state.next().unwrap().unwrap();
482        let expected: [u8; MTU_SIZE] = [
483            // test header - 2 bytes
484            0xA,
485            0xB,
486            // mctp transport header - 4 bytes
487            0b0000_0001, // mctp reserved, header version
488            192,         // destination endpoint id
489            236,         // source endpoint id
490            0b0011_0011, // som (0), eom (0), seq (3), tag owner (0), message tag (3)
491            // mctp body data - 4 bytes
492            0xD8,
493            0xE9,
494            0xFA,
495            0x0B,
496            0x1C,
497            0x2D,
498            // test trailer - 2 bytes
499            0xC,
500            0xD,
501        ];
502        assert_eq!(packet2, &expected[..]);
503
504        // Third packet (final packet with 2 bytes of data)
505        let packet3 = state.next().unwrap().unwrap();
506        let expected: [u8; MTU_SIZE] = [
507            // test header - 2 bytes
508            0xA,
509            0xB,
510            // mctp transport header - 4 bytes
511            0b0000_0001, // mctp reserved, header version
512            192,         // destination endpoint id
513            236,         // source endpoint id
514            0b0100_0011, // som (0), eom (1), seq (0), tag owner (0), message tag (3)
515            // mctp body data - 1 bytes
516            0x3E,
517            // test trailer - 2 bytes
518            0xC,
519            0xD,
520            // remainder is not populated
521            0x00,
522            0x00,
523            0x00,
524            0x00,
525            0x00,
526        ];
527        assert_eq!(packet3, &expected[..9]);
528
529        // Verify no more packets
530        let next = state.next();
531        assert!(next.is_none(), "Expected exactly 3 packets: {next:x?}");
532    }
533
534    #[test]
535    fn test_buffer_overflow_protection() {
536        // Test that buffer overflow is properly prevented
537        let mut small_buffer = [0u8; 16]; // Very small buffer
538        let mut context =
539            MctpPacketContext::<TestMedium>::new(TestMedium::new(), &mut small_buffer);
540
541        // Create a packet that would cause overflow without protection
542        let large_packet = [
543            // transport header:
544            0b0000_0001, // mctp reserved, header version
545            0b0000_1001, // destination endpoint id (9)
546            0b0001_0110, // source endpoint id (22)
547            0b1000_0011, // som, eom, seq (0), to, tag (3)
548            // message header:
549            0b0000_0000, // integrity check (off) / message type (mctp control message)
550            0b0000_0000, // rq, d, rsvd, instance id
551            0b0000_0010, // command code (2: get endpoint id)
552            0b0000_0000, // completion code
553            // Large message body that would overflow small buffer
554            0x01,
555            0x02,
556            0x03,
557            0x04,
558            0x05,
559            0x06,
560            0x07,
561            0x08,
562            0x09,
563            0x0A,
564            0x0B,
565            0x0C,
566            0x0D,
567            0x0E,
568            0x0F,
569            0x10,
570        ];
571
572        // This should return an error instead of panicking
573        let result = context.deserialize_packet(&large_packet);
574        assert!(result.is_err());
575
576        if let Err(MctpPacketError::HeaderParseError(msg)) = result {
577            assert!(msg.contains("buffer overflow"));
578        } else {
579            panic!("Expected HeaderParseError with buffer overflow message");
580        }
581    }
582
583    #[test]
584    fn test_multi_packet_buffer_overflow() {
585        // Test buffer overflow with multiple packets
586        let mut small_buffer = [0u8; 20]; // Small buffer that can fit first packet but not second
587        let mut context =
588            MctpPacketContext::<TestMedium>::new(TestMedium::new(), &mut small_buffer);
589
590        // First packet - fits in buffer
591        let first_packet = [
592            // transport header:
593            0b0000_0001, // mctp reserved, header version
594            0b0000_1001, // destination endpoint id (9)
595            0b0001_0110, // source endpoint id (22)
596            0b1000_0011, // som (1), eom (0), seq (0), to, tag (3)
597            // message header:
598            0b0000_0000, // integrity check (off) / message type (mctp control message)
599            0b0000_0000, // rq, d, rsvd, instance id
600            0b0000_0010, // command code (2: get endpoint id)
601            0b0000_0000, // completion code
602            // Small message body
603            0x01,
604            0x02,
605            0x03,
606            0x04,
607            0x05,
608            0x06,
609            0x07,
610            0x08,
611        ];
612
613        // First packet should succeed
614        let result1 = context.deserialize_packet(&first_packet);
615        assert!(result1.is_ok());
616        assert!(result1.unwrap().is_none()); // No complete message yet
617
618        // Second packet - would cause overflow
619        let second_packet = [
620            // transport header:
621            0b0000_0001, // mctp reserved, header version
622            0b0000_1001, // destination endpoint id (9)
623            0b0001_0110, // source endpoint id (22)
624            0b0101_0011, // som (0), eom (1), seq (1), to, tag (3) - correct sequence number
625            // Large continuation that would overflow
626            0x09,
627            0x0A,
628            0x0B,
629            0x0C,
630            0x0D,
631            0x0E,
632            0x0F,
633            0x10,
634            0x11,
635            0x12,
636            0x13,
637            0x14,
638            0x15,
639            0x16,
640            0x17,
641            0x18,
642        ];
643
644        // Second packet should fail with buffer overflow
645        let result2 = context.deserialize_packet(&second_packet);
646        assert!(result2.is_err());
647
648        if let Err(MctpPacketError::HeaderParseError(msg)) = result2 {
649            assert!(msg.contains("buffer overflow"));
650        } else {
651            panic!("Expected HeaderParseError with buffer overflow message");
652        }
653    }
654
655    #[test]
656    fn test_transport_header_underflow() {
657        // Test transport header parsing with insufficient bytes
658        let mut buffer = [0u8; 1024];
659        let mut context = MctpPacketContext::<TestMedium>::new(TestMedium::new(), &mut buffer);
660
661        // Packet too short for transport header (only 3 bytes)
662        let short_packet = [0x01, 0x02, 0x03];
663
664        let result = context.deserialize_packet(&short_packet);
665        assert!(result.is_err());
666
667        if let Err(MctpPacketError::HeaderParseError(msg)) = result {
668            assert!(msg.contains("cannot parse transport header"));
669        } else {
670            panic!("Expected HeaderParseError for short transport header");
671        }
672    }
673
674    #[test]
675    fn test_message_header_underflow() {
676        // Test message body parsing with insufficient bytes for message header
677        let mut buffer = [0u8; 1024];
678        let mut context = MctpPacketContext::<TestMedium>::new(TestMedium::new(), &mut buffer);
679
680        // Packet with transport header but no message header
681        let incomplete_packet = [
682            // transport header only (4 bytes)
683            0b0000_0001, // mctp reserved, header version
684            0b0000_1001, // destination endpoint id (9)
685            0b0001_0110, // source endpoint id (22)
686            0b1110_0011, /* som (1), eom (1), seq (0), to, tag (3)
687                          * No message header (need 4 more bytes) */
688        ];
689
690        let result = context.deserialize_packet(&incomplete_packet);
691        assert!(result.is_err());
692
693        if let Err(MctpPacketError::HeaderParseError(msg)) = result {
694            assert!(msg.contains("packet too small"), "msg: {msg}");
695        } else {
696            panic!("Expected HeaderParseError for short message header");
697        }
698    }
699
700    #[test]
701    fn test_serialize_buffer_underflow() {
702        // Test serialization with buffer too small for serializing the packet and having enough
703        // buffer for assembling packets
704        let mut tiny_buffer = [0u8; 4]; // Too small for 4-byte transport header
705        let mut context = MctpPacketContext::<TestMedium>::new(TestMedium::new(), &mut tiny_buffer);
706
707        let reply_context = MctpReplyContext {
708            destination_endpoint_id: EndpointId::try_from(236).unwrap(),
709            source_endpoint_id: EndpointId::try_from(192).unwrap(),
710            packet_sequence_number: MctpSequenceNumber::new(1),
711            message_tag: MctpMessageTag::try_from(3).unwrap(),
712            medium_context: (),
713        };
714
715        let message = (VendorDefinedPciHeader(0x1234), VendorDefinedPci(&[0xA5]));
716        let state_result = context.serialize_packet(reply_context, message);
717        assert!(state_result.is_ok(), "{state_result:?}");
718
719        let mut state = state_result.unwrap();
720        let packet_result = state.next().unwrap();
721
722        // Should fail because buffer is too small for transport header
723        assert!(packet_result.is_err());
724        if let Err(MctpPacketError::SerializeError(msg)) = packet_result {
725            assert!(msg.contains("assembly buffer too small"));
726        } else {
727            panic!("Expected SerializeError for small buffer");
728        }
729    }
730
731    #[test]
732    fn test_zero_size_assembly_buffer() {
733        // Test with zero-size assembly buffer
734        let mut empty_buffer = [0u8; 0];
735        let mut context =
736            MctpPacketContext::<TestMedium>::new(TestMedium::new(), &mut empty_buffer);
737
738        let packet = [
739            0b0000_0001, // mctp reserved, header version
740            0b0000_1001, // destination endpoint id (9)
741            0b0001_0110, // source endpoint id (22)
742            0b1110_0011, // som (1), eom (1), seq (0), to, tag (3)
743            0x7F,        // message header - 3 bytes (vendor defined pci)
744            0x12,        // pci vendor id - low byte
745            0x34,        // pci vendor id - high byte
746            0b0000_0010,
747            0b0000_0000,
748        ];
749
750        let result = context.deserialize_packet(&packet);
751        assert!(result.is_err());
752
753        if let Err(MctpPacketError::HeaderParseError(msg)) = result {
754            assert!(msg.contains("buffer overflow"));
755        } else {
756            panic!("Expected buffer overflow error for zero-size buffer");
757        }
758    }
759}