Skip to content

IPv6 UDP send not working. #5744

Closed
Closed
@oddstr13

Description

@oddstr13

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

Settings screenshot
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)));
         }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions