IPv6 improvements (#17268)

* IPv6 improvements

* Fix esp8266 compilation

* grrr

* Fix compilation issue

* Fix declaration

* Fix esp32c3
This commit is contained in:
s-hadinger 2022-12-04 16:57:34 +01:00 committed by GitHub
parent a7eaca59e6
commit 2a1b900775
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 704 additions and 33 deletions

View File

@ -91,6 +91,16 @@ bool WiFiClass32::getNetworkInfo(uint8_t i, String &ssid, uint8_t &encType, int3
return WiFi.getNetworkInfo(i, ssid, encType, rssi, bssid, channel);
}
// from https://github.com/espressif/arduino-esp32/pull/7520
static const int WIFI_WANT_IP6_BIT_ALT = BIT15;
bool WiFiClass32::IPv6(bool state) {
if (state)
WiFiGenericClass::setStatusBits(WIFI_WANT_IP6_BIT_ALT);
else
WiFiGenericClass::clearStatusBits(WIFI_WANT_IP6_BIT_ALT);
return true;
}
void wifi_station_disconnect() {
// erase ap: empty ssid, ...
WiFi.disconnect(true, true);

View File

@ -50,6 +50,8 @@ public:
static void forceSleepBegin();
static void forceSleepWake();
static bool getNetworkInfo(uint8_t i, String &ssid, uint8_t &encType, int32_t &rssi, uint8_t* &bssid, int32_t &channel, bool &hidden_scan);
bool IPv6(bool state); // make sure it always exists even with older Arduino framework
};
void wifi_station_disconnect();

View File

@ -45,17 +45,27 @@
#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() {
_ip = *IP_ANY_TYPE; // lwIP's v4-or-v6 generic address
#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_addr_isany(&_ip) && ((*this) != IPADDR_NONE);
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) {
@ -152,8 +162,8 @@ bool IPAddress46::operator==(const uint8_t* addr) const {
size_t IPAddress46::printTo(Print& p) const {
size_t n = 0;
if (!isSet())
return p.print(F("(IP unset)"));
// if (!isSet())
// return p.print(F("(IP unset)"));
#if LWIP_IPV6
if (isV6()) {
@ -267,4 +277,55 @@ bool IPAddress46::fromString6(const char *address) {
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

@ -123,7 +123,7 @@ class IPAddress46: public Printable {
static bool isValid(const char* arg);
friend class EthernetClass;
friend class UDP;
friend class UDP46;
friend class Client;
friend class Server;
friend class DhcpClass;
@ -181,4 +181,18 @@ class IPAddress46: public Printable {
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

@ -0,0 +1,93 @@
/*
* 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

@ -0,0 +1,335 @@
/*
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

@ -0,0 +1,77 @@
/*
* 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

@ -15,21 +15,25 @@
#include <Arduino.h>
#include <WiFiGeneric.h>
#include <WiFiUdp.h>
#include <WiFiUdp46.h>
#include "be_mapping.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};
extern "C" {
// init()
WiFiUDP *be_udp_init_ntv(void) {
return new WiFiUDP();
WiFiUDP46 *be_udp_init_ntv(void) {
return new WiFiUDP46();
}
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(WiFiUDP *udp) {
void *be_udp_deinit_ntv(WiFiUDP46 *udp) {
if (udp != nullptr) { delete udp; }
return nullptr;
}
@ -38,20 +42,22 @@ extern "C" {
}
// udp.begin(address:string, port:int) -> bool
int32_t be_udp_begin_ntv(WiFiUDP *udp, const char *host, int32_t port) {
IPAddress addr((uint32_t)0);
// if no host or host is "" then we defult to INADDR_ANY (0.0.0.0)
if(host && (*host != 0) && !WiFiGenericClass::hostByName(host, addr)){
return 0;
}
int32_t be_udp_begin_ntv(WiFiUDP46 *udp, int32_t port) {
IPAddress46 addr;
// AddLog(LOG_LEVEL_DEBUG, "BRY: udp.begin listening to '%s'", addr.toString().c_str());
return udp->begin(addr, port);
}
int32_t be_udp_begin(struct bvm *vm) {
return be_call_c_func(vm, (void*) &be_udp_begin_ntv, "b", ".si");
if (be_top(vm) >= 3 && be_isstring(vm, 2)) {
// legacy string parameter, now ignored
return be_call_c_func(vm, (void*) &be_udp_begin_ntv, "b", ".-i");
} else {
return be_call_c_func(vm, (void*) &be_udp_begin_ntv, "b", ".i");
}
}
// udp.stop() -> nil
void be_udp_stop_ntv(WiFiUDP *udp) {
void be_udp_stop_ntv(WiFiUDP46 *udp) {
udp->stop();
}
int32_t be_udp_stop(struct bvm *vm) {
@ -59,23 +65,24 @@ extern "C" {
}
// udp.begin_multicast(address:string, port:int) -> nil
int32_t be_udp_begin_mcast_ntv(WiFiUDP *udp, const char *host, int32_t port) {
IPAddress addr((uint32_t)0);
if(!WiFiGenericClass::hostByName(host, addr)){
int32_t be_udp_begin_mcast_ntv(WiFiUDP46 *udp, const char *host, int32_t port) {
IPAddress46 addr;
if(!WiFiGeneric46::hostByName(host, addr)){
return 0;
}
return udp->WiFiUDP::beginMulticast(addr, port);
return udp->WiFiUDP46::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(WiFiUDP *udp, const char *host, int32_t port, const uint8_t* buf, int32_t len) {
IPAddress addr((uint32_t)0);
if (!WiFiGenericClass::hostByName(host, addr)){
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)){
return 0;
}
// AddLog(LOG_LEVEL_DEBUG, "BRY: udp.begin got host '%s'", addr.toString().c_str());
if (!udp->beginPacket(addr, port)) { return 0; }
int bw = udp->write(buf, len);
if (!bw) { return 0; }
@ -87,7 +94,7 @@ extern "C" {
}
// udp.send_multicast(payload:bytes) -> bool
int32_t be_udp_send_mcast_ntv(WiFiUDP *udp, const uint8_t* buf, int32_t len) {
int32_t be_udp_send_mcast_ntv(WiFiUDP46 *udp, const uint8_t* buf, int32_t len) {
if (!udp->beginMulticastPacket()) { return 0; }
int bw = udp->write(buf, len);
if (!bw) { return 0; }
@ -100,7 +107,7 @@ extern "C" {
// udp.read() -> bytes or nil
int32_t be_udp_read(struct bvm *vm) {
WiFiUDP *udp = (WiFiUDP*) be_convert_single_elt(vm, 1, NULL, NULL);
WiFiUDP46 *udp = (WiFiUDP46*) be_convert_single_elt(vm, 1, NULL, NULL);
if (udp->parsePacket()) {
int btr = udp->available(); // btr contains the size of bytes_to_read
@ -128,7 +135,7 @@ extern "C" {
int32_t btr2 = udp->read(buf, btr);
// set remotet ip
IPAddress remote_ip = udp->remoteIP();
IPAddress46 remote_ip = udp->remoteIP();
be_pushstring(vm, remote_ip.toString().c_str());
be_setmember(vm, 1, "remote_ip");
be_pop(vm, 1);

View File

@ -118,6 +118,8 @@ struct WIFI {
bool wifi_test_AP_TIMEOUT = false;
bool wifi_Test_Restart = false;
bool wifi_Test_Save_SSID2 = false;
// IPv6 support, not guarded with #if LWIP_IPV6 to avoid bloating code with ifdefs
bool ipv6_local_link_called = false; // did we already enable IPv6 Local-Link address, needs to be redone at each reconnect
} Wifi;
typedef struct {

View File

@ -802,7 +802,9 @@ void CmndStatus(void)
}
if ((0 == payload) || (5 == payload)) {
// WifiDumpAddressesIPv6();
#if LWIP_IPV6
if (5 == payload) { WifiDumpAddressesIPv6(); }
#endif // LWIP_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\",\""

View File

@ -213,6 +213,9 @@ 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)
WiFi.IPv6(true);
#endif
#ifdef USE_WIFI_RANGE_EXTENDER
if (WiFi.getMode() != WIFI_AP_STA || !RgxApUp()) { // Preserve range extender connections (#17103)
@ -518,6 +521,17 @@ bool WifiHasIP(void) {
}
void WifiCheckIp(void) {
#if LWIP_IPV6
if (WL_CONNECTED == WiFi.status()) {
if (!Wifi.ipv6_local_link_called) {
WiFi.enableIpV6();
Wifi.ipv6_local_link_called = true;
// AddLog(LOG_LEVEL_DEBUG, PSTR("WIF: calling enableIpV6"));
}
}
#endif
if ((WL_CONNECTED == WiFi.status()) && WifiHasIP()) {
WifiSetState(1);
Wifi.counter = WIFI_CHECK_SEC;
@ -530,11 +544,6 @@ void WifiCheckIp(void) {
Settings->ipv4_address[2] = (uint32_t)WiFi.subnetMask();
Settings->ipv4_address[3] = (uint32_t)WiFi.dnsIP();
Settings->ipv4_address[4] = (uint32_t)WiFi.dnsIP(1);
#if LWIP_IPV6
// create Link-local address
CreateLinkLocalIPv6();
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_WIFI "IPv6 Link-Local %s"), WifiGetIPv6LinkLocal().c_str());
#endif // LWIP_IPV6
// Save current AP parameters for quick reconnect
Settings->wifi_channel = WiFi.channel();
@ -721,10 +730,21 @@ void WifiEnable(void) {
//#include <sntp.h> // sntp_servermode_dhcp()
//#endif // ESP8266
#ifdef ESP32
void WifiEvents(arduino_event_t *event);
#endif
void WifiConnect(void)
{
if (!Settings->flag4.network_wifi) { return; }
#ifdef ESP32
static bool wifi_event_registered = false;
if (!wifi_event_registered) {
WiFi.onEvent(WifiEvents); // register event listener only once
wifi_event_registered = true;
}
#endif // ESP32
WifiSetState(0);
WifiSetOutputPower();
@ -1039,3 +1059,51 @@ uint64_t WifiGetNtp(void) {
ntp_server_id++; // Next server next time
return 0;
}
// --------------------------------------------------------------------------------
// 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
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);
AddLog(LOG_LEVEL_DEBUG, PSTR("WIF: IPv6 %s %s"), addr.isLocal() ? PSTR("Link-Local") : PSTR("Global"), addr.toString().c_str());
}
break;
#endif // LWIP_IPV6
case ARDUINO_EVENT_ETH_GOT_IP:
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
{
ip_addr_t ip_addr4;
ip_addr_copy_from_ip4(ip_addr4, event->event_info.got_ip.ip_info.ip);
AddLog(LOG_LEVEL_DEBUG, PSTR("WIF: IPv4 %_I, mask %_I, gateway %_I"),
event->event_info.got_ip.ip_info.ip.addr,
event->event_info.got_ip.ip_info.netmask.addr,
event->event_info.got_ip.ip_info.gw.addr);
}
break;
case ARDUINO_EVENT_WIFI_STA_CONNECTED:
// AddLog(LOG_LEVEL_DEBUG, PSTR("WIF: Received ARDUINO_EVENT_WIFI_STA_CONNECTED"));
Wifi.ipv6_local_link_called = false; // not sure if this is needed, make sure link-local is restored at each reconnect
break;
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE:
Wifi.ipv6_local_link_called = false;
break;
default:
break;
}
}
#endif // ESP32