imix/test/
ipv6_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//! `ipv6_lowpan_test.rs`: 6LoWPAN Fragmentation Test Suite
6//!
7//! This implements a simple testing framework for 6LoWPAN fragmentation and
8//! compression. Two Imix boards run this code, one for receiving and one for
9//! transmitting. The transmitting board must call the `start` function in
10//! the `main.rs` file. The transmitting Imix then sends a variety of packets
11//! to the receiving Imix, relying on the 6LoWPAN fragmentation and reassembly
12//! layer. Note that this layer also performs 6LoWPAN compression (invisible
13//! to the upper layers), so this test suite is also dependent on the
14//! correctness of the compression/decompression implementation; for this
15//! reason, tests solely for compression/decompression have been left in a
16//! different file.
17//!
18//! This test suite will print out whether a receive packet is different than
19//! the expected packet. For this test to work correctly, and for both sides
20//! to remain in sync, they must both be started at the same time. Any dropped
21//! frames will prevent the test from completing successfully.
22//!
23//! To use this test, the `initialize_all` is called on both boards; and `start()`
24//! is called on the transmitting board. Simply call these
25//! functions in `boards/imix/src/main.rs` as follows:
26//!
27//! ```rust
28//! let lowpan_frag_test = test::ipv6_lowpan_test::initialize_all(
29//!    mux_mac,
30//!    mux_alarm,
31//! );
32//! lowpan_frag_test.start(); // If flashing the transmitting Imix
33//! ```
34
35use capsules_core::virtualizers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};
36use capsules_extra::ieee802154::device::{MacDevice, TxClient};
37use capsules_extra::net::ieee802154::MacAddress;
38use capsules_extra::net::ipv6::ip_utils::{ip6_nh, IPAddr};
39use capsules_extra::net::ipv6::{IP6Header, IP6Packet, IPPayload, TransportHeader};
40use capsules_extra::net::sixlowpan::sixlowpan_compression;
41use capsules_extra::net::sixlowpan::sixlowpan_state::{
42    RxState, Sixlowpan, SixlowpanRxClient, SixlowpanState, TxState,
43};
44use capsules_extra::net::udp::UDPHeader;
45use core::cell::Cell;
46use core::ptr::addr_of_mut;
47use core::sync::atomic::{AtomicUsize, Ordering};
48use kernel::debug;
49use kernel::hil::radio;
50use kernel::hil::time::{self, Alarm, ConvertTicks};
51use kernel::static_init;
52use kernel::ErrorCode;
53
54pub const MLP: [u8; 8] = [0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7];
55
56pub const SRC_ADDR: IPAddr = IPAddr([
57    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
58]);
59pub const DST_ADDR: IPAddr = IPAddr([
60    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
61]);
62pub const SRC_MAC_ADDR: MacAddress =
63    MacAddress::Long([0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17]);
64pub const DST_MAC_ADDR: MacAddress = MacAddress::Short(57326);
65//TODO: No longer pass MAC addresses to 6lowpan code, so these values arent used rn
66pub const IP6_HDR_SIZE: usize = 40;
67pub const UDP_HDR_SIZE: usize = 8;
68pub const PAYLOAD_LEN: usize = 200;
69pub static mut RF233_BUF: [u8; radio::MAX_BUF_SIZE] = [0_u8; radio::MAX_BUF_SIZE];
70
71/* 6LoWPAN Constants */
72const DEFAULT_CTX_PREFIX_LEN: u8 = 8;
73static DEFAULT_CTX_PREFIX: [u8; 16] = [0x0_u8; 16];
74static mut RX_STATE_BUF: [u8; 1280] = [0x0; 1280];
75
76#[derive(Copy, Clone, Debug, PartialEq)]
77enum TF {
78    Inline = 0b00,
79    Traffic = 0b01,
80    Flow = 0b10,
81    TrafficFlow = 0b11,
82}
83
84#[derive(Copy, Clone, Debug)]
85enum SAC {
86    Inline,
87    LLP64,
88    LLP16,
89    LLPIID,
90    Unspecified,
91    Ctx64,
92    Ctx16,
93    CtxIID,
94}
95
96#[derive(Copy, Clone, Debug)]
97enum DAC {
98    Inline,
99    LLP64,
100    LLP16,
101    LLPIID,
102    Ctx64,
103    Ctx16,
104    CtxIID,
105    McastInline,
106    Mcast48,
107    Mcast32,
108    Mcast8,
109    McastCtx,
110}
111
112pub const TEST_DELAY_MS: u32 = 10000;
113pub const TEST_LOOP: bool = false;
114static SUCCESS_COUNT: AtomicUsize = AtomicUsize::new(0);
115// Below was IP6_DGRAM before change to typed buffers
116//static mut IP6_DGRAM: [u8; IP6_HDR_SIZE + PAYLOAD_LEN] = [0; IP6_HDR_SIZE + PAYLOAD_LEN];
117static mut UDP_DGRAM: [u8; PAYLOAD_LEN - UDP_HDR_SIZE] = [0; PAYLOAD_LEN - UDP_HDR_SIZE]; //Becomes payload of UDP
118
119//Use a global variable option, initialize as None, then actually initialize in initialize all
120
121static mut IP6_DG_OPT: Option<IP6Packet> = None;
122//END changes
123
124type Rf233 = capsules_extra::rf233::RF233<
125    'static,
126    capsules_core::virtualizers::virtual_spi::VirtualSpiMasterDevice<
127        'static,
128        sam4l::spi::SpiHw<'static>,
129    >,
130>;
131type Ieee802154MacDevice =
132    components::ieee802154::Ieee802154ComponentMacDeviceType<Rf233, sam4l::aes::Aes<'static>>;
133
134pub struct LowpanTest<'a, A: time::Alarm<'a>> {
135    alarm: &'a A,
136    sixlowpan_tx: TxState<'a>,
137    radio: &'a dyn MacDevice<'a>,
138    test_counter: Cell<usize>,
139}
140
141pub unsafe fn initialize_all(
142    mux_mac: &'static capsules_extra::ieee802154::virtual_mac::MuxMac<'static, Ieee802154MacDevice>,
143    mux_alarm: &'static MuxAlarm<'static, sam4l::ast::Ast>,
144) -> &'static LowpanTest<
145    'static,
146    capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<'static, sam4l::ast::Ast<'static>>,
147> {
148    let radio_mac = static_init!(
149        capsules_extra::ieee802154::virtual_mac::MacUser<'static, Ieee802154MacDevice>,
150        capsules_extra::ieee802154::virtual_mac::MacUser::new(mux_mac)
151    );
152    mux_mac.add_user(radio_mac);
153    let default_rx_state = static_init!(
154        RxState<'static>,
155        RxState::new(&mut *addr_of_mut!(RX_STATE_BUF))
156    );
157
158    let sixlo_alarm = static_init!(
159        VirtualMuxAlarm<sam4l::ast::Ast>,
160        VirtualMuxAlarm::new(mux_alarm)
161    );
162    sixlo_alarm.setup();
163
164    let sixlowpan = static_init!(
165        Sixlowpan<
166            'static,
167            VirtualMuxAlarm<sam4l::ast::Ast<'static>>,
168            sixlowpan_compression::Context,
169        >,
170        Sixlowpan::new(
171            sixlowpan_compression::Context {
172                prefix: DEFAULT_CTX_PREFIX,
173                prefix_len: DEFAULT_CTX_PREFIX_LEN,
174                id: 0,
175                compress: false,
176            },
177            sixlo_alarm
178        )
179    );
180
181    let sixlowpan_state = sixlowpan as &dyn SixlowpanState;
182    let sixlowpan_tx = TxState::new(sixlowpan_state);
183
184    let _ = sixlowpan_tx.init(SRC_MAC_ADDR, DST_MAC_ADDR, radio_mac.get_pan(), None);
185
186    let alarm = static_init!(
187        VirtualMuxAlarm<'static, sam4l::ast::Ast>,
188        VirtualMuxAlarm::new(mux_alarm)
189    );
190    alarm.setup();
191
192    let lowpan_frag_test = static_init!(
193        LowpanTest<'static, VirtualMuxAlarm<'static, sam4l::ast::Ast>>,
194        LowpanTest::new(sixlowpan_tx, radio_mac, alarm)
195    );
196
197    sixlowpan_state.add_rx_state(default_rx_state);
198    sixlowpan_state.set_rx_client(lowpan_frag_test);
199    lowpan_frag_test.alarm.set_alarm_client(lowpan_frag_test);
200
201    radio_mac.set_receive_client(sixlowpan);
202
203    // Following code initializes an IP6Packet using the global UDP_DGRAM buffer as the payload
204    let mut udp_hdr: UDPHeader = UDPHeader::new();
205    udp_hdr.set_src_port(12345);
206    udp_hdr.set_dst_port(54321);
207    udp_hdr.set_len(PAYLOAD_LEN as u16);
208    //checksum is calculated and set later
209
210    let mut ip6_hdr: IP6Header = IP6Header::new();
211    ip6_hdr.set_next_header(ip6_nh::UDP);
212    ip6_hdr.set_payload_len(PAYLOAD_LEN as u16);
213    ip6_hdr.src_addr = SRC_ADDR;
214    ip6_hdr.dst_addr = DST_ADDR;
215
216    let tr_hdr: TransportHeader = TransportHeader::UDP(udp_hdr);
217
218    let ip_pyld: IPPayload = IPPayload {
219        header: tr_hdr,
220        payload: &mut *addr_of_mut!(UDP_DGRAM),
221    };
222
223    let mut ip6_dg: IP6Packet = IP6Packet {
224        header: ip6_hdr,
225        payload: ip_pyld,
226    };
227
228    ip6_dg.set_transport_checksum(); //calculates and sets UDP cksum
229
230    IP6_DG_OPT = Some(ip6_dg);
231    //Now, other places in code should have access to initialized IP6Packet.
232    //Note that this code is inherently unsafe and we make no effort to prevent
233    //race conditions, as this is merely test code
234    radio_mac.set_transmit_client(lowpan_frag_test);
235    lowpan_frag_test
236}
237
238impl<'a, A: time::Alarm<'a>> LowpanTest<'a, A> {
239    pub fn new(
240        sixlowpan_tx: TxState<'a>,
241        radio: &'a dyn MacDevice<'a>,
242        alarm: &'a A,
243    ) -> LowpanTest<'a, A> {
244        LowpanTest {
245            alarm,
246            sixlowpan_tx,
247            radio,
248            test_counter: Cell::new(0),
249        }
250    }
251
252    pub fn start(&self) {
253        //self.run_test_and_increment();
254        self.schedule_next();
255    }
256
257    fn schedule_next(&self) {
258        let delay = self.alarm.ticks_from_ms(TEST_DELAY_MS);
259        let now = self.alarm.now();
260        self.alarm.set_alarm(now, delay);
261    }
262
263    fn run_test_and_increment(&self) {
264        let test_counter = self.test_counter.get();
265        self.run_test(test_counter);
266        match TEST_LOOP {
267            true => self.test_counter.set((test_counter + 1) % self.num_tests()),
268            false => self.test_counter.set(test_counter + 1),
269        }
270    }
271
272    fn num_tests(&self) -> usize {
273        28
274    }
275
276    fn run_test(&self, test_id: usize) {
277        debug!("Running test {}:", test_id);
278        match test_id {
279            // Change TF compression
280            0 => self.ipv6_send_packet_test(TF::Inline, 255, SAC::Inline, DAC::Inline),
281            1 => self.ipv6_send_packet_test(TF::Traffic, 255, SAC::Inline, DAC::Inline),
282            2 => self.ipv6_send_packet_test(TF::Flow, 255, SAC::Inline, DAC::Inline),
283            3 => self.ipv6_send_packet_test(TF::TrafficFlow, 255, SAC::Inline, DAC::Inline),
284
285            // Change HL compression
286            4 => self.ipv6_send_packet_test(TF::TrafficFlow, 255, SAC::Inline, DAC::Inline),
287            5 => self.ipv6_send_packet_test(TF::TrafficFlow, 64, SAC::Inline, DAC::Inline),
288            6 => self.ipv6_send_packet_test(TF::TrafficFlow, 1, SAC::Inline, DAC::Inline),
289            7 => self.ipv6_send_packet_test(TF::TrafficFlow, 42, SAC::Inline, DAC::Inline),
290
291            // Change source compression
292            8 => self.ipv6_send_packet_test(TF::TrafficFlow, 42, SAC::Inline, DAC::Inline),
293            9 => self.ipv6_send_packet_test(TF::TrafficFlow, 42, SAC::LLP64, DAC::Inline),
294            10 => self.ipv6_send_packet_test(TF::TrafficFlow, 42, SAC::LLP16, DAC::Inline),
295            11 => self.ipv6_send_packet_test(TF::TrafficFlow, 42, SAC::LLPIID, DAC::Inline),
296            12 => self.ipv6_send_packet_test(TF::TrafficFlow, 42, SAC::Unspecified, DAC::Inline),
297            13 => self.ipv6_send_packet_test(TF::TrafficFlow, 42, SAC::Ctx64, DAC::Inline),
298            14 => self.ipv6_send_packet_test(TF::TrafficFlow, 42, SAC::Ctx16, DAC::Inline),
299            15 => self.ipv6_send_packet_test(TF::TrafficFlow, 42, SAC::CtxIID, DAC::Inline),
300
301            // Change dest compression
302            16 => self.ipv6_send_packet_test(TF::TrafficFlow, 42, SAC::CtxIID, DAC::Inline),
303            17 => self.ipv6_send_packet_test(TF::TrafficFlow, 42, SAC::CtxIID, DAC::LLP64),
304            18 => self.ipv6_send_packet_test(TF::TrafficFlow, 42, SAC::CtxIID, DAC::LLP16),
305            19 => self.ipv6_send_packet_test(TF::TrafficFlow, 42, SAC::CtxIID, DAC::LLPIID),
306            20 => self.ipv6_send_packet_test(TF::TrafficFlow, 42, SAC::CtxIID, DAC::Ctx64),
307            21 => self.ipv6_send_packet_test(TF::TrafficFlow, 42, SAC::CtxIID, DAC::Ctx16),
308            22 => self.ipv6_send_packet_test(TF::TrafficFlow, 42, SAC::CtxIID, DAC::CtxIID),
309            23 => self.ipv6_send_packet_test(TF::TrafficFlow, 42, SAC::CtxIID, DAC::McastInline),
310            24 => self.ipv6_send_packet_test(TF::TrafficFlow, 42, SAC::CtxIID, DAC::Mcast48),
311            25 => self.ipv6_send_packet_test(TF::TrafficFlow, 42, SAC::CtxIID, DAC::Mcast32),
312            26 => self.ipv6_send_packet_test(TF::TrafficFlow, 42, SAC::CtxIID, DAC::Mcast8),
313            27 => self.ipv6_send_packet_test(TF::TrafficFlow, 42, SAC::CtxIID, DAC::McastCtx),
314
315            _ => {}
316        }
317    }
318
319    fn run_check_test(&self, test_id: usize, buf: &[u8], len: usize) {
320        debug!("Running test {}:", test_id);
321        let success = match test_id {
322            // Change TF compression
323            0 => ipv6_check_receive_packet(TF::Inline, 255, SAC::Inline, DAC::Inline, buf, len),
324            1 => ipv6_check_receive_packet(TF::Traffic, 255, SAC::Inline, DAC::Inline, buf, len),
325            2 => ipv6_check_receive_packet(TF::Flow, 255, SAC::Inline, DAC::Inline, buf, len),
326            3 => {
327                ipv6_check_receive_packet(TF::TrafficFlow, 255, SAC::Inline, DAC::Inline, buf, len)
328            }
329
330            // Change HL compression
331            4 => {
332                ipv6_check_receive_packet(TF::TrafficFlow, 255, SAC::Inline, DAC::Inline, buf, len)
333            }
334            5 => ipv6_check_receive_packet(TF::TrafficFlow, 64, SAC::Inline, DAC::Inline, buf, len),
335            6 => ipv6_check_receive_packet(TF::TrafficFlow, 1, SAC::Inline, DAC::Inline, buf, len),
336            7 => ipv6_check_receive_packet(TF::TrafficFlow, 42, SAC::Inline, DAC::Inline, buf, len),
337
338            // Change source compression
339            8 => ipv6_check_receive_packet(TF::TrafficFlow, 42, SAC::Inline, DAC::Inline, buf, len),
340            9 => ipv6_check_receive_packet(TF::TrafficFlow, 42, SAC::LLP64, DAC::Inline, buf, len),
341            10 => ipv6_check_receive_packet(TF::TrafficFlow, 42, SAC::LLP16, DAC::Inline, buf, len),
342            11 => {
343                ipv6_check_receive_packet(TF::TrafficFlow, 42, SAC::LLPIID, DAC::Inline, buf, len)
344            }
345            12 => ipv6_check_receive_packet(
346                TF::TrafficFlow,
347                42,
348                SAC::Unspecified,
349                DAC::Inline,
350                buf,
351                len,
352            ),
353            13 => ipv6_check_receive_packet(TF::TrafficFlow, 42, SAC::Ctx64, DAC::Inline, buf, len),
354            14 => ipv6_check_receive_packet(TF::TrafficFlow, 42, SAC::Ctx16, DAC::Inline, buf, len),
355            15 => {
356                ipv6_check_receive_packet(TF::TrafficFlow, 42, SAC::CtxIID, DAC::Inline, buf, len)
357            }
358
359            // Change dest compression
360            16 => {
361                ipv6_check_receive_packet(TF::TrafficFlow, 42, SAC::CtxIID, DAC::Inline, buf, len)
362            }
363            17 => ipv6_check_receive_packet(TF::TrafficFlow, 42, SAC::CtxIID, DAC::LLP64, buf, len),
364            18 => ipv6_check_receive_packet(TF::TrafficFlow, 42, SAC::CtxIID, DAC::LLP16, buf, len),
365            19 => {
366                ipv6_check_receive_packet(TF::TrafficFlow, 42, SAC::CtxIID, DAC::LLPIID, buf, len)
367            }
368            20 => ipv6_check_receive_packet(TF::TrafficFlow, 42, SAC::CtxIID, DAC::Ctx64, buf, len),
369            21 => ipv6_check_receive_packet(TF::TrafficFlow, 42, SAC::CtxIID, DAC::Ctx16, buf, len),
370            22 => {
371                ipv6_check_receive_packet(TF::TrafficFlow, 42, SAC::CtxIID, DAC::CtxIID, buf, len)
372            }
373            23 => ipv6_check_receive_packet(
374                TF::TrafficFlow,
375                42,
376                SAC::CtxIID,
377                DAC::McastInline,
378                buf,
379                len,
380            ),
381            24 => {
382                ipv6_check_receive_packet(TF::TrafficFlow, 42, SAC::CtxIID, DAC::Mcast48, buf, len)
383            }
384            25 => {
385                ipv6_check_receive_packet(TF::TrafficFlow, 42, SAC::CtxIID, DAC::Mcast32, buf, len)
386            }
387            26 => {
388                ipv6_check_receive_packet(TF::TrafficFlow, 42, SAC::CtxIID, DAC::Mcast8, buf, len)
389            }
390            27 => {
391                ipv6_check_receive_packet(TF::TrafficFlow, 42, SAC::CtxIID, DAC::McastCtx, buf, len)
392            }
393
394            _ => {
395                debug!("Finished tests");
396                false
397            }
398        };
399        if success {
400            SUCCESS_COUNT.fetch_add(1, Ordering::SeqCst);
401        }
402        if test_id == self.num_tests() - 1 {
403            let success_count = SUCCESS_COUNT.load(Ordering::SeqCst);
404            if success_count == self.num_tests() {
405                debug!("All Tests completed successfully!");
406            } else {
407                debug!(
408                    "Successfully completed {:?}/{:?} tests",
409                    success_count,
410                    self.num_tests()
411                );
412            }
413        }
414    }
415    fn ipv6_send_packet_test(&self, tf: TF, hop_limit: u8, sac: SAC, dac: DAC) {
416        ipv6_prepare_packet(tf, hop_limit, sac, dac);
417        unsafe {
418            self.send_ipv6_packet(&MLP);
419        }
420    }
421
422    unsafe fn send_ipv6_packet(&self, _: &[u8]) {
423        self.send_next(&mut *addr_of_mut!(RF233_BUF));
424    }
425
426    fn send_next(&self, tx_buf: &'static mut [u8]) {
427        unsafe {
428            match IP6_DG_OPT {
429                Some(ref ip6_packet) => {
430                    match self
431                        .sixlowpan_tx
432                        .next_fragment(ip6_packet, tx_buf, self.radio)
433                    {
434                        Ok((is_done, frame)) => {
435                            //TODO: Fix ordering so that debug output does not indicate extra frame sent
436                            if is_done {
437                                self.schedule_next();
438                            } else {
439                                // TODO: Handle err (not just debug statement)
440                                let _ = self
441                                    .radio
442                                    .transmit(frame)
443                                    .map_err(|_| debug!("Error in radio transmit"));
444                            }
445                        }
446                        Err((retcode, _buf)) => {
447                            debug!("ERROR!: {:?}", retcode);
448                        }
449                    }
450                }
451                None => debug!("Error! tried to send uninitialized IP6Packet"),
452            }
453        }
454    }
455}
456
457impl<'a, A: time::Alarm<'a>> time::AlarmClient for LowpanTest<'a, A> {
458    fn alarm(&self) {
459        self.run_test_and_increment();
460    }
461}
462
463impl<'a, A: time::Alarm<'a>> SixlowpanRxClient for LowpanTest<'a, A> {
464    fn receive(&self, buf: &[u8], len: usize, retcode: Result<(), ErrorCode>) {
465        debug!("Receive completed: {:?}", retcode);
466        let test_num = self.test_counter.get();
467        self.test_counter.set((test_num + 1) % self.num_tests());
468        self.run_check_test(test_num, buf, len)
469    }
470}
471
472static mut ARRAY: [u8; 100] = [0x0; 100]; //used in introducing delay between frames
473impl<'a, A: time::Alarm<'a>> TxClient for LowpanTest<'a, A> {
474    fn send_done(&self, tx_buf: &'static mut [u8], _acked: bool, result: Result<(), ErrorCode>) {
475        match result {
476            Ok(()) => {}
477            _ => debug!("sendDone indicates error"),
478        }
479        unsafe {
480            //This unsafe block introduces a delay between frames to prevent
481            // a race condition on the receiver
482            //it is sorta complicated bc I was having some trouble with dead code elimination
483            let mut i = 0;
484            while i < 4000000 {
485                ARRAY[i % 100] = (i % 100) as u8;
486                i += 1;
487                if i % 1000000 == 0 {
488                    i += 2;
489                }
490            }
491        }
492        self.send_next(tx_buf);
493    }
494}
495
496fn ipv6_check_receive_packet(
497    tf: TF,
498    hop_limit: u8,
499    sac: SAC,
500    dac: DAC,
501    recv_packet: &[u8],
502    len: usize,
503) -> bool {
504    ipv6_prepare_packet(tf, hop_limit, sac, dac);
505    let mut test_success = true;
506    unsafe {
507        // First, need to check header fields match:
508        // Do this by casting first 48 bytes of rcvd packet as IP/UDP headers
509        /*let rcvip6hdr: IP6Header = ptr::read(recv_packet.as_ptr() as *const _);
510        let rcvudphdr: UDPHeader =
511            ptr::read((recv_packet.as_ptr().offset(IP6_HDR_SIZE as isize)) as *const _); */
512        match IP6Header::decode(recv_packet).done() {
513            Some((offset, rcvip6hdr)) => {
514                match UDPHeader::decode(&recv_packet[offset..len]).done() {
515                    Some((_offset, rcvudphdr)) => {
516                        // Now compare to the headers that would be being sent by prepare packet
517                        // (as we know prepare packet is running in parallel on sender to generate tx packets)
518                        match IP6_DG_OPT {
519                            Some(ref ip6_packet) => {
520                                //First check IP headers
521                                if rcvip6hdr.get_version() != ip6_packet.header.get_version() {
522                                    test_success = false;
523                                    debug!("Mismatched IP ver");
524                                }
525
526                                if rcvip6hdr.get_traffic_class()
527                                    != ip6_packet.header.get_traffic_class()
528                                {
529                                    debug!("Mismatched tc");
530                                    test_success = false;
531                                }
532                                if rcvip6hdr.get_dscp() != ip6_packet.header.get_dscp() {
533                                    debug!("Mismatched dcsp");
534                                    test_success = false;
535                                }
536                                if rcvip6hdr.get_ecn() != ip6_packet.header.get_ecn() {
537                                    debug!("Mismatched ecn");
538                                    test_success = false;
539                                }
540                                if rcvip6hdr.get_payload_len()
541                                    != ip6_packet.header.get_payload_len()
542                                {
543                                    debug!("Mismatched IP len");
544                                    test_success = false;
545                                }
546                                if rcvip6hdr.get_next_header()
547                                    != ip6_packet.header.get_next_header()
548                                {
549                                    debug!(
550                                        "Mismatched next hdr. Rcvd is: {:?}, expctd is: {:?}",
551                                        rcvip6hdr.get_next_header(),
552                                        ip6_packet.header.get_next_header()
553                                    );
554                                    test_success = false;
555                                }
556                                if rcvip6hdr.get_hop_limit() != ip6_packet.header.get_hop_limit() {
557                                    debug!("Mismatched hop limit");
558                                    test_success = false;
559                                }
560
561                                //Now check UDP headers
562
563                                match ip6_packet.payload.header {
564                                    TransportHeader::UDP(ref sent_udp_pkt) => {
565                                        if rcvudphdr.get_src_port() != sent_udp_pkt.get_src_port() {
566                                            debug!(
567                                "Mismatched src_port. Rcvd is: {:?}, expctd is: {:?}",
568                                rcvudphdr.get_src_port(),
569                                sent_udp_pkt.get_src_port()
570                            );
571                                            test_success = false;
572                                        }
573
574                                        if rcvudphdr.get_dst_port() != sent_udp_pkt.get_dst_port() {
575                                            debug!(
576                                "Mismatched dst_port. Rcvd is: {:?}, expctd is: {:?}",
577                                rcvudphdr.get_dst_port(),
578                                sent_udp_pkt.get_dst_port()
579                            );
580                                            test_success = false;
581                                        }
582
583                                        if rcvudphdr.get_len() != sent_udp_pkt.get_len() {
584                                            debug!(
585                                "Mismatched udp_len. Rcvd is: {:?}, expctd is: {:?}",
586                                rcvudphdr.get_len(),
587                                sent_udp_pkt.get_len()
588                            );
589                                            test_success = false;
590                                        }
591
592                                        if rcvudphdr.get_cksum() != sent_udp_pkt.get_cksum() {
593                                            debug!(
594                                                "Mismatched cksum. Rcvd is: {:?}, expctd is: {:?}",
595                                                rcvudphdr.get_cksum(),
596                                                sent_udp_pkt.get_cksum()
597                                            );
598                                            test_success = false;
599                                        }
600                                    }
601                                    _ => {
602                                        debug!(
603                                            "Error: For some reason prepare packet is not
604                                    preparing a UDP payload"
605                                        );
606                                    }
607                                }
608                            }
609                            None => debug!("Error! tried to read uninitialized IP6Packet"),
610                        }
611
612                        // Finally, check bytes of UDP Payload
613                        let mut payload_success = true;
614                        for i in (IP6_HDR_SIZE + UDP_HDR_SIZE)..len {
615                            if recv_packet[i] != UDP_DGRAM[i - (IP6_HDR_SIZE + UDP_HDR_SIZE)] {
616                                test_success = false;
617                                payload_success = false;
618                                debug!(
619                                    "Packets differ at idx: {} where recv = {}, ref = {}",
620                                    i - (IP6_HDR_SIZE + UDP_HDR_SIZE),
621                                    recv_packet[i],
622                                    UDP_DGRAM[i - (IP6_HDR_SIZE + UDP_HDR_SIZE)]
623                                );
624                                //break; //Comment this in to help prevent debug buffer overflows
625                            }
626                        }
627                        if !payload_success {
628                            debug!("Packet payload did not match.");
629                        }
630                    }
631                    None => {
632                        debug!("Failed to decode UDP Header");
633                        test_success = false;
634                    }
635                }
636            }
637            None => {
638                debug!("Failed to decode IPv6 Header");
639                test_success = false;
640            }
641        }
642
643        debug!("Individual Test success is: {}", test_success);
644        test_success
645    }
646}
647
648//TODO: Change this function to modify IP6Packet struct instead of raw buffer
649fn ipv6_prepare_packet(tf: TF, hop_limit: u8, sac: SAC, dac: DAC) {
650    {
651        let payload = unsafe { &mut UDP_DGRAM[0..] };
652        for i in 0..(PAYLOAD_LEN - UDP_HDR_SIZE) {
653            payload[i] = i as u8;
654        }
655    }
656    unsafe {
657        //Had to use unsafe here bc IP6_DG_OPT is mutable static
658
659        match IP6_DG_OPT {
660            Some(ref mut ip6_packet) => {
661                {
662                    let ip6_header: &mut IP6Header = &mut ip6_packet.header;
663                    ip6_header.set_payload_len(PAYLOAD_LEN as u16);
664
665                    if tf != TF::TrafficFlow {
666                        ip6_header.set_ecn(0b01);
667                    }
668                    if (tf as u8) & (TF::Traffic as u8) != 0 {
669                        ip6_header.set_dscp(0b000000);
670                    } else {
671                        ip6_header.set_dscp(0b101010);
672                    }
673
674                    if (tf as u8) & (TF::Flow as u8) != 0 {
675                        ip6_header.set_flow_label(0);
676                    } else {
677                        ip6_header.set_flow_label(0xABCDE);
678                    }
679
680                    ip6_header.set_next_header(ip6_nh::UDP);
681
682                    ip6_header.set_hop_limit(hop_limit);
683
684                    match sac {
685                        SAC::Inline => {
686                            ip6_header.src_addr = SRC_ADDR;
687                        }
688                        SAC::LLP64 => {
689                            // LLP::xxxx:xxxx:xxxx:xxxx
690                            ip6_header.src_addr.set_unicast_link_local();
691                            ip6_header.src_addr.0[8..16].copy_from_slice(&SRC_ADDR.0[8..16]);
692                        }
693                        SAC::LLP16 => {
694                            // LLP::ff:fe00:xxxx
695                            ip6_header.src_addr.set_unicast_link_local();
696                            // Distinct from compute_iid because the U/L bit is not flipped
697                            ip6_header.src_addr.0[11] = 0xff;
698                            ip6_header.src_addr.0[12] = 0xfe;
699                            ip6_header.src_addr.0[14..16].copy_from_slice(&SRC_ADDR.0[14..16]);
700                        }
701                        SAC::LLPIID => {
702                            // LLP::IID
703                            ip6_header.src_addr.set_unicast_link_local();
704                            ip6_header.src_addr.0[8..16].copy_from_slice(
705                                &sixlowpan_compression::compute_iid(&SRC_MAC_ADDR),
706                            );
707                        }
708                        SAC::Unspecified => {}
709                        SAC::Ctx64 => {
710                            // MLP::xxxx:xxxx:xxxx:xxxx
711                            ip6_header.src_addr.set_prefix(&MLP, 64);
712                            ip6_header.src_addr.0[8..16].copy_from_slice(&SRC_ADDR.0[8..16]);
713                        }
714                        SAC::Ctx16 => {
715                            // MLP::ff:fe00:xxxx
716                            ip6_header.src_addr.set_prefix(&MLP, 64);
717                            // Distinct from compute_iid because the U/L bit is not flipped
718                            ip6_header.src_addr.0[11] = 0xff;
719                            ip6_header.src_addr.0[12] = 0xfe;
720                            ip6_header.src_addr.0[14..16].copy_from_slice(&SRC_ADDR.0[14..16]);
721                        }
722                        SAC::CtxIID => {
723                            // MLP::IID
724                            ip6_header.src_addr.set_prefix(&MLP, 64);
725                            ip6_header.src_addr.0[8..16].copy_from_slice(
726                                &sixlowpan_compression::compute_iid(&SRC_MAC_ADDR),
727                            );
728                        }
729                    }
730
731                    match dac {
732                        DAC::Inline => {
733                            ip6_header.dst_addr = DST_ADDR;
734                        }
735                        DAC::LLP64 => {
736                            // LLP::xxxx:xxxx:xxxx:xxxx
737                            ip6_header.dst_addr.set_unicast_link_local();
738                            ip6_header.dst_addr.0[8..16].copy_from_slice(&DST_ADDR.0[8..16]);
739                        }
740                        DAC::LLP16 => {
741                            // LLP::ff:fe00:xxxx
742                            ip6_header.dst_addr.set_unicast_link_local();
743                            // Distinct from compute_iid because the U/L bit is not flipped
744                            ip6_header.dst_addr.0[11] = 0xff;
745                            ip6_header.dst_addr.0[12] = 0xfe;
746                            ip6_header.dst_addr.0[14..16].copy_from_slice(&SRC_ADDR.0[14..16]);
747                        }
748                        DAC::LLPIID => {
749                            // LLP::IID
750                            ip6_header.dst_addr.set_unicast_link_local();
751                            ip6_header.dst_addr.0[8..16].copy_from_slice(
752                                &sixlowpan_compression::compute_iid(&DST_MAC_ADDR),
753                            );
754                        }
755                        DAC::Ctx64 => {
756                            // MLP::xxxx:xxxx:xxxx:xxxx
757                            ip6_header.dst_addr.set_prefix(&MLP, 64);
758                            ip6_header.dst_addr.0[8..16].copy_from_slice(&SRC_ADDR.0[8..16]);
759                        }
760                        DAC::Ctx16 => {
761                            // MLP::ff:fe00:xxxx
762                            ip6_header.dst_addr.set_prefix(&MLP, 64);
763                            // Distinct from compute_iid because the U/L bit is not flipped
764                            ip6_header.dst_addr.0[11] = 0xff;
765                            ip6_header.dst_addr.0[12] = 0xfe;
766                            ip6_header.dst_addr.0[14..16].copy_from_slice(&SRC_ADDR.0[14..16]);
767                        }
768                        DAC::CtxIID => {
769                            // MLP::IID
770                            ip6_header.dst_addr.set_prefix(&MLP, 64);
771                            ip6_header.dst_addr.0[8..16].copy_from_slice(
772                                &sixlowpan_compression::compute_iid(&DST_MAC_ADDR),
773                            );
774                        }
775                        DAC::McastInline => {
776                            // first byte is ff, that's all we know
777                            ip6_header.dst_addr = DST_ADDR;
778                            ip6_header.dst_addr.0[0] = 0xff;
779                        }
780                        DAC::Mcast48 => {
781                            // ffXX::00XX:XXXX:XXXX
782                            ip6_header.dst_addr.0[0] = 0xff;
783                            ip6_header.dst_addr.0[1] = DST_ADDR.0[1];
784                            ip6_header.dst_addr.0[11..16].copy_from_slice(&DST_ADDR.0[11..16]);
785                        }
786                        DAC::Mcast32 => {
787                            // ffXX::00XX:XXXX
788                            ip6_header.dst_addr.0[0] = 0xff;
789                            ip6_header.dst_addr.0[1] = DST_ADDR.0[1];
790                            ip6_header.dst_addr.0[13..16].copy_from_slice(&DST_ADDR.0[13..16]);
791                        }
792                        DAC::Mcast8 => {
793                            // ff02::00XX
794                            ip6_header.dst_addr.0[0] = 0xff;
795                            ip6_header.dst_addr.0[1] = DST_ADDR.0[1];
796                            ip6_header.dst_addr.0[15] = DST_ADDR.0[15];
797                        }
798                        DAC::McastCtx => {
799                            // ffXX:XX + plen + pfx64 + XXXX:XXXX
800                            ip6_header.dst_addr.0[0] = 0xff;
801                            ip6_header.dst_addr.0[1] = DST_ADDR.0[1];
802                            ip6_header.dst_addr.0[2] = DST_ADDR.0[2];
803                            ip6_header.dst_addr.0[3] = 64_u8;
804                            ip6_header.dst_addr.0[4..12].copy_from_slice(&MLP);
805                            ip6_header.dst_addr.0[12..16].copy_from_slice(&DST_ADDR.0[12..16]);
806                        }
807                    }
808                } //This bracket ends mutable borrow of ip6_packet for header
809                  //Now that packet is fully prepared, set checksum
810                ip6_packet.set_transport_checksum(); //calculates and sets UDP cksum
811            }
812            None => debug!("Error! tried to prepare uninitialized IP6Packet"),
813        }
814    }
815
816    debug!(
817        "Packet with tf={:?} hl={} sac={:?} dac={:?}",
818        tf, hop_limit, sac, dac
819    );
820}