diff --git a/CHANGELOG.md b/CHANGELOG.md index 55d5a5226..26e2f2c77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ All notable changes to this project will be documented in this file. - Webradio crash with invalid url (#21446) - Zigbee crash when removing `ZbName` (#21449) - ESP32 BLE fix scanning (#21451) +- Matter auto-fix IPv6 link-local zone id when network reconnects ### Removed - Support of old insecure fingerprint algorithm. Deprecated since v8.4.0 (#21417) diff --git a/lib/default/WiFiHelper/src/WiFiHelper.h b/lib/default/WiFiHelper/src/WiFiHelper.h index 666ceba4d..6abcf583a 100644 --- a/lib/default/WiFiHelper/src/WiFiHelper.h +++ b/lib/default/WiFiHelper/src/WiFiHelper.h @@ -83,6 +83,13 @@ public: // With ESP32 Core3, the WiFi mac address is not valid until the wifi is actually started // this helper function always provide a valid mac address static String macAddress(void); + + // Auto-fix zone + // + // After a reconnect, the zone id may not be valid anymore + // In such case we detect any "%st" or "%en" zone identifier + // and replace with the current zone id + static void IPv6ZoneAutoFix(IPAddress &addr, const char* aHostname); }; diff --git a/lib/default/WiFiHelper/src/WiFiHelper_ESP32.cpp b/lib/default/WiFiHelper/src/WiFiHelper_ESP32.cpp index 6741652e1..000840e81 100644 --- a/lib/default/WiFiHelper/src/WiFiHelper_ESP32.cpp +++ b/lib/default/WiFiHelper/src/WiFiHelper_ESP32.cpp @@ -240,6 +240,44 @@ static void wifi32_dns_found_callback(const char *name, const ip_addr_t *ipaddr, // AddLog(LOG_LEVEL_DEBUG, "WIF: dns_found=%s", ipaddr ? IPAddress(*ipaddr).toString().c_str() : ""); } +// Auto-fix zone +// +// After a reconnect, the zone id may not be valid anymore +// In such case we detect any "%st" or "%en" zone identifier +// and replace with the current zone id +extern bool WifiGetIPv6LinkLocal(IPAddress *ip); +extern bool EthernetGetIPv6LinkLocal(IPAddress *ip); +void WiFiHelper::IPv6ZoneAutoFix(IPAddress &addr, const char* aHostname) { +#ifdef USE_IPV6 + if ((addr.type() == IPv6) && (addr.zone() == 0)) { + // check if hostname contains '%' + const char *zone_identifier = strchr(aHostname, '%'); + if (zone_identifier != nullptr) { + uint8_t zone_id = 0; + // check if zone id is valid + if (strncmp(zone_identifier, "%st", 3) == 0) { + IPAddress wifi_link_local; + if (WifiGetIPv6LinkLocal(&wifi_link_local)) { + zone_id = wifi_link_local.zone(); + } + } else if (strncmp(zone_identifier, "%en", 3) == 0) { + IPAddress eth_link_local; + if (EthernetGetIPv6LinkLocal(ð_link_local)) { + zone_id = eth_link_local.zone(); + } + } + if (zone_id) { + // convert to ip_addr_t which is currently the only way to change the zone_id + ip_addr_t ip_addr; + addr.to_ip_addr_t(&ip_addr); + ip_addr.u_addr.ip6.zone = zone_id; + addr = IPAddress(&ip_addr); + } + } + } +#endif +} + /** * Resolve the given hostname to an IP address. * @param aHostname Name to be resolved @@ -281,6 +319,7 @@ int WiFiHelper::hostByName(const char* aHostname, IPAddress& aResult, int32_t ti if (!ip_addr_isany_val(dns_ipaddr)) { #ifdef USE_IPV6 aResult.from_ip_addr_t(&dns_ipaddr); + WiFiHelper::IPv6ZoneAutoFix(aResult, aHostname); #else // USE_IPV6 aResult = ip_addr_get_ip4_u32(&dns_ipaddr); #endif // USE_IPV6 diff --git a/lib/default/WiFiHelper/src/WiFiHelper_ESP8266.cpp b/lib/default/WiFiHelper/src/WiFiHelper_ESP8266.cpp index ab92e459b..a705585d5 100644 --- a/lib/default/WiFiHelper/src/WiFiHelper_ESP8266.cpp +++ b/lib/default/WiFiHelper/src/WiFiHelper_ESP8266.cpp @@ -77,4 +77,6 @@ String WiFiHelper::macAddress(void) { return WiFi.macAddress(); } +void WiFiHelper::IPv6ZoneAutoFix(IPAddress &addr, const char* aHostname) { +} #endif // ESP8266 diff --git a/tasmota/tasmota_support/support_wifi.ino b/tasmota/tasmota_support/support_wifi.ino index 053f9a913..852664ad4 100644 --- a/tasmota/tasmota_support/support_wifi.ino +++ b/tasmota/tasmota_support/support_wifi.ino @@ -1278,6 +1278,7 @@ bool WifiHostByName(const char* aHostname, IPAddress& aResult) { #if ESP_IDF_VERSION_MAJOR >= 5 // try converting directly to IP if (aResult.fromString(aHostname)) { + WiFiHelper::IPv6ZoneAutoFix(aResult, aHostname); return true; // we're done } #endif