Let wpa_supplicant/hostapd generated control frames bypass the QDISC when the linux kernel supports the feature, to make sure the frames are reaching the driver and are not delayed or dropped by QDISC. This fixes a potential race when rekeying a connection under load: Without that an EAPOL#4 frame send out by wpa_supplicant may not have reached the driver when switching over to the new key, causing the AP to disconnect the STA. Signed-off-by: Alexander Wetzel <alexander@xxxxxxxxxxxxxx> --- The intend of this patch is to make sure the eapol#4 frame has at least reached the driver when we replace the key. Now this is is just the quick & easy fix to make sure EAPOL#4 is at least in the driver queues when we replace the key, as discussed here: http://lists.infradead.org/pipermail/hostap/2019-September/040514.html I've cleaned up the tested hack a bit and added the same bypass for hostapd. I don't like the two independent eapol paths and think it would make sense to let nl80211 handle eapol frames also for wpa_supplicant and not just for hostapd. But the changes to get that implemented are quite far reaching and not directly linked to the problem at hand. I've also started looking how to unify the two paths, but this will be quite invasive and nothing I see in the near future. The patch here is therefore just enabling PACKET_QDISC_BYPASS on the existing sockets we use to transmit eapol frames: When we can't bypass the QDISC - probably the kernel is < 3.14 - we simply continue anyhow, thus keeping the existing behavior. (A warning here seems a bit like overkill, but that's just my gut feeling...) Technically it would be sufficient to only apply the second part of the patch (l2_packet_linux.c): Really critical is only the eapol#4 frame. But having some qdisc drop any 802.11 management frames - and then ONLY eapol frames - did not look like a good idea. src/drivers/driver_nl80211.c | 8 ++++++-- src/l2_packet/l2_packet_linux.c | 9 +++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index f699fb53f..a8372cfc0 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -1992,6 +1992,7 @@ static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname, { struct wpa_driver_nl80211_data *drv; struct i802_bss *bss; + int enabled = 1; if (global_priv == NULL) return NULL; @@ -2038,9 +2039,12 @@ static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname, if (drv->eapol_tx_sock < 0) goto failed; - if (drv->data_tx_status) { - int enabled = 1; + /* The qdisc could delay/drop frames. Bypass it when supported. */ + setsockopt(drv->eapol_tx_sock, SOL_PACKET, PACKET_QDISC_BYPASS, + &enabled, sizeof(enabled)); + if (drv->data_tx_status) { + enabled = 1; if (setsockopt(drv->eapol_tx_sock, SOL_SOCKET, SO_WIFI_STATUS, &enabled, sizeof(enabled)) < 0) { wpa_printf(MSG_DEBUG, diff --git a/src/l2_packet/l2_packet_linux.c b/src/l2_packet/l2_packet_linux.c index 291c9dd26..1bd7d15d1 100644 --- a/src/l2_packet/l2_packet_linux.c +++ b/src/l2_packet/l2_packet_linux.c @@ -274,6 +274,7 @@ struct l2_packet_data * l2_packet_init( struct l2_packet_data *l2; struct ifreq ifr; struct sockaddr_ll ll; + int enabled = 1; l2 = os_zalloc(sizeof(struct l2_packet_data)); if (l2 == NULL) @@ -294,6 +295,14 @@ struct l2_packet_data * l2_packet_init( os_free(l2); return NULL; } + + /* The qdisc could delay/drop the eapol #3 frame, causing the frame to + * be encrypted with the new key or not to be send out at all when + * rekeying a busy link. Bypass it when supported. + */ + setsockopt(l2->fd, SOL_PACKET, PACKET_QDISC_BYPASS, + &enabled, sizeof(enabled)); + os_memset(&ifr, 0, sizeof(ifr)); os_strlcpy(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name)); if (ioctl(l2->fd, SIOCGIFINDEX, &ifr) < 0) { -- 2.23.0 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap