IPv6 improvements

This commit is contained in:
Stephan Hadinger 2022-12-10 13:44:16 +01:00
parent 6e6cbf0988
commit 4a32623a51
16 changed files with 75 additions and 1325 deletions

View File

@ -1,216 +0,0 @@
/*
AddrList.h - cycle through lwIP netif's ip addresses like a c++ list
Copyright (c) 2018 david gauchard. 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
*/
/*
This class allows to explore all configured IP addresses
in lwIP netifs, with that kind of c++ loop:
for (auto a: addrList)
out.printf("IF='%s' index=%d legacy=%d IPv4=%d local=%d hostname='%s' addr= %s\n",
a.iface().c_str(),
a.ifnumber(),
a.addr().isLegacy(),
a.addr().isV4(),
a.addr().isLocal(),
a.hostname().c_str(),
a.addr().toString().c_str());
This loop:
while (WiFi.status() != WL_CONNECTED()) {
Serial.print('.');
delay(500);
}
can be replaced by:
for (bool configured = false; !configured; ) {
for (auto iface: addrList)
if ((configured = !iface.addr().isLocal())
break;
Serial.print('.');
delay(500);
}
waiting for an IPv6 global address:
for (bool configured = false; !configured; ) {
for (auto iface: addrList)
if ((configured = ( !iface.addr().isV4()
&& !iface.addr().isLocal())))
break;
Serial.print('.');
delay(500);
}
waiting for an IPv6 global address, on a specific interface:
for (bool configured = false; !configured; ) {
for (auto iface: addrList)
if ((configured = ( !iface.addr().isV4()
&& !iface.addr().isLocal()
&& iface.ifnumber() == STATION_IF)))
break;
Serial.print('.');
delay(500);
}
*/
#ifndef __ADDRLIST_H
#define __ADDRLIST_H
#include <IPAddress.h>
#include <lwip/netif.h>
#include "IPAddress46.h"
#if LWIP_IPV6
#define IF_NUM_ADDRESSES (1 + LWIP_IPV6_NUM_ADDRESSES)
#else
#define IF_NUM_ADDRESSES (1)
#endif
namespace esp8266
{
namespace AddressListImplementation
{
struct netifWrapper
{
netifWrapper (netif* netif) : _netif(netif), _num(-1) {}
netifWrapper (const netifWrapper& o) : _netif(o._netif), _num(o._num) {}
netifWrapper& operator= (const netifWrapper& o)
{
_netif = o._netif;
_num = o._num;
return *this;
}
bool equal(const netifWrapper& o)
{
return _netif == o._netif && (!_netif || _num == o._num);
}
IPAddress46 addr () const { return ipFromNetifNum(); }
bool isLegacy () const { return _num == 0; }
bool isLocal () const { return addr().isLocal(); }
bool isV4 () const { return addr().isV4(); }
bool isV6 () const { return !addr().isV4(); }
String toString() const { return addr().toString(); }
// related to legacy address (_num=0, ipv4)
IPAddress46 ipv4 () const { return _netif->ip_addr; }
IPAddress46 netmask () const { return _netif->netmask; }
IPAddress46 gw () const { return _netif->gw; }
// common to all addresses of this interface
String ifname () const { return String(_netif->name[0]) + _netif->name[1]; }
const char* ifhostname () const { return _netif->hostname?: emptyString.c_str(); }
const char* ifmac () const { return (const char*)_netif->hwaddr; }
int ifnumber () const { return _netif->num; }
bool ifUp () const { return !!(_netif->flags & NETIF_FLAG_UP); }
const netif* interface () const { return _netif; }
const ip_addr_t* ipFromNetifNum () const
{
#if LWIP_IPV6
return _num ? &_netif->ip6_addr[_num - 1] : &_netif->ip_addr;
#else
return &_netif->ip_addr;
#endif
}
// lwIP interface
netif* _netif;
// address index within interface
// 0: legacy address (IPv4)
// n>0: (_num-1) is IPv6 index for netif->ip6_addr[]
int _num;
};
class AddressListIterator
{
public:
AddressListIterator (const netifWrapper& o) : netIf(o) {}
AddressListIterator (netif* netif) : netIf(netif)
{
// This constructor is called with lwIP's global netif_list, or
// nullptr. operator++() is designed to loop through _configured_
// addresses. That's why netIf's _num is initialized to -1 to allow
// returning the first usable address to AddressList::begin().
(void)operator++();
}
const netifWrapper& operator* () const { return netIf; }
const netifWrapper* operator-> () const { return &netIf; }
bool operator== (AddressListIterator& o) { return netIf.equal(*o); }
bool operator!= (AddressListIterator& o) { return !netIf.equal(*o); }
AddressListIterator operator++ (int)
{
AddressListIterator ret = *this;
(void)operator++();
return ret;
}
AddressListIterator& operator++ ()
{
while (netIf._netif)
{
if (++netIf._num == IF_NUM_ADDRESSES)
{
// all addresses from current interface were iterated,
// switching to next interface
netIf = netifWrapper(netIf._netif->next);
continue;
}
if (!ip_addr_isany(netIf.ipFromNetifNum()))
// found an initialized address
break;
}
return *this;
}
netifWrapper netIf;
};
class AddressList
{
public:
using const_iterator = const AddressListIterator;
const_iterator begin () const { return const_iterator(netif_list); }
const_iterator end () const { return const_iterator(nullptr); }
};
inline AddressList::const_iterator begin (const AddressList& a) { return a.begin(); }
inline AddressList::const_iterator end (const AddressList& a) { return a.end(); }
} // namespace AddressListImplementation
} // namespace esp8266
extern esp8266::AddressListImplementation::AddressList addrList;
#endif

View File

