use core::convert::TryFrom;
use crate::nic::Info;
use crate::layer::{Error, Result, ip};
use crate::wire::{Payload, PayloadMut};
use crate::wire::{udp, ip::Address, ip::Protocol};
pub struct Packet<'a, P: Payload> {
pub control: Controller<'a>,
pub packet: udp::Packet<ip::IpPacket<'a, P>>,
}
pub struct RawPacket<'a, P: Payload> {
pub control: Controller<'a>,
pub payload: &'a mut P,
}
pub struct Controller<'a> {
pub(crate) inner: ip::Controller<'a>,
}
#[derive(Copy, Clone, Debug)]
pub struct Init {
pub source: ip::Source,
pub src_port: u16,
pub dst_addr: Address,
pub dst_port: u16,
pub payload: usize,
}
impl<'a> Controller<'a> {
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> Packet<'a, P> {
pub fn reinit(self, init: Init) -> Result<Packet<'a, P>>
where P: PayloadMut
{
self.deinit().prepare(init)
}
pub fn info(&self) -> &dyn Info {
self.control.info()
}
pub fn deinit(self) -> RawPacket<'a, P>
where P: PayloadMut,
{
RawPacket {
control: self.control,
payload: self.packet.into_inner().into_raw()
}
}
pub fn send(mut self) -> Result<()>
where P: PayloadMut,
{
let capabilities = self.control.info().capabilities();
let ip_repr = self.packet.get_ref().repr();
let checksum = capabilities.udp().tx_checksum(ip_repr);
self.packet.fill_checksum(checksum);
let lower = ip::OutPacket::new_unchecked(
self.control.inner,
self.packet.into_inner());
lower.send()
}
}
impl<'a, P: Payload + PayloadMut> RawPacket<'a, P> {
pub fn info(&self) -> &dyn Info {
self.control.info()
}
pub fn prepare(self, init: Init) -> Result<Packet<'a, P>> {
let lower = ip::RawPacket {
control: self.control.inner,
payload: self.payload,
};
let packet_len = init.payload
.checked_add(8)
.ok_or(Error::BadSize)?;
let lower_init = ip::Init {
source: init.source,
dst_addr: init.dst_addr,
protocol: Protocol::Udp,
payload: packet_len,
};
let prepared = lower.prepare(lower_init)?;
let ip::InPacket { control, mut packet } = prepared.into_incoming();
let repr = init.initialize(&mut packet)?;
let control = Controller { inner: control };
Ok(Packet {
control,
packet: udp::Packet::new_unchecked(packet, repr),
})
}
}
impl Init {
fn initialize(&self, payload: &mut impl PayloadMut) -> Result<udp::Repr> {
let repr = udp::Repr {
src_port: self.src_port,
dst_port: self.dst_port,
length: u16::try_from(self.payload + 8)
.map_err(|_| Error::BadSize)?,
};
let packet = udp::packet::new_unchecked_mut(
payload.payload_mut().as_mut_slice());
repr.emit(packet, udp::Checksum::Ignored);
Ok(repr)
}
}