Re: dhcpcd kills all connections on Wi-Fi roaming between access points
Roy Marples
Tue Dec 08 17:15:40 2020
Hi Boris
On 07/12/2020 22:18, Boris Krasnovskiy wrote:
Hi Roy,
I did some investigation, and the Roaming event is actually clearly indicated by
the Wi-Fi stack.
CARRIER events in the dhcpcd are indicated but IFF_RUNNING flag, that is not
quite correct for Wi-Fi.
The way it works is:
- when IFF_RUNNING drops, but IFF_LOWER_UP stays Up it is the Roaming event
- when IFF_RUNNING and IFF_LOWER_UP drop, it is the Disconnect event.
I appreciate the conversation about making sure the IP is validated on the
Network, but it seems for Wi-Fi it should be the supplicant job to determine if
one is on the same network, not dhcpcd.
I tried roaming scenarios and did not observe kernel dumping IPv6 addresses.
And by description it should not be during the Roaming event interface stops
Running, but never transitions into down state.
Rebuilding the routing tables in dhcp_abort, does cause IP address discard, once
I disable that it works correctly
I still hope you will be interested in fixing the issue.
Attached is a patch to try and deal with this.
It does this by ignoring interface flags without IFF_RUNNING but with
IFF_LOWER_UP set in link_netlink().
Otherwise, a lack of IFF_RUNNING is treated by dhcpcd as down by dhcpcd.
The only downside of this approach is that if the netlink socket overflows any
interfaces in the roaming state will then be marked down. Hopefully this won't
happen.
I've not tested this at all really and will do so on the one machine I run
Linux on baremetal with a wireless interface (yay, Pinebook) but that might take
a few days to find.
As such I'd appreciate any testing on this by list members if at all possible
with both wired and wireless interfaces.
Roy
diff --git a/src/if-linux.c b/src/if-linux.c
index eaa5a4d6..0cfd36b2 100644
--- a/src/if-linux.c
+++ b/src/if-linux.c
@@ -512,6 +512,7 @@ int
if_carrier(struct interface *ifp, __unused const void *ifadata)
{
+ /* Ignore IFF_LOWER_UP. See link_netlink() as to why. */
return ifp->flags & IFF_RUNNING ? LINK_UP : LINK_DOWN;
}
@@ -1014,6 +1015,15 @@ link_netlink(struct dhcpcd_ctx *ctx, void *arg, struct nlmsghdr *nlm)
dhcpcd_handlehwaddr(ifp, ifi->ifi_type, hwa, hwl);
}
+ /*
+ * Nothing else to do, so handle carrier events.
+ * IFF_RUNNING means interface is ready to run.
+ * IFF_LOWER_UP means that interface L1 is up.
+ * For wireless, IFF_LOWER_UP without IFF_RUNNING indicates roaming.
+ */
+ if (!(ifi->ifi_flags & IFF_RUNNING) && ifi->ifi_flags & IFF_LOWER_UP)
+ return 0;
+
dhcpcd_handlecarrier(ifp,
ifi->ifi_flags & IFF_RUNNING ? LINK_UP : LINK_DOWN,
ifi->ifi_flags);
diff --git a/src/privsep-bpf.c b/src/privsep-bpf.c
index 23da9a07..79c4696d 100644
--- a/src/privsep-bpf.c
+++ b/src/privsep-bpf.c
@@ -73,7 +73,8 @@ ps_bpf_recvbpf(void *arg)
if (len == -1) {
int error = errno;
- logerr("%s: %s", psp->psp_ifname, __func__);
+ if (errno != ENETDOWN)
+ logerr("%s: %s", psp->psp_ifname, __func__);
if (error != ENXIO)
break;
/* If the interface has departed, close the BPF
Archive administrator: postmaster@marples.name