@ -1,331 +0,0 @@
/*
IPAddress46.cpp - IPv6 support for ESP32
This class is copied from ESP8266 Arduino framework and provides
temporary support for IPv6 on ESP32.
Copyright (C) 2021 Theo Arends and Stephan Hadinger
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
IPAddress.cpp - Base class that provides IPAddress
Copyright (c) 2011 Adrian McEwen. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is 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 <IPAddress46.h>
#include <Print.h>
#include <StreamString.h>
// Tasmota Logging
extern void AddLog(uint32_t loglevel, PGM_P formatP, ...);
enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE};
IPAddress46::IPAddress46(const IPAddress46& from)
{
ip_addr_copy(_ip, from._ip);
}
IPAddress46::IPAddress46() {
#if LWIP_IPV6
_ip = *IP6_ADDR_ANY;
#else
_ip = *IP_ADDR_ANY;
#endif
// _ip = *IP_ANY_TYPE; // lwIP's v4-or-v6 generic address
}
bool IPAddress46::isSet () const {
return !IP_IS_ANY_TYPE_VAL(_ip);
// return !ip_addr_isany(&_ip) && ((*this) != IPADDR_NONE);
}
IPAddress46::IPAddress46(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) {
setV4();
(*this)[0] = first_octet;
(*this)[1] = second_octet;
(*this)[2] = third_octet;
(*this)[3] = fourth_octet;
}
void IPAddress46::ctor32(uint32_t address) {
setV4();
v4() = address;
}
IPAddress46::IPAddress46(const uint8_t *address) {
setV4();
(*this)[0] = address[0];
(*this)[1] = address[1];
(*this)[2] = address[2];
(*this)[3] = address[3];
}
bool IPAddress46::fromString(const char *address) {
if (!fromString4(address)) {
#if LWIP_IPV6
return fromString6(address);
#else
return false;
#endif
}
return true;
}
bool IPAddress46::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;
while (*address)
{
char c = *address++;
if (c >= '0' && c <= '9')
{
acc = acc * 10 + (c - '0');
if (acc > 255) {
// Value out of [0..255] range
return false;
}
}
else if (c == '.')
{
if (dots == 3) {
// Too much dots (there must be 3 dots)
return false;
}
(*this)[dots++] = acc;
acc = 0;
}
else
{
// Invalid char
return false;
}
}
if (dots != 3) {
// Too few dots (there must be 3 dots)
return false;
}
(*this)[3] = acc;
setV4();
return true;
}
IPAddress46& IPAddress46::operator=(const uint8_t *address) {
setV4();
v4() = *reinterpret_cast<const uint32_t*>(address);
return *this;
}
IPAddress46& IPAddress46::operator=(uint32_t address) {
setV4();
v4() = address;
return *this;
}
bool IPAddress46::operator==(const uint8_t* addr) const {
return isV4() && v4() == *reinterpret_cast<const uint32_t*>(addr);
}
size_t IPAddress46::printTo(Print& p) const {
size_t n = 0;
// if (!isSet())
// return p.print(F("(IP unset)"));
#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(':');
}
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 IPAddress46::toString() const
{
StreamString sstr;
#if LWIP_IPV6
if (isV6())
sstr.reserve(40); // 8 shorts x 4 chars each + 7 colons + nullterm
else
#endif
sstr.reserve(16); // 4 bytes with 3 chars max + 3 dots + nullterm, or '(IP unset)'
printTo(sstr);
return sstr;
}
bool IPAddress46::isValid(const String& arg) {
return IPAddress46().fromString(arg);
}
bool IPAddress46::isValid(const char* arg) {
return IPAddress46().fromString(arg);
}
const IPAddress46 INADDR46_ANY; // generic "0.0.0.0" for IPv4 & IPv6
const IPAddress46 INADDR46_NONE(255,255,255,255);
void IPAddress46::clear() {
(*this) = INADDR46_ANY;
}
/**************************************/
#if LWIP_IPV6
bool IPAddress46::fromString6(const char *address) {
// TODO: test test test
uint32_t acc = 0; // Accumulator
int dots = 0, doubledots = -1;
while (*address)
{
char c = tolower(*address++);
if (isalnum(c)) {
if (c >= 'a')
c -= 'a' - '0' - 10;
acc = acc * 16 + (c - '0');
if (acc > 0xffff)
// Value out of range
return false;
}
else if (c == ':') {
if (*address == ':') {
if (doubledots >= 0)
// :: allowed once
return false;
// remember location
doubledots = dots + !!acc;
address++;
}
if (dots == 7)
// too many separators
return false;
raw6()[dots++] = PP_HTONS(acc);
acc = 0;
}
else
// Invalid char
return false;
}
if (doubledots == -1 && dots != 7)
// Too few separators
return false;
raw6()[dots++] = PP_HTONS(acc);
if (doubledots != -1) {
for (int i = dots - doubledots - 1; i >= 0; i--)
raw6()[8 - dots + doubledots + i] = raw6()[doubledots + i];
for (int i = doubledots; i < 8 - dots + doubledots; i++)
raw6()[i] = 0;
}
setV6();
return true;
}
// --------------------------------------------------
// Get host by name working for IPv6
// --------------------------------------------------
#include "lwip/dns.h"
/**
* DNS callback
* @param name
* @param ipaddr
* @param callback_arg
*/
static void wifi_dns_found_callback(const char *name, const ip_addr_t *ipaddr, void *callback_arg)
{
if(ipaddr) {
(*reinterpret_cast<IPAddress46*>(callback_arg)) = IPAddress46(ipaddr);
}
WiFiGeneric46::DnsDone();
// xEventGroupSetBits(_arduino_event_group, WIFI_DNS_DONE_BIT);
}
int WiFiGeneric46::hostByName(const char* aHostname, IPAddress46& aResult) {
ip_addr_t addr;
aResult = static_cast<uint32_t>(INADDR_NONE);
waitStatusBits(WIFI_DNS_IDLE_BIT, 16000);
clearStatusBits(WIFI_DNS_IDLE_BIT | WIFI_DNS_DONE_BIT);
err_t err = dns_gethostbyname_addrtype(aHostname, &addr, &wifi_dns_found_callback, &aResult, LWIP_DNS_ADDRTYPE_DEFAULT);
AddLog(LOG_LEVEL_DEBUG, "WIF: WiFiGeneric46::hostByName err=%i", err);
if(err == ERR_OK) {
aResult = IPAddress46(&addr);
if (!aResult.isSet()) {
#if LWIP_IPV6
aResult.setV6();
#else
aResult.setV4();
#endif
}
} 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(err == ERR_OK) {
AddLog(LOG_LEVEL_DEBUG, "WIF: WiFiGeneric46::hostByName Host: %s IP: %s", aHostname ? aHostname : "<null>", aResult.toString().c_str());
return 1;
}
return 0;
}
#endif

View File

