capsules_extra/test/
udp.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//! Capsule used for testing in-kernel port binding, sending, and receiving.
6//!
7//! This capsule takes in a src port on which to receive/send from and a dst port to send to.
8//! It binds to the src port and sends packets to the dst port. Any UDP packets received on the
9//! src port are printed to the console, along with the address/port combo they were sent from.
10//! Example use of this capsule can be found in `udp_lowpan_test.rs` in the Imix board directory.
11
12use crate::net::ipv6::ip_utils::IPAddr;
13use crate::net::network_capabilities::NetworkCapability;
14use crate::net::udp::udp_port_table::UdpPortManager;
15use crate::net::udp::udp_recv::{UDPReceiver, UDPRecvClient};
16use crate::net::udp::udp_send::{UDPSendClient, UDPSender};
17use core::cell::Cell;
18
19use kernel::debug;
20use kernel::hil::time::{self, Alarm, Frequency};
21use kernel::utilities::cells::MapCell;
22use kernel::utilities::leasable_buffer::SubSliceMut;
23use kernel::ErrorCode;
24
25pub const DST_ADDR: IPAddr = IPAddr([
26    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
27    0x1f,
28    // 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
29    // 0x0f,
30]);
31pub const PAYLOAD_LEN: usize = 192;
32pub const SEND_INTERVAL_SECONDS: u32 = 5;
33
34pub struct MockUdp<'a, A: Alarm<'a>> {
35    id: u16,
36    pub alarm: &'a A,
37    udp_sender: &'a dyn UDPSender<'a>,
38    udp_receiver: &'a UDPReceiver<'a>,
39    port_table: &'static UdpPortManager,
40    udp_dgram: MapCell<SubSliceMut<'static, u8>>,
41    src_port: Cell<u16>,
42    dst_port: Cell<u16>,
43    send_loop: Cell<bool>,
44    net_cap: Cell<&'static NetworkCapability>,
45}
46
47impl<'a, A: Alarm<'a>> MockUdp<'a, A> {
48    pub fn new(
49        id: u16,
50        alarm: &'a A,
51        udp_sender: &'a dyn UDPSender<'a>,
52        udp_receiver: &'a UDPReceiver<'a>,
53        port_table: &'static UdpPortManager,
54        udp_dgram: SubSliceMut<'static, u8>,
55        dst_port: u16,
56        net_cap: &'static NetworkCapability,
57    ) -> MockUdp<'a, A> {
58        MockUdp {
59            id,
60            alarm,
61            udp_sender,
62            udp_receiver,
63            port_table,
64            udp_dgram: MapCell::new(udp_dgram),
65            src_port: Cell::new(0), // invalid initial value
66            dst_port: Cell::new(dst_port),
67            send_loop: Cell::new(false),
68            net_cap: Cell::new(net_cap),
69        }
70    }
71
72    // starts sending packets every 5 seconds.
73    pub fn start_sending(&self) {
74        // Set alarm bc if you try to send immediately there are initialization issues
75        self.send_loop.set(true);
76        let delay = <A::Frequency>::frequency() * SEND_INTERVAL_SECONDS;
77        self.alarm
78            .set_alarm(self.alarm.now(), A::Ticks::from(delay));
79    }
80
81    pub fn update_capability(&self, new_cap: &'static NetworkCapability) {
82        self.net_cap.set(new_cap);
83    }
84
85    pub fn stop_sending(&self) {
86        let _ = self.alarm.disarm();
87    }
88
89    // Binds to passed port. If already bound to a port,
90    // unbinds currently bound to port and binds to passed port.
91    pub fn bind(&self, src_port: u16) {
92        self.src_port.set(src_port);
93        if self.udp_sender.is_bound() != self.udp_receiver.is_bound() {
94            debug!(
95                "Error: bindings should match. sender bound: {} rcvr bound: {}",
96                self.udp_sender.is_bound(),
97                self.udp_receiver.is_bound()
98            );
99        }
100        match self.udp_sender.is_bound() {
101            true => {
102                match self.port_table.unbind(
103                    self.udp_sender.get_binding().expect("missing1"),
104                    self.udp_receiver.get_binding().expect("missing2"),
105                ) {
106                    Ok(sock) => {
107                        match self
108                            .port_table
109                            .bind(sock, self.src_port.get(), self.net_cap.get())
110                        {
111                            Ok((send_bind, rcv_bind)) => {
112                                debug!("Resetting binding"); //TODO: Delete me
113                                self.udp_sender.set_binding(send_bind);
114                                self.udp_receiver.set_binding(rcv_bind);
115                            }
116                            Err(_sock) => {
117                                debug!("Binding error in mock_udp");
118                                // dropping sock destroys it!
119                            }
120                        }
121                    }
122                    Err((_send_bind, _rcv_bind)) => {
123                        debug!("TEST FAIL: attempted to unbind with mismatched bindings.");
124                    }
125                }
126            }
127            false => {
128                // Bind for the first time.
129                let socket = self.port_table.create_socket();
130                match socket {
131                    Ok(sock) => {
132                        match self
133                            .port_table
134                            .bind(sock, self.src_port.get(), self.net_cap.get())
135                        {
136                            Ok((send_bind, rcv_bind)) => {
137                                self.udp_sender.set_binding(send_bind);
138                                self.udp_receiver.set_binding(rcv_bind);
139                            }
140                            Err(_sock) => {
141                                debug!("Binding error in mock_udp (passed 0 as src_port?)");
142                                // dropping sock destroys it!
143                            }
144                        }
145                    }
146                    Err(_return_code) => {
147                        debug!("Socket error in mock_udp");
148                    }
149                }
150            }
151        }
152    }
153
154    pub fn set_dst(&self, dst_port: u16) {
155        self.dst_port.set(dst_port);
156    }
157
158    // Sends a packet containing a single 2 byte number.
159    pub fn send(&self, value: u16) -> Result<(), ErrorCode> {
160        match self.udp_dgram.take() {
161            Some(mut dgram) => {
162                dgram[0] = (value >> 8) as u8;
163                dgram[1] = (value & 0x00ff) as u8;
164                dgram.slice(0..2);
165                match self.udp_sender.send_to(
166                    DST_ADDR,
167                    self.dst_port.get(),
168                    dgram,
169                    self.net_cap.get(),
170                ) {
171                    Ok(()) => Ok(()),
172                    Err(mut buf) => {
173                        buf.reset();
174                        self.udp_dgram.replace(buf);
175                        Err(ErrorCode::RESERVE)
176                    }
177                }
178            }
179            None => {
180                debug!("ERROR: udp_dgram not present.");
181                Err(ErrorCode::FAIL)
182            }
183        }
184    }
185}
186
187impl<'a, A: Alarm<'a>> time::AlarmClient for MockUdp<'a, A> {
188    fn alarm(&self) {
189        if self.send_loop.get() {
190            let _ = self.send(self.id);
191        }
192    }
193}
194
195impl<'a, A: Alarm<'a>> UDPSendClient for MockUdp<'a, A> {
196    fn send_done(&self, result: Result<(), ErrorCode>, mut dgram: SubSliceMut<'static, u8>) {
197        debug!("Mock UDP done sending. Result: {:?}", result);
198        dgram.reset();
199        self.udp_dgram.replace(dgram);
200        debug!("");
201        let delay = <A::Frequency>::frequency() * SEND_INTERVAL_SECONDS;
202        self.alarm
203            .set_alarm(self.alarm.now(), A::Ticks::from(delay));
204    }
205}
206
207impl<'a, A: Alarm<'a>> UDPRecvClient for MockUdp<'a, A> {
208    fn receive(
209        &self,
210        src_addr: IPAddr,
211        _dst_addr: IPAddr,
212        src_port: u16,
213        _dst_port: u16,
214        payload: &[u8],
215    ) {
216        debug!(
217            "[MOCK_UDP {:?}] Received packet from {:?}:{:?}, contents: {:?}\n",
218            self.id, src_addr, src_port, payload
219        );
220    }
221}