Complete Phase 12 dual-stack networking
Add IPv6-aware Wi-Fi state, HTTPS/SSH listeners, mDNS service reconciliation, and browser Wi-Fi administration. Include a guarded build-local fix for mDNS 1.12.0 membership handling, focused regression suites, and Phase 12 acceptance documentation.
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
# Wi-Fi Phase 12 focused host regression
|
||||
|
||||
Run `python3 tests/wifi_phase12/run.py`. The renderer tests use the installed public `esp_netif_ip_addr.h` at `~/.platformio/packages/framework-espidf/components/esp_netif/include/` with host endian/config shims (no SDK modification). Optional `--sanitize` requires host ASan/UBSan runtime libraries. No PlatformIO build or device access is performed. Compilation/executables use a temporary directory.
|
||||
|
||||
The harness extracts production hostname, address reconciliation, IP callback, and deadline functions verbatim. Real manager/config headers define the data contracts. Host fakes model driver association, netif-up state, IPv6 slot states, TCP/IP execution, and clock; surrounding failover/driver operations are call-count fakes, not a full scheduler/network simulation. Wiring assertions cover pre-connect hostname installation and message dispatch.
|
||||
|
||||
Coverage includes:
|
||||
|
||||
- Configured hostname and rename without disconnect; full 59-byte hostname; config-read failure.
|
||||
- STA-only IPv6 event filtering, null events, and IPv4 netif filtering.
|
||||
- Explicit STA SLAAC enablement, link-local creation, no repeated tentative/duplicate DAD.
|
||||
- Link-local-only, ULA/GUA, IPv4-only, and dual-stack readiness.
|
||||
- IPv4 loss while IPv6 remains, IPv6 deprecation/removal and restoration.
|
||||
- No IPv4 deadline failover on usable IPv6; no perpetual fallback stability reset.
|
||||
- Dropped address/association events, dropped online disconnect, recreated LL after missed disconnect/reconnect, and stale events during stop/profile advance.
|
||||
- Permanent owner wakeup, including boot-disabled and stopped Wi-Fi; offline service withdrawal, failed record updates and pending reannouncement retries at one-second cadence.
|
||||
- Busy-loop calls do not repeat periodic work; persistent mDNS failure does not generate per-pass warnings.
|
||||
- Permanent hostname pointer lifetime, failed offline rename retry, and mutex/TCP-IP-context assertions for address and hostname access.
|
||||
- Address-read failure/uncertain callback completion withdraws stale readiness without retiring the recovery AP; later successful reads restore readiness.
|
||||
- Verbatim production console rendering of simultaneous preferred link-local, ULA and GUA addresses, with non-symmetric network-order words and IDF public formatting macros; client-interface zone guidance never renders the ESP32 zone.
|
||||
- Full numeric list and count clearing on failed callback admission, skipped callback, IP-info error, netif-down and the production disconnect-clear helper; wiring assertions require intentional disconnect, stop and disconnect-event paths to call that helper. Tentative, duplicate and deprecated slots are excluded by the preferred-getter fake matching SDK semantics.
|
||||
- Increasing configured SDK slots to four fails the production compile-time capacity assertion.
|
||||
|
||||
## Contract and SDK evidence
|
||||
|
||||
`ONLINE` means a current association/netif with IPv4 or a **preferred** IPv6 link-local/ULA/GUA address. It is not an Internet/default-route check. Deprecated-only addresses do not qualify for new service readiness. In particular, link-local-only operation suppresses DHCPv4-driven profile failover and can retire the fallback AP after the existing stability interval. IPv6 link-local clients need an interface scope. Snapshot IPv4 fields remain zero on IPv6-only networks; `ipv6_linklocal` / `ipv6_routable` booleans report preferred-address availability, not routing success. The console also lists up to three numeric preferred IPv6 addresses from the exact same TCP/IP observation as those flags. Count and all address storage are published/cleared together under the manager mutex. The configured lwIP slot count must not exceed three (compile-time contract, no silent truncation). Web/OLED continue consuming the existing flags without adding list output.
|
||||
|
||||
Inspected installed ESP-IDF 5.5.0 sources:
|
||||
|
||||
- `esp_netif/lwip/esp_netif_lwip.c`: netif-up and address getters access lwIP directly; all manager netif-up/address checks now execute inside the TCP/IP callback. Preferred getter excludes tentative/duplicate/deprecated/invalid addresses. Disconnect invalidates/clears IPv6 slots. `esp_netif_tcpip_exec` supplies synchronous TCP/IP context, with no retained stack request on return. Its IDF 5.5 wrapper ignores the underlying `tcpip_send_msg_wait_sem` result: explicit completion markers therefore detect a callback that was never executed despite an apparent `ESP_OK`. No hard wall-clock guarantee is made if upstream stalls.
|
||||
- `lwip/port/include/lwipopts.h`, `lwip/src/include/lwip/opt.h`, and `esp_netif_start_api`: saved `CONFIG_LWIP_IPV6_AUTOCONFIG` is disabled, but lwIP SLAAC remains compiled via `LWIP_IPV6_AUTOCONFIG`. Explicit per-STA `netif_set_ip6_autoconfig_enabled` is needed; AP policy is untouched.
|
||||
- `esp_netif_set_hostname_api` has a 32-byte limit, below the existing configured hostname maximum of 59. The manager therefore installs permanent bounded storage through `netif_set_hostname` in TCP/IP context, without transferring ownership to esp-netif. `netif_add` does not clear the hostname; `esp_netif/lwip/netif/wlanif.c` preserves it via `esp_netif_get_hostname` during initialization.
|
||||
- `lwip/src/core/ipv4/dhcp.c`: option 12 is read from the current netif hostname in subsequent outgoing DHCP exchanges (request/renew/rebind included). Rename does not force release/reacquisition or promise immediate router/DNS cache replacement.
|
||||
|
||||
Reverify these boundaries for an SDK upgrade. Tests do not emulate DHCP wire packets, router advertisements, actual DAD timers, mDNS component behavior, or socket listeners. A target syntax check is not a linked firmware build. Device and integration validation remain separate.
|
||||
|
||||
## Coordination
|
||||
|
||||
The owner calls the new `mdns_service_reconcile` every second even offline/stopped. A pending online reannouncement uses `mdns_service_reannounce`, which also reconciles records. Listener owners' lock-free availability stores need no queue wakeup; changes and failures converge on subsequent passes. Reconciliation never initializes the responder; startup still requires either-family STA readiness. Failures remain nonfatal, visible through service error status, and do not log each retry. Upstream mDNS calls may block: the cadence bounds attempt frequency, not upstream execution time.
|
||||
|
||||
`wifi_manager_mdns_reannounce` also refreshes DHCP option 12 while offline. Periodic hostname refresh retries failed/missed DHCP-name changes without reconnecting. The permanent hostname buffer is only read/written in TCP/IP context; no application status caller borrows that pointer (use the copied mDNS snapshot). Pending mDNS rename errors retry online. Other owners should consume the IPv6 snapshot flags rather than infer readiness from `snapshot.ip != 0`.
|
||||
|
||||
## Diagnostic addition resource budget and handoff
|
||||
|
||||
The numeric payload is three arrays of four network-order `uint32_t` words (48 bytes), plus a one-byte count that fits existing snapshot padding. No strings, device zones, task, socket, heap allocation or queue-message growth are introduced. Host layout measurements with production headers: snapshot 232 → 280 bytes; settings projection 424 → 472 bytes; manager shared storage 760 → 808 bytes; temporary address observation 16 → 64 bytes. Thus the manager's static storage grows by 48 bytes, and each existing snapshot/settings copy (console, web, local UI) grows by 48 bytes. The owner observation adds 48 bytes of transient stack payload; the existing three-entry SDK enumeration scratch is unchanged. Actual compiler stack-frame/high-water effects and linked target RAM remain for the parent's build/device checks; host sizes are not runtime headroom evidence.
|
||||
|
||||
Scoped validation: normal host suite and slot-cap negative compile PASS. `--sanitize` could not link on this host because `libasan.so.8.0.0` / `libubsan.so.1.0.0` are missing. No dependency changes, PlatformIO build or hardware operation performed. Parent owns durable documentation updates (the flags-only statements in agent memory/command docs are now stale for console status) and firmware build. Production edits are limited to `src/wifi_manager.c`, `src/wifi_manager.h`, and `src/wifi_console.c`; tests/docs for this addition stay here.
|
||||
Reference in New Issue
Block a user