1use super::BitSlice;
8use bitvec::prelude::*;
9use num_enum::TryFromPrimitive;
10use std::fmt::{Display, Formatter};
11use thiserror::Error;
12
13#[derive(Debug, Clone, Eq, PartialEq, Hash)]
17pub struct GSEHeader {
18 start: bool,
19 end: bool,
20 label_type: LabelType,
21 gse_length: u16,
22 frag_id: Option<u8>,
23 total_length: Option<u16>,
24 protocol_type: Option<u16>,
25 label: Option<Label>,
26}
27
28impl GSEHeader {
29 pub fn from_slice(slice: &[u8], re_used_label: Option<&Label>) -> Option<GSEHeader> {
48 let fixed_len = 2;
49 if slice.len() < fixed_len {
50 return None;
51 }
52 let fixed = BitSlice::from_slice(&slice[..fixed_len]);
53 let start = fixed[0];
54 let end = fixed[1];
55 let label_type = LabelType::try_from(fixed[2..4].load_be::<u8>()).unwrap();
56 if !start && !end && matches!(label_type, LabelType::Label6Byte) {
57 return None;
59 }
60 let gse_length = fixed[4..].load_be::<u16>();
61 let mut remain = &slice[fixed_len..];
62 let frag_id = if !start || !end {
63 let (&value, r) = remain.split_first()?;
64 remain = r;
65 Some(value)
66 } else {
67 None
68 };
69 let total_length = if start && !end {
70 if remain.len() < 2 {
71 return None;
72 }
73 let (field, r) = remain.split_at(2);
74 remain = r;
75 Some(u16::from_be_bytes(field.try_into().unwrap()))
76 } else {
77 None
78 };
79 let protocol_type = if start {
80 if remain.len() < 2 {
81 return None;
82 }
83 let (field, r) = remain.split_at(2);
84 remain = r;
85 Some(u16::from_be_bytes(field.try_into().unwrap()))
86 } else {
87 None
88 };
89 let label = if start {
90 if matches!(label_type, LabelType::ReUse) {
91 if let Some(label) = re_used_label {
92 Some(label.clone())
93 } else {
94 log::error!("LT = re-use, but no label to re-use");
95 return None;
96 }
97 } else {
98 let label_size = match label_type {
99 LabelType::Label6Byte => LabelSize::Size6Bytes,
100 LabelType::Label3Byte => LabelSize::Size3Bytes,
101 LabelType::Broadcast => LabelSize::Zero,
102 LabelType::ReUse => unreachable!(),
103 };
104 if remain.len() < label_size.len() {
105 log::error!("not enough bytes for label remain in slice");
106 return None;
107 }
108 let mut data = [0; 6];
109 data[..label_size.len()].copy_from_slice(&remain[..label_size.len()]);
110 Some(Label {
111 data,
112 size: label_size,
113 })
114 }
115 } else {
116 None
117 };
118 Some(GSEHeader {
119 start,
120 end,
121 label_type,
122 gse_length,
123 frag_id,
124 total_length,
125 protocol_type,
126 label,
127 })
128 }
129
130 pub fn start(&self) -> bool {
132 self.start
133 }
134
135 pub fn end(&self) -> bool {
137 self.end
138 }
139
140 pub fn is_single_fragment(&self) -> bool {
145 self.start() && self.end()
146 }
147
148 pub fn label_type(&self) -> LabelType {
150 self.label_type
151 }
152
153 pub fn gse_length(&self) -> u16 {
155 self.gse_length
156 }
157
158 pub fn fragment_id(&self) -> Option<u8> {
160 self.frag_id
161 }
162
163 pub fn total_length(&self) -> Option<u16> {
165 self.total_length
166 }
167
168 pub fn protocol_type(&self) -> Option<u16> {
170 self.protocol_type
171 }
172
173 pub fn label(&self) -> Option<&Label> {
175 self.label.as_ref()
176 }
177
178 pub fn len(&self) -> usize {
180 let mut len = 2; if self.frag_id.is_some() {
182 len += 1;
183 }
184 if self.total_length.is_some() {
185 len += 2;
186 }
187 if self.protocol_type.is_some() {
188 len += 2;
189 }
190 if !matches!(self.label_type, LabelType::ReUse)
194 && let Some(label) = &self.label
195 {
196 len += label.len();
197 }
198 len
199 }
200
201 pub fn is_empty(&self) -> bool {
207 false
208 }
209}
210
211impl Display for GSEHeader {
212 fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
213 write!(
214 f,
215 "GSE Header (S = {}, E = {}, LT = {}, GSE Length = {} bytes",
216 self.start, self.end, self.label_type, self.gse_length
217 )?;
218 if let Some(frag_id) = self.frag_id {
219 write!(f, ", Fragment ID = {}", frag_id)?;
220 }
221 if let Some(total_length) = self.total_length {
222 write!(f, ", Total Length = {}", total_length)?;
223 }
224 if let Some(protocol_type) = self.protocol_type {
225 write!(f, ", Protocol Type = {:#06x}", protocol_type)?;
226 }
227 if let Some(label) = &self.label {
228 write!(f, ", Label = {}", label)?;
229 }
230 write!(f, ")")
231 }
232}
233
234#[derive(Debug, Clone, Eq)]
240pub struct Label {
241 data: [u8; 6],
242 size: LabelSize,
243}
244
245impl Label {
246 pub fn broadcast() -> Label {
248 Label {
249 data: [0; 6],
250 size: LabelSize::Zero,
251 }
252 }
253
254 pub fn as_slice(&self) -> &[u8] {
256 &self.data[..self.len()]
257 }
258
259 pub fn len(&self) -> usize {
261 self.size.len()
262 }
263
264 pub fn is_broadcast(&self) -> bool {
266 self.is_empty()
267 }
268
269 pub fn is_empty(&self) -> bool {
273 matches!(self.size, LabelSize::Zero)
274 }
275
276 pub fn from_hex(hex_label: &str) -> Result<Label, LabelParseErr> {
280 let mut data = [0; 6];
281 let mut num_data = 0;
282 for (n, part) in hex_label.split(":").enumerate() {
283 if n >= 6 {
284 return Err(LabelParseErr::WrongHexFormat);
286 }
287 let Ok(x) = u8::from_str_radix(part, 16) else {
288 return Err(LabelParseErr::WrongHexFormat);
289 };
290 data[n] = x;
291 num_data = n;
292 }
293 let size = match num_data + 1 {
294 3 => LabelSize::Size3Bytes,
295 6 => LabelSize::Size6Bytes,
296 _ => return Err(LabelParseErr::WrongHexFormat),
297 };
298 Ok(Label { data, size })
299 }
300}
301
302#[derive(Error, Debug, Copy, Clone, Eq, PartialEq, Hash)]
304pub enum LabelParseErr {
305 #[error("The hex format for the label is wrong")]
307 WrongHexFormat,
308}
309
310impl PartialEq for Label {
311 fn eq(&self, other: &Label) -> bool {
312 self.as_slice() == other.as_slice()
313 }
314}
315
316impl std::hash::Hash for Label {
317 fn hash<H>(&self, state: &mut H)
318 where
319 H: std::hash::Hasher,
320 {
321 self.as_slice().hash(state)
322 }
323}
324
325impl Display for Label {
326 fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
327 if let Some((first, rest)) = self.as_slice().split_first() {
328 write!(f, "{:02x}", first)?;
329 for b in rest {
330 write!(f, ":{:02x}", b)?;
331 }
332 Ok(())
333 } else {
334 write!(f, "broadcast")
335 }
336 }
337}
338
339#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, TryFromPrimitive)]
341#[repr(u8)]
342pub enum LabelType {
343 Label6Byte = 0b00,
345 Label3Byte = 0b01,
347 Broadcast = 0b10,
349 ReUse = 0b11,
351}
352
353#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
354enum LabelSize {
355 Size6Bytes,
356 Size3Bytes,
357 Zero,
358}
359
360impl Display for LabelType {
361 fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
362 write!(
363 f,
364 "{}",
365 match self {
366 LabelType::Label6Byte => "6 byte label",
367 LabelType::Label3Byte => "3 byte label",
368 LabelType::Broadcast => "broadcast label",
369 LabelType::ReUse => "label re-use",
370 }
371 )
372 }
373}
374
375impl LabelSize {
376 fn len(&self) -> usize {
377 match self {
378 LabelSize::Size6Bytes => 6,
379 LabelSize::Size3Bytes => 3,
380 LabelSize::Zero => 0,
381 }
382 }
383}
384
385#[cfg(test)]
386mod test {
387 use super::*;
388 use hex_literal::hex;
389 use test_log::test;
390
391 const GSE_HEADER_SINGLE_PACKET: [u8; 10] = hex!("c0 5c 08 00 02 00 48 55 4c 4b");
392
393 #[test]
394 fn single_packet() {
395 let header = GSEHeader::from_slice(&GSE_HEADER_SINGLE_PACKET, None).unwrap();
396 assert_eq!(
397 format!("{}", header),
398 "GSE Header (S = true, E = true, LT = 6 byte label, \
399 GSE Length = 92 bytes, Protocol Type = 0x0800, \
400 Label = 02:00:48:55:4c:4b)"
401 );
402 assert!(header.start());
403 assert!(header.end());
404 assert!(header.is_single_fragment());
405 assert_eq!(header.label_type(), LabelType::Label6Byte);
406 assert_eq!(header.gse_length(), 92);
407 assert_eq!(header.fragment_id(), None);
408 assert_eq!(header.total_length(), None);
409 assert_eq!(header.protocol_type(), Some(0x0800));
410 let label = header.label().unwrap();
411 assert_eq!(label.as_slice(), &GSE_HEADER_SINGLE_PACKET[4..]);
412 assert_eq!(label.len(), 6);
413 assert!(!label.is_empty());
414 assert_eq!(header.len(), GSE_HEADER_SINGLE_PACKET.len());
415 assert!(!header.is_empty());
416 }
417
418 #[test]
419 fn too_short() {
420 assert!(GSEHeader::from_slice(&GSE_HEADER_SINGLE_PACKET[..9], None).is_none());
421 }
422
423 const GSE_HEADER_FIRST_FRAGMENT: [u8; 13] = hex!("80 5c 17 01 23 08 00 02 00 48 55 4c 4b");
424
425 #[test]
426 fn first_fragment() {
427 let header = GSEHeader::from_slice(&GSE_HEADER_FIRST_FRAGMENT, None).unwrap();
428 assert_eq!(
429 format!("{}", header),
430 "GSE Header (S = true, E = false, LT = 6 byte label, \
431 GSE Length = 92 bytes, Fragment ID = 23, Total Length = 291, \
432 Protocol Type = 0x0800, Label = 02:00:48:55:4c:4b)"
433 );
434 assert!(header.start());
435 assert!(!header.end());
436 assert!(!header.is_single_fragment());
437 assert_eq!(header.label_type(), LabelType::Label6Byte);
438 assert_eq!(header.gse_length(), 92);
439 assert_eq!(header.fragment_id(), Some(23));
440 assert_eq!(header.total_length(), Some(291));
441 assert_eq!(header.protocol_type(), Some(0x0800));
442 let label = header.label().unwrap();
443 assert_eq!(label.as_slice(), &GSE_HEADER_FIRST_FRAGMENT[7..]);
444 assert_eq!(label.len(), 6);
445 assert!(!label.is_empty());
446 assert_eq!(header.len(), GSE_HEADER_FIRST_FRAGMENT.len());
447 assert!(!header.is_empty());
448 }
449
450 const GSE_HEADER_INTERMEDIATE_FRAGMENT: [u8; 3] = hex!("30 5c 17");
451
452 #[test]
453 fn intermediate_fragment() {
454 let header = GSEHeader::from_slice(&GSE_HEADER_INTERMEDIATE_FRAGMENT, None).unwrap();
455 assert_eq!(
456 format!("{}", header),
457 "GSE Header (S = false, E = false, LT = label re-use, \
458 GSE Length = 92 bytes, Fragment ID = 23)"
459 );
460 assert!(!header.start());
461 assert!(!header.end());
462 assert!(!header.is_single_fragment());
463 assert_eq!(header.label_type(), LabelType::ReUse);
464 assert_eq!(header.gse_length(), 92);
465 assert_eq!(header.fragment_id(), Some(23));
466 assert_eq!(header.total_length(), None);
467 assert_eq!(header.protocol_type(), None);
468 assert_eq!(header.label(), None);
469 assert_eq!(header.len(), GSE_HEADER_INTERMEDIATE_FRAGMENT.len());
470 assert!(!header.is_empty());
471 }
472
473 const GSE_HEADER_LAST_FRAGMENT: [u8; 3] = hex!("70 5c 17");
474
475 #[test]
476 fn last_fragment() {
477 let header = GSEHeader::from_slice(&GSE_HEADER_LAST_FRAGMENT, None).unwrap();
478 assert_eq!(
479 format!("{}", header),
480 "GSE Header (S = false, E = true, LT = label re-use, \
481 GSE Length = 92 bytes, Fragment ID = 23)"
482 );
483 assert!(!header.start());
484 assert!(header.end());
485 assert!(!header.is_single_fragment());
486 assert_eq!(header.label_type(), LabelType::ReUse);
487 assert_eq!(header.gse_length(), 92);
488 assert_eq!(header.fragment_id(), Some(23));
489 assert_eq!(header.total_length(), None);
490 assert_eq!(header.protocol_type(), None);
491 assert_eq!(header.label(), None);
492 assert_eq!(header.len(), GSE_HEADER_LAST_FRAGMENT.len());
493 assert!(!header.is_empty());
494 }
495
496 const GSE_HEADER_SINGLE_PACKET_3BYTE_LABEL: [u8; 7] = hex!("d0 5c 08 00 55 4c 4b");
497
498 #[test]
499 fn single_packet_3byte_label() {
500 let header = GSEHeader::from_slice(&GSE_HEADER_SINGLE_PACKET_3BYTE_LABEL, None).unwrap();
501 assert_eq!(
502 format!("{}", header),
503 "GSE Header (S = true, E = true, LT = 3 byte label, \
504 GSE Length = 92 bytes, Protocol Type = 0x0800, \
505 Label = 55:4c:4b)"
506 );
507 assert!(header.start());
508 assert!(header.end());
509 assert!(header.is_single_fragment());
510 assert_eq!(header.label_type(), LabelType::Label3Byte);
511 assert_eq!(header.gse_length(), 92);
512 assert_eq!(header.fragment_id(), None);
513 assert_eq!(header.total_length(), None);
514 assert_eq!(header.protocol_type(), Some(0x0800));
515 let label = header.label().unwrap();
516 assert_eq!(label.as_slice(), &GSE_HEADER_SINGLE_PACKET_3BYTE_LABEL[4..]);
517 assert_eq!(label.len(), 3);
518 assert!(!label.is_empty());
519 assert_eq!(header.len(), GSE_HEADER_SINGLE_PACKET_3BYTE_LABEL.len());
520 assert!(!header.is_empty());
521 }
522
523 const GSE_HEADER_SINGLE_PACKET_BROADCAST_LABEL: [u8; 4] = hex!("e0 5c 08 00");
524
525 #[test]
526 fn single_packet_broadcast_label() {
527 let header =
528 GSEHeader::from_slice(&GSE_HEADER_SINGLE_PACKET_BROADCAST_LABEL, None).unwrap();
529 assert_eq!(
530 format!("{}", header),
531 "GSE Header (S = true, E = true, LT = broadcast label, \
532 GSE Length = 92 bytes, Protocol Type = 0x0800, Label = broadcast)"
533 );
534 assert!(header.start());
535 assert!(header.end());
536 assert!(header.is_single_fragment());
537 assert_eq!(header.label_type(), LabelType::Broadcast);
538 assert_eq!(header.gse_length(), 92);
539 assert_eq!(header.fragment_id(), None);
540 assert_eq!(header.total_length(), None);
541 assert_eq!(header.protocol_type(), Some(0x0800));
542 let label = header.label().unwrap();
543 assert_eq!(label.as_slice(), &[]);
544 assert_eq!(label.len(), 0);
545 assert!(label.is_empty());
546 assert_eq!(header.len(), GSE_HEADER_SINGLE_PACKET_BROADCAST_LABEL.len());
547 assert!(!header.is_empty());
548 }
549
550 const GSE_HEADER_SINGLE_PACKET_LABEL_REUSE: [u8; 4] = hex!("f0 5c 08 00");
551
552 #[test]
553 fn single_packet_label_reuse() {
554 let g0 = GSEHeader::from_slice(&GSE_HEADER_SINGLE_PACKET, None).unwrap();
555 let re_used_label = g0.label().unwrap();
556 let header =
557 GSEHeader::from_slice(&GSE_HEADER_SINGLE_PACKET_LABEL_REUSE, Some(re_used_label))
558 .unwrap();
559 assert_eq!(
560 format!("{}", header),
561 "GSE Header (S = true, E = true, LT = label re-use, \
562 GSE Length = 92 bytes, Protocol Type = 0x0800, \
563 Label = 02:00:48:55:4c:4b)"
564 );
565 assert!(header.start());
566 assert!(header.end());
567 assert!(header.is_single_fragment());
568 assert_eq!(header.label_type(), LabelType::ReUse);
569 assert_eq!(header.gse_length(), 92);
570 assert_eq!(header.fragment_id(), None);
571 assert_eq!(header.total_length(), None);
572 assert_eq!(header.protocol_type(), Some(0x0800));
573 let label = header.label().unwrap();
574 assert_eq!(label, re_used_label);
575 assert_eq!(header.len(), GSE_HEADER_SINGLE_PACKET_LABEL_REUSE.len());
576 assert!(!header.is_empty());
577 }
578
579 #[test]
580 fn padding_packet() {
581 assert_eq!(GSEHeader::from_slice(&[0; 2], None), None);
582 }
583
584 #[test]
585 fn parse_3byte_label() {
586 assert_eq!(
587 Label::from_hex("01:27:3a").unwrap(),
588 Label {
589 data: [0x01, 0x27, 0x3a, 0x00, 0x00, 0x00],
590 size: LabelSize::Size3Bytes,
591 }
592 );
593 }
594
595 #[test]
596 fn parse_6byte_label() {
597 assert_eq!(
598 Label::from_hex("af:3c:14:59:00:15").unwrap(),
599 Label {
600 data: [0xaf, 0x3c, 0x14, 0x59, 0x00, 0x15],
601 size: LabelSize::Size6Bytes,
602 }
603 );
604 }
605
606 #[test]
607 fn parse_wrong_labels() {
608 assert!(Label::from_hex("foo").is_err());
609 assert!(Label::from_hex("01:00").is_err());
610 assert!(Label::from_hex("01:23:45:67:89:ab:cd").is_err());
611 assert!(Label::from_hex("01:00:02:00").is_err());
612 assert!(Label::from_hex("01273a").is_err());
613 assert!(Label::from_hex("af3c14590015").is_err());
614 }
615
616 #[test]
617 fn broadcast_label() {
618 let label = Label::broadcast();
619 assert!(label.is_broadcast());
620 assert!(label.is_empty());
621 }
622
623 #[test]
624 fn non_broadcast_label() {
625 let label = Label {
626 data: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
627 size: LabelSize::Size6Bytes,
628 };
629 assert!(!label.is_broadcast());
630 assert!(!label.is_empty());
631 }
632
633 #[test]
634 fn hash_3bytes_does_not_read_extra_bytes() {
635 use std::hash::{DefaultHasher, Hash, Hasher};
636 let a = Label {
637 data: [0x01, 0x02, 0x03, 0x00, 0x00, 0x00],
638 size: LabelSize::Size3Bytes,
639 };
640 let b = Label {
641 data: [0x01, 0x02, 0x03, 0xff, 0xff, 0xff],
642 size: LabelSize::Size3Bytes,
643 };
644 let mut s = DefaultHasher::new();
645 let mut t = DefaultHasher::new();
646 a.hash(&mut s);
647 b.hash(&mut t);
648 assert_eq!(s.finish(), t.finish());
649 }
650}
651
652#[cfg(test)]
653mod proptests {
654 use super::*;
655 use proptest::prelude::*;
656
657 proptest! {
658 #[test]
659 fn random_header(header in proptest::collection::vec(any::<u8>(), 0..=32)) {
660 if let Some(header) = GSEHeader::from_slice(&header, None) {
661 let _ = format!("{}", header);
662 header.start();
663 header.end();
664 header.is_single_fragment();
665 header.label_type();
666 header.gse_length();
667 header.fragment_id();
668 header.total_length();
669 header.protocol_type();
670 if let Some(label) = header.label() {
671 label.as_slice();
672 let len = label.len();
673 assert_eq!(label.is_empty(), len == 0);
674 }
675 assert!(header.len() >= 3);
676 assert!(!header.is_empty());
677 }
678 }
679 }
680}