use core::fmt;
use crate::error::{Error, PduError};
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
pub struct EthernetAddress(pub [u8; 6]);
impl EthernetAddress {
pub const BROADCAST: EthernetAddress = EthernetAddress([0xff; 6]);
pub fn from_bytes(data: &[u8]) -> EthernetAddress {
let mut bytes = [0; 6];
bytes.copy_from_slice(data);
EthernetAddress(bytes)
}
pub const fn as_bytes(&self) -> &[u8] {
&self.0
}
}
impl fmt::Display for EthernetAddress {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let bytes = self.0;
write!(
f,
"{:02x}-{:02x}-{:02x}-{:02x}-{:02x}-{:02x}",
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5]
)
}
}
#[cfg(feature = "defmt")]
impl defmt::Format for EthernetAddress {
fn format(&self, fmt: defmt::Formatter) {
let bytes = self.0;
defmt::write!(
fmt,
"{:02x}-{:02x}-{:02x}-{:02x}-{:02x}-{:02x}",
bytes[0],
bytes[1],
bytes[2],
bytes[3],
bytes[4],
bytes[5]
)
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct EthernetFrame<T: AsRef<[u8]>> {
buffer: T,
}
mod field {
use core::ops::{Range, RangeFrom};
pub const DESTINATION: Range<usize> = 0..6;
pub const SOURCE: Range<usize> = 6..12;
pub const ETHERTYPE: Range<usize> = 12..14;
pub const PAYLOAD: RangeFrom<usize> = 14..;
}
pub const ETHERNET_HEADER_LEN: usize = field::PAYLOAD.start;
impl<T: AsRef<[u8]>> EthernetFrame<T> {
pub const fn new_unchecked(buffer: T) -> EthernetFrame<T> {
EthernetFrame { buffer }
}
pub fn new_checked(buffer: T) -> Result<EthernetFrame<T>, Error> {
let packet = Self::new_unchecked(buffer);
packet.check_len()?;
Ok(packet)
}
pub fn check_len(&self) -> Result<(), Error> {
let len = self.buffer.as_ref().len();
if len < ETHERNET_HEADER_LEN {
Err(Error::Pdu(PduError::Ethernet))
} else {
Ok(())
}
}
pub fn into_inner(self) -> T {
self.buffer
}
pub const fn header_len() -> usize {
ETHERNET_HEADER_LEN
}
pub const fn buffer_len(payload_len: usize) -> usize {
ETHERNET_HEADER_LEN + payload_len
}
#[inline]
pub fn dst_addr(&self) -> EthernetAddress {
let data = self.buffer.as_ref();
EthernetAddress::from_bytes(&data[field::DESTINATION])
}
#[inline]
pub fn src_addr(&self) -> EthernetAddress {
let data = self.buffer.as_ref();
EthernetAddress::from_bytes(&data[field::SOURCE])
}
#[inline]
pub fn ethertype(&self) -> u16 {
let data = self.buffer.as_ref();
data.get(field::ETHERTYPE)
.map(|res| u16::from_be_bytes(res.try_into().unwrap()))
.unwrap_or(0)
}
}
impl<'a, T: AsRef<[u8]> + ?Sized> EthernetFrame<&'a T> {
#[inline]
pub fn payload(&self) -> &'a [u8] {
let data = self.buffer.as_ref();
&data[field::PAYLOAD]
}
}
impl<T: AsRef<[u8]> + AsMut<[u8]>> EthernetFrame<T> {
#[inline]
pub fn set_dst_addr(&mut self, value: EthernetAddress) {
let data = self.buffer.as_mut();
data[field::DESTINATION].copy_from_slice(value.as_bytes())
}
#[inline]
pub fn set_src_addr(&mut self, value: EthernetAddress) {
let data = self.buffer.as_mut();
data[field::SOURCE].copy_from_slice(value.as_bytes())
}
#[inline]
pub fn set_ethertype(&mut self, value: u16) {
let data = self.buffer.as_mut();
data[field::ETHERTYPE].copy_from_slice(&value.to_be_bytes());
}
#[inline]
pub fn payload_mut(&mut self) -> &mut [u8] {
let data = self.buffer.as_mut();
&mut data[field::PAYLOAD]
}
}
impl<T: AsRef<[u8]>> AsRef<[u8]> for EthernetFrame<T> {
fn as_ref(&self) -> &[u8] {
self.buffer.as_ref()
}
}
impl<T: AsRef<[u8]>> fmt::Display for EthernetFrame<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"EthernetII src={} dst={} type={}",
self.src_addr(),
self.dst_addr(),
self.ethertype()
)
}
}