1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.

use crate::net::ipv6::IP6Header;
use crate::net::sixlowpan::sixlowpan_state::SixlowpanRxClient;

use kernel::debug;
use kernel::utilities::cells::OptionalCell;
use kernel::ErrorCode;

// To provide some context for the entire rx chain:
/*
- The radio in the kernel has a single `RxClient`, which is set as the mac layer
  (awake_mac, typically)
- The mac layer (i.e. `AwakeMac`) has a single `RxClient`, which is the
  mac_device(`ieee802154::Framer::framer`)
- The Mac device has a single receive client - `MuxMac` (virtual MAC device).
- The `MuxMac` can have multiple "users" which are of type `MacUser`
- Any received packet is passed to ALL MacUsers, which are expected to filter
  packets themselves accordingly.
- Right now, we initialize two MacUsers in the kernel (in main.rs/components).
  These are the 'radio_mac', which is the MacUser for the RadioDriver that
  enables the userland interface to directly send 802154 frames, and udp_mac,
  the mac layer that is ultimately associated with the udp userland interface.
- The udp_mac MacUser has a single receive client, which is the `sixlowpan_state` struct
- `sixlowpan_state` has a single rx_client, which in our case is a single struct that
  implements the `ip_receive ` trait.
- the `ip_receive` implementing struct (`IP6RecvStruct`) has a single client, which is
  udp_recv, a `UDPReceive` struct.
- The UDPReceive struct is a field of the UDPDriver, which ultimately passes the
  packets up to userland.
*/

pub trait IP6RecvClient {
    fn receive(&self, header: IP6Header, payload: &[u8]);
}

/// Currently only one implementation of this trait should exist,
/// as we do not multiplex received packets based on the address.
/// The receiver receives IP packets destined for any local address.
/// The receiver should drop any packets with destination addresses
/// that are not among the local addresses of this device.
pub trait IP6Receiver<'a> {
    fn set_client(&self, client: &'a dyn IP6RecvClient);
}

pub struct IP6RecvStruct<'a> {
    client: OptionalCell<&'a dyn IP6RecvClient>,
}

impl<'a> IP6Receiver<'a> for IP6RecvStruct<'a> {
    fn set_client(&self, client: &'a dyn IP6RecvClient) {
        self.client.set(client);
    }
}

impl<'a> IP6RecvStruct<'a> {
    pub fn new() -> IP6RecvStruct<'a> {
        IP6RecvStruct {
            client: OptionalCell::empty(),
        }
    }
}

impl<'a> SixlowpanRxClient for IP6RecvStruct<'a> {
    fn receive(&self, buf: &[u8], len: usize, result: Result<(), ErrorCode>) {
        // TODO: Drop here?
        if len > buf.len() || result != Ok(()) {
            return;
        }
        match IP6Header::decode(buf).done() {
            Some((offset, ip6_header)) => {
                let checksum_result = ip6_header.check_transport_checksum(&buf[offset..len]);
                if checksum_result == Err(ErrorCode::FAIL) {
                    debug!("cksum fail!: {:?}", checksum_result);
                    return; //Dropped.
                }
                // Note: Protocols for which checksum verification is not implemented (TCP, etc.)
                // are automatically assumed as fine, rather than dropped

                self.client
                    .map(|client| client.receive(ip6_header, &buf[offset..len]));
            }
            None => {
                debug!("failed to decode ipv6 header");
                // TODO: Report the error somewhere...
            }
        }
    }
}