1use super::BitSlice;
8use bitvec::prelude::*;
9use num_enum::TryFromPrimitive;
10use std::fmt::{Display, Formatter};
11
12#[derive(Debug, Clone, Eq, PartialEq, Hash)]
16pub struct GSEHeader {
17 start: bool,
18 end: bool,
19 label_type: LabelType,
20 gse_length: u16,
21 frag_id: Option<u8>,
22 total_length: Option<u16>,
23 protocol_type: Option<u16>,
24 label: Option<Label>,
25}
26
27impl GSEHeader {
28 pub fn from_slice(slice: &[u8], re_used_label: Option<&Label>) -> Option<GSEHeader> {
47 let fixed_len = 2;
48 if slice.len() < fixed_len {
49 return None;
50 }
51 let fixed = BitSlice::from_slice(&slice[..fixed_len]);
52 let start = fixed[0];
53 let end = fixed[1];
54 let label_type = LabelType::try_from(fixed[2..4].load_be::<u8>()).unwrap();
55 if !start && !end && matches!(label_type, LabelType::Label6Byte) {
56 return None;
58 }
59 let gse_length = fixed[4..].load_be::<u16>();
60 let mut remain = &slice[fixed_len..];
61 let frag_id = if !start || !end {
62 let (&value, r) = remain.split_first()?;
63 remain = r;
64 Some(value)
65 } else {
66 None
67 };
68 let total_length = if start && !end {
69 if remain.len() < 2 {
70 return None;
71 }
72 let (field, r) = remain.split_at(2);
73 remain = r;
74 Some(u16::from_be_bytes(field.try_into().unwrap()))
75 } else {
76 None
77 };
78 let protocol_type = if start {
79 if remain.len() < 2 {
80 return None;
81 }
82 let (field, r) = remain.split_at(2);
83 remain = r;
84 Some(u16::from_be_bytes(field.try_into().unwrap()))
85 } else {
86 None
87 };
88 let label = if start {
89 if matches!(label_type, LabelType::ReUse) {
90 if let Some(label) = re_used_label {
91 Some(label.clone())
92 } else {
93 log::error!("LT = re-use, but not label to re-use");
94 return None;
95 }
96 } else {
97 let label_size = match label_type {
98 LabelType::Label6Byte => LabelSize::Size6Bytes,
99 LabelType::Label3Byte => LabelSize::Size3Bytes,
100 LabelType::Broadcast => LabelSize::Zero,
101 LabelType::ReUse => unreachable!(),
102 };
103 if remain.len() < label_size.len() {
104 log::error!("not enough bytes for label remain in slice");
105 return None;
106 }
107 let mut data = [0; 6];
108 data[..label_size.len()].copy_from_slice(&remain[..label_size.len()]);
109 Some(Label {
110 data,
111 size: label_size,
112 })
113 }
114 } else {
115 None
116 };
117 Some(GSEHeader {
118 start,
119 end,
120 label_type,
121 gse_length,
122 frag_id,
123 total_length,
124 protocol_type,
125 label,
126 })
127 }
128
129 pub fn start(&self) -> bool {
131 self.start
132 }
133
134 pub fn end(&self) -> bool {
136 self.end
137 }
138
139 pub fn is_single_fragment(&self) -> bool {
144 self.start() && self.end()
145 }
146
147 pub fn label_type(&self) -> LabelType {
149 self.label_type
150 }
151
152 pub fn gse_length(&self) -> u16 {
154 self.gse_length
155 }
156
157 pub fn fragment_id(&self) -> Option<u8> {
159 self.frag_id
160 }
161
162 pub fn total_length(&self) -> Option<u16> {
164 self.total_length
165 }
166
167 pub fn protocol_type(&self) -> Option<u16> {
169 self.protocol_type
170 }
171
172 pub fn label(&self) -> Option<&Label> {
174 self.label.as_ref()
175 }
176
177 pub fn len(&self) -> usize {
179 let mut len = 2; if self.frag_id.is_some() {
181 len += 1;
182 }
183 if self.total_length.is_some() {
184 len += 2;
185 }
186 if self.protocol_type.is_some() {
187 len += 2;
188 }
189 if !matches!(self.label_type, LabelType::ReUse) {
193 if let Some(label) = &self.label {
194 len += label.len();
195 }
196 }
197 len
198 }
199
200 pub fn is_empty(&self) -> bool {
206 false
207 }
208}
209
210impl Display for GSEHeader {
211 fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
212 write!(
213 f,
214 "GSE Header (S = {}, E = {}, LT = {}, GSE Length = {} bytes",
215 self.start, self.end, self.label_type, self.gse_length
216 )?;
217 if let Some(frag_id) = self.frag_id {
218 write!(f, ", Fragment ID = {}", frag_id)?;
219 }
220 if let Some(total_length) = self.total_length {
221 write!(f, ", Total Length = {}", total_length)?;
222 }
223 if let Some(protocol_type) = self.protocol_type {
224 write!(f, ", Protocol Type = {:#06x}", protocol_type)?;
225 }
226 if let Some(label) = &self.label {
227 write!(f, ", Label = {}", label)?;
228 }
229 write!(f, ")")
230 }
231}
232
233#[derive(Debug, Clone, Eq, PartialEq, Hash)]
239pub struct Label {
240 data: [u8; 6],
241 size: LabelSize,
242}
243
244impl Label {
245 pub fn as_slice(&self) -> &[u8] {
247 &self.data[..self.len()]
248 }
249
250 pub fn len(&self) -> usize {
252 self.size.len()
253 }
254
255 pub fn is_empty(&self) -> bool {
259 matches!(self.size, LabelSize::Zero)
260 }
261}
262
263impl Display for Label {
264 fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
265 if let Some((first, rest)) = self.as_slice().split_first() {
266 write!(f, "{:02x}", first)?;
267 for b in rest {
268 write!(f, ":{:02x}", b)?;
269 }
270 Ok(())
271 } else {
272 write!(f, "broadcast")
273 }
274 }
275}
276
277#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, TryFromPrimitive)]
279#[repr(u8)]
280pub enum LabelType {
281 Label6Byte = 0b00,
283 Label3Byte = 0b01,
285 Broadcast = 0b10,
287 ReUse = 0b11,
289}
290
291#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
292enum LabelSize {
293 Size6Bytes,
294 Size3Bytes,
295 Zero,
296}
297
298impl Display for LabelType {
299 fn fmt(&self, f: &mut Formatter) -> Result<(), std::fmt::Error> {
300 write!(
301 f,
302 "{}",
303 match self {
304 LabelType::Label6Byte => "6 byte label",
305 LabelType::Label3Byte => "3 byte label",
306 LabelType::Broadcast => "broadcast label",
307 LabelType::ReUse => "label re-use",
308 }
309 )
310 }
311}
312
313impl LabelSize {
314 fn len(&self) -> usize {
315 match self {
316 LabelSize::Size6Bytes => 6,
317 LabelSize::Size3Bytes => 3,
318 LabelSize::Zero => 0,
319 }
320 }
321}
322
323#[cfg(test)]
324mod test {
325 use super::*;
326 use hex_literal::hex;
327
328 const GSE_HEADER_SINGLE_PACKET: [u8; 10] = hex!("c0 5c 08 00 02 00 48 55 4c 4b");
329
330 #[test]
331 fn single_packet() {
332 let header = GSEHeader::from_slice(&GSE_HEADER_SINGLE_PACKET, None).unwrap();
333 assert_eq!(
334 format!("{}", header),
335 "GSE Header (S = true, E = true, LT = 6 byte label, \
336 GSE Length = 92 bytes, Protocol Type = 0x0800, \
337 Label = 02:00:48:55:4c:4b)"
338 );
339 assert!(header.start());
340 assert!(header.end());
341 assert!(header.is_single_fragment());
342 assert_eq!(header.label_type(), LabelType::Label6Byte);
343 assert_eq!(header.gse_length(), 92);
344 assert_eq!(header.fragment_id(), None);
345 assert_eq!(header.total_length(), None);
346 assert_eq!(header.protocol_type(), Some(0x0800));
347 let label = header.label().unwrap();
348 assert_eq!(label.as_slice(), &GSE_HEADER_SINGLE_PACKET[4..]);
349 assert_eq!(label.len(), 6);
350 assert!(!label.is_empty());
351 assert_eq!(header.len(), GSE_HEADER_SINGLE_PACKET.len());
352 assert!(!header.is_empty());
353 }
354
355 #[test]
356 fn too_short() {
357 assert!(GSEHeader::from_slice(&GSE_HEADER_SINGLE_PACKET[..9], None).is_none());
358 }
359
360 const GSE_HEADER_FIRST_FRAGMENT: [u8; 13] = hex!("80 5c 17 01 23 08 00 02 00 48 55 4c 4b");
361
362 #[test]
363 fn first_fragment() {
364 let header = GSEHeader::from_slice(&GSE_HEADER_FIRST_FRAGMENT, None).unwrap();
365 assert_eq!(
366 format!("{}", header),
367 "GSE Header (S = true, E = false, LT = 6 byte label, \
368 GSE Length = 92 bytes, Fragment ID = 23, Total Length = 291, \
369 Protocol Type = 0x0800, Label = 02:00:48:55:4c:4b)"
370 );
371 assert!(header.start());
372 assert!(!header.end());
373 assert!(!header.is_single_fragment());
374 assert_eq!(header.label_type(), LabelType::Label6Byte);
375 assert_eq!(header.gse_length(), 92);
376 assert_eq!(header.fragment_id(), Some(23));
377 assert_eq!(header.total_length(), Some(291));
378 assert_eq!(header.protocol_type(), Some(0x0800));
379 let label = header.label().unwrap();
380 assert_eq!(label.as_slice(), &GSE_HEADER_FIRST_FRAGMENT[7..]);
381 assert_eq!(label.len(), 6);
382 assert!(!label.is_empty());
383 assert_eq!(header.len(), GSE_HEADER_FIRST_FRAGMENT.len());
384 assert!(!header.is_empty());
385 }
386
387 const GSE_HEADER_INTERMEDIATE_FRAGMENT: [u8; 3] = hex!("30 5c 17");
388
389 #[test]
390 fn intermediate_fragment() {
391 let header = GSEHeader::from_slice(&GSE_HEADER_INTERMEDIATE_FRAGMENT, None).unwrap();
392 assert_eq!(
393 format!("{}", header),
394 "GSE Header (S = false, E = false, LT = label re-use, \
395 GSE Length = 92 bytes, Fragment ID = 23)"
396 );
397 assert!(!header.start());
398 assert!(!header.end());
399 assert!(!header.is_single_fragment());
400 assert_eq!(header.label_type(), LabelType::ReUse);
401 assert_eq!(header.gse_length(), 92);
402 assert_eq!(header.fragment_id(), Some(23));
403 assert_eq!(header.total_length(), None);
404 assert_eq!(header.protocol_type(), None);
405 assert_eq!(header.label(), None);
406 assert_eq!(header.len(), GSE_HEADER_INTERMEDIATE_FRAGMENT.len());
407 assert!(!header.is_empty());
408 }
409
410 const GSE_HEADER_LAST_FRAGMENT: [u8; 3] = hex!("70 5c 17");
411
412 #[test]
413 fn last_fragment() {
414 let header = GSEHeader::from_slice(&GSE_HEADER_LAST_FRAGMENT, None).unwrap();
415 assert_eq!(
416 format!("{}", header),
417 "GSE Header (S = false, E = true, LT = label re-use, \
418 GSE Length = 92 bytes, Fragment ID = 23)"
419 );
420 assert!(!header.start());
421 assert!(header.end());
422 assert!(!header.is_single_fragment());
423 assert_eq!(header.label_type(), LabelType::ReUse);
424 assert_eq!(header.gse_length(), 92);
425 assert_eq!(header.fragment_id(), Some(23));
426 assert_eq!(header.total_length(), None);
427 assert_eq!(header.protocol_type(), None);
428 assert_eq!(header.label(), None);
429 assert_eq!(header.len(), GSE_HEADER_LAST_FRAGMENT.len());
430 assert!(!header.is_empty());
431 }
432
433 const GSE_HEADER_SINGLE_PACKET_3BYTE_LABEL: [u8; 7] = hex!("d0 5c 08 00 55 4c 4b");
434
435 #[test]
436 fn single_packet_3byte_label() {
437 let header = GSEHeader::from_slice(&GSE_HEADER_SINGLE_PACKET_3BYTE_LABEL, None).unwrap();
438 assert_eq!(
439 format!("{}", header),
440 "GSE Header (S = true, E = true, LT = 3 byte label, \
441 GSE Length = 92 bytes, Protocol Type = 0x0800, \
442 Label = 55:4c:4b)"
443 );
444 assert!(header.start());
445 assert!(header.end());
446 assert!(header.is_single_fragment());
447 assert_eq!(header.label_type(), LabelType::Label3Byte);
448 assert_eq!(header.gse_length(), 92);
449 assert_eq!(header.fragment_id(), None);
450 assert_eq!(header.total_length(), None);
451 assert_eq!(header.protocol_type(), Some(0x0800));
452 let label = header.label().unwrap();
453 assert_eq!(label.as_slice(), &GSE_HEADER_SINGLE_PACKET_3BYTE_LABEL[4..]);
454 assert_eq!(label.len(), 3);
455 assert!(!label.is_empty());
456 assert_eq!(header.len(), GSE_HEADER_SINGLE_PACKET_3BYTE_LABEL.len());
457 assert!(!header.is_empty());
458 }
459
460 const GSE_HEADER_SINGLE_PACKET_BROADCAST_LABEL: [u8; 4] = hex!("e0 5c 08 00");
461
462 #[test]
463 fn single_packet_broadcast_label() {
464 let header =
465 GSEHeader::from_slice(&GSE_HEADER_SINGLE_PACKET_BROADCAST_LABEL, None).unwrap();
466 assert_eq!(
467 format!("{}", header),
468 "GSE Header (S = true, E = true, LT = broadcast label, \
469 GSE Length = 92 bytes, Protocol Type = 0x0800, Label = broadcast)"
470 );
471 assert!(header.start());
472 assert!(header.end());
473 assert!(header.is_single_fragment());
474 assert_eq!(header.label_type(), LabelType::Broadcast);
475 assert_eq!(header.gse_length(), 92);
476 assert_eq!(header.fragment_id(), None);
477 assert_eq!(header.total_length(), None);
478 assert_eq!(header.protocol_type(), Some(0x0800));
479 let label = header.label().unwrap();
480 assert_eq!(label.as_slice(), &[]);
481 assert_eq!(label.len(), 0);
482 assert!(label.is_empty());
483 assert_eq!(header.len(), GSE_HEADER_SINGLE_PACKET_BROADCAST_LABEL.len());
484 assert!(!header.is_empty());
485 }
486
487 const GSE_HEADER_SINGLE_PACKET_LABEL_REUSE: [u8; 4] = hex!("f0 5c 08 00");
488
489 #[test]
490 fn single_packet_label_reuse() {
491 let g0 = GSEHeader::from_slice(&GSE_HEADER_SINGLE_PACKET, None).unwrap();
492 let re_used_label = g0.label().unwrap();
493 let header =
494 GSEHeader::from_slice(&GSE_HEADER_SINGLE_PACKET_LABEL_REUSE, Some(re_used_label))
495 .unwrap();
496 assert_eq!(
497 format!("{}", header),
498 "GSE Header (S = true, E = true, LT = label re-use, \
499 GSE Length = 92 bytes, Protocol Type = 0x0800, \
500 Label = 02:00:48:55:4c:4b)"
501 );
502 assert!(header.start());
503 assert!(header.end());
504 assert!(header.is_single_fragment());
505 assert_eq!(header.label_type(), LabelType::ReUse);
506 assert_eq!(header.gse_length(), 92);
507 assert_eq!(header.fragment_id(), None);
508 assert_eq!(header.total_length(), None);
509 assert_eq!(header.protocol_type(), Some(0x0800));
510 let label = header.label().unwrap();
511 assert_eq!(label, re_used_label);
512 assert_eq!(header.len(), GSE_HEADER_SINGLE_PACKET_LABEL_REUSE.len());
513 assert!(!header.is_empty());
514 }
515
516 #[test]
517 fn padding_packet() {
518 assert_eq!(GSEHeader::from_slice(&[0; 2], None), None);
519 }
520}
521
522#[cfg(test)]
523mod proptests {
524 use super::*;
525 use proptest::prelude::*;
526
527 proptest! {
528 #[test]
529 fn random_header(header in proptest::collection::vec(any::<u8>(), 0..=32)) {
530 if let Some(header) = GSEHeader::from_slice(&header, None) {
531 let _ = format!("{}", header);
532 header.start();
533 header.end();
534 header.is_single_fragment();
535 header.label_type();
536 header.gse_length();
537 header.fragment_id();
538 header.total_length();
539 header.protocol_type();
540 if let Some(label) = header.label() {
541 label.as_slice();
542 let len = label.len();
543 assert_eq!(label.is_empty(), len == 0);
544 }
545 assert!(header.len() >= 3);
546 assert!(!header.is_empty());
547 }
548 }
549 }
550}