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}