Description
Basic Infos
- This issue complies with the issue POLICY doc.
- I have read the documentation at readthedocs and the issue is not addressed there.
- I have tested that the issue is present in current master branch (aka latest git).
- I have searched the issue tracker for a similar issue.
- If there is a stack dump, I have decoded it.
- I have filled out all fields below.
Platform
- Hardware: [ESP-12]
- Core Version: [latest git hash or date]
- Development Env: [Arduino IDE|other]
- Operating System: [Windows]
Settings in IDE
Relevant: lwIP variant: v2 IPv6 Lower memory
Problem Description
IPv6 UDP packets are not sent due to local_ip
being set to 0.0.0.0, IPv4
.
This is the underlying issue that prompted my question in regards to multicast IPv6.
For IPv6 multicast, I got it working by hacking setMulticastInterface
in UdpContext.h:
void setMulticastInterface(const IPAddress& addr)
{
#if LWIP_VERSION_MAJOR == 1
udp_set_multicast_netif_addr(_pcb, (ip_addr_t)addr);
#else
+ _pcb->local_ip.u_addr = ((const ip_addr_t*)addr)->u_addr;
+ _pcb->local_ip.type = ((const ip_addr_t*)addr)->type;
udp_set_multicast_netif_addr(_pcb, ip_2_ip4((const ip_addr_t*)addr));
#endif
}
And passing the IPv6 address of the interface to beginPacketMulticast
;
IPAddress getIP6Address(int ifn=STATION_IF) {
// Prefer non-local address
for (auto a: addrList) {
if (a.ifnumber() == ifn && a.addr().isV6() && !a.addr().isLocal()) {
return a.addr();
}
}
// Fall back to local address
for (auto a: addrList) {
if (a.ifnumber() == ifn && a.addr().isV6()) {
return a.addr();
}
}
// Final fall-back to the IPv6 wildcard address; [::]
return IP6_ADDR_ANY;
}
// -----------------------------------------------
void loop() {
// <snip>
Udp.beginPacketMulticast(multicast_ip, multicast_port, getIP6Address(), multicast_ttl)
// <snip>
}
The reason it fails :ust rc=-6
, is due to !IP_ADDR_PCB_VERSION_MATCH(pcb, dst_ip)
in lwIP's udp.c
.
From <lwip/ip_addr.h>
:
#define IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr) (IP_GET_TYPE(&pcb->local_ip) == IP_GET_TYPE(ipaddr))
#define IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr) (IP_IS_ANY_TYPE_VAL(pcb->local_ip) || IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr))
The local_ip
is neither IP6_ADDR_ANY
, or of type IPADDR_TYPE_ANY
, and as such, udp_sendto
fails with ERR_VAL(-6)
.
IP_ADDR_ANY
is defined as IP4_ADDR_ANY
in <lwip/ip_address.h>
, which is a ip_addr_t = {u_addr={0ul, 0ul, 0ul, 0ul}, type=0
.
Ideally, IP_ADDR_ANY
should probably have type IPADDR_TYPE_ANY(46)
, not IPADDR_TYPE_V4(0)
on dual-stack systems, but this might be an upstream issue?
Lastly, this issue might not show up when replying to received packets (I have not tested this).
MCVE Sketch
Traffic watched on router with tcpdump -i br-lan -n port 18888
15:13:05.245105 IP 10.79.2.187.50506 > 8.8.8.8.18888: UDP, length 7
15:13:16.262131 IP 10.79.2.187.50506 > 8.8.8.8.18888: UDP, length 7
#define LWIP_DEBUG 1
#include <lwip/debug.h>
#define UDP_DEBUG LWIP_DBG_ON
#include <lwip-git-hash.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <wifi_credentials.h> // WIFI_SSID & WIFI_PASSWORD
uint16_t remote_port = 18888;
char* remote_address_1_str = "8.8.8.8";
char* remote_address_2_str = "2001:4860:4860::8888";
IPAddress remote_address_1;
IPAddress remote_address_2;
WiFiUDP Udp;
void setup() {
Serial.begin(115200);
Serial.println();
Serial.println(ESP.getFullVersion());
Serial.println();
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(500);
}
Serial.print("Connected! IP address: ");
Serial.println(WiFi.localIP());
//Serial.printf("UDP server on port %d\n", localPort);
//Udp.begin(localPort);
remote_address_1.fromString(remote_address_1_str);
remote_address_2.fromString(remote_address_2_str);
}
void loop() {
Serial.println("----------------------------------");
Serial.print("Sending UDP packet to ");
Serial.print(remote_address_1);
Serial.print(" port ");
Serial.println(remote_port);
Serial.print("Udp.beginPacket: ");
Serial.println((int)Udp.beginPacket(remote_address_1, remote_port), DEC);
Serial.print("Udp.write: ");
Serial.println((int)Udp.write("Testing"), DEC);
Serial.print("Udp.endPacket: ");
Serial.println((int)Udp.endPacket(), DEC);
Serial.println("----------------------------------");
delay(1000);
Serial.print("Sending UDP packet to ");
Serial.print(remote_address_2);
Serial.print(" port ");
Serial.println(remote_port);
Serial.print("Udp.beginPacket: ");
Serial.println((int)Udp.beginPacket(remote_address_2, remote_port), DEC);
Serial.print("Udp.write: ");
Serial.println((int)Udp.write("Testing"), DEC);
Serial.print("Udp.endPacket: ");
Serial.println((int)Udp.endPacket(), DEC);
delay(10000);
}
Debug Messages
SDK:3.0.0-dev(c0f7b44)/Core:2.5.0-beta3=20499903/lwIP:IPv6+STABLE-2_1_2_RELEASE/glue:1.0-11-g87c709d/BearSSL:6778687
sta configwifi evt: 2
unchangedscandone
.scandone
state: 0 -> 2 (b0)
state: 2 -> 3 (0)
state: 3 -> 5 (10)
add 0
aid 9
cnt
connected with Solvang, channel 6
dhcp client start...
wifi evt: 0
...ip:10.79.2.187,mask:255.255.252.0,gw:10.79.0.1
wifi evt: 3
Connected! IP address: 10.79.2.187
----------------------------------
Sending UDP packet to 8.8.8.8 port 18888
Udp.beginPacket: 1
Udp.write: 7
Udp.endPacket: 1
----------------------------------
ip:10.79.2.187,mask:255.255.252.0,gw:10.79.0.1
ip:10.79.2.187,mask:255.255.252.0,gw:10.79.0.1
Sending UDP packet to 2001:4860:4860::8888 port 18888
Udp.beginPacket: 1
Udp.write: 7
Udp.endPacket: :ust rc=-6
:: _pcb == NULL = false
:: addr == NULL = false
:: IP_ADDR_PCB_VERSION_MATCH(_pcb, addr) = false
:: _pcb->local_ip = 0.0.0.0
:: _pcb->local_ip.type = 0
:: addr = 2001:4860:4860::8888
0
pm open,type:2 0
----------------------------------
Sending UDP packet to 8.8.8.8 port 18888
Udp.beginPacket: 1
Udp.write: 7
Udp.endPacket: 1
----------------------------------
Sending UDP packet to 2001:4860:4860::8888 port 18888
Udp.beginPacket: 1
Udp.write: 7
Udp.endPacket: :ust rc=-6
:: _pcb == NULL = false
:: addr == NULL = false
:: IP_ADDR_PCB_VERSION_MATCH(_pcb, addr) = false
:: _pcb->local_ip = 0.0.0.0
:: _pcb->local_ip.type = 0
:: addr = 2001:4860:4860::8888
0
----------------------------------
Edit:
Some extra debug output in <UdpContext.h>
send()
is present;
err_t err = udp_sendto(_pcb, tx_copy, addr, port);
if (err != ERR_OK) {
DEBUGV(":ust rc=%d\r\n", (int) err);
+ //#define IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr) (IP_GET_TYPE(&pcb->local_ip) == IP_GET_TYPE(ipaddr))
+ //#define IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr) (IP_IS_ANY_TYPE_VAL(pcb->local_ip) || IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr))
+ DEBUGV(":: _pcb == NULL = %s\r\n", (_pcb == NULL) ? "true" : "false");
+ DEBUGV(":: addr == NULL = %s\r\n", (addr == NULL) ? "true" : "false");
+ DEBUGV(":: IP_ADDR_PCB_VERSION_MATCH(_pcb, addr) = %s\r\n", (IP_ADDR_PCB_VERSION_MATCH(_pcb, addr)) ? "true" : "false");
+ DEBUGV(":: _pcb->local_ip = %s\r\n", (ipaddr_ntoa(&_pcb->local_ip)));
+ DEBUGV(":: _pcb->local_ip.type = %d\r\n", (int)(_pcb->local_ip.type));
+ DEBUGV(":: addr = %s\r\n", (ipaddr_ntoa(addr)));
}