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,27 @@
|
||||
# Phase 12 mDNS owner host regression
|
||||
|
||||
Run `python3 tests/mdns_phase12/run.py` from the repository root. Uses the host C11 compiler and temporary fake SDK headers; compiles the actual production module. No PlatformIO, device operations, or generated firmware assets.
|
||||
|
||||
Covers notifications before initialization and while the project mutex is held; default unavailable SSH; fixed HTTPS443/SSH22 and empty TXT; repeated starts without duplicate records or hostname churn; record add/remove failures and retry; offline withdrawal; offline rename and retry; latest-state coalescing; init/hostname/instance failure latches and cleanup. Family tests cover lost IPv4 with surviving IPv6, IPv6-only/link-local readiness, no valid IPv6, netif down, stop with stale addresses, missed GOT_IP6, explicitly failed and silently dropped action submission, delayed upstream disable, missing STA netif, and no enable churn during ordinary healthy polls. TCP/IP fakes assert address reads occur in TCP/IP context; netif actions assert neither project mutex nor publication critical section is held. Actual multicast, component tasks, DNS conflicts, and sockets are not simulated.
|
||||
|
||||
## Integration contract
|
||||
|
||||
- Listener owners call `void mdns_service_set_https_available(bool)` / `void mdns_service_set_ssh_available(bool)` after successful listener creation and on unavailability. Calls use tiny portMUX critical sections, safe before initialization, with no blocking semaphore, allocation, callbacks, or component calls. Xtensa does not promise lock-free C11 atomic bool, so no atomics are required.
|
||||
- The sole Wi-Fi owner calls `esp_err_t mdns_service_reconcile(void)` periodically, even offline. No new arguments are needed: it looks up the permanent `WIFI_STA_DEF` netif and samples addresses via `esp_netif_tcpip_exec`. No project mutex or publication mux is held across SDK/component calls.
|
||||
- Reconciliation never initializes the responder. Before module init it returns invalid-state; after module init but before responder startup it is a successful no-op. Once initialized it applies listener states and family readiness, retrying failed operations on subsequent passes. Notifications converge on a later pass, not synchronously; an in-flight pass can briefly reflect an older state.
|
||||
- Existing start/reannounce also reconcile. Start remains gated by usable STA in either family. Stop now clears announcement expectation **and requests family disable**, even if netif still holds nonzero addresses; it does not destroy/reinitialize the responder. Errors are retained in the snapshot. Do not call lifecycle operations concurrently or while holding another service lock. The manager owns start/stop, not event callbacks.
|
||||
- Required effective SDK options remain `CONFIG_MDNS_PREDEF_NETIF_STA=y`, AP/ETH predefined interfaces disabled, `CONFIG_LWIP_IPV4=y`, `CONFIG_LWIP_IPV6=y`, `CONFIG_MDNS_MAX_SERVICES >= 2`. No configuration change was made for the repair.
|
||||
|
||||
## Exact dependency contracts and limitations
|
||||
|
||||
Inspected installed Espressif mDNS **1.12.0** and ESP-IDF **5.5.0**:
|
||||
|
||||
- `mdns_netif.c` initializes IPv6 from `esp_netif_get_ip6_linklocal`, independently of IPv4. Its predefined handlers process disconnect and address acquisition, but not STA_LOST_IP. `mdns_networking_lwip.c` tracks family readiness separately from current addresses. `mdns_send.c` checks readiness before emitting A/AAAA, but can emit zero A if readiness remains true after IPv4 loss. Explicit family disable repairs that stale readiness, including when IPv6 survives.
|
||||
- `mdns_send.c` uses `esp_netif_get_all_ip6`, whose IDF implementation includes **valid addresses, including deprecated addresses**, excludes invalid/tentative/zero addresses, and reads lwIP state directly. Our sampling therefore runs in TCP/IP context and intentionally follows valid-address semantics, not preferred-only semantics. No address cache is passed to mDNS; it still reads addresses when serializing records.
|
||||
- `mdns_netif_action` is asynchronous, has no public readiness getter or acknowledgement, and `post_custom_action` returns `ESP_OK` even if action enqueue fails. A cached successful API return is not proof of applied state. Allocation errors retry on the next pass; silent losses require reassertion. Missing-family disables are idempotent and reasserted every poll. Present-family enables restart probes, so they are submitted on family-mask transitions and at a **30-second repair cadence**, not every healthy interval. This also repairs late upstream disconnect actions and failed internal PCB initialization. There is no responder restart or service-record churn.
|
||||
- Public-only control cannot simultaneously guarantee acknowledged readiness and absolutely no periodic enable reprobes. Healthy families re-probe every 30 seconds as the explicit tradeoff. Recovery from silent dropped enables is on a subsequent repair cadence **once the component queue/network resources make progress**, not a hard deadline under sustained failure. Missing-family disable retries each poll. Polling, concurrent network changes, and component queuing leave a transient window in which stale/zero A responses can still escape; this is convergence, not an atomic packet-level filter. No upstream patch is included.
|
||||
- `mdns_responder.c` adds/removes records synchronously under its own mutex. Hostname setting waits for the component worker; instance setting queues work. Work per pass is one bounded address scan, at most one family action, and two record decisions; no additional tasks, queues, dynamic application storage, or retry loops. This is not a hard wall-clock guarantee for upstream blocking calls.
|
||||
|
||||
## Target validation
|
||||
|
||||
In addition to the host suite, the updated `src/mdns_service.c` was compiled to a temporary object using its exact `.pio/build/esp32-s3-devkitc-1-n16r8/compile_commands.json` command and the installed Xtensa compiler / IDF 5.5 headers. Compilation passed. No full PlatformIO build, link, or hardware validation was performed.
|
||||
Reference in New Issue
Block a user