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};
11
12/// GSE Header.
13///
14/// This structure stores the parsed field values from a GSE Header.
15#[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    /// Creates a GSE Header by parsing the values in a slice.
29    ///
30    /// On success, the GSE Header is returned.
31    ///
32    /// If the slice is not long enough to fully contain the GSE Header, `None`
33    /// is returned. Since GSE Headers are variable-length, whether this
34    /// function returns `None` or not can depend on the values at the beginning
35    /// of the slice, in addition to its length.
36    ///
37    /// Additionally, `None` is returned if the header corresponds to padding
38    /// bytes (i.e., if the contents of its fixed fields are all zero).
39    ///
40    /// In order to fully parse a GSE Header, due to the concept of "label
41    /// re-use", it is necessary to know the label of a previous GSE Header in
42    /// the same BBFRAME. This can be provided in the `re_used_label`
43    /// parameter. If this parameter is `None` and a GSE Header with START = 1
44    /// and label re-use is found in the slice, then this function fails,
45    /// returning `None`.
46    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            // This header corresponds to padding bytes
57            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    /// Gives the value of the Start Indicator field.
130    pub fn start(&self) -> bool {
131        self.start
132    }
133
134    /// Gives the value of the End Indicator field.
135    pub fn end(&self) -> bool {
136        self.end
137    }
138
139    /// Returns `true` if the GSE Packet is not fragmented.
140    ///
141    /// A GSE Packet is not fragmented if both its Start Indicator and its End
142    /// Indicator contain `true`.
143    pub fn is_single_fragment(&self) -> bool {
144        self.start() && self.end()
145    }
146
147    /// Gives the value Label Type Indicator field.
148    pub fn label_type(&self) -> LabelType {
149        self.label_type
150    }
151
152    /// Gives the value of the GSE Length field.
153    pub fn gse_length(&self) -> u16 {
154        self.gse_length
155    }
156
157    /// Gives the value of the Fragment ID field, if present.
158    pub fn fragment_id(&self) -> Option<u8> {
159        self.frag_id
160    }
161
162    /// Gives the value of the Total Length field, if present.
163    pub fn total_length(&self) -> Option<u16> {
164        self.total_length
165    }
166
167    /// Gives the value of the Protocol Type field, if present.
168    pub fn protocol_type(&self) -> Option<u16> {
169        self.protocol_type
170    }
171
172    /// Gives the value of the Label field, if present.
173    pub fn label(&self) -> Option<&Label> {
174        self.label.as_ref()
175    }
176
177    /// Gives the length in bytes of the GSE Header.
178    pub fn len(&self) -> usize {
179        let mut len = 2; // fixed length
180        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        // When the label type is re-use, the GSEHeader struct contains a label,
190        // but this was not transmitted over-the-air in the header, so we should
191        // not add the length of the label.
192        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    /// Returns `true` if the GSE Header has a length of zero bytes.
201    ///
202    /// This always returns `false`, since a GSE Header never has a length of
203    /// zero bytes. This function exists because objects that implement a `len`
204    /// method should also implement an `is_empty` method.
205    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/// GSE Label.
234///
235/// GSE Labels are used for address filtering in the receiver. GSE supports
236/// three kinds of labels: a 6-byte label (as an Ethernet MAC address), a 3-byte
237/// label, and a broadcast label, which is empty.
238#[derive(Debug, Clone, Eq, PartialEq, Hash)]
239pub struct Label {
240    data: [u8; 6],
241    size: LabelSize,
242}
243
244impl Label {
245    /// Gives a slice containing the label data.
246    pub fn as_slice(&self) -> &[u8] {
247        &self.data[..self.len()]
248    }
249
250    /// Gives the length of the label in bytes.
251    pub fn len(&self) -> usize {
252        self.size.len()
253    }
254
255    /// Returns `true` if the label has a length of zero bytes.
256    ///
257    /// This function returns `true` if the label is the broadcast label.
258    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/// Label Type field values.
278#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, TryFromPrimitive)]
279#[repr(u8)]
280pub enum LabelType {
281    /// 6-byte label.
282    Label6Byte = 0b00,
283    /// 3-byte label.
284    Label3Byte = 0b01,
285    /// Broadcast label.
286    Broadcast = 0b10,
287    /// Label re-use.
288    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}