ethox/layer/udp/
packet.rs

1use core::convert::TryFrom;
2
3use crate::nic::Info;
4use crate::layer::{Error, Result, ip};
5use crate::wire::{Payload, PayloadMut};
6use crate::wire::{udp, ip::Address, ip::Protocol};
7
8/// An incoming UDP packet.
9pub struct Packet<'a, P: Payload> {
10    /// A reference to the UDP endpoint state.
11    pub control: Controller<'a>,
12    /// The valid packet inside the buffer.
13    pub packet: udp::Packet<ip::IpPacket<'a, P>>,
14}
15
16/// A buffer for an outgoing UDP packet.
17pub struct RawPacket<'a, P: Payload> {
18    /// A reference to the UDP endpoint state.
19    pub control: Controller<'a>,
20    /// A mutable reference to the payload buffer.
21    pub payload: &'a mut P,
22}
23
24/// A reference to the endpoint of layers below (phy + eth + ip + udp).
25///
26/// This is not really useful on its own but should instead be used either within a `Packet` or a
27/// `RawPacket`. Some of the methods offered there will access the non-public members of this
28/// struct to fulfill their task.
29pub struct Controller<'a> {
30    pub(crate) inner: ip::Controller<'a>,
31}
32
33/// An initializer for a UDP packet.
34///
35/// This is used to prepare a `RawPacket`, filling in the header structures. Afterwards, the
36/// payload is accessible as a mutable slice and can be inserted. Lastly, the packet is sent.
37///
38/// ## Example
39///
40/// Here a function initializing and sending simple raw packet with a payload of `Hello, world!`.
41///
42/// ```
43/// use ethox::managed::Partial;
44/// use ethox::layer::{ip, udp, Result};
45/// use ethox::wire::ip::Address;
46///
47/// const HELLO: &[u8] = b"Hello, world!";
48///
49/// fn greet(raw: udp::RawPacket<Partial<&mut [u8]>>) -> Result<()> {
50///     let init = udp::Init {
51///         source: ip::Source::Exact(Address::v4(192, 168, 0, 20)),
52///         src_port: 9400,
53///         dst_addr: Address::v4(192, 168, 0, 1),
54///         dst_port: 43,
55///         payload: HELLO.len(),
56///     };
57///
58///     let mut out = raw.prepare(init)?;
59///     out.packet
60///         .payload_mut_slice()
61///         .copy_from_slice(HELLO);
62///     out.send()
63/// }
64/// ```
65#[derive(Copy, Clone, Debug)]
66pub struct Init {
67    /// The sender ip selection, passed directly to the ip layer below.
68    pub source: ip::Source,
69    /// The source port to use on the local machine.
70    pub src_port: u16,
71    /// The destination address of the packet.
72    pub dst_addr: Address,
73    /// The destination port of the packet.
74    pub dst_port: u16,
75    /// The length of the payload which is sent.
76    pub payload: usize,
77}
78
79impl<'a> Controller<'a> {
80    /// Get the hardware info for that packet.
81    pub fn info(&self) -> &dyn Info {
82        self.inner.info()
83    }
84
85    /// Proof to the compiler that we can shorten the lifetime arbitrarily.
86    pub fn borrow_mut(&mut self) -> Controller {
87        Controller {
88            inner: self.inner.borrow_mut(),
89        }
90    }
91}
92
93impl<'a, P: Payload> Packet<'a, P> {
94    /// Reinitialize the buffer with a packet generated by the library.
95    pub fn reinit(self, init: Init) -> Result<Packet<'a, P>>
96        where P: PayloadMut
97    {
98        // TODO: optimize this? If the previous headers have correct sizes, do not overwrite the
99        // contents of the packet and sparsely update fields.
100        self.deinit().prepare(init)
101    }
102
103    /// Get the hardware info for that packet.
104    pub fn info(&self) -> &dyn Info {
105        self.control.info()
106    }
107
108    /// Unwrap the raw packet buffer.
109    ///
110    /// This does not modify the contents of the buffer but it will drop the state derived from
111    /// parsing the different packet layers.
112    pub fn deinit(self) -> RawPacket<'a, P>
113        where P: PayloadMut,
114    {
115        RawPacket {
116            control: self.control,
117            payload: self.packet.into_inner().into_raw()
118        }
119    }
120
121    /// Called last after having initialized the payload.
122    ///
123    /// Finalizes and queues the packet.
124    pub fn send(mut self) -> Result<()>
125        where P: PayloadMut,
126    {
127        let capabilities = self.control.info().capabilities();
128        let ip_repr = self.packet.get_ref().repr();
129        let checksum = capabilities.udp().tx_checksum(ip_repr);
130        self.packet.fill_checksum(checksum);
131        let lower = ip::OutPacket::new_unchecked(
132            self.control.inner,
133            self.packet.into_inner());
134        lower.send()
135    }
136}
137
138impl<'a, P: Payload + PayloadMut> RawPacket<'a, P> {
139    /// Get the hardware info for that packet.
140    pub fn info(&self) -> &dyn Info {
141        self.control.info()
142    }
143
144    /// Initialize to a valid ip packet.
145    pub fn prepare(self, init: Init) -> Result<Packet<'a, P>> {
146        let lower = ip::RawPacket {
147            control: self.control.inner,
148            payload: self.payload,
149        };
150
151        let packet_len = init.payload
152            .checked_add(8)
153            .ok_or(Error::BadSize)?;
154
155        let lower_init = ip::Init {
156            source: init.source,
157            dst_addr: init.dst_addr,
158            protocol: Protocol::Udp,
159            payload: packet_len,
160        };
161
162        let prepared = lower.prepare(lower_init)?;
163        let ip::InPacket { control, mut packet } = prepared.into_incoming();
164        let repr = init.initialize(&mut packet)?;
165
166        // Reconstruct the control.
167        let control = Controller { inner: control };
168
169        Ok(Packet {
170            control,
171            packet: udp::Packet::new_unchecked(packet, repr),
172        })
173    }
174}
175
176impl Init {
177    fn initialize(&self, payload: &mut impl PayloadMut) -> Result<udp::Repr> {
178        let repr = udp::Repr {
179            src_port: self.src_port,
180            dst_port: self.dst_port,
181            // Can't overflow, already inited ip with that length.
182            length: u16::try_from(self.payload + 8)
183                .map_err(|_| Error::BadSize)?,
184        };
185
186        // Assumes length was already dealt with.
187        let packet = udp::packet::new_unchecked_mut(
188            payload.payload_mut().as_mut_slice());
189        repr.emit(packet, udp::Checksum::Ignored);
190
191        Ok(repr)
192    }
193}