Skip to main content

dvb_gse/
gseheader.rs

1//! DVB GSE (Generic Stream Encapsulation) Header.
2//!
3//! The GSE Header is a variable-length header at the start of every GSE
4//! Packet. See Section 4.2 in
5//! [TS 102 606-1](https://www.etsi.org/deliver/etsi_ts/102600_102699/10260601/01.02.01_60/ts_10260601v010201p.pdf).
6
7use super::BitSlice;
8use bitvec::prelude::*;
9use num_enum::TryFromPrimitive;
10use std::fmt::{Display, Formatter};
11use thiserror::Error;
12
13/// GSE Header.
14///
15/// This structure stores the parsed field values from a GSE Header.
16#[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    /// Creates a GSE Header by parsing the values in a slice.
30    ///
31    /// On success, the GSE Header is returned.
32    ///
33    /// If the slice is not long enough to fully contain the GSE Header, `None`
34    /// is returned. Since GSE Headers are variable-length, whether this
35    /// function returns `None` or not can depend on the values at the beginning
36    /// of the slice, in addition to its length.
37    ///
38    /// Additionally, `None` is returned if the header corresponds to padding
39    /// bytes (i.e., if the contents of its fixed fields are all zero).
40    ///
41    /// In order to fully parse a GSE Header, due to the concept of "label
42    /// re-use", it is necessary to know the label of a previous GSE Header in
43    /// the same BBFRAME. This can be provided in the `re_used_label`
44    /// parameter. If this parameter is `None` and a GSE Header with START = 1
45    /// and label re-use is found in the slice, then this function fails,
46    /// returning `None`.
47    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            // This header corresponds to padding bytes
58            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    /// Gives the value of the Start Indicator field.
131    pub fn start(&self) -> bool {
132        self.start
133    }
134
135    /// Gives the value of the End Indicator field.
136    pub fn end(&self) -> bool {
137        self.end
138    }
139
140    /// Returns `true` if the GSE Packet is not fragmented.
141    ///
142    /// A GSE Packet is not fragmented if both its Start Indicator and its End
143    /// Indicator contain `true`.
144    pub fn is_single_fragment(&self) -> bool {
145        self.start() && self.end()
146    }
147
148    /// Gives the value Label Type Indicator field.
149    pub fn label_type(&self) -> LabelType {
150        self.label_type
151    }
152
153    /// Gives the value of the GSE Length field.
154    pub fn gse_length(&self) -> u16 {
155        self.gse_length
156    }
157
158    /// Gives the value of the Fragment ID field, if present.
159    pub fn fragment_id(&self) -> Option<u8> {
160        self.frag_id
161    }
162
163    /// Gives the value of the Total Length field, if present.
164    pub fn total_length(&self) -> Option<u16> {
165        self.total_length
166    }
167
168    /// Gives the value of the Protocol Type field, if present.
169    pub fn protocol_type(&self) -> Option<u16> {
170        self.protocol_type
171    }
172
173    /// Gives the value of the Label field, if present.
174    pub fn label(&self) -> Option<&Label> {
175        self.label.as_ref()
176    }
177
178    /// Gives the length in bytes of the GSE Header.
179    pub fn len(&self) -> usize {
180        let mut len = 2; // fixed length
181        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        // When the label type is re-use, the GSEHeader struct contains a label,
191        // but this was not transmitted over-the-air in the header, so we should
192        // not add the length of the label.
193        if !matches!(self.label_type, LabelType::ReUse)
194            && let Some(label) = &self.label
195        {
196            len += label.len();
197        }
198        len
199    }
200
201    /// Returns `true` if the GSE Header has a length of zero bytes.
202    ///
203    /// This always returns `false`, since a GSE Header never has a length of
204    /// zero bytes. This function exists because objects that implement a `len`
205    /// method should also implement an `is_empty` method.
206    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/// GSE Label.
235///
236/// GSE Labels are used for address filtering in the receiver. GSE supports
237/// three kinds of labels: a 6-byte label (as an Ethernet MAC address), a 3-byte
238/// label, and a broadcast label, which is empty.
239#[derive(Debug, Clone, Eq)]
240pub struct Label {
241    data: [u8; 6],
242    size: LabelSize,
243}
244
245impl Label {
246    /// Returns the broadcast (empty) label.
247    pub fn broadcast() -> Label {
248        Label {
249            data: [0; 6],
250            size: LabelSize::Zero,
251        }
252    }
253
254    /// Gives a slice containing the label data.
255    pub fn as_slice(&self) -> &[u8] {
256        &self.data[..self.len()]
257    }
258
259    /// Gives the length of the label in bytes.
260    pub fn len(&self) -> usize {
261        self.size.len()
262    }
263
264    /// Returns `true` if the label is the broadcast (empty) label.
265    pub fn is_broadcast(&self) -> bool {
266        self.is_empty()
267    }
268
269    /// Returns `true` if the label has a length of zero bytes.
270    ///
271    /// This function returns `true` if the label is the broadcast label.
272    pub fn is_empty(&self) -> bool {
273        matches!(self.size, LabelSize::Zero)
274    }
275
276    /// Parses a 3-byte or 6-byte label given in hex.
277    ///
278    /// The format for the label is either `ab:cd:ef` or `01:23:45:ab:cd:ef`.
279    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                // too long
285                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/// Label parse error.
303#[derive(Error, Debug, Copy, Clone, Eq, PartialEq, Hash)]
304pub enum LabelParseErr {
305    /// Wrong hex format for label.
306    #[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/// Label Type field values.
340#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, TryFromPrimitive)]
341#[repr(u8)]
342pub enum LabelType {
343    /// 6-byte label.
344    Label6Byte = 0b00,
345    /// 3-byte label.
346    Label3Byte = 0b01,
347    /// Broadcast label.
348    Broadcast = 0b10,
349    /// Label re-use.
350    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}