Thanks to visit codestin.com
Credit goes to docs.rs

etherparse/link/
ethernet2_header_slice.rs

1use crate::*;
2use core::slice::from_raw_parts;
3
4///A slice containing an ethernet 2 header of a network package.
5#[derive(Clone, Debug, Eq, PartialEq)]
6pub struct Ethernet2HeaderSlice<'a> {
7    pub(crate) slice: &'a [u8],
8}
9
10impl<'a> Ethernet2HeaderSlice<'a> {
11    /// Creates a ethernet slice from an other slice.
12    pub fn from_slice(slice: &'a [u8]) -> Result<Ethernet2HeaderSlice<'a>, err::LenError> {
13        //check length
14        if slice.len() < Ethernet2Header::LEN {
15            return Err(err::LenError {
16                required_len: Ethernet2Header::LEN,
17                len: slice.len(),
18                len_source: LenSource::Slice,
19                layer: err::Layer::Ethernet2Header,
20                layer_start_offset: 0,
21            });
22        }
23
24        //all done
25        Ok(Ethernet2HeaderSlice {
26            // SAFETY:
27            // Safe as slice length is checked to be at least
28            // Ethernet2Header::LEN (14) before this.
29            slice: unsafe { from_raw_parts(slice.as_ptr(), Ethernet2Header::LEN) },
30        })
31    }
32
33    /// Converts the given slice into a ethernet 2 header slice WITHOUT any
34    /// checks to ensure that the data present is an ethernet 2 header or that the
35    /// slice length is matching the header length.
36    ///
37    /// If you are not sure what this means, use [`Ethernet2HeaderSlice::from_slice`]
38    /// instead.
39    ///
40    /// # Safety
41    ///
42    /// The caller must ensured that the given slice has the length of
43    /// [`Ethernet2Header::LEN`]
44    #[inline]
45    #[cfg(feature = "std")]
46    pub(crate) unsafe fn from_slice_unchecked(slice: &[u8]) -> Ethernet2HeaderSlice {
47        debug_assert!(slice.len() == Ethernet2Header::LEN);
48        Ethernet2HeaderSlice { slice }
49    }
50
51    /// Returns the slice containing the ethernet 2 header
52    #[inline]
53    pub fn slice(&self) -> &'a [u8] {
54        self.slice
55    }
56
57    /// Read the destination MAC address
58    #[inline]
59    pub fn destination(&self) -> [u8; 6] {
60        // SAFETY:
61        // Safe as the contructor checks that the slice has
62        // at least the length of Ethernet2Header::LEN (14).
63        unsafe { get_unchecked_6_byte_array(self.slice.as_ptr()) }
64    }
65
66    /// Read the source MAC address
67    #[inline]
68    pub fn source(&self) -> [u8; 6] {
69        // SAFETY:
70        // Safe as the contructor checks that the slice has
71        // at least the length of Ethernet2Header::LEN (14).
72        unsafe { get_unchecked_6_byte_array(self.slice.as_ptr().add(6)) }
73    }
74
75    /// Read the ether_type field of the header indicating the protocol
76    /// after the header.
77    #[inline]
78    pub fn ether_type(&self) -> EtherType {
79        // SAFETY:
80        // Safe as the contructor checks that the slice has
81        // at least the length of Ethernet2Header::LEN (14).
82        EtherType(unsafe { get_unchecked_be_u16(self.slice.as_ptr().add(12)) })
83    }
84
85    /// Decode all the fields and copy the results to a [`Ethernet2Header`] struct
86    pub fn to_header(&self) -> Ethernet2Header {
87        Ethernet2Header {
88            source: self.source(),
89            destination: self.destination(),
90            ether_type: self.ether_type(),
91        }
92    }
93}
94
95#[cfg(test)]
96mod test {
97    use super::*;
98    use crate::test_gens::*;
99    use alloc::{format, vec::Vec};
100    use proptest::prelude::*;
101
102    proptest! {
103        #[test]
104        fn from_slice(
105            input in ethernet_2_any(),
106            dummy_data in proptest::collection::vec(any::<u8>(), 0..20)
107        ) {
108            // serialize
109            let mut buffer: Vec<u8> = Vec::with_capacity(14 + dummy_data.len());
110            input.write(&mut buffer).unwrap();
111            buffer.extend(&dummy_data[..]);
112
113            // calls with a valid result
114            {
115                let result = Ethernet2HeaderSlice::from_slice(&buffer[..]).unwrap();
116                assert_eq!(&buffer[..14], result.slice());
117            }
118
119            // call with not enough data in the slice
120            for len in 0..=13 {
121                assert_eq!(
122                    Ethernet2HeaderSlice::from_slice(&buffer[..len]),
123                    Err(err::LenError{
124                        required_len: Ethernet2Header::LEN,
125                        len: len,
126                        len_source: LenSource::Slice,
127                        layer: err::Layer::Ethernet2Header,
128                        layer_start_offset: 0,
129                    })
130                );
131            }
132        }
133    }
134
135    proptest! {
136        #[test]
137        fn getters(input in ethernet_2_any()) {
138            let buffer = input.to_bytes();
139            let slice = Ethernet2HeaderSlice::from_slice(&buffer).unwrap();
140            assert_eq!(input.destination, slice.destination());
141            assert_eq!(input.source, slice.source());
142            assert_eq!(input.ether_type, slice.ether_type());
143        }
144    }
145
146    proptest! {
147        #[test]
148        fn to_header(input in ethernet_2_any()) {
149            let buffer = input.to_bytes();
150            let slice = Ethernet2HeaderSlice::from_slice(&buffer).unwrap();
151            assert_eq!(input, slice.to_header());
152        }
153    }
154
155    proptest! {
156        #[test]
157        fn clone_eq(input in ethernet_2_any()) {
158            let buffer = input.to_bytes();
159            let slice = Ethernet2HeaderSlice::from_slice(&buffer).unwrap();
160            assert_eq!(slice, slice.clone());
161        }
162    }
163
164    proptest! {
165        #[test]
166        fn dbg(input in ethernet_2_any()) {
167            let buffer = input.to_bytes();
168            let slice = Ethernet2HeaderSlice::from_slice(&buffer).unwrap();
169            assert_eq!(
170                &format!(
171                    "Ethernet2HeaderSlice {{ slice: {:?} }}",
172                    slice.slice()
173                ),
174                &format!("{:?}", slice)
175            );
176        }
177    }
178}