Mac

Struct Mac 

Source
pub struct Mac<P: Platform, const IDENTITIES: usize = DEFAULT_IDENTITIES, const PEERS: usize = DEFAULT_PEERS, const CHANNELS: usize = DEFAULT_CHANNELS, const ACKS: usize = DEFAULT_ACKS, const TX: usize = DEFAULT_TX, const FRAME: usize = MAX_RESEND_FRAME_LEN, const DUP: usize = DEFAULT_DUP> { /* private fields */ }
Expand description

Central MAC coordinator that owns and drives the full UMSH radio-facing state machine.

Mac is the top-level entry point for UMSH protocol operation. It combines a radio driver, cryptographic engine, clock, RNG, counter store, and all protocol state into a single fully-typed, allocation-free structure. All const-generic capacity parameters are enforced at compile time via heapless collections — there are no heap allocations inside Mac.

§Generic parameters

  • P: Platform — a trait bundle supplying the concrete driver types for Radio, Aes/Sha (crypto), Clock, Rng, and CounterStore. Implement Platform once per deployment target to swap in real hardware drivers, software stubs, or test doubles.
  • IDENTITIES — maximum simultaneously active local identities (default DEFAULT_IDENTITIES).
  • PEERS — maximum known remote peers and their per-identity pairwise key entries (default DEFAULT_PEERS).
  • CHANNELS — maximum registered multicast channel keys (default DEFAULT_CHANNELS).
  • ACKS — maximum simultaneously in-flight ACK-requested sends per identity (default DEFAULT_ACKS).
  • TX — depth of the transmit queue (default DEFAULT_TX). Must be large enough to absorb a burst of control frames (MAC ACKs + forwarded frames) alongside any backlogged application sends.
  • FRAME — maximum byte length of a stored frame buffer for retransmission (default [MAX_RESEND_FRAME_LEN]).
  • DUP — capacity of the duplicate-detection cache (default DEFAULT_DUP).

§Lifecycle

  1. Construct with Mac::new, supplying concrete driver instances and policy.
  2. Register identities via Mac::add_identity; call Mac::load_persisted_counter on each long-term identity to restore the safe frame-counter start point from non-volatile storage.
  3. Register peers via Mac::add_peer. Secure unicast and blind-unicast state is derived lazily from the local private key and peer public key on first use.
  4. Register channels via Mac::add_channel or Mac::add_named_channel.
  5. Drive the event loop via Mac::run / Mac::run_quiet for long-lived tasks, or by awaiting Mac::next_event when you need to multiplex MAC progress with other async work. The coordinator handles incoming frames, outgoing transmits, forwarding, ACK matching, retransmission scheduling, and timer deadlines — no external polling required.
  6. Send traffic by calling queue_broadcast, queue_unicast, queue_multicast, etc. from application code between (or concurrent with) event-loop iterations.
  7. Persist counters by calling Mac::service_counter_persistence whenever next_event signals that pending persistence work is ready to flush.

§Example (pseudo-code)

let mut mac = Mac::<MyPlatform>::new(
    radio, crypto, clock, rng, counter_store,
    RepeaterConfig::default(), OperatingPolicy::default(),
);
let id = mac.add_identity(my_identity)?;
mac.load_persisted_counter(id).await?;

mac.run(|id, event| {
    let _ = (id, event);
    // handle deliveries / ACKs here and schedule persistence work as needed
}).await?;

Implementations§

Source§

impl<P: Platform, const IDENTITIES: usize, const PEERS: usize, const CHANNELS: usize, const ACKS: usize, const TX: usize, const FRAME: usize, const DUP: usize> Mac<P, IDENTITIES, PEERS, CHANNELS, ACKS, TX, FRAME, DUP>

Source

pub fn new( radio: P::Radio, crypto: CryptoEngine<P::Aes, P::Sha>, clock: P::Clock, rng: P::Rng, counter_store: P::CounterStore, repeater: RepeaterConfig, operating_policy: OperatingPolicy, ) -> Self

Creates a MAC coordinator with the supplied radio, crypto, timing, and policy state.

Source

pub fn radio(&self) -> &P::Radio

Borrow the underlying radio.

Source

pub fn radio_mut(&mut self) -> &mut P::Radio

Mutably borrow the underlying radio.

Source

pub fn crypto(&self) -> &CryptoEngine<P::Aes, P::Sha>

Borrow the crypto engine.

Source

pub fn clock(&self) -> &P::Clock

Borrow the monotonic clock.

Source

pub fn rng(&self) -> &P::Rng

Borrow the RNG.

Source

pub fn rng_mut(&mut self) -> &mut P::Rng

Mutably borrow the RNG.

Source

pub fn counter_store(&self) -> &P::CounterStore

Borrow the counter store.

Source

pub fn tx_queue(&self) -> &TxQueue<TX, FRAME>

