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}