1use crate::SOM;
14use crate::error::Error;
15use crate::packet::checksum::checksum8;
16use crate::packet::crc::crc16;
17use crate::packet::header::{Address, ControlByte};
18use crate::packet::scb::ScbView;
19use crate::packet::trailer::Trailer;
20
21pub const HEADER_LEN: usize = 5;
23
24pub const MAC_LEN: usize = 4;
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub struct ParsedPacket<'a> {
33 pub addr: Address,
35 pub ctrl: ControlByte,
37 pub scb: Option<ScbView<'a>>,
39 pub code: u8,
41 pub data: &'a [u8],
44 pub mac: Option<[u8; MAC_LEN]>,
46 pub trailer: Trailer,
48}
49
50impl<'a> ParsedPacket<'a> {
51 pub fn parse(buf: &'a [u8]) -> Result<(Self, usize), Error> {
72 if buf.len() < HEADER_LEN {
73 return Err(Error::Truncated {
74 have: buf.len(),
75 need: HEADER_LEN,
76 });
77 }
78 if buf[0] != SOM {
79 return Err(Error::BadSom(buf[0]));
80 }
81
82 let addr = Address::from_raw(buf[1]);
83 let len = u16::from_le_bytes([buf[2], buf[3]]) as usize;
84 let ctrl = ControlByte::decode(buf[4])?;
85
86 if buf.len() < len {
87 return Err(Error::Truncated {
88 have: buf.len(),
89 need: len,
90 });
91 }
92 let frame = &buf[..len];
93
94 let trailer_len = if ctrl.use_crc() { 2 } else { 1 };
95 if frame.len() < HEADER_LEN + 1 + trailer_len {
96 return Err(Error::BadLength {
97 declared: len,
98 actual: frame.len(),
99 });
100 }
101
102 let mut cursor = HEADER_LEN;
103
104 let scb = if ctrl.has_scb() {
105 let view = ScbView::parse(&frame[cursor..])?;
106 cursor += view.wire_len();
107 Some(view)
108 } else {
109 None
110 };
111
112 if cursor + 1 + trailer_len > frame.len() {
113 return Err(Error::BadLength {
114 declared: len,
115 actual: frame.len(),
116 });
117 }
118 let code = frame[cursor];
119 cursor += 1;
120
121 let mac_present = scb.map(|s| s.ty.has_mac()).unwrap_or(false);
122 let mac_room = if mac_present { MAC_LEN } else { 0 };
123
124 let payload_end =
125 frame
126 .len()
127 .checked_sub(trailer_len + mac_room)
128 .ok_or(Error::BadLength {
129 declared: len,
130 actual: frame.len(),
131 })?;
132 if payload_end < cursor {
133 return Err(Error::BadLength {
134 declared: len,
135 actual: frame.len(),
136 });
137 }
138 let data = &frame[cursor..payload_end];
139
140 let mac = if mac_present {
141 let m = &frame[payload_end..payload_end + MAC_LEN];
142 let mut arr = [0u8; MAC_LEN];
143 arr.copy_from_slice(m);
144 Some(arr)
145 } else {
146 None
147 };
148
149 let trailer = if ctrl.use_crc() {
150 let got = u16::from_le_bytes([frame[frame.len() - 2], frame[frame.len() - 1]]);
151 let want = crc16(&frame[..frame.len() - 2]);
152 if got != want {
153 return Err(Error::BadCrc { got, want });
154 }
155 Trailer::Crc(got)
156 } else {
157 let got = frame[frame.len() - 1];
158 let want = checksum8(&frame[..frame.len() - 1]);
159 if got != want {
160 return Err(Error::BadChecksum { got, want });
161 }
162 Trailer::Checksum(got)
163 };
164
165 Ok((
166 Self {
167 addr,
168 ctrl,
169 scb,
170 code,
171 data,
172 mac,
173 trailer,
174 },
175 len,
176 ))
177 }
178}
179
180#[cfg(feature = "alloc")]
181mod alloc_impls {
182 use super::*;
183 use crate::packet::scb::Scb;
184 use alloc::vec::Vec;
185
186 #[derive(Debug, Clone)]
193 pub struct PacketBuilder {
194 pub addr: Address,
196 pub ctrl: ControlByte,
198 pub scb: Option<Scb>,
200 pub code: u8,
202 pub data: Vec<u8>,
204 }
205
206 impl PacketBuilder {
207 pub fn plain(addr: Address, ctrl: ControlByte, code: u8, data: Vec<u8>) -> Self {
209 Self {
210 addr,
211 ctrl,
212 scb: None,
213 code,
214 data,
215 }
216 }
217
218 pub fn encode(&self) -> Result<Vec<u8>, Error> {
224 self.encode_inner(None::<fn(&[u8]) -> [u8; super::MAC_LEN]>)
225 }
226
227 pub fn encode_with_mac<F>(&self, mac_fn: F) -> Result<Vec<u8>, Error>
233 where
234 F: FnOnce(&[u8]) -> [u8; super::MAC_LEN],
235 {
236 self.encode_inner(Some(mac_fn))
237 }
238
239 fn encode_inner<F>(&self, mac_fn: Option<F>) -> Result<Vec<u8>, Error>
240 where
241 F: FnOnce(&[u8]) -> [u8; super::MAC_LEN],
242 {
243 let scb_present = self.ctrl.has_scb();
245 if scb_present != self.scb.is_some() {
246 return Err(Error::BadControlByte(self.ctrl.encode()));
247 }
248 let mac_required = self.scb.as_ref().map(|s| s.ty.has_mac()).unwrap_or(false);
249 if mac_required && mac_fn.is_none() {
250 return Err(Error::BadMac);
251 }
252
253 let trailer_len = if self.ctrl.use_crc() { 2 } else { 1 };
254 let mac_len = if mac_required { super::MAC_LEN } else { 0 };
255 let scb_len = self.scb.as_ref().map(|s| s.data.len() + 2).unwrap_or(0);
256 let total = HEADER_LEN + scb_len + 1 + self.data.len() + mac_len + trailer_len;
257
258 if total > u16::MAX as usize {
259 return Err(Error::BufferOverflow {
260 need: total,
261 have: u16::MAX as usize,
262 });
263 }
264
265 let mut out = Vec::with_capacity(total);
266 out.push(SOM);
267 out.push(self.addr.as_byte());
268 let len_bytes = (total as u16).to_le_bytes();
269 out.push(len_bytes[0]);
270 out.push(len_bytes[1]);
271 out.push(self.ctrl.encode());
272
273 if let Some(scb) = &self.scb {
274 scb.encode(&mut out);
275 }
276
277 out.push(self.code);
278 out.extend_from_slice(&self.data);
279
280 if let Some(f) = mac_fn {
281 let mac = f(&out);
282 out.extend_from_slice(&mac);
283 }
284
285 if self.ctrl.use_crc() {
286 let crc = crc16(&out);
287 out.extend_from_slice(&crc.to_le_bytes());
288 } else {
289 out.push(checksum8(&out));
290 }
291
292 debug_assert_eq!(out.len(), total);
293 Ok(out)
294 }
295 }
296}
297
298#[cfg(feature = "alloc")]
299pub use alloc_impls::PacketBuilder;
300
301#[cfg(test)]
302mod tests {
303 use super::*;
304 use crate::packet::header::{CtrlFlags, Sqn};
305 use crate::packet::scb::{Scb, ScsType};
306 use alloc::vec::Vec;
307
308 fn make_poll(addr: u8, sqn: u8) -> Vec<u8> {
309 PacketBuilder::plain(
310 Address::pd(addr).unwrap(),
311 ControlByte::new(Sqn::new(sqn).unwrap(), CtrlFlags::USE_CRC),
312 0x60, Vec::new(),
314 )
315 .encode()
316 .unwrap()
317 }
318
319 #[test]
320 fn roundtrip_poll() {
321 let bytes = make_poll(0x05, 1);
322 let (parsed, used) = ParsedPacket::parse(&bytes).unwrap();
323 assert_eq!(used, bytes.len());
324 assert_eq!(parsed.addr.pd_addr(), 0x05);
325 assert_eq!(parsed.ctrl.sqn.value(), 1);
326 assert!(parsed.ctrl.use_crc());
327 assert_eq!(parsed.code, 0x60);
328 assert!(parsed.data.is_empty());
329 assert!(parsed.scb.is_none());
330 assert!(parsed.mac.is_none());
331 }
332
333 #[test]
334 fn roundtrip_with_data_checksum() {
335 let bytes = PacketBuilder::plain(
336 Address::pd(0x01).unwrap(),
337 ControlByte::new(Sqn::new(2).unwrap(), CtrlFlags::empty()),
338 0x6E, alloc::vec![0x00, 0x80, 0x25, 0x00, 0x00],
340 )
341 .encode()
342 .unwrap();
343
344 let (parsed, used) = ParsedPacket::parse(&bytes).unwrap();
345 assert_eq!(used, bytes.len());
346 assert_eq!(parsed.code, 0x6E);
347 assert_eq!(parsed.data, &[0x00, 0x80, 0x25, 0x00, 0x00]);
348 assert!(matches!(parsed.trailer, Trailer::Checksum(_)));
349 }
350
351 #[test]
352 fn roundtrip_with_scb_no_mac() {
353 let scb = Scb::new(ScsType::Scs11, [0x00, 1, 2, 3, 4, 5, 6, 7, 8]);
354 let bytes = PacketBuilder {
355 addr: Address::pd(0x01).unwrap(),
356 ctrl: ControlByte::new(
357 Sqn::new(0).unwrap(),
358 CtrlFlags::USE_CRC | CtrlFlags::HAS_SCB,
359 ),
360 scb: Some(scb.clone()),
361 code: 0x76,
362 data: Vec::new(),
363 }
364 .encode()
365 .unwrap();
366
367 let (parsed, _) = ParsedPacket::parse(&bytes).unwrap();
368 let view = parsed.scb.unwrap();
369 assert_eq!(view.ty, ScsType::Scs11);
370 assert_eq!(view.data, scb.data.as_slice());
371 assert!(parsed.mac.is_none());
372 }
373
374 #[test]
375 fn roundtrip_with_scb_and_mac() {
376 let mac_value = [0xDE, 0xAD, 0xBE, 0xEF];
377 let scb = Scb::new(ScsType::Scs15, []);
378 let bytes = PacketBuilder {
379 addr: Address::pd(0x02).unwrap(),
380 ctrl: ControlByte::new(
381 Sqn::new(2).unwrap(),
382 CtrlFlags::USE_CRC | CtrlFlags::HAS_SCB,
383 ),
384 scb: Some(scb),
385 code: 0x60,
386 data: alloc::vec![0xAA, 0xBB],
387 }
388 .encode_with_mac(|_| mac_value)
389 .unwrap();
390
391 let (parsed, _) = ParsedPacket::parse(&bytes).unwrap();
392 assert_eq!(parsed.mac.unwrap(), mac_value);
393 assert_eq!(parsed.data, &[0xAA, 0xBB]);
394 }
395
396 #[test]
397 fn rejects_bad_som() {
398 let mut bytes = make_poll(1, 1);
399 bytes[0] = 0x52;
400 assert!(matches!(
401 ParsedPacket::parse(&bytes),
402 Err(Error::BadSom(0x52))
403 ));
404 }
405
406 #[test]
407 fn rejects_truncated() {
408 let bytes = [0x53u8, 0x01];
409 assert!(matches!(
410 ParsedPacket::parse(&bytes),
411 Err(Error::Truncated { .. })
412 ));
413 }
414
415 #[test]
416 fn rejects_bad_crc() {
417 let mut bytes = make_poll(1, 1);
418 let n = bytes.len();
419 bytes[n - 1] ^= 0xFF;
420 assert!(matches!(
421 ParsedPacket::parse(&bytes),
422 Err(Error::BadCrc { .. })
423 ));
424 }
425
426 #[test]
427 fn rejects_bad_checksum() {
428 let mut bytes = PacketBuilder::plain(
429 Address::pd(0x01).unwrap(),
430 ControlByte::new(Sqn::new(1).unwrap(), CtrlFlags::empty()),
431 0x60,
432 Vec::new(),
433 )
434 .encode()
435 .unwrap();
436 let n = bytes.len();
437 bytes[n - 1] ^= 0xFF;
438 assert!(matches!(
439 ParsedPacket::parse(&bytes),
440 Err(Error::BadChecksum { .. })
441 ));
442 }
443
444 #[test]
445 fn parser_total_on_random_garbage() {
446 for seed in 0u64..256 {
448 let mut x = seed.wrapping_mul(0x9E37_79B9_7F4A_7C15);
449 let mut buf = [0u8; 64];
450 for b in buf.iter_mut() {
451 x = x
452 .wrapping_mul(6364136223846793005)
453 .wrapping_add(1442695040888963407);
454 *b = (x >> 33) as u8;
455 }
456 let _ = ParsedPacket::parse(&buf);
457 }
458 }
459}