use crate::{err::Layer, err::SliceWriteSpaceError, *}; /// Ethernet II header. #[derive(Clone, Debug, Eq, PartialEq, Default)] pub struct Ethernet2Header { /// Source MAC Address pub source: [u8; 6], /// Destination MAC Address pub destination: [u8; 6], /// Protocol present after the ethernet2 header. pub ether_type: EtherType, } impl Ethernet2Header { /// Serialized size of an Ethernet2 header in bytes/octets. pub const LEN: usize = 14; /// Deprecated use [`Ethernet2Header::LEN`] instead. #[deprecated(since = "0.14.0", note = "Use `Ethernet2Header::LEN` instead")] pub const SERIALIZED_SIZE: usize = Ethernet2Header::LEN; /// Deprecated use [`Ethernet2Header::from_slice`] instead. #[deprecated(since = "0.10.1", note = "Use Ethernet2Header::from_slice instead.")] #[inline] pub fn read_from_slice(slice: &[u8]) -> Result<(Ethernet2Header, &[u8]), err::LenError> { Ethernet2Header::from_slice(slice) } /// Read an Ethernet2Header from a slice and return the header & unused parts of the slice. #[inline] pub fn from_slice(slice: &[u8]) -> Result<(Ethernet2Header, &[u8]), err::LenError> { Ok(( Ethernet2HeaderSlice::from_slice(slice)?.to_header(), &slice[Ethernet2Header::LEN..], )) } /// Read an Ethernet2Header from a static sized byte array. #[inline] pub fn from_bytes(bytes: [u8; 14]) -> Ethernet2Header { Ethernet2Header { destination: [bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5]], source: [bytes[6], bytes[7], bytes[8], bytes[9], bytes[10], bytes[11]], ether_type: EtherType(u16::from_be_bytes([bytes[12], bytes[13]])), } } /// Reads an Ethernet-II header from the current position of the read argument. #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] pub fn read( reader: &mut T, ) -> Result { let buffer = { let mut buffer = [0; Ethernet2Header::LEN]; reader.read_exact(&mut buffer)?; buffer }; Ok( // SAFETY: Safe as the buffer contains exactly the needed Ethernet2Header::LEN bytes. unsafe { Ethernet2HeaderSlice::from_slice_unchecked(&buffer) }.to_header(), ) } /// Serialize the header to a given slice. Returns the unused part of the slice. pub fn write_to_slice<'a>( &self, slice: &'a mut [u8], ) -> Result<&'a mut [u8], SliceWriteSpaceError> { // length check if slice.len() < Ethernet2Header::LEN { Err(SliceWriteSpaceError { required_len: Ethernet2Header::LEN, len: slice.len(), layer: Layer::Ethernet2Header, layer_start_offset: 0, }) } else { slice[..Ethernet2Header::LEN].copy_from_slice(&self.to_bytes()); Ok(&mut slice[Ethernet2Header::LEN..]) } } /// Writes a given Ethernet-II header to the current position of the write argument. #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] #[inline] pub fn write(&self, writer: &mut T) -> Result<(), std::io::Error> { writer.write_all(&self.to_bytes()) } /// Length of the serialized header in bytes. #[inline] pub fn header_len(&self) -> usize { 14 } /// Returns the serialized form of the header as a statically /// sized byte array. #[inline] pub fn to_bytes(&self) -> [u8; 14] { let ether_type_be = self.ether_type.0.to_be_bytes(); [ self.destination[0], self.destination[1], self.destination[2], self.destination[3], self.destination[4], self.destination[5], self.source[0], self.source[1], self.source[2], self.source[3], self.source[4], self.source[5], ether_type_be[0], ether_type_be[1], ] } } #[cfg(test)] mod test { use super::*; use crate::test_gens::*; use alloc::{format, vec::Vec}; use proptest::prelude::*; use std::io::{Cursor, ErrorKind}; #[test] fn default() { let e: Ethernet2Header = Default::default(); assert_eq!([0u8; 6], e.source); assert_eq!([0u8; 6], e.destination); assert_eq!(EtherType(0), e.ether_type); } proptest! { #[test] fn from_slice( input in ethernet_2_any(), dummy_data in proptest::collection::vec(any::(), 0..20) ) { // serialize let mut buffer: Vec = Vec::with_capacity(14 + dummy_data.len()); input.write(&mut buffer).unwrap(); buffer.extend(&dummy_data[..]); // calls with a valid result { let (result, rest) = Ethernet2Header::from_slice(&buffer[..]).unwrap(); assert_eq!(input, result); assert_eq!(&buffer[14..], rest); } #[allow(deprecated)] { let (result, rest) = Ethernet2Header::read_from_slice(&buffer[..]).unwrap(); assert_eq!(input, result); assert_eq!(&buffer[14..], rest); } // call with not enough data in the slice for len in 0..=13 { assert_eq!( Ethernet2Header::from_slice(&buffer[..len]), Err(err::LenError{ required_len: Ethernet2Header::LEN, len: len, len_source: LenSource::Slice, layer: err::Layer::Ethernet2Header, layer_start_offset: 0, }) ); } } } proptest! { #[test] fn from_bytes(input in ethernet_2_any()) { assert_eq!( input, Ethernet2Header::from_bytes(input.to_bytes()) ); } } proptest! { #[test] fn read( input in ethernet_2_any(), dummy_data in proptest::collection::vec(any::(), 0..20) ) { // normal read let mut buffer = Vec::with_capacity(14 + dummy_data.len()); input.write(&mut buffer).unwrap(); buffer.extend(&dummy_data[..]); // calls with a valid result { let mut cursor = Cursor::new(&buffer); let result = Ethernet2Header::read(&mut cursor).unwrap(); assert_eq!(input, result); assert_eq!(cursor.position(), 14); } // unexpected eof for len in 0..=13 { let mut cursor = Cursor::new(&buffer[0..len]); assert_eq!( Ethernet2Header::read(&mut cursor) .unwrap_err() .kind(), ErrorKind::UnexpectedEof ); } } } proptest! { #[test] fn write_to_slice(input in ethernet_2_any()) { // normal write { let mut buffer: [u8;14] = [0;14]; input.write_to_slice(&mut buffer).unwrap(); assert_eq!(buffer, input.to_bytes()); } // len to small for len in 0..14 { let mut buffer: [u8;14] = [0;14]; assert_eq!( SliceWriteSpaceError { required_len: Ethernet2Header::LEN, len, layer: Layer::Ethernet2Header, layer_start_offset: 0, }, input.write_to_slice(&mut buffer[..len]).unwrap_err() ); } } } proptest! { #[test] fn write(input in ethernet_2_any()) { // successful write { let mut buffer: Vec = Vec::with_capacity(14); input.write(&mut buffer).unwrap(); assert_eq!(&buffer[..], &input.to_bytes()); } // not enough memory for write (unexpected eof) for len in 0..8 { let mut buffer = [0u8;8]; let mut writer = Cursor::new(&mut buffer[..len]); assert!(input.write(&mut writer).is_err()); } } } proptest! { #[test] fn header_len(input in ethernet_2_any()) { assert_eq!(input.header_len(), 14); } } proptest! { #[test] fn to_bytes(input in ethernet_2_any()) { let ether_type_be = input.ether_type.0.to_be_bytes(); assert_eq!( input.to_bytes(), [ input.destination[0], input.destination[1], input.destination[2], input.destination[3], input.destination[4], input.destination[5], input.source[0], input.source[1], input.source[2], input.source[3], input.source[4], input.source[5], ether_type_be[0], ether_type_be[1], ] ); } } proptest! { #[test] fn clone_eq(input in ethernet_2_any()) { assert_eq!(input, input.clone()); } } proptest! { #[test] fn dbg(input in ethernet_2_any()) { assert_eq!( &format!( "Ethernet2Header {{ source: {:?}, destination: {:?}, ether_type: {:?} }}", input.source, input.destination, input.ether_type ), &format!("{:?}", input) ); } } }