diff --git a/CMakeLists.txt b/CMakeLists.txt index 0834ae1ec34..e121aaf3e3c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,7 +51,6 @@ set(CORE_SRCS cores/esp32/FunctionalInterrupt.cpp cores/esp32/HardwareSerial.cpp cores/esp32/IPAddress.cpp - cores/esp32/IPv6Address.cpp cores/esp32/libb64/cdecode.c cores/esp32/libb64/cencode.c cores/esp32/main.cpp diff --git a/cores/esp32/IPAddress.cpp b/cores/esp32/IPAddress.cpp index 002dccb3fcd..0fa5affdea7 100644 --- a/cores/esp32/IPAddress.cpp +++ b/cores/esp32/IPAddress.cpp @@ -1,38 +1,40 @@ /* - IPAddress.cpp - Base class that provides IPAddress - Copyright (c) 2011 Adrian McEwen. All right reserved. + IPAddress.cpp - Base class that provides IPAddress + Copyright (c) 2011 Adrian McEwen. All right reserved. - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ -#include -#include -#include -#include +#include "IPAddress.h" +#include "Print.h" +#include "lwip/netif.h" +#include "StreamString.h" IPAddress::IPAddress() : IPAddress(IPv4) {} IPAddress::IPAddress(IPType ip_type) { _type = ip_type; + _zone = IP6_NO_ZONE; memset(_address.bytes, 0, sizeof(_address.bytes)); } IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) { _type = IPv4; + _zone = IP6_NO_ZONE; memset(_address.bytes, 0, sizeof(_address.bytes)); _address.bytes[IPADDRESS_V4_BYTES_INDEX] = first_octet; _address.bytes[IPADDRESS_V4_BYTES_INDEX + 1] = second_octet; @@ -40,7 +42,7 @@ IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_oc _address.bytes[IPADDRESS_V4_BYTES_INDEX + 3] = fourth_octet; } -IPAddress::IPAddress(uint8_t o1, uint8_t o2, uint8_t o3, uint8_t o4, uint8_t o5, uint8_t o6, uint8_t o7, uint8_t o8, uint8_t o9, uint8_t o10, uint8_t o11, uint8_t o12, uint8_t o13, uint8_t o14, uint8_t o15, uint8_t o16) { +IPAddress::IPAddress(uint8_t o1, uint8_t o2, uint8_t o3, uint8_t o4, uint8_t o5, uint8_t o6, uint8_t o7, uint8_t o8, uint8_t o9, uint8_t o10, uint8_t o11, uint8_t o12, uint8_t o13, uint8_t o14, uint8_t o15, uint8_t o16, uint8_t z) { _type = IPv6; _address.bytes[0] = o1; _address.bytes[1] = o2; @@ -58,12 +60,14 @@ IPAddress::IPAddress(uint8_t o1, uint8_t o2, uint8_t o3, uint8_t o4, uint8_t o5, _address.bytes[13] = o14; _address.bytes[14] = o15; _address.bytes[15] = o16; + _zone = z; } IPAddress::IPAddress(uint32_t address) { // IPv4 only _type = IPv4; + _zone = IP6_NO_ZONE; memset(_address.bytes, 0, sizeof(_address.bytes)); _address.dword[IPADDRESS_V4_DWORD_INDEX] = address; @@ -78,14 +82,16 @@ IPAddress::IPAddress(uint32_t address) IPAddress::IPAddress(const uint8_t *address) : IPAddress(IPv4, address) {} -IPAddress::IPAddress(IPType ip_type, const uint8_t *address) +IPAddress::IPAddress(IPType ip_type, const uint8_t *address, uint8_t z) { _type = ip_type; if (ip_type == IPv4) { memset(_address.bytes, 0, sizeof(_address.bytes)); memcpy(&_address.bytes[IPADDRESS_V4_BYTES_INDEX], address, sizeof(uint32_t)); + _zone = 0; } else { memcpy(_address.bytes, address, sizeof(_address.bytes)); + _zone = z; } } @@ -94,151 +100,20 @@ IPAddress::IPAddress(const char *address) fromString(address); } -IPAddress& IPAddress::operator=(const uint8_t *address) -{ - // IPv4 only conversion from byte pointer - _type = IPv4; - memset(_address.bytes, 0, sizeof(_address.bytes)); - memcpy(&_address.bytes[IPADDRESS_V4_BYTES_INDEX], address, sizeof(uint32_t)); - return *this; -} - -IPAddress& IPAddress::operator=(const char *address) -{ - fromString(address); - return *this; -} - -IPAddress& IPAddress::operator=(uint32_t address) -{ - // IPv4 conversion - // See note on conversion/comparison and uint32_t - _type = IPv4; - memset(_address.bytes, 0, sizeof(_address.bytes)); - _address.dword[IPADDRESS_V4_DWORD_INDEX] = address; - return *this; -} - -bool IPAddress::operator==(const IPAddress& addr) const -{ - return (addr._type == _type) - && (memcmp(addr._address.bytes, _address.bytes, sizeof(_address.bytes)) == 0); -} - -bool IPAddress::operator==(const uint8_t* addr) const -{ - // IPv4 only comparison to byte pointer - // Can't support IPv6 as we know our type, but not the length of the pointer - return _type == IPv4 && memcmp(addr, &_address.bytes[IPADDRESS_V4_BYTES_INDEX], sizeof(uint32_t)) == 0; -} - -uint8_t IPAddress::operator[](int index) const { - if (_type == IPv4) { - return _address.bytes[IPADDRESS_V4_BYTES_INDEX + index]; - } - return _address.bytes[index]; -} - -uint8_t& IPAddress::operator[](int index) { - if (_type == IPv4) { - return _address.bytes[IPADDRESS_V4_BYTES_INDEX + index]; - } - return _address.bytes[index]; -} - -size_t IPAddress::printTo(Print& p) const -{ - size_t n = 0; - - if (_type == IPv6) { - // IPv6 IETF canonical format: compress left-most longest run of two or more zero fields, lower case - int8_t longest_start = -1; - int8_t longest_length = 1; - int8_t current_start = -1; - int8_t current_length = 0; - for (int8_t f = 0; f < 8; f++) { - if (_address.bytes[f * 2] == 0 && _address.bytes[f * 2 + 1] == 0) { - if (current_start == -1) { - current_start = f; - current_length = 1; - } else { - current_length++; - } - if (current_length > longest_length) { - longest_start = current_start; - longest_length = current_length; - } - } else { - current_start = -1; - } - } - for (int f = 0; f < 8; f++) { - if (f < longest_start || f >= longest_start + longest_length) { - uint8_t c1 = _address.bytes[f * 2] >> 4; - uint8_t c2 = _address.bytes[f * 2] & 0xf; - uint8_t c3 = _address.bytes[f * 2 + 1] >> 4; - uint8_t c4 = _address.bytes[f * 2 + 1] & 0xf; - if (c1 > 0) { - n += p.print((char)(c1 < 10 ? '0' + c1 : 'a' + c1 - 10)); - } - if (c1 > 0 || c2 > 0) { - n += p.print((char)(c2 < 10 ? '0' + c2 : 'a' + c2 - 10)); - } - if (c1 > 0 || c2 > 0 || c3 > 0) { - n += p.print((char)(c3 < 10 ? '0' + c3 : 'a' + c3 - 10)); - } - n += p.print((char)(c4 < 10 ? '0' + c4 : 'a' + c4 - 10)); - if (f < 7) { - n += p.print(':'); - } - } else if (f == longest_start) { - if (longest_start == 0) { - n += p.print(':'); - } - n += p.print(':'); - } - } - return n; - } - - // IPv4 - for (int i =0; i < 3; i++) - { - n += p.print(_address.bytes[IPADDRESS_V4_BYTES_INDEX + i], DEC); - n += p.print('.'); - } - n += p.print(_address.bytes[IPADDRESS_V4_BYTES_INDEX + 3], DEC); - return n; -} - -String IPAddress::toString4() const +IPAddress::IPAddress(const IPAddress& address) { - char szRet[16]; - snprintf(szRet, sizeof(szRet), "%u.%u.%u.%u", _address.bytes[IPADDRESS_V4_BYTES_INDEX], _address.bytes[IPADDRESS_V4_BYTES_INDEX + 1], _address.bytes[IPADDRESS_V4_BYTES_INDEX + 2], _address.bytes[IPADDRESS_V4_BYTES_INDEX + 3]); - return String(szRet); + *this = address; } -String IPAddress::toString6() const +String IPAddress::toString(bool includeZone) const { StreamString s; - s.reserve(40); - printTo(s); - return s; + printTo(s, includeZone); + return String(s); } -String IPAddress::toString() const -{ - if (_type == IPv4) { - return toString4(); - } else { - return toString6(); - } -} - -bool IPAddress::fromString(const char *address) -{ - if (!fromString4(address)) - { +bool IPAddress::fromString(const char *address) { + if (!fromString4(address)) { return fromString6(address); } return true; @@ -336,6 +211,12 @@ bool IPAddress::fromString6(const char *address) { colons++; acc = 0; } + else if (c == '%') { + _zone = netif_name_to_index(address); + while(*address != '\0'){ + address++; + } + } else // Invalid char return false; @@ -364,5 +245,186 @@ bool IPAddress::fromString6(const char *address) { return true; } -// declared one time - as external in IPAddress.h -IPAddress INADDR_NONE(0, 0, 0, 0); +IPAddress& IPAddress::operator=(const uint8_t *address) +{ + // IPv4 only conversion from byte pointer + _type = IPv4; + memset(_address.bytes, 0, sizeof(_address.bytes)); + memcpy(&_address.bytes[IPADDRESS_V4_BYTES_INDEX], address, sizeof(uint32_t)); + return *this; +} + +IPAddress& IPAddress::operator=(const char *address) +{ + fromString(address); + return *this; +} + +IPAddress& IPAddress::operator=(uint32_t address) +{ + // IPv4 conversion + // See note on conversion/comparison and uint32_t + _type = IPv4; + memset(_address.bytes, 0, sizeof(_address.bytes)); + _address.dword[IPADDRESS_V4_DWORD_INDEX] = address; + return *this; +} + +IPAddress& IPAddress::operator=(const IPAddress& address){ + _type = address.type(); + _zone = address.zone(); + memcpy(_address.bytes, address._address.bytes, sizeof(_address.bytes)); + return *this; +} + +bool IPAddress::operator==(const IPAddress& addr) const { + return (addr._type == _type) + && (memcmp(addr._address.bytes, _address.bytes, sizeof(_address.bytes)) == 0); +} + +bool IPAddress::operator==(const uint8_t* addr) const +{ + // IPv4 only comparison to byte pointer + // Can't support IPv6 as we know our type, but not the length of the pointer + return _type == IPv4 && memcmp(addr, &_address.bytes[IPADDRESS_V4_BYTES_INDEX], sizeof(uint32_t)) == 0; +} + +uint8_t IPAddress::operator[](int index) const { + if (_type == IPv4) { + return _address.bytes[IPADDRESS_V4_BYTES_INDEX + index]; + } + return _address.bytes[index]; +} + +uint8_t& IPAddress::operator[](int index) { + if (_type == IPv4) { + return _address.bytes[IPADDRESS_V4_BYTES_INDEX + index]; + } + return _address.bytes[index]; +} + +size_t IPAddress::printTo(Print& p) const +{ + return printTo(p, false); +} + +size_t IPAddress::printTo(Print& p, bool includeZone) const +{ + size_t n = 0; + + if (_type == IPv6) { + // IPv6 IETF canonical format: compress left-most longest run of two or more zero fields, lower case + int8_t longest_start = -1; + int8_t longest_length = 1; + int8_t current_start = -1; + int8_t current_length = 0; + for (int8_t f = 0; f < 8; f++) { + if (_address.bytes[f * 2] == 0 && _address.bytes[f * 2 + 1] == 0) { + if (current_start == -1) { + current_start = f; + current_length = 1; + } else { + current_length++; + } + if (current_length > longest_length) { + longest_start = current_start; + longest_length = current_length; + } + } else { + current_start = -1; + } + } + for (int f = 0; f < 8; f++) { + if (f < longest_start || f >= longest_start + longest_length) { + uint8_t c1 = _address.bytes[f * 2] >> 4; + uint8_t c2 = _address.bytes[f * 2] & 0xf; + uint8_t c3 = _address.bytes[f * 2 + 1] >> 4; + uint8_t c4 = _address.bytes[f * 2 + 1] & 0xf; + if (c1 > 0) { + n += p.print((char)(c1 < 10 ? '0' + c1 : 'a' + c1 - 10)); + } + if (c1 > 0 || c2 > 0) { + n += p.print((char)(c2 < 10 ? '0' + c2 : 'a' + c2 - 10)); + } + if (c1 > 0 || c2 > 0 || c3 > 0) { + n += p.print((char)(c3 < 10 ? '0' + c3 : 'a' + c3 - 10)); + } + n += p.print((char)(c4 < 10 ? '0' + c4 : 'a' + c4 - 10)); + if (f < 7) { + n += p.print(':'); + } + } else if (f == longest_start) { + if (longest_start == 0) { + n += p.print(':'); + } + n += p.print(':'); + } + } + // add a zone if zone-id is non-zero + if(_zone > 0 && includeZone){ + n += p.print('%'); + char if_name[NETIF_NAMESIZE]; + netif_index_to_name(_zone, if_name); + n += p.print(if_name); + } + return n; + } + + // IPv4 + for (int i =0; i < 3; i++) + { + n += p.print(_address.bytes[IPADDRESS_V4_BYTES_INDEX + i], DEC); + n += p.print('.'); + } + n += p.print(_address.bytes[IPADDRESS_V4_BYTES_INDEX + 3], DEC); + return n; +} + +IPAddress::IPAddress(const ip_addr_t *addr){ + from_ip_addr_t(addr); +} + +void IPAddress::to_ip_addr_t(ip_addr_t* addr) const { + if(_type == IPv6){ + addr->type = IPADDR_TYPE_V6; + addr->u_addr.ip6.addr[0] = _address.dword[0]; + addr->u_addr.ip6.addr[1] = _address.dword[1]; + addr->u_addr.ip6.addr[2] = _address.dword[2]; + addr->u_addr.ip6.addr[3] = _address.dword[3]; +#if LWIP_IPV6_SCOPES + addr->u_addr.ip6.zone = _zone; +#endif /* LWIP_IPV6_SCOPES */ + } else { + addr->type = IPADDR_TYPE_V4; + addr->u_addr.ip4.addr = _address.dword[IPADDRESS_V4_DWORD_INDEX]; + } +} + +IPAddress& IPAddress::from_ip_addr_t(const ip_addr_t* addr){ + if(addr->type == IPADDR_TYPE_V6){ + _type = IPv6; + _address.dword[0] = addr->u_addr.ip6.addr[0]; + _address.dword[1] = addr->u_addr.ip6.addr[1]; + _address.dword[2] = addr->u_addr.ip6.addr[2]; + _address.dword[3] = addr->u_addr.ip6.addr[3]; +#if LWIP_IPV6_SCOPES + _zone = addr->u_addr.ip6.zone; +#endif /* LWIP_IPV6_SCOPES */ + } else { + _type = IPv4; + _address.dword[IPADDRESS_V4_DWORD_INDEX] = addr->u_addr.ip4.addr; + } + return *this; +} + +esp_ip6_addr_type_t IPAddress::addr_type() const { + if(_type != IPv6){ + return ESP_IP6_ADDR_IS_UNKNOWN; + } + ip_addr_t addr; + to_ip_addr_t(&addr); + return esp_netif_ip6_get_addr_type((esp_ip6_addr_t*)(&(addr.u_addr.ip6))); +} + +const IPAddress IN6ADDR_ANY(IPv6); +const IPAddress INADDR_NONE(0,0,0,0); diff --git a/cores/esp32/IPAddress.h b/cores/esp32/IPAddress.h index 329ca92afe9..0a3efd01c8d 100644 --- a/cores/esp32/IPAddress.h +++ b/cores/esp32/IPAddress.h @@ -1,82 +1,83 @@ /* - IPAddress.h - Base class that provides IPAddress - Copyright (c) 2011 Adrian McEwen. All right reserved. + IPAddress.h - Base class that provides IPAddress + Copyright (c) 2011 Adrian McEwen. All right reserved. - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ -#ifndef IPAddress_h -#define IPAddress_h +#pragma once #include -#include -#include - -// A class to make it easier to handle and pass around IP addresses +#include "Printable.h" +#include "WString.h" +#include "lwip/ip_addr.h" +#include "esp_netif_ip_addr.h" #define IPADDRESS_V4_BYTES_INDEX 12 #define IPADDRESS_V4_DWORD_INDEX 3 -enum IPType -{ +// A class to make it easier to handle and pass around IP addresses + +enum IPType { IPv4, IPv6 }; -class IPAddress: public Printable -{ +class IPAddress : public Printable { private: union { uint8_t bytes[16]; uint32_t dword[4]; } _address; IPType _type; + uint8_t _zone; // Access the raw byte array containing the address. Because this returns a pointer // to the internal structure rather than a copy of the address this function should only // be used when you know that the usage of the returned uint8_t* will be transient and not // stored. - uint8_t* raw_address() - { - return _type == IPv4 ? &_address.bytes[IPADDRESS_V4_BYTES_INDEX] : _address.bytes; - } + uint8_t* raw_address() { return _type == IPv4 ? &_address.bytes[IPADDRESS_V4_BYTES_INDEX] : _address.bytes; } public: // Constructors + + // Default IPv4 IPAddress(); IPAddress(IPType ip_type); IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet); - IPAddress(uint8_t o1, uint8_t o2, uint8_t o3, uint8_t o4, uint8_t o5, uint8_t o6, uint8_t o7, uint8_t o8, uint8_t o9, uint8_t o10, uint8_t o11, uint8_t o12, uint8_t o13, uint8_t o14, uint8_t o15, uint8_t o16); + IPAddress(uint8_t o1, uint8_t o2, uint8_t o3, uint8_t o4, uint8_t o5, uint8_t o6, uint8_t o7, uint8_t o8, uint8_t o9, uint8_t o10, uint8_t o11, uint8_t o12, uint8_t o13, uint8_t o14, uint8_t o15, uint8_t o16, uint8_t z=0); + // IPv4; see implementation note IPAddress(uint32_t address); + // Default IPv4 IPAddress(const uint8_t *address); - IPAddress(IPType ip_type, const uint8_t *address); + IPAddress(IPType ip_type, const uint8_t *address, uint8_t z=0); // If IPv4 fails tries IPv6 see fromString function IPAddress(const char *address); - virtual ~IPAddress() {} + IPAddress(const IPAddress& address); bool fromString(const char *address); bool fromString(const String &address) { return fromString(address.c_str()); } - // Overloaded cast operator to allow IPAddress objects to be used where a - // uint32_t is expected - operator uint32_t() const - { - return _type == IPv4 ? _address.dword[IPADDRESS_V4_DWORD_INDEX] : 0; - } + // Overloaded cast operator to allow IPAddress objects to be used where a uint32_t is expected + // NOTE: IPv4 only; see implementation note + operator uint32_t() const { return _type == IPv4 ? _address.dword[IPADDRESS_V4_DWORD_INDEX] : 0; }; bool operator==(const IPAddress& addr) const; + bool operator!=(const IPAddress& addr) const { return !(*this == addr); }; + + // NOTE: IPv4 only; we don't know the length of the pointer bool operator==(const uint8_t* addr) const; // Overloaded index operator to allow getting and setting individual octets of the address @@ -84,31 +85,35 @@ class IPAddress: public Printable uint8_t& operator[](int index); // Overloaded copy operators to allow initialisation of IPAddress objects from other types + // NOTE: IPv4 only IPAddress& operator=(const uint8_t *address); + // NOTE: IPv4 only; see implementation note IPAddress& operator=(uint32_t address); // If IPv4 fails tries IPv6 see fromString function IPAddress& operator=(const char *address); + IPAddress& operator=(const IPAddress& address); virtual size_t printTo(Print& p) const; - String toString() const; + String toString(bool includeZone = false) const; IPType type() const { return _type; } - friend class EthernetClass; + // Espresif LwIP conversions + IPAddress(const ip_addr_t *addr); + void to_ip_addr_t(ip_addr_t* addr) const; + IPAddress& from_ip_addr_t(const ip_addr_t* addr); + esp_ip6_addr_type_t addr_type() const; + uint8_t zone() const { return (type() == IPv6)?_zone:0; } + size_t printTo(Print& p, bool includeZone) const; + friend class UDP; friend class Client; friend class Server; - friend class DhcpClass; - friend class DNSClient; protected: bool fromString4(const char *address); bool fromString6(const char *address); - String toString4() const; - String toString6() const; }; -// changed to extern because const declaration creates copies in BSS of INADDR_NONE for each CPP unit that includes it -extern IPAddress INADDR_NONE; -extern IPAddress IN6ADDR_ANY; -#endif +extern const IPAddress IN6ADDR_ANY; +extern const IPAddress INADDR_NONE; diff --git a/cores/esp32/IPv6Address.cpp b/cores/esp32/IPv6Address.cpp deleted file mode 100644 index 7d3c0de5f53..00000000000 --- a/cores/esp32/IPv6Address.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - IPv6Address.cpp - Base class that provides IPv6Address - Copyright (c) 2011 Adrian McEwen. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include - -IPv6Address::IPv6Address() -{ - memset(_address.bytes, 0, sizeof(_address.bytes)); -} - -IPv6Address::IPv6Address(const uint8_t *address) -{ - memcpy(_address.bytes, address, sizeof(_address.bytes)); -} - -IPv6Address::IPv6Address(const uint32_t *address) -{ - memcpy(_address.bytes, (const uint8_t *)address, sizeof(_address.bytes)); -} - -IPv6Address& IPv6Address::operator=(const uint8_t *address) -{ - memcpy(_address.bytes, address, sizeof(_address.bytes)); - return *this; -} - -bool IPv6Address::operator==(const uint8_t* addr) const -{ - return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0; -} - -size_t IPv6Address::printTo(Print& p) const -{ - size_t n = 0; - for(int i = 0; i < 16; i+=2) { - if(i){ - n += p.print(':'); - } - n += p.printf("%02x", _address.bytes[i]); - n += p.printf("%02x", _address.bytes[i+1]); - - } - return n; -} - -String IPv6Address::toString() const -{ - char szRet[40]; - sprintf(szRet,"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", - _address.bytes[0], _address.bytes[1], _address.bytes[2], _address.bytes[3], - _address.bytes[4], _address.bytes[5], _address.bytes[6], _address.bytes[7], - _address.bytes[8], _address.bytes[9], _address.bytes[10], _address.bytes[11], - _address.bytes[12], _address.bytes[13], _address.bytes[14], _address.bytes[15]); - return String(szRet); -} - -bool IPv6Address::fromString(const char *address) -{ - //format 0011:2233:4455:6677:8899:aabb:ccdd:eeff - if(strlen(address) != 39){ - return false; - } - char * pos = (char *)address; - size_t i = 0; - for(i = 0; i < 16; i+=2) { - if(!sscanf(pos, "%2hhx", &_address.bytes[i]) || !sscanf(pos+2, "%2hhx", &_address.bytes[i+1])){ - return false; - } - pos += 5; - } - return true; -} diff --git a/cores/esp32/IPv6Address.h b/cores/esp32/IPv6Address.h deleted file mode 100644 index e61d0e7b371..00000000000 --- a/cores/esp32/IPv6Address.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - IPv6Address.h - Base class that provides IPv6Address - Copyright (c) 2011 Adrian McEwen. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef IPv6Address_h -#define IPv6Address_h - -#include -#include -#include - -// A class to make it easier to handle and pass around IP addresses - -class IPv6Address: public Printable -{ -private: - union { - uint8_t bytes[16]; // IPv4 address - uint32_t dword[4]; - } _address; - - // Access the raw byte array containing the address. Because this returns a pointer - // to the internal structure rather than a copy of the address this function should only - // be used when you know that the usage of the returned uint8_t* will be transient and not - // stored. - uint8_t* raw_address() - { - return _address.bytes; - } - -public: - // Constructors - IPv6Address(); - IPv6Address(const uint8_t *address); - IPv6Address(const uint32_t *address); - virtual ~IPv6Address() {} - - bool fromString(const char *address); - bool fromString(const String &address) { return fromString(address.c_str()); } - - operator const uint8_t*() const - { - return _address.bytes; - } - operator const uint32_t*() const - { - return _address.dword; - } - bool operator==(const IPv6Address& addr) const - { - return (_address.dword[0] == addr._address.dword[0]) - && (_address.dword[1] == addr._address.dword[1]) - && (_address.dword[2] == addr._address.dword[2]) - && (_address.dword[3] == addr._address.dword[3]); - } - bool operator==(const uint8_t* addr) const; - - // Overloaded index operator to allow getting and setting individual octets of the address - uint8_t operator[](int index) const - { - return _address.bytes[index]; - } - uint8_t& operator[](int index) - { - return _address.bytes[index]; - } - - // Overloaded copy operators to allow initialisation of IPv6Address objects from other types - IPv6Address& operator=(const uint8_t *address); - - virtual size_t printTo(Print& p) const; - String toString() const; - - friend class UDP; - friend class Client; - friend class Server; -}; - -#endif diff --git a/cores/esp32/StreamString.h b/cores/esp32/StreamString.h index dbdf3fb0097..fa983786c70 100644 --- a/cores/esp32/StreamString.h +++ b/cores/esp32/StreamString.h @@ -21,7 +21,8 @@ #ifndef STREAMSTRING_H_ #define STREAMSTRING_H_ - +#include "Stream.h" +#include "WString.h" class StreamString: public Stream, public String { diff --git a/docs/en/api/wifi.rst b/docs/en/api/wifi.rst index d7bb60cce7c..010a11cfc1c 100644 --- a/docs/en/api/wifi.rst +++ b/docs/en/api/wifi.rst @@ -327,14 +327,14 @@ Get the softAP subnet mask. IPAddress softAPSubnetMask(); -softAPenableIpV6 +softAPenableIPv6 **************** Function used to enable the IPv6 support. .. code-block:: arduino - bool softAPenableIpV6(); + bool softAPenableIPv6(bool enable=true); The function will return ``true`` if the configuration is successful. @@ -345,9 +345,9 @@ Function to get the IPv6 address. .. code-block:: arduino - IPv6Address softAPIPv6(); + IPAddress softAPIPv6(); -The function will return the AP IPv6 address in ``IPv6Address`` format. +The function will return the AP IPv6 address in ``IPAddress`` format. softAPgetHostname ***************** diff --git a/libraries/AsyncUDP/src/AsyncUDP.cpp b/libraries/AsyncUDP/src/AsyncUDP.cpp index e533755da7a..1c650f1a721 100644 --- a/libraries/AsyncUDP/src/AsyncUDP.cpp +++ b/libraries/AsyncUDP/src/AsyncUDP.cpp @@ -424,12 +424,12 @@ IPAddress AsyncUDPPacket::localIP() return IPAddress(_localIp.u_addr.ip4.addr); } -IPv6Address AsyncUDPPacket::localIPv6() +IPAddress AsyncUDPPacket::localIPv6() { if(_localIp.type != IPADDR_TYPE_V6){ - return IPv6Address(); + return IPAddress(IPv6); } - return IPv6Address(_localIp.u_addr.ip6.addr); + return IPAddress(IPv6, (const uint8_t *)_localIp.u_addr.ip6.addr, _localIp.u_addr.ip6.zone); } uint16_t AsyncUDPPacket::localPort() @@ -445,12 +445,12 @@ IPAddress AsyncUDPPacket::remoteIP() return IPAddress(_remoteIp.u_addr.ip4.addr); } -IPv6Address AsyncUDPPacket::remoteIPv6() +IPAddress AsyncUDPPacket::remoteIPv6() { if(_remoteIp.type != IPADDR_TYPE_V6){ - return IPv6Address(); + return IPAddress(IPv6); } - return IPv6Address(_remoteIp.u_addr.ip6.addr); + return IPAddress(IPv6, (const uint8_t *)_remoteIp.u_addr.ip6.addr, _remoteIp.u_addr.ip6.zone); } uint16_t AsyncUDPPacket::remotePort() @@ -739,32 +739,28 @@ bool AsyncUDP::listen(uint16_t port) bool AsyncUDP::listen(const IPAddress addr, uint16_t port) { ip_addr_t laddr; - laddr.type = IPADDR_TYPE_V4; - laddr.u_addr.ip4.addr = addr; + addr.to_ip_addr_t(&laddr); return listen(&laddr, port); } bool AsyncUDP::listenMulticast(const IPAddress addr, uint16_t port, uint8_t ttl, tcpip_adapter_if_t tcpip_if) { ip_addr_t laddr; - laddr.type = IPADDR_TYPE_V4; - laddr.u_addr.ip4.addr = addr; + addr.to_ip_addr_t(&laddr); return listenMulticast(&laddr, port, ttl, tcpip_if); } bool AsyncUDP::connect(const IPAddress addr, uint16_t port) { ip_addr_t daddr; - daddr.type = IPADDR_TYPE_V4; - daddr.u_addr.ip4.addr = addr; + addr.to_ip_addr_t(&daddr); return connect(&daddr, port); } size_t AsyncUDP::writeTo(const uint8_t *data, size_t len, const IPAddress addr, uint16_t port, tcpip_adapter_if_t tcpip_if) { ip_addr_t daddr; - daddr.type = IPADDR_TYPE_V4; - daddr.u_addr.ip4.addr = addr; + addr.to_ip_addr_t(&daddr); return writeTo(data, len, &daddr, port, tcpip_if); } @@ -776,44 +772,12 @@ IPAddress AsyncUDP::listenIP() return IPAddress(_pcb->remote_ip.u_addr.ip4.addr); } -bool AsyncUDP::listen(const IPv6Address addr, uint16_t port) -{ - ip_addr_t laddr; - laddr.type = IPADDR_TYPE_V6; - memcpy((uint8_t*)(laddr.u_addr.ip6.addr), (const uint8_t*)addr, 16); - return listen(&laddr, port); -} - -bool AsyncUDP::listenMulticast(const IPv6Address addr, uint16_t port, uint8_t ttl, tcpip_adapter_if_t tcpip_if) -{ - ip_addr_t laddr; - laddr.type = IPADDR_TYPE_V6; - memcpy((uint8_t*)(laddr.u_addr.ip6.addr), (const uint8_t*)addr, 16); - return listenMulticast(&laddr, port, ttl, tcpip_if); -} - -bool AsyncUDP::connect(const IPv6Address addr, uint16_t port) -{ - ip_addr_t daddr; - daddr.type = IPADDR_TYPE_V6; - memcpy((uint8_t*)(daddr.u_addr.ip6.addr), (const uint8_t*)addr, 16); - return connect(&daddr, port); -} - -size_t AsyncUDP::writeTo(const uint8_t *data, size_t len, const IPv6Address addr, uint16_t port, tcpip_adapter_if_t tcpip_if) -{ - ip_addr_t daddr; - daddr.type = IPADDR_TYPE_V6; - memcpy((uint8_t*)(daddr.u_addr.ip6.addr), (const uint8_t*)addr, 16); - return writeTo(data, len, &daddr, port, tcpip_if); -} - -IPv6Address AsyncUDP::listenIPv6() +IPAddress AsyncUDP::listenIPv6() { if(!_pcb || _pcb->remote_ip.type != IPADDR_TYPE_V6){ - return IPv6Address(); + return IPAddress(IPv6); } - return IPv6Address(_pcb->remote_ip.u_addr.ip6.addr); + return IPAddress(IPv6, (const uint8_t *)_pcb->remote_ip.u_addr.ip6.addr, _pcb->remote_ip.u_addr.ip6.zone); } size_t AsyncUDP::write(const uint8_t *data, size_t len) @@ -866,14 +830,6 @@ size_t AsyncUDP::sendTo(AsyncUDPMessage &message, const IPAddress addr, uint16_t return writeTo(message.data(), message.length(), addr, port, tcpip_if); } -size_t AsyncUDP::sendTo(AsyncUDPMessage &message, const IPv6Address addr, uint16_t port, tcpip_adapter_if_t tcpip_if) -{ - if(!message) { - return 0; - } - return writeTo(message.data(), message.length(), addr, port, tcpip_if); -} - size_t AsyncUDP::send(AsyncUDPMessage &message) { if(!message) { diff --git a/libraries/AsyncUDP/src/AsyncUDP.h b/libraries/AsyncUDP/src/AsyncUDP.h index c9f365d1197..31d075191df 100644 --- a/libraries/AsyncUDP/src/AsyncUDP.h +++ b/libraries/AsyncUDP/src/AsyncUDP.h @@ -2,7 +2,6 @@ #define ESPASYNCUDP_H #include "IPAddress.h" -#include "IPv6Address.h" #include "Print.h" #include "Stream.h" #include @@ -81,10 +80,10 @@ class AsyncUDPPacket : public Stream tcpip_adapter_if_t interface(); IPAddress localIP(); - IPv6Address localIPv6(); + IPAddress localIPv6(); uint16_t localPort(); IPAddress remoteIP(); - IPv6Address remoteIPv6(); + IPAddress remoteIPv6(); uint16_t remotePort(); void remoteMac(uint8_t * mac); @@ -121,22 +120,18 @@ class AsyncUDP : public Print bool listen(const ip_addr_t *addr, uint16_t port); bool listen(const IPAddress addr, uint16_t port); - bool listen(const IPv6Address addr, uint16_t port); bool listen(uint16_t port); bool listenMulticast(const ip_addr_t *addr, uint16_t port, uint8_t ttl=1, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); bool listenMulticast(const IPAddress addr, uint16_t port, uint8_t ttl=1, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); - bool listenMulticast(const IPv6Address addr, uint16_t port, uint8_t ttl=1, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); bool connect(const ip_addr_t *addr, uint16_t port); bool connect(const IPAddress addr, uint16_t port); - bool connect(const IPv6Address addr, uint16_t port); void close(); size_t writeTo(const uint8_t *data, size_t len, const ip_addr_t *addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); size_t writeTo(const uint8_t *data, size_t len, const IPAddress addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); - size_t writeTo(const uint8_t *data, size_t len, const IPv6Address addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); size_t write(const uint8_t *data, size_t len); size_t write(uint8_t data); @@ -147,14 +142,13 @@ class AsyncUDP : public Print size_t sendTo(AsyncUDPMessage &message, const ip_addr_t *addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); size_t sendTo(AsyncUDPMessage &message, const IPAddress addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); - size_t sendTo(AsyncUDPMessage &message, const IPv6Address addr, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); size_t send(AsyncUDPMessage &message); size_t broadcastTo(AsyncUDPMessage &message, uint16_t port, tcpip_adapter_if_t tcpip_if=TCPIP_ADAPTER_IF_MAX); size_t broadcast(AsyncUDPMessage &message); IPAddress listenIP(); - IPv6Address listenIPv6(); + IPAddress listenIPv6(); bool connected(); esp_err_t lastErr(); operator bool(); diff --git a/libraries/ESPmDNS/examples/mDNS-SD_Extended/mDNS-SD_Extended.ino b/libraries/ESPmDNS/examples/mDNS-SD_Extended/mDNS-SD_Extended.ino index 6f2dfddfb3b..9e582b3236a 100644 --- a/libraries/ESPmDNS/examples/mDNS-SD_Extended/mDNS-SD_Extended.ino +++ b/libraries/ESPmDNS/examples/mDNS-SD_Extended/mDNS-SD_Extended.ino @@ -70,7 +70,7 @@ void browseService(const char * service, const char * proto){ Serial.print(": "); Serial.print(MDNS.hostname(i)); Serial.print(" ("); - Serial.print(MDNS.IP(i)); + Serial.print(MDNS.address(i)); Serial.print(":"); Serial.print(MDNS.port(i)); Serial.println(")"); diff --git a/libraries/ESPmDNS/src/ESPmDNS.cpp b/libraries/ESPmDNS/src/ESPmDNS.cpp index bccc4de5758..21d93aa4e2a 100644 --- a/libraries/ESPmDNS/src/ESPmDNS.cpp +++ b/libraries/ESPmDNS/src/ESPmDNS.cpp @@ -265,7 +265,7 @@ String MDNSResponder::hostname(int idx) { return String(result->hostname); } -IPAddress MDNSResponder::IP(int idx) { +IPAddress MDNSResponder::address(int idx) { mdns_result_t * result = _getResult(idx); if(!result){ log_e("Result %d not found", idx); @@ -281,20 +281,20 @@ IPAddress MDNSResponder::IP(int idx) { return IPAddress(); } -IPv6Address MDNSResponder::IPv6(int idx) { +IPAddress MDNSResponder::addressV6(int idx) { mdns_result_t * result = _getResult(idx); if(!result){ log_e("Result %d not found", idx); - return IPv6Address(); + return IPAddress(IPv6); } mdns_ip_addr_t * addr = result->addr; while(addr){ if(addr->addr.type == MDNS_IP_PROTOCOL_V6){ - return IPv6Address(addr->addr.u_addr.ip6.addr); + return IPAddress(IPv6, (const uint8_t *)addr->addr.u_addr.ip6.addr, addr->addr.u_addr.ip6.zone); } addr = addr->next; } - return IPv6Address(); + return IPAddress(IPv6); } uint16_t MDNSResponder::port(int idx) { diff --git a/libraries/ESPmDNS/src/ESPmDNS.h b/libraries/ESPmDNS/src/ESPmDNS.h index 6a5cb56ffba..01ca7518d2f 100644 --- a/libraries/ESPmDNS/src/ESPmDNS.h +++ b/libraries/ESPmDNS/src/ESPmDNS.h @@ -42,7 +42,6 @@ License (MIT license): #define ESP32MDNS_H #include "Arduino.h" -#include "IPv6Address.h" #include "mdns.h" #include "esp_interface.h" @@ -108,8 +107,8 @@ class MDNSResponder { } String hostname(int idx); - IPAddress IP(int idx); - IPv6Address IPv6(int idx); + IPAddress address(int idx); + IPAddress addressV6(int idx); uint16_t port(int idx); int numTxt(int idx); bool hasTxt(int idx, const char * key); diff --git a/libraries/Ethernet/src/ETH.cpp b/libraries/Ethernet/src/ETH.cpp index 40c408ee69a..92d91b40a1a 100644 --- a/libraries/Ethernet/src/ETH.cpp +++ b/libraries/Ethernet/src/ETH.cpp @@ -401,13 +401,13 @@ bool ETHClass::beginSPI(eth_phy_type_t type, uint8_t phy_addr, int cs, int irq, // Init SPI bus if(_pin_sck >= 0 && _pin_miso >= 0 && _pin_mosi >= 0){ - spi_bus_config_t buscfg = { - .mosi_io_num = _pin_mosi, - .miso_io_num = _pin_miso, - .sclk_io_num = _pin_sck, - .quadwp_io_num = -1, - .quadhd_io_num = -1, - }; + spi_bus_config_t buscfg; + memset(&buscfg, 0, sizeof(spi_bus_config_t)); + buscfg.mosi_io_num = _pin_mosi; + buscfg.miso_io_num = _pin_miso; + buscfg.sclk_io_num = _pin_sck; + buscfg.quadwp_io_num = -1; + buscfg.quadhd_io_num = -1; ret = spi_bus_initialize(spi_host, &buscfg, SPI_DMA_CH_AUTO); if(ret != ESP_OK){ log_e("SPI bus initialize failed: %d", ret); @@ -433,13 +433,13 @@ bool ETHClass::beginSPI(eth_phy_type_t type, uint8_t phy_addr, int cs, int irq, phy_config.reset_gpio_num = _pin_rst; // Configure SPI interface for specific SPI module - spi_device_interface_config_t spi_devcfg = { - .mode = 0, - .clock_speed_hz = _spi_freq_mhz * 1000 * 1000, - .input_delay_ns = 20, - .spics_io_num = _pin_cs, - .queue_size = 20, - }; + spi_device_interface_config_t spi_devcfg; + memset(&spi_devcfg, 0, sizeof(spi_device_interface_config_t)); + spi_devcfg.mode = 0; + spi_devcfg.clock_speed_hz = _spi_freq_mhz * 1000 * 1000; + spi_devcfg.input_delay_ns = 20; + spi_devcfg.spics_io_num = _pin_cs; + spi_devcfg.queue_size = 20; esp_eth_mac_t *mac = NULL; esp_eth_phy_t *phy = NULL; @@ -861,24 +861,42 @@ bool ETHClass::setHostname(const char * hostname) return esp_netif_set_hostname(_esp_netif, hostname) == 0; } -bool ETHClass::enableIpV6() +bool ETHClass::enableIPv6(bool en) { - if(_esp_netif == NULL){ - return false; + // if(_esp_netif == NULL){ + // return false; + // } + // return esp_netif_create_ip6_linklocal(_esp_netif) == 0; + if (en) { + WiFiGenericClass::setStatusBits(ETH_WANT_IP6_BIT); + } else { + WiFiGenericClass::clearStatusBits(ETH_WANT_IP6_BIT); } - return esp_netif_create_ip6_linklocal(_esp_netif) == 0; + return true; } -IPv6Address ETHClass::localIPv6() +IPAddress ETHClass::localIPv6() { if(_esp_netif == NULL){ - return IPv6Address(); + return IPAddress(IPv6); } static esp_ip6_addr_t addr; if(esp_netif_get_ip6_linklocal(_esp_netif, &addr)){ - return IPv6Address(); + return IPAddress(IPv6); + } + return IPAddress(IPv6, (const uint8_t *)addr.addr, addr.zone); +} + +IPAddress ETHClass::globalIPv6() +{ + if(_esp_netif == NULL){ + return IPAddress(IPv6); } - return IPv6Address(addr.addr); + 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); } const char * ETHClass::ifkey(void) @@ -1031,6 +1049,28 @@ void ETHClass::printInfo(Print & out){ out.print(dnsIP()); 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){ + out.print(" "); + out.print("inet6 "); + IPAddress(IPv6, (const uint8_t *)if_ip6[i].addr, if_ip6[i].zone).printTo(out, true); + out.print(" type "); + out.print(types[esp_netif_ip6_get_addr_type(&if_ip6[i])]); + out.println(); + } + + // out.print(" "); + // out.print("inet6 "); + // localIPv6().printTo(out); + // out.println(); + + // out.print(" "); + // out.print("inet6 "); + // globalIPv6().printTo(out); + // out.println(); + out.println(); } diff --git a/libraries/Ethernet/src/ETH.h b/libraries/Ethernet/src/ETH.h index 7ef39ef561f..7159ebd4574 100644 --- a/libraries/Ethernet/src/ETH.h +++ b/libraries/Ethernet/src/ETH.h @@ -145,8 +145,9 @@ class ETHClass { IPAddress broadcastIP(); IPAddress networkID(); uint8_t subnetCIDR(); - bool enableIpV6(); - IPv6Address localIPv6(); + bool enableIPv6(bool en=true); + IPAddress localIPv6(); + IPAddress globalIPv6(); const char * ifkey(void); const char * desc(void); String impl_name(void); diff --git a/libraries/WiFi/examples/WiFiBlueToothSwitch/WiFiBlueToothSwitch.ino b/libraries/WiFi/examples/WiFiBlueToothSwitch/WiFiBlueToothSwitch.ino index 771a531a480..be9aa239627 100644 --- a/libraries/WiFi/examples/WiFiBlueToothSwitch/WiFiBlueToothSwitch.ino +++ b/libraries/WiFi/examples/WiFiBlueToothSwitch/WiFiBlueToothSwitch.ino @@ -89,7 +89,6 @@ void WiFiEvent(WiFiEvent_t event){ break; case ARDUINO_EVENT_WIFI_STA_CONNECTED: Serial.println("STA Connected"); - WiFi.enableIpV6(); break; case ARDUINO_EVENT_WIFI_STA_GOT_IP6: Serial.print("STA IPv6: "); @@ -114,6 +113,7 @@ void setup() { Serial.begin(115200); pinMode(0, INPUT_PULLUP); WiFi.onEvent(WiFiEvent); // Will call WiFiEvent() from another thread. + WiFi.enableIPv6(); Serial.print("ESP32 SDK: "); Serial.println(ESP.getSdkVersion()); Serial.println("Press the button to select the next mode"); diff --git a/libraries/WiFi/examples/WiFiIPv6/WiFiIPv6.ino b/libraries/WiFi/examples/WiFiIPv6/WiFiIPv6.ino index 3dcba56eec2..c7edd384d82 100644 --- a/libraries/WiFi/examples/WiFiIPv6/WiFiIPv6.ino +++ b/libraries/WiFi/examples/WiFiIPv6/WiFiIPv6.ino @@ -70,16 +70,12 @@ void WiFiEvent(WiFiEvent_t event){ case ARDUINO_EVENT_WIFI_AP_START: //can set ap hostname here WiFi.softAPsetHostname(AP_SSID); - //enable ap ipv6 here - WiFi.softAPenableIpV6(); break; case ARDUINO_EVENT_WIFI_STA_START: //set sta hostname here WiFi.setHostname(AP_SSID); break; case ARDUINO_EVENT_WIFI_STA_CONNECTED: - //enable sta ipv6 here - WiFi.enableIpV6(); break; case ARDUINO_EVENT_WIFI_STA_GOT_IP6: Serial.print("STA IPv6: "); @@ -107,7 +103,11 @@ void setup(){ WiFi.disconnect(true); WiFi.onEvent(WiFiEvent); // Will call WiFiEvent() from another thread. WiFi.mode(WIFI_MODE_APSTA); + //enable ap ipv6 here + WiFi.softAPenableIPv6(); WiFi.softAP(AP_SSID); + //enable sta ipv6 here + WiFi.enableIPv6(); WiFi.begin(STA_SSID, STA_PASS); } diff --git a/libraries/WiFi/src/WiFi.h b/libraries/WiFi/src/WiFi.h index 457f913ae8e..30b9e31f744 100644 --- a/libraries/WiFi/src/WiFi.h +++ b/libraries/WiFi/src/WiFi.h @@ -26,7 +26,6 @@ #include "Print.h" #include "IPAddress.h" -#include "IPv6Address.h" #include "WiFiType.h" #include "WiFiSTA.h" diff --git a/libraries/WiFi/src/WiFiAP.cpp b/libraries/WiFi/src/WiFiAP.cpp index a88547f9a89..b02b929bce9 100644 --- a/libraries/WiFi/src/WiFiAP.cpp +++ b/libraries/WiFi/src/WiFiAP.cpp @@ -411,26 +411,35 @@ bool WiFiAPClass::softAPsetHostname(const char * hostname) * Enable IPv6 on the softAP interface. * @return true on success */ -bool WiFiAPClass::softAPenableIpV6() +bool WiFiAPClass::softAPenableIPv6(bool enable) { - if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){ - return false; + if (enable) { + WiFiGenericClass::setStatusBits(AP_WANT_IP6_BIT); + } else { + WiFiGenericClass::clearStatusBits(AP_WANT_IP6_BIT); } - return esp_netif_create_ip6_linklocal(get_esp_interface_netif(ESP_IF_WIFI_AP)) == ESP_OK; + return true; + // if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){ + // return false; + // } + // return esp_netif_create_ip6_linklocal(get_esp_interface_netif(ESP_IF_WIFI_AP)) == ESP_OK; } /** * Get the softAP interface IPv6 address. - * @return IPv6Address softAP IPv6 + * @return IPAddress softAP IPv6 */ -IPv6Address WiFiAPClass::softAPIPv6() + +IPAddress WiFiAPClass::softAPIPv6() { - esp_ip6_addr_t addr; + static esp_ip6_addr_t addr; if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){ - return IPv6Address(); + return IPAddress(IPv6); } - if(esp_netif_get_ip6_linklocal(get_esp_interface_netif(ESP_IF_WIFI_AP), &addr)) { - return IPv6Address(); + + if(esp_netif_get_ip6_linklocal(get_esp_interface_netif(ESP_IF_WIFI_STA), &addr)){ + return IPAddress(IPv6); } - return IPv6Address(addr.addr); + return IPAddress(IPv6, (const uint8_t *)addr.addr, addr.zone); } + diff --git a/libraries/WiFi/src/WiFiAP.h b/libraries/WiFi/src/WiFiAP.h index 626a5b5b350..a07fab54335 100644 --- a/libraries/WiFi/src/WiFiAP.h +++ b/libraries/WiFi/src/WiFiAP.h @@ -56,8 +56,8 @@ class WiFiAPClass IPAddress softAPSubnetMask(); uint8_t softAPSubnetCIDR(); - bool softAPenableIpV6(); - IPv6Address softAPIPv6(); + bool softAPenableIPv6(bool enable=true); + IPAddress softAPIPv6(); const char * softAPgetHostname(); bool softAPsetHostname(const char * hostname); diff --git a/libraries/WiFi/src/WiFiClient.cpp b/libraries/WiFi/src/WiFiClient.cpp index 864c33322f3..4127bcad3de 100644 --- a/libraries/WiFi/src/WiFiClient.cpp +++ b/libraries/WiFi/src/WiFiClient.cpp @@ -23,6 +23,11 @@ #include #include +#define IN6_IS_ADDR_V4MAPPED(a) \ + ((((__const uint32_t *) (a))[0] == 0) \ + && (((__const uint32_t *) (a))[1] == 0) \ + && (((__const uint32_t *) (a))[2] == htonl (0xffff))) + #define WIFI_CLIENT_DEF_CONN_TIMEOUT_MS (3000) #define WIFI_CLIENT_MAX_WRITE_RETRY (10) #define WIFI_CLIENT_SELECT_TIMEOUT_US (1000000) @@ -219,22 +224,33 @@ int WiFiClient::connect(IPAddress ip, uint16_t port) { return connect(ip,port,_timeout); } + int WiFiClient::connect(IPAddress ip, uint16_t port, int32_t timeout_ms) { + struct sockaddr_storage serveraddr = {}; _timeout = timeout_ms; - int sockfd = socket(AF_INET, SOCK_STREAM, 0); + int sockfd = -1; + + if (ip.type() == IPv6) { + struct sockaddr_in6 *tmpaddr = (struct sockaddr_in6 *)&serveraddr; + sockfd = socket(AF_INET6, SOCK_STREAM, 0); + tmpaddr->sin6_family = AF_INET6; + memcpy(tmpaddr->sin6_addr.un.u8_addr, &ip[0], 16); + tmpaddr->sin6_port = htons(port); + tmpaddr->sin6_scope_id = ip.zone(); + } else { + struct sockaddr_in *tmpaddr = (struct sockaddr_in *)&serveraddr; + sockfd = socket(AF_INET, SOCK_STREAM, 0); + tmpaddr->sin_family = AF_INET; + tmpaddr->sin_addr.s_addr = ip; + tmpaddr->sin_port = htons(port); + } if (sockfd < 0) { log_e("socket: %d", errno); return 0; } fcntl( sockfd, F_SETFL, fcntl( sockfd, F_GETFL, 0 ) | O_NONBLOCK ); - uint32_t ip_addr = ip; - struct sockaddr_in serveraddr; - memset((char *) &serveraddr, 0, sizeof(serveraddr)); - serveraddr.sin_family = AF_INET; - memcpy((void *)&serveraddr.sin_addr.s_addr, (const void *)(&ip_addr), 4); - serveraddr.sin_port = htons(port); fd_set fdset; struct timeval tv; FD_ZERO(&fdset); @@ -574,8 +590,24 @@ IPAddress WiFiClient::remoteIP(int fd) const struct sockaddr_storage addr; socklen_t len = sizeof addr; getpeername(fd, (struct sockaddr*)&addr, &len); - struct sockaddr_in *s = (struct sockaddr_in *)&addr; - return IPAddress((uint32_t)(s->sin_addr.s_addr)); + + // IPv4 socket, old way + if (((struct sockaddr*)&addr)->sa_family == AF_INET) { + struct sockaddr_in *s = (struct sockaddr_in *)&addr; + return IPAddress((uint32_t)(s->sin_addr.s_addr)); + } + + // IPv6, but it might be IPv4 mapped address + if (((struct sockaddr*)&addr)->sa_family == AF_INET6) { + struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)&addr; + if (IN6_IS_ADDR_V4MAPPED(saddr6->sin6_addr.un.u32_addr)) { + return IPAddress(IPv4, (uint8_t*)saddr6->sin6_addr.s6_addr+IPADDRESS_V4_BYTES_INDEX); + } else { + return IPAddress(IPv6, (uint8_t*)(saddr6->sin6_addr.s6_addr), saddr6->sin6_scope_id); + } + } + log_e("WiFiClient::remoteIP Not AF_INET or AF_INET6?"); + return (IPAddress(0,0,0,0)); } uint16_t WiFiClient::remotePort(int fd) const @@ -638,4 +670,3 @@ int WiFiClient::fd() const return clientSocketHandle->fd(); } } - diff --git a/libraries/WiFi/src/WiFiGeneric.cpp b/libraries/WiFi/src/WiFiGeneric.cpp index 8ef803064c4..2fade00e450 100644 --- a/libraries/WiFi/src/WiFiGeneric.cpp +++ b/libraries/WiFi/src/WiFiGeneric.cpp @@ -42,6 +42,7 @@ extern "C" { #include "lwip/opt.h" #include "lwip/err.h" #include "lwip/dns.h" +#include "lwip/netif.h" #include "dhcpserver/dhcpserver.h" #include "dhcpserver/dhcpserver_options.h" @@ -191,16 +192,17 @@ esp_err_t set_esp_interface_ip(esp_interface_t interface, IPAddress local_ip=IPA 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_SUBNET_MASK, - (void*)&info.netmask.addr, sizeof(info.netmask.addr) - ); - if(err){ - log_e("DHCPS Set Netmask Failed! 0x%04x", err); - return err; - } + // Following block is commented because it breaks AP DHCPS on recent ESP-IDF + // err = esp_netif_dhcps_option( + // esp_netif, + // ESP_NETIF_OP_SET, + // ESP_NETIF_SUBNET_MASK, + // (void*)&info.netmask.addr, sizeof(info.netmask.addr) + // ); + // if(err){ + // log_e("DHCPS Set Netmask Failed! 0x%04x", err); + // return err; + // } err = esp_netif_dhcps_option( esp_netif, ESP_NETIF_OP_SET, @@ -459,7 +461,13 @@ static void _arduino_event_cb(void* arg, esp_event_base_t event_base, int32_t ev } else if (event_base == IP_EVENT && event_id == IP_EVENT_GOT_IP6) { ip_event_got_ip6_t * event = (ip_event_got_ip6_t*)event_data; esp_interface_t iface = get_esp_netif_interface(event->esp_netif); - log_v("IF[%d] Got IPv6: IP Index: %d, Zone: %d, " IPV6STR, iface, event->ip_index, event->ip6_info.ip.zone, IPV62STR(event->ip6_info.ip)); +#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); + esp_ip6_addr_type_t addr_type = esp_netif_ip6_get_addr_type(&event->ip6_info.ip); + 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, esp_netif_get_desc(event->esp_netif), iface, 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(iface == ESP_IF_WIFI_STA){ arduino_event.event_id = ARDUINO_EVENT_WIFI_STA_GOT_IP6; @@ -554,6 +562,8 @@ static void _arduino_event_cb(void* arg, esp_event_base_t event_base, int32_t ev } } +static uint32_t _initial_bits = NET_DNS_IDLE_BIT; + static bool _start_network_event_task(){ if(!_arduino_event_group){ _arduino_event_group = xEventGroupCreate(); @@ -561,7 +571,7 @@ static bool _start_network_event_task(){ log_e("Network Event Group Create Failed!"); return false; } - xEventGroupSetBits(_arduino_event_group, WIFI_DNS_IDLE_BIT); + xEventGroupSetBits(_arduino_event_group, _initial_bits); } if(!_arduino_event_queue){ _arduino_event_queue = xQueueCreate(32, sizeof(arduino_event_t*)); @@ -909,21 +919,23 @@ bool WiFiGenericClass::setHostname(const char * hostname) int WiFiGenericClass::setStatusBits(int bits){ if(!_arduino_event_group){ - return 0; + _initial_bits |= bits; + return _initial_bits; } return xEventGroupSetBits(_arduino_event_group, bits); } int WiFiGenericClass::clearStatusBits(int bits){ if(!_arduino_event_group){ - return 0; + _initial_bits &= ~bits; + return _initial_bits; } return xEventGroupClearBits(_arduino_event_group, bits); } int WiFiGenericClass::getStatusBits(){ if(!_arduino_event_group){ - return 0; + return _initial_bits; } return xEventGroupGetBits(_arduino_event_group); } @@ -1051,12 +1063,16 @@ esp_err_t WiFiGenericClass::_eventCallback(arduino_event_t *event) } } else if(event->event_id == ARDUINO_EVENT_WIFI_STA_STOP) { WiFiSTAClass::_setStatus(WL_STOPPED); - clearStatusBits(STA_STARTED_BIT | STA_CONNECTED_BIT | STA_HAS_IP_BIT | STA_HAS_IP6_BIT); + clearStatusBits(STA_STARTED_BIT | STA_CONNECTED_BIT | STA_HAS_IP_BIT | STA_HAS_IP6_BIT | STA_HAS_IP6_GLOBAL_BIT); } else if(event->event_id == ARDUINO_EVENT_WIFI_STA_CONNECTED) { + if (getStatusBits() & STA_WANT_IP6_BIT){ + esp_err_t err = esp_netif_create_ip6_linklocal(get_esp_interface_netif(ESP_IF_WIFI_STA)); + if(err != ESP_OK){ + log_e("Failed to enable IPv6 Link Local on STA: [%d] %s", err, esp_err_to_name(err)); + } + } WiFiSTAClass::_setStatus(WL_IDLE_STATUS); setStatusBits(STA_CONNECTED_BIT); - - //esp_netif_create_ip6_linklocal(esp_netifs[ESP_IF_WIFI_STA]); } else if(event->event_id == ARDUINO_EVENT_WIFI_STA_DISCONNECTED) { uint8_t reason = event->event_info.wifi_sta_disconnected.reason; // Reason 0 causes crash, use reason 1 (UNSPECIFIED) instead @@ -1074,7 +1090,7 @@ esp_err_t WiFiGenericClass::_eventCallback(arduino_event_t *event) } else { WiFiSTAClass::_setStatus(WL_DISCONNECTED); } - clearStatusBits(STA_CONNECTED_BIT | STA_HAS_IP_BIT | STA_HAS_IP6_BIT); + clearStatusBits(STA_CONNECTED_BIT | STA_HAS_IP_BIT | STA_HAS_IP6_BIT | STA_HAS_IP6_GLOBAL_BIT); bool DoReconnect = false; if(reason == WIFI_REASON_ASSOC_LEAVE) { //Voluntarily disconnected. Don't reconnect! @@ -1113,6 +1129,12 @@ esp_err_t WiFiGenericClass::_eventCallback(arduino_event_t *event) } else if(event->event_id == ARDUINO_EVENT_WIFI_AP_START) { setStatusBits(AP_STARTED_BIT); + if (getStatusBits() & AP_WANT_IP6_BIT){ + esp_err_t err = esp_netif_create_ip6_linklocal(get_esp_interface_netif(ESP_IF_WIFI_AP)); + if(err != ESP_OK){ + log_e("Failed to enable IPv6 Link Local on AP: [%d] %s", err, esp_err_to_name(err)); + } + } } else if(event->event_id == ARDUINO_EVENT_WIFI_AP_STOP) { clearStatusBits(AP_STARTED_BIT | AP_HAS_CLIENT_BIT); } else if(event->event_id == ARDUINO_EVENT_WIFI_AP_STACONNECTED) { @@ -1126,11 +1148,17 @@ esp_err_t WiFiGenericClass::_eventCallback(arduino_event_t *event) } else if(event->event_id == ARDUINO_EVENT_ETH_START) { setStatusBits(ETH_STARTED_BIT); } else if(event->event_id == ARDUINO_EVENT_ETH_STOP) { - clearStatusBits(ETH_STARTED_BIT | ETH_CONNECTED_BIT | ETH_HAS_IP_BIT | ETH_HAS_IP6_BIT); + clearStatusBits(ETH_STARTED_BIT | ETH_CONNECTED_BIT | ETH_HAS_IP_BIT | ETH_HAS_IP6_BIT | ETH_HAS_IP6_GLOBAL_BIT); } else if(event->event_id == ARDUINO_EVENT_ETH_CONNECTED) { + if (getStatusBits() & ETH_WANT_IP6_BIT){ + esp_err_t err = esp_netif_create_ip6_linklocal(get_esp_interface_netif(ESP_IF_ETH)); + if(err != ESP_OK){ + log_e("Failed to enable IPv6 Link Local on ETH: [%d] %s", err, esp_err_to_name(err)); + } + } setStatusBits(ETH_CONNECTED_BIT); } else if(event->event_id == ARDUINO_EVENT_ETH_DISCONNECTED) { - clearStatusBits(ETH_CONNECTED_BIT | ETH_HAS_IP_BIT | ETH_HAS_IP6_BIT); + clearStatusBits(ETH_CONNECTED_BIT | ETH_HAS_IP_BIT | ETH_HAS_IP6_BIT | ETH_HAS_IP6_GLOBAL_BIT); } else if(event->event_id == ARDUINO_EVENT_ETH_GOT_IP) { #if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG uint8_t * ip = (uint8_t *)&(event->event_info.got_ip.ip_info.ip.addr); @@ -1146,11 +1174,26 @@ esp_err_t WiFiGenericClass::_eventCallback(arduino_event_t *event) clearStatusBits(ETH_HAS_IP_BIT); } else if(event->event_id == ARDUINO_EVENT_WIFI_STA_GOT_IP6) { - setStatusBits(STA_CONNECTED_BIT | STA_HAS_IP6_BIT); + setStatusBits(STA_CONNECTED_BIT); + esp_ip6_addr_type_t addr_type = esp_netif_ip6_get_addr_type((esp_ip6_addr_t*)&(event->event_info.got_ip6.ip6_info.ip)); + if(addr_type == ESP_IP6_ADDR_IS_GLOBAL){ + setStatusBits(STA_HAS_IP6_GLOBAL_BIT); + } else if(addr_type == ESP_IP6_ADDR_IS_LINK_LOCAL){ + setStatusBits(STA_HAS_IP6_BIT); + } } else if(event->event_id == ARDUINO_EVENT_WIFI_AP_GOT_IP6) { - setStatusBits(AP_HAS_IP6_BIT); + esp_ip6_addr_type_t addr_type = esp_netif_ip6_get_addr_type((esp_ip6_addr_t*)&(event->event_info.got_ip6.ip6_info.ip)); + if(addr_type == ESP_IP6_ADDR_IS_LINK_LOCAL){ + setStatusBits(AP_HAS_IP6_BIT); + } } else if(event->event_id == ARDUINO_EVENT_ETH_GOT_IP6) { - setStatusBits(ETH_CONNECTED_BIT | ETH_HAS_IP6_BIT); + setStatusBits(ETH_CONNECTED_BIT); + esp_ip6_addr_type_t addr_type = esp_netif_ip6_get_addr_type((esp_ip6_addr_t*)&(event->event_info.got_ip6.ip6_info.ip)); + if(addr_type == ESP_IP6_ADDR_IS_GLOBAL){ + setStatusBits(ETH_HAS_IP6_GLOBAL_BIT); + } else if(addr_type == ESP_IP6_ADDR_IS_LINK_LOCAL){ + setStatusBits(ETH_HAS_IP6_BIT); + } } else if(event->event_id == ARDUINO_EVENT_SC_GOT_SSID_PSWD) { WiFi.begin( (const char *)event->event_info.sc_got_ssid_pswd.ssid, @@ -1546,6 +1589,13 @@ bool WiFiGenericClass::setDualAntennaConfig(uint8_t gpio_ant1, uint8_t gpio_ant2 // ------------------------------------------------ Generic Network function --------------------------------------------- // ----------------------------------------------------------------------------------------------------------------------- +typedef struct gethostbynameParameters { + const char *hostname; + ip_addr_t addr; + uint8_t addr_type; + int result; +} gethostbynameParameters_t; + /** * DNS callback * @param name @@ -1554,18 +1604,18 @@ bool WiFiGenericClass::setDualAntennaConfig(uint8_t gpio_ant1, uint8_t gpio_ant2 */ static void wifi_dns_found_callback(const char *name, const ip_addr_t *ipaddr, void *callback_arg) { + gethostbynameParameters_t *parameters = static_cast(callback_arg); if(ipaddr) { - (*reinterpret_cast(callback_arg)) = ipaddr->u_addr.ip4.addr; + if(parameters->result == 0){ + memcpy(&(parameters->addr), ipaddr, sizeof(ip_addr_t)); + parameters->result = 1; + } + } else { + parameters->result = -1; } - xEventGroupSetBits(_arduino_event_group, WIFI_DNS_DONE_BIT); + xEventGroupSetBits(_arduino_event_group, NET_DNS_DONE_BIT); } -typedef struct gethostbynameParameters { - const char *hostname; - ip_addr_t addr; - void *callback_arg; -} gethostbynameParameters_t; - /** * Callback to execute dns_gethostbyname in lwIP's TCP/IP context * @param param Parameters for dns_gethostbyname call @@ -1573,39 +1623,60 @@ typedef struct gethostbynameParameters { static esp_err_t wifi_gethostbyname_tcpip_ctx(void *param) { gethostbynameParameters_t *parameters = static_cast(param); - return dns_gethostbyname(parameters->hostname, ¶meters->addr, &wifi_dns_found_callback, parameters->callback_arg); + return dns_gethostbyname_addrtype(parameters->hostname, ¶meters->addr, &wifi_dns_found_callback, parameters, parameters->addr_type); } /** - * Resolve the given hostname to an IP address. If passed hostname is an IP address, it will be parsed into IPAddress structure. - * @param aHostname Name to be resolved or string containing IP address + * Resolve the given hostname to an IP address. + * @param aHostname Name to be resolved * @param aResult IPAddress structure to store the returned IP address * @return 1 if aIPAddrString was successfully converted to an IP address, * else error code */ -int WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult) +int WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult, bool preferV6) { - if (!aResult.fromString(aHostname)) - { - gethostbynameParameters_t params; - params.hostname = aHostname; - params.callback_arg = &aResult; - aResult = static_cast(0); - waitStatusBits(WIFI_DNS_IDLE_BIT, 16000); - clearStatusBits(WIFI_DNS_IDLE_BIT | WIFI_DNS_DONE_BIT); - err_t err = esp_netif_tcpip_exec(wifi_gethostbyname_tcpip_ctx, ¶ms); - if(err == ERR_OK && params.addr.u_addr.ip4.addr) { - aResult = params.addr.u_addr.ip4.addr; - } else if(err == ERR_INPROGRESS) { - waitStatusBits(WIFI_DNS_DONE_BIT, 15000); //real internal timeout in lwip library is 14[s] - clearStatusBits(WIFI_DNS_DONE_BIT); - } - setStatusBits(WIFI_DNS_IDLE_BIT); - if((uint32_t)aResult == 0){ - log_e("DNS Failed for %s", aHostname); + err_t err = ERR_OK; + gethostbynameParameters_t params; + + // This should generally check if we have a global address assigned to one of the interfaces. + // If such address is not assigned, there is no point in trying to get V6 from DNS as we will not be able to reach it. + // That is of course, if 'preferV6' is not set to true + static bool hasGlobalV6 = false; + bool hasGlobalV6Now = (getStatusBits() & NET_HAS_IP6_GLOBAL_BIT) != 0; + if(hasGlobalV6 != hasGlobalV6Now){ + hasGlobalV6 = hasGlobalV6Now; + dns_clear_cache(); + log_d("Clearing DNS cache"); + } + + aResult = static_cast(0); + params.hostname = aHostname; + params.addr_type = (preferV6 || hasGlobalV6)?LWIP_DNS_ADDRTYPE_IPV6_IPV4:LWIP_DNS_ADDRTYPE_IPV4; + params.result = 0; + aResult.to_ip_addr_t(&(params.addr)); + + if (!aResult.fromString(aHostname)) { + waitStatusBits(NET_DNS_IDLE_BIT, 16000); + clearStatusBits(NET_DNS_IDLE_BIT | NET_DNS_DONE_BIT); + + err = esp_netif_tcpip_exec(wifi_gethostbyname_tcpip_ctx, ¶ms); + if (err == ERR_OK) { + aResult.from_ip_addr_t(&(params.addr)); + } else if (err == ERR_INPROGRESS) { + waitStatusBits(NET_DNS_DONE_BIT, 15000); //real internal timeout in lwip library is 14[s] + clearStatusBits(NET_DNS_DONE_BIT); + if (params.result == 1) { + aResult.from_ip_addr_t(&(params.addr)); + err = ERR_OK; + } } + setStatusBits(NET_DNS_IDLE_BIT); + } + if (err == ERR_OK) { + return 1; } - return (uint32_t)aResult != 0; + log_e("DNS Failed for '%s' with error '%d' and result '%d'", aHostname, err, params.result); + return err; } IPAddress WiFiGenericClass::calculateNetworkID(IPAddress ip, IPAddress subnet) { diff --git a/libraries/WiFi/src/WiFiGeneric.h b/libraries/WiFi/src/WiFiGeneric.h index 38396f5a72e..3de43905416 100644 --- a/libraries/WiFi/src/WiFiGeneric.h +++ b/libraries/WiFi/src/WiFiGeneric.h @@ -32,6 +32,7 @@ #include "esp_netif_types.h" #include "esp_eth_driver.h" #include "wifi_provisioning/manager.h" +#include "lwip/ip_addr.h" ESP_EVENT_DECLARE_BASE(ARDUINO_EVENTS); @@ -111,6 +112,34 @@ typedef void (*WiFiEventSysCb)(arduino_event_t *event); typedef size_t wifi_event_id_t; +// General Flags +static const int NET_DNS_IDLE_BIT = BIT0; +static const int NET_DNS_DONE_BIT = BIT1; +// WiFi Scan Flags +static const int WIFI_SCANNING_BIT = BIT2; +static const int WIFI_SCAN_DONE_BIT = BIT3; +// AP Flags +static const int AP_STARTED_BIT = BIT4; +static const int AP_HAS_IP6_BIT = BIT5; +static const int AP_HAS_CLIENT_BIT = BIT6; +static const int AP_WANT_IP6_BIT = BIT7; +// STA Flags +static const int STA_STARTED_BIT = BIT8; +static const int STA_CONNECTED_BIT = BIT9; +static const int STA_HAS_IP_BIT = BIT10; +static const int STA_HAS_IP6_BIT = BIT11; +static const int STA_HAS_IP6_GLOBAL_BIT = BIT12; +static const int STA_WANT_IP6_BIT = BIT13; +// ETH Flags +static const int ETH_STARTED_BIT = BIT14; +static const int ETH_CONNECTED_BIT = BIT15; +static const int ETH_HAS_IP_BIT = BIT16; +static const int ETH_HAS_IP6_BIT = BIT17; +static const int ETH_HAS_IP6_GLOBAL_BIT = BIT18; +static const int ETH_WANT_IP6_BIT = BIT19; +// Masks +static const int NET_HAS_IP6_GLOBAL_BIT = STA_HAS_IP6_GLOBAL_BIT | ETH_HAS_IP6_GLOBAL_BIT; + typedef enum { WIFI_POWER_19_5dBm = 78,// 19.5dBm WIFI_POWER_19dBm = 76,// 19dBm @@ -126,22 +155,6 @@ typedef enum { WIFI_POWER_MINUS_1dBm = -4// -1dBm } wifi_power_t; -static const int AP_STARTED_BIT = BIT0; -static const int AP_HAS_IP6_BIT = BIT1; -static const int AP_HAS_CLIENT_BIT = BIT2; -static const int STA_STARTED_BIT = BIT3; -static const int STA_CONNECTED_BIT = BIT4; -static const int STA_HAS_IP_BIT = BIT5; -static const int STA_HAS_IP6_BIT = BIT6; -static const int ETH_STARTED_BIT = BIT7; -static const int ETH_CONNECTED_BIT = BIT8; -static const int ETH_HAS_IP_BIT = BIT9; -static const int ETH_HAS_IP6_BIT = BIT10; -static const int WIFI_SCANNING_BIT = BIT11; -static const int WIFI_SCAN_DONE_BIT= BIT12; -static const int WIFI_DNS_IDLE_BIT = BIT13; -static const int WIFI_DNS_DONE_BIT = BIT14; - typedef enum { WIFI_RX_ANT0 = 0, WIFI_RX_ANT1, @@ -216,7 +229,7 @@ class WiFiGenericClass static bool _isReconnectableReason(uint8_t reason); public: - static int hostByName(const char *aHostname, IPAddress &aResult); + static int hostByName(const char *aHostname, IPAddress &aResult, bool preferV6=false); static IPAddress calculateNetworkID(IPAddress ip, IPAddress subnet); static IPAddress calculateBroadcast(IPAddress ip, IPAddress subnet); @@ -226,6 +239,7 @@ class WiFiGenericClass friend class WiFiSTAClass; friend class WiFiScanClass; friend class WiFiAPClass; + friend class ETHClass; }; #endif /* ESP32WIFIGENERIC_H_ */ diff --git a/libraries/WiFi/src/WiFiMulti.cpp b/libraries/WiFi/src/WiFiMulti.cpp index 3d69e481293..22ec1ea46f9 100644 --- a/libraries/WiFi/src/WiFiMulti.cpp +++ b/libraries/WiFi/src/WiFiMulti.cpp @@ -30,6 +30,7 @@ WiFiMulti::WiFiMulti() { + ipv6_support = false; } WiFiMulti::~WiFiMulti() @@ -159,6 +160,9 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout) if(bestNetwork.ssid) { log_i("[WIFI] Connecting BSSID: %02X:%02X:%02X:%02X:%02X:%02X SSID: %s Channel: %d (%d)", bestBSSID[0], bestBSSID[1], bestBSSID[2], bestBSSID[3], bestBSSID[4], bestBSSID[5], bestNetwork.ssid, bestChannel, bestNetworkDb); + if (ipv6_support == true) { + WiFi.enableIPv6(); + } WiFi.begin(bestNetwork.ssid, bestNetwork.passphrase, bestChannel, bestBSSID); status = WiFi.status(); @@ -202,3 +206,7 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout) return status; } + +void WiFiMulti::enableIPv6(bool state) { + ipv6_support = state; +} diff --git a/libraries/WiFi/src/WiFiMulti.h b/libraries/WiFi/src/WiFiMulti.h index 38ddb5d9f95..d8551fab9dd 100644 --- a/libraries/WiFi/src/WiFiMulti.h +++ b/libraries/WiFi/src/WiFiMulti.h @@ -42,10 +42,12 @@ class WiFiMulti bool addAP(const char* ssid, const char *passphrase = NULL); + void enableIPv6(bool state); uint8_t run(uint32_t connectTimeout=5000); private: std::vector APlist; + bool ipv6_support; }; #endif /* WIFICLIENTMULTI_H_ */ diff --git a/libraries/WiFi/src/WiFiSTA.cpp b/libraries/WiFi/src/WiFiSTA.cpp index bf80d37393b..fab3bce6563 100644 --- a/libraries/WiFi/src/WiFiSTA.cpp +++ b/libraries/WiFi/src/WiFiSTA.cpp @@ -805,30 +805,50 @@ int8_t WiFiSTAClass::RSSI(void) /** * Enable IPv6 on the station interface. + * Should be called before WiFi.begin() + * * @return true on success */ -bool WiFiSTAClass::enableIpV6() +bool WiFiSTAClass::enableIPv6(bool en) { + if (en) { + WiFiGenericClass::setStatusBits(STA_WANT_IP6_BIT); + } else { + WiFiGenericClass::clearStatusBits(STA_WANT_IP6_BIT); + } + return true; +} + +/** + * Get the station interface link-local IPv6 address. + * @return IPAddress + */ +IPAddress WiFiSTAClass::localIPv6() +{ + static esp_ip6_addr_t addr; if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){ - return false; + return IPAddress(IPv6); + } + if(esp_netif_get_ip6_linklocal(get_esp_interface_netif(ESP_IF_WIFI_STA), &addr)){ + return IPAddress(IPv6); } - return esp_netif_create_ip6_linklocal(get_esp_interface_netif(ESP_IF_WIFI_STA)) == ESP_OK; + return IPAddress(IPv6, (const uint8_t *)addr.addr, addr.zone); } /** - * Get the station interface IPv6 address. - * @return IPv6Address + * Get the station interface global IPv6 address. + * @return IPAddress */ -IPv6Address WiFiSTAClass::localIPv6() +IPAddress WiFiSTAClass::globalIPv6() { - esp_ip6_addr_t addr; + static esp_ip6_addr_t addr; if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){ - return IPv6Address(); + return IPAddress(IPv6); } - if(esp_netif_get_ip6_linklocal(get_esp_interface_netif(ESP_IF_WIFI_STA), &addr)) { - return IPv6Address(); + if(esp_netif_get_ip6_global(get_esp_interface_netif(ESP_IF_WIFI_STA), &addr)){ + return IPAddress(IPv6); } - return IPv6Address(addr.addr); + return IPAddress(IPv6, (const uint8_t *)addr.addr, addr.zone); } diff --git a/libraries/WiFi/src/WiFiSTA.h b/libraries/WiFi/src/WiFiSTA.h index 07f01922cef..4fbb789aa04 100644 --- a/libraries/WiFi/src/WiFiSTA.h +++ b/libraries/WiFi/src/WiFiSTA.h @@ -93,8 +93,9 @@ class WiFiSTAClass IPAddress networkID(); uint8_t subnetCIDR(); - bool enableIpV6(); - IPv6Address localIPv6(); + bool enableIPv6(bool en=true); + IPAddress localIPv6(); + IPAddress globalIPv6(); // STA WiFi info static wl_status_t status(); diff --git a/libraries/WiFi/src/WiFiServer.cpp b/libraries/WiFi/src/WiFiServer.cpp index ef59cf14d6d..9d79b5f7c46 100644 --- a/libraries/WiFi/src/WiFiServer.cpp +++ b/libraries/WiFi/src/WiFiServer.cpp @@ -51,8 +51,8 @@ WiFiClient WiFiServer::accept(){ _accepted_sockfd = -1; } else { - struct sockaddr_in _client; - int cs = sizeof(struct sockaddr_in); + struct sockaddr_in6 _client; + int cs = sizeof(struct sockaddr_in6); #ifdef ESP_IDF_VERSION_MAJOR client_sock = lwip_accept(sockfd, (struct sockaddr *)&_client, (socklen_t*)&cs); #else @@ -80,14 +80,21 @@ void WiFiServer::begin(uint16_t port, int enable){ if(port){ _port = port; } - struct sockaddr_in server; - sockfd = socket(AF_INET , SOCK_STREAM, 0); + struct sockaddr_in6 server; + sockfd = socket(AF_INET6 , SOCK_STREAM, 0); if (sockfd < 0) return; setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)); - server.sin_family = AF_INET; - server.sin_addr.s_addr = _addr; - server.sin_port = htons(_port); + server.sin6_family = AF_INET6; + if (_addr.type() == IPv4) { + memcpy(server.sin6_addr.s6_addr+11, (uint8_t*)&_addr[0], 4); + server.sin6_addr.s6_addr[10] = 0xFF; + server.sin6_addr.s6_addr[11] = 0xFF; + } else { + memcpy(server.sin6_addr.s6_addr, (uint8_t*)&_addr[0], 16); + } + memset(server.sin6_addr.s6_addr, 0x0, 16); + server.sin6_port = htons(_port); if(bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0) return; if(listen(sockfd , _max_clients) < 0) @@ -110,8 +117,8 @@ bool WiFiServer::hasClient() { if (_accepted_sockfd >= 0) { return true; } - struct sockaddr_in _client; - int cs = sizeof(struct sockaddr_in); + struct sockaddr_in6 _client; + int cs = sizeof(struct sockaddr_in6); #ifdef ESP_IDF_VERSION_MAJOR _accepted_sockfd = lwip_accept(sockfd, (struct sockaddr *)&_client, (socklen_t*)&cs); #else @@ -140,4 +147,3 @@ void WiFiServer::close(){ void WiFiServer::stop(){ end(); } - diff --git a/libraries/WiFi/src/WiFiServer.h b/libraries/WiFi/src/WiFiServer.h index c51986701c4..5a022d14829 100644 --- a/libraries/WiFi/src/WiFiServer.h +++ b/libraries/WiFi/src/WiFiServer.h @@ -37,7 +37,6 @@ class WiFiServer : public Server { public: void listenOnLocalhost(){} - // _addr(INADDR_ANY) is the same as _addr() ==> 0.0.0.0 WiFiServer(uint16_t port=80, uint8_t max_clients=4):sockfd(-1),_accepted_sockfd(-1),_addr(),_port(port),_max_clients(max_clients),_listening(false),_noDelay(false) { log_v("WiFiServer::WiFiServer(port=%d, ...)", port); } diff --git a/libraries/WiFi/src/WiFiUdp.cpp b/libraries/WiFi/src/WiFiUdp.cpp index 6b053bbbd14..5d8b513a2d8 100644 --- a/libraries/WiFi/src/WiFiUdp.cpp +++ b/libraries/WiFi/src/WiFiUdp.cpp @@ -51,7 +51,11 @@ uint8_t WiFiUDP::begin(IPAddress address, uint16_t port){ } tx_buffer_len = 0; +#if LWIP_IPV6 + if ((udp_server=socket((address.type() == IPv6) ? AF_INET6 : AF_INET, SOCK_DGRAM, 0)) == -1){ +#else if ((udp_server=socket(AF_INET, SOCK_DGRAM, 0)) == -1){ +#endif log_e("could not create socket: %d", errno); return 0; } @@ -63,12 +67,31 @@ uint8_t WiFiUDP::begin(IPAddress address, uint16_t port){ return 0; } - struct sockaddr_in addr; - memset((char *) &addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(server_port); - addr.sin_addr.s_addr = (in_addr_t)address; - if(bind(udp_server , (struct sockaddr*)&addr, sizeof(addr)) == -1){ + struct sockaddr_storage serveraddr = {}; + size_t sock_size = 0; +#if LWIP_IPV6 + if (address.type() == IPv6) { + struct sockaddr_in6 *tmpaddr = (struct sockaddr_in6 *)&serveraddr; + ip_addr_t addr; + address.to_ip_addr_t(&addr); + memset((char *) tmpaddr, 0, sizeof(struct sockaddr_in)); + tmpaddr->sin6_family = AF_INET6; + tmpaddr->sin6_port = htons(server_port); + tmpaddr->sin6_scope_id = addr.u_addr.ip6.zone; + inet6_addr_from_ip6addr(&tmpaddr->sin6_addr, ip_2_ip6(&addr)); + tmpaddr->sin6_flowinfo = 0; + sock_size = sizeof(sockaddr_in6); + } else +#endif + { + struct sockaddr_in *tmpaddr = (struct sockaddr_in *)&serveraddr; + memset((char *) tmpaddr, 0, sizeof(struct sockaddr_in)); + tmpaddr->sin_family = AF_INET; + tmpaddr->sin_port = htons(server_port); + tmpaddr->sin_addr.s_addr = (in_addr_t)address; + sock_size = sizeof(sockaddr_in); + } + if(bind(udp_server , (sockaddr*)&serveraddr, sock_size) == -1){ log_e("could not bind socket: %d", errno); stop(); return 0; @@ -78,23 +101,48 @@ uint8_t WiFiUDP::begin(IPAddress address, uint16_t port){ } uint8_t WiFiUDP::begin(uint16_t p){ - return begin(IPAddress(INADDR_ANY), p); + return begin(IPAddress(), p); } -uint8_t WiFiUDP::beginMulticast(IPAddress a, uint16_t p){ - if(begin(IPAddress(INADDR_ANY), p)){ - if((uint32_t)a != 0){ - struct ip_mreq mreq; - mreq.imr_multiaddr.s_addr = (in_addr_t)a; - mreq.imr_interface.s_addr = INADDR_ANY; - if (setsockopt(udp_server, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { +uint8_t WiFiUDP::beginMulticast(IPAddress address, uint16_t p){ + if(begin(IPAddress(), p)){ + ip_addr_t addr; + address.to_ip_addr_t(&addr); + if (ip_addr_ismulticast(&addr)) { +#if LWIP_IPV6 + if (address.type() == IPv6) { + struct ipv6_mreq mreq; + bool joined = false; + inet6_addr_from_ip6addr(&mreq.ipv6mr_multiaddr, ip_2_ip6(&addr)); + + // iterate on each interface + for (netif* intf = netif_list; intf != nullptr; intf = intf->next) { + mreq.ipv6mr_interface = intf->num + 1; + if (intf->name[0] != 'l' || intf->name[1] != 'o') { // skip 'lo' local interface + int ret = setsockopt(udp_server, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)); + if (ret >= 0) { joined = true; } + } + } + if (!joined) { log_e("could not join igmp: %d", errno); stop(); return 0; + } + } else +#endif + { + struct ip_mreq mreq; + mreq.imr_multiaddr.s_addr = (in_addr_t)address; + mreq.imr_interface.s_addr = INADDR_ANY; + if (setsockopt(udp_server, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { + log_e("could not join igmp: %d", errno); + stop(); + return 0; + } } - multicast_ip = a; + multicast_ip = address; + return 1; } - return 1; } return 0; } @@ -112,19 +160,38 @@ void WiFiUDP::stop(){ } if(udp_server == -1) return; - if((uint32_t)multicast_ip != 0){ - struct ip_mreq mreq; - mreq.imr_multiaddr.s_addr = (in_addr_t)multicast_ip; - mreq.imr_interface.s_addr = (in_addr_t)0; - setsockopt(udp_server, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)); - multicast_ip = IPAddress(INADDR_ANY); + ip_addr_t addr; + multicast_ip.to_ip_addr_t(&addr); + if (!ip_addr_isany(&addr)) { +#if LWIP_IPV6 + if (multicast_ip.type() == IPv6) { + struct ipv6_mreq mreq; + inet6_addr_from_ip6addr(&mreq.ipv6mr_multiaddr, ip_2_ip6(&addr)); + + // iterate on each interface + for (netif* intf = netif_list; intf != nullptr; intf = intf->next) { + mreq.ipv6mr_interface = intf->num + 1; + if (intf->name[0] != 'l' || intf->name[1] != 'o') { // skip 'lo' local interface + setsockopt(udp_server, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq, sizeof(mreq)); + } + } + } else +#endif + { + struct ip_mreq mreq; + mreq.imr_multiaddr.s_addr = (in_addr_t)multicast_ip; + mreq.imr_interface.s_addr = (in_addr_t)0; + setsockopt(udp_server, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)); + } + // now common code for v4/v6 + multicast_ip = IPAddress(); } close(udp_server); udp_server = -1; } int WiFiUDP::beginMulticastPacket(){ - if(!server_port || multicast_ip == IPAddress(INADDR_ANY)) + if(!server_port || multicast_ip == IPAddress()) return 0; remote_ip = multicast_ip; remote_port = server_port; @@ -176,14 +243,31 @@ int WiFiUDP::beginPacket(const char *host, uint16_t port){ } int WiFiUDP::endPacket(){ - struct sockaddr_in recipient; - recipient.sin_addr.s_addr = (uint32_t)remote_ip; - recipient.sin_family = AF_INET; - recipient.sin_port = htons(remote_port); - int sent = sendto(udp_server, tx_buffer, tx_buffer_len, 0, (struct sockaddr*) &recipient, sizeof(recipient)); - if(sent < 0){ - log_e("could not send data: %d", errno); - return 0; + ip_addr_t addr; + remote_ip.to_ip_addr_t(&addr); + + if (remote_ip.type() == IPv4) { + struct sockaddr_in recipient; + recipient.sin_addr.s_addr = (uint32_t)remote_ip; + recipient.sin_family = AF_INET; + recipient.sin_port = htons(remote_port); + int sent = sendto(udp_server, tx_buffer, tx_buffer_len, 0, (struct sockaddr*) &recipient, sizeof(recipient)); + if(sent < 0){ + log_e("could not send data: %d", errno); + return 0; + } + } else { + struct sockaddr_in6 recipient; + recipient.sin6_flowinfo = 0; + recipient.sin6_addr = *(in6_addr*)(ip_addr_t*)(&addr); + recipient.sin6_family = AF_INET6; + recipient.sin6_port = htons(remote_port); + recipient.sin6_scope_id = remote_ip.zone(); + int sent = sendto(udp_server, tx_buffer, tx_buffer_len, 0, (struct sockaddr*) &recipient, sizeof(recipient)); + if(sent < 0){ + log_e("could not send data: %d", errno); + return 0; + } } return 1; } @@ -207,13 +291,14 @@ size_t WiFiUDP::write(const uint8_t *buffer, size_t size){ int WiFiUDP::parsePacket(){ if(rx_buffer) return 0; - struct sockaddr_in si_other; - int slen = sizeof(si_other) , len; + struct sockaddr_storage si_other_storage; // enough storage for v4 and v6 + socklen_t slen = sizeof(sockaddr_storage); + int len; char *buf = (char *)malloc(1460); if(!buf) { return 0; } - if ((len = recvfrom(udp_server, buf, 1460, MSG_DONTWAIT, (struct sockaddr *) &si_other, (socklen_t *)&slen)) == -1){ + if ((len = recvfrom(udp_server, buf, 1460, MSG_DONTWAIT, (struct sockaddr *) &si_other_storage, (socklen_t *)&slen)) == -1){ free(buf); if(errno == EWOULDBLOCK){ return 0; @@ -221,8 +306,30 @@ int WiFiUDP::parsePacket(){ log_e("could not receive data: %d", errno); return 0; } - remote_ip = IPAddress(si_other.sin_addr.s_addr); - remote_port = ntohs(si_other.sin_port); + if (si_other_storage.ss_family == AF_INET) { + struct sockaddr_in &si_other = (sockaddr_in&) si_other_storage; + remote_ip = IPAddress(si_other.sin_addr.s_addr); + remote_port = ntohs(si_other.sin_port); + } +#if LWIP_IPV6 + else if (si_other_storage.ss_family == AF_INET6) { + struct sockaddr_in6 &si_other = (sockaddr_in6&) si_other_storage; + remote_ip = IPAddress(IPv6, (uint8_t*)&si_other.sin6_addr, si_other.sin6_scope_id); // force IPv6 + ip_addr_t addr; + remote_ip.to_ip_addr_t(&addr); + /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ + if (remote_ip.type() == IPv6 && ip6_addr_isipv4mappedipv6(ip_2_ip6(&addr))) { + unmap_ipv4_mapped_ipv6(ip_2_ip4(&addr), ip_2_ip6(&addr)); + IP_SET_TYPE_VAL(addr, IPADDR_TYPE_V4); + remote_ip.from_ip_addr_t(&addr); + } + remote_port = ntohs(si_other.sin6_port); + } +#endif // LWIP_IPV6=1 + else { + remote_ip = ip_addr_any.u_addr.ip4.addr; + remote_port = 0; + } if (len > 0) { rx_buffer = new(std::nothrow) cbuf(len); rx_buffer->write(buf, len);