diff --git a/src/main.cpp b/src/main.cpp index cbf5884..8c2dfd8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -138,6 +138,7 @@ unsigned long wifiConnectedAt = 0; AutoInterfaceWrapper autoIface; bool autoIfaceDeferredStart = false; unsigned long autoIfaceDeferredAt = 0; +unsigned long lastAutoIfaceLinkCheck = 0; // LXMF diagnostic counters (reset each heartbeat) static uint32_t diagTcpSkipEvents = 0; @@ -1130,6 +1131,22 @@ void loop() { } } + // 7.7. AutoInterface link-local rotation watch — covers SLAAC privacy + // address rotation while STA stays associated. notify_link_change() + // is idempotent in the library, so polling here is cheap (string + // compare, no socket churn) and only does real work on actual change. + if (autoIface.isOnline() && wifiSTAConnected && + millis() - lastAutoIfaceLinkCheck >= 2000) { + lastAutoIfaceLinkCheck = millis(); + IPv6Address ll = WiFi.localIPv6(); + bool isLinkLocal = (ll[0] == 0xfe) && ((ll[1] & 0xc0) == 0x80); + if (isLinkLocal) { + esp_netif_t* sta = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"); + uint32_t scope = sta ? esp_netif_get_netif_impl_index(sta) : 1; + autoIface.notifyLinkChange(ll.toString(), scope); + } + } + // 8. WiFi + TCP loops (with global budget) — skip only if RNS severely overloaded { bool skipTcp = (rnsDuration > 500); diff --git a/src/transport/AutoInterfaceWrapper.cpp b/src/transport/AutoInterfaceWrapper.cpp index b1d7783..89bbc6c 100644 --- a/src/transport/AutoInterfaceWrapper.cpp +++ b/src/transport/AutoInterfaceWrapper.cpp @@ -58,6 +58,13 @@ void AutoInterfaceWrapper::loop() { if (_started && _wrapper) _wrapper.loop(); } +void AutoInterfaceWrapper::notifyLinkChange(const String& link_local_addr, + uint32_t scope_id) { + if (!_started || !_impl) return; + if (link_local_addr.length() == 0) return; + _impl->notify_link_change(link_local_addr.c_str(), scope_id); +} + bool AutoInterfaceWrapper::isOnline() const { return _started && _wrapper && _wrapper.online(); } diff --git a/src/transport/AutoInterfaceWrapper.h b/src/transport/AutoInterfaceWrapper.h index 8075978..a3df174 100644 --- a/src/transport/AutoInterfaceWrapper.h +++ b/src/transport/AutoInterfaceWrapper.h @@ -14,7 +14,10 @@ * 1. wifi STA connects → resolve link-local IPv6 + scope id * 2. wrapper.start(group_id, max_peers, link_local, scope_id) * 3. wrapper.loop() each main-loop tick - * 4. on STA disconnect → wrapper.stop() + * 4. periodically poll WiFi.localIPv6() and call notifyLinkChange() — + * catches SLAAC privacy-address rotation while STA stays associated; + * idempotent at the library layer (no socket churn unless changed) + * 5. on STA disconnect → wrapper.stop() */ class AutoInterfaceWrapper { public: @@ -24,6 +27,7 @@ public: uint32_t scope_id); void stop(); void loop(); + void notifyLinkChange(const String& link_local_addr, uint32_t scope_id); bool isOnline() const; size_t peerCount() const;