blob: 6334068f855fbe60e7ea3508856b1170c53b5ee7 [file] [log] [blame]
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<T: std::io::Read + std::io::Seek + Sized>(
reader: &mut T,
) -> Result<Ethernet2Header, std::io::Error> {
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<T: std::io::Write + Sized>(&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::<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, 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::<u8>(), 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<u8> = 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)
);
}
}
}