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}