1use core::ops::Range;
2
3use crate::{EncodeError, ParseError, options::OptionDecoder};
4
5pub const UMSH_VERSION: u8 = 0b11;
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq)]
10#[repr(u8)]
11pub enum PacketType {
12 Broadcast = 0,
13 MacAck = 1,
14 Unicast = 2,
15 UnicastAckReq = 3,
16 Multicast = 4,
17 Reserved5 = 5,
18 BlindUnicast = 6,
19 BlindUnicastAckReq = 7,
20}
21
22impl PacketType {
23 pub const fn from_bits(value: u8) -> Self {
25 match value & 0x07 {
26 0 => Self::Broadcast,
27 1 => Self::MacAck,
28 2 => Self::Unicast,
29 3 => Self::UnicastAckReq,
30 4 => Self::Multicast,
31 5 => Self::Reserved5,
32 6 => Self::BlindUnicast,
33 _ => Self::BlindUnicastAckReq,
34 }
35 }
36
37 pub fn is_secure(self) -> bool {
39 matches!(
40 self,
41 Self::Unicast
42 | Self::UnicastAckReq
43 | Self::Multicast
44 | Self::BlindUnicast
45 | Self::BlindUnicastAckReq
46 )
47 }
48
49 pub fn ack_requested(self) -> bool {
51 matches!(self, Self::UnicastAckReq | Self::BlindUnicastAckReq)
52 }
53
54 pub fn is_routable(self) -> bool {
56 !matches!(self, Self::Reserved5)
57 }
58}
59
60#[derive(Clone, Copy, Debug, PartialEq, Eq)]
66#[repr(u8)]
67pub enum PayloadType {
68 Empty = 0xFF,
70 Unspecified = 0,
72 NodeIdentity = 1,
74 MacCommand = 2,
76 TextMessage = 3,
78 ChatRoomMessage = 5,
80 CoapOverUmsh = 7,
82 NodeManagement = 8,
84}
85
86impl PayloadType {
87 pub fn from_byte(byte: u8) -> Option<Self> {
89 match byte {
90 0 => Some(Self::Unspecified),
91 1 => Some(Self::NodeIdentity),
92 2 => Some(Self::MacCommand),
93 3 => Some(Self::TextMessage),
94 5 => Some(Self::ChatRoomMessage),
95 7 => Some(Self::CoapOverUmsh),
96 8 => Some(Self::NodeManagement),
97 _ => None,
98 }
99 }
100
101 pub fn allowed_for(self, packet_type: PacketType) -> bool {
103 match self {
104 Self::Empty | Self::Unspecified | Self::NodeIdentity => {
105 !matches!(packet_type, PacketType::MacAck)
106 }
107 Self::MacCommand => matches!(
108 packet_type,
109 PacketType::Unicast
110 | PacketType::UnicastAckReq
111 | PacketType::BlindUnicast
112 | PacketType::BlindUnicastAckReq
113 | PacketType::Multicast
114 ),
115 Self::TextMessage | Self::CoapOverUmsh | Self::NodeManagement => matches!(
116 packet_type,
117 PacketType::Unicast
118 | PacketType::UnicastAckReq
119 | PacketType::BlindUnicast
120 | PacketType::BlindUnicastAckReq
121 | PacketType::Multicast
122 ),
123 Self::ChatRoomMessage => matches!(
124 packet_type,
125 PacketType::Unicast
126 | PacketType::UnicastAckReq
127 | PacketType::BlindUnicast
128 | PacketType::BlindUnicastAckReq
129 ),
130 }
131 }
132}
133
134#[derive(Clone, Copy, Debug, PartialEq, Eq)]
136pub struct Fcf(pub u8);
137
138impl Fcf {
139 pub const fn new(
141 packet_type: PacketType,
142 full_source: bool,
143 options_present: bool,
144 flood_hops_present: bool,
145 ) -> Self {
146 Self(
147 (UMSH_VERSION << 6)
148 | ((packet_type as u8) << 3)
149 | ((full_source as u8) << 2)
150 | ((options_present as u8) << 1)
151 | flood_hops_present as u8,
152 )
153 }
154
155 pub const fn version(self) -> u8 {
157 self.0 >> 6
158 }
159
160 pub const fn packet_type(self) -> PacketType {
162 PacketType::from_bits((self.0 >> 3) & 0x07)
163 }
164
165 pub const fn full_source(self) -> bool {
167 self.0 & 0x04 != 0
168 }
169
170 pub const fn options_present(self) -> bool {
172 self.0 & 0x02 != 0
173 }
174
175 pub const fn flood_hops_present(self) -> bool {
177 self.0 & 0x01 != 0
178 }
179}
180
181#[derive(Clone, Copy, Debug, PartialEq, Eq)]
183pub struct Scf(pub u8);
184
185impl Scf {
186 pub const fn new(encrypted: bool, mic_size: MicSize, salt_present: bool) -> Self {
188 Self(((encrypted as u8) << 7) | ((mic_size as u8) << 5) | ((salt_present as u8) << 4))
189 }
190
191 pub const fn encrypted(self) -> bool {
193 self.0 & 0x80 != 0
194 }
195
196 pub fn mic_size(self) -> Result<MicSize, ParseError> {
198 MicSize::from_bits((self.0 >> 5) & 0x03)
199 }
200
201 pub const fn salt_present(self) -> bool {
203 self.0 & 0x10 != 0
204 }
205
206 pub const fn reserved_valid(self) -> bool {
208 self.0 & 0x0F == 0
209 }
210}
211
212#[derive(Clone, Copy, Debug, PartialEq, Eq)]
214pub enum MicSize {
215 Mic4 = 0,
216 Mic8 = 1,
217 Mic12 = 2,
218 Mic16 = 3,
219}
220
221impl MicSize {
222 pub const fn byte_len(self) -> usize {
224 match self {
225 Self::Mic4 => 4,
226 Self::Mic8 => 8,
227 Self::Mic12 => 12,
228 Self::Mic16 => 16,
229 }
230 }
231
232 pub fn from_bits(value: u8) -> Result<Self, ParseError> {
234 match value {
235 0 => Ok(Self::Mic4),
236 1 => Ok(Self::Mic8),
237 2 => Ok(Self::Mic12),
238 3 => Ok(Self::Mic16),
239 other => Err(ParseError::InvalidMicSize(other)),
240 }
241 }
242}
243
244#[derive(Clone, Copy, Debug, PartialEq, Eq)]
246pub struct FloodHops(pub u8);
247
248impl FloodHops {
249 pub fn new(remaining: u8, accumulated: u8) -> Option<Self> {
251 if remaining <= 0x0F && accumulated <= 0x0F {
252 Some(Self((remaining << 4) | accumulated))
253 } else {
254 None
255 }
256 }
257
258 pub const fn remaining(self) -> u8 {
260 self.0 >> 4
261 }
262
263 pub const fn accumulated(self) -> u8 {
265 self.0 & 0x0F
266 }
267
268 pub fn decremented(self) -> Self {
270 let remaining = self.remaining();
271 if remaining == 0 {
272 self
273 } else {
274 Self::new(remaining - 1, self.accumulated().saturating_add(1)).unwrap_or(self)
275 }
276 }
277}
278
279#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
281pub struct NodeHint(pub [u8; 3]);
282
283impl NodeHint {
284 pub fn from_public_key(key: &PublicKey) -> Self {
286 Self([key.0[0], key.0[1], key.0[2]])
287 }
288}
289
290#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
292pub struct RouterHint(pub [u8; 2]);
293
294impl RouterHint {
295 pub fn from_public_key(key: &PublicKey) -> Self {
297 Self([key.0[0], key.0[1]])
298 }
299}
300
301#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
303pub struct ChannelId(pub [u8; 2]);
304
305#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
307pub struct PublicKey(pub [u8; 32]);
308
309impl PublicKey {
310 pub fn hint(&self) -> NodeHint {
312 NodeHint::from_public_key(self)
313 }
314
315 pub fn router_hint(&self) -> RouterHint {
317 RouterHint::from_public_key(self)
318 }
319}
320
321#[derive(Clone, Copy, zeroize::Zeroize)]
323pub struct ChannelKey(pub [u8; 32]);
324
325impl PartialEq for ChannelKey {
326 fn eq(&self, other: &Self) -> bool {
327 self.0 == other.0
328 }
329}
330
331impl Eq for ChannelKey {}
332
333impl core::fmt::Debug for ChannelKey {
334 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
335 f.write_str("ChannelKey([redacted])")
336 }
337}
338
339#[derive(Clone, Copy, Debug, PartialEq, Eq)]
341pub enum SourceAddr<'a> {
342 Hint(NodeHint),
343 Full(&'a PublicKey),
344}
345
346impl SourceAddr<'_> {
347 pub fn hint(&self) -> NodeHint {
349 match self {
350 Self::Hint(hint) => *hint,
351 Self::Full(key) => key.hint(),
352 }
353 }
354}
355
356#[derive(Clone, Copy, Debug, PartialEq, Eq)]
358pub struct SecInfo {
359 pub scf: Scf,
360 pub frame_counter: u32,
361 pub salt: Option<u16>,
362}
363
364impl SecInfo {
365 pub fn wire_len(&self) -> usize {
367 if self.salt.is_some() { 7 } else { 5 }
368 }
369
370 pub fn encode(&self, buf: &mut [u8]) -> Result<usize, EncodeError> {
372 let needed = self.wire_len();
373 if buf.len() < needed {
374 return Err(EncodeError::BufferTooSmall);
375 }
376 buf[0] = self.scf.0;
377 buf[1..5].copy_from_slice(&self.frame_counter.to_be_bytes());
378 if let Some(salt) = self.salt {
379 buf[5..7].copy_from_slice(&salt.to_be_bytes());
380 }
381 Ok(needed)
382 }
383
384 pub fn decode(buf: &[u8]) -> Result<Self, ParseError> {
386 if buf.len() < 5 {
387 return Err(ParseError::Truncated);
388 }
389 let scf = Scf(buf[0]);
390 if !scf.reserved_valid() {
391 return Err(ParseError::InvalidScfReserved);
392 }
393 let salt = if scf.salt_present() {
394 if buf.len() < 7 {
395 return Err(ParseError::Truncated);
396 }
397 Some(u16::from_be_bytes([buf[5], buf[6]]))
398 } else {
399 None
400 };
401 Ok(Self {
402 scf,
403 frame_counter: u32::from_be_bytes([buf[1], buf[2], buf[3], buf[4]]),
404 salt,
405 })
406 }
407}
408
409#[derive(Debug, Clone, Copy, PartialEq, Eq)]
411pub enum OptionNumber {
412 RegionCode,
413 TraceRoute,
414 SourceRoute,
415 OperatorCallsign,
416 MinRssi,
417 RouteRetry,
418 StationCallsign,
419 MinSnr,
420 Unknown(u16),
421}
422
423impl OptionNumber {
424 pub fn as_u16(self) -> u16 {
426 match self {
427 Self::RegionCode => 11,
428 Self::TraceRoute => 2,
429 Self::SourceRoute => 3,
430 Self::OperatorCallsign => 4,
431 Self::MinRssi => 5,
432 Self::RouteRetry => 6,
433 Self::StationCallsign => 7,
434 Self::MinSnr => 9,
435 Self::Unknown(value) => value,
436 }
437 }
438
439 pub fn is_critical(self) -> bool {
441 self.as_u16() & 1 != 0
442 }
443
444 pub fn is_dynamic(self) -> bool {
446 self.as_u16() & 2 != 0
447 }
448}
449
450impl From<u16> for OptionNumber {
451 fn from(value: u16) -> Self {
452 match value {
453 2 => Self::TraceRoute,
454 3 => Self::SourceRoute,
455 4 => Self::OperatorCallsign,
456 5 => Self::MinRssi,
457 6 => Self::RouteRetry,
458 7 => Self::StationCallsign,
459 9 => Self::MinSnr,
460 11 => Self::RegionCode,
461 other => Self::Unknown(other),
462 }
463 }
464}
465
466#[derive(Clone, Copy, Debug, PartialEq, Eq)]
468pub enum SourceAddrRef {
469 Hint(NodeHint),
470 FullKeyAt { offset: usize },
471 Encrypted { offset: usize, len: usize },
472 None,
473}
474
475#[derive(Clone, Debug, PartialEq, Eq)]
477pub struct PacketHeader {
478 pub fcf: Fcf,
479 pub options_range: Range<usize>,
480 pub flood_hops: Option<FloodHops>,
481 pub dst: Option<NodeHint>,
482 pub channel: Option<ChannelId>,
483 pub ack_dst: Option<NodeHint>,
484 pub source: SourceAddrRef,
485 pub sec_info: Option<SecInfo>,
486 pub body_range: Range<usize>,
487 pub mic_range: Range<usize>,
488 pub total_len: usize,
489}
490
491impl PacketHeader {
492 pub fn parse(buf: &[u8]) -> Result<Self, ParseError> {
494 if buf.is_empty() {
495 return Err(ParseError::Truncated);
496 }
497
498 let fcf = Fcf(buf[0]);
499 if fcf.version() != UMSH_VERSION {
500 return Err(ParseError::InvalidVersion(fcf.version()));
501 }
502
503 let mut cursor = 1;
504 let options_range = if fcf.options_present() {
505 let len = scan_options_field(&buf[cursor..])?;
506 let range = cursor..cursor + len;
507 cursor += len;
508 range
509 } else {
510 cursor..cursor
511 };
512
513 let flood_hops = if fcf.flood_hops_present() {
514 if cursor >= buf.len() {
515 return Err(ParseError::Truncated);
516 }
517 let fh = FloodHops(buf[cursor]);
518 cursor += 1;
519 Some(fh)
520 } else {
521 None
522 };
523
524 let packet_type = fcf.packet_type();
525 let mut dst = None;
526 let mut channel = None;
527 let mut ack_dst = None;
528 let mut source = SourceAddrRef::None;
529 let mut sec_info = None;
530
531 match packet_type {
532 PacketType::Broadcast => {
533 let src_len = source_len(fcf.full_source());
534 source = if fcf.full_source() {
535 ensure_len(buf, cursor, 32)?;
536 SourceAddrRef::FullKeyAt { offset: cursor }
537 } else {
538 ensure_len(buf, cursor, 3)?;
539 SourceAddrRef::Hint(NodeHint([buf[cursor], buf[cursor + 1], buf[cursor + 2]]))
540 };
541 cursor += src_len;
542 Ok(Self {
543 fcf,
544 options_range,
545 flood_hops,
546 dst,
547 channel,
548 ack_dst,
549 source,
550 sec_info,
551 body_range: cursor..buf.len(),
552 mic_range: buf.len()..buf.len(),
553 total_len: buf.len(),
554 })
555 }
556 PacketType::MacAck => {
557 ensure_len(buf, cursor, 3)?;
558 ack_dst = Some(NodeHint([buf[cursor], buf[cursor + 1], buf[cursor + 2]]));
559 cursor += 3;
560 ensure_len(buf, cursor, 8)?;
561 Ok(Self {
562 fcf,
563 options_range,
564 flood_hops,
565 dst,
566 channel,
567 ack_dst,
568 source,
569 sec_info,
570 body_range: cursor..cursor + 8,
571 mic_range: cursor..cursor + 8,
572 total_len: cursor + 8,
573 })
574 }
575 PacketType::Unicast | PacketType::UnicastAckReq => {
576 ensure_len(buf, cursor, 3)?;
577 dst = Some(NodeHint([buf[cursor], buf[cursor + 1], buf[cursor + 2]]));
578 cursor += 3;
579 let src_len = source_len(fcf.full_source());
580 source = if fcf.full_source() {
581 ensure_len(buf, cursor, 32)?;
582 SourceAddrRef::FullKeyAt { offset: cursor }
583 } else {
584 ensure_len(buf, cursor, 3)?;
585 SourceAddrRef::Hint(NodeHint([buf[cursor], buf[cursor + 1], buf[cursor + 2]]))
586 };
587 cursor += src_len;
588 let parsed_sec = SecInfo::decode(&buf[cursor..])?;
589 let sec_len = parsed_sec.wire_len();
590 sec_info = Some(parsed_sec);
591 cursor += sec_len;
592 let mic_len = parsed_sec.scf.mic_size()?.byte_len();
593 ensure_len(buf, cursor, mic_len)?;
594 let mic_start = buf
595 .len()
596 .checked_sub(mic_len)
597 .ok_or(ParseError::Truncated)?;
598 if mic_start < cursor {
599 return Err(ParseError::Truncated);
600 }
601 Ok(Self {
602 fcf,
603 options_range,
604 flood_hops,
605 dst,
606 channel,
607 ack_dst,
608 source,
609 sec_info,
610 body_range: cursor..mic_start,
611 mic_range: mic_start..buf.len(),
612 total_len: buf.len(),
613 })
614 }
615 PacketType::Multicast => {
616 ensure_len(buf, cursor, 2)?;
617 channel = Some(ChannelId([buf[cursor], buf[cursor + 1]]));
618 cursor += 2;
619 let parsed_sec = SecInfo::decode(&buf[cursor..])?;
620 let sec_len = parsed_sec.wire_len();
621 sec_info = Some(parsed_sec);
622 cursor += sec_len;
623 let mic_len = parsed_sec.scf.mic_size()?.byte_len();
624 let mic_start = buf
625 .len()
626 .checked_sub(mic_len)
627 .ok_or(ParseError::Truncated)?;
628 if mic_start < cursor {
629 return Err(ParseError::Truncated);
630 }
631 if parsed_sec.scf.encrypted() {
632 let src_len = source_len(fcf.full_source());
633 source = SourceAddrRef::Encrypted {
634 offset: cursor,
635 len: src_len,
636 };
637 Ok(Self {
638 fcf,
639 options_range,
640 flood_hops,
641 dst,
642 channel,
643 ack_dst,
644 source,
645 sec_info,
646 body_range: cursor..mic_start,
647 mic_range: mic_start..buf.len(),
648 total_len: buf.len(),
649 })
650 } else {
651 let src_len = source_len(fcf.full_source());
652 source = if fcf.full_source() {
653 ensure_len(buf, cursor, 32)?;
654 SourceAddrRef::FullKeyAt { offset: cursor }
655 } else {
656 ensure_len(buf, cursor, 3)?;
657 SourceAddrRef::Hint(NodeHint([
658 buf[cursor],
659 buf[cursor + 1],
660 buf[cursor + 2],
661 ]))
662 };
663 cursor += src_len;
664 Ok(Self {
665 fcf,
666 options_range,
667 flood_hops,
668 dst,
669 channel,
670 ack_dst,
671 source,
672 sec_info,
673 body_range: cursor..mic_start,
674 mic_range: mic_start..buf.len(),
675 total_len: buf.len(),
676 })
677 }
678 }
679 PacketType::BlindUnicast | PacketType::BlindUnicastAckReq => {
680 ensure_len(buf, cursor, 2)?;
681 channel = Some(ChannelId([buf[cursor], buf[cursor + 1]]));
682 cursor += 2;
683 let parsed_sec = SecInfo::decode(&buf[cursor..])?;
684 let sec_len = parsed_sec.wire_len();
685 sec_info = Some(parsed_sec);
686 cursor += sec_len;
687 let src_len = source_len(fcf.full_source());
688 ensure_len(buf, cursor, 3 + src_len)?;
689 if parsed_sec.scf.encrypted() {
690 source = SourceAddrRef::Encrypted {
691 offset: cursor + 3,
692 len: src_len,
693 };
694 cursor += 3 + src_len;
695 } else {
696 dst = Some(NodeHint([buf[cursor], buf[cursor + 1], buf[cursor + 2]]));
697 cursor += 3;
698 source = if fcf.full_source() {
699 ensure_len(buf, cursor, 32)?;
700 SourceAddrRef::FullKeyAt { offset: cursor }
701 } else {
702 ensure_len(buf, cursor, 3)?;
703 SourceAddrRef::Hint(NodeHint([
704 buf[cursor],
705 buf[cursor + 1],
706 buf[cursor + 2],
707 ]))
708 };
709 cursor += src_len;
710 }
711 let mic_len = parsed_sec.scf.mic_size()?.byte_len();
712 let mic_start = buf
713 .len()
714 .checked_sub(mic_len)
715 .ok_or(ParseError::Truncated)?;
716 if mic_start < cursor {
717 return Err(ParseError::Truncated);
718 }
719 Ok(Self {
720 fcf,
721 options_range,
722 flood_hops,
723 dst,
724 channel,
725 ack_dst,
726 source,
727 sec_info,
728 body_range: cursor..mic_start,
729 mic_range: mic_start..buf.len(),
730 total_len: buf.len(),
731 })
732 }
733 PacketType::Reserved5 => Err(ParseError::MalformedOption),
734 }
735 }
736
737 pub fn packet_type(&self) -> PacketType {
739 self.fcf.packet_type()
740 }
741
742 pub fn ack_requested(&self) -> bool {
744 self.packet_type().ack_requested()
745 }
746
747 pub fn is_beacon(&self) -> bool {
749 self.packet_type() == PacketType::Broadcast && self.body_range.is_empty()
750 }
751}
752
753#[derive(Clone, Debug, Default, PartialEq, Eq)]
754pub struct ParsedOptions {
755 pub region_code: Option<[u8; 2]>,
756 pub source_route: Option<Range<usize>>,
757 pub trace_route: Option<Range<usize>>,
758 pub min_rssi: Option<i16>,
759 pub min_snr: Option<i8>,
760 pub route_retry: bool,
761 pub has_unknown_critical: bool,
762}
763
764impl ParsedOptions {
765 pub fn extract(buf: &[u8], range: Range<usize>) -> Result<Self, ParseError> {
766 let mut parsed = Self::default();
767 if range.is_empty() {
768 return Ok(parsed);
769 }
770 let options = &buf[range.clone()];
771 for entry in OptionDecoder::new(options) {
772 let (number, value) = entry?;
773 let relative_start = unsafe { value.as_ptr().offset_from(options.as_ptr()) } as usize;
774 let value_start = range.start + relative_start;
775 let value_range = value_start..value_start + value.len();
776 match OptionNumber::from(number) {
777 OptionNumber::RegionCode if value.len() == 2 => {
778 parsed.region_code = Some([value[0], value[1]]);
779 }
780 OptionNumber::TraceRoute => parsed.trace_route = Some(value_range),
781 OptionNumber::SourceRoute => parsed.source_route = Some(value_range),
782 OptionNumber::RouteRetry if value.is_empty() => parsed.route_retry = true,
783 OptionNumber::MinRssi if value.len() == 2 => {
784 parsed.min_rssi = Some(i16::from_be_bytes([value[0], value[1]]));
785 }
786 OptionNumber::MinSnr if value.len() == 1 => parsed.min_snr = Some(value[0] as i8),
787 OptionNumber::Unknown(raw) if raw & 1 != 0 => parsed.has_unknown_critical = true,
788 _ => {}
789 }
790 }
791 Ok(parsed)
792 }
793}
794
795pub fn iter_options<'a>(buf: &'a [u8], range: Range<usize>) -> OptionDecoder<'a> {
796 OptionDecoder::new(&buf[range])
797}
798
799pub fn feed_aad(header: &PacketHeader, packet_buf: &[u8], mut sink: impl FnMut(&[u8])) {
800 sink(&packet_buf[..1]);
801 for option in iter_options(packet_buf, header.options_range.clone()) {
802 let Ok((number, value)) = option else {
803 return;
804 };
805 let option_number = OptionNumber::from(number);
806 if option_number.is_dynamic() {
807 continue;
808 }
809 let mut tl = [0u8; 4];
810 tl[..2].copy_from_slice(&number.to_be_bytes());
811 tl[2..].copy_from_slice(&(value.len() as u16).to_be_bytes());
812 sink(&tl);
813 sink(value);
814 }
815
816 if let Some(dst) = header.dst {
817 sink(&dst.0);
818 }
819 if let Some(channel) = header.channel {
820 sink(&channel.0);
821 }
822 match header.source {
823 SourceAddrRef::Hint(hint) => sink(&hint.0),
824 SourceAddrRef::FullKeyAt { offset } => sink(&packet_buf[offset..offset + 32]),
825 SourceAddrRef::Encrypted { .. } | SourceAddrRef::None => {}
826 }
827 if let Some(sec_info) = header.sec_info {
828 let mut buf = [0u8; 7];
829 let Ok(len) = sec_info.encode(&mut buf) else {
830 return;
831 };
832 sink(&buf[..len]);
833 }
834}
835
836fn ensure_len(buf: &[u8], offset: usize, len: usize) -> Result<(), ParseError> {
837 if buf.len() < offset + len {
838 Err(ParseError::Truncated)
839 } else {
840 Ok(())
841 }
842}
843
844fn scan_options_field(data: &[u8]) -> Result<usize, ParseError> {
845 let mut decoder = OptionDecoder::new(data);
846 while let Some(result) = decoder.next() {
847 result?;
848 }
849
850 Ok(data.len() - decoder.remainder().len())
851}
852
853pub(crate) fn source_len(full_source: bool) -> usize {
854 if full_source { 32 } else { 3 }
855}
856
857#[derive(Debug, PartialEq, Eq)]
858pub struct UnsealedPacket<'a> {
859 buf: &'a mut [u8],
860 total_len: usize,
861 body_range: Range<usize>,
862 blind_addr_range: Option<Range<usize>>,
863 mic_range: Range<usize>,
864 sec_info_range: Range<usize>,
865 aad_static_options: Range<usize>,
866}
867
868impl<'a> UnsealedPacket<'a> {
869 pub fn new(
870 buf: &'a mut [u8],
871 total_len: usize,
872 body_range: Range<usize>,
873 blind_addr_range: Option<Range<usize>>,
874 mic_range: Range<usize>,
875 sec_info_range: Range<usize>,
876 aad_static_options: Range<usize>,
877 ) -> Self {
878 Self {
879 buf,
880 total_len,
881 body_range,
882 blind_addr_range,
883 mic_range,
884 sec_info_range,
885 aad_static_options,
886 }
887 }
888
889 pub fn header(&self) -> Result<PacketHeader, ParseError> {
890 PacketHeader::parse(self.as_bytes())
891 }
892
893 pub fn body(&self) -> &[u8] {
894 &self.buf[self.body_range.clone()]
895 }
896
897 pub fn body_mut(&mut self) -> &mut [u8] {
898 &mut self.buf[self.body_range.clone()]
899 }
900
901 pub fn blind_addr_range(&self) -> Option<Range<usize>> {
902 self.blind_addr_range.clone()
903 }
904
905 pub fn blind_addr(&self) -> Option<&[u8]> {
906 let range = self.blind_addr_range.clone()?;
907 Some(&self.buf[range])
908 }
909
910 pub fn mic_slot(&mut self) -> &mut [u8] {
911 &mut self.buf[self.mic_range.clone()]
912 }
913
914 pub fn as_bytes(&self) -> &[u8] {
915 &self.buf[..self.total_len]
916 }
917
918 pub fn as_bytes_mut(&mut self) -> &mut [u8] {
919 &mut self.buf[..self.total_len]
920 }
921
922 pub fn total_len(&self) -> usize {
923 self.total_len
924 }
925
926 pub fn sec_info_range(&self) -> Range<usize> {
927 self.sec_info_range.clone()
928 }
929
930 pub fn aad_static_options(&self) -> Range<usize> {
931 self.aad_static_options.clone()
932 }
933}