capsules_extra/net/udp/udp_send.rs
1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Definition and implementation for a virtualized UDP sending
6//! interface.
7//!
8//! The [UDPSender](trait.UDPSender.html) trait provides
9//! an interface for kernel capsules to send a UDP packet, and the
10//! [UDPSendClient](trait.UDPSendClient.html) trait is implemented by
11//! upper layer clients to allow them to receive `send_done` callbacks once
12//! transmission has completed.
13//!
14//! In order to virtualize between both apps and kernel capsules, this
15//! file uses a MuxUdpSender which treats the userspace UDP driver as
16//! a kernel capsule with a special capability that allows it to bind
17//! to arbitrary ports. Therefore the correctness of port binding /
18//! packet transmission/delivery is also dependent on the port binding
19//! logic in the driver being correct.
20//!
21//! The MuxUdpSender acts as a FIFO queue for transmitted packets,
22//! with each capsule being allowed a single outstanding / unsent
23//! packet at a time.
24//!
25//! Because the userspace driver is viewed by the MuxUdpSender as
26//! being a single capsule, the userspace driver must queue app
27//! packets on its own, as it can only pass a single packet to the
28//! MuxUdpSender queue at a time.
29
30use crate::net::ipv6::ip_utils::IPAddr;
31use crate::net::ipv6::ipv6_send::{IP6SendClient, IP6Sender};
32use crate::net::ipv6::TransportHeader;
33use crate::net::network_capabilities::{NetworkCapability, UdpVisibilityCapability};
34use crate::net::udp::udp_port_table::UdpPortBindingTx;
35use crate::net::udp::UDPHeader;
36
37use core::cell::Cell;
38
39use kernel::capabilities::UdpDriverCapability;
40use kernel::collections::list::{List, ListLink, ListNode};
41use kernel::debug;
42use kernel::utilities::cells::{MapCell, OptionalCell};
43use kernel::utilities::leasable_buffer::SubSliceMut;
44use kernel::ErrorCode;
45
46pub struct MuxUdpSender<'a, T: IP6Sender<'a>> {
47 sender_list: List<'a, UDPSendStruct<'a, T>>,
48 ip_sender: &'a dyn IP6Sender<'a>,
49}
50
51impl<'a, T: IP6Sender<'a>> MuxUdpSender<'a, T> {
52 pub fn new(ip6_sender: &'a dyn IP6Sender<'a>) -> MuxUdpSender<'a, T> {
53 // similar to UdpSendStruct new()
54 MuxUdpSender {
55 sender_list: List::new(),
56 ip_sender: ip6_sender,
57 }
58 }
59
60 fn send_to(
61 &self,
62 dest: IPAddr,
63 transport_header: TransportHeader,
64 caller: &'a UDPSendStruct<'a, T>,
65 net_cap: &'static NetworkCapability,
66 ) -> Result<(), ErrorCode> {
67 // Add this sender to the tail of the sender_list
68 let list_empty = self.sender_list.head().is_none();
69 self.add_client(caller);
70 let mut ret = Ok(());
71 // If list empty, initiate send immediately, and return result.
72 // Otherwise, packet is queued.
73 if list_empty {
74 ret = match caller.tx_buffer.take() {
75 Some(buf) => {
76 let ret = self
77 .ip_sender
78 .send_to(dest, transport_header, &buf, net_cap);
79 caller.tx_buffer.replace(buf); //Replace buffer as soon as sent.
80 ret
81 }
82 None => {
83 debug!("No buffer available to take.");
84 Err(ErrorCode::FAIL)
85 }
86 }
87 } else {
88 caller.net_cap.replace(net_cap); //store capability with sender
89 }
90 ret
91 }
92
93 fn add_client(&self, sender: &'a UDPSendStruct<'a, T>) {
94 self.sender_list.push_tail(sender);
95 }
96}
97
98/// This function implements the `IP6SendClient` trait for the `UDPSendStruct`,
99/// and is necessary to receive callbacks from the lower (IP) layer. When
100/// the UDP layer receives this callback, it forwards it to the `UDPSendClient`.
101impl<'a, T: IP6Sender<'a>> IP6SendClient for MuxUdpSender<'a, T> {
102 fn send_done(&self, result: Result<(), ErrorCode>) {
103 let last_sender = self.sender_list.pop_head();
104 let next_sender_option = self.sender_list.head(); // must check here, because udp driver
105 // could queue addl. sends in response to
106 // send_done.
107 last_sender.map(|last_sender| {
108 last_sender
109 .client
110 .map(|client| match last_sender.tx_buffer.take() {
111 Some(buf) => {
112 client.send_done(result, buf);
113 }
114 None => {
115 debug!("ERROR: Missing buffer in send done.");
116 }
117 })
118 });
119
120 let success = match next_sender_option {
121 Some(next_sender) => {
122 //send next packet in queue
123 match next_sender.tx_buffer.take() {
124 Some(buf) => match next_sender.next_th.take() {
125 Some(th) => match next_sender.net_cap.take() {
126 Some(net_cap) => {
127 let ret = self.ip_sender.send_to(
128 next_sender.next_dest.get(),
129 th,
130 &buf,
131 net_cap,
132 );
133 next_sender.tx_buffer.replace(buf);
134 if ret != Ok(()) {
135 debug!("IP send_to failed: {:?}", ret);
136 }
137 ret
138 }
139 None => Err(ErrorCode::FAIL),
140 },
141 None => {
142 debug!("Missing transport header.");
143 Err(ErrorCode::FAIL)
144 }
145 },
146 None => {
147 debug!("No buffer available to take.");
148 Err(ErrorCode::FAIL)
149 }
150 }
151 }
152 None => Ok(()), //No more packets queued.
153 };
154 if success != Ok(()) {
155 debug!("Error in udp_send send_done() callback.");
156 }
157 }
158}
159
160/// The `send_done` function in this trait is invoked after the UDPSender
161/// has completed sending the requested packet. Note that the
162/// `UDPSender::set_client` method must be called to set the client.
163pub trait UDPSendClient {
164 fn send_done(&self, result: Result<(), ErrorCode>, dgram: SubSliceMut<'static, u8>);
165}
166
167/// This trait represents the bulk of the UDP functionality.
168///
169/// The two variants of sending a packet (either via the `send_to` or
170/// `send` methods) represent whether the caller wants to construct a
171/// custom `UDPHeader` or not. Calling `send_to` tells the UDP layer
172/// to construct a default `UDPHeader` and forward the payload to the
173/// respective destination and port.
174pub trait UDPSender<'a> {
175 /// This function sets the client for the `UDPSender` instance
176 ///
177 /// # Arguments
178 /// `client` - Implementation of `UDPSendClient` to be set as the client
179 /// for the `UDPSender` instance
180 fn set_client(&self, client: &'a dyn UDPSendClient);
181
182 /// This function constructs a `UDPHeader` and sends the payload to the
183 /// provided destination IP address and
184 /// destination port from the src port contained in the UdpPortBindingTx.
185 ///
186 /// # Arguments
187 /// `dest` - IPv6 address to send the UDP packet to
188 /// `dst_port` - Destination port to send the packet to
189 /// `buf` - UDP payload
190 /// `binding` - type that specifies what port the sender is bound to.
191 ///
192 /// # Return Value
193 /// Any synchronous errors are returned via the returned `Result<(), ErrorCode>`
194 /// value; asynchronous errors are delivered via the callback.
195 fn send_to(
196 &'a self,
197 dest: IPAddr,
198 dst_port: u16,
199 //src_port: u16,
200 buf: SubSliceMut<'static, u8>,
201 net_cap: &'static NetworkCapability,
202 ) -> Result<(), SubSliceMut<'static, u8>>;
203
204 /// This function is identical to `send_to()` except that it takes in
205 /// an explicit src_port instead of a binding. This allows it to be used
206 /// by the userspace driver, above which apps are bound to multiple ports
207 ///
208 /// # Arguments
209 /// `dest` - IPv6 address to send the UDP packet to
210 /// `dst_port` - Destination port to send the packet to
211 /// `src_port` - Port to send the packet from
212 /// `buf` - UDP payload
213 ///
214 /// # Return Value
215 /// Any synchronous errors are returned via the returned `Result<(), ErrorCode>`
216 /// value; asynchronous errors are delivered via the callback.
217 fn driver_send_to(
218 &'a self,
219 dest: IPAddr,
220 dst_port: u16,
221 src_port: u16,
222 buf: SubSliceMut<'static, u8>,
223 driver_send_cap: &dyn UdpDriverCapability,
224 net_cap: &'static NetworkCapability,
225 ) -> Result<(), SubSliceMut<'static, u8>>;
226
227 /// This function constructs an IP packet from the completed `UDPHeader`
228 /// and buffer, and sends it to the provided IP address
229 ///
230 /// # Arguments
231 /// `dest` - IP address to send the UDP packet to
232 /// `udp_header` - Completed UDP header to be sent to the destination
233 /// `buf` - A byte array containing the UDP payload
234 ///
235 /// # Return Value
236 /// Returns any synchronous errors or success. Note that any asynchrounous
237 /// errors are returned via the callback.
238 fn send(
239 &'a self,
240 dest: IPAddr,
241 udp_header: UDPHeader,
242 buf: SubSliceMut<'static, u8>,
243 net_cap: &'static NetworkCapability,
244 ) -> Result<(), SubSliceMut<'static, u8>>;
245
246 fn get_binding(&self) -> Option<UdpPortBindingTx>;
247
248 fn is_bound(&self) -> bool;
249
250 fn set_binding(&self, binding: UdpPortBindingTx) -> Option<UdpPortBindingTx>;
251}
252
253/// This is a specific instantiation of the `UDPSender` trait. Note
254/// that this struct contains a reference to an `IP6Sender` which it
255/// forwards packets to (and receives callbacks from).
256pub struct UDPSendStruct<'a, T: IP6Sender<'a>> {
257 udp_mux_sender: &'a MuxUdpSender<'a, T>,
258 client: OptionalCell<&'a dyn UDPSendClient>,
259 next: ListLink<'a, UDPSendStruct<'a, T>>,
260 tx_buffer: MapCell<SubSliceMut<'static, u8>>,
261 next_dest: Cell<IPAddr>,
262 next_th: OptionalCell<TransportHeader>,
263 binding: MapCell<UdpPortBindingTx>,
264 udp_vis: &'static UdpVisibilityCapability,
265 net_cap: OptionalCell<&'static NetworkCapability>,
266}
267
268impl<'a, T: IP6Sender<'a>> ListNode<'a, UDPSendStruct<'a, T>> for UDPSendStruct<'a, T> {
269 fn next(&'a self) -> &'a ListLink<'a, UDPSendStruct<'a, T>> {
270 &self.next
271 }
272}
273
274/// Below is the implementation of the `UDPSender` traits for the
275/// `UDPSendStruct`.
276impl<'a, T: IP6Sender<'a>> UDPSender<'a> for UDPSendStruct<'a, T> {
277 fn set_client(&self, client: &'a dyn UDPSendClient) {
278 self.client.set(client);
279 }
280
281 fn send_to(
282 &'a self,
283 dest: IPAddr,
284 dst_port: u16,
285 buf: SubSliceMut<'static, u8>,
286 net_cap: &'static NetworkCapability,
287 ) -> Result<(), SubSliceMut<'static, u8>> {
288 let mut udp_header = UDPHeader::new();
289 udp_header.set_dst_port(dst_port);
290 match self.binding.take() {
291 Some(binding) => {
292 if !net_cap.remote_port_valid(dst_port, self.udp_vis)
293 || !net_cap.local_port_valid(binding.get_port(), self.udp_vis)
294 {
295 self.binding.replace(binding);
296 Err(buf)
297 } else if binding.get_port() == 0 {
298 self.binding.replace(binding);
299 Err(buf)
300 } else {
301 udp_header.set_src_port(binding.get_port());
302 self.binding.replace(binding);
303 self.send(dest, udp_header, buf, net_cap)
304 }
305 }
306 None => Err(buf),
307 }
308 }
309
310 // TODO: different capabilities for driver_send_to?
311 fn driver_send_to(
312 &'a self,
313 dest: IPAddr,
314 dst_port: u16,
315 src_port: u16,
316 buf: SubSliceMut<'static, u8>,
317 _driver_send_cap: &dyn UdpDriverCapability,
318 net_cap: &'static NetworkCapability,
319 ) -> Result<(), SubSliceMut<'static, u8>> {
320 let mut udp_header = UDPHeader::new();
321 udp_header.set_dst_port(dst_port);
322 udp_header.set_src_port(src_port);
323 self.send(dest, udp_header, buf, net_cap)
324 }
325
326 fn send(
327 &'a self,
328 dest: IPAddr,
329 mut udp_header: UDPHeader,
330 buf: SubSliceMut<'static, u8>,
331 net_cap: &'static NetworkCapability,
332 ) -> Result<(), SubSliceMut<'static, u8>> {
333 udp_header.set_len((buf.len() + udp_header.get_hdr_size()) as u16);
334 let transport_header = TransportHeader::UDP(udp_header);
335 self.tx_buffer.replace(buf);
336 self.next_dest.replace(dest);
337 self.next_th.replace(transport_header); // th = transport header
338 match self
339 .udp_mux_sender
340 .send_to(dest, transport_header, self, net_cap)
341 {
342 Ok(()) => Ok(()),
343 _ => Err(self.tx_buffer.take().unwrap()),
344 }
345 }
346
347 fn get_binding(&self) -> Option<UdpPortBindingTx> {
348 self.binding.take()
349 }
350
351 fn is_bound(&self) -> bool {
352 self.binding.is_some()
353 }
354
355 fn set_binding(&self, binding: UdpPortBindingTx) -> Option<UdpPortBindingTx> {
356 self.binding.replace(binding)
357 }
358}
359
360impl<'a, T: IP6Sender<'a>> UDPSendStruct<'a, T> {
361 pub fn new(
362 udp_mux_sender: &'a MuxUdpSender<'a, T>, /*binding: UdpPortBindingTx*/
363 udp_vis: &'static UdpVisibilityCapability,
364 ) -> UDPSendStruct<'a, T> {
365 UDPSendStruct {
366 udp_mux_sender,
367 client: OptionalCell::empty(),
368 next: ListLink::empty(),
369 tx_buffer: MapCell::empty(),
370 next_dest: Cell::new(IPAddr::new()),
371 next_th: OptionalCell::empty(),
372 binding: MapCell::empty(),
373 udp_vis,
374 net_cap: OptionalCell::empty(),
375 }
376 }
377}