Border Router OTA using WiFi

How do I find the interface ID of the upstream interface?

Hi. I’ve been away for a while and now decided to come back to try and tackle this problem. I am still unable to figure out how to configure a static prefix. I selected PREFIX_CONF=static and IPV6_PREFIX as 2001:db8:: and IPV6_ADDR as 2001:db8::1. I also set CFLAGS += -DCONFIG_GNRC_IPV6_STATIC_ADDR_UPSTREAM=<pid>. I tried with various pid values, from 1 to 10 but none of them work.

The interface auto-selection is still probably selecting the wired uplink because the ethos “termprog” is still running when I run the terminal and if I try to set UPLINK=wifi manually, I’m running into a “RIOT kernel panic” problem.

Is there anything else I can check or am I doing something wrong here?

You are doing nothing wrong, in fact you have found a two bugs! I see that the address of the failed assertion is not properly printed, but enabling VERBOSE_ASSERT=1 will print the source of the culprit.

See #19854 and #19855 for a simple fix.

With those applied what works for me is

make BOARD=esp32-wroom-32 UPLINK=wifi PREFIX_CONF=static IPV6_PREFIX=2001:db8::/64


--- a/examples/gnrc_border_router/Makefile.board.dep
+++ b/examples/gnrc_border_router/Makefile.board.dep
@@ -8,8 +8,12 @@ ifeq (,$(filter native,$(BOARD)))
     ifneq (,$(filter esp32 esp8266,$(CPU)))
       USEMODULE += esp_wifi
       ifneq (ble, $(DOWNLINK))
-        USEMODULE += esp_now
+#        USEMODULE += esp_now
+      USEMODULE += slipdev_l2addr
+      CFLAGS += -DCONFIG_GNRC_IPV6_STATIC_ADDR_UPSTREAM=8      # netif-esp-wifi
       $(error Only esp32 and esp8266 are currently supported)

Mind you that the upstream network and the downstream network can’t have the same prefix, so you can’t have both 2001:db8::1 on the upstream and 2001:db8::/64 on the downstream. But if you want routing to the internet, you’d have to use your real prefixes anyway.

Thank you very much! Finally there’s something new to see! :slight_smile:

My problem is only half solved, though.

This is the output that I’m getting now.

I’m finally seeing the global ipv6 address, which probably means that the ESP32 router assigned a global address to the downstream (wired) interface. I still have a small issue and another question.

Firstly, I’ve also added these lines USEMODULE += slipdev_l2addr and CFLAGS += -DSLIPDEV_PARAM_UART=UART_DEV\(1\) in the Makefile.board.dep file of the SUIT update example, and connected the router and the Nucleo board using UART. I am running USE_ETHOS=0 BOARD=nucleo-f767zi make flash term. I’ve double checked the connections and I’m sure the wiring is correct. But I cannot see the global ipv6 address on the Nucleo board running the SUIT application.

Secondly, I’m running a COAP fileserver on my Linux host and I connected my laptop to the same WiFi network as the ESP32 router. I would like to know how I can add a route from the ESP32 to my fileserver so that I can achieve an OTA firmware update.

Sorry for asking multiple questions at once, but I’m running a little low on time. Thanks in advance.

I assume Interface 5 is your SLIP interface? (you can check with ps). Can you do a link-local ping to ensure your wiring is correct?

ping ff02::1%5

Also you don’t want to do router advertisements on the downstream interface:

ifconfig 5 -rtr_adv

For reaching the Downstream network from your laptop, you have to manually add a route to the downstream network via the address of the upstream (WiFi) interface of the ESP32:

ip route add 2001:db8::/64 via fe80::a6cf:12ff:fe9a:2dc8 dev wlan0

(replace wlan0 with the real name of your WiFi interface)

You will also have to set your laptop as the default router on the RIOT side, for the border router application you can do so by setting IPV6_DEFAULT_ROUTER to the address of your laptop’s WiFi interface.

I’m assuming a link-local ping means running the ping command in the terminal of the Nucleo board running the SUIT update code. That did not work, 100% packet loss. I also tried the ps command and I could not find the SLIP interface. This is the output for those commands.

