• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::*;
2 use core::slice::from_raw_parts;
3 
4 ///A slice containing an ethernet 2 header of a network package.
5 #[derive(Clone, Debug, Eq, PartialEq)]
6 pub struct Ethernet2HeaderSlice<'a> {
7     pub(crate) slice: &'a [u8],
8 }
9 
10 impl<'a> Ethernet2HeaderSlice<'a> {
11     /// Creates a ethernet slice from an other slice.
from_slice(slice: &'a [u8]) -> Result<Ethernet2HeaderSlice<'a>, err::LenError>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")]
from_slice_unchecked(slice: &[u8]) -> Ethernet2HeaderSlice46     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]
slice(&self) -> &'a [u8]53     pub fn slice(&self) -> &'a [u8] {
54         self.slice
55     }
56 
57     /// Read the destination MAC address
58     #[inline]
destination(&self) -> [u8; 6]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]
source(&self) -> [u8; 6]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]
ether_type(&self) -> EtherType78     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
to_header(&self) -> Ethernet2Header86     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)]
96 mod 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 }
179