diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index 0faa70a5b..0691b6caa 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -117,11 +117,16 @@ static inline int wpa_drv_get_ssid(struct wpa_supplicant *wpa_s, u8 *ssid) static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, - const u8 *seq, size_t seq_len, - const u8 *key, size_t key_len) + const u8 *seq, size_t seq_len, + const u8 *key, size_t key_len) { + if (alg != WPA_ALG_NONE) { + if (key_idx >= 0 && key_idx <= 6) + wpa_s->keys_cleared &= ~BIT(key_idx); + else + wpa_s->keys_cleared = 0; + } if (wpa_s->driver->set_key) { - wpa_s->keys_cleared = 0; return wpa_s->driver->set_key(wpa_s->ifname, wpa_s->drv_priv, alg, addr, key_idx, set_tx, seq, seq_len, key, key_len); diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 1eb03ccc6..f8b3d9fd8 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -2163,7 +2163,6 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s, wpas_notify_disconnect_reason(wpa_s); if (wpa_supplicant_dynamic_keys(wpa_s)) { wpa_dbg(wpa_s, MSG_DEBUG, "Disconnect event - remove keys"); - wpa_s->keys_cleared = 0; wpa_clear_keys(wpa_s, wpa_s->bssid); } last_ssid = wpa_s->current_ssid; diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 31e71f1be..48fe00c14 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -495,29 +495,23 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) */ void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr) { - if (wpa_s->keys_cleared) { - /* Some drivers (e.g., ndiswrapper & NDIS drivers) seem to have - * timing issues with keys being cleared just before new keys - * are set or just after association or something similar. This - * shows up in group key handshake failing often because of the - * client not receiving the first encrypted packets correctly. - * Skipping some of the extra key clearing steps seems to help - * in completing group key handshake more reliably. */ - wpa_dbg(wpa_s, MSG_DEBUG, "No keys have been configured - " - "skip key clearing"); - return; - } + int i, max; + +#ifdef CONFIG_IEEE80211W + max = 6; +#else /* CONFIG_IEEE80211W */ + max = 4; +#endif /* CONFIG_IEEE80211W */ /* MLME-DELETEKEYS.request */ - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0); - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0); - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0); - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0); -#ifdef CONFIG_IEEE80211W - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0); - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0); -#endif /* CONFIG_IEEE80211W */ - if (addr) { + for (i = 0; i < max; i++) { + if (wpa_s->keys_cleared & BIT(i)) + continue; + wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, i, 0, NULL, 0, + NULL, 0); + } + if (!(wpa_s->keys_cleared & BIT(0)) && addr && + !is_zero_ether_addr(addr)) { wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL, 0); /* MLME-SETPROTECTION.request(None) */ @@ -526,7 +520,7 @@ void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr) MLME_SETPROTECTION_PROTECT_TYPE_NONE, MLME_SETPROTECTION_KEY_TYPE_PAIRWISE); } - wpa_s->keys_cleared = 1; + wpa_s->keys_cleared = (u32) -1; } diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 8563b1838..a1931bb65 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -432,7 +432,8 @@ struct wpa_supplicant { unsigned char last_eapol_src[ETH_ALEN]; - int keys_cleared; + unsigned int keys_cleared; /* bitfield of key indexes that the driver is + * known not to be configured with a key */ struct wpa_blacklist *blacklist;