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