use crate::{Buf, BufMut, BufResult, Codec, Cursor};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Header {
pub destination_address: Address,
pub source_address: Address,
pub length_or_type: EtherType,
}
impl Header {
pub const SIZE: usize = 14;
}
impl Codec for Header {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.destination_address.encode(writer, ())?;
self.source_address.encode(writer, ())?;
self.length_or_type.encode(writer, ())?;
Ok(())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
let destination_address = Address::decode(reader, ())?;
let source_address = Address::decode(reader, ())?;
let length_or_type = EtherType::decode(reader, ())?;
Ok(Self {
destination_address,
source_address,
length_or_type,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct EtherType(pub u16);
impl EtherType {
pub const IPV4: Self = Self(0x0800);
pub const IPV6: Self = Self(0x86DD);
pub const ARP: Self = Self(0x0806);
pub const RARP: Self = Self(0x8035);
pub const VLAN: Self = Self(0x8100);
pub const EAPOL: Self = Self(0x888E);
pub fn is_length(&self) -> bool {
self.0 <= 1500
}
pub fn is_type(&self) -> bool {
self.0 >= 1536
}
}
impl Codec for EtherType {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.0.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
Ok(Self(u16::decode(reader, ())?))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Address(pub [u8; 6]);
impl Address {
pub const BROADCAST: Self = Self([0xFF; 6]);
pub const UNSPECIFIED: Self = Self([0x00; 6]);
pub fn new(bytes: [u8; 6]) -> Self {
Self(bytes)
}
pub fn is_broadcast(&self) -> bool {
self.0 == [0xFF; 6]
}
pub fn is_multicast(&self) -> bool {
(self.0[0] & 0x01) != 0
}
pub fn is_local(&self) -> bool {
(self.0[0] & 0x02) != 0
}
}
impl Codec for Address {
fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
self.0.encode(writer, ())
}
fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
Ok(Self(<[u8; 6]>::decode(reader, ())?))
}
}
#[cfg(test)]
mod tests {
use core::fmt::Debug;
use crate::{
Codec, Cursor,
ieee::ethernet::{Address, EtherType, Header},
};
fn codec_roundtrip<T: Codec<C> + Debug + Eq, C: Copy>(
etalon_struct: T,
etalon_bytes: &[u8],
context: C,
) {
let mut encoded_bytes = vec![];
{
let writer = &mut Cursor::new(&mut encoded_bytes);
etalon_struct.encode(writer, context).unwrap();
}
assert_eq!(etalon_bytes, &encoded_bytes);
let decoded_struct = {
let reader = &mut Cursor::new(&mut encoded_bytes);
T::decode(reader, context).unwrap()
};
assert_eq!(etalon_struct, decoded_struct);
encoded_bytes.fill(0x00);
{
let writer = &mut Cursor::new(&mut encoded_bytes);
decoded_struct.encode(writer, context).unwrap();
}
assert_eq!(etalon_bytes, &encoded_bytes);
}
#[test]
fn address() {
let addr = Address::new([0x00, 0x1A, 0x2B, 0x3C, 0x4D, 0x5E]);
let bytes = &[0x00, 0x1A, 0x2B, 0x3C, 0x4D, 0x5E][..];
codec_roundtrip(addr, bytes, ());
assert!(!addr.is_broadcast());
assert!(!addr.is_multicast());
assert!(!addr.is_local());
assert!(Address::BROADCAST.is_broadcast());
assert!(Address::BROADCAST.is_multicast());
}
#[test]
fn ether_type() {
let ipv4 = EtherType::IPV4;
let bytes = &[0x08, 0x00][..];
codec_roundtrip(ipv4, bytes, ());
assert!(ipv4.is_type());
assert!(!ipv4.is_length());
let length = EtherType(1500);
assert!(length.is_length());
assert!(!length.is_type());
}
#[test]
fn header() {
let etalon_bytes = &[
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x1A, 0x2B, 0x3C, 0x4D, 0x5E, 0x08, 0x00, ];
let etalon_struct = Header {
destination_address: Address::BROADCAST,
source_address: Address::new([0x00, 0x1A, 0x2B, 0x3C, 0x4D, 0x5E]),
length_or_type: EtherType::IPV4,
};
codec_roundtrip(etalon_struct, etalon_bytes, ());
}
}