imix/test/
icmp_lowpan_test.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//! `icmp_lowpan_test.rs`: Test kernel space sending of
6//! ICMP packets over 6LoWPAN
7//!
8//! Currently this file only tests sending messages.
9//!
10//! To use this test suite, simply call the `run` function.
11//! Insert the code into `boards/imix/src/main.rs` as follows:
12//!
13//!```rust
14//! test::icmp_lowpan_test::run(mux_mac, mux_alarm);
15//! ```
16
17use capsules_extra::ieee802154::device::MacDevice;
18use capsules_extra::net::icmpv6::icmpv6_send::{ICMP6SendStruct, ICMP6Sender};
19use capsules_extra::net::icmpv6::{ICMP6Header, ICMP6Type};
20use capsules_extra::net::ieee802154::MacAddress;
21use capsules_extra::net::ipv6::ip_utils::IPAddr;
22use capsules_extra::net::ipv6::ipv6_send::{IP6SendStruct, IP6Sender};
23use capsules_extra::net::ipv6::{IP6Packet, IPPayload, TransportHeader};
24use capsules_extra::net::network_capabilities::{
25    AddrRange, IpVisibilityCapability, NetworkCapability, PortRange,
26};
27use capsules_extra::net::sixlowpan::sixlowpan_compression;
28use capsules_extra::net::sixlowpan::sixlowpan_state::{Sixlowpan, SixlowpanState, TxState};
29use kernel::ErrorCode;
30
31use capsules_core::virtualizers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};
32use core::cell::Cell;
33use core::ptr::addr_of_mut;
34use kernel::capabilities::NetworkCapabilityCreationCapability;
35use kernel::create_capability;
36use kernel::debug;
37use kernel::hil::radio;
38use kernel::hil::time::{self, Alarm, ConvertTicks};
39use kernel::static_init;
40
41pub const SRC_ADDR: IPAddr = IPAddr([
42    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
43]);
44pub const DST_ADDR: IPAddr = IPAddr([
45    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
46]);
47
48/* 6LoWPAN Constants */
49const DEFAULT_CTX_PREFIX_LEN: u8 = 8;
50static DEFAULT_CTX_PREFIX: [u8; 16] = [0x0_u8; 16];
51static mut RX_STATE_BUF: [u8; 1280] = [0x0; 1280];
52const DST_MAC_ADDR: MacAddress = MacAddress::Short(0x802);
53const SRC_MAC_ADDR: MacAddress = MacAddress::Short(0xf00f);
54
55pub const TEST_DELAY_MS: u32 = 10000;
56pub const TEST_LOOP: bool = false;
57
58static mut ICMP_PAYLOAD: [u8; 10] = [0; 10];
59
60pub static mut RF233_BUF: [u8; radio::MAX_BUF_SIZE] = [0_u8; radio::MAX_BUF_SIZE];
61
62//Use a global variable option, initialize as None, then actually initialize in initialize all
63
64pub struct LowpanICMPTest<'a, A: time::Alarm<'a>> {
65    alarm: &'a A,
66    test_counter: Cell<usize>,
67    icmp_sender: &'a dyn ICMP6Sender<'a>,
68    net_cap: &'static NetworkCapability,
69}
70
71type Rf233 = capsules_extra::rf233::RF233<
72    'static,
73    capsules_core::virtualizers::virtual_spi::VirtualSpiMasterDevice<
74        'static,
75        sam4l::spi::SpiHw<'static>,
76    >,
77>;
78type Ieee802154MacDevice =
79    components::ieee802154::Ieee802154ComponentMacDeviceType<Rf233, sam4l::aes::Aes<'static>>;
80
81pub unsafe fn run(
82    mux_mac: &'static capsules_extra::ieee802154::virtual_mac::MuxMac<'static, Ieee802154MacDevice>,
83    mux_alarm: &'static MuxAlarm<'static, sam4l::ast::Ast>,
84) {
85    let create_cap = create_capability!(NetworkCapabilityCreationCapability);
86    let net_cap = static_init!(
87        NetworkCapability,
88        NetworkCapability::new(AddrRange::Any, PortRange::Any, PortRange::Any, &create_cap)
89    );
90    let ip_vis = static_init!(
91        IpVisibilityCapability,
92        IpVisibilityCapability::new(&create_cap)
93    );
94    let radio_mac = static_init!(
95        capsules_extra::ieee802154::virtual_mac::MacUser<'static, Ieee802154MacDevice>,
96        capsules_extra::ieee802154::virtual_mac::MacUser::new(mux_mac)
97    );
98    mux_mac.add_user(radio_mac);
99    let ipsender_virtual_alarm = static_init!(
100        VirtualMuxAlarm<'static, sam4l::ast::Ast>,
101        VirtualMuxAlarm::new(mux_alarm)
102    );
103    ipsender_virtual_alarm.setup();
104
105    let sixlowpan = static_init!(
106        Sixlowpan<
107            'static,
108            VirtualMuxAlarm<sam4l::ast::Ast<'static>>,
109            sixlowpan_compression::Context,
110        >,
111        Sixlowpan::new(
112            sixlowpan_compression::Context {
113                prefix: DEFAULT_CTX_PREFIX,
114                prefix_len: DEFAULT_CTX_PREFIX_LEN,
115                id: 0,
116                compress: false,
117            },
118            ipsender_virtual_alarm
119        )
120    );
121
122    let sixlowpan_state = sixlowpan as &dyn SixlowpanState;
123    let sixlowpan_tx = TxState::new(sixlowpan_state);
124
125    let icmp_hdr = ICMP6Header::new(ICMP6Type::Type128); // Echo Request
126
127    let ip_pyld: IPPayload = IPPayload {
128        header: TransportHeader::ICMP(icmp_hdr),
129        payload: &mut *addr_of_mut!(ICMP_PAYLOAD),
130    };
131
132    let ip6_dg = static_init!(IP6Packet<'static>, IP6Packet::new(ip_pyld));
133
134    let ip6_sender = static_init!(
135        IP6SendStruct<'static, VirtualMuxAlarm<'static, sam4l::ast::Ast<'static>>>,
136        IP6SendStruct::new(
137            ip6_dg,
138            ipsender_virtual_alarm,
139            &mut *addr_of_mut!(RF233_BUF),
140            sixlowpan_tx,
141            radio_mac,
142            DST_MAC_ADDR,
143            SRC_MAC_ADDR,
144            ip_vis
145        )
146    );
147    radio_mac.set_transmit_client(ip6_sender);
148
149    let icmp_send_struct = static_init!(
150        ICMP6SendStruct<
151            'static,
152            IP6SendStruct<'static, VirtualMuxAlarm<'static, sam4l::ast::Ast<'static>>>,
153        >,
154        ICMP6SendStruct::new(ip6_sender)
155    );
156
157    let alarm = static_init!(
158        VirtualMuxAlarm<'static, sam4l::ast::Ast>,
159        VirtualMuxAlarm::new(mux_alarm)
160    );
161    alarm.setup();
162
163    let icmp_lowpan_test = static_init!(
164        LowpanICMPTest<'static, VirtualMuxAlarm<'static, sam4l::ast::Ast>>,
165        LowpanICMPTest::new(
166            //sixlowpan_tx,
167            //radio_mac,
168            alarm,
169            icmp_send_struct,
170            net_cap
171        )
172    );
173
174    ip6_sender.set_client(icmp_send_struct);
175    icmp_send_struct.set_client(icmp_lowpan_test);
176    icmp_lowpan_test.alarm.set_alarm_client(icmp_lowpan_test);
177    ipsender_virtual_alarm.set_alarm_client(ip6_sender);
178    icmp_lowpan_test.start();
179}
180
181impl<'a, A: time::Alarm<'a>> capsules_extra::net::icmpv6::icmpv6_send::ICMP6SendClient
182    for LowpanICMPTest<'a, A>
183{
184    fn send_done(&self, result: Result<(), ErrorCode>) {
185        match result {
186            Ok(()) => {
187                debug!("ICMP Echo Request Packet Sent!");
188                match self.test_counter.get() {
189                    2 => debug!("Test completed successfully."),
190                    _ => self.schedule_next(),
191                }
192            }
193            _ => debug!("Failed to send ICMP Packet!"),
194        }
195    }
196}
197
198impl<'a, A: time::Alarm<'a>> LowpanICMPTest<'a, A> {
199    pub fn new(
200        alarm: &'a A,
201        icmp_sender: &'a dyn ICMP6Sender<'a>,
202        net_cap: &'static NetworkCapability,
203    ) -> LowpanICMPTest<'a, A> {
204        LowpanICMPTest {
205            alarm,
206            test_counter: Cell::new(0),
207            icmp_sender,
208            net_cap,
209        }
210    }
211
212    pub fn start(&self) {
213        self.schedule_next();
214    }
215
216    fn schedule_next(&self) {
217        let delta = self.alarm.ticks_from_ms(TEST_DELAY_MS);
218        let now = self.alarm.now();
219        self.alarm.set_alarm(now, delta);
220    }
221
222    fn run_test_and_increment(&self) {
223        let test_counter = self.test_counter.get();
224        self.run_test(test_counter);
225        match TEST_LOOP {
226            true => self.test_counter.set((test_counter + 1) % self.num_tests()),
227            false => self.test_counter.set(test_counter + 1),
228        }
229    }
230
231    fn num_tests(&self) -> usize {
232        2
233    }
234
235    fn run_test(&self, test_id: usize) {
236        debug!("Running test {}:", test_id);
237        match test_id {
238            0 => self.ipv6_send_packet_test(),
239            1 => self.ipv6_send_packet_test(),
240            _ => {}
241        }
242    }
243
244    fn ipv6_send_packet_test(&self) {
245        unsafe {
246            self.send_ipv6_packet();
247        }
248    }
249
250    unsafe fn send_ipv6_packet(&self) {
251        self.send_next();
252    }
253
254    fn send_next(&self) {
255        let icmp_hdr = ICMP6Header::new(ICMP6Type::Type128); // Echo Request
256        let _ = unsafe {
257            self.icmp_sender.send(
258                DST_ADDR,
259                icmp_hdr,
260                &mut *addr_of_mut!(ICMP_PAYLOAD),
261                self.net_cap,
262            )
263        };
264    }
265}
266
267impl<'a, A: time::Alarm<'a>> time::AlarmClient for LowpanICMPTest<'a, A> {
268    fn alarm(&self) {
269        self.run_test_and_increment();
270    }
271}