This is a continuation on the topic of adding IPv6 Support to ESP32 Arduino (#9016)

* IPv6 for Arduino 3.0.0

* Fix warning in WifiUdp

* remove comment / formating

* Add zone to IPAddress and update WiFiUDP and WiFiGeneric

* Add from ip_addr_t conversion and better toString implementation

* Use constant for IPAddress offset

@sgryphon is this better?

* Combine hostByName to support both IPv6 and IPv4 results

* implement logic to use v6 dns only when global v6 address is assigned and remove IPv6Address

* Rename softAPenableIPv6

* Rename mDNS methods

* fix IPAddress method to work with const address

* Some cleanup and do not print zone in IPAddress

* rename WiFiMulti method

* Fix AP DHCPS not properly working on recent IDF

* Add option to print the zone at the end of IPv6

@TD-er

* remove log prints from hostByName

* Use correct array length for listing IPv6 addresses

* Implement some Tasmota requirements

Added constructor that takes `const ip_addr_t *`.
Added `addr_type()` getter
Organize header to highlight the Espressif additions to IPAddress

* add 'const' to IPAddress::addr_type()

* Fix WiFiUdp not updating mapped v4 address

* Update WiFiServer.cpp

---------

Co-authored-by: Jason2866 <24528715+Jason2866@users.noreply.github.com>
Co-authored-by: s-hadinger <49731213+s-hadinger@users.noreply.github.com>
This commit is contained in:
Me No Dev 2024-01-15 15:24:34 +02:00 committed by GitHub
parent e4d6a8abf9
commit 768719c68f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 799 additions and 659 deletions

View File

@ -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

View File

@ -15,24 +15,26 @@
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 <Arduino.h>
#include <IPAddress.h>
#include <Print.h>
#include <StreamString.h>
#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)
IPAddress::IPAddress(const IPAddress& 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;
*this = address;
}
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
{
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);
}
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);

View File

@ -15,68 +15,69 @@
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 <stdint.h>
#include <WString.h>
#include <Printable.h>
// 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 @@ public:
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;

View File

@ -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 <Arduino.h>
#include <IPv6Address.h>
#include <Print.h>
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;
}

View File

@ -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 <stdint.h>
#include <WString.h>
#include <Printable.h>
// 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

View File

@ -21,7 +21,8 @@
#ifndef STREAMSTRING_H_
#define STREAMSTRING_H_
#include "Stream.h"
#include "WString.h"
class StreamString: public Stream, public String
{

View File

@ -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
*****************

View File

@ -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) {

View File

@ -2,7 +2,6 @@
#define ESPASYNCUDP_H
#include "IPAddress.h"
#include "IPv6Address.h"
#include "Print.h"
#include "Stream.h"
#include <functional>
@ -81,10 +80,10 @@ public:
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 @@ public:
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 @@ public:
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();

View File

@ -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(")");

View File

@ -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) {

View File

@ -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 @@ public:
}
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);

View File

@ -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 IPv6Address(addr.addr);
return IPAddress(IPv6, (const uint8_t *)addr.addr, addr.zone);
}
IPAddress ETHClass::globalIPv6()
{
if(_esp_netif == NULL){
return IPAddress(IPv6);
}
static esp_ip6_addr_t addr;
if(esp_netif_get_ip6_global(_esp_netif, &addr)){
return IPAddress(IPv6);
}
return IPAddress(IPv6, (const uint8_t *)addr.addr, addr.zone);
}
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();
}

View File

@ -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);

View File

@ -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");

View File

@ -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);
}

View File

@ -26,7 +26,6 @@
#include "Print.h"
#include "IPAddress.h"
#include "IPv6Address.h"
#include "WiFiType.h"
#include "WiFiSTA.h"

View File

@ -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);
}

View File

