Repository navigation
cell M6: bound the neighbour-list replay residual — signed freshness window + the live relay measured - #578
Conversation
…window + measure the live relay (#566) The signed lists left a replay residual: a genuine beacon re-aired. Two shapes survive the signature, and this bounds both. - A store-and-forward relay is beaten by the phase check: it re-airs a beacon only after receiving it, so its copy lands ~a beacon's airtime after the cell's TBTT. A test-only CELL_REPLAY_MODE=relay (a live relay of a cell's genuine beacons) plus UE phase-error instrumentation (CELL_UE_NBR_PHASE_LOG, cell.ue.nbr_phase_stats) measure it on the rig (testrig m6_nlrelay.sh): the relay's copies land ~636 us off and are refused on phase (0 stale: fresh signature), while genuine beacons land within 8 us of phase against the 300 us tolerance. - An on-phase copy (a cut-through repeater / reflector) the phase check cannot tell from the cell. It is now bounded by the signed freshness window: NS IE v3 signs win_sf (the window length) alongside win, so the length cannot be relabelled, and CELL_NL_WINDOW_SF (down to 1 superframe) caps a copy's useful life at ~102 ms instead of ~6.5 s. cell_m6 covers the v3 round-trip, the signed window length, and a relabel refusal. docs/cell-m6.md states both residuals and their bounds. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PR Summary by QodoBound neighbour-list replay with signed windows and relay measurements
AI Description
Diagram
High-Level Assessment
Files changed (4)
|
Code Review by Qodo
1.
|
…rame timeline A signature's window is win * win_sf superframes of net_sf; comparing raw win across cells with different win_sf (a switch, a DU restart, or two DUs with different CELL_NL_WINDOW_SF) was wrong — it could refuse genuine beacons or adopt a far-future serving window and brick freshness. Both the serving go-back check and the neighbour freshness now compare win*win_sf, with one coarser window of slack, so differing window lengths interoperate. Also: the on-phase residual bound is ~2*win_sf (the +-1 window tolerance), ~205 ms at win_sf=1 — docs corrected. CELL_REPLAY_DELAY_SF reworded as an off-phase delayed replay (send_packet has no sub-slot departure). Dead relay stop flag removed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CELL_NL_WINDOW_SF=1 made win = net_sf / win_sf = net_sf (~2^34, PTP-derived) overflow the 4-byte NS IE window field (it only fit at win_sf=64). The v3 window field is now 8 bytes; a small window no longer wraps. Selftest covers a win above 2^32. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
All six findings fixed in 1, 3, 4 — comparing windows of different lengths. These were three faces of one bug: comparing raw 2 — the on-phase bound. Corrected to ~2· 5 — 6 — dead stop flag. Removed. Plus: a 64-bit window. The new Rig (all pass): the live relay is refused on phase (896/run, ~645 µs off, 0 stale — fresh signature), genuine beacons land within 8 µs (p99 7) of phase; the cross-length case measures cell 2 cleanly. ctest 95/95. |
#566, the last open item: the neighbour-list residual. The signed lists (CA → cell key → NL) stop forgery, so the residual is a genuine beacon re-aired. This bounds both shapes it can take, and measures the one the rig can produce.
1. A store-and-forward relay — beaten by the phase check (measured).
A relay decodes a genuine beacon and re-airs it, so it cannot be on time: its copy lands about a beacon's airtime after the cell's own TBTT, outside the phase tolerance.
CELL_REPLAY_MODE=relay(test only) adds a live relay to the existing replayer role: it re-airs each genuine cell-2 beacon — signature, certificate, fresh window and all — as soon as its RX path has the whole frame.CELL_UE_NBR_PHASE_LOGlogs each neighbour beacon's phase error and verdict;cell.ue.nbr_phase_statssummarises the error of the beacons taken.scripts/m6_nlrelay.sh, 2 runs, DU2 alive): the relay re-aired 1267–1310 beacons per run; its copies landed a median 636 µs off and were refused on phase (895–896/run), 0 as stale (the signature is current — freshness does not stop it). Genuine cell 2 stayed measured in 100% of reports. Genuine neighbour beacons landed within 6–7 µs (p99), 8 µs (max) of their predicted phase, against the 300 µs tolerance — a ~40× margin.2. An on-phase copy — bounded by the freshness window (code + selftests).
A cut-through repeater or reflector re-radiates the beacon with almost no delay, on phase; the phase check cannot tell it from the cell. The signed freshness window caps how long such a copy stays valid:
win_sf(the window length) alongsidewin, so a replayer cannot relabel a 64-superframe signature as a 1-superframe one (or back).cell_m6covers the v3 round-trip, a relabel refusal, andwin_sf = 0being invalid.CELL_NL_WINDOW_SF(defaultkNlWindowSf= 64; down to 1) sets the window. At 1 superframe a copy's useful life is ~102 ms instead of ~6.5 s, at the cost of an Ed25519 signature per superframe. The UE's staleness check keys off the signedwin_sf.A copy fresher than the window, on phase, is physically the cell's own signal re-radiated; only distance bounding (or a per-beacon challenge, which this one-way broadcast path has no room for) would stop it.
docs/cell-m6.mdstates both residuals and their bounds.ctest: 95/95 pass.
🤖 Generated with Claude Code