wireparse 0.1.0

Library for reading and writing ethernet and other related protocals.
Documentation
use crate::{
    io::{ReadData, ReadDataUnchecked, UncheckedReader, WriteDataUnchecked},
    ArpError, EtherProtocal, Result,
};

#[derive(Clone, Debug, Eq, PartialEq, Default)]
pub struct ArpPayload<'a> {
    pub hardware_type: ArpHardwareType,
    pub protocal_type: EtherProtocal,
    pub hardware_address_length: u8,
    pub protocal_address_length: u8,
    pub operation: ArpOperation,
    pub sender_hardware_address: &'a [u8],
    pub sender_protocal_address: &'a [u8],
    pub target_hardware_address: &'a [u8],
    pub target_protocal_address: &'a [u8],
}

impl<'a> ArpPayload<'a> {
    pub const LEN: usize = 8;

    pub fn size(&self) -> usize {
        Self::LEN
            + (self.hardware_address_length as usize * 2)
            + (self.protocal_address_length as usize * 2)
    }

    pub fn from_slice(data: &'a [u8]) -> Result<Self> {
        if data.len() < Self::LEN {
            return Err(ArpError::NotEnoughBytesForAddrLengths {
                provided_size: data.len(),
                expected_size: Self::LEN,
            }
            .into());
        }

        let reader = &mut data[..].as_ref();

        let hardware_type = reader.read_unchecked();
        let protocal_type = reader.read_unchecked();
        let hardware_address_length = reader.read_unchecked();
        let protocal_address_length = reader.read_unchecked();
        let operation = reader.read_unchecked();

        let expected_size = Self::LEN
            + (hardware_address_length as usize * 2)
            + (protocal_address_length as usize * 2);

        if data.len() < expected_size {
            return Err(ArpError::NotEnoughBytesForAddrs {
                provided_size: data.len(),
                expected_size,
            }
            .into());
        }

        Ok(Self {
            hardware_type,
            protocal_type,
            hardware_address_length,
            protocal_address_length,
            operation,
            sender_hardware_address: reader.read_slice_unchecked(hardware_address_length as usize),
            sender_protocal_address: reader.read_slice_unchecked(protocal_address_length as usize),
            target_hardware_address: reader.read_slice_unchecked(hardware_address_length as usize),
            target_protocal_address: reader.read_slice_unchecked(protocal_address_length as usize),
        })
    }
}

impl<'a> ReadData<'a> for ArpPayload<'a> {
    fn read(reader: &mut impl crate::io::Reader<'a>) -> crate::Result<Self> {
        if reader.length() < Self::LEN {
            return Err(ArpError::NotEnoughBytesForAddrLengths {
                provided_size: reader.length(),
                expected_size: Self::LEN,
            }
            .into());
        }

        let hardware_type = reader.read_unchecked();
        let protocal_type = reader.read_unchecked();
        let hardware_address_length = reader.read_unchecked();
        let protocal_address_length = reader.read_unchecked();
        let operation = reader.read_unchecked();

        let expected_size =
            (hardware_address_length as usize * 2) + (protocal_address_length as usize * 2);

        if reader.length() < expected_size {
            return Err(ArpError::NotEnoughBytesForAddrs {
                provided_size: reader.length(),
                expected_size,
            }
            .into());
        }

        Ok(Self {
            hardware_type,
            protocal_type,
            hardware_address_length,
            protocal_address_length,
            operation,
            sender_hardware_address: reader.read_slice_unchecked(hardware_address_length as usize),
            sender_protocal_address: reader.read_slice_unchecked(protocal_address_length as usize),
            target_hardware_address: reader.read_slice_unchecked(hardware_address_length as usize),
            target_protocal_address: reader.read_slice_unchecked(protocal_address_length as usize),
        })
    }
}

impl<'a> WriteDataUnchecked for &ArpPayload<'a> {
    fn write_to_unchecked(self, writer: &mut impl crate::io::UncheckedWriter) {
        writer.write_unchecked(self.hardware_type);
        writer.write_unchecked(self.protocal_type);
        writer.write_unchecked(self.hardware_address_length);
        writer.write_unchecked(self.protocal_address_length);
        writer.write_unchecked(self.operation);
        writer.write_slice_unchecked(self.sender_hardware_address);
        writer.write_slice_unchecked(self.sender_protocal_address);
        writer.write_slice_unchecked(self.target_hardware_address);
        writer.write_slice_unchecked(self.target_protocal_address);
    }
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ArpHardwareType {
    Unknown(u16),
    Ethernet,
}

impl ArpHardwareType {
    pub fn to_u16(&self) -> u16 {
        match *self {
            Self::Ethernet => 1,
            Self::Unknown(n) => n,
        }
    }

    pub fn from_u16(val: u16) -> Self {
        match val {
            1 => Self::Ethernet,
            n => Self::Unknown(n),
        }
    }
}

impl Default for ArpHardwareType {
    fn default() -> Self {
        Self::Unknown(0)
    }
}

impl<'a> ReadDataUnchecked<'a> for ArpHardwareType {
    fn read_unchecked(reader: &mut impl crate::io::UncheckedReader<'a>) -> Self {
        Self::from_u16(reader.read_unchecked())
    }
}

impl WriteDataUnchecked for ArpHardwareType {
    fn write_to_unchecked(self, writer: &mut impl crate::io::UncheckedWriter) {
        writer.write_unchecked(self.to_u16())
    }
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ArpOperation {
    Unknown(u16),
    Request,
    Reply,
}

impl ArpOperation {
    pub fn to_u16(&self) -> u16 {
        match *self {
            Self::Request => 1,
            Self::Reply => 2,
            Self::Unknown(n) => n,
        }
    }

    pub fn from_u16(val: u16) -> Self {
        match val {
            1 => Self::Request,
            2 => Self::Reply,
            n => Self::Unknown(n),
        }
    }
}

impl Default for ArpOperation {
    fn default() -> Self {
        Self::Unknown(0)
    }
}

impl<'a> ReadDataUnchecked<'a> for ArpOperation {
    fn read_unchecked(reader: &mut impl crate::io::UncheckedReader<'a>) -> Self {
        Self::from_u16(reader.read_unchecked())
    }
}

impl WriteDataUnchecked for ArpOperation {
    fn write_to_unchecked(self, writer: &mut impl crate::io::UncheckedWriter) {
        writer.write_unchecked(self.to_u16())
    }
}