1 use crate::{err::*, *}; 2 3 /// Slice containing an Ethernet 2 headers & payload. 4 #[derive(Clone, Eq, PartialEq)] 5 pub struct Ethernet2Slice<'a> { 6 fcs_len: usize, 7 slice: &'a [u8], 8 } 9 10 impl<'a> Ethernet2Slice<'a> { 11 /// Try creating a [`Ethernet2Slice`] from a slice containing the 12 /// Ethernet 2 header & payload WITHOUT an FCS (frame check sequence) 13 /// at the end. from_slice_without_fcs(slice: &'a [u8]) -> Result<Ethernet2Slice<'a>, LenError>14 pub fn from_slice_without_fcs(slice: &'a [u8]) -> Result<Ethernet2Slice<'a>, LenError> { 15 // check length 16 if slice.len() < Ethernet2Header::LEN { 17 return Err(LenError { 18 required_len: Ethernet2Header::LEN, 19 len: slice.len(), 20 len_source: LenSource::Slice, 21 layer: Layer::Ethernet2Header, 22 layer_start_offset: 0, 23 }); 24 } 25 26 Ok(Ethernet2Slice { fcs_len: 0, slice }) 27 } 28 29 /// Try creating a [`Ethernet2Slice`] from a slice containing the 30 /// Ethernet 2 header & payload with a CRC 32 bit FCS (frame 31 /// check sequence) at the end. 32 /// 33 /// In case you are not sure if your ethernet2 frame has a FCS or not 34 /// use [`Ethernet2Slice::from_slice_without_fcs`] instead and rely on the 35 /// lower layers (e.g. IP) to determine the correct payload length. from_slice_with_crc32_fcs(slice: &'a [u8]) -> Result<Ethernet2Slice<'a>, LenError>36 pub fn from_slice_with_crc32_fcs(slice: &'a [u8]) -> Result<Ethernet2Slice<'a>, LenError> { 37 // check length 38 let fcs_len = 4; 39 if slice.len() < Ethernet2Header::LEN + fcs_len { 40 return Err(LenError { 41 required_len: Ethernet2Header::LEN + 4, 42 len: slice.len(), 43 len_source: LenSource::Slice, 44 layer: Layer::Ethernet2Header, 45 layer_start_offset: 0, 46 }); 47 } 48 49 Ok(Ethernet2Slice { fcs_len, slice }) 50 } 51 52 /// Returns the slice containing the ethernet 2 header 53 /// payload and FCS if present. 54 #[inline] slice(&self) -> &'a [u8]55 pub fn slice(&self) -> &'a [u8] { 56 self.slice 57 } 58 59 /// Read the destination MAC address 60 #[inline] destination(&self) -> [u8; 6]61 pub fn destination(&self) -> [u8; 6] { 62 // SAFETY: 63 // Safe as the contructor checks that the slice has 64 // at least the length of Ethernet2Header::LEN (14). 65 unsafe { get_unchecked_6_byte_array(self.slice.as_ptr()) } 66 } 67 68 /// Read the source MAC address 69 #[inline] source(&self) -> [u8; 6]70 pub fn source(&self) -> [u8; 6] { 71 // SAFETY: 72 // Safe as the contructor checks that the slice has 73 // at least the length of Ethernet2Header::LEN (14). 74 unsafe { get_unchecked_6_byte_array(self.slice.as_ptr().add(6)) } 75 } 76 77 /// Read the ether_type field of the header indicating the protocol 78 /// after the header. 79 #[inline] ether_type(&self) -> EtherType80 pub fn ether_type(&self) -> EtherType { 81 // SAFETY: 82 // Safe as the contructor checks that the slice has 83 // at least the length of Ethernet2Header::LEN (14). 84 EtherType(unsafe { get_unchecked_be_u16(self.slice.as_ptr().add(12)) }) 85 } 86 87 /// Returns the frame check sequence if present. 88 #[inline] fcs(&self) -> Option<[u8; 4]>89 pub fn fcs(&self) -> Option<[u8; 4]> { 90 if self.fcs_len == 4 { 91 // SAFETY: Safe as the slice length was verified 92 // to be at least Ethernet2Header::LEN + fcs_len by 93 // "from_slice_without_fcs" & "from_slice_with_crc32_fcs". 94 Some(unsafe { 95 [ 96 *self.slice.as_ptr().add(self.slice.len() - 4), 97 *self.slice.as_ptr().add(self.slice.len() - 3), 98 *self.slice.as_ptr().add(self.slice.len() - 2), 99 *self.slice.as_ptr().add(self.slice.len() - 1), 100 ] 101 }) 102 } else { 103 None 104 } 105 } 106 107 /// Decode all the fields and copy the results to a [`Ethernet2Header`] struct to_header(&self) -> Ethernet2Header108 pub fn to_header(&self) -> Ethernet2Header { 109 Ethernet2Header { 110 source: self.source(), 111 destination: self.destination(), 112 ether_type: self.ether_type(), 113 } 114 } 115 116 /// Slice containing the Ethernet 2 header. header_slice(&self) -> &[u8]117 pub fn header_slice(&self) -> &[u8] { 118 unsafe { 119 // SAFETY: 120 // Safe as the contructor checks that the slice has 121 // at least the length of Ethernet2Header::LEN (14). 122 core::slice::from_raw_parts(self.slice.as_ptr(), Ethernet2Header::LEN) 123 } 124 } 125 126 /// Returns the slice containing the Ethernet II payload & ether type 127 /// identifying it's content type. 128 #[inline] payload(&self) -> EtherPayloadSlice<'a>129 pub fn payload(&self) -> EtherPayloadSlice<'a> { 130 EtherPayloadSlice { 131 ether_type: self.ether_type(), 132 payload: self.payload_slice(), 133 } 134 } 135 136 /// Returns the slice containing the Ethernet II payload. 137 #[inline] payload_slice(&self) -> &'a [u8]138 pub fn payload_slice(&self) -> &'a [u8] { 139 unsafe { 140 // SAFETY: Safe as the slice length was verified 141 // to be at least Ethernet2Header::LEN + fcs_len by 142 // "from_slice_without_fcs" & "from_slice_with_crc32_fcs". 143 core::slice::from_raw_parts( 144 self.slice.as_ptr().add(Ethernet2Header::LEN), 145 self.slice.len() - Ethernet2Header::LEN - self.fcs_len, 146 ) 147 } 148 } 149 150 /// Length of the Ethernet 2 header in bytes (equal to 151 /// [`crate::Ethernet2Header::LEN`]). 152 #[inline] header_len(&self) -> usize153 pub const fn header_len(&self) -> usize { 154 Ethernet2Header::LEN 155 } 156 } 157 158 impl core::fmt::Debug for Ethernet2Slice<'_> { fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result159 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 160 f.debug_struct("Ethernet2Slice") 161 .field("header", &self.to_header()) 162 .field("payload", &self.payload()) 163 .field("fcs", &self.fcs()) 164 .finish() 165 } 166 } 167 168 #[cfg(test)] 169 mod test { 170 use super::*; 171 use crate::test_gens::*; 172 use alloc::{format, vec::Vec}; 173 use proptest::prelude::*; 174 175 proptest! { 176 #[test] 177 fn debug_clone_eq( 178 eth in ethernet_2_any(), 179 has_fcs in any::<bool>() 180 ) { 181 let payload: [u8;8] = [1,2,3,4,5,6,7,8]; 182 let mut data = Vec::with_capacity( 183 eth.header_len() + 184 payload.len() 185 ); 186 data.extend_from_slice(ð.to_bytes()); 187 data.extend_from_slice(&payload); 188 189 // decode packet 190 let slice = if has_fcs { 191 Ethernet2Slice::from_slice_with_crc32_fcs(&data).unwrap() 192 } else { 193 Ethernet2Slice::from_slice_without_fcs(&data).unwrap() 194 }; 195 196 // check debug output 197 prop_assert_eq!( 198 format!("{:?}", slice), 199 format!( 200 "Ethernet2Slice {{ header: {:?}, payload: {:?}, fcs: {:?} }}", 201 slice.to_header(), 202 slice.payload(), 203 slice.fcs() 204 ) 205 ); 206 prop_assert_eq!(slice.clone(), slice); 207 } 208 } 209 210 proptest! { 211 #[test] 212 fn getters(eth in ethernet_2_any()) { 213 let payload: [u8;8] = [1,2,3,4,5,6,7,8]; 214 let mut data = Vec::with_capacity( 215 eth.header_len() + 216 payload.len() 217 ); 218 data.extend_from_slice(ð.to_bytes()); 219 data.extend_from_slice(&payload); 220 221 // without fcs 222 { 223 let slice = Ethernet2Slice::from_slice_without_fcs(&data).unwrap(); 224 assert_eq!(eth.destination, slice.destination()); 225 assert_eq!(eth.source, slice.source()); 226 assert_eq!(eth.ether_type, slice.ether_type()); 227 assert_eq!(&payload, slice.payload_slice()); 228 assert_eq!( 229 EtherPayloadSlice{ 230 payload: &payload, 231 ether_type: eth.ether_type, 232 }, 233 slice.payload() 234 ); 235 assert_eq!(None, slice.fcs()); 236 assert_eq!(eth, slice.to_header()); 237 assert_eq!(&data, slice.slice()); 238 assert_eq!(&data[..Ethernet2Header::LEN], slice.header_slice()); 239 } 240 // with fcs 241 { 242 let slice = Ethernet2Slice::from_slice_with_crc32_fcs(&data).unwrap(); 243 assert_eq!(eth.destination, slice.destination()); 244 assert_eq!(eth.source, slice.source()); 245 assert_eq!(eth.ether_type, slice.ether_type()); 246 assert_eq!(&payload[..payload.len() - 4], slice.payload_slice()); 247 assert_eq!( 248 EtherPayloadSlice{ 249 payload: &payload[..payload.len() - 4], 250 ether_type: eth.ether_type, 251 }, 252 slice.payload() 253 ); 254 assert_eq!(Some([5, 6, 7, 8]), slice.fcs()); 255 assert_eq!(eth, slice.to_header()); 256 assert_eq!(&data, slice.slice()); 257 assert_eq!(&data[..Ethernet2Header::LEN], slice.header_slice()); 258 } 259 } 260 } 261 262 proptest! { 263 #[test] 264 fn from_slice_without_fcs(eth in ethernet_2_any()) { 265 266 let payload: [u8;10] = [1,2,3,4,5,6,7,8,9,10]; 267 let data = { 268 let mut data = Vec::with_capacity( 269 eth.header_len() + 270 payload.len() 271 ); 272 data.extend_from_slice(ð.to_bytes()); 273 data.extend_from_slice(&payload); 274 data 275 }; 276 277 // normal decode 278 { 279 let slice = Ethernet2Slice::from_slice_without_fcs(&data).unwrap(); 280 assert_eq!(slice.to_header(), eth); 281 assert_eq!(slice.payload_slice(), &payload); 282 assert_eq!(slice.fcs(), None); 283 } 284 285 // decode without payload 286 { 287 let slice = Ethernet2Slice::from_slice_without_fcs(&data[..Ethernet2Header::LEN]).unwrap(); 288 assert_eq!(slice.to_header(), eth); 289 assert_eq!(slice.payload_slice(), &[]); 290 assert_eq!(slice.fcs(), None); 291 } 292 293 // length error 294 for len in 0..Ethernet2Header::LEN { 295 assert_eq!( 296 Ethernet2Slice::from_slice_without_fcs(&data[..len]).unwrap_err(), 297 LenError{ 298 required_len: Ethernet2Header::LEN, 299 len, 300 len_source: LenSource::Slice, 301 layer: Layer::Ethernet2Header, 302 layer_start_offset: 0 303 } 304 ); 305 } 306 } 307 } 308 309 proptest! { 310 #[test] 311 fn from_slice_with_crc32_fcs( 312 eth in ethernet_2_any() 313 ) { 314 let payload: [u8;10] = [1,2,3,4,5,6,7,8,9,10]; 315 let fcs: [u8;4] = [11,12,13,14]; 316 let data = { 317 let mut data = Vec::with_capacity( 318 eth.header_len() + 319 payload.len() 320 ); 321 data.extend_from_slice(ð.to_bytes()); 322 data.extend_from_slice(&payload); 323 data.extend_from_slice(&fcs); 324 data 325 }; 326 327 // normal decode 328 { 329 let slice = Ethernet2Slice::from_slice_with_crc32_fcs(&data).unwrap(); 330 assert_eq!(slice.to_header(), eth); 331 assert_eq!(slice.payload_slice(), &payload); 332 assert_eq!(slice.fcs(), Some(fcs)); 333 } 334 335 // decode without payload 336 { 337 let slice = Ethernet2Slice::from_slice_with_crc32_fcs(&data[..Ethernet2Header::LEN + 4]).unwrap(); 338 assert_eq!(slice.to_header(), eth); 339 assert_eq!(slice.payload_slice(), &[]); 340 assert_eq!(slice.fcs(), Some([1,2,3,4])); 341 } 342 343 // length error 344 for len in 0..Ethernet2Header::LEN + 4 { 345 assert_eq!( 346 Ethernet2Slice::from_slice_with_crc32_fcs(&data[..len]).unwrap_err(), 347 LenError{ 348 required_len: Ethernet2Header::LEN + 4, 349 len, 350 len_source: LenSource::Slice, 351 layer: Layer::Ethernet2Header, 352 layer_start_offset: 0 353 } 354 ); 355 } 356 } 357 } 358 } 359