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