etherparse/link/
double_vlan_slice.rs

1use crate::*;
2
3/// Two IEEE 802.1Q VLAN Tagging headers & payload slices (helper
4/// struct to check vlan tagging values in a [crate::`SlicedPacket`]).
5///
6/// Note that it is NOT guaranteed that the two VLAN headers directly
7/// followed each other in the original packet. In the original packet
8/// there could be another LinkExt header present in between them (e.g.
9/// a MacSec Security Tag).
10#[derive(Clone, Eq, PartialEq)]
11pub struct DoubleVlanSlice<'a> {
12    /// Outer VLAN header & payload (should include the header of inner vlan header
13    /// and potentially additional link extension headers (e.g. MacSec) in between).
14    pub outer: SingleVlanSlice<'a>,
15    /// Inner VLAN header & payload.
16    pub inner: SingleVlanSlice<'a>,
17}
18
19impl<'a> DoubleVlanSlice<'a> {
20    /// Decode all the fields and copy the results to a DoubleVlanHeader struct
21    #[inline]
22    pub fn to_header(&self) -> DoubleVlanHeader {
23        DoubleVlanHeader {
24            outer: self.outer.to_header(),
25            inner: self.inner.to_header(),
26        }
27    }
28
29    /// Returns the slice containing the payload & ether type
30    /// identifying it's content type after bother VLAN headers.
31    #[inline]
32    pub fn payload(&self) -> EtherPayloadSlice<'a> {
33        self.inner.payload()
34    }
35
36    /// Returns the slice containing the payload after both
37    /// VLAN headers.
38    pub fn payload_slice(&self) -> &'a [u8] {
39        self.inner.payload_slice()
40    }
41}
42
43impl core::fmt::Debug for DoubleVlanSlice<'_> {
44    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
45        f.debug_struct("DoubleVlanSlice")
46            .field("outer", &self.outer.to_header())
47            .field("inner", &self.inner.to_header())
48            .field("payload", &self.payload())
49            .finish()
50    }
51}
52
53#[cfg(test)]
54mod test {
55    use super::*;
56    use crate::test_gens::*;
57    use alloc::{format, vec::Vec};
58    use proptest::prelude::*;
59
60    proptest! {
61        #[test]
62        fn debug_clone_eq(
63            vlan in vlan_double_any()
64        ) {
65            let payload: [u8;8] = [1,2,3,4,5,6,7,8];
66            let mut data = Vec::with_capacity(
67                vlan.outer.header_len() +
68                vlan.inner.header_len() +
69                payload.len()
70            );
71            data.extend_from_slice(&vlan.outer.to_bytes());
72            data.extend_from_slice(&vlan.inner.to_bytes());
73            data.extend_from_slice(&payload);
74
75            // decode packet
76            let slice = DoubleVlanSlice{
77                outer: SingleVlanSlice::from_slice(&data).unwrap(),
78                inner: SingleVlanSlice::from_slice(&data[SingleVlanHeader::LEN..]).unwrap(),
79            };
80
81            // check debug output
82            prop_assert_eq!(
83                format!("{:?}", slice),
84                format!(
85                    "DoubleVlanSlice {{ outer: {:?}, inner: {:?}, payload: {:?} }}",
86                    slice.outer.to_header(),
87                    slice.inner.to_header(),
88                    slice.payload(),
89                )
90            );
91            prop_assert_eq!(slice.clone(), slice);
92        }
93    }
94
95    proptest! {
96        #[test]
97        fn getters(vlan in vlan_double_any()) {
98            let payload: [u8;8] = [1,2,3,4,5,6,7,8];
99            let mut data = Vec::with_capacity(
100                vlan.outer.header_len() +
101                vlan.inner.header_len() +
102                payload.len()
103            );
104            data.extend_from_slice(&vlan.outer.to_bytes());
105            data.extend_from_slice(&vlan.inner.to_bytes());
106            data.extend_from_slice(&payload);
107
108            let slice = DoubleVlanSlice{
109                outer: SingleVlanSlice::from_slice(&data).unwrap(),
110                inner: SingleVlanSlice::from_slice(&data[SingleVlanHeader::LEN..]).unwrap(),
111            };
112            assert_eq!(&data, slice.outer.slice());
113            assert_eq!(vlan.outer, slice.outer.to_header());
114            assert_eq!(&data[SingleVlanHeader::LEN..], slice.inner.slice());
115            assert_eq!(vlan.inner, slice.inner.to_header());
116            assert_eq!(vlan, slice.to_header());
117            assert_eq!(
118                EtherPayloadSlice{
119                    ether_type: vlan.inner.ether_type,
120                    len_source: LenSource::Slice,
121                    payload: &payload,
122                },
123                slice.payload()
124            );
125            assert_eq!(&payload, slice.payload_slice());
126        }
127    }
128}