@ -1,198 +0,0 @@
/*
IPAddress46.h - IPv6 support for ESP32
This class is copied from ESP8266 Arduino framework and provides
temporary support for IPv6 on ESP32.
Copyright (C) 2021 Theo Arends and Stephan Hadinger
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __IPADDRESS46_H
#define __IPADDRESS46_H
#include <Printable.h>
#include <WString.h>
#include <lwip/netif.h>
class IPAddress46: public Printable {
private:
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 reinterpret_cast<uint8_t*>(&v4());
}
const uint8_t* raw_address() const {
return reinterpret_cast<const uint8_t*>(&v4());
}
void ctor32 (uint32_t);
public:
// Constructors
IPAddress46();
IPAddress46(const IPAddress46& from);
IPAddress46(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet);
IPAddress46(uint32_t address) { ctor32(address); }
IPAddress46(unsigned long address) { ctor32(address); }
IPAddress46(int address) { ctor32(address); }
IPAddress46(const uint8_t *address);
bool fromString(const char *address);
bool fromString(const String &address) { return fromString(address.c_str()); }
// Overloaded cast operator to allow IPAddress46 objects to be used where a pointer
// to a four-byte uint8_t array is expected
operator uint32_t() const { return isV4()? v4(): (uint32_t)0; }
operator uint32_t() { return isV4()? v4(): (uint32_t)0; }
bool isSet () const;
operator bool () const { return isSet(); } // <-
operator bool () { return isSet(); } // <- both are needed
// generic IPv4 wrapper to uint32-view like arduino loves to see it
const uint32_t& v4() const { return ip_2_ip4(&_ip)->addr; } // for raw_address(const)
uint32_t& v4() { return ip_2_ip4(&_ip)->addr; }
bool operator==(const IPAddress46& addr) const {
return ip_addr_cmp(&_ip, &addr._ip);
}
bool operator!=(const IPAddress46& 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 isV4()? *(raw_address() + index): 0;
}
uint8_t& operator[](int index) {
setV4();
return *(raw_address() + index);
}
// Overloaded copy operators to allow initialisation of IPAddress46 objects from other types
IPAddress46& operator=(const uint8_t *address);
IPAddress46& operator=(uint32_t address);
IPAddress46& operator=(const IPAddress46&) = default;
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 UDP46;
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); }
#if LWIP_IPV6
IPAddress46(const ip_addr_t& lwip_addr) { ip_addr_copy(_ip, lwip_addr); }
IPAddress46(const ip_addr_t* lwip_addr) { ip_addr_copy(_ip, *lwip_addr); }
IPAddress46& operator=(const ip_addr_t& lwip_addr) { ip_addr_copy(_ip, lwip_addr); return *this; }
IPAddress46& operator=(const ip_addr_t* lwip_addr) { ip_addr_copy(_ip, *lwip_addr); return *this; }
uint16_t* raw6()
{
setV6();
return reinterpret_cast<uint16_t*>(ip_2_ip6(&_ip));
}
const uint16_t* raw6() const
{
return isV6()? reinterpret_cast<const uint16_t*>(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); }
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() { }
#endif
protected:
bool fromString4(const char *address);
};
// --------------------------------------------------------------------------------
// We need to create a subclass of WiFiGenericClass to access protected methods
// --------------------------------------------------------------------------------
#include "WiFiGeneric.h"
class WiFiGeneric46 : public WiFiGenericClass
{
public:
WiFiGeneric46() {};
static int hostByName(const char *aHostname, IPAddress46 &aResult);
static void DnsDone(void) { setStatusBits(WIFI_DNS_DONE_BIT); };
};
#endif // __IPADDRESS46_H

View File

@ -1,93 +0,0 @@
/*
* Udp.cpp: Library to send/receive UDP packets.
*
* NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these)
* 1) UDP does not guarantee the order in which assembled UDP packets are received. This
* might not happen often in practice, but in larger network topologies, a UDP
* packet can be received out of sequence.
* 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being
* aware of it. Again, this may not be a concern in practice on small local networks.
* For more information, see http://www.cafeaulait.org/course/week12/35.html
*
* MIT License:
* Copyright (c) 2008 Bjoern Hartmann
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* bjoern@cs.stanford.edu 12/30/2008
*/
#ifndef udp46_h
#define udp46_h
#include <Stream.h>
#include <IPAddress46.h>
class UDP46: public Stream
{
public:
virtual uint8_t begin(uint16_t) =0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use
virtual uint8_t beginMulticast(IPAddress46, uint16_t) { return 0; } // initialize, start listening on specified multicast IP address and port. Returns 1 if successful, 0 on failure
virtual void stop() =0; // Finish with the UDP socket
// Sending UDP packets
// Start building up a packet to send to the remote host specific in ip and port
// Returns 1 if successful, 0 if there was a problem with the supplied IP address or port
virtual int beginPacket(IPAddress46 ip, uint16_t port) =0;
// Start building up a packet to send to the remote host specific in host and port
// Returns 1 if successful, 0 if there was a problem resolving the hostname or port
virtual int beginPacket(const char *host, uint16_t port) =0;
// Finish off this packet and send it
// Returns 1 if the packet was sent successfully, 0 if there was an error
virtual int endPacket() =0;
// Write a single byte into the packet
virtual size_t write(uint8_t) =0;
// Write size bytes from buffer into the packet
virtual size_t write(const uint8_t *buffer, size_t size) =0;
// Start processing the next available incoming packet
// Returns the size of the packet in bytes, or 0 if no packets are available
virtual int parsePacket() =0;
// Number of bytes remaining in the current packet
virtual int available() =0;
// Read a single byte from the current packet
virtual int read() =0;
// Read up to len bytes from the current packet and place them into buffer
// Returns the number of bytes read, or 0 if none are available
virtual int read(unsigned char* buffer, size_t len) =0;
// Read up to len characters from the current packet and place them into buffer
// Returns the number of characters read, or 0 if none are available
virtual int read(char* buffer, size_t len) =0;
// Return the next byte from the current packet without moving on to the next byte
virtual int peek() =0;
virtual void flush() =0; // Finish reading the current packet
// Return the IP address of the host who sent the current incoming packet
virtual IPAddress46 remoteIP() =0;
// Return the port of the host who sent the current incoming packet
virtual uint16_t remotePort() =0;
protected:
uint8_t* rawIPAddress(IPAddress46& addr)
{
return addr.raw_address();
}
};
#endif

View File

