FP6 IPv6 failure: on my device it is NOT the “RA lifetime 0” tracker bug — it’s undelivered solicited-node multicast (packet capture inside)
I’ve spent the last several days instrumenting this properly (with help from Anthropic Claude): adb, dumpsys network_stack, neighbour/route/multicast dumps taken in the failed state, and an ICMPv6 packet capture from a second machine on the same LAN.
I want to be careful about scope. This thread has repeatedly converged on Google Issue Tracker 429703129 (“Android loses IPv6 route after RA with router lifetime 0”) as the cause. On my device that explanation is definitively wrong — I can show the default route is present and being refreshed by RAs throughout the failure. That doesn’t mean nobody here has 429703129; this thread is long and it is entirely possible several different faults are producing similar-looking symptoms. But at least one of us has a different bug, and here it is in detail.
Long version
Setup
- Fairphone 6, Android 16, build FP6.QREL.16.82.0, Google Play system update: 1 June 2026, stock, locked bootloader.
- FRITZ!Box 4050 + FRITZ!Repeater 3000 AX.
- ISP: EE (UK), dual-stack, /56 delegated, SLAAC + RA, no DHCPv6
- Private DNS = “Automatic” — i.e. opportunistic DoT to the router, which doesn’t serve it, so in practice plain DNS. The failure reproduces with DoT effectively out of the picture, which suggests the “DNS over TLS” framing in this thread’s title is a casualty rather than a cause.
- A Linux laptop on the same LAN holds IPv6 at 10/10 verified at the moment the phone reads 0/10.
Addresses below are anonymised but internally consistent (solicited-node arithmetic still checks out):
|
|
| LAN prefix |
2001:db8:1:1::/64 |
| Router |
fe80::1 / 2001:db8:1:1::1 |
| Laptop |
fe80::2 / 2001:db8:1:1::2 |
| Phone link-local |
fe80::a:b:c:d |
| Phone temp GUA |
2001:db8:1:1:1234:5678:9abc:def0 → solicited-node ff02::1:ffbc:def0 |
| Phone MAC |
aa:bb:cc:dd:ee:ff |
What this is NOT (on my device)
1. AOSP issue 429703129 (RA with router lifetime 0 → default route lost, never restored). In the failed state:
$ adb shell ip -6 route show table all
...
default via fe80::1 dev wlan0 table 1023 proto ra metric 1024 expires 1690sec hoplimit 255 pref medium
The default route is present, learned from RA, with ~1690s left of a 1800s router lifetime — meaning an RA was received and processed roughly a minute before capture. This held across three separate failure episodes. RAs continue to arrive throughout (visible in the dumpsys network_stack packet log). Nanoc’s earlier finding — that no lifetime-0 RA precedes the failure — is consistent with this, seen from the phone’s side.
2. NUD / gateway unreachability. The gateway’s neighbour entry reads REACHABLE or STALE during failure — both normal — never FAILED.
3. APF RA starvation. APF counters in dumpsys network_stack show RAs being passed to the kernel, not dropped, over the failure window. (Caveat: these are cumulative counters read at a single moment, not watched incrementing.)
4. Loss of provisioning. Android’s LinkProperties never changes. No provisioning-loss event of any kind. From the OS’s point of view, nothing has happened.
5. Upstream / ISP flap. Other devices on the same LAN are verified at 10/10 IPv6 at the moment the phone reads 0/10.
6. VPN. The failure recurs with Tailscale fully disconnected. (VPNs appear in this thread as workarounds — a full-tunnel VPN masks the broken inbound path by carrying everything over IPv4 — not as causes.)
Why the OS never self-heals
NetworkMonitor revalidates whenever apps report the network broken. In the failed state its probes look like this:
- DNS resolves in ~60–90 ms (fine)
- HTTP / HTTPS / fallback probes each take ~10 seconds, then return HTTP 204
The most natural reading of that ~10 s is an IPv6 connection attempt timing out and falling back to IPv4. Because the probes ultimately succeed (over v4), Android marks the network validated and takes no recovery action. That is why the phone sits there broken indefinitely: its own health check passes.
It also explains the user-visible symptom set — apps with good happy-eyeballs behaviour merely stall; apps without it hang; and the whole thing masquerades as a DNS problem.
The phone is joined to its multicast groups
In the failed state, phone awake:
$ adb shell ip -6 maddr show dev wlan0
23: wlan0
inet6 ff02::1:ff00:0
inet6 ff02::2
inet6 ff02::fb
inet6 ff02::1:ffbc:def0 <-- solicited-node, temp GUA
inet6 ff02::1:ff...:... <-- solicited-node, stable GUA + ULAs
inet6 ff02::1:ff0c:d <-- solicited-node, link-local
inet6 ff02::1
...
Every expected group is present. The kernel believes it is a member of all of them.
The core finding: multicast ND fails, unicast to the same address works
From the laptop, cold neighbour cache (ip -6 neigh flush), during a confirmed failure — and note the phone was fully awake, screen on, connected over USB and actively responding to adb throughout this test, so “the phone was asleep and missed the multicast” does not explain it:
$ ping -6 -c 4 2001:db8:1:1:1234:5678:9abc:def0 # phone's temp GUA
From 2001:db8:1:1::2 icmp_seq=1 Destination unreachable: Address unreachable
... 100% packet loss
Now install a static neighbour entry — bypassing solicited-node multicast resolution entirely — and ping the exact same address:
$ sudo ip -6 neigh replace 2001:db8:1:1:1234:5678:9abc:def0 lladdr aa:bb:cc:dd:ee:ff dev wlan0
$ ping -6 -c 4 2001:db8:1:1:1234:5678:9abc:def0
64 bytes from ...: icmp_seq=1 ttl=64 time=9 ms
64 bytes from ...: icmp_seq=2 ttl=64 time=206 ms
64 bytes from ...: icmp_seq=3 ttl=64 time=39 ms
64 bytes from ...: icmp_seq=4 ttl=64 time=62 ms
--- 0% packet loss
Same address. Same phone. Same radio. Same minute.
Resolved via multicast ND: unreachable. Delivered via unicast: flawless.
(Gotcha: ip -6 neigh flush does not remove PERMANENT entries. Use ip -6 neigh del to clean up, or you’ll fool yourself into thinking it recovered.)
The packet capture
ICMPv6 capture from the laptop during the failure. Timestamps and ordering unedited; addresses anonymised.
(a) The laptop’s multicast transmit path is healthy — solicited-node NS to the router is answered immediately:
10:40:21.853 2001:db8:1:1::2 > ff02::1:ff00:0001: NS, who has fe80::1
10:40:21.859 fe80::1 > 2001:db8:1:1::2 : NA, tgt is fe80::1 <-- 6ms
(b) Six seconds later — solicited-node NS to the phone’s group. Six attempts. Zero replies:
10:40:27.176 2001:db8:1:1::2 > ff02::1:ffbc:def0: NS, who has 2001:db8:1:1:1234:5678:9abc:def0
10:40:28.188 2001:db8:1:1::2 > ff02::1:ffbc:def0: NS, who has 2001:db8:1:1:1234:5678:9abc:def0
10:40:29.212 2001:db8:1:1::2 > ff02::1:ffbc:def0: NS, who has 2001:db8:1:1:1234:5678:9abc:def0
10:40:30.236 2001:db8:1:1::2 > ff02::1:ffbc:def0: NS, who has 2001:db8:1:1:1234:5678:9abc:def0
10:40:31.260 fe80::2 > ff02::1:ffbc:def0: NS, who has 2001:db8:1:1:1234:5678:9abc:def0
10:40:32.284 fe80::2 > ff02::1:ffbc:def0: NS, who has 2001:db8:1:1:1234:5678:9abc:def0
^^^ never answered
(c) Thirty seconds later — unicast to that identical address (static neigh entry). Perfect:
10:41:02.190 2001:db8:1:1::2 > 2001:db8:1:1:1234:5678:9abc:def0: echo request, seq 1
10:41:02.199 2001:db8:1:1:1234:5678:9abc:def0 > 2001:db8:1:1::2: echo reply, seq 1
... 4/4 replies, 9–206 ms
(d) Meanwhile the phone is demonstrably alive and transmitting — sending its own NUD probes to the laptop and getting answers, right through the failure:
10:41:07.289 fe80::a:b:c:d > 2001:db8:1:1::2: NS, who has 2001:db8:1:1::2
10:41:07.289 2001:db8:1:1::2 > fe80::a:b:c:d : NA
(e) No MLD traffic anywhere. Zero MLD frames in this capture, and a separate 15-minute tcpdump filtered on icmp6 and ip6[40] == 130 caught no MLD general queries at all. There appears to be no MLD querier on this LAN, which would mean multicast group state has no refresh mechanism and can only decay. (Caveat: a capture at the laptop cannot see MLD reports the phone sends, since those are forwarded toward router ports, not to peer clients — so this tells us about the querier, not about the phone’s reports.)
What I think this means
Verified: the phone’s addresses, routes, group memberships, transmit path, unicast receive path, and all-nodes multicast receive (RAs arrive fine) are all correct and working.
The failure is that NS sent to the phone’s solicited-node multicast groups produce no NA. The consequences follow directly, and explain everything users see:
- Nothing on the LAN can resolve the phone’s global addresses to a MAC. Inbound IPv6 blackholes, including return traffic for the phone’s own outbound connections.
- Outbound still works, so the link looks healthy to every OS-level check — hence no self-healing.
- I observed a freshly rotated temporary address that was already unreachable, within a couple of hours of coming into existence. Since Android rotates temp addresses every few hours and prefers them as the source for new connections, this is a plausible mechanism for the progressive decay people describe — things get worse over hours rather than failing cleanly. (Inference, not demonstrated.)
- A Wi-Fi toggle presumably fixes it because reassociation rebuilds all of this state from scratch. (Inference.)
What I have NOT established — please help
1. Where the frames actually die. Either the AP never transmits the solicited-node frames, or it transmits them and the phone’s Wi-Fi chip drops them despite the kernel’s membership. A laptop capture cannot see the AP’s radio, so I cannot distinguish these — and this is precisely the fork that decides whether this is an AVM bug or a Fairphone/Qualcomm bug. My router’s own packet capture produced a zero-byte file; if anyone has an AP that can capture its WLAN interface properly, that measurement would settle it.
Note that the phone’s kernel is joined to the groups, so if the chip is filtering, its RX filter has desynced from the kernel’s membership list.
2. Whether the router is failing the same way. I infer it must be — the router faces the identical resolution problem for return traffic, and the phone’s inbound IPv6 is dead — but I never captured the router’s own NS, so this is inference, not observation.
3. Whether link-local really survives. In earlier testing, the phone’s link-local appeared to remain reachable from a “cold” cache while its GUAs did not, which looked like a fascinating anomaly. I now think that was probably an artefact. The capture shows the phone sends its own NUD probes to the laptop roughly every 85 seconds, each carrying a source link-layer address option — which repopulates the laptop’s neighbour cache for the phone’s link-local without any multicast resolution happening at all. In the capture, the laptop never once sent an NS to the link-local’s solicited-node group; every link-local NS it sent was unicast, i.e. it already had the entry.
If that’s right, the mechanism is simpler and stronger than I first thought: all solicited-node multicast delivery to the phone may be broken, with no exceptions. Someone should test this cleanly: start a capture, ip -6 neigh del <phone link-local>, ping it, and check whether an NS to ff02::1:ff<last 24 bits> actually goes out and is answered.
4. One spontaneous recovery. On one occasion the failure cleared without a Wi-Fi toggle — but it coincided with me plugging in USB and running diagnostics, so I don’t trust it as evidence of anything and mention it only for completeness.
Reproduce it yourself (no root needed)
While your phone is in the failed state, from a Linux box on the same LAN:
# Via adb, on the phone:
adb shell ip -6 route show table all # default route still there? (mine: yes)
adb shell ip -6 neigh # gateway FAILED? (mine: no)
adb shell ip -6 maddr show dev wlan0 # joined to solicited-node groups? (mine: yes)
adb shell ip -6 addr show dev wlan0 # note the current *temporary* GUA
# On the laptop:
sudo ip -6 neigh flush dev <iface>
ping -6 -c 4 <phone temp GUA> # expect: Address unreachable
# The decisive test — bypass multicast ND entirely:
sudo ip -6 neigh replace <phone temp GUA> lladdr <phone MAC> dev <iface>
ping -6 -c 4 <phone temp GUA> # expect: works perfectly
sudo ip -6 neigh del <phone temp GUA> dev <iface> # clean up — flush won't remove it
If you see the same thing — unreachable via multicast ND, perfectly reachable via unicast — then we’re looking at the same bug, and it is not the one in the tracker.
Workarounds, ranked
- Disable IPv6 on the router. Total, but punishes the whole household for one device.
- Wi-Fi toggle when it breaks. Automatable (Tasker).
- Full-tunnel VPN. Masks the broken inbound path. This is likely why VPNs keep appearing in this thread as fixes.
- Untested, but worth someone trying: an app holding a
WifiManager.MulticastLock forces the Wi-Fi stack to accept multicast during power-save. If that prevents the failure, it would both confirm the mechanism and give a workaround that doesn’t cost you IPv6.
For Fairphone engineering
Minimal statement of the bug:
On FP6 / Android 16 (FP6.QREL.16.82.0), after a period of Wi-Fi association, Neighbour Solicitations addressed to the device’s solicited-node multicast groups (ff02::1:ffXX:XXXX) cease to be answered, while (a) the kernel remains correctly joined to those groups (ip -6 maddr show dev wlan0), (b) unicast frames to the same IPv6 addresses are received and answered normally (verified via a static neighbour entry from a peer on the LAN), and (c) all-nodes multicast (ff02::1, e.g. RAs) continues to be received. Neighbour Discovery for the device’s global addresses therefore fails network-wide, blackholing inbound IPv6 while outbound continues to work. Android’s own validation probes fall back to IPv4 and report the network as valid, so the condition never self-heals.
This is not AOSP issue 429703129: the default route is present and being refreshed by RAs throughout the failure.
The specific thing I’d ask you to check: is the Wi-Fi firmware’s multicast RX filter being programmed with, and kept in sync with, the kernel’s IPv6 multicast group memberships? One suggestive asymmetry: APF on this device answers IGMPv3 general queries in firmware (the DROPPED_IGMP_V3_GENERAL_QUERY_REPLIED counter accumulates steadily overnight), i.e. IPv4 multicast membership is actively maintained in hardware while the phone dozes. I see no corresponding MLDv2 counter. If IPv6 multicast membership is not maintained with equivalent care, that is precisely the shape of this bug. (This is a hypothesis from counter names, not a finding.)
I have full unredacted captures — pcap, dumpsys network_stack, route/neigh/maddr dumps, in-failure and post-recovery — and will happily provide them privately.