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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.

//! This file contains the definition and implementation for the UDP reception
//! interface. It follows the same virtualization model as that described in `udp_send.rs`,
//! except that no queueing is needed because received packets are immediately dispatched to the
//! appropriate capsule / app. Once again, port binding for userspace apps is managed separately
//! by the UDP userspace driver, which must correctly check bindings of kernel apps to ensure
//! correctness when dispatching received packets to the appropriate client.

use crate::net::ipv6::ip_utils::IPAddr;
use crate::net::ipv6::ipv6_recv::IP6RecvClient;
use crate::net::ipv6::IP6Header;
use crate::net::udp::driver::UDPDriver;
use crate::net::udp::udp_port_table::{PortQuery, UdpPortBindingRx};
use crate::net::udp::UDPHeader;

use kernel::collections::list::{List, ListLink, ListNode};
use kernel::debug;
use kernel::utilities::cells::{MapCell, OptionalCell};

pub struct MuxUdpReceiver<'a> {
    rcvr_list: List<'a, UDPReceiver<'a>>,
    driver: OptionalCell<&'static UDPDriver<'static>>,
}

impl<'a> MuxUdpReceiver<'a> {
    pub fn new() -> MuxUdpReceiver<'a> {
        MuxUdpReceiver {
            rcvr_list: List::new(),
            driver: OptionalCell::empty(),
        }
    }

    pub fn add_client(&self, rcvr: &'a UDPReceiver<'a>) {
        self.rcvr_list.push_tail(rcvr);
    }

    pub fn set_driver(&self, driver_ref: &'static UDPDriver) {
        self.driver.replace(driver_ref);
    }
}

impl<'a> IP6RecvClient for MuxUdpReceiver<'a> {
    fn receive(&self, ip_header: IP6Header, payload: &[u8]) {
        match UDPHeader::decode(payload).done() {
            Some((offset, udp_header)) => {
                let len = udp_header.get_len() as usize;
                let dst_port = udp_header.get_dst_port();
                if len > payload.len() {
                    debug!("[UDP_RECV] Error: Received UDP length too long");
                    return;
                }
                for rcvr in self.rcvr_list.iter() {
                    match rcvr.binding.take() {
                        Some(binding) => {
                            if binding.get_port() == dst_port {
                                rcvr.client.map(|client| {
                                    client.receive(
                                        ip_header.get_src_addr(),
                                        ip_header.get_dst_addr(),
                                        udp_header.get_src_port(),
                                        udp_header.get_dst_port(),
                                        &payload[offset..],
                                    );
                                });
                                rcvr.binding.replace(binding);
                                break;
                            }
                            rcvr.binding.replace(binding);
                        }
                        // The UDPReceiver used by the driver will not have a binding
                        None => match self.driver.take() {
                            Some(driver) => {
                                if driver.is_bound(dst_port) {
                                    driver.receive(
                                        ip_header.get_src_addr(),
                                        ip_header.get_dst_addr(),
                                        udp_header.get_src_port(),
                                        udp_header.get_dst_port(),
                                        &payload[offset..],
                                    );
                                    self.driver.replace(driver);
                                    break;
                                }
                                self.driver.replace(driver);
                            }
                            None => {}
                        },
                    }
                }
            }
            None => {}
        }
    }
}

/// The UDP driver implements this client interface trait to receive
/// packets passed up the network stack to the UDPReceiver, and then
/// distributes them to userland applications from there.
/// Kernel apps can also instantiate structs that implement this trait
/// in order to receive UDP packets
pub trait UDPRecvClient {
    fn receive(
        &self,
        src_addr: IPAddr,
        dst_addr: IPAddr,
        src_port: u16,
        dst_port: u16,
        payload: &[u8],
    );
}

/// This struct is set as the client of the MuxUdpReceiver, and passes
/// received packets up to whatever app layer client assigns itself
/// as the UDPRecvClient held by this UDPReceiver.
pub struct UDPReceiver<'a> {
    client: OptionalCell<&'a dyn UDPRecvClient>,
    binding: MapCell<UdpPortBindingRx>,
    next: ListLink<'a, UDPReceiver<'a>>,
}

impl<'a> ListNode<'a, UDPReceiver<'a>> for UDPReceiver<'a> {
    fn next(&'a self) -> &'a ListLink<'a, UDPReceiver<'a>> {
        &self.next
    }
}

impl<'a> UDPReceiver<'a> {
    pub fn new() -> UDPReceiver<'a> {
        UDPReceiver {
            client: OptionalCell::empty(),
            binding: MapCell::empty(),
            next: ListLink::empty(),
        }
    }

    pub fn set_client(&self, client: &'a dyn UDPRecvClient) {
        self.client.set(client);
    }

    pub fn get_binding(&self) -> Option<UdpPortBindingRx> {
        self.binding.take()
    }

    pub fn is_bound(&self) -> bool {
        self.binding.is_some()
    }

    pub fn set_binding(&self, binding: UdpPortBindingRx) -> Option<UdpPortBindingRx> {
        self.binding.replace(binding)
    }
}