internet 0.1.0

Network library for rust
Documentation
//! Ethernet Header Mapping.
//!
//! Provides zero-copy read and write access to IEEE 802.3 Ethernet header fields.
//!
//! As defined in [IEEE 802.3].
//!
//! [IEEE 802.3]: https://standards.ieee.org/ieee/802.3/

use crate::ieee::ethernet::{Address, EtherType};
use crate::{Buf, BufMut};

/// A zero-copy mapping for an Ethernet header.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct HeaderMapping<T> {
    buffer: T,
}

impl<T> HeaderMapping<T> {
    /// Creates a new header mapping.
    pub fn new(buffer: T) -> Self {
        Self { buffer }
    }

    /// Consumes the mapping and returns the underlying buffer.
    pub fn into_inner(self) -> T {
        self.buffer
    }
}

impl<T: Buf> HeaderMapping<T> {
    /// Reads the destination MAC address.
    pub fn read_destination_address(&self) -> Address {
        unsafe { Address::new(self.buffer.get_array_unchecked::<6>(0)) }
    }

    /// Reads the source MAC address.
    pub fn read_source_address(&self) -> Address {
        unsafe { Address::new(self.buffer.get_array_unchecked::<6>(6)) }
    }

    /// Reads the EtherType or Length field.
    pub fn read_ether_type(&self) -> EtherType {
        unsafe { EtherType(self.buffer.get_u16_be_unchecked(12)) }
    }
}

impl<T: BufMut> HeaderMapping<T> {
    /// Writes the destination MAC address.
    pub fn write_destination_address(&mut self, addr: Address) {
        unsafe { self.buffer.set_array_unchecked(0, &addr.0) }
    }

    /// Writes the source MAC address.
    pub fn write_source_address(&mut self, addr: Address) {
        unsafe { self.buffer.set_array_unchecked(6, &addr.0) }
    }

    /// Writes the EtherType or Length field.
    pub fn write_ether_type(&mut self, ether_type: EtherType) {
        unsafe { self.buffer.set_u16_be_unchecked(12, ether_type.0) }
    }
}

#[cfg(test)]
mod tests {
    use super::{Address, EtherType, HeaderMapping};

    #[test]
    fn read_fields() {
        // Broadcast destination, specific source, IPv4 EtherType
        let buffer = [
            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // Destination
            0x00, 0x1A, 0x2B, 0x3C, 0x4D, 0x5E, // Source
            0x08, 0x00, // EtherType: IPv4
        ];

        let mapping = HeaderMapping::new(&buffer[..]);

        assert_eq!(mapping.read_destination_address(), Address::BROADCAST);
        assert_eq!(
            mapping.read_source_address(),
            Address::new([0x00, 0x1A, 0x2B, 0x3C, 0x4D, 0x5E])
        );
        assert_eq!(mapping.read_ether_type(), EtherType::IPV4);
    }

    #[test]
    fn write_fields() {
        let mut buffer = [0u8; 14];

        {
            let mut mapping = HeaderMapping::new(&mut buffer[..]);
            mapping.write_destination_address(Address::BROADCAST);
            mapping.write_source_address(Address::new([0x00, 0x1A, 0x2B, 0x3C, 0x4D, 0x5E]));
            mapping.write_ether_type(EtherType::IPV6);
        }

        assert_eq!(&buffer[0..6], &[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]);
        assert_eq!(&buffer[6..12], &[0x00, 0x1A, 0x2B, 0x3C, 0x4D, 0x5E]);
        assert_eq!(&buffer[12..14], &[0x86, 0xDD]); // IPv6 EtherType
    }
}