use crate::layer::{eth, Result, Error};
use crate::nic::Info;
use crate::wire::{arp, ethernet, ip, Payload, PayloadMut};
pub struct In<'a, P: Payload> {
pub control: Controller<'a>,
pub packet: arp::Packet<ethernet::Frame<&'a mut P>>,
}
pub struct Out<'a, P: Payload> {
control: Controller<'a>,
packet: arp::Packet<ethernet::Frame<&'a mut P>>,
}
pub struct Raw<'a, P: Payload> {
pub control: Controller<'a>,
pub payload: &'a mut P,
}
pub struct Controller<'a> {
pub(crate) inner: eth::Controller<'a>,
}
pub enum Init {
EthernetIpv4Request {
source_hardware_addr: ethernet::Address,
source_protocol_addr: ip::v4::Address,
target_hardware_addr: ethernet::Address,
target_protocol_addr: ip::v4::Address,
},
}
impl<'a> Controller<'a> {
pub(crate) fn new(control: eth::Controller<'a>) -> Self {
Controller { inner: control }
}
pub fn info(&self) -> &dyn Info {
self.inner.info()
}
pub fn borrow_mut(&mut self) -> Controller {
Controller {
inner: self.inner.borrow_mut(),
}
}
}
impl<'a, P: Payload> In<'a, P> {
pub(crate) fn new(control: Controller<'a>, packet: arp::Packet<ethernet::Frame<&'a mut P>>) -> Self {
In { control, packet }
}
pub fn deinit(self) -> Raw<'a, P>
where
P: PayloadMut,
{
let payload = self.packet.into_inner().into_inner();
Raw::new(self.control, payload)
}
}
impl<'a, P: PayloadMut> In<'a, P> {
pub fn answer(mut self) -> Result<Out<'a, P>> {
let dst_address;
let answer = match self.packet.repr() {
arp::Repr::EthernetIpv4 {
operation: arp::Operation::Request,
source_hardware_addr,
source_protocol_addr,
target_hardware_addr: _,
target_protocol_addr,
} => {
dst_address = source_hardware_addr;
arp::Repr::EthernetIpv4 {
operation: arp::Operation::Reply,
source_hardware_addr: self.control.inner.src_addr(),
source_protocol_addr: target_protocol_addr,
target_hardware_addr: source_hardware_addr,
target_protocol_addr: source_protocol_addr,
}
}
_ => return Err(Error::Illegal),
};
let eth_frame = self.packet.into_inner();
let eth_init = eth::Init {
src_addr: self.control.inner.src_addr(),
dst_addr: dst_address,
ethertype: ethernet::EtherType::Arp,
payload: 28,
};
let eth_in = eth::InPacket {
control: self.control.inner,
frame: eth_frame,
};
let packet = eth_in.reinit(eth_init)?;
let eth::InPacket { control, mut frame} = packet.into_incoming();
answer.emit(
arp::packet::new_unchecked_mut(frame.payload_mut_slice()),
);
let control = Controller::new(control);
Ok(Out {
control,
packet: arp::Packet::new_unchecked(frame, answer),
})
}
}
impl<'a, P: Payload> Out<'a, P> {
pub fn send(self) -> Result<()>
where
P: PayloadMut,
{
let lower = eth::OutPacket::new_unchecked(
self.control.inner,
self.packet.into_inner(),
);
lower.send()
}
}
impl<'a, P: Payload + PayloadMut> Raw<'a, P> {
pub(crate) fn new(control: Controller<'a>, payload: &'a mut P) -> Self {
Raw { control, payload }
}
pub fn prepare(self, init: Init) -> Result<Out<'a, P>> {
let mut lower = eth::RawPacket {
control: self.control.inner,
payload: self.payload,
};
let eth_init = eth::Init {
src_addr: lower.control.src_addr(),
dst_addr: ethernet::Address::BROADCAST,
ethertype: ethernet::EtherType::Arp,
payload: 28,
};
let packet = lower.prepare(eth_init)?;
let eth::InPacket { control, mut frame } = packet.into_incoming();
let repr = init.initialize(&mut frame)?;
let control = Controller::new(control);
Ok(Out {
control,
packet: arp::Packet::new_unchecked(frame, repr),
})
}
}
impl Init {
fn initialize(&self, payload: &mut impl PayloadMut) -> Result<arp::Repr> {
let repr = self.repr();
let packet = arp::packet::new_unchecked_mut(payload.payload_mut().as_mut_slice());
repr.emit(packet);
Ok(repr)
}
fn repr(&self) -> arp::Repr {
match *self {
Init::EthernetIpv4Request {
source_hardware_addr,
source_protocol_addr,
target_hardware_addr,
target_protocol_addr,
} => arp::Repr::EthernetIpv4 {
operation: arp::Operation::Request,
source_hardware_addr,
source_protocol_addr,
target_hardware_addr,
target_protocol_addr,
},
}
}
}