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, const RN: usize = DEFAULT_CHANNEL_REPLAY, const HN: usize = DEFAULT_CHANNEL_HINT_REPLAY> { /* private fields */ }

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, const RN: usize, const HN: usize> Mac<P, IDENTITIES, PEERS, CHANNELS, ACKS, TX, FRAME, DUP, RN, HN>

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 const fn counters(&self) -> MacCounters

Cumulative frame tallies since construction.

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, RN, HN>

Borrow the channel table.

Source

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

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.

§Flash-wear invariant

This method must remain read-only. In particular, booting or repeatedly rebooting without transmitting must never write a new reservation and wear out embedded flash. The first authenticated send schedules the future reservation; the MAC driver services that pending write because actual transmission has made persistence necessary.

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 async fn load_all_persisted_rx_counters( &mut self, ) -> Result<usize, <P::CounterStore as CounterStore>::Error>

Load persisted RX frame-counter boundaries for all registered peers and store them in [PeerInfo::initial_rx_counter].

Call this once at boot after registering all known peers. When pairwise keys are first derived for each peer, the replay window is initialised to the loaded boundary so frames replayed from before the reboot are rejected.

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, AddPeerError>

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

When the software-crypto feature is enabled, the supplied public key is validated as a well-formed Ed25519 compressed point on the curve. Malformed keys are rejected with AddPeerError::InvalidPublicKey before they can pollute the peer registry.

Source

pub fn remove_peer(&mut self, key: &PublicKey) -> bool

Removes a registered peer and every piece of per-peer transport state: pairwise crypto, replay windows, pending counter resyncs, and any deferred inbound frame. Returns whether the peer was registered.

The peer registry is dense, so removal moves the last entry into the freed slot; state keyed by the moved peer’s old identifier is re-keyed here. Persisted RX counter boundaries are deliberately retained: if the peer is re-added later, replay protection resumes from the stored boundary instead of accepting replays from before the removal.

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 remove_channel(&mut self, key: &ChannelKey) -> bool

Removes a previously added channel by its exact key, discarding the channel’s replay state with it (re-adding the key later starts at first contact). Returns whether a channel was removed.

Source

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

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

The name is canonicalized (ASCII lowercase fold) before derivation, so Public and public register the same channel.

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.

Note: the encrypted, ack_requested, and salt flags on options are silently forced to false because broadcasts cannot carry any of them on the wire.

TODO: this sanitization is silent — a caller that explicitly set ack_requested = true for a broadcast will get a successful SendReceipt and never learn the flag was dropped. Surface this as a debug-level event (or split SendOptions into kind-specific builders) so the loss is observable.

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, ack_trailer: [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, ack_trailer: [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 fn poll_wait_for_wake( &mut self, cx: &mut Context<'_>, buf: &mut [u8; FRAME], ) -> Poll<Result<WakeReason, <P::Radio as Radio>::Error>>

Register radio/timer wakers and report what has become ready.

This is Phase 2 of next_event exposed as a sync poll method so that callers sharing the coordinator through an AsyncRefCell can release the exclusive borrow between polls. The caller-provided buf is populated with the received frame when the return value is WakeReason::Received.

Source

pub async fn process_wake_reason( &mut self, reason: WakeReason, buf: &mut [u8; FRAME], on_event: impl FnMut(LocalIdentityId, MacEventRef<'_>), ) -> Result<(), MacError<<P::Radio as Radio>::Error>>

Run Phases 3-5 after poll_wait_for_wake has reported a wake reason: process the received frame (if any), drain immediate ACKs, and service pending ACK timeouts.

§Precondition

When reason is WakeReason::Received, buf must be the same buffer — containing the same bytes — that was passed to the matching poll_wait_for_wake call. The received frame bytes live in buf[..rx.len]; reason only carries the accompanying metadata (RxInfo). Passing a different or reinitialized buffer will cause the received frame to be silently discarded and the contents of buf to be misinterpreted as a MAC frame.

This precondition only matters when using the split-phase API for AsyncRefCell sharing. When driving the coordinator through next_event the buffer is a local stack variable and the pairing is guaranteed automatically.

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 process_received_frame( &mut self, buf: &mut [u8; FRAME], frame_len: usize, rx: &RxInfo, on_event: impl FnMut(LocalIdentityId, MacEventRef<'_>), ) -> bool

Process a received frame, dispatching events through on_event.

This is the shared implementation used by both receive_one and next_event. Returns true when the frame produced at least one event or side-effect.

Every reception passes through here exactly once, which is what makes it the place to tally them: the rx_frames/rx_accepted pair counts one radio reception and whether anything came of it.

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_trailer: &[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.

Source

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

Ensure key is registered at least transiently, returning its slot.

A known peer is returned as-is; an unknown one is auto-registered exactly like a full-source sender would be — unpinned and LRU-evictable, never promoted. This is the node layer’s hook for answering a stranger (an Identity Request reply, say) whose frame arrived on a path that does not auto-register its source, such as a broadcast. Deliberately not gated on auto_register_full_key_peers: the caller is making an explicit per-peer decision, not opting into registering every full-source sender.

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, const RN: usize, const HN: usize> Freeze for Mac<P, IDENTITIES, PEERS, CHANNELS, ACKS, TX, FRAME, DUP, RN, HN>
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, const RN: usize, const HN: usize> RefUnwindSafe for Mac<P, IDENTITIES, PEERS, CHANNELS, ACKS, TX, FRAME, DUP, RN, HN>

§

impl<P, const IDENTITIES: usize, const PEERS: usize, const CHANNELS: usize, const ACKS: usize, const TX: usize, const FRAME: usize, const DUP: usize, const RN: usize, const HN: usize> Send for Mac<P, IDENTITIES, PEERS, CHANNELS, ACKS, TX, FRAME, DUP, RN, HN>
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, const RN: usize, const HN: usize> Sync for Mac<P, IDENTITIES, PEERS, CHANNELS, ACKS, TX, FRAME, DUP, RN, HN>
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, const RN: usize, const HN: usize> Unpin for Mac<P, IDENTITIES, PEERS, CHANNELS, ACKS, TX, FRAME, DUP, RN, HN>
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, const RN: usize, const HN: usize> UnwindSafe for Mac<P, IDENTITIES, PEERS, CHANNELS, ACKS, TX, FRAME, DUP, RN, HN>

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.