Also, I have another weird thing happening. As soon as I connect the ESP and the Nucleo boards together, the ESP starts resetting every few seconds. Even when I run the ping function, the ESP resets. This is how it looks.

I’m guessing this is because the ESP32 UART 1 pins are defined in the RIOT core as GPIO 9 and 10, which are SD3 and SD2 as per this pinout I found online, which are apparently connected to the flash memory of the board. Maybe using UART through these pins is causing that reset?

1 Like

You can set DEVELHELP=1 to enable thread names in ps. But looking at the ifconfig output you already chose the right interface.

Can you try other pins for UART? I don’t think all pins are possible to use for that, you better check the data sheet.

Yes, setting DEVELHELP=1 confirmed that interface 5 is SLIP. I’ve also tried with all possible combinations of UART connection on both devices. But I’m still not seeing a global address and ping ff02::1%5 still says 100% packet loss.

Can you try with FLASH_MODE=dio - this should make the flash use only two pins and free up GPIO9 and GPIO10 for UART

You can also try tests/periph/uart (and connect RX and TX on your board) to test if the UART is working in principle.

After taking a closer look at the devices running the router/SUIT example and trying out tests/periph_uart, I think I’ve understood a couple things. Firstly, according to the RIOT documentation there are two UARTs defined in the ESP, and UART_DEV(1) is the one connected to the flash pins while UART_DEV(0) is connecting the board to the terminal when I run term. I tried connecting the UART_DEV(0) to the Nucleo, and though I cannot use the terminal on the ESP32 while they are connected, I can see that when I run ping ff02::1%5 from the Nucleo, an LED on the ESP32 flashes 3 times. So I think from a hardware perspective, the UART connection is working which I also confirmed by running tests/periph_uart.

I think the SLIP connection could be the issue. Is there anything else I need to check or set in the Makefiles? The FLASH_MODE = dio also did not work and the ESP still resets when it receives something through the UART.


That’s great news! I only found this when reading the ESP32 SoC page in the documentation. Did you try a make BOARD=… clean? If you still can’t access the 2nd UART, @gschorcht should know more about that.

I think the UART_DEV(1) is technically working, but can only transmit. When I try the 'tests/periph_uart, I am able to send a test message from the ESP to the Nucleo. But when I try to send something back from the Nucleo, that’s when the ESP just resets. I tried with make clean with the same result.

I managed to solve the link-local ping issue. Turns out in my attempts to make the SLIP work, I initialised the UART in the main.c file, which I now removed. I am now able to ping ff02::1%5

I also have a global ipv6 address on the Nucleo board now.

But I had to manually enter ifconfig 5 -rtr_adv in the terminal, which I will not be able to do every time I power off and power on the board. Is there a way to do this in the Makefile?

Also, I would like to know how to reach this address from my Linux host. I have tried running this

but it just says RTNETLINK answers: File exists and I cannot ping it from my PC. Any ideas as to why this might be happening?

Yes - IMHO it’s a bug that this is on by default if there is no prefix configured on the interface, but I suppose opinions differ there. If you don’t need the deceive to be a router, you can just swap the gnrc_ipv6_router_default module for gnrc_ipv6_default and the node will no longer act as a router but try to solicit a router instead.

If you need routing, you’d need a way to get a prefix and those methods will all only enable router advertisements on the downstream interface.

Alternatively you can just set


Huh that’s odd - is your wlan0 interface connected to a network?

Not really. I’ve been using my PC as a WiFi hotspot because I do not have a spare router currently. But the hotspot also uses the same wlan0 interface, doesn’t it?

You can find the name of your WiFi interface in ifconfig or ip a s.

Yes, I understand that. This is the ifconfig output.

I think this is the interface wlp0s20f3 as it is the only one with some activity in terms of Tx and Rx packets.

I tried routing to my ESP’s address like you suggested. It says RTNETLINK answers: File exists and the address is unreachable when I try to ping.

Does it make a difference if I’m using my PC as an Access Point (which I am doing right now) vs connecting it to a network?

Sorry, the ipv6 address I used in sudo ip route add 2001:db8::/64 via fe80::6411:da1d:befc:7eaf dev wlp0s20f3 is incorrect, it should be fe80::a6cf:12ff:fe9a:2dc8. Now when I added the route for the correct ipv6, File Exists did not show up but ping still doesn’t work.

