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}