IPv6 support for Ethernet (ESP32)

This commit is contained in:
Stephan Hadinger 2022-12-08 19:06:51 +01:00
parent de408921ec
commit 2f1b2ec5fd
7 changed files with 111 additions and 37 deletions

View File

@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file.
### Added
- Serial Modbus transmit enable GPIOs to all modbus energy drivers and modbus bridge (#17247)
- Berry crypto module, with AES_GCM by default and EC_CC25519 optional
- IPv6 support for Ethernet (ESP32)
### Breaking Changed

View File

@ -808,6 +808,7 @@
#define D_LOG_UPLOAD "UPL: " // Upload
#define D_LOG_UPNP "UPP: " // UPnP
#define D_LOG_WIFI "WIF: " // Wifi
#define D_LOG_ETH "ETH: " // Ethernet
#define D_LOG_ZIGBEE "ZIG: " // Zigbee
#define D_LOG_TCP "TCP: " // TCP bridge
#define D_LOG_BERRY "BRY: " // Berry scripting language

View File

@ -828,11 +828,20 @@ void CmndStatus(void)
ResponseAppend_P(PSTR(",\"Ethernet\":{\"" D_CMND_HOSTNAME "\":\"%s\",\""
D_CMND_IPADDRESS "\":\"%_I\",\"" D_JSON_GATEWAY "\":\"%_I\",\"" D_JSON_SUBNETMASK "\":\"%_I\",\""
D_JSON_DNSSERVER "1\":\"%_I\",\"" D_JSON_DNSSERVER "2\":\"%_I\",\""
D_JSON_MAC "\":\"%s\"}"),
D_JSON_MAC "\":\"%s\""
#if LWIP_IPV6
",\"" D_JSON_IP6_GLOBAL "\":\"%s\",\"" D_JSON_IP6_LOCAL "\":\"%s\""
#endif // LWIP_IPV6
"}"),
EthernetHostname(),
(uint32_t)EthernetLocalIP(), Settings->eth_ipv4_address[1], Settings->eth_ipv4_address[2],
Settings->eth_ipv4_address[3], Settings->eth_ipv4_address[4],
EthernetMacAddress().c_str());
EthernetMacAddress().c_str()
#if LWIP_IPV6
,EthernetGetIPv6().c_str(), EthernetGetIPv6LinkLocal().c_str()
#endif // LWIP_IPV6
);
#endif // USE_ETHERNET
ResponseAppend_P(PSTR(",\"" D_CMND_WEBSERVER "\":%d,\"HTTP_API\":%d,\"" D_CMND_WIFICONFIG "\":%d,\"" D_CMND_WIFIPOWER "\":%s}}"),
Settings->webserver, Settings->flag5.disable_referer_chk, Settings->sta_config, WifiGetOutputPower().c_str());

View File