@ -1,335 +0,0 @@
/*
Udp.cpp - UDP class for Raspberry Pi
Copyright (c) 2016 Hristo Gochkov 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 "WiFiUdp46.h"
#include <lwip/sockets.h>
#include <lwip/netdb.h>
#include <errno.h>
#undef write
#undef read
// Tasmota Logging
extern void AddLog(uint32_t loglevel, PGM_P formatP, ...);
enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE};
WiFiUDP46::WiFiUDP46()
: udp_server(-1)
, server_port(0)
, remote_port(0)
, tx_buffer(0)
, tx_buffer_len(0)
, rx_buffer(0)
{}
WiFiUDP46::~WiFiUDP46(){
stop();
}
uint8_t WiFiUDP46::begin(IPAddress46 address, uint16_t port){
stop();
server_port = port;
tx_buffer = new char[1460];
if(!tx_buffer){
log_e("could not create tx buffer: %d", errno);
return 0;
}
#if LWIP_IPV6
if ((udp_server=socket(AF_INET6, 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;
}
// AddLog(LOG_LEVEL_DEBUG, "WiFiUDP46::begin socket called");
int yes = 1;
if (setsockopt(udp_server,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes)) < 0) {
log_e("could not set socket option: %d", errno);
stop();
return 0;
}
//AddLog(LOG_LEVEL_DEBUG, "WiFiUDP46::begin setsockopt called");
struct sockaddr* sock_addr = NULL;
size_t sock_size = 0;
struct sockaddr_in addr;
#if LWIP_IPV6
struct sockaddr_in6 addr6;
if (address.isV6()) {
// AddLog(LOG_LEVEL_DEBUG, "WiFiUDP46::begin set IPv6");
memset((char *) &addr6, 0, sizeof(sockaddr_in6));
addr6.sin6_len = sizeof(sockaddr_in6);
addr6.sin6_family = AF_INET6;
addr6.sin6_port = htons(server_port);
addr6.sin6_addr = *(in6_addr*)(ip_addr_t*)address;
addr6.sin6_addr = in6addr_any;
addr6.sin6_flowinfo = 0;
sock_addr = (struct sockaddr*)&addr6;
sock_size = sizeof(sockaddr_in6);
// AddLog(LOG_LEVEL_DEBUG, "SOCK_ADDR_TYPE_MATCH(name, sock)=%i", SOCK_ADDR_TYPE_MATCH(sock_addr, sock_size));
} else
#endif
if (1) {
memset((char *) &addr, 0, sizeof(sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(server_port);
addr.sin_addr.s_addr = (in_addr_t)address;
sock_addr = (struct sockaddr*)&addr;
sock_size = sizeof(sockaddr_in);
}
//AddLog(LOG_LEVEL_DEBUG, "WiFiUDP46::begin udp_server=%p sock_addr=%p sock_size=%i", udp_server, sock_addr, sock_size);
if(bind(udp_server , sock_addr, sock_size) == -1){
AddLog(LOG_LEVEL_DEBUG, "WIF: WiFiUDP46::begin bind error=%o", errno);
log_e("could not bind socket: %d", errno);
stop();
return 0;
}
fcntl(udp_server, F_SETFL, O_NONBLOCK);
return 1;
}
uint8_t WiFiUDP46::begin(uint16_t p){
return begin(IPAddress46(), p);
}
uint8_t WiFiUDP46::beginMulticast(IPAddress46 a, uint16_t p){
if(begin(IPAddress46(), p)){
if(!ip_addr_isany((ip_addr_t*)a)){
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 0;
}
void WiFiUDP46::stop(){
if(tx_buffer){
delete[] tx_buffer;
tx_buffer = NULL;
}
tx_buffer_len = 0;
if(rx_buffer){
cbuf *b = rx_buffer;
rx_buffer = NULL;
delete b;
}
if(udp_server == -1)
return;
if(!ip_addr_isany((ip_addr_t*)multicast_ip)){
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = (in_addr_t)multicast_ip;
mreq.imr_interface.s_addr = (in_addr_t)0;
#if LWIP_IPV6
setsockopt(udp_server, IPPROTO_IPV6, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
#else
setsockopt(udp_server, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq));
#endif
multicast_ip = IPAddress46(INADDR_ANY);
}
close(udp_server);
udp_server = -1;
}
int WiFiUDP46::beginMulticastPacket(){
if(!server_port || multicast_ip == IPAddress46(INADDR_ANY))
return 0;
remote_ip = multicast_ip;
remote_port = server_port;
return beginPacket();
}
int WiFiUDP46::beginPacket(){
if(!remote_port)
return 0;
// allocate tx_buffer if is necessary
if(!tx_buffer){
tx_buffer = new char[1460];
if(!tx_buffer){
log_e("could not create tx buffer: %d", errno);
return 0;
}
}
tx_buffer_len = 0;
// check whereas socket is already open
if (udp_server != -1)
return 1;
if ((udp_server=socket(AF_INET, SOCK_DGRAM, 0)) == -1){
log_e("could not create socket: %d", errno);
return 0;
}
fcntl(udp_server, F_SETFL, O_NONBLOCK);
return 1;
}
int WiFiUDP46::beginPacket(IPAddress46 ip, uint16_t port){
remote_ip = ip;
remote_port = port;
return beginPacket();
}
int WiFiUDP46::beginPacket(const char *host, uint16_t port){
struct hostent *server;
server = gethostbyname(host);
if (server == NULL){
log_e("could not get host from dns: %d", errno);
return 0;
}
return beginPacket(IPAddress46((const uint8_t *)(server->h_addr_list[0])), port);
}
int WiFiUDP46::endPacket(){
if (remote_ip.isV4()) {
struct sockaddr_in recipient;
recipient.sin_len = sizeof(sockaddr_in);
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_len = sizeof(sockaddr_in6);
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);
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;
}
size_t WiFiUDP46::write(uint8_t data){
if(tx_buffer_len == 1460){
endPacket();
tx_buffer_len = 0;
}
tx_buffer[tx_buffer_len++] = data;
return 1;
}
size_t WiFiUDP46::write(const uint8_t *buffer, size_t size){
size_t i;
for(i=0;i<size;i++)
write(buffer[i]);
return i;
}
int WiFiUDP46::parsePacket(){
if(rx_buffer)
return 0;
struct sockaddr_in si_other;
int slen = sizeof(si_other) , len;
char * buf = new char[1460];
if(!buf){
return 0;
}
if ((len = recvfrom(udp_server, buf, 1460, MSG_DONTWAIT, (struct sockaddr *) &si_other, (socklen_t *)&slen)) == -1){
delete[] buf;
if(errno == EWOULDBLOCK){
return 0;
}
log_e("could not receive data: %d", errno);
return 0;
}
remote_ip = IPAddress46(si_other.sin_addr.s_addr);
remote_port = ntohs(si_other.sin_port);
if (len > 0) {
rx_buffer = new cbuf(len);
rx_buffer->write(buf, len);
}
delete[] buf;
return len;
}
int WiFiUDP46::available(){
if(!rx_buffer) return 0;
return rx_buffer->available();
}
int WiFiUDP46::read(){
if(!rx_buffer) return -1;
int out = rx_buffer->read();
if(!rx_buffer->available()){
cbuf *b = rx_buffer;
rx_buffer = 0;
delete b;
}
return out;
}
int WiFiUDP46::read(unsigned char* buffer, size_t len){
return read((char *)buffer, len);
}
int WiFiUDP46::read(char* buffer, size_t len){
if(!rx_buffer) return 0;
int out = rx_buffer->read(buffer, len);
if(!rx_buffer->available()){
cbuf *b = rx_buffer;
rx_buffer = 0;
delete b;
}
return out;
}
int WiFiUDP46::peek(){
if(!rx_buffer) return -1;
return rx_buffer->peek();
}
void WiFiUDP46::flush(){
if(!rx_buffer) return;
cbuf *b = rx_buffer;
rx_buffer = 0;
delete b;
}
IPAddress46 WiFiUDP46::remoteIP(){
return remote_ip;
}
uint16_t WiFiUDP46::remotePort(){
return remote_port;
}

View File

@ -1,77 +0,0 @@
/*
* Udp.cpp: Library to send/receive UDP packets.
*
* NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these)
* 1) UDP does not guarantee the order in which assembled UDP packets are received. This
* might not happen often in practice, but in larger network topologies, a UDP
* packet can be received out of sequence.
* 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being
* aware of it. Again, this may not be a concern in practice on small local networks.
* For more information, see http://www.cafeaulait.org/course/week12/35.html
*
* MIT License:
* Copyright (c) 2008 Bjoern Hartmann
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* bjoern@cs.stanford.edu 12/30/2008
*/
#ifndef _WIFIUDP46_H_
#define _WIFIUDP46_H_
#include <Arduino.h>
#include <Udp46.h>
#include <cbuf.h>
class WiFiUDP46 : public UDP46 {
private:
int udp_server;
IPAddress46 multicast_ip;
IPAddress46 remote_ip;
uint16_t server_port;
uint16_t remote_port;
char * tx_buffer;
size_t tx_buffer_len;
cbuf * rx_buffer;
public:
WiFiUDP46();
~WiFiUDP46();
uint8_t begin(IPAddress46 a, uint16_t p);
uint8_t begin(uint16_t p);
uint8_t beginMulticast(IPAddress46 a, uint16_t p);
void stop();
int beginMulticastPacket();
int beginPacket();
int beginPacket(IPAddress46 ip, uint16_t port);
int beginPacket(const char *host, uint16_t port);
int endPacket();
size_t write(uint8_t);
size_t write(const uint8_t *buffer, size_t size);
int parsePacket();
int available();
int read();
int read(unsigned char* buffer, size_t len);
int read(char* buffer, size_t len);
int peek();
void flush();
IPAddress46 remoteIP();
uint16_t remotePort();
};
#endif /* _WIFIUDP46_H_ */

