capsules_extra/net/udp/
udp_recv.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 the UDP reception interface.
6//!
7//! It follows the same virtualization model as that described in
8//! `udp_send.rs`, except that no queueing is needed because received
9//! packets are immediately dispatched to the appropriate capsule /
10//! app. Once again, port binding for userspace apps is managed
11//! separately by the UDP userspace driver, which must correctly check
12//! bindings of kernel apps to ensure correctness when dispatching
13//! received packets to the appropriate client.
14
15use crate::net::ipv6::ip_utils::IPAddr;
16use crate::net::ipv6::ipv6_recv::IP6RecvClient;
17use crate::net::ipv6::IP6Header;
18use crate::net::udp::driver::UDPDriver;
19use crate::net::udp::udp_port_table::{PortQuery, UdpPortBindingRx};
20use crate::net::udp::UDPHeader;
21
22use kernel::collections::list::{List, ListLink, ListNode};
23use kernel::debug;
24use kernel::utilities::cells::{MapCell, OptionalCell};
25
26pub struct MuxUdpReceiver<'a> {
27    rcvr_list: List<'a, UDPReceiver<'a>>,
28    driver: OptionalCell<&'static UDPDriver<'static>>,
29}
30
31impl<'a> MuxUdpReceiver<'a> {
32    pub fn new() -> MuxUdpReceiver<'a> {
33        MuxUdpReceiver {
34            rcvr_list: List::new(),
35            driver: OptionalCell::empty(),
36        }
37    }
38
39    pub fn add_client(&self, rcvr: &'a UDPReceiver<'a>) {
40        self.rcvr_list.push_tail(rcvr);
41    }
42
43    pub fn set_driver(&self, driver_ref: &'static UDPDriver) {
44        self.driver.replace(driver_ref);
45    }
46}
47
48impl IP6RecvClient for MuxUdpReceiver<'_> {
49    fn receive(&self, ip_header: IP6Header, payload: &[u8]) {
50        match UDPHeader::decode(payload).done() {
51            Some((offset, udp_header)) => {
52                let len = udp_header.get_len() as usize;
53                let dst_port = udp_header.get_dst_port();
54                if len > payload.len() {
55                    debug!("[UDP_RECV] Error: Received UDP length too long");
56                    return;
57                }
58                for rcvr in self.rcvr_list.iter() {
59                    match rcvr.binding.take() {
60                        Some(binding) => {
61                            if binding.get_port() == dst_port {
62                                rcvr.client.map(|client| {
63                                    client.receive(
64                                        ip_header.get_src_addr(),
65                                        ip_header.get_dst_addr(),
66                                        udp_header.get_src_port(),
67                                        udp_header.get_dst_port(),
68                                        &payload[offset..],
69                                    );
70                                });
71                                rcvr.binding.replace(binding);
72                                break;
73                            }
74                            rcvr.binding.replace(binding);
75                        }
76                        // The UDPReceiver used by the driver will not have a binding
77                        None => match self.driver.take() {
78                            Some(driver) => {
79                                if driver.is_bound(dst_port) {
80                                    driver.receive(
81                                        ip_header.get_src_addr(),
82                                        ip_header.get_dst_addr(),
83                                        udp_header.get_src_port(),
84                                        udp_header.get_dst_port(),
85                                        &payload[offset..],
86                                    );
87                                    self.driver.replace(driver);
88                                    break;
89                                }
90                                self.driver.replace(driver);
91                            }
92                            None => {}
93                        },
94                    }
95                }
96            }
97            None => {}
98        }
99    }
100}
101
102/// Client interface trait to receive UDP packets.
103///
104/// Intended to received packets passed up the network stack to the
105/// UDPReceiver, and then distributes them to userland applications
106/// from there.  Kernel apps can also instantiate structs that
107/// implement this trait in order to receive UDP packets
108pub trait UDPRecvClient {
109    fn receive(
110        &self,
111        src_addr: IPAddr,
112        dst_addr: IPAddr,
113        src_port: u16,
114        dst_port: u16,
115        payload: &[u8],
116    );
117}
118
119/// This struct is set as the client of the MuxUdpReceiver, and passes
120/// received packets up to whatever app layer client assigns itself
121/// as the UDPRecvClient held by this UDPReceiver.
122pub struct UDPReceiver<'a> {
123    client: OptionalCell<&'a dyn UDPRecvClient>,
124    binding: MapCell<UdpPortBindingRx>,
125    next: ListLink<'a, UDPReceiver<'a>>,
126}
127
128impl<'a> ListNode<'a, UDPReceiver<'a>> for UDPReceiver<'a> {
129    fn next(&'a self) -> &'a ListLink<'a, UDPReceiver<'a>> {
130        &self.next
131    }
132}
133
134impl<'a> UDPReceiver<'a> {
135    pub fn new() -> UDPReceiver<'a> {
136        UDPReceiver {
137            client: OptionalCell::empty(),
138            binding: MapCell::empty(),
139            next: ListLink::empty(),
140        }
141    }
142
143    pub fn set_client(&self, client: &'a dyn UDPRecvClient) {
144        self.client.set(client);
145    }
146
147    pub fn get_binding(&self) -> Option<UdpPortBindingRx> {
148        self.binding.take()
149    }
150
151    pub fn is_bound(&self) -> bool {
152        self.binding.is_some()
153    }
154
155    pub fn set_binding(&self, binding: UdpPortBindingRx) -> Option<UdpPortBindingRx> {
156        self.binding.replace(binding)
157    }
158}