Borrow the transmit queue.

Source

pub fn tx_queue_mut(&mut self) -> &mut TxQueue<TX, FRAME>

Mutably borrow the transmit queue.

Source

pub fn dup_cache(&self) -> &DuplicateCache<DUP>

Borrow the duplicate cache.

Source

pub fn peer_registry(&self) -> &PeerRegistry<PEERS>

Borrow the peer registry.

Source

pub fn peer_registry_mut(&mut self) -> &mut PeerRegistry<PEERS>

Mutably borrow the peer registry.

Source

pub fn channels(&self) -> &ChannelTable<CHANNELS>

Borrow the channel table.

Source

pub fn channels_mut(&mut self) -> &mut ChannelTable<CHANNELS>

Mutably borrow the channel table.

Source

pub fn repeater_config(&self) -> &RepeaterConfig

Borrow repeater configuration.

Source

pub fn repeater_config_mut(&mut self) -> &mut RepeaterConfig

Mutably borrow repeater configuration.

Source

pub fn operating_policy(&self) -> &OperatingPolicy

Borrow the local operating policy.

Source

pub fn operating_policy_mut(&mut self) -> &mut OperatingPolicy

Mutably borrow the local operating policy.

Source

pub fn auto_register_full_key_peers(&self) -> bool

Return whether inbound secure packets carrying a full source key may auto-register peers.

Source

pub fn set_auto_register_full_key_peers(&mut self, enabled: bool)

Enable or disable inbound full-key peer auto-registration.

Source

pub fn add_identity( &mut self, identity: P::Identity, ) -> Result<LocalIdentityId, CapacityError>

Register one long-term local identity.

Source

pub async fn load_persisted_counter( &mut self, id: LocalIdentityId, ) -> Result<u32, CounterPersistenceError<<P::CounterStore as CounterStore>::Error>>

Load the persisted frame-counter boundary for id from the counter store.

Source

pub async fn service_counter_persistence( &mut self, ) -> Result<usize, <P::CounterStore as CounterStore>::Error>

Persist all currently scheduled frame-counter reservations.

Source

pub fn register_ephemeral( &mut self, parent: LocalIdentityId, identity: SoftwareIdentity, ) -> Result<LocalIdentityId, CapacityError>

Register an ephemeral software identity linked to parent.

Source

pub fn remove_ephemeral(&mut self, id: LocalIdentityId) -> bool

Remove an ephemeral identity slot if one exists at id.

Source

pub fn identity( &self, id: LocalIdentityId, ) -> Option<&IdentitySlot<P::Identity, PEERS, ACKS, FRAME>>

Borrow an identity slot by identifier.

Source

pub fn identity_mut( &mut self, id: LocalIdentityId, ) -> Option<&mut IdentitySlot<P::Identity, PEERS, ACKS, FRAME>>

Mutably borrow an identity slot by identifier.

Source

pub fn add_peer(&mut self, key: PublicKey) -> Result<PeerId, CapacityError>

Registers or refreshes a known remote peer in the shared registry.

Source

pub fn add_channel(&mut self, key: ChannelKey) -> Result<(), CapacityError>

Adds or updates a shared channel and derives its multicast keys.

Source

pub fn add_named_channel(&mut self, name: &str) -> Result<(), CapacityError>

Adds or updates a named channel using the coordinator’s channel-key derivation.

Source

pub fn identity_count(&self) -> usize

Return the number of occupied identity slots.

Source

pub fn install_pairwise_keys_advanced( &mut self, identity_id: LocalIdentityId, peer_id: PeerId, pairwise_keys: PairwiseKeys, ) -> Result<Option<PeerCryptoState>, SendError>

Installs pairwise transport keys for one local identity and remote peer.

§Safety (logical)

Installing wrong keys will silently corrupt the session. This method is deliberately gated behind the unsafe-advanced feature. Prefer going through the node-layer PFS session manager instead.

Source

pub fn queue_broadcast( &mut self, from: LocalIdentityId, payload: &[u8], options: &SendOptions, ) -> Result<SendReceipt, SendError>

Enqueues a broadcast frame for transmission.

Source

pub async fn send_broadcast( &mut self, from: LocalIdentityId, payload: &[u8], options: &SendOptions, ) -> Result<SendReceipt, SendError>

Enqueue a broadcast frame for transmission.

Source

pub fn queue_multicast( &mut self, from: LocalIdentityId, channel_id: &ChannelId, payload: &[u8], options: &SendOptions, ) -> Result<SendReceipt, SendError>

Enqueues a multicast frame using the configured channel keys.

Source

pub async fn send_multicast( &mut self, from: LocalIdentityId, channel_id: &ChannelId, payload: &[u8], options: &SendOptions, ) -> Result<SendReceipt, SendError>

Enqueue a multicast frame for transmission.

Source

