1use core::future::poll_fn;
2
3use rand::Rng;
4use umsh_core::{ChannelId, ChannelKey, PublicKey};
5use umsh_hal::{Clock, CounterStore};
6use umsh_sync::AsyncRefCell;
7
8use crate::{
9 AddPeerError, CapacityError, DEFAULT_ACKS, DEFAULT_CHANNEL_HINT_REPLAY, DEFAULT_CHANNEL_REPLAY,
10 DEFAULT_CHANNELS, DEFAULT_DUP, DEFAULT_FRAME, DEFAULT_IDENTITIES, DEFAULT_PEERS, DEFAULT_TX,
11 Platform,
12 coordinator::{CounterPersistenceError, LocalIdentityId, Mac, MacError, SendError},
13 peers::PeerId,
14 send::{SendOptions, SendReceipt},
15};
16
17pub struct MacHandle<
24 'a,
25 P: Platform,
26 const IDENTITIES: usize = DEFAULT_IDENTITIES,
27 const PEERS: usize = DEFAULT_PEERS,
28 const CHANNELS: usize = DEFAULT_CHANNELS,
29 const ACKS: usize = DEFAULT_ACKS,
30 const TX: usize = DEFAULT_TX,
31 const FRAME: usize = DEFAULT_FRAME,
32 const DUP: usize = DEFAULT_DUP,
33 const RN: usize = DEFAULT_CHANNEL_REPLAY,
34 const HN: usize = DEFAULT_CHANNEL_HINT_REPLAY,
35> {
36 mac: &'a AsyncRefCell<Mac<P, IDENTITIES, PEERS, CHANNELS, ACKS, TX, FRAME, DUP, RN, HN>>,
37}
38
39impl<
40 'a,
41 P: Platform,
42 const IDENTITIES: usize,
43 const PEERS: usize,
44 const CHANNELS: usize,
45 const ACKS: usize,
46 const TX: usize,
47 const FRAME: usize,
48 const DUP: usize,
49 const RN: usize,
50 const HN: usize,
51> Copy for MacHandle<'a, P, IDENTITIES, PEERS, CHANNELS, ACKS, TX, FRAME, DUP, RN, HN>
52{
53}
54
55impl<
56 'a,
57 P: Platform,
58 const IDENTITIES: usize,
59 const PEERS: usize,
60 const CHANNELS: usize,
61 const ACKS: usize,
62 const TX: usize,
63 const FRAME: usize,
64 const DUP: usize,
65 const RN: usize,
66 const HN: usize,
67> Clone for MacHandle<'a, P, IDENTITIES, PEERS, CHANNELS, ACKS, TX, FRAME, DUP, RN, HN>
68{
69 fn clone(&self) -> Self {
70 *self
71 }
72}
73
74impl<
75 'a,
76 P: Platform,
77 const IDENTITIES: usize,
78 const PEERS: usize,
79 const CHANNELS: usize,
80 const ACKS: usize,
81 const TX: usize,
82 const FRAME: usize,
83 const DUP: usize,
84 const RN: usize,
85 const HN: usize,
86> MacHandle<'a, P, IDENTITIES, PEERS, CHANNELS, ACKS, TX, FRAME, DUP, RN, HN>
87{
88 pub fn new(
90 mac: &'a AsyncRefCell<Mac<P, IDENTITIES, PEERS, CHANNELS, ACKS, TX, FRAME, DUP, RN, HN>>,
91 ) -> Self {
92 Self { mac }
93 }
94
95 pub async fn counters(&self) -> crate::MacCounters {
97 self.mac.borrow().await.counters()
98 }
99
100 pub async fn add_identity(
102 &self,
103 identity: P::Identity,
104 ) -> Result<LocalIdentityId, CapacityError> {
105 self.mac.borrow_mut().await.add_identity(identity)
106 }
107
108 pub async fn load_persisted_counter(
110 &self,
111 id: LocalIdentityId,
112 ) -> Result<u32, CounterPersistenceError<<P::CounterStore as CounterStore>::Error>> {
113 self.mac.borrow_mut().await.load_persisted_counter(id).await
114 }
115
116 pub async fn service_counter_persistence(
118 &self,
119 ) -> Result<usize, <P::CounterStore as CounterStore>::Error> {
120 self.mac
121 .borrow_mut()
122 .await
123 .service_counter_persistence()
124 .await
125 }
126
127 pub async fn load_all_persisted_rx_counters(
136 &self,
137 ) -> Result<usize, <P::CounterStore as CounterStore>::Error> {
138 self.mac
139 .borrow_mut()
140 .await
141 .load_all_persisted_rx_counters()
142 .await
143 }
144
145 pub async fn add_peer(&self, key: PublicKey) -> Result<PeerId, AddPeerError> {
147 self.mac.borrow_mut().await.add_peer(key)
148 }
149
150 pub async fn remove_peer(&self, key: &PublicKey) -> bool {
154 self.mac.borrow_mut().await.remove_peer(key)
155 }
156
157 pub async fn ensure_transient_peer(&self, key: &PublicKey) -> bool {
161 self.mac
162 .borrow_mut()
163 .await
164 .ensure_transient_peer(key)
165 .is_ok()
166 }
167
168 pub async fn add_channel(&self, key: ChannelKey) -> Result<(), CapacityError> {
170 self.mac.borrow_mut().await.add_channel(key)
171 }
172
173 pub async fn remove_channel(&self, key: &ChannelKey) -> bool {
176 self.mac.borrow_mut().await.remove_channel(key)
177 }
178
179 pub async fn add_named_channel(&self, name: &str) -> Result<(), crate::AddChannelError> {
183 self.mac.borrow_mut().await.add_named_channel(name)
184 }
185
186 pub async fn auto_register_full_key_peers(&self) -> bool {
188 self.mac.borrow().await.auto_register_full_key_peers()
189 }
190
191 pub async fn set_auto_register_full_key_peers(&self, enabled: bool) {
193 self.mac
194 .borrow_mut()
195 .await
196 .set_auto_register_full_key_peers(enabled);
197 }
198
199 pub async fn repeater_enabled(&self) -> bool {
201 self.mac.borrow().await.repeater_config().enabled
202 }
203
204 pub async fn set_repeater_enabled(&self, enabled: bool) {
210 self.mac.borrow_mut().await.repeater_config_mut().enabled = enabled;
211 }
212
213 pub async fn set_repeater_policy(
225 &self,
226 regions: &[[u8; 2]],
227 default_region: Option<[u8; 2]>,
228 min_rssi: Option<i16>,
229 min_snr: Option<i8>,
230 ) -> usize {
231 let mut mac = self.mac.borrow_mut().await;
232 let config = mac.repeater_config_mut();
233 config.regions.clear();
234 for region in regions {
235 if config.regions.push(*region).is_err() {
236 break;
237 }
238 }
239 config.default_region = default_region;
240 config.min_rssi = min_rssi;
241 config.min_snr = min_snr;
242 config.regions.len()
243 }
244
245 #[cfg(any(feature = "unsafe-advanced", test))]
250 pub(crate) async fn install_pairwise_keys(
251 &self,
252 identity_id: LocalIdentityId,
253 peer_id: PeerId,
254 pairwise_keys: umsh_crypto::PairwiseKeys,
255 ) -> Result<Option<crate::peers::PeerCryptoState>, SendError> {
256 self.mac
257 .borrow_mut()
258 .await
259 .install_pairwise_keys(identity_id, peer_id, pairwise_keys)
260 }
261
262 #[cfg(feature = "unsafe-advanced")]
269 pub async fn install_pairwise_keys_advanced(
270 &self,
271 identity_id: LocalIdentityId,
272 peer_id: PeerId,
273 pairwise_keys: umsh_crypto::PairwiseKeys,
274 ) -> Result<Option<crate::peers::PeerCryptoState>, SendError> {
275 self.install_pairwise_keys(identity_id, peer_id, pairwise_keys)
276 .await
277 }
278
279 pub async fn send_broadcast(
281 &self,
282 from: LocalIdentityId,
283 payload: &[u8],
284 options: &SendOptions,
285 ) -> Result<SendReceipt, SendError> {
286 self.mac
287 .borrow_mut()
288 .await
289 .send_broadcast(from, payload, options)
290 .await
291 }
292
293 pub async fn send_multicast(
295 &self,
296 from: LocalIdentityId,
297 channel: &ChannelId,
298 payload: &[u8],
299 options: &SendOptions,
300 ) -> Result<SendReceipt, SendError> {
301 self.mac
302 .borrow_mut()
303 .await
304 .send_multicast(from, channel, payload, options)
305 .await
306 }
307
308 pub async fn send_unicast(
310 &self,
311 from: LocalIdentityId,
312 dst: &PublicKey,
313 payload: &[u8],
314 options: &SendOptions,
315 ) -> Result<Option<SendReceipt>, SendError> {
316 self.mac
317 .borrow_mut()
318 .await
319 .send_unicast(from, dst, payload, options)
320 .await
321 }
322
323 pub async fn send_blind_unicast(
325 &self,
326 from: LocalIdentityId,
327 dst: &PublicKey,
328 channel: &ChannelId,
329 payload: &[u8],
330 options: &SendOptions,
331 ) -> Result<Option<SendReceipt>, SendError> {
332 self.mac
333 .borrow_mut()
334 .await
335 .send_blind_unicast(from, dst, channel, payload, options)
336 .await
337 }
338
339 pub async fn next_event(
346 &self,
347 mut on_event: impl FnMut(LocalIdentityId, crate::MacEventRef<'_>),
348 ) -> Result<(), MacError<<P::Radio as umsh_hal::Radio>::Error>> {
349 loop {
350 self.mac
352 .borrow_mut()
353 .await
354 .drain_tx_queue(&mut on_event)
355 .await?;
356
357 let mut buf = [0u8; FRAME];
370 let mut cond_ticket = self.mac.scoped_ticket();
371 let reason = poll_fn(|cx| {
372 self.mac.poll_with_mut(cx, &mut cond_ticket, |mac, cx| {
373 mac.poll_wait_for_wake(cx, &mut buf)
375 })
376 })
377 .await
378 .map_err(MacError::Radio)?;
379 drop(cond_ticket);
380
381 self.mac
383 .borrow_mut()
384 .await
385 .process_wake_reason(reason, &mut buf, &mut on_event)
386 .await?;
387
388 {
393 let mut mac = self.mac.borrow_mut().await;
394 let _ = mac.service_counter_persistence().await;
395 let _ = mac.service_rx_counter_persistence().await;
396 }
397
398 let tx_empty = self.mac.borrow().await.tx_queue().is_empty();
402 if !tx_empty {
403 continue;
404 }
405 return Ok(());
406 }
407 }
408
409 pub async fn run(
413 &self,
414 mut on_event: impl FnMut(LocalIdentityId, crate::MacEventRef<'_>),
415 ) -> Result<(), MacError<<P::Radio as umsh_hal::Radio>::Error>> {
416 loop {
417 self.next_event(&mut on_event).await?;
418 }
419 }
420
421 pub async fn run_quiet(&self) -> Result<(), MacError<<P::Radio as umsh_hal::Radio>::Error>> {
423 self.run(|_, _| {}).await
424 }
425
426 pub async fn fill_random(&self, dest: &mut [u8]) {
428 self.mac.borrow_mut().await.rng_mut().fill_bytes(dest);
429 }
430
431 pub async fn now_ms(&self) -> u64 {
433 self.mac.borrow().await.clock().now_ms()
434 }
435
436 #[cfg(feature = "software-crypto")]
437 pub async fn register_ephemeral(
439 &self,
440 parent: LocalIdentityId,
441 identity: umsh_crypto::software::SoftwareIdentity,
442 ) -> Result<LocalIdentityId, CapacityError> {
443 self.mac
444 .borrow_mut()
445 .await
446 .register_ephemeral(parent, identity)
447 }
448
449 #[cfg(feature = "software-crypto")]
450 pub async fn remove_ephemeral(&self, id: LocalIdentityId) -> bool {
452 self.mac.borrow_mut().await.remove_ephemeral(id)
453 }
454
455 pub async fn cancel_pending_ack(
459 &self,
460 identity_id: LocalIdentityId,
461 receipt: SendReceipt,
462 ) -> bool {
463 self.mac
464 .borrow_mut()
465 .await
466 .cancel_pending_ack(identity_id, receipt)
467 }
468
469 pub async fn frame_counter(&self, id: LocalIdentityId) -> Option<u32> {
471 self.mac
472 .borrow()
473 .await
474 .identity(id)
475 .map(|slot| slot.frame_counter())
476 }
477
478 pub async fn persisted_frame_counter(&self, id: LocalIdentityId) -> Option<u32> {
480 self.mac
481 .borrow()
482 .await
483 .identity(id)
484 .map(|slot| slot.persisted_counter())
485 }
486
487 pub async fn for_each_peer(&self, f: &mut dyn FnMut(umsh_core::PublicKey)) {
491 let mac = self.mac.borrow().await;
492 for (_, info) in mac.peer_registry().iter() {
493 f(info.public_key);
494 }
495 }
496
497 pub async fn peer_route(&self, peer: &umsh_core::PublicKey) -> Option<crate::CachedRoute> {
500 let mac = self.mac.borrow().await;
501 let (peer_id, _) = mac.peer_registry().lookup_by_key(peer)?;
502 mac.peer_registry().get(peer_id)?.route.clone()
503 }
504
505 pub async fn clear_peer_route(&self, peer: &umsh_core::PublicKey) -> bool {
507 let mut mac = self.mac.borrow_mut().await;
508 let Some((peer_id, _)) = mac.peer_registry().lookup_by_key(peer) else {
509 return false;
510 };
511 mac.peer_registry_mut().clear_route(peer_id)
512 }
513
514 pub async fn for_each_peer_counter(
517 &self,
518 id: LocalIdentityId,
519 f: &mut dyn FnMut(umsh_core::PublicKey, u32, u32),
520 ) {
521 let mac = self.mac.borrow().await;
522 let Some(slot) = mac.identity(id) else {
523 return;
524 };
525 for (peer_id, state) in slot.peer_crypto().iter() {
526 let Some(info) = mac.peer_registry().get(*peer_id) else {
527 continue;
528 };
529 f(
530 info.public_key,
531 state.replay_window.last_accepted,
532 state.persisted_rx_counter,
533 );
534 }
535 }
536}