I also added IPV6_DEFAULT_ROUTER = fe80::92b0:690f:c4d1:f8ef in the border router application.

I experimented with a lot of ping commands and I understood a couple things.

Firstly, ignore the RTNETLINK answers: File exists output, I was experimenting with another setup and did not realise that there is already a route to 2001:db8::/64 in that setup.

I am able to ping the RIOT node and the ESP32 back and forth, and I am able to ping the ESP32 from Linux using fe80::a6cf:12ff:fe9a:2dc8%wlp0s20f3 successfully. The only problem is that I am not able to reach the RIOT node from Linux, even after adding the route using the command ip route add 2001:db8::/64 via fe80::a6cf:12ff:fe9a:2dc8 dev wlp0s20f3

I also noticed that the ESP32 does not have a global ipv6 on the upstream interface. Could this be the cause of this problem?

This has already become a very long discussion. I hope this is the last step in my network setup. I also asked one of my colleagues and he told me that this might be a bug in RIOT.

Hi. I’ve been racking my brain on this for so long and finally gave up after a while. But I recently came across a Fritzbox router at a friend’s house and decided to try it out once.

To my surprise it worked! I can see the ping reply now.

$ ping 2001:db8::ac97:d831:a613:bd6e
PING 2001:db8::ac97:d831:a613:bd6e(2001:db8::ac97:d831:a613:bd6e) 56 data bytes
64 bytes from 2001:db8::ac97:d831:a613:bd6e: icmp_seq=1 ttl=63 time=225 ms
64 bytes from 2001:db8::ac97:d831:a613:bd6e: icmp_seq=2 ttl=63 time=224 ms
64 bytes from 2001:db8::ac97:d831:a613:bd6e: icmp_seq=3 ttl=63 time=44.2 ms
64 bytes from 2001:db8::ac97:d831:a613:bd6e: icmp_seq=4 ttl=63 time=75.8 ms
64 bytes from 2001:db8::ac97:d831:a613:bd6e: icmp_seq=5 ttl=63 time=103 ms
64 bytes from 2001:db8::ac97:d831:a613:bd6e: icmp_seq=6 ttl=63 time=135 ms
64 bytes from 2001:db8::ac97:d831:a613:bd6e: icmp_seq=7 ttl=63 time=158 ms
64 bytes from 2001:db8::ac97:d831:a613:bd6e: icmp_seq=8 ttl=63 time=180 ms
64 bytes from 2001:db8::ac97:d831:a613:bd6e: icmp_seq=9 ttl=63 time=203 ms
--- 2001:db8::ac97:d831:a613:bd6e ping statistics ---
9 packets transmitted, 9 received, 0% packet loss, time 8009ms
rtt min/avg/max/mdev = 44.221/149.870/225.095/61.405 ms

I can also see a global address on my PC’s WiFi interface

$ ip -6 addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 state UNKNOWN qlen 1000
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
3: wlp0s20f3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
    inet6 2a0c:d242:4380:0:d395:2bd7:b130:bfa2/64 scope global temporary dynamic 
       valid_lft 6358sec preferred_lft 2758sec
    inet6 2a0c:d242:4380:0:ba71:dade:552a:b04/64 scope global dynamic mngtmpaddr noprefixroute 
       valid_lft 6358sec preferred_lft 2758sec
    inet6 fe80::4ece:3ca2:d0e6:ea33/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

I’m assuming this is because I’ve never actually connected to a network which provides ipv6, and never realised it until now. Or it could be that this Fritzbox router has ipv6 turned on by default, and I was unable to configure it on my home network.

I have one last problem to be solved. I am unable to trigger a SUIT update, this is the output when I try to trigger an update.

> suit: received URL: "coap://[2001:db8::1]/fw/suit_update/nucleo-f767zi/riot.suit.latest.bin"
suit_worker: started.
suit_worker: downloading "coap://[2001:db8::1]/fw/suit_update/nucleo-f767zi/riot.suit.latest.bin"
suit_worker: error getting manifest
suit_worker: update failed, hdr invalid