Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 37 additions & 7 deletions mctp-estack/src/fragment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ impl Fragmenter {
/// (If you do, the vector has to hold exactly one buffer that is
/// equal to the one passed to `fragment()`.)
///
/// `out` must be at least as large as the specified `mtu`.
/// `out` must be at least as large as the specified `mtu` plus the MCTP transport header (four bytes).
pub fn fragment<'f>(
&mut self,
payload: &[u8],
Expand All @@ -113,7 +113,7 @@ impl Fragmenter {
/// (If you do, the vector has to hold exactly one buffer that is
/// equal to the one passed to `fragment()`.)
///
/// `out` must be at least as large as the specified `mtu`.
/// `out` must be at least as large as the specified `mtu` plus the MCTP transport header (four bytes).
pub fn fragment_vectored<'f>(
&mut self,
payload: &[&[u8]],
Expand All @@ -129,17 +129,19 @@ impl Fragmenter {
return SendOutput::failure(Error::BadArgument, self);
}

// Require at least MTU buffer size, to ensure that all non-end
let fragment_length = self.mtu + MctpHeader::LEN;

// Require at least fragment_length buffer size, to ensure that all non-end
// fragments are the same size per the spec.
if out.len() < self.mtu {
if out.len() < fragment_length {
debug!("small out buffer");
return SendOutput::failure(Error::BadArgument, self);
}

// Reserve header space, the remaining buffer keeps being
// updated in `rest`
let max_total = out.len().min(self.mtu);
let (h, mut rest) = out[..max_total].split_at_mut(MctpHeader::LEN);
let (h, mut rest) =
out[..fragment_length].split_at_mut(MctpHeader::LEN);

// Append type byte
if self.header.som {
Expand All @@ -162,7 +164,7 @@ impl Fragmenter {
self.header.som = false;
self.header.seq = (self.header.seq + 1) & mctp::MCTP_SEQ_MASK;

let used = max_total - rest.len();
let used = fragment_length - rest.len();
SendOutput::Packet(&mut out[..used])
}
}
Expand Down Expand Up @@ -215,3 +217,31 @@ impl SendOutput<'_> {
Self::Error { err, cookie: None }
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_minimum_mtu() {
let mut fragmenter = Fragmenter::new(
mctp::MCTP_TYPE_CONTROL,
Eid(8),
Eid(9),
Tag::Owned(mctp::TagValue(0)),
mctp::MCTP_MIN_MTU,
None,
MsgIC(false),
0,
)
.unwrap();

let dummy_in = vec![1u8; mctp::MCTP_MIN_MTU * 2];
let mut dummy_out = vec![0u8; mctp::MCTP_MIN_MTU * 2];
let fragment = fragmenter.fragment(&dummy_in, &mut dummy_out);
let expected_length = mctp::MCTP_MIN_MTU + crate::MctpHeader::LEN;
assert!(
matches!(fragment, SendOutput::Packet(packet) if packet.len() == expected_length)
);
}
}
3 changes: 2 additions & 1 deletion standalone/src/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ impl<S: Read + Write> Inner<S> {
}

loop {
let mut tx_pkt = [0u8; mctp_estack::serial::MTU_MAX];
// Add for the four byte transport header
let mut tx_pkt = [0u8; mctp_estack::serial::MTU_MAX + 4];
let r = fragmenter.fragment(&tx_msg, &mut tx_pkt);
match r {
SendOutput::Packet(p) => {
Expand Down
Loading