Skip to main content

components/
thread_network.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 2023.
4
5//! Component to initialize the Thread Network.
6//!
7//! This provides one Component, ThreadNetworkComponent. This component initializes
8//! a Thread Network controller for maintaining and managing a Thread network.
9//!
10//! Usage
11//! -----
12//! ```rust
13//!        let thread_driver = components::thread_network::ThreadNetworkComponent::new(
14//!             board_kernel,
15//!             capsules_extra::net::thread::driver::DRIVER_NUM,
16//!             udp_send_mux,
17//!             udp_recv_mux,
18//!             udp_port_table,
19//!             aes_mux,
20//!             device_id,
21//!             mux_alarm,
22//!         )
23//!         .finalize(components::thread_network_component_static!(
24//!         nrf52840::rtc::Rtc,
25//!         nrf52840::aes::AesECB<'static>
26//!         ));
27//! ```
28
29use capsules_core::virtualizers::virtual_aes_ccm::MuxAES128CCM;
30use capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm;
31use capsules_extra::net::ipv6::ipv6_send::IP6SendStruct;
32use capsules_extra::net::network_capabilities::{
33    AddrRange, NetworkCapability, PortRange, UdpVisibilityCapability,
34};
35use kernel::hil::symmetric_encryption::{self, AES, AES128, AESCBC, AESCCM, AESCtr, AESECB};
36
37use capsules_core::virtualizers::virtual_alarm::MuxAlarm;
38use capsules_extra::net::thread::thread_utils::THREAD_PORT_NUMBER;
39use capsules_extra::net::udp::udp_port_table::UdpPortManager;
40use capsules_extra::net::udp::udp_recv::MuxUdpReceiver;
41use capsules_extra::net::udp::udp_recv::UDPReceiver;
42use capsules_extra::net::udp::udp_send::{MuxUdpSender, UDPSendStruct, UDPSender};
43use core::mem::MaybeUninit;
44use kernel::capabilities::{
45    MemoryAllocationCapability, NetworkCapabilityCreationCapability, UdpDriverCapability,
46};
47use kernel::component::Component;
48use kernel::hil::radio;
49use kernel::hil::time::Alarm;
50
51const MAX_PAYLOAD_LEN: usize = super::udp_mux::MAX_PAYLOAD_LEN;
52pub const CRYPT_SIZE: usize = 3 * symmetric_encryption::AES_BLOCK_SIZE + radio::MAX_BUF_SIZE;
53
54// Setup static space for the objects.
55#[macro_export]
56macro_rules! thread_network_component_static {
57    ($A:ty, $B:ty, $C:ty $(,)?) => {{
58        use components::udp_mux::MAX_PAYLOAD_LEN;
59
60        let udp_send = kernel::static_buf!(
61            capsules_extra::net::udp::udp_send::UDPSendStruct<
62                'static,
63                capsules_extra::net::ipv6::ipv6_send::IP6SendStruct<
64                    'static,
65                    capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<'static, $A>,
66                >,
67            >
68        );
69        let udp_vis_cap =
70            kernel::static_buf!(capsules_extra::net::network_capabilities::UdpVisibilityCapability);
71        let net_cap =
72            kernel::static_buf!(capsules_extra::net::network_capabilities::NetworkCapability);
73        let thread_network_driver = kernel::static_buf!(
74            capsules_extra::net::thread::driver::ThreadNetworkDriver<
75                'static,
76                VirtualMuxAlarm<'static, $A>,
77            >
78        );
79        let send_buffer = kernel::static_buf!([u8; MAX_PAYLOAD_LEN]);
80        let recv_buffer = kernel::static_buf!([u8; MAX_PAYLOAD_LEN]);
81        let udp_recv =
82            kernel::static_buf!(capsules_extra::net::udp::udp_recv::UDPReceiver<'static>);
83        let crypt_buf = kernel::static_buf!([u8; components::ieee802154::CRYPT_SIZE]);
84        let crypt = kernel::static_buf!(
85            capsules_core::virtualizers::virtual_aes_ccm::VirtualAES128CCM<'static, $B>,
86        );
87        let alarm = kernel::static_buf!(VirtualMuxAlarm<'static, $A>);
88        let driver_cap = kernel::static_buf!($C);
89
90        (
91            udp_send,
92            udp_vis_cap,
93            net_cap,
94            thread_network_driver,
95            send_buffer,
96            recv_buffer,
97            udp_recv,
98            crypt_buf,
99            crypt,
100            alarm,
101            driver_cap,
102        )
103    }};
104}
105pub struct ThreadNetworkComponent<
106    A: Alarm<'static> + 'static,
107    B: AES<'static, AES128> + AESCtr + AESCBC + AESECB + 'static,
108    C: UdpDriverCapability + 'static,
109    MEM: MemoryAllocationCapability + 'static,
110    NET: NetworkCapabilityCreationCapability + 'static,
111> {
112    board_kernel: &'static kernel::Kernel,
113    driver_num: usize,
114    udp_send_mux:
115        &'static MuxUdpSender<'static, IP6SendStruct<'static, VirtualMuxAlarm<'static, A>>>,
116    udp_recv_mux: &'static MuxUdpReceiver<'static>,
117    port_table: &'static UdpPortManager,
118    aes_mux: &'static MuxAES128CCM<'static, B>,
119    serial_num: [u8; 8],
120    alarm_mux: &'static MuxAlarm<'static, A>,
121    driver_cap: C,
122    mem_cap: MEM,
123    create_cap: NET,
124}
125
126impl<
127    A: Alarm<'static> + 'static,
128    B: AES<'static, AES128> + AESCtr + AESCBC + AESECB + 'static,
129    C: UdpDriverCapability + 'static,
130    MEM: MemoryAllocationCapability + 'static,
131    NET: NetworkCapabilityCreationCapability + 'static,
132> ThreadNetworkComponent<A, B, C, MEM, NET>
133{
134    pub fn new(
135        board_kernel: &'static kernel::Kernel,
136        driver_num: usize,
137        udp_send_mux: &'static MuxUdpSender<
138            'static,
139            IP6SendStruct<'static, VirtualMuxAlarm<'static, A>>,
140        >,
141        udp_recv_mux: &'static MuxUdpReceiver<'static>,
142        port_table: &'static UdpPortManager,
143        aes_mux: &'static MuxAES128CCM<'static, B>,
144        serial_num: [u8; 8],
145        alarm_mux: &'static MuxAlarm<'static, A>,
146        driver_cap: C,
147        mem_cap: MEM,
148        create_cap: NET,
149    ) -> Self {
150        Self {
151            board_kernel,
152            driver_num,
153            udp_send_mux,
154            udp_recv_mux,
155            port_table,
156            aes_mux,
157            serial_num,
158            alarm_mux,
159            driver_cap,
160            mem_cap,
161            create_cap,
162        }
163    }
164}
165
166impl<
167    A: Alarm<'static> + 'static,
168    B: AES<'static, AES128> + AESCtr + AESCBC + AESECB + 'static,
169    C: UdpDriverCapability + 'static,
170    MEM: MemoryAllocationCapability + 'static,
171    NET: NetworkCapabilityCreationCapability + 'static,
172> Component for ThreadNetworkComponent<A, B, C, MEM, NET>
173{
174    type StaticInput = (
175        &'static mut MaybeUninit<
176            UDPSendStruct<
177                'static,
178                capsules_extra::net::ipv6::ipv6_send::IP6SendStruct<
179                    'static,
180                    VirtualMuxAlarm<'static, A>,
181                >,
182            >,
183        >,
184        &'static mut MaybeUninit<
185            capsules_extra::net::network_capabilities::UdpVisibilityCapability,
186        >,
187        &'static mut MaybeUninit<capsules_extra::net::network_capabilities::NetworkCapability>,
188        &'static mut MaybeUninit<
189            capsules_extra::net::thread::driver::ThreadNetworkDriver<
190                'static,
191                VirtualMuxAlarm<'static, A>,
192            >,
193        >,
194        &'static mut MaybeUninit<[u8; MAX_PAYLOAD_LEN]>,
195        &'static mut MaybeUninit<[u8; MAX_PAYLOAD_LEN]>,
196        &'static mut MaybeUninit<UDPReceiver<'static>>,
197        &'static mut MaybeUninit<[u8; CRYPT_SIZE]>,
198        &'static mut MaybeUninit<
199            capsules_core::virtualizers::virtual_aes_ccm::VirtualAES128CCM<'static, B>,
200        >,
201        &'static mut MaybeUninit<VirtualMuxAlarm<'static, A>>,
202        &'static mut MaybeUninit<C>,
203    );
204    type Output = &'static capsules_extra::net::thread::driver::ThreadNetworkDriver<
205        'static,
206        VirtualMuxAlarm<'static, A>,
207    >;
208
209    fn finalize(self, s: Self::StaticInput) -> Self::Output {
210        let thread_virtual_alarm: &mut VirtualMuxAlarm<'_, A> =
211            s.9.write(VirtualMuxAlarm::new(self.alarm_mux));
212        thread_virtual_alarm.setup();
213
214        // AES-128CCM setup
215        let crypt_buf = s.7.write([0; CRYPT_SIZE]);
216        let aes_ccm = s.8.write(
217            capsules_core::virtualizers::virtual_aes_ccm::VirtualAES128CCM::new(
218                self.aes_mux,
219                crypt_buf,
220            ),
221        );
222        aes_ccm.setup();
223
224        let udp_vis = s.1.write(UdpVisibilityCapability::new(&self.create_cap));
225        let udp_send = s.0.write(UDPSendStruct::new(self.udp_send_mux, udp_vis));
226
227        let driver_cap: &'static C = s.10.write(self.driver_cap);
228
229        let net_cap = s.2.write(NetworkCapability::new(
230            AddrRange::Any,
231            PortRange::Any,
232            PortRange::Any,
233            &self.create_cap,
234        ));
235
236        let send_buffer = s.4.write([0; MAX_PAYLOAD_LEN]);
237        let recv_buffer = s.5.write([0; MAX_PAYLOAD_LEN]);
238
239        let thread_network_driver = s.3.write(
240            capsules_extra::net::thread::driver::ThreadNetworkDriver::new(
241                udp_send,
242                aes_ccm,
243                thread_virtual_alarm,
244                self.board_kernel
245                    .create_grant(self.driver_num, &self.mem_cap),
246                self.serial_num,
247                MAX_PAYLOAD_LEN,
248                self.port_table,
249                kernel::utilities::leasable_buffer::SubSliceMut::new(send_buffer),
250                kernel::utilities::leasable_buffer::SubSliceMut::new(recv_buffer),
251                driver_cap,
252                net_cap,
253            ),
254        );
255
256        thread_virtual_alarm.set_alarm_client(thread_network_driver);
257
258        udp_send.set_client(thread_network_driver);
259        AESCCM::set_client(aes_ccm, thread_network_driver);
260
261        let udp_driver_rcvr = s.6.write(UDPReceiver::new());
262        udp_driver_rcvr.set_client(thread_network_driver);
263
264        // TODO: Thread requires port 19788 for sending/receiving MLE messages.
265        // The below implementation binds Thread to the required port and updates
266        // the UDP receiving/sending objects. There is a chance that creating a socket
267        // fails due to the max number of sockets being exceeded or failing to bind
268        // the requested port. In either case, the current implementation panics here
269        // as it is impossible to create a Thread network without port 19788 (used for MLE).
270        // Future implementations may wish to change this behavior.
271        self.port_table
272            .create_socket()
273            .map(|socket| {
274                self.port_table
275                    .bind(socket, THREAD_PORT_NUMBER, net_cap)
276                    .map_or_else(
277                        |_| (),
278                        |(tx_bind, rx_bind)| {
279                            udp_driver_rcvr.set_binding(rx_bind);
280                            udp_send.set_binding(tx_bind);
281                        },
282                    )
283            })
284            .unwrap();
285
286        self.udp_recv_mux.add_client(udp_driver_rcvr);
287
288        thread_network_driver
289    }
290}