View File

@ -137,8 +137,6 @@ typedef int SerialConfig;
//#define PortUdp_writestr(log_data) PortUdp.write((const uint8_t *)(log_data), strlen(log_data))
#define PortUdp_write(log_data, n) PortUdp.write((const uint8_t *)(log_data), n)
#undef LWIP_IPV6
#define REASON_DEFAULT_RST 0 // "Power on" normal startup by power on
#define REASON_WDT_RST 1 // "Hardware Watchdog" hardware watch dog reset
#define REASON_EXCEPTION_RST 2 // "Exception" exception reset, GPIO status wont change

View File

@ -15,7 +15,7 @@
#include <Arduino.h>
#include <WiFiGeneric.h>
#include <WiFiUdp46.h>
#include <WiFiUdp.h>
#include "be_mapping.h"
// Tasmota Logging
@ -25,15 +25,15 @@ enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_D
extern "C" {
// init()
WiFiUDP46 *be_udp_init_ntv(void) {
return new WiFiUDP46();
WiFiUDP *be_udp_init_ntv(void) {
return new WiFiUDP();
}
int32_t be_udp_init(struct bvm *vm) {
return be_call_c_func(vm, (void*) &be_udp_init_ntv, "+.p", "");
}
// deinit()
void *be_udp_deinit_ntv(WiFiUDP46 *udp) {
void *be_udp_deinit_ntv(WiFiUDP *udp) {
if (udp != nullptr) { delete udp; }
return nullptr;
}
@ -42,8 +42,8 @@ extern "C" {
}
// udp.begin(address:string, port:int) -> bool
int32_t be_udp_begin_ntv(WiFiUDP46 *udp, int32_t port) {
IPAddress46 addr;
int32_t be_udp_begin_ntv(WiFiUDP *udp, int32_t port) {
IPAddress addr;
// AddLog(LOG_LEVEL_DEBUG, "BRY: udp.begin listening to '%s'", addr.toString().c_str());
return udp->begin(addr, port);
}
@ -57,7 +57,7 @@ extern "C" {
}
// udp.stop() -> nil
void be_udp_stop_ntv(WiFiUDP46 *udp) {
void be_udp_stop_ntv(WiFiUDP *udp) {
udp->stop();
}
int32_t be_udp_stop(struct bvm *vm) {
@ -65,21 +65,21 @@ extern "C" {
}
// udp.begin_multicast(address:string, port:int) -> nil
int32_t be_udp_begin_mcast_ntv(WiFiUDP46 *udp, const char *host, int32_t port) {
IPAddress46 addr;
if(!WiFiGeneric46::hostByName(host, addr)){
int32_t be_udp_begin_mcast_ntv(WiFiUDP *udp, const char *host, int32_t port) {
IPAddress addr;
if(!WiFiGenericClass::hostByName(host, addr)){
return 0;
}
return udp->WiFiUDP46::beginMulticast(addr, port);
return udp->WiFiUDP::beginMulticast(addr, port);
}
int32_t be_udp_begin_mcast(struct bvm *vm) {
return be_call_c_func(vm, (void*) &be_udp_begin_mcast_ntv, "b", ".si");
}
// udp.send(address:string, port:int, payload:bytes) -> bool
int32_t be_udp_send_ntv(WiFiUDP46 *udp, const char *host, int32_t port, const uint8_t* buf, int32_t len) {
IPAddress46 addr;
if (!WiFiGeneric46::hostByName(host, addr)){
int32_t be_udp_send_ntv(WiFiUDP *udp, const char *host, int32_t port, const uint8_t* buf, int32_t len) {
IPAddress addr;
if (!WiFiGenericClass::hostByName(host, addr)){
return 0;
}
// AddLog(LOG_LEVEL_DEBUG, "BRY: udp.begin got host '%s'", addr.toString().c_str());
@ -94,7 +94,7 @@ extern "C" {
}
// udp.send_multicast(payload:bytes) -> bool
int32_t be_udp_send_mcast_ntv(WiFiUDP46 *udp, const uint8_t* buf, int32_t len) {
int32_t be_udp_send_mcast_ntv(WiFiUDP *udp, const uint8_t* buf, int32_t len) {
if (!udp->beginMulticastPacket()) { return 0; }
int bw = udp->write(buf, len);
if (!bw) { return 0; }
@ -107,7 +107,7 @@ extern "C" {
// udp.read() -> bytes or nil
int32_t be_udp_read(struct bvm *vm) {
WiFiUDP46 *udp = (WiFiUDP46*) be_convert_single_elt(vm, 1, NULL, NULL);
WiFiUDP *udp = (WiFiUDP*) be_convert_single_elt(vm, 1, NULL, NULL);
if (udp->parsePacket()) {
int btr = udp->available(); // btr contains the size of bytes_to_read
@ -135,7 +135,7 @@ extern "C" {
int32_t btr2 = udp->read(buf, btr);
// set remotet ip
IPAddress46 remote_ip = udp->remoteIP();
IPAddress remote_ip = udp->remoteIP();
be_pushstring(vm, remote_ip.toString().c_str());
be_setmember(vm, 1, "remote_ip");
be_pop(vm, 1);

View File

@ -405,6 +405,12 @@
#define WIFI_SOFT_AP_CHANNEL 1 // Soft Access Point Channel number between 1 and 13 as used by Wi-Fi Manager web GUI
#define USE_IMPROV // Add support for IMPROV serial protocol as used by esp-web-tools (+2k code)
// -- IPv6 support -------------------------------
// #define USE_IPV6 // Enable IPv6 support (if the underlying esp-idf is also configured to support it)
// Code size increase:
// ESP8266: tbd
// ESP32: tbd
// -- ESP-NOW -------------------------------------
//#define USE_TASMESH // Enable Tasmota Mesh using ESP-NOW (+11k code)

View File

@ -32,6 +32,13 @@
#include "include/i18n.h" // Language support configured by my_user_config.h
#include "include/tasmota_template.h" // Hardware configuration
// ------------------------------------------------------------------------------------------
// If IPv6 is not support by the underlying esp-idf, disable it
// ------------------------------------------------------------------------------------------
#if !LWIP_IPV6
#undef USE_IPV6
#endif
// Libraries
#include <ESP8266HTTPClient.h> // Ota
#include <ESP8266httpUpdate.h> // Ota
@ -494,7 +501,7 @@ void setup(void) {
#ifdef ESP32
AddLog(LOG_LEVEL_INFO, PSTR("HDW: %s %s"), GetDeviceHardware().c_str(),
FoundPSRAM() ? (CanUsePSRAM() ? "(PSRAM)" : "(PSRAM disabled)") : "" );
AddLog(LOG_LEVEL_DEBUG, PSTR("HDW: FoundPSRAM=%i CanUsePSRAM=%i"), FoundPSRAM(), CanUsePSRAM());
// AddLog(LOG_LEVEL_DEBUG, PSTR("HDW: FoundPSRAM=%i CanUsePSRAM=%i"), FoundPSRAM(), CanUsePSRAM());
#if !defined(HAS_PSRAM_FIX)
if (FoundPSRAM() && !CanUsePSRAM()) {
AddLog(LOG_LEVEL_INFO, PSTR("HDW: PSRAM is disabled, requires specific compilation on this hardware (see doc)"));

View File

@ -802,24 +802,24 @@ void CmndStatus(void)
}
if ((0 == payload) || (5 == payload)) {
#if LWIP_IPV6
#ifdef USE_IPV6
if (5 == payload) { WifiDumpAddressesIPv6(); }
#endif // LWIP_IPV6
#endif // USE_IPV6
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS5_NETWORK "\":{\"" D_CMND_HOSTNAME "\":\"%s\",\""
D_CMND_IPADDRESS "\":\"%_I\",\"" D_JSON_GATEWAY "\":\"%_I\",\"" D_JSON_SUBNETMASK "\":\"%_I\",\""
D_JSON_DNSSERVER "1\":\"%_I\",\"" D_JSON_DNSSERVER "2\":\"%_I\",\""
D_JSON_MAC "\":\"%s\""
#if LWIP_IPV6
#ifdef USE_IPV6
",\"" D_JSON_IP6_GLOBAL "\":\"%s\",\"" D_JSON_IP6_LOCAL "\":\"%s\""
#endif // LWIP_IPV6
#endif // USE_IPV6
),
TasmotaGlobal.hostname,
(uint32_t)WiFi.localIP(), Settings->ipv4_address[1], Settings->ipv4_address[2],
Settings->ipv4_address[3], Settings->ipv4_address[4],
WiFi.macAddress().c_str()
#if LWIP_IPV6
#ifdef USE_IPV6
,WifiGetIPv6().c_str(), WifiGetIPv6LinkLocal().c_str()
#endif // LWIP_IPV6
#endif // USE_IPV6
);
#ifdef USE_TASMESH
ResponseAppend_P(PSTR(",\"SoftAPMac\":\"%s\""), WiFi.softAPmacAddress().c_str());
@ -830,17 +830,17 @@ void CmndStatus(void)
D_JSON_DNSSERVER "1\":\"%_I\",\"" D_JSON_DNSSERVER "2\":\"%_I\",\""
D_JSON_MAC "\":\"%s\""
#if LWIP_IPV6
#ifdef USE_IPV6
",\"" D_JSON_IP6_GLOBAL "\":\"%s\",\"" D_JSON_IP6_LOCAL "\":\"%s\""
#endif // LWIP_IPV6
#endif // USE_IPV6
"}"),
EthernetHostname(),
(uint32_t)EthernetLocalIP(), Settings->eth_ipv4_address[1], Settings->eth_ipv4_address[2],
Settings->eth_ipv4_address[3], Settings->eth_ipv4_address[4],
EthernetMacAddress().c_str()
#if LWIP_IPV6
#ifdef USE_IPV6
,EthernetGetIPv6().c_str(), EthernetGetIPv6LinkLocal().c_str()
#endif // LWIP_IPV6
#endif // USE_IPV6
);
#endif // USE_ETHERNET
ResponseAppend_P(PSTR(",\"" D_CMND_WEBSERVER "\":%d,\"HTTP_API\":%d,\"" D_CMND_WIFICONFIG "\":%d,\"" D_CMND_WIFIPOWER "\":%s}}"),

View File

@ -41,13 +41,6 @@ const uint8_t WIFI_CHECK_SEC = 20; // seconds
const uint8_t WIFI_RETRY_OFFSET_SEC = WIFI_RETRY_SECONDS; // seconds
#include <ESP8266WiFi.h> // Wifi, MQTT, Ota, WifiManager
#if LWIP_IPV6
#ifdef ESP8266
#include <AddrList.h> // IPv6 DualStack
#else
#include <AddrList46.h> // IPv6 DualStack
#endif
#endif // LWIP_IPV6=1
int WifiGetRssiAsQuality(int rssi) {
int quality = 0;
@ -213,7 +206,7 @@ void WifiBegin(uint8_t flag, uint8_t channel) {
#endif // USE_EMULATION
WiFi.persistent(false); // Solve possible wifi init errors (re-add at 6.2.1.16 #4044, #4083)
#if LWIP_IPV6 && defined(ESP32)
#if defined(USE_IPV6) && defined(ESP32)
WiFi.IPv6(true);
#endif
@ -465,7 +458,7 @@ void WifiSetState(uint8_t state)
}
}
#if LWIP_IPV6
#ifdef USE_IPV6
//
// Scan through all interfaces to find a global or local IPv6 address
// Arg:
@ -476,8 +469,8 @@ static String WifiFindIPv6(bool is_local, const char * if_type = "st") {
if (intf->name[0] == if_type[0] && intf->name[1] == if_type[1]) {
for (uint32_t i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
ip_addr_t *ipv6 = &intf->ip6_addr[i];
if (IP_IS_V6_VAL(*ipv6) && !ip_addr_isloopback(ipv6) && ((bool)ip_addr_islinklocal(ipv6) == is_local)) {
return IPAddress46(ipv6).toString();
if (IP_IS_V6_VAL(*ipv6) && !ip_addr_isloopback(ipv6) && !ip_addr_isany(ipv6) && ((bool)ip_addr_islinklocal(ipv6) == is_local)) {
return IPAddress(ipv6).toString();
}
}
}
@ -510,33 +503,28 @@ void CreateLinkLocalIPv6(void)
void WifiDumpAddressesIPv6(void)
{
for (netif* intf = netif_list; intf != nullptr; intf = intf->next) {
if (!ip_addr_isany_val(intf->ip_addr)) AddLog(LOG_LEVEL_DEBUG, "WIF: '%c%c' IPv4 %s", intf->name[0], intf->name[1], IPAddress46(intf->ip_addr).toString().c_str());
if (!ip_addr_isany_val(intf->ip_addr)) AddLog(LOG_LEVEL_DEBUG, "WIF: '%c%c' IPv4 %s", intf->name[0], intf->name[1], IPAddress(intf->ip_addr).toString().c_str());
for (uint32_t i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
if (!ip_addr_isany_val(intf->ip6_addr[i]))
AddLog(LOG_LEVEL_DEBUG, "WIF: '%c%c' IPv6 %s %s", intf->name[0], intf->name[1],
IPAddress46(intf->ip6_addr[i]).toString().c_str(),
IPAddress(intf->ip6_addr[i]).toString().c_str(),
ip_addr_islinklocal(&intf->ip6_addr[i]) ? "local" : "");
}
}
}
#endif // LWIP_IPV6=1
#endif // USE_IPV6
// Check to see if we have any routable IP address
bool WifiHasIP(void) {
#if LWIP_IPV6
for (auto a : addrList) {
if(!ip_addr_isloopback((ip_addr_t*)a.addr()) && !a.isLocal()) {
return true;
}
}
return false;
#ifdef USE_IPV6
return !WiFi.localIP().isAny();
#else
return (uint32_t)WiFi.localIP() != 0;
#endif
#endif // USE_IPV6
}
void WifiCheckIp(void) {
#if LWIP_IPV6
#ifdef USE_IPV6
if (WL_CONNECTED == WiFi.status()) {
if (!Wifi.ipv6_local_link_called) {
WiFi.enableIpV6();
@ -545,7 +533,7 @@ void WifiCheckIp(void) {
}
}
#endif
#endif // USE_IPV6
if ((WL_CONNECTED == WiFi.status()) && WifiHasIP()) {
WifiSetState(1);
@ -1081,24 +1069,23 @@ uint64_t WifiGetNtp(void) {
// Respond to some Arduino/esp-idf events for better IPv6 support
// --------------------------------------------------------------------------------
#ifdef ESP32
#include "IPAddress46.h"
// typedef void (*WiFiEventSysCb)(arduino_event_t *event);
void WifiEvents(arduino_event_t *event) {
switch (event->event_id) {
#if LWIP_IPV6
#ifdef USE_IPV6
case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
case ARDUINO_EVENT_ETH_GOT_IP6:
{
ip_addr_t ip_addr6;
ip_addr_copy_from_ip6(ip_addr6, event->event_info.got_ip6.ip6_info.ip);
IPAddress46 addr(ip_addr6);
IPAddress addr(ip_addr6);
AddLog(LOG_LEVEL_DEBUG, PSTR("%s: IPv6 %s %s"),
event->event_id == ARDUINO_EVENT_ETH_GOT_IP6 ? "ETH" : "WIF",
addr.isLocal() ? PSTR("Local") : PSTR("Global"), addr.toString().c_str());
}
break;
#endif // LWIP_IPV6
#endif // USE_IPV6
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
case ARDUINO_EVENT_ETH_GOT_IP:
{

View File

@ -610,7 +610,7 @@ void StartWebserver(int type, IPAddress ipweb)
Webserver->begin(); // Web server start
}
if (Web.state != type) {
#if LWIP_IPV6
#ifdef USE_IPV6
String ipv6_addr = WifiGetIPv6();
if (ipv6_addr!="") {
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %_I and IPv6 global address %s "),
@ -622,7 +622,7 @@ void StartWebserver(int type, IPAddress ipweb)
#else
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %_I"),
NetworkHostname(), (Mdns.begun) ? PSTR(".local") : "", (uint32_t)ipweb);
#endif // LWIP_IPV6 = 1
#endif // USE_IPV6
TasmotaGlobal.rules_flag.http_init = 1;
Web.state = type;
}
@ -2359,7 +2359,7 @@ void HandleInformation(void)
int32_t rssi = WiFi.RSSI();
WSContentSend_P(PSTR("}1" D_AP "%d " D_SSID " (" D_RSSI ")}2%s (%d%%, %d dBm) 11%c"), Settings->sta_active +1, HtmlEscape(SettingsText(SET_STASSID1 + Settings->sta_active)).c_str(), WifiGetRssiAsQuality(rssi), rssi, pgm_read_byte(&kWifiPhyMode[WiFi.getPhyMode() & 0x3]) );
WSContentSend_P(PSTR("}1" D_HOSTNAME "}2%s%s"), TasmotaGlobal.hostname, (Mdns.begun) ? PSTR(".local") : "");
#if LWIP_IPV6
#ifdef USE_IPV6
String ipv6_addr = WifiGetIPv6();
if (ipv6_addr != "") {
WSContentSend_P(PSTR("}1 IPv6 Global (wifi)}2%s"), ipv6_addr.c_str());
@ -2368,7 +2368,7 @@ void HandleInformation(void)
if (ipv6_addr != "") {
WSContentSend_P(PSTR("}1 IPv6 Local (wifi)}2%s"), ipv6_addr.c_str());
}
#endif // LWIP_IPV6 = 1
#endif // USE_IPV6
if (static_cast<uint32_t>(WiFi.localIP()) != 0) {
WSContentSend_P(PSTR("}1" D_MAC_ADDRESS "}2%s"), WiFi.macAddress().c_str());
WSContentSend_P(PSTR("}1" D_IP_ADDRESS " (wifi)}2%_I"), (uint32_t)WiFi.localIP());
@ -2387,7 +2387,7 @@ void HandleInformation(void)
WSContentSend_P(PSTR("}1<hr/>}2<hr/>"));
}
WSContentSend_P(PSTR("}1" D_HOSTNAME "}2%s%s"), EthernetHostname(), (Mdns.begun) ? PSTR(".local") : "");
#if LWIP_IPV6
#ifdef USE_IPV6
String ipv6_eth_addr = EthernetGetIPv6();
if (ipv6_eth_addr != "") {
WSContentSend_P(PSTR("}1 IPv6 Global (eth)}2%s"), ipv6_eth_addr.c_str());
@ -2396,7 +2396,7 @@ void HandleInformation(void)
if (ipv6_eth_addr != "") {
WSContentSend_P(PSTR("}1 IPv6 Local (eth)}2%s"), ipv6_eth_addr.c_str());
}
#endif // LWIP_IPV6 = 1
#endif // USE_IPV6
WSContentSend_P(PSTR("}1" D_MAC_ADDRESS "}2%s"), EthernetMacAddress().c_str());
WSContentSend_P(PSTR("}1" D_IP_ADDRESS " (eth)}2%_I"), (uint32_t)EthernetLocalIP());
}

View File

@ -971,10 +971,10 @@ void MqttConnected(void) {
if (static_cast<uint32_t>(WiFi.localIP()) != 0) {
ResponseAppend_P(PSTR(",\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%_I\""),
TasmotaGlobal.hostname, (uint32_t)WiFi.localIP());
#if LWIP_IPV6
#ifdef USE_IPV6
ResponseAppend_P(PSTR(",\"" D_JSON_IP6_GLOBAL "\":\"%s\""), WifiGetIPv6().c_str());
ResponseAppend_P(PSTR(",\"" D_JSON_IP6_LOCAL "\":\"%s\""), WifiGetIPv6LinkLocal().c_str());
#endif // LWIP_IPV6 = 1
#endif // USE_IPV6
}
#if defined(ESP32) && CONFIG_IDF_TARGET_ESP32 && defined(USE_ETHERNET)
if (static_cast<uint32_t>(EthernetLocalIP()) != 0) {

View File

@ -214,7 +214,7 @@ extern "C" {
if (Settings->flag4.network_wifi) {
int32_t rssi = WiFi.RSSI();
bool show_rssi = false;
#if LWIP_IPV6
#ifdef USE_IPV6
String ipv6_addr = WifiGetIPv6();
if (ipv6_addr != "") {
be_map_insert_str(vm, "ip6", ipv6_addr.c_str());
@ -225,10 +225,10 @@ extern "C" {
be_map_insert_str(vm, "ip6local", ipv6_addr.c_str());
show_rssi = true;
}
#endif
#endif // USE_IPV6
if (static_cast<uint32_t>(WiFi.localIP()) != 0) {
be_map_insert_str(vm, "mac", WiFi.macAddress().c_str());
be_map_insert_str(vm, "ip", IPAddress46((uint32_t)WiFi.localIP()).toString().c_str()); // quick fix for IPAddress bug
be_map_insert_str(vm, "ip", IPAddress((uint32_t)WiFi.localIP()).toString().c_str()); // quick fix for IPAddress bug
show_rssi = true;
}
if (show_rssi) {
@ -252,9 +252,9 @@ extern "C" {
#ifdef USE_ETHERNET
if (static_cast<uint32_t>(EthernetLocalIP()) != 0) {
be_map_insert_str(vm, "mac", EthernetMacAddress().c_str());
be_map_insert_str(vm, "ip", IPAddress46((uint32_t)EthernetLocalIP()).toString().c_str()); // quick fix for IPAddress bug
be_map_insert_str(vm, "ip", IPAddress((uint32_t)EthernetLocalIP()).toString().c_str()); // quick fix for IPAddress bug
}
#if LWIP_IPV6
#ifdef USE_IPV6
String ipv6_addr = EthernetGetIPv6();
if (ipv6_addr != "") {
be_map_insert_str(vm, "ip6", ipv6_addr.c_str());
@ -263,8 +263,8 @@ extern "C" {
if (ipv6_addr != "") {
be_map_insert_str(vm, "ip6local", ipv6_addr.c_str());
}
#endif
#endif
#endif // USE_IPV6
#endif // USE_ETHERNET
be_pop(vm, 1);
be_return(vm);
}

View File

@ -94,9 +94,9 @@ void EthernetEvent(arduino_event_t *event) {
break;
case ARDUINO_EVENT_ETH_CONNECTED:
#if LWIP_IPV6
#ifdef USE_IPV6
ETH.enableIpV6(); // enable Link-Local
#endif
#endif // USE_IPV6
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_ETH D_CONNECTED " at %dMbps%s, Mac %s, Hostname %s"),
ETH.linkSpeed(), (ETH.fullDuplex()) ? " Full Duplex" : "",
ETH.macAddress().c_str(), eth_hostname
@ -143,6 +143,7 @@ void EthernetSetIp(void) {
Settings->eth_ipv4_address[4]); // IPAddress dns2
}
#ifdef USE_IPV6
// Returns only IPv6 global address (no loopback and no link-local)
String EthernetGetIPv6(void)
{
@ -153,6 +154,7 @@ String EthernetGetIPv6LinkLocal(void)
{
return WifiFindIPv6(true, "en");
}
#endif // USE_IPV6
void EthernetInit(void) {
if (!Settings->flag4.network_ethernet) { return; }