@ -466,21 +466,34 @@ void WifiSetState(uint8_t state)
}
#if LWIP_IPV6
//
// Scan through all interfaces to find a global or local IPv6 address
// Arg:
// is_local: is the address Link-Local (true) or Global (false)
// if_type: possible values are "st" for Wifi STA, "en" for Ethernet, "lo" for localhost (not useful)
static String WifiFindIPv6(bool is_local, const char * if_type = "st") {
for (netif* intf = netif_list; intf != nullptr; intf = intf->next) {
if (intf->name[0] == if_type[0] && intf->name[1] == if_type[1]) {
for (uint32_t i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
ip_addr_t *ipv6 = &intf->ip6_addr[i];
if (IP_IS_V6_VAL(*ipv6) && !ip_addr_isloopback(ipv6) && ((bool)ip_addr_islinklocal(ipv6) == is_local)) {
return IPAddress46(ipv6).toString();
}
}
}
}
return String();
}
// Returns only IPv6 global address (no loopback and no link-local)
String WifiGetIPv6(void)
{
for (auto a : addrList) {
if(!ip_addr_isloopback((ip_addr_t*)a.addr()) && !a.isLocal() && a.isV6()) return a.toString();
}
return "";
return WifiFindIPv6(false, "st");
}
String WifiGetIPv6LinkLocal(void)
{
for (auto a : addrList) {
if(!ip_addr_isloopback((ip_addr_t*)a.addr()) && a.isLocal() && a.isV6()) return a.toString();
}
return "";
return WifiFindIPv6(true, "st");
}
// add an IPv6 link-local address to all netif
@ -493,16 +506,18 @@ void CreateLinkLocalIPv6(void)
#endif // ESP32
}
//
void WifiDumpAddressesIPv6(void)
{
for (auto a: addrList)
AddLog(LOG_LEVEL_DEBUG, PSTR("IF='%s' index=%d legacy=%d IPv4=%d local=%d addr='%s'"),
a.ifname().c_str(),
a.ifnumber(),
a.isLegacy(),
a.addr().isV4(),
a.addr().isLocal(),
a.toString().c_str());
for (netif* intf = netif_list; intf != nullptr; intf = intf->next) {
if (!ip_addr_isany_val(intf->ip_addr)) AddLog(LOG_LEVEL_DEBUG, "WIF: '%c%c' IPv4 %s", intf->name[0], intf->name[1], IPAddress46(intf->ip_addr).toString().c_str());
for (uint32_t i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
if (!ip_addr_isany_val(intf->ip6_addr[i]))
AddLog(LOG_LEVEL_DEBUG, "WIF: '%c%c' IPv6 %s %s", intf->name[0], intf->name[1],
IPAddress46(intf->ip6_addr[i]).toString().c_str(),
ip_addr_islinklocal(&intf->ip6_addr[i]) ? "local" : "");
}
}
}
#endif // LWIP_IPV6=1
@ -738,7 +753,7 @@ void WifiConnect(void)
{
if (!Settings->flag4.network_wifi) { return; }
#ifdef ESP32
#if defined(ESP32) && !defined(FIRMWARE_MINIMAL)
static bool wifi_event_registered = false;
if (!wifi_event_registered) {
WiFi.onEvent(WifiEvents); // register event listener only once
@ -895,6 +910,7 @@ bool WifiHostByName(const char* aHostname, IPAddress& aResult) {
if (WiFi.hostByName(aHostname, aResult)) {
// Host name resolved
if (0xFFFFFFFF != (uint32_t)aResult) {
AddLog(LOG_LEVEL_DEBUG, "WIF: Resolving '%s' (%s)", aHostname, aResult.toString().c_str());
return true;
}
}
@ -903,6 +919,7 @@ bool WifiHostByName(const char* aHostname, IPAddress& aResult) {
uint32_t dns_address = (!TasmotaGlobal.global_state.eth_down) ? Settings->eth_ipv4_address[3] : Settings->ipv4_address[3];
DnsClient.begin((IPAddress)dns_address);
if (1 == DnsClient.getHostByName(aHostname, aResult)) {
AddLog(LOG_LEVEL_DEBUG, "WIF: Resolving '%s' (%s)", aHostname, aResult.toString().c_str());
return true;
}
}
@ -1076,16 +1093,19 @@ void WifiEvents(arduino_event_t *event) {
ip_addr_t ip_addr6;
ip_addr_copy_from_ip6(ip_addr6, event->event_info.got_ip6.ip6_info.ip);
IPAddress46 addr(ip_addr6);
AddLog(LOG_LEVEL_DEBUG, PSTR("WIF: IPv6 %s %s"), addr.isLocal() ? PSTR("Link-Local") : PSTR("Global"), addr.toString().c_str());
AddLog(LOG_LEVEL_DEBUG, PSTR("%s: IPv6 %s %s"),
event->event_id == ARDUINO_EVENT_ETH_GOT_IP6 ? "ETH" : "WIF",
addr.isLocal() ? PSTR("Local") : PSTR("Global"), addr.toString().c_str());
}
break;
#endif // LWIP_IPV6
case ARDUINO_EVENT_ETH_GOT_IP:
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
case ARDUINO_EVENT_ETH_GOT_IP:
{
ip_addr_t ip_addr4;
ip_addr_copy_from_ip4(ip_addr4, event->event_info.got_ip.ip_info.ip);
AddLog(LOG_LEVEL_DEBUG, PSTR("WIF: IPv4 %_I, mask %_I, gateway %_I"),
AddLog(LOG_LEVEL_DEBUG, PSTR("%s: IPv4 %_I, mask %_I, gateway %_I"),
event->event_id == ARDUINO_EVENT_ETH_GOT_IP ? "ETH" : "WIF",
event->event_info.got_ip.ip_info.ip.addr,
event->event_info.got_ip.ip_info.netmask.addr,
event->event_info.got_ip.ip_info.gw.addr);

View File

@ -2362,11 +2362,11 @@ void HandleInformation(void)
#if LWIP_IPV6
String ipv6_addr = WifiGetIPv6();
if (ipv6_addr != "") {
WSContentSend_P(PSTR("}1 IPv6 Global }2%s"), ipv6_addr.c_str());
WSContentSend_P(PSTR("}1 IPv6 Global (wifi)}2%s"), ipv6_addr.c_str());
}
ipv6_addr = WifiGetIPv6LinkLocal();
if (ipv6_addr != "") {
WSContentSend_P(PSTR("}1 IPv6 Link-Local }2%s"), ipv6_addr.c_str());
WSContentSend_P(PSTR("}1 IPv6 Local (wifi)}2%s"), ipv6_addr.c_str());
}
#endif // LWIP_IPV6 = 1
if (static_cast<uint32_t>(WiFi.localIP()) != 0) {
@ -2387,6 +2387,16 @@ void HandleInformation(void)
WSContentSend_P(PSTR("}1<hr/>}2<hr/>"));
}
WSContentSend_P(PSTR("}1" D_HOSTNAME "}2%s%s"), EthernetHostname(), (Mdns.begun) ? PSTR(".local") : "");
#if LWIP_IPV6
String ipv6_eth_addr = EthernetGetIPv6();
if (ipv6_eth_addr != "") {
WSContentSend_P(PSTR("}1 IPv6 Global (eth)}2%s"), ipv6_eth_addr.c_str());
}
ipv6_eth_addr = EthernetGetIPv6LinkLocal();
if (ipv6_eth_addr != "") {
WSContentSend_P(PSTR("}1 IPv6 Local (eth)}2%s"), ipv6_eth_addr.c_str());
}
#endif // LWIP_IPV6 = 1
WSContentSend_P(PSTR("}1" D_MAC_ADDRESS "}2%s"), EthernetMacAddress().c_str());
WSContentSend_P(PSTR("}1" D_IP_ADDRESS " (eth)}2%_I"), (uint32_t)EthernetLocalIP());
}

View File

@ -228,7 +228,7 @@ extern "C" {
#endif
if (static_cast<uint32_t>(WiFi.localIP()) != 0) {
be_map_insert_str(vm, "mac", WiFi.macAddress().c_str());
be_map_insert_str(vm, "ip", WiFi.localIP().toString().c_str());
be_map_insert_str(vm, "ip", IPAddress46((uint32_t)WiFi.localIP()).toString().c_str()); // quick fix for IPAddress bug
show_rssi = true;
}
if (show_rssi) {
@ -252,8 +252,18 @@ extern "C" {
#ifdef USE_ETHERNET
if (static_cast<uint32_t>(EthernetLocalIP()) != 0) {
be_map_insert_str(vm, "mac", EthernetMacAddress().c_str());
be_map_insert_str(vm, "ip", EthernetLocalIP().toString().c_str());
be_map_insert_str(vm, "ip", IPAddress46((uint32_t)EthernetLocalIP()).toString().c_str()); // quick fix for IPAddress bug
}
#if LWIP_IPV6
String ipv6_addr = EthernetGetIPv6();
if (ipv6_addr != "") {
be_map_insert_str(vm, "ip6", ipv6_addr.c_str());
}
ipv6_addr = EthernetGetIPv6LinkLocal();
if (ipv6_addr != "") {
be_map_insert_str(vm, "ip6local", ipv6_addr.c_str());
}
#endif
#endif
be_pop(vm, 1);
be_return(vm);

View File

@ -85,19 +85,28 @@
char eth_hostname[sizeof(TasmotaGlobal.hostname)];
uint8_t eth_config_change;
void EthernetEvent(WiFiEvent_t event) {
switch (event) {
void EthernetEvent(arduino_event_t *event) {
switch (event->event_id) {
case ARDUINO_EVENT_ETH_START:
AddLog(LOG_LEVEL_DEBUG, PSTR("ETH: " D_ATTEMPTING_CONNECTION));
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_ETH D_ATTEMPTING_CONNECTION));
ETH.setHostname(eth_hostname);
break;
case ARDUINO_EVENT_ETH_CONNECTED:
AddLog(LOG_LEVEL_INFO, PSTR("ETH: " D_CONNECTED " at %dMbps%s"),
ETH.linkSpeed(), (ETH.fullDuplex()) ? " Full Duplex" : "");
#if LWIP_IPV6
ETH.enableIpV6(); // enable Link-Local
#endif
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_ETH D_CONNECTED " at %dMbps%s, Mac %s, Hostname %s"),
ETH.linkSpeed(), (ETH.fullDuplex()) ? " Full Duplex" : "",
ETH.macAddress().c_str(), eth_hostname
);
// AddLog(LOG_LEVEL_DEBUG, D_LOG_ETH "ETH.enableIpV6() -> %i", ETH.enableIpV6());
break;
case ARDUINO_EVENT_ETH_GOT_IP:
AddLog(LOG_LEVEL_DEBUG, PSTR("ETH: Mac %s, IPAddress %_I, Hostname %s"),
ETH.macAddress().c_str(), (uint32_t)ETH.localIP(), eth_hostname);
// AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_ETH "Mac %s, IPAddress %_I, Hostname %s"),
// ETH.macAddress().c_str(), (uint32_t)ETH.localIP(), eth_hostname);
Settings->eth_ipv4_address[1] = (uint32_t)ETH.gatewayIP();
Settings->eth_ipv4_address[2] = (uint32_t)ETH.subnetMask();
if (0 == Settings->eth_ipv4_address[0]) { // At this point ETH.dnsIP() are NOT correct unless DHCP
@ -107,15 +116,18 @@ void EthernetEvent(WiFiEvent_t event) {
TasmotaGlobal.rules_flag.eth_connected = 1;
TasmotaGlobal.global_state.eth_down = 0;
break;
case ARDUINO_EVENT_ETH_DISCONNECTED:
AddLog(LOG_LEVEL_INFO, PSTR("ETH: Disconnected"));
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_ETH "Disconnected"));
TasmotaGlobal.rules_flag.eth_disconnected = 1;
TasmotaGlobal.global_state.eth_down = 1;
break;
case ARDUINO_EVENT_ETH_STOP:
AddLog(LOG_LEVEL_DEBUG, PSTR("ETH: Stopped"));
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_ETH "Stopped"));
TasmotaGlobal.global_state.eth_down = 1;
break;
default:
break;
}
@ -130,10 +142,21 @@ void EthernetSetIp(void) {
Settings->eth_ipv4_address[4]); // IPAddress dns2
}
// Returns only IPv6 global address (no loopback and no link-local)
String EthernetGetIPv6(void)
{
return WifiFindIPv6(false, "en");
}
String EthernetGetIPv6LinkLocal(void)
{
return WifiFindIPv6(true, "en");
}
void EthernetInit(void) {
if (!Settings->flag4.network_ethernet) { return; }
if (!PinUsed(GPIO_ETH_PHY_MDC) && !PinUsed(GPIO_ETH_PHY_MDIO)) {
AddLog(LOG_LEVEL_DEBUG, PSTR("ETH: No ETH MDC and/or ETH MDIO GPIO defined"));
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_ETH "No ETH MDC and/or ETH MDIO GPIO defined"));
return;
}
@ -180,7 +203,7 @@ void EthernetInit(void) {
delay(1);
#endif // CONFIG_IDF_TARGET_ESP32
if (!ETH.begin(Settings->eth_address, eth_power, eth_mdc, eth_mdio, (eth_phy_type_t)Settings->eth_type, (eth_clock_mode_t)Settings->eth_clk_mode)) {
AddLog(LOG_LEVEL_DEBUG, PSTR("ETH: Bad PHY type or init error"));
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_ETH "Bad PHY type or init error"));
return;
};