1#[allow(unused)]
9use crate::fmt::{debug, error, info, trace, warn};
10
11use mctp::{Eid, Error, MsgIC, MsgType, Result, Tag, MCTP_HEADER_VERSION_1};
12
13use crate::{AppCookie, Header, HEADER_LEN, MAX_MTU};
14
15#[derive(Debug)]
19pub struct Fragmenter {
20 src: Eid,
21 dest: Eid,
22 typ: MsgType,
23 tag: Tag,
24 ic: MsgIC,
25 seq: u8,
26 mtu: usize,
27
28 first: bool,
29 done: bool,
30 cookie: Option<AppCookie>,
31
32 payload_used: usize,
34}
35
36impl Fragmenter {
37 pub(crate) fn new(
38 typ: MsgType,
39 src: Eid,
40 dest: Eid,
41 tag: Tag,
42 mtu: usize,
43 cookie: Option<AppCookie>,
44 ic: MsgIC,
45 initial_seq: u8,
46 ) -> Result<Self> {
47 if tag.tag().0 > mctp::MCTP_TAG_MAX {
48 return Err(Error::InvalidInput);
49 }
50 debug_assert!(typ.0 & 0x80 == 0, "IC bit's set in typ");
51 debug_assert!(initial_seq & !mctp::MCTP_SEQ_MASK == 0);
52 if mtu < HEADER_LEN + 1 {
53 debug!("mtu too small");
54 return Err(Error::BadArgument);
55 }
56 if mtu > MAX_MTU {
57 debug!("mtu too large");
58 return Err(Error::BadArgument);
59 }
60 Ok(Self {
63 payload_used: 0,
64 src,
65 dest,
66 typ,
67 mtu,
68 first: true,
69 done: false,
70 seq: initial_seq,
71 tag,
72 cookie,
73 ic,
74 })
75 }
76
77 pub fn tag(&self) -> Tag {
78 self.tag
79 }
80
81 pub fn dest(&self) -> Eid {
82 self.dest
83 }
84
85 pub fn cookie(&self) -> Option<AppCookie> {
86 self.cookie
87 }
88
89 fn header(&self) -> Header {
90 let mut header = Header::new(MCTP_HEADER_VERSION_1);
91 header.set_dest_endpoint_id(self.dest.0);
92 header.set_source_endpoint_id(self.src.0);
93 header.set_pkt_seq(self.seq);
94 if self.first {
95 header.set_som(self.first as u8);
96 }
97 header.set_msg_tag(self.tag.tag().0);
98 header.set_to(self.tag.is_owner() as u8);
99 header
100 }
101
102 pub fn fragment<'f>(
107 &mut self,
108 payload: &[u8],
109 out: &'f mut [u8],
110 ) -> SendOutput<'f> {
111 if self.done {
112 return SendOutput::success(self);
113 }
114
115 let min = HEADER_LEN + self.first as usize;
117
118 if out.len() < min {
119 return SendOutput::failure(Error::NoSpace, self);
120 }
121
122 let max_total = out.len().min(self.mtu);
125 let (h, mut rest) = out[..max_total].split_at_mut(HEADER_LEN);
127
128 if self.first {
130 rest[0] = mctp::encode_type_ic(self.typ, self.ic);
131 rest = &mut rest[1..];
132 }
133
134 if payload.len() < self.payload_used {
135 return SendOutput::failure(Error::InvalidInput, self);
137 }
138
139 let p = &payload[self.payload_used..];
141 let l = p.len().min(rest.len());
142 let (d, rest) = rest.split_at_mut(l);
143 self.payload_used += l;
144 d.copy_from_slice(&p[..l]);
145
146 let mut header = self.header();
148 if self.payload_used == payload.len() {
149 header.set_eom(1);
150 self.done = true;
151 }
152 h.copy_from_slice(&header.0);
153
154 self.first = false;
155 self.seq = (self.seq + 1) & mctp::MCTP_SEQ_MASK;
156
157 let used = max_total - rest.len();
158 SendOutput::Packet(&mut out[..used])
159 }
160
161 pub fn is_done(&self) -> bool {
162 self.done
163 }
164}
165
166pub enum SendOutput<'p> {
167 Packet(&'p mut [u8]),
168 Complete {
169 tag: Tag,
170 cookie: Option<AppCookie>,
171 },
172 Error {
173 err: Error,
174 cookie: Option<AppCookie>,
175 },
176}
177
178impl SendOutput<'_> {
179 pub(crate) fn unborrowed<'x>(self) -> Option<SendOutput<'x>> {
184 match self {
185 Self::Packet(_) => unreachable!(),
186 Self::Complete { tag, cookie } => {
187 Some(SendOutput::Complete { tag, cookie })
188 }
189 Self::Error { err, cookie } => {
190 Some(SendOutput::Error { err, cookie })
191 }
192 }
193 }
194
195 pub(crate) fn success(f: &Fragmenter) -> Self {
196 Self::Complete {
197 tag: f.tag,
198 cookie: f.cookie,
199 }
200 }
201
202 pub(crate) fn failure(err: Error, f: &Fragmenter) -> Self {
203 Self::Error {
204 err,
205 cookie: f.cookie,
206 }
207 }
208
209 pub(crate) fn bare_failure(err: Error) -> Self {
211 Self::Error { err, cookie: None }
212 }
213}