Recently I replaced an old 2.4 GHz-only Linksys WRT54GL wireless router with a shiny new, dual band TP-Link Archer C20 (hardware version V1). Unfortunately, the new router brought some unusual problems. It turns out some devices are now unable to get a global IPv6 address when connected over Wi-Fi. For example, my Android 5.1 smartphone and my work laptop with Debian Jessie and Network Manager don't get IPv6 connectivity. They worked just fine when connected through the old router. At the same time, a different phone with Android 6.0 seems to have no problems with the new Archer C20 router.
First a brief note on the network setup: Archer C20 is used here as a wireless access point only. Some other host on the network acts as a gateway to the Internet. That host also provides a DHCP service for IPv4 and runs the route advertisement daemon (radvd) for IPv6 SLAAC. The setup has been quite well tested and works flawlessly on the wired Ethernet. The old WRT54GL has also been used in this way, which is why IPv6 connectivity on the Wi-Fi worked fine even though the old router's firmware had no explicit IPv6 support.
As the TP-Link FAQ entry explains, the WAN port on the C20 is unused, the network is connected to one of the LAN ports and the DHCP server on the C20 is disabled. IPv6 status tab in the configuration interface shows the following:
The IPv6 problem is somewhat frustrating to diagnose, since it only appears some time after the router has been restarted. For instance, I've usually seen that IPv6 stops working the next day after a reboot. Similarly, changing some unrelated settings, like the wireless SSID, also appears to temporarily fix the issue, only for it to reappear after a while.
Searching the web I can find some discussions about similar problems with TP-Link routers, with no clear conclusion. The firmware changelog does say in a vague way that the latest version fixes an IPv6 problem. However, I've tried the V1_160427 and V1_151120 firmwares and they both behave in the same (broken) way.
After much head scratching I found out that the base cause why my laptop does not get an IPv6 address over Wi-Fi is IPv6 duplicate address detection. This is apparent from the dadfailed flag on the link local address:
$ ip addr show dev wlan0 3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000 link/ether a0:88:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff inet 192.168.xx.xx/24 brd 192.168.xx.255 scope global dynamic wlan0 valid_lft 484sec preferred_lft 484sec inet6 fe80::a288:xxxx:xxxx:xxxx/64 scope link tentative dadfailed valid_lft forever preferred_lft forever
Also, when you know what to look for, this error appears in the logs:
$ dmesg|grep duplicate IPv6: wlan0: IPv6 duplicate address fe80::a288:xxxx:xxxx:xxxx detected!
So it seems that my laptop thinks that there is another device on the network with the same link-local (and hence Ethernet MAC) address. This is of course not true. In fact, if I disable the duplicate address detection, IPv6 starts working properly:
# sysctl net.ipv6.conf.wlan0.accept_dad=0
Investigating things a bit further, Wireshark shows the following curious packet capture immediately after the laptop connects to the wireless network:
This appears to be the progress of a normal attempt at a IPv6 autoconfiguration from the laptop's side. The laptop (with the MAC address
a0:88:...) sends some packets to a IPv6 multicast address (
33:33:...). However, all these packets seem to be immediately reflected back to the laptop by Archer C20. The incoming packets highlighted in yellow are byte-by-byte identical to the preceding outgoing packets, with only the destination address in the Ethernet header changed from the multicast to the laptop's MAC address. These incoming packets are not present when the laptop is connected to one of the wired LAN ports, or when using the old wireless router.
These reflected packets trigger the duplicate address detection in the laptop's network stack and the autoconfiguration is interrupted. It seems that at some point in the Archer C20 uptime, IPv6 multicast groups stop working correctly. In fact I don't understand why it even tries to do anything special with those. WRT54GL had no concept of IPv6 and it worked fine. I've experimented with other options that looked related to multicast (like IGMP settings), but with no success. So unfortunately at the moment I don't have a good network-side solution. Any suggestions would be most welcome. Changing the stock firmware might work, but support in OpenWRT for this hardware currently seems experimental at best.
The device-side work-around is to disable DAD like I show above, but this is somewhat ugly. There might be a way to disable it on a per-network basis with Network Manager (see dad-timeout), but I have not tried this yet. It is also still not clear why some devices appear to work. It might be that Android simply disabled duplicate address detection in 6.0.