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.
45//! Virtual IEEE 802.15.4 MAC device
6//!
7//! `MuxMac` provides multiplexed access to an 802.15.4 MAC device. This enables
8//! a single underlying 802.15.4 radio to be shared transparently by multiple
9//! users. For example, the kernel might want to send raw 802.15.4 frames and
10//! subsequently 6LoWPAN-encoded and fragmented IP packets. This capsule allows
11//! that to happen by providing a mechanism for sequencing transmission attempts,
12//! Every radio frame received is provided to all listening clients so that each
13//! client can perform its own frame filtering logic.
14//!
15//! Usage
16//! -----
17//!
18//! ```rust,ignore
19//! # use kernel::static_init;
20//!
21//! // Create the mux.
22//! let mux_mac = static_init!(
23//! capsules::ieee802154::virtual_mac::MuxMac<'static>,
24//! capsules::ieee802154::virtual_mac::MuxMac::new(&'static mac_device));
25//! mac_device.set_transmit_client(mux_mac);
26//! mac_device.set_receive_client(mux_mac);
27//!
28//! // Everything that uses the virtualized MAC device must create one of these.
29//! let virtual_mac = static_init!(
30//! capsules::ieee802154::virtual_mac::MacUser<'static>,
31//! capsules::ieee802154::virtual_mac::MacUser::new(mux_mac));
32//! mux_mac.add_user(virtual_mac);
33//! ```
3435use crate::ieee802154::{device, framer};
36use crate::net::ieee802154::{Header, KeyId, MacAddress, PanID, SecurityLevel};
3738use kernel::collections::list::{List, ListLink, ListNode};
39use kernel::utilities::cells::{MapCell, OptionalCell};
40use kernel::ErrorCode;
4142/// IEE 802.15.4 MAC device muxer that keeps a list of MAC users and sequences
43/// any pending transmission requests. Any received frames from the underlying
44/// MAC device are sent to all users.
45pub struct MuxMac<'a, M: device::MacDevice<'a>> {
46 mac: &'a M,
47 users: List<'a, MacUser<'a, M>>,
48 inflight: OptionalCell<&'a MacUser<'a, M>>,
49}
5051impl<'a, M: device::MacDevice<'a>> device::TxClient for MuxMac<'a, M> {
52fn send_done(&self, spi_buf: &'static mut [u8], acked: bool, result: Result<(), ErrorCode>) {
53self.inflight.take().map(move |user| {
54 user.send_done(spi_buf, acked, result);
55 });
56self.do_next_op_async();
57 }
58}
5960impl<'a, M: device::MacDevice<'a>> device::RxClient for MuxMac<'a, M> {
61fn receive<'b>(
62&self,
63 buf: &'b [u8],
64 header: Header<'b>,
65 lqi: u8,
66 data_offset: usize,
67 data_len: usize,
68 ) {
69for user in self.users.iter() {
70 user.receive(buf, header, lqi, data_offset, data_len);
71 }
72 }
73}
7475impl<'a, M: device::MacDevice<'a>> MuxMac<'a, M> {
76pub const fn new(mac: &'a M) -> MuxMac<'a, M> {
77 MuxMac {
78 mac,
79 users: List::new(),
80 inflight: OptionalCell::empty(),
81 }
82 }
8384/// Registers a MAC user with this MAC mux device. Each MAC user should only
85 /// be registered once.
86pub fn add_user(&self, user: &'a MacUser<'a, M>) {
87self.users.push_head(user);
88 }
8990/// Gets the next `MacUser` and operation to perform if an operation is not
91 /// already underway.
92fn get_next_op_if_idle(&self) -> Option<(&'a MacUser<'a, M>, Op)> {
93if self.inflight.is_some() {
94return None;
95 }
9697let mnode = self.users.iter().find(|node| {
98 node.operation.take().is_some_and(|op| {
99let pending = op != Op::Idle;
100 node.operation.replace(op);
101 pending
102 })
103 });
104 mnode.and_then(|node| {
105 node.operation.take().map(|op| {
106 node.operation.replace(Op::Idle);
107 (node, op)
108 })
109 })
110 }
111112/// Performs a non-idle operation on a `MacUser` asynchronously: that is, if the
113 /// transmission operation results in immediate failure, then return the
114 /// buffer to the `MacUser` via its transmit client.
115fn perform_op_async(&self, node: &'a MacUser<'a, M>, op: Op) {
116if let Op::Transmit(frame) = op {
117match self.mac.transmit(frame) {
118// If Err, the transmission failed,
119 // otherwise it succeeded.
120Ok(()) => {
121self.inflight.set(node);
122 }
123Err((ecode, buf)) => {
124 node.send_done(buf, false, Err(ecode));
125 }
126 }
127 }
128 }
129130/// Performs a non-idle operation on a `MacUser` synchronously, returning
131 /// the error code and the buffer immediately.
132fn perform_op_sync(
133&self,
134 node: &'a MacUser<'a, M>,
135 op: Op,
136 ) -> Option<Result<(), (ErrorCode, &'static mut [u8])>> {
137if let Op::Transmit(frame) = op {
138let result = self.mac.transmit(frame);
139if result.is_ok() {
140self.inflight.set(node);
141 }
142Some(result)
143 } else {
144None
145}
146 }
147148/// Begins the next outstanding transmission if there is no ongoing
149 /// operation and there is a user waiting to transmit a frame.
150 /// Since this is being called asynchronously, return any buffers to the active
151 /// `tx_client` via the `send_done` callback in the event of failure.
152fn do_next_op_async(&self) {
153self.get_next_op_if_idle()
154 .map(|(node, op)| self.perform_op_async(node, op));
155 }
156157/// Begins the next outstanding transmission if there is no ongoing
158 /// operation and there is a user waiting to transmit a frame. Since this is
159 /// being called synchronously, there is a need to identify the MacUser that
160 /// just queued its transmission request. This can only be done by comparing
161 /// the raw pointer references of the two users, since there is no
162 /// type-level way to guarantee that the enqueued user is actually in this Mux device's
163 /// `users` list. It's safe because the raw pointer references are never
164 /// dereferenced.
165 ///
166 /// If the newly-enqueued transmission is immediately executed by this mux
167 /// device but fails immediately, return the buffer synchronously.
168fn do_next_op_sync(
169&self,
170 new_node: &MacUser<'a, M>,
171 ) -> Option<Result<(), (ErrorCode, &'static mut [u8])>> {
172self.get_next_op_if_idle().and_then(|(node, op)| {
173if core::ptr::eq(node, new_node) {
174// The new node's operation is the one being scheduled, so the
175 // operation is synchronous
176self.perform_op_sync(node, op)
177 } else {
178// The operation being scheduled is not the new node, so the
179 // operation is asynchronous with respect to the new node.
180self.perform_op_async(node, op);
181None
182}
183 })
184 }
185}
186187#[derive(Eq, PartialEq, Debug)]
188enum Op {
189 Idle,
190 Transmit(framer::Frame),
191}
192193/// Keep state for each Mac user.
194///
195/// All users of the virtualized MAC interface need to create one of
196/// these and register it with the MAC device muxer `MuxMac` by
197/// calling `MuxMac#add_user`. Then, each `MacUser` behaves exactly
198/// like an independent MAC device, except MAC device state is shared
199/// between all MacUsers because there is only one MAC device. For
200/// example, the MAC device address is shared, so calling
201/// `set_address` on one `MacUser` sets the MAC address for all
202/// `MacUser`s.
203pub struct MacUser<'a, M: device::MacDevice<'a>> {
204 mux: &'a MuxMac<'a, M>,
205 operation: MapCell<Op>,
206 next: ListLink<'a, MacUser<'a, M>>,
207 tx_client: OptionalCell<&'a dyn device::TxClient>,
208 rx_client: OptionalCell<&'a dyn device::RxClient>,
209}
210211impl<'a, M: device::MacDevice<'a>> MacUser<'a, M> {
212pub const fn new(mux: &'a MuxMac<'a, M>) -> Self {
213Self {
214 mux,
215 operation: MapCell::new(Op::Idle),
216 next: ListLink::empty(),
217 tx_client: OptionalCell::empty(),
218 rx_client: OptionalCell::empty(),
219 }
220 }
221}
222223impl<'a, M: device::MacDevice<'a>> MacUser<'a, M> {
224fn send_done(&self, spi_buf: &'static mut [u8], acked: bool, result: Result<(), ErrorCode>) {
225self.tx_client
226 .get()
227 .map(move |client| client.send_done(spi_buf, acked, result));
228 }
229230fn receive<'b>(
231&self,
232 buf: &'b [u8],
233 header: Header<'b>,
234 lqi: u8,
235 data_offset: usize,
236 data_len: usize,
237 ) {
238self.rx_client
239 .get()
240 .map(move |client| client.receive(buf, header, lqi, data_offset, data_len));
241 }
242}
243244impl<'a, M: device::MacDevice<'a>> ListNode<'a, MacUser<'a, M>> for MacUser<'a, M> {
245fn next(&'a self) -> &'a ListLink<'a, MacUser<'a, M>> {
246&self.next
247 }
248}
249250impl<'a, M: device::MacDevice<'a>> device::MacDevice<'a> for MacUser<'a, M> {
251fn set_transmit_client(&self, client: &'a dyn device::TxClient) {
252self.tx_client.set(client);
253 }
254255fn set_receive_client(&self, client: &'a dyn device::RxClient) {
256self.rx_client.set(client);
257 }
258259fn get_address(&self) -> u16 {
260self.mux.mac.get_address()
261 }
262263fn get_address_long(&self) -> [u8; 8] {
264self.mux.mac.get_address_long()
265 }
266267fn get_pan(&self) -> u16 {
268self.mux.mac.get_pan()
269 }
270271fn set_address(&self, addr: u16) {
272self.mux.mac.set_address(addr)
273 }
274275fn set_address_long(&self, addr: [u8; 8]) {
276self.mux.mac.set_address_long(addr)
277 }
278279fn set_pan(&self, id: u16) {
280self.mux.mac.set_pan(id)
281 }
282283fn config_commit(&self) {
284self.mux.mac.config_commit()
285 }
286287fn is_on(&self) -> bool {
288self.mux.mac.is_on()
289 }
290291fn start(&self) -> Result<(), ErrorCode> {
292self.mux.mac.start()
293 }
294295fn prepare_data_frame(
296&self,
297 buf: &'static mut [u8],
298 dst_pan: PanID,
299 dst_addr: MacAddress,
300 src_pan: PanID,
301 src_addr: MacAddress,
302 security_needed: Option<(SecurityLevel, KeyId)>,
303 ) -> Result<framer::Frame, &'static mut [u8]> {
304self.mux
305 .mac
306 .prepare_data_frame(buf, dst_pan, dst_addr, src_pan, src_addr, security_needed)
307 }
308309fn transmit(&self, frame: framer::Frame) -> Result<(), (ErrorCode, &'static mut [u8])> {
310// If the muxer is idle, immediately transmit the frame, otherwise
311 // attempt to queue the transmission request. However, each MAC user can
312 // only have one pending transmission request, so if there already is a
313 // pending transmission then we must fail to entertain this one.
314match self.operation.take() {
315None => Err((ErrorCode::FAIL, frame.into_buf())),
316Some(op) => match op {
317 Op::Idle => {
318self.operation.replace(Op::Transmit(frame));
319self.mux.do_next_op_sync(self).unwrap_or(Ok(()))
320 }
321 Op::Transmit(old_frame) => {
322self.operation.replace(Op::Transmit(old_frame));
323Err((ErrorCode::BUSY, frame.into_buf()))
324 }
325 },
326 }
327 }
328}