* Add Config * Add Cache and remove pre-commit action * [pre-commit.ci lite] apply automatic fixes * Remove freeze * Fix * Update action * Use latest stable Python 3 version * Improve caching * Improve cache tag * Improve bot message * fix(typos): Fix typos * fix(typos): Fix more typos * refactor(udp_server): Convert script from Python 2 to 3 * Fix whitespace * Clang-format fixes * Prettier fixes * Black formatting * Manual fixes * Line endings * Fix flake and make Vale manual * Fix flake and reformat --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Co-authored-by: Rodrigo Garcia <rodrigo.garcia@espressif.com>
798 lines
27 KiB
C++
798 lines
27 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;
|
|
}
|
|
|
|
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) {
|
|
esp_event_handler_unregister(IP_EVENT, ESP_EVENT_ANY_ID, &_ip_event_cb);
|
|
_ip_ev_instance = NULL;
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
|
|
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);
|
|
} 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: %d", 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: %d", 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) {
|
|
return NULL;
|
|
}
|
|
esp_err_t err = esp_netif_get_mac(_esp_netif, mac);
|
|
if (err != ESP_OK) {
|
|
log_e("Failed to get netif mac: %d", err);
|
|
return NULL;
|
|
}
|
|
// getMac(mac);
|
|
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;
|
|
}
|