From 23fa1f897c3f711916475604516a0b6601ef7ea9 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Tue, 21 Nov 2023 18:17:04 +0100 Subject: [PATCH 1/8] IPv6 for Arduino 3.0.0 --- cores/esp32/IPAddress.cpp | 226 +++++++++++++++++++++++------ cores/esp32/IPAddress.h | 161 +++++++++++++++++--- libraries/WiFi/src/WiFiClient.cpp | 64 ++++++-- libraries/WiFi/src/WiFiGeneric.cpp | 58 +++++++- libraries/WiFi/src/WiFiGeneric.h | 7 + libraries/WiFi/src/WiFiMulti.cpp | 7 + libraries/WiFi/src/WiFiMulti.h | 2 + libraries/WiFi/src/WiFiSTA.cpp | 13 ++ libraries/WiFi/src/WiFiSTA.h | 1 + libraries/WiFi/src/WiFiServer.cpp | 28 ++-- libraries/WiFi/src/WiFiServer.h | 1 - libraries/WiFi/src/WiFiUdp.cpp | 168 ++++++++++++++++----- 12 files changed, 606 insertions(+), 130 deletions(-) diff --git a/cores/esp32/IPAddress.cpp b/cores/esp32/IPAddress.cpp index 0575363f254..316db954de7 100644 --- a/cores/esp32/IPAddress.cpp +++ b/cores/esp32/IPAddress.cpp @@ -20,68 +20,87 @@ #include #include #include +#include -IPAddress::IPAddress() -{ - _address.dword = 0; +IPAddress::IPAddress() { +#if LWIP_IPV6 + _ip = *IP6_ADDR_ANY; +#else + _ip = *IP_ADDR_ANY; +#endif + // _ip = *IP_ANY_TYPE; // lwIP's v4-or-v6 generic address } -IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) +IPAddress::IPAddress(const IPAddress& from) { - _address.bytes[0] = first_octet; - _address.bytes[1] = second_octet; - _address.bytes[2] = third_octet; - _address.bytes[3] = fourth_octet; + ip_addr_copy(_ip, from._ip); } -IPAddress::IPAddress(uint32_t address) -{ - _address.dword = address; +IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) { + uint8_t addr[] { + first_octet, + second_octet, + third_octet, + fourth_octet, + }; + *this = &addr[0]; } -IPAddress::IPAddress(const uint8_t *address) -{ - memcpy(_address.bytes, address, sizeof(_address.bytes)); +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) { + setV6(); + (*this)[0] = o1; + (*this)[1] = o2; + (*this)[2] = o3; + (*this)[3] = o4; + (*this)[4] = o5; + (*this)[5] = o6; + (*this)[6] = o7; + (*this)[7] = o8; + (*this)[8] = o9; + (*this)[9] = o10; + (*this)[10] = o11; + (*this)[11] = o12; + (*this)[12] = o13; + (*this)[13] = o14; + (*this)[14] = o15; + (*this)[15] = o16; } -IPAddress& IPAddress::operator=(const uint8_t *address) -{ - memcpy(_address.bytes, address, sizeof(_address.bytes)); - return *this; +IPAddress::IPAddress(IPType type, const uint8_t *address) { + IPAddress(type, address, 0); } -IPAddress& IPAddress::operator=(uint32_t address) -{ - _address.dword = address; - return *this; -} +IPAddress::IPAddress(IPType type, const uint8_t *address, uint8_t zone) { + if (type == IPv4) { + setV4(); + memcpy(&this->_ip.u_addr.ip4, address, 4); + } else if (type == IPv6) { + setV6(); + memcpy(&this->_ip.u_addr.ip6.addr[0], address, 16); + setZone(zone); + } else { +#if LWIP_IPV6 + _ip = *IP6_ADDR_ANY; +#else + _ip = *IP_ADDR_ANY; +#endif + } -bool IPAddress::operator==(const uint8_t* addr) const -{ - return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0; } -size_t IPAddress::printTo(Print& p) const -{ - size_t n = 0; - for(int i = 0; i < 3; i++) { - n += p.print(_address.bytes[i], DEC); - n += p.print('.'); +bool IPAddress::fromString(const char *address) { + if (!fromString4(address)) { +#if LWIP_IPV6 + return fromString6(address); +#else + return false; +#endif } - n += p.print(_address.bytes[3], DEC); - return n; -} - -String IPAddress::toString() const -{ - char szRet[16]; - sprintf(szRet,"%u.%u.%u.%u", _address.bytes[0], _address.bytes[1], _address.bytes[2], _address.bytes[3]); - return String(szRet); + return true; } -bool IPAddress::fromString(const char *address) -{ - // TODO: add support for "a", "a.b", "a.b.c" formats +bool IPAddress::fromString4(const char *address) { + // TODO: (IPv4) add support for "a", "a.b", "a.b.c" formats uint16_t acc = 0; // Accumulator uint8_t dots = 0; @@ -103,7 +122,7 @@ bool IPAddress::fromString(const char *address) // Too much dots (there must be 3 dots) return false; } - _address.bytes[dots++] = acc; + (*this)[dots++] = acc; acc = 0; } else @@ -117,9 +136,122 @@ bool IPAddress::fromString(const char *address) // Too few dots (there must be 3 dots) return false; } - _address.bytes[3] = acc; + (*this)[3] = acc; + + setV4(); return true; } +IPAddress& IPAddress::operator=(const uint8_t *address) { + uint32_t value; + memcpy_P(&value, address, sizeof(value)); + *this = value; + return *this; +} + +IPAddress& IPAddress::operator=(uint32_t address) { + setV4(); + v4() = address; + return *this; +} + +bool IPAddress::operator==(const uint8_t* addr) const { + if (!isV4()) { + return false; + } + + uint32_t value; + memcpy_P(&value, addr, sizeof(value)); + + return v4() == value; +} + +size_t IPAddress::printTo(Print& p) const { + size_t n = 0; + +#if LWIP_IPV6 + if (isV6()) { + int count0 = 0; + for (int i = 0; i < 8; i++) { + uint16_t bit = PP_NTOHS(raw6()[i]); + if (bit || count0 < 0) { + n += p.printf("%x", bit); + if (count0 > 0) + // no more hiding 0 + count0 = -8; + } else + count0++; + if ((i != 7 && count0 < 2) || count0 == 7) + n += p.print(':'); + } + // add a zone if zone-id si non-zero + if (_ip.u_addr.ip6.zone) { + n += p.print('%'); + char if_name[NETIF_NAMESIZE]; + netif_index_to_name(_ip.u_addr.ip6.zone, if_name); + n += p.print(if_name); + } + return n; + } +#endif + + for(int i = 0; i < 4; i++) { + n += p.print((*this)[i], DEC); + if (i != 3) + n += p.print('.'); + } + return n; +} + +String IPAddress::toString() const +{ + StreamString sstr; +#if LWIP_IPV6 + if (isV6()) + sstr.reserve(44); // 8 shorts x 4 chars each + 7 colons + nullterm + '%' + zone-id + else +#endif + sstr.reserve(16); // 4 bytes with 3 chars max + 3 dots + nullterm, or '(IP unset)' + printTo(sstr); + return sstr; +} + +bool IPAddress::isValid(const String& arg) { + return IPAddress().fromString(arg); +} + +bool IPAddress::isValid(const char* arg) { + return IPAddress().fromString(arg); +} + +const IPAddress INADDR46_ANY; // generic "0.0.0.0" for IPv4 & IPv6 +const IPAddress INADDR46_NONE(255,255,255,255); + +void IPAddress::clear() { + (*this) = INADDR46_ANY; +} + +/**************************************/ + +#if LWIP_IPV6 + +bool IPAddress::fromString6(const char *address) { + ip6_addr_t ip6; + if (ip6addr_aton(address, &ip6)) { + setV6(); + memcpy(&this->_ip.u_addr.ip6.addr[0], ip6.addr, 16); + // look for '%' in string + const char *s = address; + while (*s && *s != '%') { s++; } + if (*s == '%') { + // we have a zone id + setZone(netif_name_to_index(s + 1)); + } + return true; + } + return false; +} +#endif // LWIP_IPV6 + // declared one time - as external in IPAddress.h -IPAddress INADDR_NONE(0, 0, 0, 0); +IPAddress INADDR_NONE(0, 0, 0, 0); // TODO diff --git a/cores/esp32/IPAddress.h b/cores/esp32/IPAddress.h index 3bedd4f8749..9fec26ada35 100644 --- a/cores/esp32/IPAddress.h +++ b/cores/esp32/IPAddress.h @@ -20,77 +20,190 @@ #ifndef IPAddress_h #define IPAddress_h -#include #include #include +#include -// A class to make it easier to handle and pass around IP addresses +enum IPType +{ + IPv4 = IPADDR_TYPE_V4, + IPv6 = IPADDR_TYPE_V6 +}; class IPAddress: public Printable { private: - union { - uint8_t bytes[4]; // IPv4 address - uint32_t dword; - } _address; + ip_addr_t _ip; // 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; + uint8_t* raw_address() { + return reinterpret_cast(&v4()); } + const uint8_t* raw_address() const { + return reinterpret_cast(&v4()); + } + + void ctor32 (uint32_t); public: // Constructors IPAddress(); + IPAddress(const IPAddress& from); IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet); - IPAddress(uint32_t address); - IPAddress(const uint8_t *address); - virtual ~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(uint32_t address) { *this = address; } + IPAddress(int address) { *this = address; } + IPAddress(const uint8_t *address) { *this = address; } + IPAddress(IPType type, const uint8_t *address); + IPAddress(IPType type, const uint8_t *address, uint8_t zone); 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 pointer // to a four-byte uint8_t array is expected - operator uint32_t() const - { - return _address.dword; + operator uint32_t() const { return isV4()? v4(): (uint32_t)0; } + operator uint32_t() { return isV4()? v4(): (uint32_t)0; } + + // generic IPv4 wrapper to uint32-view like arduino loves to see it + const uint32_t& v4() const { return ip_2_ip4(&_ip)->addr; } + uint32_t& v4() { return ip_2_ip4(&_ip)->addr; } + + bool operator==(const IPAddress& addr) const { + return ip_addr_cmp(&_ip, &addr._ip); } - bool operator==(const IPAddress& addr) const - { - return _address.dword == addr._address.dword; + bool operator!=(const IPAddress& addr) const { + return !ip_addr_cmp(&_ip, &addr._ip); + } + bool operator==(uint32_t addr) const { + return isV4() && v4() == addr; + } + // bool operator==(unsigned long addr) const { + // return isV4() && v4() == (uint32_t)addr; + // } + bool operator!=(uint32_t addr) const { + return !(isV4() && v4() == addr); } + // bool operator!=(unsigned long addr) const { + // return isV4() && v4() != (uint32_t)addr; + // } bool operator==(const uint8_t* addr) const; + int operator>>(int n) const { + return isV4()? v4() >> n: 0; + } + // 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) const { + if (!isV4()) { + return 0; + } + + return ip4_addr_get_byte_val(*ip_2_ip4(&_ip), index); } - uint8_t& operator[](int index) - { - return _address.bytes[index]; + uint8_t& operator[](int index) { + setV4(); + uint8_t* ptr = reinterpret_cast(&v4()); + return *(ptr + index); } // Overloaded copy operators to allow initialisation of IPAddress objects from other types IPAddress& operator=(const uint8_t *address); IPAddress& operator=(uint32_t address); + IPAddress& operator=(const IPAddress&) = default; + + IPType type() const { return (IPType)_ip.type; } virtual size_t printTo(Print& p) const; String toString() const; + void clear(); + + /* + check if input string(arg) is a valid IPV4 address or not. + return true on valid. + return false on invalid. + */ + static bool isValid(const String& arg); + static bool isValid(const char* arg); + friend class EthernetClass; friend class UDP; friend class Client; friend class Server; friend class DhcpClass; friend class DNSClient; + + operator ip_addr_t () const { return _ip; } + operator const ip_addr_t*() const { return &_ip; } + operator ip_addr_t*() { return &_ip; } + + bool isV4() const { return IP_IS_V4_VAL(_ip); } + void setV4() { IP_SET_TYPE_VAL(_ip, IPADDR_TYPE_V4); } + + bool isLocal() const { return ip_addr_islinklocal(&_ip); } + bool isAny() const { return ip_addr_isany_val(_ip); } + +#if LWIP_IPV6 + IPAddress(const ip_addr_t& lwip_addr) { ip_addr_copy(_ip, lwip_addr); } + IPAddress(const ip_addr_t* lwip_addr) { ip_addr_copy(_ip, *lwip_addr); } + + IPAddress& operator=(const ip_addr_t& lwip_addr) { ip_addr_copy(_ip, lwip_addr); return *this; } + IPAddress& operator=(const ip_addr_t* lwip_addr) { ip_addr_copy(_ip, *lwip_addr); return *this; } + + uint16_t* raw6() + { + setV6(); + return reinterpret_cast(ip_2_ip6(&_ip)); + } + + const uint16_t* raw6() const + { + return isV6()? reinterpret_cast(ip_2_ip6(&_ip)): nullptr; + } + + // when not IPv6, ip_addr_t == ip4_addr_t so this one would be ambiguous + // required otherwise + operator const ip4_addr_t*() const { return isV4()? ip_2_ip4(&_ip): nullptr; } + + bool isV6() const { return IP_IS_V6_VAL(_ip); } + void setV6() { + IP_SET_TYPE_VAL(_ip, IPADDR_TYPE_V6); + ip6_addr_clear_zone(ip_2_ip6(&_ip)); + } + inline uint8_t zone() const { return isV6() ? ip_2_ip6(&_ip)->zone : 0; } + void setZone(uint8_t zone) { + if (isV6()) { + ip_2_ip6(&_ip)->zone = zone; + } + } + + +protected: + bool fromString6(const char *address); + +#else + + // allow portable code when IPv6 is not enabled + + uint16_t* raw6() { return nullptr; } + const uint16_t* raw6() const { return nullptr; } + bool isV6() const { return false; } + void setV6() { } + inline uint8_t zone() const { return 0; } + void setZone(uint8_t zone) { } + +#endif + +protected: + bool fromString4(const char *address); }; // 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 diff --git a/libraries/WiFi/src/WiFiClient.cpp b/libraries/WiFi/src/WiFiClient.cpp index a4301ad0e09..9a1c02240ff 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) @@ -217,22 +222,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); @@ -301,6 +317,19 @@ int WiFiClient::connect(const char *host, uint16_t port) int WiFiClient::connect(const char *host, uint16_t port, int32_t timeout_ms) { + if (WiFiGenericClass::getStatusBits() & WIFI_WANT_IP6_BIT) { + ip_addr_t srv6; + if(!WiFiGenericClass::hostByName6(host, srv6)){ + return 0; + } + if (srv6.type == IPADDR_TYPE_V4) { + IPAddress ip(srv6.u_addr.ip4.addr); + return connect(ip, port, timeout_ms); + } else { + IPAddress ip(IPv6, (uint8_t*)&srv6.u_addr.ip6.addr[0]); + return connect(ip, port, timeout_ms); + } + } IPAddress srv((uint32_t)0); if(!WiFiGenericClass::hostByName(host, srv)){ return 0; @@ -552,8 +581,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+12); + } 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 @@ -616,4 +661,3 @@ int WiFiClient::fd() const return clientSocketHandle->fd(); } } - diff --git a/libraries/WiFi/src/WiFiGeneric.cpp b/libraries/WiFi/src/WiFiGeneric.cpp index 6b1d7358bc6..4fe638c7e7a 100644 --- a/libraries/WiFi/src/WiFiGeneric.cpp +++ b/libraries/WiFi/src/WiFiGeneric.cpp @@ -1054,8 +1054,8 @@ esp_err_t WiFiGenericClass::_eventCallback(arduino_event_t *event) } else if(event->event_id == ARDUINO_EVENT_WIFI_STA_CONNECTED) { WiFiSTAClass::_setStatus(WL_IDLE_STATUS); setStatusBits(STA_CONNECTED_BIT); - - //esp_netif_create_ip6_linklocal(esp_netifs[ESP_IF_WIFI_STA]); + if (getStatusBits() & WIFI_WANT_IP6_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 @@ -1561,8 +1561,27 @@ static void wifi_dns_found_callback(const char *name, const ip_addr_t *ipaddr, v } /** - * 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 + * IPv6 compatible DNS callback + * @param name + * @param ipaddr + * @param callback_arg + */ +static void wifi_dns6_found_callback(const char *name, const ip_addr_t *ipaddr, void *callback_arg) +{ + struct dns_api_msg *msg = (struct dns_api_msg *)callback_arg; + + if(ipaddr && !msg->result) { + msg->ip_addr = *ipaddr; + msg->result = 1; + } else { + msg->result = -1; + } + xEventGroupSetBits(_arduino_event_group, WIFI_DNS_DONE_BIT); +} + +/** + * 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 @@ -1590,6 +1609,37 @@ int WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult) return (uint32_t)aResult != 0; } +/** + * Resolve the given hostname to an IP6 address. + * @param aHostname Name to be resolved + * @param aResult IPv6Address structure to store the returned IP address + * @return 1 if aHostname was successfully converted to an IP address, + * else error code + */ +int WiFiGenericClass::hostByName6(const char* aHostname, ip_addr_t& aResult) +{ + ip_addr_t addr; + struct dns_api_msg arg; + + memset(&arg, 0x0, sizeof(arg)); + waitStatusBits(WIFI_DNS_IDLE_BIT, 16000); + clearStatusBits(WIFI_DNS_IDLE_BIT | WIFI_DNS_DONE_BIT); + + err_t err = dns_gethostbyname_addrtype(aHostname, &addr, &wifi_dns6_found_callback, + &arg, LWIP_DNS_ADDRTYPE_IPV6_IPV4); + if(err == ERR_OK) { + aResult = 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); + if (arg.result == 1) { + aResult = arg.ip_addr; + } + } + setStatusBits(WIFI_DNS_IDLE_BIT); + return (uint32_t)err == ERR_OK || (err == ERR_INPROGRESS && arg.result == 1); +} + IPAddress WiFiGenericClass::calculateNetworkID(IPAddress ip, IPAddress subnet) { IPAddress networkID; diff --git a/libraries/WiFi/src/WiFiGeneric.h b/libraries/WiFi/src/WiFiGeneric.h index 38396f5a72e..ce723409eca 100644 --- a/libraries/WiFi/src/WiFiGeneric.h +++ b/libraries/WiFi/src/WiFiGeneric.h @@ -141,6 +141,7 @@ 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; +static const int WIFI_WANT_IP6_BIT = BIT15; typedef enum { WIFI_RX_ANT0 = 0, @@ -154,6 +155,11 @@ typedef enum { WIFI_TX_ANT_AUTO } wifi_tx_ant_t; +struct dns_api_msg { + ip_addr_t ip_addr; + int result; +}; + class WiFiGenericClass { public: @@ -196,6 +202,7 @@ class WiFiGenericClass static const char * getHostname(); static bool setHostname(const char * hostname); static bool hostname(const String& aHostname) { return setHostname(aHostname.c_str()); } + static int hostByName6(const char *aHostname, ip_addr_t& aResult); static esp_err_t _eventCallback(arduino_event_t *event); diff --git a/libraries/WiFi/src/WiFiMulti.cpp b/libraries/WiFi/src/WiFiMulti.cpp index 3d69e481293..9e7f03c6531 100644 --- a/libraries/WiFi/src/WiFiMulti.cpp +++ b/libraries/WiFi/src/WiFiMulti.cpp @@ -30,6 +30,7 @@ WiFiMulti::WiFiMulti() { + ipv6_support = false; } WiFiMulti::~WiFiMulti() @@ -160,6 +161,8 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout) 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); WiFi.begin(bestNetwork.ssid, bestNetwork.passphrase, bestChannel, bestBSSID); + if (ipv6_support == true) + WiFi.IPv6(true); status = WiFi.status(); auto startTime = millis(); @@ -202,3 +205,7 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout) return status; } + +void WiFiMulti::IPv6(bool state) { + ipv6_support = state; +} diff --git a/libraries/WiFi/src/WiFiMulti.h b/libraries/WiFi/src/WiFiMulti.h index 38ddb5d9f95..bbeb78dc860 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 IPv6(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 558feb5255a..45f5394c72f 100644 --- a/libraries/WiFi/src/WiFiSTA.cpp +++ b/libraries/WiFi/src/WiFiSTA.cpp @@ -796,6 +796,19 @@ bool WiFiSTAClass::enableIpV6() return esp_netif_create_ip6_linklocal(get_esp_interface_netif(ESP_IF_WIFI_STA)) == ESP_OK; } +/** + * Enable IPv6 support on the station interface. + * @return true on success + */ +bool WiFiSTAClass::IPv6(bool state) +{ + if (state) + WiFiGenericClass::setStatusBits(WIFI_WANT_IP6_BIT); + else + WiFiGenericClass::clearStatusBits(WIFI_WANT_IP6_BIT); + return true; +} + /** * Get the station interface IPv6 address. * @return IPv6Address diff --git a/libraries/WiFi/src/WiFiSTA.h b/libraries/WiFi/src/WiFiSTA.h index 3f224211a1e..f02742a9dbb 100644 --- a/libraries/WiFi/src/WiFiSTA.h +++ b/libraries/WiFi/src/WiFiSTA.h @@ -92,6 +92,7 @@ class WiFiSTAClass uint8_t subnetCIDR(); bool enableIpV6(); + bool IPv6(bool state); IPv6Address localIPv6(); // STA WiFi info diff --git a/libraries/WiFi/src/WiFiServer.cpp b/libraries/WiFi/src/WiFiServer.cpp index db21858125b..3790c079b4a 100644 --- a/libraries/WiFi/src/WiFiServer.cpp +++ b/libraries/WiFi/src/WiFiServer.cpp @@ -47,8 +47,8 @@ WiFiClient WiFiServer::available(){ _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 @@ -76,14 +76,23 @@ 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) { + // log_e("---------------- 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 { + // log_e("---------------- IPv6"); + 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) @@ -106,8 +115,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 @@ -136,4 +145,3 @@ void WiFiServer::close(){ void WiFiServer::stop(){ end(); } - diff --git a/libraries/WiFi/src/WiFiServer.h b/libraries/WiFi/src/WiFiServer.h index 346986abad5..d933231bdbb 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 0d75739afb9..002b4dce419 100644 --- a/libraries/WiFi/src/WiFiUdp.cpp +++ b/libraries/WiFi/src/WiFiUdp.cpp @@ -50,7 +50,11 @@ uint8_t WiFiUDP::begin(IPAddress address, uint16_t port){ return 0; } +#if LWIP_IPV6 + if ((udp_server=socket(address.isV6() ? 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; } @@ -62,12 +66,30 @@ 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.isV6()) { + struct sockaddr_in6 *tmpaddr = (struct sockaddr_in6 *)&serveraddr; + ip_addr_t * ip_addr = (ip_addr_t*) address; + memset((char *) tmpaddr, 0, sizeof(struct sockaddr_in)); + tmpaddr->sin6_family = AF_INET6; + tmpaddr->sin6_port = htons(server_port); + tmpaddr->sin6_scope_id = ip_addr->u_addr.ip6.zone; + inet6_addr_from_ip6addr(&tmpaddr->sin6_addr, ip_2_ip6(ip_addr)); + tmpaddr->sin6_flowinfo = 0; + sock_size = sizeof(sockaddr_in6); + } else +#endif + if (1) { + 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; @@ -77,23 +99,47 @@ 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) { + if(begin(IPAddress(), p)){ + ip_addr_t * ip_addr = (ip_addr_t*) a; + if (ip_addr_ismulticast(ip_addr)) { +#if LWIP_IPV6 + if (IP_IS_V6_VAL(*ip_addr)) { + struct ipv6_mreq mreq; + bool joined = false; + inet6_addr_from_ip6addr(&mreq.ipv6mr_multiaddr, ip_2_ip6(ip_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 + if (1) { + 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) { + log_e("could not join igmp: %d", errno); + stop(); + return 0; + } } multicast_ip = a; + return 1; } - return 1; } return 0; } @@ -111,19 +157,37 @@ 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 * mcast_addr = (ip_addr_t*) multicast_ip; + if (!ip_addr_isany(mcast_addr)) { +#if LWIP_IPV6 + if (IP_IS_V6(mcast_addr)) { + struct ipv6_mreq mreq; + inet6_addr_from_ip6addr(&mreq.ipv6mr_multiaddr, ip_2_ip6(mcast_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_LEAVE_GROUP, &mreq, sizeof(mreq)); + } + } + } else +#endif + if (1) { + 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 +240,29 @@ 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; + + if (remote_ip.isV4()) { + 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*)remote_ip; + 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 +286,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 +301,28 @@ 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 *ip_addr = (ip_addr_t*) remote_ip; + /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ + if (IP_IS_V6_VAL(*ip_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(ip_addr))) { + unmap_ipv4_mapped_ipv6(ip_2_ip4(ip_addr), ip_2_ip6(ip_addr)); + IP_SET_TYPE_VAL(*ip_addr, IPADDR_TYPE_V4); + } + remote_port = ntohs(si_other.sin6_port); + } +#endif // LWIP_IPV6=1 + else { + remote_ip = *IP_ADDR_ANY; + remote_port = 0; + } if (len > 0) { rx_buffer = new(std::nothrow) cbuf(len); rx_buffer->write(buf, len); From a78841aafdf52e87e0279424c4a03c8734ef77c2 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Tue, 21 Nov 2023 21:10:49 +0100 Subject: [PATCH 2/8] Fix warning in WifiUdp --- libraries/WiFi/src/WiFiUdp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/WiFi/src/WiFiUdp.cpp b/libraries/WiFi/src/WiFiUdp.cpp index 002b4dce419..a6ea05d2be2 100644 --- a/libraries/WiFi/src/WiFiUdp.cpp +++ b/libraries/WiFi/src/WiFiUdp.cpp @@ -168,7 +168,7 @@ void WiFiUDP::stop(){ 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_LEAVE_GROUP, &mreq, sizeof(mreq)); + setsockopt(udp_server, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq, sizeof(mreq)); } } } else From 13d55a7d9a1adc8f532630cb2bc32508fcae4b5d Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Wed, 22 Nov 2023 16:01:24 +0100 Subject: [PATCH 3/8] remove comment / formating --- cores/esp32/IPAddress.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cores/esp32/IPAddress.cpp b/cores/esp32/IPAddress.cpp index 316db954de7..1722065c7bd 100644 --- a/cores/esp32/IPAddress.cpp +++ b/cores/esp32/IPAddress.cpp @@ -28,7 +28,6 @@ IPAddress::IPAddress() { #else _ip = *IP_ADDR_ANY; #endif - // _ip = *IP_ANY_TYPE; // lwIP's v4-or-v6 generic address } IPAddress::IPAddress(const IPAddress& from) @@ -80,9 +79,9 @@ IPAddress::IPAddress(IPType type, const uint8_t *address, uint8_t zone) { setZone(zone); } else { #if LWIP_IPV6 - _ip = *IP6_ADDR_ANY; + _ip = *IP6_ADDR_ANY; #else - _ip = *IP_ADDR_ANY; + _ip = *IP_ADDR_ANY; #endif } From 0cff29df48885a629d48d9d921f83c464a44c4c0 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Wed, 22 Nov 2023 16:03:20 +0100 Subject: [PATCH 4/8] add comment --- cores/esp32/IPAddress.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/esp32/IPAddress.h b/cores/esp32/IPAddress.h index 9fec26ada35..e190c832a5e 100644 --- a/cores/esp32/IPAddress.h +++ b/cores/esp32/IPAddress.h @@ -185,7 +185,7 @@ class IPAddress: public Printable protected: bool fromString6(const char *address); -#else +#else /* !LWIP_IPV6 */ // allow portable code when IPv6 is not enabled From b88aa5444e9b24ef440209b3043cf079749154e5 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Wed, 22 Nov 2023 22:45:34 +0100 Subject: [PATCH 5/8] Remove `if (1)` --- libraries/WiFi/src/WiFiUdp.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/WiFi/src/WiFiUdp.cpp b/libraries/WiFi/src/WiFiUdp.cpp index a6ea05d2be2..9bb45a3f62a 100644 --- a/libraries/WiFi/src/WiFiUdp.cpp +++ b/libraries/WiFi/src/WiFiUdp.cpp @@ -81,7 +81,7 @@ uint8_t WiFiUDP::begin(IPAddress address, uint16_t port){ sock_size = sizeof(sockaddr_in6); } else #endif - if (1) { + { struct sockaddr_in *tmpaddr = (struct sockaddr_in *)&serveraddr; memset((char *) tmpaddr, 0, sizeof(struct sockaddr_in)); tmpaddr->sin_family = AF_INET; @@ -127,7 +127,7 @@ uint8_t WiFiUDP::beginMulticast(IPAddress a, uint16_t p){ } } else #endif - if (1) { + { struct ip_mreq mreq; mreq.imr_multiaddr.s_addr = (in_addr_t)a; mreq.imr_interface.s_addr = INADDR_ANY; @@ -173,7 +173,7 @@ void WiFiUDP::stop(){ } } else #endif - if (1) { + { struct ip_mreq mreq; mreq.imr_multiaddr.s_addr = (in_addr_t)multicast_ip; mreq.imr_interface.s_addr = (in_addr_t)0; From 9f680df77a7ae8e040bad17e54968c2d325a3c39 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Wed, 22 Nov 2023 22:50:07 +0100 Subject: [PATCH 6/8] Guard IPv6 --- libraries/WiFi/src/WiFiClient.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/libraries/WiFi/src/WiFiClient.cpp b/libraries/WiFi/src/WiFiClient.cpp index 9a1c02240ff..8b2ed2d0e3e 100644 --- a/libraries/WiFi/src/WiFiClient.cpp +++ b/libraries/WiFi/src/WiFiClient.cpp @@ -229,14 +229,17 @@ int WiFiClient::connect(IPAddress ip, uint16_t port, int32_t timeout_ms) _timeout = timeout_ms; int sockfd = -1; - if (ip.type() == IPv6) { +#if LWIP_IPV6 + if (ip.isV6()) { 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 { + } else +#endif + { struct sockaddr_in *tmpaddr = (struct sockaddr_in *)&serveraddr; sockfd = socket(AF_INET, SOCK_STREAM, 0); tmpaddr->sin_family = AF_INET; @@ -588,6 +591,7 @@ IPAddress WiFiClient::remoteIP(int fd) const return IPAddress((uint32_t)(s->sin_addr.s_addr)); } +#if LWIP_IPV6 // IPv6, but it might be IPv4 mapped address if (((struct sockaddr*)&addr)->sa_family == AF_INET6) { struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)&addr; @@ -597,6 +601,7 @@ IPAddress WiFiClient::remoteIP(int fd) const return IPAddress(IPv6, (uint8_t*)(saddr6->sin6_addr.s6_addr), saddr6->sin6_scope_id); } } +#endif log_e("WiFiClient::remoteIP Not AF_INET or AF_INET6?"); return (IPAddress(0,0,0,0)); } From ac21e7d0c7c9970aaa4196328270b3d909c34f34 Mon Sep 17 00:00:00 2001 From: s-hadinger <49731213+s-hadinger@users.noreply.github.com> Date: Wed, 22 Nov 2023 22:53:15 +0100 Subject: [PATCH 7/8] Fix WiFiServer IPv4 in IPv6 --- libraries/WiFi/src/WiFiServer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/WiFi/src/WiFiServer.cpp b/libraries/WiFi/src/WiFiServer.cpp index 3790c079b4a..da2c0b11ae2 100644 --- a/libraries/WiFi/src/WiFiServer.cpp +++ b/libraries/WiFi/src/WiFiServer.cpp @@ -82,16 +82,16 @@ void WiFiServer::begin(uint16_t port, int enable){ return; setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)); server.sin6_family = AF_INET6; + memset(server.sin6_addr.s6_addr, 0x0, 16); if (_addr.type() == IPv4) { // log_e("---------------- IPv4"); - memcpy(server.sin6_addr.s6_addr+11, (uint8_t*)&_addr[0], 4); + memcpy(server.sin6_addr.s6_addr+12, (uint8_t*)&_addr[0], 4); server.sin6_addr.s6_addr[10] = 0xFF; server.sin6_addr.s6_addr[11] = 0xFF; } else { // log_e("---------------- IPv6"); 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; From 5740c6965aa8431e625e0784e4302d206fe2a815 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Fri, 24 Nov 2023 17:11:02 +0100 Subject: [PATCH 8/8] Simplify `IPv6()` --- libraries/WiFi/src/WiFiMulti.cpp | 9 +-------- libraries/WiFi/src/WiFiMulti.h | 2 -- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/libraries/WiFi/src/WiFiMulti.cpp b/libraries/WiFi/src/WiFiMulti.cpp index 9e7f03c6531..918c9e0fc61 100644 --- a/libraries/WiFi/src/WiFiMulti.cpp +++ b/libraries/WiFi/src/WiFiMulti.cpp @@ -28,11 +28,6 @@ #include #include -WiFiMulti::WiFiMulti() -{ - ipv6_support = false; -} - WiFiMulti::~WiFiMulti() { for(uint32_t i = 0; i < APlist.size(); i++) { @@ -161,8 +156,6 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout) 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); WiFi.begin(bestNetwork.ssid, bestNetwork.passphrase, bestChannel, bestBSSID); - if (ipv6_support == true) - WiFi.IPv6(true); status = WiFi.status(); auto startTime = millis(); @@ -207,5 +200,5 @@ uint8_t WiFiMulti::run(uint32_t connectTimeout) } void WiFiMulti::IPv6(bool state) { - ipv6_support = state; + WiFi.IPv6(state); } diff --git a/libraries/WiFi/src/WiFiMulti.h b/libraries/WiFi/src/WiFiMulti.h index bbeb78dc860..d01a5a4c4ed 100644 --- a/libraries/WiFi/src/WiFiMulti.h +++ b/libraries/WiFi/src/WiFiMulti.h @@ -37,7 +37,6 @@ typedef struct { class WiFiMulti { public: - WiFiMulti(); ~WiFiMulti(); bool addAP(const char* ssid, const char *passphrase = NULL); @@ -47,7 +46,6 @@ class WiFiMulti private: std::vector APlist; - bool ipv6_support; }; #endif /* WIFICLIENTMULTI_H_ */