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())
}
}