components/
ieee802154.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//! Component for IEEE 802.15.4 radio syscall interface.
6//!
7//! This provides one Component, `Ieee802154Component`, which implements a
8//! userspace syscall interface to a full 802.15.4 stack with a always-on MAC
9//! implementation, as well as multiplexed access to that MAC implementation.
10//!
11//! Usage
12//! -----
13//! ```rust
14//! let aes_mux = components::ieee802154::MuxAes128ccmComponent::new(
15//!     &base_peripherals.ecb,
16//! )
17//!  .finalize(components::mux_aes128ccm_component_static!(
18//!     nrf52840::aes::AesECB
19//! ));
20//!
21//! let (radio, mux_mac) = components::ieee802154::Ieee802154Component::new(
22//!     board_kernel,
23//!     capsules_extra::ieee802154::DRIVER_NUM,
24//!     &nrf52::ieee802154_radio::RADIO,
25//!     aes_mux,
26//!     PAN_ID,
27//!     SRC_MAC,
28//!     deferred_caller,
29//! )
30//! .finalize(components::ieee802154_component_static!(
31//!     nrf52::ieee802154_radio::Radio,
32//!     nrf52::aes::AesECB<'static>
33//! ));
34//! ```
35
36use capsules_core::virtualizers::virtual_aes_ccm::MuxAES128CCM;
37use capsules_extra::ieee802154::device::MacDevice;
38use capsules_extra::ieee802154::mac::{AwakeMac, Mac};
39use core::mem::MaybeUninit;
40use kernel::capabilities;
41use kernel::component::Component;
42use kernel::create_capability;
43use kernel::hil::radio::{self, MAX_BUF_SIZE};
44use kernel::hil::symmetric_encryption::{self, AES128Ctr, AES128, AES128CBC, AES128CCM, AES128ECB};
45
46// This buffer is used as an intermediate buffer for AES CCM encryption. An
47// upper bound on the required size is `3 * BLOCK_SIZE + radio::MAX_BUF_SIZE`.
48pub const CRYPT_SIZE: usize = 3 * symmetric_encryption::AES128_BLOCK_SIZE + radio::MAX_BUF_SIZE;
49
50#[macro_export]
51macro_rules! mux_aes128ccm_component_static {
52    ($A:ty $(,)?) => {{
53        kernel::static_buf!(capsules_core::virtualizers::virtual_aes_ccm::MuxAES128CCM<'static, $A>)
54    };};
55}
56
57pub type MuxAes128ccmComponentType<A> = MuxAES128CCM<'static, A>;
58
59pub struct MuxAes128ccmComponent<A: 'static + AES128<'static> + AES128Ctr + AES128CBC + AES128ECB> {
60    aes: &'static A,
61}
62
63impl<A: 'static + AES128<'static> + AES128Ctr + AES128CBC + AES128ECB> MuxAes128ccmComponent<A> {
64    pub fn new(aes: &'static A) -> Self {
65        Self { aes }
66    }
67}
68
69impl<A: 'static + AES128<'static> + AES128Ctr + AES128CBC + AES128ECB> Component
70    for MuxAes128ccmComponent<A>
71{
72    type StaticInput = &'static mut MaybeUninit<MuxAES128CCM<'static, A>>;
73    type Output = &'static MuxAES128CCM<'static, A>;
74
75    fn finalize(self, static_buffer: Self::StaticInput) -> Self::Output {
76        let aes_mux = static_buffer.write(MuxAES128CCM::new(self.aes));
77        kernel::deferred_call::DeferredCallClient::register(aes_mux);
78        self.aes.set_client(aes_mux);
79
80        aes_mux
81    }
82}
83
84// Setup static space for the objects.
85#[macro_export]
86macro_rules! ieee802154_component_static {
87    ($R:ty, $A:ty $(,)?) => {{
88        let virtual_aes = kernel::static_buf!(
89            capsules_core::virtualizers::virtual_aes_ccm::VirtualAES128CCM<'static, $A>
90        );
91        let awake_mac = kernel::static_buf!(capsules_extra::ieee802154::mac::AwakeMac<'static, $R>);
92        let framer = kernel::static_buf!(
93            capsules_extra::ieee802154::framer::Framer<
94                'static,
95                capsules_extra::ieee802154::mac::AwakeMac<'static, $R>,
96                capsules_core::virtualizers::virtual_aes_ccm::VirtualAES128CCM<'static, $A>,
97            >
98        );
99
100        let mux_mac = kernel::static_buf!(
101            capsules_extra::ieee802154::virtual_mac::MuxMac<
102                'static,
103                capsules_extra::ieee802154::framer::Framer<
104                    'static,
105                    capsules_extra::ieee802154::mac::AwakeMac<'static, $R>,
106                    capsules_core::virtualizers::virtual_aes_ccm::VirtualAES128CCM<'static, $A>,
107                >,
108            >
109        );
110        let mac_user = kernel::static_buf!(
111            capsules_extra::ieee802154::virtual_mac::MacUser<
112                'static,
113                capsules_extra::ieee802154::framer::Framer<
114                    'static,
115                    capsules_extra::ieee802154::mac::AwakeMac<'static, $R>,
116                    capsules_core::virtualizers::virtual_aes_ccm::VirtualAES128CCM<'static, $A>,
117                >,
118            >
119        );
120        let radio_driver = kernel::static_buf!(
121            capsules_extra::ieee802154::RadioDriver<
122                'static,
123                capsules_extra::ieee802154::virtual_mac::MacUser<
124                    'static,
125                    capsules_extra::ieee802154::framer::Framer<
126                        'static,
127                        capsules_extra::ieee802154::mac::AwakeMac<'static, $R>,
128                        capsules_core::virtualizers::virtual_aes_ccm::VirtualAES128CCM<'static, $A>,
129                    >,
130                >,
131            >
132        );
133
134        let radio_buf = kernel::static_buf!([u8; kernel::hil::radio::MAX_BUF_SIZE]);
135        let radio_rx_buf = kernel::static_buf!([u8; kernel::hil::radio::MAX_BUF_SIZE]);
136        let crypt_buf = kernel::static_buf!([u8; components::ieee802154::CRYPT_SIZE]);
137        let radio_rx_crypt_buf = kernel::static_buf!([u8; kernel::hil::radio::MAX_BUF_SIZE]);
138
139        (
140            virtual_aes,
141            awake_mac,
142            framer,
143            mux_mac,
144            mac_user,
145            radio_driver,
146            radio_buf,
147            radio_rx_buf,
148            crypt_buf,
149            radio_rx_crypt_buf,
150        )
151    };};
152}
153
154pub type Ieee802154ComponentType<R, A> = capsules_extra::ieee802154::RadioDriver<
155    'static,
156    capsules_extra::ieee802154::virtual_mac::MacUser<
157        'static,
158        capsules_extra::ieee802154::framer::Framer<
159            'static,
160            capsules_extra::ieee802154::mac::AwakeMac<'static, R>,
161            capsules_core::virtualizers::virtual_aes_ccm::VirtualAES128CCM<'static, A>,
162        >,
163    >,
164>;
165
166pub type Ieee802154ComponentMacDeviceType<R, A> = capsules_extra::ieee802154::framer::Framer<
167    'static,
168    capsules_extra::ieee802154::mac::AwakeMac<'static, R>,
169    capsules_core::virtualizers::virtual_aes_ccm::VirtualAES128CCM<'static, A>,
170>;
171
172pub struct Ieee802154Component<
173    R: 'static + kernel::hil::radio::Radio<'static>,
174    A: 'static + AES128<'static> + AES128Ctr + AES128CBC + AES128ECB,
175> {
176    board_kernel: &'static kernel::Kernel,
177    driver_num: usize,
178    radio: &'static R,
179    aes_mux: &'static MuxAES128CCM<'static, A>,
180    pan_id: capsules_extra::net::ieee802154::PanID,
181    short_addr: u16,
182    long_addr: [u8; 8],
183}
184
185impl<
186        R: 'static + kernel::hil::radio::Radio<'static>,
187        A: 'static + AES128<'static> + AES128Ctr + AES128CBC + AES128ECB,
188    > Ieee802154Component<R, A>
189{
190    pub fn new(
191        board_kernel: &'static kernel::Kernel,
192        driver_num: usize,
193        radio: &'static R,
194        aes_mux: &'static MuxAES128CCM<'static, A>,
195        pan_id: capsules_extra::net::ieee802154::PanID,
196        short_addr: u16,
197        long_addr: [u8; 8],
198    ) -> Self {
199        Self {
200            board_kernel,
201            driver_num,
202            radio,
203            aes_mux,
204            pan_id,
205            short_addr,
206            long_addr,
207        }
208    }
209}
210
211impl<
212        R: 'static + kernel::hil::radio::Radio<'static>,
213        A: 'static + AES128<'static> + AES128Ctr + AES128CBC + AES128ECB,
214    > Component for Ieee802154Component<R, A>
215{
216    type StaticInput = (
217        &'static mut MaybeUninit<
218            capsules_core::virtualizers::virtual_aes_ccm::VirtualAES128CCM<'static, A>,
219        >,
220        &'static mut MaybeUninit<capsules_extra::ieee802154::mac::AwakeMac<'static, R>>,
221        &'static mut MaybeUninit<
222            capsules_extra::ieee802154::framer::Framer<
223                'static,
224                AwakeMac<'static, R>,
225                capsules_core::virtualizers::virtual_aes_ccm::VirtualAES128CCM<'static, A>,
226            >,
227        >,
228        &'static mut MaybeUninit<
229            capsules_extra::ieee802154::virtual_mac::MuxMac<
230                'static,
231                capsules_extra::ieee802154::framer::Framer<
232                    'static,
233                    AwakeMac<'static, R>,
234                    capsules_core::virtualizers::virtual_aes_ccm::VirtualAES128CCM<'static, A>,
235                >,
236            >,
237        >,
238        &'static mut MaybeUninit<
239            capsules_extra::ieee802154::virtual_mac::MacUser<
240                'static,
241                capsules_extra::ieee802154::framer::Framer<
242                    'static,
243                    AwakeMac<'static, R>,
244                    capsules_core::virtualizers::virtual_aes_ccm::VirtualAES128CCM<'static, A>,
245                >,
246            >,
247        >,
248        &'static mut MaybeUninit<
249            capsules_extra::ieee802154::RadioDriver<
250                'static,
251                capsules_extra::ieee802154::virtual_mac::MacUser<
252                    'static,
253                    capsules_extra::ieee802154::framer::Framer<
254                        'static,
255                        AwakeMac<'static, R>,
256                        capsules_core::virtualizers::virtual_aes_ccm::VirtualAES128CCM<'static, A>,
257                    >,
258                >,
259            >,
260        >,
261        &'static mut MaybeUninit<[u8; radio::MAX_BUF_SIZE]>,
262        &'static mut MaybeUninit<[u8; radio::MAX_BUF_SIZE]>,
263        &'static mut MaybeUninit<[u8; CRYPT_SIZE]>,
264        &'static mut MaybeUninit<[u8; radio::MAX_BUF_SIZE]>,
265    );
266    type Output = (
267        &'static capsules_extra::ieee802154::RadioDriver<
268            'static,
269            capsules_extra::ieee802154::virtual_mac::MacUser<
270                'static,
271                capsules_extra::ieee802154::framer::Framer<
272                    'static,
273                    AwakeMac<'static, R>,
274                    capsules_core::virtualizers::virtual_aes_ccm::VirtualAES128CCM<'static, A>,
275                >,
276            >,
277        >,
278        &'static capsules_extra::ieee802154::virtual_mac::MuxMac<
279            'static,
280            capsules_extra::ieee802154::framer::Framer<
281                'static,
282                AwakeMac<'static, R>,
283                capsules_core::virtualizers::virtual_aes_ccm::VirtualAES128CCM<'static, A>,
284            >,
285        >,
286    );
287
288    fn finalize(self, static_buffer: Self::StaticInput) -> Self::Output {
289        let grant_cap = create_capability!(capabilities::MemoryAllocationCapability);
290
291        let crypt_buf = static_buffer.8.write([0; CRYPT_SIZE]);
292        let aes_ccm = static_buffer.0.write(
293            capsules_core::virtualizers::virtual_aes_ccm::VirtualAES128CCM::new(
294                self.aes_mux,
295                crypt_buf,
296            ),
297        );
298        aes_ccm.setup();
299
300        // Keeps the radio on permanently; pass-through layer.
301        let radio_rx_buf = static_buffer.7.write([0; radio::MAX_BUF_SIZE]);
302        let awake_mac = static_buffer.1.write(AwakeMac::new(self.radio));
303        self.radio.set_transmit_client(awake_mac);
304        self.radio.set_receive_client(awake_mac);
305        self.radio.set_receive_buffer(radio_rx_buf);
306
307        let radio_rx_crypt_buf = static_buffer.9.write([0; MAX_BUF_SIZE]);
308
309        let mac_device = static_buffer
310            .2
311            .write(capsules_extra::ieee802154::framer::Framer::new(
312                awake_mac,
313                aes_ccm,
314                kernel::utilities::leasable_buffer::SubSliceMut::new(radio_rx_crypt_buf),
315            ));
316        AES128CCM::set_client(aes_ccm, mac_device);
317        awake_mac.set_transmit_client(mac_device);
318        awake_mac.set_receive_client(mac_device);
319        awake_mac.set_config_client(mac_device);
320
321        let mux_mac = static_buffer
322            .3
323            .write(capsules_extra::ieee802154::virtual_mac::MuxMac::new(
324                mac_device,
325            ));
326        mac_device.set_transmit_client(mux_mac);
327        mac_device.set_receive_client(mux_mac);
328
329        let userspace_mac =
330            static_buffer
331                .4
332                .write(capsules_extra::ieee802154::virtual_mac::MacUser::new(
333                    mux_mac,
334                ));
335        mux_mac.add_user(userspace_mac);
336
337        let radio_buffer = static_buffer.6.write([0; radio::MAX_BUF_SIZE]);
338        let radio_driver = static_buffer
339            .5
340            .write(capsules_extra::ieee802154::RadioDriver::new(
341                userspace_mac,
342                self.board_kernel.create_grant(self.driver_num, &grant_cap),
343                radio_buffer,
344            ));
345        kernel::deferred_call::DeferredCallClient::register(radio_driver);
346
347        mac_device.set_key_procedure(radio_driver);
348        mac_device.set_device_procedure(radio_driver);
349        userspace_mac.set_transmit_client(radio_driver);
350        userspace_mac.set_receive_client(radio_driver);
351        userspace_mac.set_pan(self.pan_id);
352        userspace_mac.set_address(self.short_addr);
353        userspace_mac.set_address_long(self.long_addr);
354
355        (radio_driver, mux_mac)
356    }
357}
358
359// IEEE 802.15.4 RAW DRIVER
360
361// Setup static space for the objects.
362#[macro_export]
363macro_rules! ieee802154_raw_component_static {
364    ($R:ty $(,)?) => {{
365        let radio_driver =
366            kernel::static_buf!(capsules_extra::ieee802154::phy_driver::RadioDriver<$R>);
367        let tx_buffer = kernel::static_buf!([u8; kernel::hil::radio::MAX_BUF_SIZE]);
368        let rx_buffer = kernel::static_buf!([u8; kernel::hil::radio::MAX_BUF_SIZE]);
369
370        (radio_driver, tx_buffer, rx_buffer)
371    };};
372}
373
374pub type Ieee802154RawComponentType<R> =
375    capsules_extra::ieee802154::phy_driver::RadioDriver<'static, R>;
376
377pub struct Ieee802154RawComponent<R: 'static + kernel::hil::radio::Radio<'static>> {
378    board_kernel: &'static kernel::Kernel,
379    driver_num: usize,
380    radio: &'static R,
381}
382
383impl<R: 'static + kernel::hil::radio::Radio<'static>> Ieee802154RawComponent<R> {
384    pub fn new(
385        board_kernel: &'static kernel::Kernel,
386        driver_num: usize,
387        radio: &'static R,
388    ) -> Self {
389        Self {
390            board_kernel,
391            driver_num,
392            radio,
393        }
394    }
395}
396
397impl<R: 'static + kernel::hil::radio::Radio<'static>> Component for Ieee802154RawComponent<R> {
398    type StaticInput = (
399        &'static mut MaybeUninit<capsules_extra::ieee802154::phy_driver::RadioDriver<'static, R>>,
400        &'static mut MaybeUninit<[u8; radio::MAX_BUF_SIZE]>,
401        &'static mut MaybeUninit<[u8; radio::MAX_BUF_SIZE]>,
402    );
403    type Output = &'static capsules_extra::ieee802154::phy_driver::RadioDriver<'static, R>;
404
405    fn finalize(self, static_buffer: Self::StaticInput) -> Self::Output {
406        let grant_cap = create_capability!(capabilities::MemoryAllocationCapability);
407
408        let tx_buffer = static_buffer.1.write([0; MAX_BUF_SIZE]);
409        let radio_rx_buf = static_buffer.2.write([0; radio::MAX_BUF_SIZE]);
410
411        let radio_driver =
412            static_buffer
413                .0
414                .write(capsules_extra::ieee802154::phy_driver::RadioDriver::new(
415                    self.radio,
416                    self.board_kernel.create_grant(self.driver_num, &grant_cap),
417                    tx_buffer,
418                ));
419
420        self.radio.set_transmit_client(radio_driver);
421        self.radio.set_receive_client(radio_driver);
422        self.radio.set_receive_buffer(radio_rx_buf);
423
424        radio_driver
425    }
426}