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, AES128Ctr, AES128, AES128CBC, AES128CCM, AES128ECB};
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;
45use kernel::capabilities::NetworkCapabilityCreationCapability;
46use kernel::component::Component;
47use kernel::create_capability;
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::AES128_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 $(,)?) => {{
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
89        (
90            udp_send,
91            udp_vis_cap,
92            net_cap,
93            thread_network_driver,
94            send_buffer,
95            recv_buffer,
96            udp_recv,
97            crypt_buf,
98            crypt,
99            alarm,
100        )
101    };};
102}
103pub struct ThreadNetworkComponent<
104    A: Alarm<'static> + 'static,
105    B: AES128<'static> + AES128Ctr + AES128CBC + AES128ECB + 'static,
106> {
107    board_kernel: &'static kernel::Kernel,
108    driver_num: usize,
109    udp_send_mux:
110        &'static MuxUdpSender<'static, IP6SendStruct<'static, VirtualMuxAlarm<'static, A>>>,
111    udp_recv_mux: &'static MuxUdpReceiver<'static>,
112    port_table: &'static UdpPortManager,
113    aes_mux: &'static MuxAES128CCM<'static, B>,
114    serial_num: [u8; 8],
115    alarm_mux: &'static MuxAlarm<'static, A>,
116}
117
118impl<
119        A: Alarm<'static> + 'static,
120        B: AES128<'static> + AES128Ctr + AES128CBC + AES128ECB + 'static,
121    > ThreadNetworkComponent<A, B>
122{
123    pub fn new(
124        board_kernel: &'static kernel::Kernel,
125        driver_num: usize,
126        udp_send_mux: &'static MuxUdpSender<
127            'static,
128            IP6SendStruct<'static, VirtualMuxAlarm<'static, A>>,
129        >,
130        udp_recv_mux: &'static MuxUdpReceiver<'static>,
131        port_table: &'static UdpPortManager,
132        aes_mux: &'static MuxAES128CCM<'static, B>,
133        serial_num: [u8; 8],
134        alarm_mux: &'static MuxAlarm<'static, A>,
135    ) -> Self {
136        Self {
137            board_kernel,
138            driver_num,
139            udp_send_mux,
140            udp_recv_mux,
141            port_table,
142            aes_mux,
143            serial_num,
144            alarm_mux,
145        }
146    }
147}
148
149impl<
150        A: Alarm<'static> + 'static,
151        B: AES128<'static> + AES128Ctr + AES128CBC + AES128ECB + 'static,
152    > Component for ThreadNetworkComponent<A, B>
153{
154    type StaticInput = (
155        &'static mut MaybeUninit<
156            UDPSendStruct<
157                'static,
158                capsules_extra::net::ipv6::ipv6_send::IP6SendStruct<
159                    'static,
160                    VirtualMuxAlarm<'static, A>,
161                >,
162            >,
163        >,
164        &'static mut MaybeUninit<
165            capsules_extra::net::network_capabilities::UdpVisibilityCapability,
166        >,
167        &'static mut MaybeUninit<capsules_extra::net::network_capabilities::NetworkCapability>,
168        &'static mut MaybeUninit<
169            capsules_extra::net::thread::driver::ThreadNetworkDriver<
170                'static,
171                VirtualMuxAlarm<'static, A>,
172            >,
173        >,
174        &'static mut MaybeUninit<[u8; MAX_PAYLOAD_LEN]>,
175        &'static mut MaybeUninit<[u8; MAX_PAYLOAD_LEN]>,
176        &'static mut MaybeUninit<UDPReceiver<'static>>,
177        &'static mut MaybeUninit<[u8; CRYPT_SIZE]>,
178        &'static mut MaybeUninit<
179            capsules_core::virtualizers::virtual_aes_ccm::VirtualAES128CCM<'static, B>,
180        >,
181        &'static mut MaybeUninit<VirtualMuxAlarm<'static, A>>,
182    );
183    type Output = &'static capsules_extra::net::thread::driver::ThreadNetworkDriver<
184        'static,
185        VirtualMuxAlarm<'static, A>,
186    >;
187
188    fn finalize(self, s: Self::StaticInput) -> Self::Output {
189        let thread_virtual_alarm: &mut VirtualMuxAlarm<'_, A> =
190            s.9.write(VirtualMuxAlarm::new(self.alarm_mux));
191        thread_virtual_alarm.setup();
192
193        let grant_cap = create_capability!(capabilities::MemoryAllocationCapability);
194
195        // AES-128CCM setup
196        let crypt_buf = s.7.write([0; CRYPT_SIZE]);
197        let aes_ccm = s.8.write(
198            capsules_core::virtualizers::virtual_aes_ccm::VirtualAES128CCM::new(
199                self.aes_mux,
200                crypt_buf,
201            ),
202        );
203        aes_ccm.setup();
204
205        let create_cap = create_capability!(NetworkCapabilityCreationCapability);
206        let udp_vis = s.1.write(UdpVisibilityCapability::new(&create_cap));
207        let udp_send = s.0.write(UDPSendStruct::new(self.udp_send_mux, udp_vis));
208
209        // Can't use create_capability bc need capability to have a static lifetime
210        // so that Thread driver can use it as needed
211        struct DriverCap;
212        unsafe impl capabilities::UdpDriverCapability for DriverCap {}
213        static DRIVER_CAP: DriverCap = DriverCap;
214
215        let net_cap = s.2.write(NetworkCapability::new(
216            AddrRange::Any,
217            PortRange::Any,
218            PortRange::Any,
219            &create_cap,
220        ));
221
222        let send_buffer = s.4.write([0; MAX_PAYLOAD_LEN]);
223        let recv_buffer = s.5.write([0; MAX_PAYLOAD_LEN]);
224
225        let thread_network_driver = s.3.write(
226            capsules_extra::net::thread::driver::ThreadNetworkDriver::new(
227                udp_send,
228                aes_ccm,
229                thread_virtual_alarm,
230                self.board_kernel.create_grant(self.driver_num, &grant_cap),
231                self.serial_num,
232                MAX_PAYLOAD_LEN,
233                self.port_table,
234                kernel::utilities::leasable_buffer::SubSliceMut::new(send_buffer),
235                kernel::utilities::leasable_buffer::SubSliceMut::new(recv_buffer),
236                &DRIVER_CAP,
237                net_cap,
238            ),
239        );
240
241        thread_virtual_alarm.set_alarm_client(thread_network_driver);
242
243        udp_send.set_client(thread_network_driver);
244        AES128CCM::set_client(aes_ccm, thread_network_driver);
245
246        let udp_driver_rcvr = s.6.write(UDPReceiver::new());
247        udp_driver_rcvr.set_client(thread_network_driver);
248
249        // TODO: Thread requires port 19788 for sending/receiving MLE messages.
250        // The below implementation binds Thread to the required port and updates
251        // the UDP receiving/sending objects. There is a chance that creating a socket
252        // fails due to the max number of sockets being exceeded or failing to bind
253        // the requested port. In either case, the current implementation panics here
254        // as it is impossible to create a Thread network without port 19788 (used for MLE).
255        // Future implementations may wish to change this behavior.
256        self.port_table
257            .create_socket()
258            .map(|socket| {
259                self.port_table
260                    .bind(socket, THREAD_PORT_NUMBER, net_cap)
261                    .map_or_else(
262                        |_| (),
263                        |(tx_bind, rx_bind)| {
264                            udp_driver_rcvr.set_binding(rx_bind);
265                            udp_send.set_binding(tx_bind);
266                        },
267                    )
268            })
269            .unwrap();
270
271        self.udp_recv_mux.add_client(udp_driver_rcvr);
272
273        thread_network_driver
274    }
275}