nl80211: Check previous MAC address for locally-generated-deauth

When using MAC randomization wpa_supplicant can change the local MAC
address during roaming scenario:

1. We attach to AP1 (with MAC1/SSID1).
2. Roaming to AP2 (with MAC2/SSID2) is started:
  a) we send DEAUTH(for AP1, with MAC1)
  b) we change MAC to MAC2 due to randomization
  c) we start authentication for AP2
  d) we get notification about DEAUTH for AP1 (which we ignore)
  e) we complete association with AP2

In point 2d we completely ignore the notification which later causes
problems. This happens if the deauthentication event is generated by the
local driver (e.g., due to beacon loss) instead of AP2 sending an
explicit Deauthentication frame.

The intended behavior is as follows: during roaming we generate DEAUTH
(2a) and signal this event right away. To protect from handling of our
own DEAUTH for the 2nd time supplicant marks 'ignore_next_local_deauth'
variable.  In point 2d we should receive this notification and clear the
flag but this does not happen because MAC1 in the notification is not
the current MAC address (it has been changed in 2b) so this notification
is ignored as a one with a "foreign" address.

So we end up successfully at AP2 but with 'ignore_next_local_deauth'
still set which causes problems.  For example if AP2 shuts down it has
been observed on some drivers that the DEAUTH notification is generated
as a local one and since we have flag to ignore it nothing is reported
over D-Bus.

To address the problem let's store the previously used MAC address and
use it for checking for foreign address (in combination with the current
one).

Signed-off-by: Andrzej Ostruszka <amo@semihalf.com>
This commit is contained in:
Andrzej Ostruszka 2022-06-13 14:09:13 +02:00 committed by Jouni Malinen
parent 87ffa1bec6
commit 98e9d553f2
3 changed files with 12 additions and 3 deletions

View file

@ -1189,6 +1189,7 @@ static void nl80211_refresh_mac(struct wpa_driver_nl80211_data *drv,
MACSTR " to " MACSTR, MACSTR " to " MACSTR,
ifindex, bss->ifname, ifindex, bss->ifname,
MAC2STR(bss->addr), MAC2STR(addr)); MAC2STR(bss->addr), MAC2STR(addr));
os_memcpy(bss->prev_addr, bss->addr, ETH_ALEN);
os_memcpy(bss->addr, addr, ETH_ALEN); os_memcpy(bss->addr, addr, ETH_ALEN);
if (notify) if (notify)
wpa_supplicant_event(drv->ctx, wpa_supplicant_event(drv->ctx,
@ -10892,6 +10893,7 @@ static int nl80211_set_mac_addr(void *priv, const u8 *addr)
wpa_printf(MSG_DEBUG, "nl80211: set_mac_addr for %s to " MACSTR, wpa_printf(MSG_DEBUG, "nl80211: set_mac_addr for %s to " MACSTR,
bss->ifname, MAC2STR(addr)); bss->ifname, MAC2STR(addr));
drv->addr_changed = new_addr; drv->addr_changed = new_addr;
os_memcpy(bss->prev_addr, bss->addr, ETH_ALEN);
os_memcpy(bss->addr, addr, ETH_ALEN); os_memcpy(bss->addr, addr, ETH_ALEN);
if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1) < 0) if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1) < 0)

View file

@ -68,6 +68,7 @@ struct i802_bss {
unsigned int use_nl_connect:1; unsigned int use_nl_connect:1;
u8 addr[ETH_ALEN]; u8 addr[ETH_ALEN];
u8 prev_addr[ETH_ALEN];
int freq; int freq;
int bandwidth; int bandwidth;

View file

@ -1240,8 +1240,11 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
* ignore_next_local_deauth as well, to avoid next local * ignore_next_local_deauth as well, to avoid next local
* deauth event be wrongly ignored. * deauth event be wrongly ignored.
*/ */
if (!os_memcmp(mgmt->sa, drv->first_bss->addr, if (os_memcmp(mgmt->sa, drv->first_bss->addr,
ETH_ALEN)) { ETH_ALEN) == 0 ||
(!is_zero_ether_addr(drv->first_bss->prev_addr) &&
os_memcmp(mgmt->sa, drv->first_bss->prev_addr,
ETH_ALEN) == 0)) {
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
"nl80211: Received a locally generated deauth event. Clear ignore_next_local_deauth flag"); "nl80211: Received a locally generated deauth event. Clear ignore_next_local_deauth flag");
drv->ignore_next_local_deauth = 0; drv->ignore_next_local_deauth = 0;
@ -1451,7 +1454,10 @@ static void mlme_event(struct i802_bss *bss,
os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 && os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 &&
(is_zero_ether_addr(bss->rand_addr) || (is_zero_ether_addr(bss->rand_addr) ||
os_memcmp(bss->rand_addr, data + 4, ETH_ALEN) != 0) && os_memcmp(bss->rand_addr, data + 4, ETH_ALEN) != 0) &&
os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) { os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0 &&
(is_zero_ether_addr(drv->first_bss->prev_addr) ||
os_memcmp(bss->prev_addr, data + 4 + ETH_ALEN,
ETH_ALEN) != 0)) {
wpa_printf(MSG_MSGDUMP, "nl80211: %s: Ignore MLME frame event " wpa_printf(MSG_MSGDUMP, "nl80211: %s: Ignore MLME frame event "
"for foreign address", bss->ifname); "for foreign address", bss->ifname);
return; return;