use crate::layer::{Error, Result, eth};
use crate::nic::{self, Info};
use crate::time::Instant;
use crate::wire::{ethernet, ip};
use crate::wire::{Checksum, Reframe, Payload, PayloadMut, PayloadResult, payload};
pub struct In<'a, P: Payload> {
pub control: Controller<'a>,
pub packet: IpPacket<'a, P>,
}
#[must_use = "You need to call `send` explicitely on an OutPacket, otherwise no packet is sent."]
pub struct Out<'a, P: Payload> {
control: Controller<'a>,
packet: IpPacket<'a, P>,
}
pub struct Raw<'a, P: Payload> {
pub control: Controller<'a>,
pub payload: &'a mut P,
}
pub struct Controller<'a> {
pub(crate) eth: eth::Controller<'a>,
pub(crate) endpoint: &'a mut dyn Endpoint,
}
pub type V4Packet<'a, P> = ip::v4::Packet<ethernet::Frame<&'a mut P>>;
pub type V6Packet<'a, P> = ip::v6::Packet<ethernet::Frame<&'a mut P>>;
pub enum IpPacket<'a, P: Payload> {
V4(V4Packet<'a, P>),
V6(V6Packet<'a, P>),
}
#[derive(Copy, Clone, Debug)]
pub struct Init {
pub source: Source,
pub dst_addr: ip::Address,
pub protocol: ip::Protocol,
pub payload: usize,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Source {
Mask {
subnet: ip::Subnet,
},
Exact(ip::Address),
}
pub(crate) struct Route {
pub(crate) next_hop: ip::Address,
pub(crate) src_addr: ip::Address,
}
#[derive(Clone, Copy)]
struct EthRoute {
src_mac: ethernet::Address,
src_addr: ip::Address,
next_mac: ethernet::Address,
}
pub(crate) trait Endpoint{
fn local_ip(&self, subnet: ip::Subnet) -> Option<ip::Address>;
fn route(&self, dst_addr: ip::Address, time: Instant) -> Option<Route>;
fn resolve(&mut self, _: ip::Address, _: Instant, look: bool) -> Result<ethernet::Address>;
}
impl<'a> Controller<'a> {
pub(crate) fn wrap(self,
wrap: impl FnOnce(&'a mut dyn nic::Handle) -> &'a mut dyn nic::Handle,
) -> Self {
let eth = self.eth.wrap(wrap);
Controller { eth, endpoint: self.endpoint }
}
pub fn info(&self) -> &dyn Info {
self.eth.info()
}
pub fn borrow_mut(&mut self) -> Controller {
Controller {
eth: self.eth.borrow_mut(),
endpoint: self.endpoint,
}
}
pub fn local_ip(&self, subnet: ip::Subnet) -> Option<ip::Address> {
self.endpoint.local_ip(subnet)
}
pub fn resolve(&mut self, dst_addr: ip::Address)
-> Result<ethernet::Address>
{
let time = self.info().timestamp();
self.endpoint.resolve(dst_addr, time, true)
}
fn route_to(&mut self, dst_addr: ip::Address) -> Result<EthRoute> {
let now = self.eth.info().timestamp();
let Route { next_hop, src_addr } = self.endpoint
.route(dst_addr, now)
.ok_or(Error::Unreachable)?;
let next_mac = self.resolve(next_hop)?;
let src_mac = self.eth.src_addr();
Ok(EthRoute {
src_mac,
src_addr,
next_mac,
})
}
}
impl<'a, P: Payload> In<'a, P> {
pub fn deinit(self) -> Raw<'a, P>
where P: PayloadMut,
{
Raw {
control: self.control,
payload: self.packet.into_raw()
}
}
}
impl<'a, P: PayloadMut> In<'a, P> {
pub fn reinit(mut self, init: Init) -> Result<Out<'a, P>> {
let route = self.control.route_to(init.dst_addr)?;
let lower_init = init.init_eth(route, init.payload)?;
let eth_packet = eth::InPacket {
control: self.control.eth,
frame: self.packet.into_inner(),
};
let packet = eth_packet.reinit(lower_init)?;
let eth::InPacket { control, mut frame } = packet.into_incoming();
let repr = init.initialize(route.src_addr, &mut frame)?;
Ok(Out {
control: Controller {
eth: control,
endpoint: self.control.endpoint,
},
packet: IpPacket::new_unchecked(frame, repr),
})
}
}
impl<'a, P: Payload> Out<'a, P> {
pub fn new_unchecked(
control: Controller<'a>,
packet: IpPacket<'a, P>) -> Self
{
Out { control, packet, }
}
pub fn into_incoming(self) -> In<'a, P> {
let Out { control, packet } = self;
In { control, packet }
}
pub fn repr(&self) -> ip::Repr {
self.packet.repr()
}
}
impl<'a, P: PayloadMut> Out<'a, P> {
pub fn send(mut self) -> Result<()> {
let capabilities = self.control.info().capabilities();
match &mut self.packet {
IpPacket::V4(ipv4) => {
ipv4.fill_checksum(capabilities.ipv4().tx_checksum());
},
_ => (),
}
let lower = eth::OutPacket::new_unchecked(
self.control.eth,
self.packet.into_inner());
lower.send()
}
pub fn payload_mut_slice(&mut self) -> &mut [u8] {
self.packet.payload_mut().as_mut_slice()
}
}
impl<'a, P: Payload + PayloadMut> Raw<'a, P> {
pub fn control(&self) -> &Controller<'a> {
&self.control
}
pub fn prepare(mut self, init: Init) -> Result<Out<'a, P>> {
let route = self.control.route_to(init.dst_addr)?;
let lower_init = init.init_eth(route, init.payload)?;
let lower = eth::RawPacket {
control: self.control.eth,
payload: self.payload,
};
let packet = lower.prepare(lower_init)?;
let eth::InPacket { control, mut frame } = packet.into_incoming();
let repr = init.initialize(route.src_addr, &mut frame)?;
Ok(Out {
control: Controller {
eth: control,
endpoint: self.control.endpoint,
},
packet: IpPacket::new_unchecked(frame, repr),
})
}
}
impl Init {
fn initialize(&self, src_addr: ip::Address, payload: &mut impl PayloadMut) -> Result<ip::Repr> {
let repr = self.ip_repr(src_addr)?;
repr.emit(payload.payload_mut().as_mut_slice(), Checksum::Ignored);
Ok(repr)
}
fn ip_repr(&self, src_addr: ip::Address) -> Result<ip::Repr> {
let repr = ip::Repr::Unspecified {
src_addr,
dst_addr: self.dst_addr,
hop_limit: u8::max_value(),
protocol: self.protocol,
payload_len: self.payload,
};
repr.lower(&[]).ok_or(Error::Illegal)
}
fn init_eth(&self, route: EthRoute, payload: usize) -> Result<eth::Init> {
enum Protocol { Ipv4, Ipv6 }
let protocol = match self.dst_addr {
ip::Address::Ipv4(_) => Protocol::Ipv4,
ip::Address::Ipv6(_) => Protocol::Ipv6,
_ => return Err(Error::Illegal),
};
let eth_init = eth::Init {
src_addr: route.src_mac,
dst_addr: route.next_mac,
ethertype: match protocol {
Protocol::Ipv4 => ethernet::EtherType::Ipv4,
Protocol::Ipv6 => ethernet::EtherType::Ipv6,
},
payload: match protocol {
Protocol::Ipv4 => payload + 20,
Protocol::Ipv6 => payload + 40,
},
};
Ok(eth_init)
}
}
impl<'a, P: Payload> IpPacket<'a, P> {
pub fn new_unchecked(inner: ethernet::Frame<&'a mut P>, repr: ip::Repr) -> Self {
match repr {
ip::Repr::Ipv4(repr) => IpPacket::V4(ip::v4::Packet::new_unchecked(inner, repr)),
ip::Repr::Ipv6(repr) => IpPacket::V6(ip::v6::Packet::new_unchecked(inner, repr)),
_ => panic!("Unchecked must be from specific ip representation"),
}
}
pub fn repr(&self) -> ip::Repr {
match self {
IpPacket::V4(packet) => packet.repr().into(),
IpPacket::V6(packet) => packet.repr().into(),
}
}
pub fn into_inner(self) -> ethernet::Frame<&'a mut P> {
match self {
IpPacket::V4(packet) => packet.into_inner(),
IpPacket::V6(packet) => packet.into_inner(),
}
}
pub fn into_raw(self) -> &'a mut P {
self.into_inner().into_inner()
}
}
impl<'a, P: Payload> Payload for IpPacket<'a, P> {
fn payload(&self) -> &payload {
match self {
IpPacket::V4(packet) => packet.payload(),
IpPacket::V6(packet) => packet.payload(),
}
}
}
impl<'a, P: PayloadMut> PayloadMut for IpPacket<'a, P> {
fn payload_mut(&mut self) -> &mut payload {
match self {
IpPacket::V4(packet) => packet.payload_mut(),
IpPacket::V6(packet) => packet.payload_mut(),
}
}
fn resize(&mut self, length: usize) -> PayloadResult<()> {
match self {
IpPacket::V4(packet) => packet.resize(length),
IpPacket::V6(packet) => packet.resize(length),
}
}
fn reframe(&mut self, frame: Reframe) -> PayloadResult<()> {
match self {
IpPacket::V4(packet) => packet.reframe(frame),
IpPacket::V6(packet) => packet.reframe(frame),
}
}
}
impl From<ip::Address> for Source {
fn from(address: ip::Address) -> Self {
Source::Exact(address)
}
}
impl From<ip::Subnet> for Source {
fn from(subnet: ip::Subnet) -> Self {
Source::Mask { subnet, }
}
}