modules/woz_matter/include/matter_mrp.h
openaliro/openaliro
Module

matter_mrp.h

Message Reliability Protocol: backoff, retransmit, dedup.

modules/woz_matter/include/matter_mrp.h2 documented symbols

Overview

Message Reliability Protocol: backoff, retransmit, dedup. Matter runs over UDP, so reliability is the application's problem. MRP is the answer: mark a message as needing an acknowledgement, retransmit on an exponential backoff until it is acked, and drop counters you have already seen. Two objects with two different lifetimes, deliberately not merged: struct matter_mrp_window per SESSION — duplicate suppression struct matter_mrp per EXCHANGE — one un-acked message, one owed ack NO TIMERS LIVE HERE. Every entry point takes now_ms and the object only ever computes deadlines, so the caller owns the timer and this layer stays testable on the host with a fake clock. That is also the stage 0 work-queue constraint honoured by construction: a module that never arms a timer cannot accidentally arm one on k_sys_work_q, which was measured at 3,568 of 4,096 bytes with the reader running.

depends on matter_status.h  ·  used by matter_exchange.h matter_mrp.c

API

Cstruct matter_mrp_window

modules/woz_matter/include/matter_mrp.h:122

Replay window over a peer's message counters. bitmap bit i records that counter max_counter - (i + 1) has been seen, so a message up to MATTER_MRP_WINDOW_BITS behind the high-water mark is still placed exactly. Anything older than that is refused, because there is no longer any evidence either way and accepting is the unsafe guess.

Cstruct matter_mrp

modules/woz_matter/include/matter_mrp.h:156

Per-exchange reliability state. At most ONE un-acked message at a time, which is the protocol's own rule and not a simplification: MRP has no send window, so an exchange with a message in flight must wait (CircuitMatter enforces the same thing at exchange.py:67-68). The exchange layer owns the message bytes; this struct holds only the counter and the deadlines.

##define MATTER_MRP_MARGIN_NUM 1127u

modules/woz_matter/include/matter_mrp.h:61

##define MATTER_MRP_MARGIN_DEN 1024u

modules/woz_matter/include/matter_mrp.h:62

##define MATTER_MRP_BASE_NUM 16u

modules/woz_matter/include/matter_mrp.h:63

##define MATTER_MRP_BASE_DEN 10u

modules/woz_matter/include/matter_mrp.h:64

##define MATTER_MRP_JITTER_BASE 1024u

modules/woz_matter/include/matter_mrp.h:66

Jitter is (JITTER_BASE + rand[0,255]) / JITTER_BASE, i.e. 1.0 .. 1.249.

##define MATTER_MRP_THRESHOLD 1u

modules/woz_matter/include/matter_mrp.h:68

Retransmissions before the backoff starts growing.

##define MATTER_MRP_MAX_EXP 4u

modules/woz_matter/include/matter_mrp.h:70

CHIP caps the exponent here, "reasonable maximum after 5 tries".

##define MATTER_MRP_MAX_TRANSMISSIONS 5u

modules/woz_matter/include/matter_mrp.h:73

Total transmissions including the first: 1 + CHIP's MAX_RETRANS of 4.

##define MATTER_MRP_IDLE_INTERVAL_MS 500u

modules/woz_matter/include/matter_mrp.h:76

Peer retransmit intervals advertised by default (ms).

##define MATTER_MRP_ACTIVE_INTERVAL_MS 300u

modules/woz_matter/include/matter_mrp.h:77

##define MATTER_MRP_STANDALONE_ACK_MS 200u

modules/woz_matter/include/matter_mrp.h:83

Grace period to piggyback an ack on a real outbound message before giving up and sending a bare one (ReliableMessageProtocolConfig.h:95, exchange.py:29).

##define MATTER_MRP_SENDER_BOOST_MS 1500u

modules/woz_matter/include/matter_mrp.h:93

Flat addition to every retransmit deadline on a Thread transport (ReliableMessageProtocolConfig.h:178-184: 1500 ms when CHIP_ENABLE_OPENTHREAD and not Linux, 0 otherwise). It is separate from matter_mrp_backoff_ms() because the spec formula does not contain it -- it is CHIP's allowance for mesh latency, applied where the transport is known. This node is a Thread node, so matter_mrp_arm() adds it.

