Skip to content

post-audit hardening: wifi_tx_power persistence, wifi s_idx race, MISRA/microlink sweep + doc reconciliation + USB-NCM setup guide - #81

Open
iliabaranov wants to merge 7 commits into
mainfrom
dev
Open

post-audit hardening: wifi_tx_power persistence, wifi s_idx race, MISRA/microlink sweep + doc reconciliation + USB-NCM setup guide#81
iliabaranov wants to merge 7 commits into
mainfrom
dev

Conversation

@iliabaranov

@iliabaranov iliabaranov commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Post-audit hardening + doc hygiene off dev.

Firmware

  • wifi_tx_power persistence — the one runtime setter that didn't survive power loss (NVS wifi_txp, re-applied at WIFI_EVENT_STA_START).
  • dcs_wifi s_idx atomic — closes the last residual of the MISRA "wifi_status unlocked read".
  • Event-driven demote on link-down — link-down events wake the route supervisor for instant failover; purely additive (periodic poll preserved as fallback), non-safety supervisor.

Tests

  • EMC-blip / auto-arm regression guard — host test proving the release debounce rejects transient spurious loop-closes while still arming on a genuine sustained close (359 checks, 0 failures).

Host / USB-NCM tether

  • New docs/USB_NCM_SETUP.md — cross-platform USB-NCM host setup (Linux verified + Windows/macOS notes + the subnet gotcha).
  • systemd-networkd tether variant (ce862ec, added 2026-08-08) — host/setup/ gains a .network (DHCPServer+NAT) + a networkd-dispatcher neighbor-cache-flush hook, and install.sh now auto-detects NetworkManager vs systemd-networkd and installs the matching set (the 70-*.link naming rule stays manager-agnostic). Fixes the case where a systemd-networkd HIL/fleet host silently got only 1 of the 3 hardening pieces; contributed + verified on the fleet host that tethers the DUT (self-heals across the chip's re-enumerations). Also documents the "package present but service disabled" gotcha.

Audit reconciliation

🤖 Generated with Claude Code

iliabaranov and others added 2 commits August 7, 2026 13:30
/api/wifi_tx_power applied esp_wifi_set_max_tx_power at runtime but never
persisted, so a runtime override reset to the config default (20 dBm) on
reboot/power loss — violating the rule that every runtime-toggleable
setting survives power loss. Add a dcs_app NVS key (wifi_txp, quarter-dBm,
8..84; 0/absent = keep config default), persist on set, and re-apply at
WIFI_EVENT_STA_START. Mirrors the existing ring_offset/usb_enabled pattern
(both bench-verified surviving reboot).

Audited all runtime setters: ring_offset, pstop_num, usb_enabled,
ts_boot_en, peer slots, and operators already persist; ring_led1/derp/wg
are transient by design. wifi_tx_power was the only gap.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UJz4ZB7WcPErDqKLWDq3ht
- New docs/USB_NCM_SETUP.md: canonical host setup for the USB-NCM tether
  — verified Linux (NetworkManager shared-mode) steps plus Windows (ICS)
  and macOS (Internet Sharing) notes, and the subnet gotcha that blocks
  the default 10.42.0.1:8890 machine bond on those hosts. README and
  host/README.md now point at it.
- README status section refreshed to 2026-08-07: outbound cold-bond,
  half-open/black-hole demote, OTA wrong-lineage first-chunk reject,
  USB-NCM stability, and max_missed 3->5 moved to "recently closed";
  added the peer-scaling churn follow-up.
- Certification section: integrity target updated to SIL 3 (IEC 61508)
  + PL e (ISO 13849) dual track, pointing at the docs/safety/ case.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UJz4ZB7WcPErDqKLWDq3ht
@iliabaranov
iliabaranov requested a review from davidt315 August 7, 2026 21:21
iliabaranov and others added 2 commits August 7, 2026 14:49
dcs_wifi_status() runs on the httpd task and read s_idx (the current
WiFi-list index) unlocked while the WiFi event task increments it — the
one residual of the MISRA-review "dcs_wifi_status unlocked read" defect
(its siblings s_disc_reason/s_connected were already atomic_int). Make
s_idx atomic_int (load/store/fetch_add) so all cross-task shared reads in
this file are lock-free and race-free. Diagnostics-only; no behavior
change on correctly-aligned reads, closes the defect cleanly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UJz4ZB7WcPErDqKLWDq3ht
…ink sweep

- MISRA_COMPLIANCE: the 5 "flagged" real defects are all FIXED (dcs_eth
  cleanup ladder, telemetry MAX_TASKS 64 + overflow guard, wifi_status
  atomics, usb toggle reply); add the components/microlink sweep result
  (17 files) — style profile matches the deviation register, zero genuine
  leak/null/race/buffer defects in the network logic; the only two
  warning-level hits are confirmed false positives in KAT-verified crypto
  (poly1305 masked remainder; donna a24 nb-bounded mul). Handler-cap
  resolved (46 slots).
- CRYPTO_SPEEDUP_REPORT: mark the -O3-on-primitives recommendation
  MERGED + DEPLOYED via #74 (7867d4b) — it read as still-pending.
- MULTI_REMOTE_VALIDATION: reconcile the httpd handler-cap note
  (16 -> 30 user handlers = 46 total, no longer at the limit).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UJz4ZB7WcPErDqKLWDq3ht
@iliabaranov iliabaranov changed the title NVS persistence: wifi_tx_power survives power loss + README/USB-NCM setup docs post-audit hardening: wifi_tx_power persistence, wifi s_idx race, MISRA/microlink sweep + doc reconciliation + USB-NCM setup guide Aug 7, 2026
iliabaranov and others added 3 commits August 7, 2026 15:39
The route supervisor previously reacted to a link drop only on its 1 Hz
poll (or esp_netif's own GOT_IP/LOST_IP). Add link-DOWN event handlers
(ETHERNET_EVENT_DISCONNECTED, WIFI_EVENT_STA_DISCONNECTED,
IP_EVENT_ETH/STA_LOST_IP) that wake the supervisor to re-arbitrate the
default route immediately, so it demotes off a dead link now instead of
up to a period later. UP/promote stays on the periodic loop (natural
anti-flap debounce) — asymmetric by design.

Safe-by-construction: purely additive. The wait becomes
ulTaskNotifyTake(period), so the 1 Hz periodic poll is fully preserved as
fallback — if a kick never fires, behavior is identical to before (no
regression possible). The seconds-based failover ladder is decoupled from
wake frequency via an esp_timer elapsed-time gate so event wakes can't
over-count its streaks. Route arbitration is idempotent and runs on every
wake. The supervisor is non-safety (the safety heartbeat uses its own
source-bound socket). New net_sup_kicks telemetry counts link-down wakes.

Validation: boots healthy and bonds (state=2) on PSTOP54. The kick-latency
IMPROVEMENT itself is not bench-validated — inducing a link-down safely
needs a backup uplink this bench lacks (eth-drop strands the unit;
WiFi-toggle OOM-panics it, a separate pre-existing RAM-budget fragility).
Needs a HIL failover-latency check before the improvement is claimed;
the change is safe to ship regardless (additive, fallback preserved).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UJz4ZB7WcPErDqKLWDq3ht
Adds a host-side regression guard for the software mitigation of the
suspected WiFi-TX EMC auto-arm anomaly: a transmit burst momentarily
coupling into the open E-stop loop and being read as CLOSED must never
manufacture an OK/arm while the operator holds STOP.

Exercises estop_verdict's asymmetric release debounce against
(a) every sub-threshold blip length bracketed by opens, (b) a 50x flapping
close/open burst, and (c) that a genuine sustained close still arms exactly
at the debounce threshold (the mitigation doesn't wedge legitimate arming).
Both cores. 359 checks, 0 failures on the gcc-14 host harness.

Documents the mitigation envelope: it defends transients shorter than
LOOP_RECLOSE_DEBOUNCE_TICKS; a coupling sustained through the full debounce
window is out of scope here and is covered by the machine-side min-STOP
re-arm gesture (separate layer, pstop_c). Pure software; no bench/scope —
we cannot measure the physical coupling, but we can prove the guard rejects
the transient pattern it produces.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UJz4ZB7WcPErDqKLWDq3ht
…nstaller

The host/setup/ tether hardening assumed NetworkManager, so on a
systemd-networkd host (no NM) two of the three pieces silently didn't apply:
the shared profile (no nmcli) and the neighbor-cache flush (NM dispatcher).
Contributed by the fleet/HIL host that tethers the DUT (hq0), verified there
2026-08-08 self-healing across the chip's re-enumerations.

- 80-esp-pstop.network: systemd-networkd equivalent of the NM shared profile —
  static 10.42.0.1/24 + built-in DHCPServer + IPMasquerade + ConfigureWithoutCarrier.
- esp-pstop-flush-networkd: networkd-dispatcher port of 90-esp-pstop-flush
  (keyed on $IFACE; install into routable.d + degraded.d).
- install.sh: auto-detects NetworkManager vs systemd-networkd and installs the
  matching set; the 70-esp-pstop.link naming rule stays manager-agnostic.
  Runs `systemctl enable --now networkd-dispatcher` — the package is often
  present but DISABLED, so the hook otherwise never fires.
- USB_NCM_SETUP.md: documents the installer + both manual paths + the gotcha.

Standardized on 10.42.0.1/24 for repo consistency (matches the NM path + the
chip's factory-default machine peer); the subnet is arbitrary when the host is
only a NAT'd uplink (chip bonds to a remote machine over Tailscale).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UJz4ZB7WcPErDqKLWDq3ht
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant