use crate::layer::{eth, Result};
use crate::wire::{arp, ethernet, ip::Address as IpAddress, Payload, PayloadMut};
use crate::time::Instant;
use crate::layer::ip;
use super::packet::{Controller, In, Init, Raw};
use super::neighbor::Cache;
pub struct Endpoint<'data> {
neighbors: Cache<'data>,
}
pub struct Receiver<'a, 'data> {
endpoint: EndpointRef<'a, 'data>,
}
pub struct Sender<'a, 'data> {
endpoint: EndpointRef<'a, 'data>,
}
struct EndpointRef<'a, 'data> {
inner: &'a mut Endpoint<'data>,
ip: &'a mut ip::Routing<'data>,
}
impl<'data> Endpoint<'data> {
pub fn new<C>(neighbors: C) -> Self
where C: Into<Cache<'data>>,
{
Endpoint {
neighbors: neighbors.into(),
}
}
pub fn answer<'a>(&'a mut self, ip: &'a mut ip::Endpoint<'data>) -> Receiver<'a, 'data> {
self.answer_for(ip.routing())
}
pub(crate) fn answer_for<'a>(&'a mut self, ip: &'a mut ip::Routing<'data>) -> Receiver<'a, 'data> {
Receiver {
endpoint: self.get_mut(ip),
}
}
pub fn query<'a>(&'a mut self, ip: &'a mut ip::Endpoint<'data>) -> Sender<'a, 'data> {
self.query_for(ip.routing())
}
pub(crate) fn query_for<'a>(&'a mut self, ip: &'a mut ip::Routing<'data>) -> Sender<'a, 'data> {
Sender {
endpoint: self.get_mut(ip),
}
}
fn get_mut<'a>(&'a mut self, ip: &'a mut ip::Routing<'data>) -> EndpointRef<'a, 'data> {
EndpointRef { inner: self, ip, }
}
pub(crate) fn neighbors(&self) -> &Cache<'data> {
&self.neighbors
}
pub(crate) fn neighbors_mut(&mut self) -> &mut Cache<'data> {
&mut self.neighbors
}
}
impl EndpointRef<'_, '_> {
fn handle_internally<P: PayloadMut>(&mut self, packet: In<P>) -> Result<()> {
let (operation, source_hardware_addr, source_protocol_addr, target_protocol_addr) =
match packet.packet.repr() {
arp::Repr::EthernetIpv4 {
operation,
source_hardware_addr,
source_protocol_addr,
target_hardware_addr: _,
target_protocol_addr
} => {
(operation, source_hardware_addr, source_protocol_addr, target_protocol_addr)
},
_ => return Ok(()),
};
self.update(
source_hardware_addr,
IpAddress::Ipv4(source_protocol_addr),
packet.control.info().timestamp());
if target_protocol_addr.is_unicast() && self.ip.accepts(IpAddress::Ipv4(target_protocol_addr)) {
if let arp::Operation::Request = operation {
packet.answer()?.send()?;
}
}
Ok(())
}
fn send_oustanding<P: PayloadMut>(&mut self, raw: Raw<P>) -> Result<()> {
let ts = raw.control.info().timestamp();
let unresolved = self.inner.neighbors
.missing()
.filter(|missing| missing.is_alive(ts) && missing.looking_for())
.filter_map(|missing| match missing.protocol_addr() {
IpAddress::Ipv4(addr) => Some(addr),
_ => None,
})
.filter_map(|addr| {
self.ip.find_local_route(IpAddress::Ipv4(addr), ts)
.map(|route| (addr, route))
})
.next();
let (addr, route) = match unresolved {
None => return Ok(()),
Some(required) => required,
};
debug_assert_eq!(route.next_hop, IpAddress::Ipv4(addr));
let ip_src_address = match route.src_addr {
IpAddress::Ipv4(addr) => addr,
_ => unreachable!("Ipv4 destination routed with non-ipv4 source"),
};
let mut raw = raw;
let src = raw.control.inner.src_addr();
let prepared = raw.prepare(Init::EthernetIpv4Request {
source_hardware_addr: src,
target_hardware_addr: ethernet::Address::BROADCAST,
source_protocol_addr: ip_src_address,
target_protocol_addr: addr,
})?;
let reset = self.inner.neighbors.requesting(IpAddress::Ipv4(addr), ts);
debug_assert!(reset.is_ok());
prepared.send()?;
Ok(())
}
fn update(&mut self, hw_addr: ethernet::Address, prot_addr: IpAddress, time: Instant) -> bool {
if let Some(_) = self.inner.neighbors.lookup(prot_addr, time) {
assert!(self.inner.neighbors.fill(prot_addr, hw_addr, Some(time)).is_ok());
true
} else {
false
}
}
}
impl<P> eth::Recv<P> for Receiver<'_, '_>
where P: PayloadMut,
{
fn receive(&mut self, eth::InPacket { control, frame }: eth::InPacket<P>) {
let packet = match frame.repr().ethertype {
ethernet::EtherType::Arp => match arp::Packet::new_checked(frame) {
Ok(packet) => packet,
Err(_) => return,
},
_ => return,
};
let control = Controller::new(control);
let packet = In::new(control, packet);
if let Err(_) = self.endpoint.handle_internally(packet) {
}
}
}
impl<P> eth::Send<P> for Sender<'_, '_>
where P: Payload + PayloadMut,
{
fn send(&mut self, packet: eth::RawPacket<P>) {
let eth::RawPacket {
control: mut eth_handle,
payload,
} = packet;
let control = Controller::new(eth_handle.borrow_mut());
let packet = Raw::new(control, payload);
if let Err(_) = self.endpoint.send_oustanding(packet) {
}
}
}