• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&eth.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(&eth.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(&eth.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(&eth.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