arduino-esp32/libraries/Network/src/NetworkInterface.cpp
Me No Dev 77ca7ea7e5
IDF release/v5.1 (#10038)
* IDF release/v5.1 dc859c1e67

* fix(lwip): Filter out V6 packets if V6 is not enabled

the ESP might accept and act on some IPv6 packets, even though IPv6 is not enabled for the interface in Arduino. This change makes the ESP ignore all IPv6 packets if IPv6 address is not available.

* fix(lwip): DNS header is not required

* fix(ot): Add LWIP_HOOK_IP6_INPUT_CUSTOM support
2024-07-16 19:35:06 +03:00

854 lines
28 KiB
C++

/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "NetworkInterface.h"
#include "NetworkManager.h"
#include "esp_netif.h"
#include "esp_netif_defaults.h"
#include "esp_system.h"
#include "lwip/ip_addr.h"
#include "lwip/err.h"
#include "lwip/netif.h"
#include "dhcpserver/dhcpserver.h"
#include "dhcpserver/dhcpserver_options.h"
#include "esp32-hal-log.h"
static NetworkInterface *_interfaces[ESP_NETIF_ID_MAX] = {NULL, NULL, NULL, NULL, NULL, NULL};
static esp_event_handler_instance_t _ip_ev_instance = NULL;
static NetworkInterface *getNetifByEspNetif(esp_netif_t *esp_netif) {
for (int i = 0; i < ESP_NETIF_ID_MAX; ++i) {
if (_interfaces[i] != NULL && _interfaces[i]->netif() == esp_netif) {
return _interfaces[i];
}
}
return NULL;
}
NetworkInterface *getNetifByID(Network_Interface_ID id) {
if (id < ESP_NETIF_ID_MAX) {
return _interfaces[id];
}
return NULL;
}
#if CONFIG_LWIP_HOOK_IP6_INPUT_CUSTOM
extern "C" int lwip_hook_ip6_input(struct pbuf *p, struct netif *inp) __attribute__((weak));
extern "C" int lwip_hook_ip6_input(struct pbuf *p, struct netif *inp) {
if (ip6_addr_isany_val(inp->ip6_addr[0].u_addr.ip6)) {
// We don't have an LL address -> eat this packet here, so it won't get accepted on input netif
pbuf_free(p);
return 1;
}
return 0;
}
#endif
static void _ip_event_cb(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) {
if (event_base == IP_EVENT) {
NetworkInterface *netif = NULL;
if (event_id == IP_EVENT_STA_GOT_IP || event_id == IP_EVENT_ETH_GOT_IP || event_id == IP_EVENT_PPP_GOT_IP) {
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
netif = getNetifByEspNetif(event->esp_netif);
} else if (event_id == IP_EVENT_STA_LOST_IP || event_id == IP_EVENT_PPP_LOST_IP || event_id == IP_EVENT_ETH_LOST_IP) {
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
netif = getNetifByEspNetif(event->esp_netif);
} else if (event_id == IP_EVENT_GOT_IP6) {
ip_event_got_ip6_t *event = (ip_event_got_ip6_t *)event_data;
netif = getNetifByEspNetif(event->esp_netif);
} else if (event_id == IP_EVENT_AP_STAIPASSIGNED) {
ip_event_ap_staipassigned_t *event = (ip_event_ap_staipassigned_t *)event_data;
netif = getNetifByEspNetif(event->esp_netif);
}
if (netif != NULL) {
netif->_onIpEvent(event_id, event_data);
}
}
}
void NetworkInterface::_onIpEvent(int32_t event_id, void *event_data) {
arduino_event_t arduino_event;
arduino_event.event_id = ARDUINO_EVENT_MAX;
if (event_id == _got_ip_event_id) {
setStatusBits(ESP_NETIF_HAS_IP_BIT);
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
log_v(
"%s Got %sIP: " IPSTR " MASK: " IPSTR " GW: " IPSTR, desc(), event->ip_changed ? "New " : "Same ", IP2STR(&event->ip_info.ip),
IP2STR(&event->ip_info.netmask), IP2STR(&event->ip_info.gw)
);
#endif
memcpy(&arduino_event.event_info.got_ip, event_data, sizeof(ip_event_got_ip_t));
#if SOC_WIFI_SUPPORTED
if (_interface_id == ESP_NETIF_ID_STA) {
arduino_event.event_id = ARDUINO_EVENT_WIFI_STA_GOT_IP;
} else
#endif
if (_interface_id == ESP_NETIF_ID_PPP) {
arduino_event.event_id = ARDUINO_EVENT_PPP_GOT_IP;
} else if (_interface_id >= ESP_NETIF_ID_ETH && _interface_id < ESP_NETIF_ID_MAX) {
arduino_event.event_id = ARDUINO_EVENT_ETH_GOT_IP;
}
} else if (event_id == _lost_ip_event_id) {
clearStatusBits(ESP_NETIF_HAS_IP_BIT);
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
log_v("%s Lost IP", desc());
#endif
#if SOC_WIFI_SUPPORTED
if (_interface_id == ESP_NETIF_ID_STA) {
arduino_event.event_id = ARDUINO_EVENT_WIFI_STA_LOST_IP;
} else
#endif
if (_interface_id == ESP_NETIF_ID_PPP) {
arduino_event.event_id = ARDUINO_EVENT_PPP_LOST_IP;
} else if (_interface_id >= ESP_NETIF_ID_ETH && _interface_id < ESP_NETIF_ID_MAX) {
arduino_event.event_id = ARDUINO_EVENT_ETH_LOST_IP;
}
} else if (event_id == IP_EVENT_GOT_IP6) {
ip_event_got_ip6_t *event = (ip_event_got_ip6_t *)event_data;
esp_ip6_addr_type_t addr_type = esp_netif_ip6_get_addr_type(&event->ip6_info.ip);
if (addr_type == ESP_IP6_ADDR_IS_GLOBAL) {
setStatusBits(ESP_NETIF_HAS_GLOBAL_IP6_BIT);
} else if (addr_type == ESP_IP6_ADDR_IS_LINK_LOCAL) {
setStatusBits(ESP_NETIF_HAS_LOCAL_IP6_BIT);
}
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
char if_name[NETIF_NAMESIZE] = {
0,
};
netif_index_to_name(event->ip6_info.ip.zone, if_name);
static const char *addr_types[] = {"UNKNOWN", "GLOBAL", "LINK_LOCAL", "SITE_LOCAL", "UNIQUE_LOCAL", "IPV4_MAPPED_IPV6"};
log_v(
"IF %s Got IPv6: Interface: %d, IP Index: %d, Type: %s, Zone: %d (%s), Address: " IPV6STR, desc(), _interface_id, event->ip_index, addr_types[addr_type],
event->ip6_info.ip.zone, if_name, IPV62STR(event->ip6_info.ip)
);
#endif
memcpy(&arduino_event.event_info.got_ip6, event_data, sizeof(ip_event_got_ip6_t));
#if SOC_WIFI_SUPPORTED
if (_interface_id == ESP_NETIF_ID_STA) {
arduino_event.event_id = ARDUINO_EVENT_WIFI_STA_GOT_IP6;
} else if (_interface_id == ESP_NETIF_ID_AP) {
arduino_event.event_id = ARDUINO_EVENT_WIFI_AP_GOT_IP6;
} else
#endif
if (_interface_id == ESP_NETIF_ID_PPP) {
arduino_event.event_id = ARDUINO_EVENT_PPP_GOT_IP6;
} else if (_interface_id >= ESP_NETIF_ID_ETH && _interface_id < ESP_NETIF_ID_MAX) {
arduino_event.event_id = ARDUINO_EVENT_ETH_GOT_IP6;
}
#if SOC_WIFI_SUPPORTED
} else if (event_id == IP_EVENT_AP_STAIPASSIGNED && _interface_id == ESP_NETIF_ID_AP) {
setStatusBits(ESP_NETIF_HAS_IP_BIT);
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_VERBOSE
ip_event_ap_staipassigned_t *event = (ip_event_ap_staipassigned_t *)event_data;
log_v(
"%s Assigned IP: " IPSTR " to MAC: %02X:%02X:%02X:%02X:%02X:%02X", desc(), IP2STR(&event->ip), event->mac[0], event->mac[1], event->mac[2], event->mac[3],
event->mac[4], event->mac[5]
);
#endif
arduino_event.event_id = ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED;
memcpy(&arduino_event.event_info.wifi_ap_staipassigned, event_data, sizeof(ip_event_ap_staipassigned_t));
#endif
}
if (arduino_event.event_id < ARDUINO_EVENT_MAX) {
Network.postEvent(&arduino_event);
}
}
NetworkInterface::NetworkInterface()
: _esp_netif(NULL), _interface_event_group(NULL), _initial_bits(0), _got_ip_event_id(-1), _lost_ip_event_id(-1), _interface_id(ESP_NETIF_ID_MAX) {}
NetworkInterface::~NetworkInterface() {
destroyNetif();
}
IPAddress NetworkInterface::calculateNetworkID(IPAddress ip, IPAddress subnet) const {
IPAddress networkID;
for (size_t i = 0; i < 4; i++) {
networkID[i] = subnet[i] & ip[i];
}
return networkID;
}
IPAddress NetworkInterface::calculateBroadcast(IPAddress ip, IPAddress subnet) const {
IPAddress broadcastIp;
for (int i = 0; i < 4; i++) {
broadcastIp[i] = ~subnet[i] | ip[i];
}
return broadcastIp;
}
uint8_t NetworkInterface::calculateSubnetCIDR(IPAddress subnetMask) const {
uint8_t CIDR = 0;
for (uint8_t i = 0; i < 4; i++) {
if (subnetMask[i] == 0x80) { // 128
CIDR += 1;
} else if (subnetMask[i] == 0xC0) { // 192
CIDR += 2;
} else if (subnetMask[i] == 0xE0) { // 224
CIDR += 3;
} else if (subnetMask[i] == 0xF0) { // 242
CIDR += 4;
} else if (subnetMask[i] == 0xF8) { // 248
CIDR += 5;
} else if (subnetMask[i] == 0xFC) { // 252
CIDR += 6;
} else if (subnetMask[i] == 0xFE) { // 254
CIDR += 7;
} else if (subnetMask[i] == 0xFF) { // 255
CIDR += 8;
}
}
return CIDR;
}
int NetworkInterface::setStatusBits(int bits) {
if (!_interface_event_group) {
_initial_bits |= bits;
return _initial_bits;
}
return xEventGroupSetBits(_interface_event_group, bits);
}
int NetworkInterface::clearStatusBits(int bits) {
if (!_interface_event_group) {
_initial_bits &= ~bits;
return _initial_bits;
}
return xEventGroupClearBits(_interface_event_group, bits);
}
int NetworkInterface::getStatusBits() const {
if (!_interface_event_group) {
return _initial_bits;
}
return xEventGroupGetBits(_interface_event_group);
}
int NetworkInterface::waitStatusBits(int bits, uint32_t timeout_ms) const {
if (!_interface_event_group) {
return 0;
}
bits = xEventGroupWaitBits(
_interface_event_group, // The event group being tested.
bits, // The bits within the event group to wait for.
pdFALSE, // bits should be cleared before returning.
pdTRUE, // Don't wait for all bits, any bit will do.
timeout_ms / portTICK_PERIOD_MS
)
& bits; // Wait a maximum of timeout_ms for any bit to be set.
return bits;
}
void NetworkInterface::destroyNetif() {
if (_ip_ev_instance != NULL) {
bool do_not_unreg_ev_handler = false;
for (int i = 0; i < ESP_NETIF_ID_MAX; ++i) {
if (_interfaces[i] != NULL && _interfaces[i] != this) {
do_not_unreg_ev_handler = true;
break;
}
}
if (!do_not_unreg_ev_handler) {
if (esp_event_handler_unregister(IP_EVENT, ESP_EVENT_ANY_ID, &_ip_event_cb) == ESP_OK) {
_ip_ev_instance = NULL;
log_v("Unregistered event handler");
} else {
log_e("Failed to unregister event handler");
}
}
}
if (_esp_netif != NULL) {
esp_netif_destroy(_esp_netif);
_esp_netif = NULL;
}
if (_interface_event_group != NULL) {
vEventGroupDelete(_interface_event_group);
_interface_event_group = NULL;
_initial_bits = 0;
}
for (int i = 0; i < ESP_NETIF_ID_MAX; ++i) {
if (_interfaces[i] != NULL && _interfaces[i] == this) {
_interfaces[i] = NULL;
break;
}
}
}
bool NetworkInterface::initNetif(Network_Interface_ID interface_id) {
if (_esp_netif == NULL || interface_id >= ESP_NETIF_ID_MAX) {
return false;
}
_interface_id = interface_id;
_got_ip_event_id = esp_netif_get_event_id(_esp_netif, ESP_NETIF_IP_EVENT_GOT_IP);
_lost_ip_event_id = esp_netif_get_event_id(_esp_netif, ESP_NETIF_IP_EVENT_LOST_IP);
_interfaces[_interface_id] = this;
if (_interface_event_group == NULL) {
_interface_event_group = xEventGroupCreate();
if (!_interface_event_group) {
log_e("Interface Event Group Create Failed!");
return false;
}
setStatusBits(_initial_bits);
}
if (_ip_ev_instance == NULL && esp_event_handler_instance_register(IP_EVENT, ESP_EVENT_ANY_ID, &_ip_event_cb, NULL, &_ip_ev_instance)) {
log_e("event_handler_instance_register for IP_EVENT Failed!");
return false;
}
return true;
}
bool NetworkInterface::started() const {
return (getStatusBits() & ESP_NETIF_STARTED_BIT) != 0;
}
bool NetworkInterface::connected() const {
return (getStatusBits() & ESP_NETIF_CONNECTED_BIT) != 0;
}
bool NetworkInterface::hasIP() const {
return (getStatusBits() & (ESP_NETIF_HAS_IP_BIT | ESP_NETIF_HAS_STATIC_IP_BIT)) != 0;
}
bool NetworkInterface::hasLinkLocalIPv6() const {
return (getStatusBits() & ESP_NETIF_HAS_LOCAL_IP6_BIT) != 0;
}
bool NetworkInterface::hasGlobalIPv6() const {
return (getStatusBits() & ESP_NETIF_HAS_GLOBAL_IP6_BIT) != 0;
}
bool NetworkInterface::enableIPv6(bool en) {
if (en) {
setStatusBits(ESP_NETIF_WANT_IP6_BIT);
if (_esp_netif != NULL && connected()) {
// If we are already connected, try to enable IPv6 immediately
esp_err_t err = esp_netif_create_ip6_linklocal(_esp_netif);
if (err != ESP_OK) {
log_e("Failed to enable IPv6 Link Local on %s: [%d] %s", desc(), err, esp_err_to_name(err));
} else {
log_v("Enabled IPv6 Link Local on %s", desc());
}
}
} else {
clearStatusBits(ESP_NETIF_WANT_IP6_BIT);
}
return true;
}
bool NetworkInterface::dnsIP(uint8_t dns_no, IPAddress ip) {
if (_esp_netif == NULL || dns_no > 2) {
return false;
}
esp_netif_flags_t flags = esp_netif_get_flags(_esp_netif);
if (flags & ESP_NETIF_DHCP_SERVER && dns_no > 0) {
log_e("Server interfaces can have only one DNS server.");
return false;
}
esp_netif_dns_info_t d;
// ToDo: can this work with IPv6 addresses?
d.ip.type = IPADDR_TYPE_V4;
if (static_cast<uint32_t>(ip) != 0) {
d.ip.u_addr.ip4.addr = static_cast<uint32_t>(ip);
} else {
d.ip.u_addr.ip4.addr = 0;
}
if (esp_netif_set_dns_info(_esp_netif, (esp_netif_dns_type_t)dns_no, &d) != ESP_OK) {
return false;
}
return true;
}
bool NetworkInterface::config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1, IPAddress dns2, IPAddress dns3) {
if (_esp_netif == NULL) {
return false;
}
esp_err_t err = ESP_OK;
esp_netif_ip_info_t info;
esp_netif_dns_info_t d1;
esp_netif_dns_info_t d2;
esp_netif_dns_info_t d3;
d1.ip.type = IPADDR_TYPE_V4;
d2.ip.type = IPADDR_TYPE_V4;
d3.ip.type = IPADDR_TYPE_V4;
if (static_cast<uint32_t>(local_ip) != 0) {
info.ip.addr = static_cast<uint32_t>(local_ip);
info.gw.addr = static_cast<uint32_t>(gateway);
info.netmask.addr = static_cast<uint32_t>(subnet);
d1.ip.u_addr.ip4.addr = static_cast<uint32_t>(dns1);
d2.ip.u_addr.ip4.addr = static_cast<uint32_t>(dns2);
d3.ip.u_addr.ip4.addr = static_cast<uint32_t>(dns3);
} else {
info.ip.addr = 0;
info.gw.addr = 0;
info.netmask.addr = 0;
d1.ip.u_addr.ip4.addr = 0;
d2.ip.u_addr.ip4.addr = 0;
d3.ip.u_addr.ip4.addr = 0;
}
esp_netif_flags_t flags = esp_netif_get_flags(_esp_netif);
if (flags & ESP_NETIF_DHCP_SERVER) {
// Set DNS Server
if (d2.ip.u_addr.ip4.addr != 0) {
err = esp_netif_set_dns_info(_esp_netif, ESP_NETIF_DNS_MAIN, &d2);
if (err) {
log_e("Netif Set DNS Info Failed! 0x%04x: %s", err, esp_err_to_name(err));
return false;
}
}
// Stop DHCPS
err = esp_netif_dhcps_stop(_esp_netif);
if (err && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED) {
log_e("DHCPS Stop Failed! 0x%04x: %s", err, esp_err_to_name(err));
return false;
}
// Set IPv4, Netmask, Gateway
err = esp_netif_set_ip_info(_esp_netif, &info);
if (err) {
log_e("Netif Set IP Failed! 0x%04x: %s", err, esp_err_to_name(err));
return false;
}
dhcps_lease_t lease;
lease.enable = true;
uint8_t CIDR = calculateSubnetCIDR(subnet);
log_v(
"SoftAP: %s | Gateway: %s | DHCP Start: %s | Netmask: %s", local_ip.toString().c_str(), gateway.toString().c_str(), dns1.toString().c_str(),
subnet.toString().c_str()
);
// netmask must have room for at least 12 IP addresses (AP + GW + 10 DHCP Leasing addresses)
// netmask also must be limited to the last 8 bits of IPv4, otherwise this function won't work
// IDF NETIF checks netmask for the 3rd byte: https://github.com/espressif/esp-idf/blob/master/components/esp_netif/lwip/esp_netif_lwip.c#L1857-L1862
if (CIDR > 28 || CIDR < 24) {
log_e("Bad netmask. It must be from /24 to /28 (255.255.255. 0<->240)");
return false; // ESP_FAIL if initializing failed
}
#define _byte_swap32(num) (((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | ((num >> 8) & 0xff00) | ((num << 24) & 0xff000000))
// The code below is ready for any netmask, not limited to 255.255.255.0
uint32_t netmask = _byte_swap32(info.netmask.addr);
uint32_t ap_ipaddr = _byte_swap32(info.ip.addr);
uint32_t dhcp_ipaddr = _byte_swap32(static_cast<uint32_t>(dns1));
dhcp_ipaddr = dhcp_ipaddr == 0 ? ap_ipaddr + 1 : dhcp_ipaddr;
uint32_t leaseStartMax = ~netmask - 10;
// there will be 10 addresses for DHCP to lease
lease.start_ip.addr = dhcp_ipaddr;
lease.end_ip.addr = lease.start_ip.addr + 10;
// Check if local_ip is in the same subnet as the dhcp leasing range initial address
if ((ap_ipaddr & netmask) != (dhcp_ipaddr & netmask)) {
log_e(
"The AP IP address (%s) and the DHCP start address (%s) must be in the same subnet", local_ip.toString().c_str(),
IPAddress(_byte_swap32(dhcp_ipaddr)).toString().c_str()
);
return false; // ESP_FAIL if initializing failed
}
// prevents DHCP lease range to overflow subnet range
if ((dhcp_ipaddr & ~netmask) >= leaseStartMax) {
// make first DHCP lease addr stay in the beginning of the netmask range
lease.start_ip.addr = (dhcp_ipaddr & netmask) + 1;
lease.end_ip.addr = lease.start_ip.addr + 10;
log_w("DHCP Lease out of range - Changing DHCP leasing start to %s", IPAddress(_byte_swap32(lease.start_ip.addr)).toString().c_str());
}
// Check if local_ip is within DHCP range
if (ap_ipaddr >= lease.start_ip.addr && ap_ipaddr <= lease.end_ip.addr) {
log_e(
"The AP IP address (%s) can't be within the DHCP range (%s -- %s)", local_ip.toString().c_str(),
IPAddress(_byte_swap32(lease.start_ip.addr)).toString().c_str(), IPAddress(_byte_swap32(lease.end_ip.addr)).toString().c_str()
);
return false; // ESP_FAIL if initializing failed
}
// Check if gateway is within DHCP range
uint32_t gw_ipaddr = _byte_swap32(info.gw.addr);
bool gw_in_same_subnet = (gw_ipaddr & netmask) == (ap_ipaddr & netmask);
if (gw_in_same_subnet && gw_ipaddr >= lease.start_ip.addr && gw_ipaddr <= lease.end_ip.addr) {
log_e(
"The GatewayP address (%s) can't be within the DHCP range (%s -- %s)", gateway.toString().c_str(),
IPAddress(_byte_swap32(lease.start_ip.addr)).toString().c_str(), IPAddress(_byte_swap32(lease.end_ip.addr)).toString().c_str()
);
return false; // ESP_FAIL if initializing failed
}
// all done, just revert back byte order of DHCP lease range
lease.start_ip.addr = _byte_swap32(lease.start_ip.addr);
lease.end_ip.addr = _byte_swap32(lease.end_ip.addr);
log_v("DHCP Server Range: %s to %s", IPAddress(lease.start_ip.addr).toString().c_str(), IPAddress(lease.end_ip.addr).toString().c_str());
err = esp_netif_dhcps_option(_esp_netif, ESP_NETIF_OP_SET, ESP_NETIF_REQUESTED_IP_ADDRESS, (void *)&lease, sizeof(dhcps_lease_t));
if (err) {
log_e("DHCPS Set Lease Failed! 0x%04x: %s", err, esp_err_to_name(err));
return false;
}
// Offer DNS to DHCP clients
if (d2.ip.u_addr.ip4.addr != 0) {
dhcps_offer_t dhcps_dns_value = OFFER_DNS;
err = esp_netif_dhcps_option(_esp_netif, ESP_NETIF_OP_SET, ESP_NETIF_DOMAIN_NAME_SERVER, &dhcps_dns_value, sizeof(dhcps_dns_value));
if (err) {
log_e("Netif Set DHCP Option Failed! 0x%04x: %s", err, esp_err_to_name(err));
return false;
}
}
// Start DHCPS
err = esp_netif_dhcps_start(_esp_netif);
if (err) {
log_e("DHCPS Start Failed! 0x%04x: %s", err, esp_err_to_name(err));
return false;
}
} else {
// Stop DHCPC
err = esp_netif_dhcpc_stop(_esp_netif);
if (err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED) {
log_e("DHCP could not be stopped! Error: 0x%04x: %s", err, esp_err_to_name(err));
return false;
}
clearStatusBits(ESP_NETIF_HAS_IP_BIT | ESP_NETIF_HAS_STATIC_IP_BIT);
// Set IPv4, Netmask, Gateway
err = esp_netif_set_ip_info(_esp_netif, &info);
if (err != ERR_OK) {
log_e("ETH IP could not be configured! Error: 0x%04x: %s", err, esp_err_to_name(err));
return false;
}
// Set DNS Servers
esp_netif_set_dns_info(_esp_netif, ESP_NETIF_DNS_MAIN, &d1);
esp_netif_set_dns_info(_esp_netif, ESP_NETIF_DNS_BACKUP, &d2);
esp_netif_set_dns_info(_esp_netif, ESP_NETIF_DNS_FALLBACK, &d3);
// Start DHCPC if static IP was set
if (info.ip.addr == 0) {
err = esp_netif_dhcpc_start(_esp_netif);
if (err != ESP_OK && err != ESP_ERR_ESP_NETIF_DHCP_ALREADY_STARTED) {
log_w("DHCP could not be started! Error: 0x%04x: %s", err, esp_err_to_name(err));
return false;
}
} else {
setStatusBits(ESP_NETIF_HAS_STATIC_IP_BIT);
}
}
return true;
}
const char *NetworkInterface::getHostname() const {
if (_esp_netif == NULL) {
return "";
}
const char *hostname;
if (esp_netif_get_hostname(_esp_netif, &hostname)) {
return NULL;
}
return hostname;
}
bool NetworkInterface::setHostname(const char *hostname) const {
if (_esp_netif == NULL) {
return false;
}
return esp_netif_set_hostname(_esp_netif, hostname) == 0;
}
bool NetworkInterface::linkUp() const {
if (_esp_netif == NULL) {
return false;
}
return esp_netif_is_netif_up(_esp_netif);
}
const char *NetworkInterface::ifkey(void) const {
if (_esp_netif == NULL) {
return "";
}
return esp_netif_get_ifkey(_esp_netif);
}
const char *NetworkInterface::desc(void) const {
if (_esp_netif == NULL) {
return "";
}
return esp_netif_get_desc(_esp_netif);
}
String NetworkInterface::impl_name(void) const {
if (_esp_netif == NULL) {
return String("");
}
char netif_name[8];
esp_err_t err = esp_netif_get_netif_impl_name(_esp_netif, netif_name);
if (err != ESP_OK) {
log_e("Failed to get netif impl_name: 0x%04x %s", err, esp_err_to_name(err));
return String("");
}
return String(netif_name);
}
int NetworkInterface::impl_index() const {
if (_esp_netif == NULL) {
return -1;
}
return esp_netif_get_netif_impl_index(_esp_netif);
}
int NetworkInterface::route_prio() const {
if (_esp_netif == NULL) {
return -1;
}
return esp_netif_get_route_prio(_esp_netif);
}
bool NetworkInterface::setDefault() {
if (_esp_netif == NULL) {
return false;
}
esp_err_t err = esp_netif_set_default_netif(_esp_netif);
if (err != ESP_OK) {
log_e("Failed to set default netif: 0x%04x %s", err, esp_err_to_name(err));
return false;
}
return true;
}
bool NetworkInterface::isDefault() const {
if (_esp_netif == NULL) {
return false;
}
return esp_netif_get_default_netif() == _esp_netif;
}
uint8_t *NetworkInterface::macAddress(uint8_t *mac) const {
if (!mac || _esp_netif == NULL || _interface_id == ESP_NETIF_ID_PPP) {
return NULL;
}
esp_err_t err = esp_netif_get_mac(_esp_netif, mac);
if (err != ESP_OK) {
log_e("Failed to get netif mac: 0x%04x %s", err, esp_err_to_name(err));
return NULL;
}
return mac;
}
String NetworkInterface::macAddress(void) const {
uint8_t mac[6] = {0, 0, 0, 0, 0, 0};
char macStr[18] = {0};
macAddress(mac);
sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return String(macStr);
}
IPAddress NetworkInterface::localIP() const {
if (_esp_netif == NULL) {
return IPAddress();
}
esp_netif_ip_info_t ip;
if (esp_netif_get_ip_info(_esp_netif, &ip)) {
return IPAddress();
}
return IPAddress(ip.ip.addr);
}
IPAddress NetworkInterface::subnetMask() const {
if (_esp_netif == NULL) {
return IPAddress();
}
esp_netif_ip_info_t ip;
if (esp_netif_get_ip_info(_esp_netif, &ip)) {
return IPAddress();
}
return IPAddress(ip.netmask.addr);
}
IPAddress NetworkInterface::gatewayIP() const {
if (_esp_netif == NULL) {
return IPAddress();
}
esp_netif_ip_info_t ip;
if (esp_netif_get_ip_info(_esp_netif, &ip)) {
return IPAddress();
}
return IPAddress(ip.gw.addr);
}
IPAddress NetworkInterface::dnsIP(uint8_t dns_no) const {
if (_esp_netif == NULL) {
return IPAddress();
}
esp_netif_dns_info_t d;
if (esp_netif_get_dns_info(_esp_netif, dns_no ? ESP_NETIF_DNS_BACKUP : ESP_NETIF_DNS_MAIN, &d) != ESP_OK) {
return IPAddress();
}
if (d.ip.type == ESP_IPADDR_TYPE_V6) {
// IPv6 from 4x uint32_t; byte order based on IPV62STR() in esp_netif_ip_addr.h
// log_v("DNS got IPv6: " IPV6STR, IPV62STR(d.ip.u_addr.ip6));
uint32_t addr0 esp_netif_htonl(d.ip.u_addr.ip6.addr[0]);
uint32_t addr1 esp_netif_htonl(d.ip.u_addr.ip6.addr[1]);
uint32_t addr2 esp_netif_htonl(d.ip.u_addr.ip6.addr[2]);
uint32_t addr3 esp_netif_htonl(d.ip.u_addr.ip6.addr[3]);
return IPAddress(
(uint8_t)(addr0 >> 24) & 0xFF, (uint8_t)(addr0 >> 16) & 0xFF, (uint8_t)(addr0 >> 8) & 0xFF, (uint8_t)addr0 & 0xFF, (uint8_t)(addr1 >> 24) & 0xFF,
(uint8_t)(addr1 >> 16) & 0xFF, (uint8_t)(addr1 >> 8) & 0xFF, (uint8_t)addr1 & 0xFF, (uint8_t)(addr2 >> 24) & 0xFF, (uint8_t)(addr2 >> 16) & 0xFF,
(uint8_t)(addr2 >> 8) & 0xFF, (uint8_t)addr2 & 0xFF, (uint8_t)(addr3 >> 24) & 0xFF, (uint8_t)(addr3 >> 16) & 0xFF, (uint8_t)(addr3 >> 8) & 0xFF,
(uint8_t)addr3 & 0xFF, d.ip.u_addr.ip6.zone
);
}
// IPv4 from single uint32_t
// log_v("DNS IPv4: " IPSTR, IP2STR(&d.ip.u_addr.ip4));
return IPAddress(d.ip.u_addr.ip4.addr);
}
IPAddress NetworkInterface::broadcastIP() const {
if (_esp_netif == NULL) {
return IPAddress();
}
esp_netif_ip_info_t ip;
if (esp_netif_get_ip_info(_esp_netif, &ip)) {
return IPAddress();
}
return calculateBroadcast(IPAddress(ip.gw.addr), IPAddress(ip.netmask.addr));
}
IPAddress NetworkInterface::networkID() const {
if (_esp_netif == NULL) {
return IPAddress();
}
esp_netif_ip_info_t ip;
if (esp_netif_get_ip_info(_esp_netif, &ip)) {
return IPAddress();
}
return calculateNetworkID(IPAddress(ip.gw.addr), IPAddress(ip.netmask.addr));
}
uint8_t NetworkInterface::subnetCIDR() const {
if (_esp_netif == NULL) {
return (uint8_t)0;
}
esp_netif_ip_info_t ip;
if (esp_netif_get_ip_info(_esp_netif, &ip)) {
return (uint8_t)0;
}
return calculateSubnetCIDR(IPAddress(ip.netmask.addr));
}
IPAddress NetworkInterface::linkLocalIPv6() const {
if (_esp_netif == NULL) {
return IPAddress(IPv6);
}
static esp_ip6_addr_t addr;
if (esp_netif_get_ip6_linklocal(_esp_netif, &addr)) {
return IPAddress(IPv6);
}
return IPAddress(IPv6, (const uint8_t *)addr.addr, addr.zone);
}
IPAddress NetworkInterface::globalIPv6() const {
if (_esp_netif == NULL) {
return IPAddress(IPv6);
}
static esp_ip6_addr_t addr;
if (esp_netif_get_ip6_global(_esp_netif, &addr)) {
return IPAddress(IPv6);
}
return IPAddress(IPv6, (const uint8_t *)addr.addr, addr.zone);
}
size_t NetworkInterface::printTo(Print &out) const {
size_t bytes = 0;
if (_esp_netif == NULL) {
return bytes;
}
if (isDefault()) {
bytes += out.print("*");
}
const char *dscr = esp_netif_get_desc(_esp_netif);
if (dscr != NULL) {
bytes += out.print(dscr);
}
bytes += out.print(":");
if (esp_netif_is_netif_up(_esp_netif)) {
bytes += out.print(" <UP");
} else {
bytes += out.print(" <DOWN");
}
bytes += printDriverInfo(out);
bytes += out.print(">");
bytes += out.print(" (");
esp_netif_flags_t flags = esp_netif_get_flags(_esp_netif);
if (flags & ESP_NETIF_DHCP_CLIENT) {
bytes += out.print("DHCPC");
if (getStatusBits() & ESP_NETIF_HAS_STATIC_IP_BIT) {
bytes += out.print("_OFF");
}
}
if (flags & ESP_NETIF_DHCP_SERVER) {
bytes += out.print("DHCPS");
}
if (flags & ESP_NETIF_FLAG_AUTOUP) {
bytes += out.print(",AUTOUP");
}
if (flags & ESP_NETIF_FLAG_GARP) {
bytes += out.print(",GARP");
}
if (flags & ESP_NETIF_FLAG_EVENT_IP_MODIFIED) {
bytes += out.print(",IP_MOD");
}
if (flags & ESP_NETIF_FLAG_IS_PPP) {
bytes += out.print(",PPP");
}
if (flags & ESP_NETIF_FLAG_IS_BRIDGE) {
bytes += out.print(",BRIDGE");
}
if (flags & ESP_NETIF_FLAG_MLDV6_REPORT) {
bytes += out.print(",V6_REP");
}
bytes += out.println(")");
bytes += out.print(" ");
bytes += out.print("ether ");
bytes += out.print(macAddress());
bytes += out.println();
bytes += out.print(" ");
bytes += out.print("inet ");
bytes += out.print(localIP());
bytes += out.print(" netmask ");
bytes += out.print(subnetMask());
bytes += out.print(" broadcast ");
bytes += out.print(broadcastIP());
bytes += out.println();
bytes += out.print(" ");
bytes += out.print("gateway ");
bytes += out.print(gatewayIP());
bytes += out.print(" dns ");
bytes += out.print(dnsIP());
bytes += out.println();
static const char *types[] = {"UNKNOWN", "GLOBAL", "LINK_LOCAL", "SITE_LOCAL", "UNIQUE_LOCAL", "IPV4_MAPPED_IPV6"};
esp_ip6_addr_t if_ip6[CONFIG_LWIP_IPV6_NUM_ADDRESSES];
int v6addrs = esp_netif_get_all_ip6(_esp_netif, if_ip6);
for (int i = 0; i < v6addrs; ++i) {
bytes += out.print(" ");
bytes += out.print("inet6 ");
bytes += IPAddress(IPv6, (const uint8_t *)if_ip6[i].addr, if_ip6[i].zone).printTo(out, true);
bytes += out.print(" type ");
bytes += out.print(types[esp_netif_ip6_get_addr_type(&if_ip6[i])]);
bytes += out.println();
}
return bytes;
}