• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::*;
2 use core::slice::from_raw_parts;
3 
4 /// A slice containing an double vlan header of a network package.
5 #[derive(Clone, Debug, Eq, PartialEq)]
6 pub struct DoubleVlanHeaderSlice<'a> {
7     pub(crate) slice: &'a [u8],
8 }
9 
10 impl<'a> DoubleVlanHeaderSlice<'a> {
11     /// Creates a double header slice from a slice.
from_slice( slice: &'a [u8], ) -> Result<DoubleVlanHeaderSlice<'a>, err::double_vlan::HeaderSliceError>12     pub fn from_slice(
13         slice: &'a [u8],
14     ) -> Result<DoubleVlanHeaderSlice<'a>, err::double_vlan::HeaderSliceError> {
15         use err::double_vlan::{HeaderError::*, HeaderSliceError::*};
16 
17         // check length
18         if slice.len() < DoubleVlanHeader::LEN {
19             return Err(Len(err::LenError {
20                 required_len: DoubleVlanHeader::LEN,
21                 len: slice.len(),
22                 len_source: LenSource::Slice,
23                 layer: err::Layer::VlanHeader,
24                 layer_start_offset: 0,
25             }));
26         }
27 
28         // create slice
29         let result = DoubleVlanHeaderSlice {
30             // SAFETY:
31             // Safe as the slice length is checked is before to have
32             // at least the length of DoubleVlanHeader::LEN (8)
33             slice: unsafe { from_raw_parts(slice.as_ptr(), DoubleVlanHeader::LEN) },
34         };
35 
36         use ether_type::*;
37 
38         //check that outer ethertype is matching
39         match result.outer().ether_type() {
40             VLAN_TAGGED_FRAME | PROVIDER_BRIDGING | VLAN_DOUBLE_TAGGED_FRAME => {
41                 //all done
42                 Ok(result)
43             }
44             value => Err(Content(NonVlanEtherType {
45                 unexpected_ether_type: value,
46             })),
47         }
48     }
49 
50     /// Returns the slice containing the double vlan header
51     #[inline]
slice(&self) -> &'a [u8]52     pub fn slice(&self) -> &'a [u8] {
53         self.slice
54     }
55 
56     /// Returns a slice with the outer vlan header
57     #[inline]
outer(&self) -> SingleVlanHeaderSlice<'a>58     pub fn outer(&self) -> SingleVlanHeaderSlice<'a> {
59         // SAFETY:
60         // Safe as the constructor checks that the slice has the length
61         // of DoubleVlanHeader::LEN (8) and the
62         // SingleVlanHeader::LEN has a size of 4.
63         unsafe {
64             SingleVlanHeaderSlice::from_slice_unchecked(from_raw_parts(
65                 self.slice.as_ptr(),
66                 SingleVlanHeader::LEN,
67             ))
68         }
69     }
70 
71     /// Returns a slice with the inner vlan header.
72     #[inline]
inner(&self) -> SingleVlanHeaderSlice<'a>73     pub fn inner(&self) -> SingleVlanHeaderSlice<'a> {
74         // SAFETY:
75         // Safe as the constructor checks that the slice has the length
76         // of DoubleVlanHeader::LEN (8) and the
77         // SingleVlanHeader::LEN has a size of 4.
78         unsafe {
79             SingleVlanHeaderSlice::from_slice_unchecked(from_raw_parts(
80                 self.slice.as_ptr().add(SingleVlanHeader::LEN),
81                 SingleVlanHeader::LEN,
82             ))
83         }
84     }
85 
86     /// Decode all the fields and copy the results to a DoubleVlanHeader struct
to_header(&self) -> DoubleVlanHeader87     pub fn to_header(&self) -> DoubleVlanHeader {
88         DoubleVlanHeader {
89             outer: self.outer().to_header(),
90             inner: self.inner().to_header(),
91         }
92     }
93 }
94 
95 #[cfg(test)]
96 mod test {
97     use crate::{test_gens::*, *};
98     use alloc::{format, vec::Vec};
99     use proptest::prelude::*;
100 
101     proptest! {
102         #[test]
103         fn from_slice(
104             input in vlan_double_any(),
105             dummy_data in proptest::collection::vec(any::<u8>(), 0..20),
106             ether_type_non_vlan in ether_type_any().prop_filter(
107                 "ether_type must not be a vlan ether type",
108                 |v| !VlanHeader::VLAN_ETHER_TYPES.iter().any(|&x| v == &x)
109             )
110         ) {
111             use err::double_vlan::{HeaderError::*, HeaderSliceError::*};
112             {
113                 // serialize
114                 let mut buffer: Vec<u8> = Vec::with_capacity(input.header_len() + dummy_data.len());
115                 input.write(&mut buffer).unwrap();
116                 buffer.extend(&dummy_data[..]);
117 
118                 // normal
119                 {
120                     let slice = DoubleVlanHeaderSlice::from_slice(&buffer).unwrap();
121                     assert_eq!(slice.slice(), &buffer[..8]);
122                 }
123 
124                 // slice length to small
125                 for len in 0..8 {
126                     assert_eq!(
127                         DoubleVlanHeaderSlice::from_slice(&buffer[..len])
128                             .unwrap_err(),
129 
130                         Len(err::LenError{
131                             required_len: 8,
132                             len: len,
133                             len_source: LenSource::Slice,
134                             layer: err::Layer::VlanHeader,
135                             layer_start_offset: 0,
136                         })
137                     );
138                 }
139             }
140 
141             // bad outer ether type
142             {
143                 let mut bad_outer = input.clone();
144                 bad_outer.outer.ether_type = ether_type_non_vlan;
145                 assert_eq!(
146                     DoubleVlanHeaderSlice::from_slice(&bad_outer.to_bytes())
147                         .unwrap_err(),
148                     Content(NonVlanEtherType{ unexpected_ether_type: ether_type_non_vlan })
149                 );
150             }
151         }
152     }
153 
154     proptest! {
155         #[test]
156         fn getters(input in vlan_double_any()) {
157             let bytes = input.to_bytes();
158             let slice = DoubleVlanHeaderSlice::from_slice(&bytes).unwrap();
159 
160             assert_eq!(input.outer, slice.outer().to_header());
161             assert_eq!(input.inner, slice.inner().to_header());
162         }
163     }
164 
165     proptest! {
166         #[test]
167         fn to_header(input in vlan_double_any()) {
168             let bytes = input.to_bytes();
169             let slice = DoubleVlanHeaderSlice::from_slice(&bytes).unwrap();
170 
171             assert_eq!(
172                 DoubleVlanHeader{
173                     outer: input.outer,
174                     inner: input.inner,
175                 },
176                 slice.to_header()
177             );
178         }
179     }
180 
181     proptest! {
182         #[test]
183         fn clone_eq(input in vlan_double_any()) {
184             let bytes = input.to_bytes();
185             let slice = DoubleVlanHeaderSlice::from_slice(&bytes).unwrap();
186             assert_eq!(slice, slice.clone());
187         }
188     }
189 
190     proptest! {
191         #[test]
192         fn dbg(input in vlan_double_any()) {
193             let bytes = input.to_bytes();
194             let slice = DoubleVlanHeaderSlice::from_slice(&bytes).unwrap();
195             assert_eq!(
196                 &format!(
197                     "DoubleVlanHeaderSlice {{ slice: {:?} }}",
198                     slice.slice(),
199                 ),
200                 &format!("{:?}", slice)
201             );
202         }
203     }
204 }
205