use crate::nic;
use crate::layer::{Error, Result};
use crate::wire::{ethernet, Payload, PayloadResult, PayloadMut, PayloadMutExt, Reframe, ReframePayload, payload};
pub struct In<'a, P: Payload> {
pub control: Controller<'a>,
pub frame: ethernet::Frame<&'a mut 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>,
frame: 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) nic_handle: &'a mut dyn nic::Handle,
pub(crate) endpoint: &'a mut dyn Endpoint,
}
pub struct Init {
pub src_addr: ethernet::Address,
pub dst_addr: ethernet::Address,
pub ethertype: ethernet::EtherType,
pub payload: usize,
}
pub(crate) trait Endpoint{
fn src_addr(&mut self) -> 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 nic_handle = wrap(self.nic_handle);
Controller { nic_handle, endpoint: self.endpoint }
}
pub fn borrow_mut(&mut self) -> Controller {
Controller {
nic_handle: self.nic_handle,
endpoint: self.endpoint,
}
}
pub fn info(&self) -> &dyn nic::Info {
self.nic_handle.info()
}
pub fn src_addr(&mut self) -> ethernet::Address {
self.endpoint.src_addr()
}
pub fn send(&mut self) -> Result<()> {
self.nic_handle.queue()
}
}
impl<'a, P: Payload> In<'a, P> {
pub fn deinit(self) -> Raw<'a, P>
where P: PayloadMut,
{
Raw {
control: self.control,
payload: self.frame.into_inner(),
}
}
}
impl<'a, P: PayloadMut> In<'a, P> {
pub fn reinit(self, init: Init) -> Result<Out<'a, P>> {
let In { control, frame } = self;
let new_len = ethernet::frame::buffer_len(init.payload);
let new_repr = ethernet::Repr {
src_addr: init.src_addr,
dst_addr: init.dst_addr,
ethertype: init.ethertype,
};
let raw_repr = frame.repr();
let raw_buffer = frame.into_inner();
let raw_len = raw_buffer.payload().len();
let raw_payload = raw_len - raw_repr.header_len();
let payload = init.payload.min(raw_payload);
let old_payload = raw_len - payload..raw_len;
let new_payload = new_len - payload..new_len;
raw_buffer.reframe_payload(ReframePayload {
length: new_len,
old_payload,
new_payload,
})?;
new_repr.emit(ethernet::frame::new_unchecked_mut(raw_buffer.payload_mut()));
let frame = ethernet::Frame::new_unchecked(raw_buffer, new_repr);
Ok(Out {
control,
frame,
})
}
}
impl<'a, P: Payload> Out<'a, P> {
pub fn new_unchecked(
control: Controller<'a>,
frame: ethernet::Frame<&'a mut P>) -> Self
{
Out{ control, frame, }
}
pub fn into_incoming(self) -> In<'a, P> {
let Out { control, frame } = self;
In { control, frame }
}
pub fn into_raw(self) -> Raw<'a, P> {
let Out { control, frame } = self;
Raw { control, payload: frame.into_inner() }
}
pub fn send(mut self) -> Result<()> {
self.control.send()
}
}
impl<'a, P: PayloadMut> Out<'a, P> {
pub fn payload_mut_slice(&mut self) -> &mut [u8] {
self.frame.payload_mut_slice()
}
}
impl<'a, P: Payload + PayloadMut> Raw<'a, P> {
pub fn prepare(self, init: Init) -> Result<Out<'a, P>> {
let mut payload = self.payload;
let repr = init.initialize(&mut payload)?;
Ok(Out {
control: self.control,
frame: ethernet::Frame::new_unchecked(payload, repr),
})
}
}
impl<P: Payload> Payload for Out<'_, P> {
fn payload(&self) -> &payload {
self.frame.payload()
}
}
impl<P: PayloadMut> PayloadMut for Out<'_, P> {
fn payload_mut(&mut self) -> &mut payload {
self.frame.payload_mut()
}
fn resize(&mut self, length: usize) -> PayloadResult<()> {
self.frame.resize(length)
}
fn reframe(&mut self, frame: Reframe) -> PayloadResult<()> {
self.frame.reframe(frame)
}
}
impl Init {
fn initialize<P: PayloadMut>(&self, payload: &mut P) -> Result<ethernet::Repr> {
let real_len = ethernet::frame::buffer_len(self.payload);
let repr = ethernet::Repr {
src_addr: self.src_addr,
dst_addr: self.dst_addr,
ethertype: self.ethertype,
};
payload.resize(real_len)?;
let ethernet = ethernet::frame::new_unchecked_mut(payload.payload_mut());
ethernet.check_len()
.map_err(|_| Error::BadSize)?;
repr.emit(ethernet);
Ok(repr)
}
}