use core::fmt;
use super::address::MacAddress;
use super::ether_type::EtherType;
use super::frame::{EthernetFrameMut, HEADER_LENGTH};
const DESTINATION: core::ops::Range<usize> = 0..6;
const SOURCE: core::ops::Range<usize> = 6..12;
const ETHER_TYPE: core::ops::Range<usize> = 12..14;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum EthernetFrameBuildError {
MissingDestination,
MissingSource,
MissingEtherType,
LengthOverflow {
header_length: usize,
payload_length: usize,
},
BufferTooShort {
required: usize,
available: usize,
},
}
impl fmt::Display for EthernetFrameBuildError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::MissingDestination => formatter.write_str("missing Ethernet destination address"),
Self::MissingSource => formatter.write_str("missing Ethernet source address"),
Self::MissingEtherType => formatter.write_str("missing Ethernet protocol type"),
Self::LengthOverflow {
header_length,
payload_length,
} => write!(
formatter,
"Ethernet frame length overflow: {header_length} + {payload_length}"
),
Self::BufferTooShort {
required,
available,
} => write!(
formatter,
"Ethernet buffer is too short: need {required} bytes, have {available}"
),
}
}
}
pub struct EthernetFrameBuilder<'a> {
buffer: &'a mut [u8],
payload_length: usize,
destination: Option<MacAddress>,
source: Option<MacAddress>,
ether_type: Option<EtherType>,
}
impl<'a> EthernetFrameBuilder<'a> {
#[inline]
pub fn new(buffer: &'a mut [u8], payload_length: usize) -> Self {
Self {
buffer,
payload_length,
destination: None,
source: None,
ether_type: None,
}
}
#[inline]
pub fn destination(mut self, destination: MacAddress) -> Self {
self.destination = Some(destination);
self
}
#[inline]
pub fn source(mut self, source: MacAddress) -> Self {
self.source = Some(source);
self
}
#[inline]
pub fn ether_type(mut self, ether_type: EtherType) -> Self {
self.ether_type = Some(ether_type);
self
}
#[inline]
pub fn build(self) -> Result<EthernetFrameMut<'a>, EthernetFrameBuildError> {
let destination = self
.destination
.ok_or(EthernetFrameBuildError::MissingDestination)?;
let source = self.source.ok_or(EthernetFrameBuildError::MissingSource)?;
let ether_type = self
.ether_type
.ok_or(EthernetFrameBuildError::MissingEtherType)?;
let frame_length = HEADER_LENGTH.checked_add(self.payload_length).ok_or(
EthernetFrameBuildError::LengthOverflow {
header_length: HEADER_LENGTH,
payload_length: self.payload_length,
},
)?;
if self.buffer.len() < frame_length {
return Err(EthernetFrameBuildError::BufferTooShort {
required: frame_length,
available: self.buffer.len(),
});
}
let bytes = &mut self.buffer[..frame_length];
bytes[DESTINATION].copy_from_slice(&destination.octets());
bytes[SOURCE].copy_from_slice(&source.octets());
bytes[ETHER_TYPE].copy_from_slice(ðer_type.raw().to_be_bytes());
Ok(EthernetFrameMut::from_validated(bytes))
}
}