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