@ -56,8 +56,8 @@ public:
IPAddress softAPSubnetMask();
uint8_t softAPSubnetCIDR();
bool softAPenableIpV6();
IPv6Address softAPIPv6();
bool softAPenableIPv6(bool enable=true);
IPAddress softAPIPv6();
const char * softAPgetHostname();
bool softAPsetHostname(const char * hostname);

View File

@ -23,6 +23,11 @@
#include <lwip/netdb.h>
#include <errno.h>
#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);
// 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();
}
}

View File

@ -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) {
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 @@ set_ant:
// ------------------------------------------------ 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 @@ set_ant:
*/
static void wifi_dns_found_callback(const char *name, const ip_addr_t *ipaddr, void *callback_arg)
{
gethostbynameParameters_t *parameters = static_cast<gethostbynameParameters_t *>(callback_arg);
if(ipaddr) {
(*reinterpret_cast<IPAddress*>(callback_arg)) = ipaddr->u_addr.ip4.addr;
if(parameters->result == 0){
memcpy(&(parameters->addr), ipaddr, sizeof(ip_addr_t));
parameters->result = 1;
}
xEventGroupSetBits(_arduino_event_group, WIFI_DNS_DONE_BIT);
} else {
parameters->result = -1;
}
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<gethostbynameParameters_t *>(param);
return dns_gethostbyname(parameters->hostname, &parameters->addr, &wifi_dns_found_callback, parameters->callback_arg);
return dns_gethostbyname_addrtype(parameters->hostname, &parameters->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))
{
err_t err = ERR_OK;
gethostbynameParameters_t params;
params.hostname = aHostname;
params.callback_arg = &aResult;
// 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<uint32_t>(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, &params);
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);
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, &params);
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;
}
}
return (uint32_t)aResult != 0;
setStatusBits(NET_DNS_IDLE_BIT);
}
if (err == ERR_OK) {
return 1;
}
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) {

View File

@ -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_ */

View File

@ -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;
}

View File

@ -42,10 +42,12 @@ public:
bool addAP(const char* ssid, const char *passphrase = NULL);
void enableIPv6(bool state);
uint8_t run(uint32_t connectTimeout=5000);
private:
std::vector<WifiAPlist_t> APlist;
bool ipv6_support;
};
#endif /* WIFICLIENTMULTI_H_ */

View File

@ -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(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
return false;
if (en) {
WiFiGenericClass::setStatusBits(STA_WANT_IP6_BIT);
} else {
WiFiGenericClass::clearStatusBits(STA_WANT_IP6_BIT);
}
return esp_netif_create_ip6_linklocal(get_esp_interface_netif(ESP_IF_WIFI_STA)) == ESP_OK;
return true;
}
/**
* Get the station interface IPv6 address.
* @return IPv6Address
* Get the station interface link-local IPv6 address.
* @return IPAddress
*/
IPv6Address WiFiSTAClass::localIPv6()
IPAddress WiFiSTAClass::localIPv6()
{
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_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);
}
/**
* Get the station interface global IPv6 address.
* @return IPAddress
*/
IPAddress WiFiSTAClass::globalIPv6()
{
static esp_ip6_addr_t addr;
if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){
return IPAddress(IPv6);
}
if(esp_netif_get_ip6_global(get_esp_interface_netif(ESP_IF_WIFI_STA), &addr)){
return IPAddress(IPv6);
}
return IPAddress(IPv6, (const uint8_t *)addr.addr, addr.zone);
}

View File

@ -93,8 +93,9 @@ public:
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();

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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,24 +101,49 @@ 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){
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)a;
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 0;
}
@ -112,19 +160,38 @@ void WiFiUDP::stop(){
}
if(udp_server == -1)
return;
if((uint32_t)multicast_ip != 0){
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));
multicast_ip = IPAddress(INADDR_ANY);
}
// 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,6 +243,10 @@ int WiFiUDP::beginPacket(const char *host, uint16_t port){
}
int WiFiUDP::endPacket(){
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;
@ -185,6 +256,19 @@ int WiFiUDP::endPacket(){
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;
}
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);