pub fn queue_mac_ack_for_peer( &mut self, peer_id: PeerId, dst: NodeHint, ack_tag: [u8; 8], ) -> Result<(), SendError>

Enqueues a MAC ACK frame, using any cached route to peer_id when available.

Source

pub fn queue_mac_ack( &mut self, dst: NodeHint, ack_tag: [u8; 8], ) -> Result<(), SendError>

Enqueues an immediate direct MAC ACK frame.

Source

pub fn queue_unicast( &mut self, from: LocalIdentityId, peer: &PublicKey, payload: &[u8], options: &SendOptions, ) -> Result<Option<SendReceipt>, SendError>

Enqueues a unicast frame and optional pending-ACK state.

Source

pub async fn send_unicast( &mut self, from: LocalIdentityId, peer: &PublicKey, payload: &[u8], options: &SendOptions, ) -> Result<Option<SendReceipt>, SendError>

Enqueue a unicast frame for transmission, deriving secure peer state on first use.

Source

pub fn queue_blind_unicast( &mut self, from: LocalIdentityId, peer: &PublicKey, channel_id: &ChannelId, payload: &[u8], options: &SendOptions, ) -> Result<Option<SendReceipt>, SendError>

Enqueues a blind-unicast frame and optional pending-ACK state.

Source

pub async fn send_blind_unicast( &mut self, from: LocalIdentityId, peer: &PublicKey, channel_id: &ChannelId, payload: &[u8], options: &SendOptions, ) -> Result<Option<SendReceipt>, SendError>

Enqueue a blind-unicast frame for transmission, deriving secure peer state on first use.

Source