##define MATTER_MRP_WINDOW_BITS 32u

modules/woz_matter/include/matter_mrp.h:96

Counter window width in bits (CHIPConfig.h:309). One uint32_t.

Fuint32_t matter_mrp_backoff_ms(uint32_t base_ms, uint8_t send_count, uint8_t jitter)

modules/woz_matter/include/matter_mrp.h:112

Delay before the n'th retransmission of a message already sent send_count times, per Matter Core 4.12.2.1: i = MRP_BACKOFF_MARGIN * base t = i * MRP_BACKOFF_BASE^max(0, n - MRP_BACKOFF_THRESHOLD) t = t * (1.0 + random(0,1) * MRP_BACKOFF_JITTER) @param base_ms peer's advertised idle or active retransmit interval. @param send_count transmissions ALREADY made, so 1 after the first send. Zero is treated as 1; there is no backoff before a first send. @param jitter one random byte. Pass 0 for a deterministic schedule. @return delay in ms, saturating at UINT32_MAX. Excludes SENDER_BOOST.

Fvoid matter_mrp_window_init(struct matter_mrp_window *w)

modules/woz_matter/include/matter_mrp.h:129

Fint matter_mrp_window_check(const struct matter_mrp_window *w, uint32_t counter)

modules/woz_matter/include/matter_mrp.h:142

Test a counter WITHOUT recording it. Split from commit on purpose. The counter is only trustworthy once the message it rode in on has been authenticated, so the caller must check, decrypt, and only then commit. Committing first would let anyone who can put a UDP datagram on the mesh drag max_counter forward and lock out the real peer. @return MATTER_OK if new, MATTER_E_DUP if already seen or too old.

Fvoid matter_mrp_window_commit(struct matter_mrp_window *w, uint32_t counter)

modules/woz_matter/include/matter_mrp.h:145

Record an authenticated counter, advancing the window if it is ahead.

Cenum matter_mrp_action

modules/woz_matter/include/matter_mrp.h:173

What matter_mrp_poll() says is due now.

Fvoid matter_mrp_init(struct matter_mrp *m, uint32_t base_ms)

modules/woz_matter/include/matter_mrp.h:210

@param base_ms peer's retransmit interval, e.g. MATTER_MRP_ACTIVE_INTERVAL_MS.

Fint matter_mrp_arm(struct matter_mrp *m, uint32_t counter, uint32_t now_ms, uint8_t jitter)

modules/woz_matter/include/matter_mrp.h:220

Register a reliable message as sent and set its retransmit deadline. Call after every transmission of it, the first included: each call bumps send_count, which is what grows the backoff. @return MATTER_OK, or MATTER_E_STATE if a DIFFERENT counter is already in flight, since MRP permits only one.

Fint matter_mrp_on_ack(struct matter_mrp *m, uint32_t counter)

modules/woz_matter/include/matter_mrp.h:228

Apply a received acknowledgement. @return MATTER_OK if it cleared the in-flight message, MATTER_E_STATE if nothing was in flight, MATTER_E_INVAL if it acked a different counter (stale or forged -- either way the in-flight message stays pending).

Fvoid matter_mrp_on_reliable_recv(struct matter_mrp *m, uint32_t counter, uint32_t now_ms)

modules/woz_matter/include/matter_mrp.h:234

Note an inbound message that requested an acknowledgement, starting the piggyback grace period.

Fbool matter_mrp_take_ack(struct matter_mrp *m, uint32_t *counter)

modules/woz_matter/include/matter_mrp.h:240

Claim the owed ack so an outbound message can carry it, clearing the pending standalone. @return true if there was one, and *counter is set.

Fenum matter_mrp_action matter_mrp_poll(struct matter_mrp *m, uint32_t now_ms, uint32_t *counter)

modules/woz_matter/include/matter_mrp.h:246

What is due at now_ms. @param counter receives the message counter the action refers to.

Fbool matter_mrp_next_deadline(const struct matter_mrp *m, uint32_t *out_ms)

modules/woz_matter/include/matter_mrp.h:253

Deadline of the soonest pending event, for arming one timer. @param out_ms receives an absolute ms deadline, untouched when false. @return false when nothing is pending and no timer is needed.