1 use crate::{err::*, *}; 2 3 /// Slice containing a VLAN header & payload. 4 #[derive(Clone, Eq, PartialEq)] 5 pub struct DoubleVlanSlice<'a> { 6 pub(crate) slice: &'a [u8], 7 } 8 9 impl<'a> DoubleVlanSlice<'a> { 10 /// Try creating a [`DoubleVlanSlice`] from a slice containing the 11 /// VLAN header & payload. from_slice( slice: &'a [u8], ) -> Result<DoubleVlanSlice<'a>, err::double_vlan::HeaderSliceError>12 pub fn from_slice( 13 slice: &'a [u8], 14 ) -> Result<DoubleVlanSlice<'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(LenError { 20 required_len: DoubleVlanHeader::LEN, 21 len: slice.len(), 22 len_source: LenSource::Slice, 23 layer: Layer::VlanHeader, 24 layer_start_offset: 0, 25 })); 26 } 27 28 // create slice 29 let result = DoubleVlanSlice { slice }; 30 31 // check that outer ethertype is matching 32 use ether_type::*; 33 match result.outer().ether_type() { 34 VLAN_TAGGED_FRAME | PROVIDER_BRIDGING | VLAN_DOUBLE_TAGGED_FRAME => Ok(result), 35 value => Err(Content(NonVlanEtherType { 36 unexpected_ether_type: value, 37 })), 38 } 39 } 40 41 /// Returns the slice containing the VLAN header and payload. 42 #[inline] slice(&self) -> &'a [u8]43 pub fn slice(&self) -> &'a [u8] { 44 self.slice 45 } 46 47 /// Outer VLAN header & payload (includes header of inner vlan header). 48 #[inline] outer(&self) -> SingleVlanSlice49 pub fn outer(&self) -> SingleVlanSlice { 50 SingleVlanSlice { slice: self.slice } 51 } 52 53 /// Inner VLAN header & payload. 54 #[inline] inner(&self) -> SingleVlanSlice55 pub fn inner(&self) -> SingleVlanSlice { 56 SingleVlanSlice { 57 slice: unsafe { 58 // SAFETY: Safe as "from_slice" verified the slice length 59 // to be DoubleVlanHeader::LEN (aka 2*SingleVlanHeader::LEN). 60 core::slice::from_raw_parts( 61 self.slice.as_ptr().add(SingleVlanHeader::LEN), 62 self.slice.len() - SingleVlanHeader::LEN, 63 ) 64 }, 65 } 66 } 67 68 /// Decode all the fields and copy the results to a DoubleVlanHeader struct 69 #[inline] to_header(&self) -> DoubleVlanHeader70 pub fn to_header(&self) -> DoubleVlanHeader { 71 DoubleVlanHeader { 72 outer: self.outer().to_header(), 73 inner: self.inner().to_header(), 74 } 75 } 76 77 /// Returns the slice containing the payload & ether type 78 /// identifying it's content type after bother VLAN headers. 79 #[inline] payload(&self) -> EtherPayloadSlice<'a>80 pub fn payload(&self) -> EtherPayloadSlice<'a> { 81 EtherPayloadSlice { 82 ether_type: self.inner().ether_type(), 83 payload: self.payload_slice(), 84 } 85 } 86 87 /// Returns the slice containing the payload after both 88 /// VLAN headers. payload_slice(&self) -> &'a [u8]89 pub fn payload_slice(&self) -> &'a [u8] { 90 unsafe { 91 // SAFETY: 92 // Safe as the contructor checks that the slice has 93 // at least the length of DoubleVlanHeader::LEN (8). 94 core::slice::from_raw_parts( 95 self.slice.as_ptr().add(DoubleVlanHeader::LEN), 96 self.slice.len() - DoubleVlanHeader::LEN, 97 ) 98 } 99 } 100 101 /// Length of the VLAN header in bytes (equal to 102 /// [`crate::DoubleVlanHeader::LEN`]). 103 #[inline] header_len(&self) -> usize104 pub const fn header_len(&self) -> usize { 105 DoubleVlanHeader::LEN 106 } 107 } 108 109 impl core::fmt::Debug for DoubleVlanSlice<'_> { fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result110 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 111 f.debug_struct("DoubleVlanSlice") 112 .field("outer", &self.outer().to_header()) 113 .field("inner", &self.inner().to_header()) 114 .field("payload", &self.payload()) 115 .finish() 116 } 117 } 118 119 #[cfg(test)] 120 mod test { 121 use super::*; 122 use crate::test_gens::*; 123 use alloc::{format, vec::Vec}; 124 use proptest::prelude::*; 125 126 proptest! { 127 #[test] 128 fn debug_clone_eq( 129 vlan in vlan_double_any() 130 ) { 131 let payload: [u8;8] = [1,2,3,4,5,6,7,8]; 132 let mut data = Vec::with_capacity( 133 vlan.header_len() + 134 payload.len() 135 ); 136 data.extend_from_slice(&vlan.to_bytes()); 137 data.extend_from_slice(&payload); 138 139 // decode packet 140 let slice = DoubleVlanSlice::from_slice(&data).unwrap(); 141 142 // check debug output 143 prop_assert_eq!( 144 format!("{:?}", slice), 145 format!( 146 "DoubleVlanSlice {{ outer: {:?}, inner: {:?}, payload: {:?} }}", 147 slice.outer().to_header(), 148 slice.inner().to_header(), 149 slice.payload(), 150 ) 151 ); 152 prop_assert_eq!(slice.clone(), slice); 153 } 154 } 155 156 proptest! { 157 #[test] 158 fn getters(vlan in vlan_double_any()) { 159 let payload: [u8;8] = [1,2,3,4,5,6,7,8]; 160 let mut data = Vec::with_capacity( 161 vlan.header_len() + 162 payload.len() 163 ); 164 data.extend_from_slice(&vlan.to_bytes()); 165 data.extend_from_slice(&payload); 166 167 let slice = DoubleVlanSlice::from_slice(&data).unwrap(); 168 assert_eq!(&data, slice.slice()); 169 assert_eq!(&data, slice.outer().slice()); 170 assert_eq!(vlan.outer, slice.outer().to_header()); 171 assert_eq!(&data[SingleVlanHeader::LEN..], slice.inner().slice()); 172 assert_eq!(vlan.inner, slice.inner().to_header()); 173 assert_eq!(vlan, slice.to_header()); 174 assert_eq!( 175 EtherPayloadSlice{ 176 ether_type: vlan.inner.ether_type, 177 payload: &payload 178 }, 179 slice.payload() 180 ); 181 assert_eq!(&payload, slice.payload_slice()); 182 assert_eq!(DoubleVlanHeader::LEN, slice.header_len()); 183 } 184 } 185 186 proptest! { 187 #[test] 188 fn from_slice( 189 vlan in vlan_double_any(), 190 ether_type_non_vlan in ether_type_any().prop_filter( 191 "ether_type must not be a vlan ether type", 192 |v| !VlanHeader::VLAN_ETHER_TYPES.iter().any(|&x| v == &x) 193 ) 194 ) { 195 use err::double_vlan::{HeaderError::*, HeaderSliceError::*}; 196 197 let payload: [u8;10] = [1,2,3,4,5,6,7,8,9,10]; 198 let data = { 199 let mut data = Vec::with_capacity( 200 vlan.header_len() + 201 payload.len() 202 ); 203 data.extend_from_slice(&vlan.to_bytes()); 204 data.extend_from_slice(&payload); 205 data 206 }; 207 208 // normal decode 209 { 210 let slice = DoubleVlanSlice::from_slice(&data).unwrap(); 211 assert_eq!(slice.to_header(), vlan); 212 assert_eq!(slice.payload_slice(), &payload); 213 } 214 215 // length error 216 for len in 0..DoubleVlanHeader::LEN { 217 assert_eq!( 218 DoubleVlanSlice::from_slice(&data[..len]).unwrap_err(), 219 Len(LenError{ 220 required_len: DoubleVlanHeader::LEN, 221 len, 222 len_source: LenSource::Slice, 223 layer: Layer::VlanHeader, 224 layer_start_offset: 0 225 }) 226 ); 227 } 228 229 // mismatching outer ether type 230 { 231 let mut bad_data = data.clone(); 232 let e_be = ether_type_non_vlan.0.to_be_bytes(); 233 bad_data[2] = e_be[0]; 234 bad_data[3] = e_be[1]; 235 assert_eq!( 236 DoubleVlanSlice::from_slice(&bad_data).unwrap_err(), 237 Content(NonVlanEtherType{ 238 unexpected_ether_type: ether_type_non_vlan, 239 }) 240 ); 241 } 242 } 243 } 244 } 245