pub async fn transmit_next( &mut self, on_event: &mut impl FnMut(LocalIdentityId, MacEventRef<'_>), ) -> Result<Option<SendReceipt>, MacError<<P::Radio as Radio>::Error>>

Transmit the next eligible queued frame, if any.

While a post-transmit forwarding listen window is active, only immediate MAC ACK traffic is permitted to bypass the listen state. Forwarded sends arm a new listen window after the radio transmit completes. Non-immediate traffic honors queued CAD backoff state and gives up after the configured maximum number of CAD attempts.

Source

pub async fn drain_tx_queue( &mut self, on_event: &mut impl FnMut(LocalIdentityId, MacEventRef<'_>), ) -> Result<(), MacError<<P::Radio as Radio>::Error>>

Keep transmitting until the queue is empty.

Progress stops when CAD keeps reporting busy, when a post-transmit listen window blocks normal traffic, or when the queue is otherwise unable to shrink further in the current cycle.

Source

pub async fn poll_cycle( &mut self, on_event: impl FnMut(LocalIdentityId, MacEventRef<'_>), ) -> Result<(), MacError<<P::Radio as Radio>::Error>>

Runs one coordinator cycle over the current MAC state.

The cycle performs four ordered phases:

  1. Drain any queued transmit work.
  2. Receive and process at most one inbound frame.
  3. Drain any immediate ACK generated during receive handling.
  4. Service pending ACK timers and emit timeout events.

The callback may be invoked zero or more times depending on what the receive and timeout phases accept or resolve. Service one MAC coordinator cycle.

Source

pub fn earliest_deadline_ms(&self) -> Option<u64>

Compute the earliest deadline across all coordinator timers.

Returns None when there are no pending timers. The returned value covers pending ACK deadlines (both ack_deadline_ms and forwarding confirm_deadline_ms), the post-transmit listen window, and deferred transmit-queue entries.

Source

pub async fn next_event( &mut self, on_event: impl FnMut(LocalIdentityId, MacEventRef<'_>), ) -> Result<(), MacError<<P::Radio as Radio>::Error>>

Run the coordinator’s event loop until at least one event is delivered or a timer-driven action (retransmit, timeout) is processed.

Unlike poll_cycle, this method properly awaits the radio and timer deadlines instead of returning immediately when nothing is ready. Callers can use tokio::select! (or equivalent) to multiplex user input alongside MAC events:

loop {
    tokio::select! {
        line = stdin.next_line() => { /* handle input */ }
        result = mac.next_event(|id, event| { /* handle event */ }) => {
            result?;
        }
    }
}
Source

pub async fn run( &mut self, on_event: impl FnMut(LocalIdentityId, MacEventRef<'_>), ) -> Result<(), MacError<<P::Radio as Radio>::Error>>

Drive the coordinator forever, invoking on_event for each delivered event.

This is the preferred long-lived run loop for standalone MAC-driven tasks such as repeaters or dedicated radio services. Unlike manually calling poll_cycle in a loop, run keeps the wake/sleep policy inside the coordinator by delegating to next_event, which already waits for radio activity and protocol deadlines.

Source

pub async fn run_quiet( &mut self, ) -> Result<(), MacError<<P::Radio as Radio>::Error>>

Drive the coordinator forever while ignoring emitted events.

Useful for standalone repeaters or bridge tasks that do not need to observe inbound deliveries directly but still need the coordinator to service forwarding, ACKs, and retransmissions without an app-owned polling loop.

Source

pub async fn receive_one( &mut self, on_event: impl FnMut(LocalIdentityId, MacEventRef<'_>), ) -> Result<bool, MacError<<P::Radio as Radio>::Error>>

Non-blocking receive: polls the radio once and processes a frame if available.

This is the legacy non-blocking API used by poll_cycle. For new code, prefer next_event which properly awaits the radio and timer deadlines.

Source

pub fn complete_ack( &mut self, peer: &PublicKey, ack_tag: &[u8; 8], ) -> Option<(LocalIdentityId, SendReceipt)>

Mark a pending receipt as acknowledged and emit an event through on_event.

Source

pub fn service_pending_ack_timeouts( &mut self, on_event: impl FnMut(LocalIdentityId, MacEventRef<'_>), ) -> Result<(), CapacityError>

Expire or retry pending ACK state based on now_ms.

Source

pub fn cancel_pending_ack( &mut self, identity_id: LocalIdentityId, receipt: SendReceipt, ) -> bool

Cancel a pending ACK-requested send, stopping retransmissions.

Removes the pending ACK entry for the given identity slot and receipt, and removes any matching entry from the transmit queue. Returns true if a pending ACK was found and removed.

Auto Trait Implementations§

§

impl<P, const IDENTITIES: usize, const PEERS: usize, const CHANNELS: usize, const ACKS: usize, const TX: usize, const FRAME: usize, const DUP: usize> Freeze for Mac<P, IDENTITIES, PEERS, CHANNELS, ACKS, TX, FRAME, DUP>
where <P as Platform>::Radio: Freeze, <P as Platform>::Clock: Freeze, <P as Platform>::Rng: Freeze, <P as Platform>::CounterStore: Freeze, <P as Platform>::Aes: Freeze, <P as Platform>::Sha: Freeze, <P as Platform>::Identity: Freeze,

§

impl<P, const IDENTITIES: usize, const PEERS: usize, const CHANNELS: usize, const ACKS: usize, const TX: usize, const FRAME: usize, const DUP: usize> RefUnwindSafe for Mac<P, IDENTITIES, PEERS, CHANNELS, ACKS, TX, FRAME, DUP>

§

impl<P, const IDENTITIES: usize, const PEERS: usize, const CHANNELS: usize, const ACKS: usize, const TX: usize, const FRAME: usize, const DUP: usize> Send for Mac<P, IDENTITIES, PEERS, CHANNELS, ACKS, TX, FRAME, DUP>
where <P as Platform>::Radio: Send, <P as Platform>::Clock: Send, <P as Platform>::Rng: Send, <P as Platform>::CounterStore: Send, <P as Platform>::Aes: Send, <P as Platform>::Sha: Send, <P as Platform>::Identity: Send,

§

impl<P, const IDENTITIES: usize, const PEERS: usize, const CHANNELS: usize, const ACKS: usize, const TX: usize, const FRAME: usize, const DUP: usize> Sync for Mac<P, IDENTITIES, PEERS, CHANNELS, ACKS, TX, FRAME, DUP>
where <P as Platform>::Radio: Sync, <P as Platform>::Clock: Sync, <P as Platform>::Rng: Sync, <P as Platform>::CounterStore: Sync, <P as Platform>::Aes: Sync, <P as Platform>::Sha: Sync, <P as Platform>::Identity: Sync,

§

impl<P, const IDENTITIES: usize, const PEERS: usize, const CHANNELS: usize, const ACKS: usize, const TX: usize, const FRAME: usize, const DUP: usize> Unpin for Mac<P, IDENTITIES, PEERS, CHANNELS, ACKS, TX, FRAME, DUP>
where <P as Platform>::Radio: Unpin, <P as Platform>::Clock: Unpin, <P as Platform>::Rng: Unpin, <P as Platform>::CounterStore: Unpin, <P as Platform>::Aes: Unpin, <P as Platform>::Sha: Unpin, <P as Platform>::Identity: Unpin,

§

impl<P, const IDENTITIES: usize, const PEERS: usize, const CHANNELS: usize, const ACKS: usize, const TX: usize, const FRAME: usize, const DUP: usize> UnwindSafe for Mac<P, IDENTITIES, PEERS, CHANNELS, ACKS, TX, FRAME, DUP>

Blanket Implementations§

§

impl<T> Any for T
where T: 'static + ?Sized,

§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<T> Borrow<T> for T
where T: ?Sized,

§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
§

impl<T> BorrowMut<T> for T
where T: ?Sized,

§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> From<T> for T

§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T, U> Into<U> for T
where U: From<T>,

§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.