]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Flush PMKSA cache entries and invalidate EAP state on network changes
authorJouni Malinen <jouni@qca.qualcomm.com>
Wed, 7 Sep 2011 14:46:00 +0000 (17:46 +0300)
committerJouni Malinen <j@w1.fi>
Wed, 7 Sep 2011 14:46:00 +0000 (17:46 +0300)
If a network configuration block is removed or modified, flush
all PMKSA cache entries that were created using that network
configuration. Similarly, invalidate EAP state (fast re-auth).

The special case for OKC on wpa_supplicant reconfiguration
(network_ctx pointer change) is now addressed as part of the
PMKSA cache flushing, so it does not need a separate mechanism
for clearing the network_ctx values in the PMKSA cache.

src/rsn_supp/pmksa_cache.c
src/rsn_supp/pmksa_cache.h
src/rsn_supp/wpa.c
src/rsn_supp/wpa.h
wpa_supplicant/ctrl_iface.c
wpa_supplicant/notify.c
wpa_supplicant/wpa_supplicant.c

index 12f1f1ef301907155350da138592c5d2b61b98f7..6d828a43eadd6d1a7f2da146de5268b781f6e38f 100644 (file)
@@ -229,6 +229,40 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
 }
 
 
+/**
+ * pmksa_cache_flush - Flush PMKSA cache entries for a specific network
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ * @network_ctx: Network configuration context or %NULL to flush all entries
+ */
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx)
+{
+       struct rsn_pmksa_cache_entry *entry, *prev = NULL, *tmp;
+       int removed = 0;
+
+       entry = pmksa->pmksa;
+       while (entry) {
+               if (entry->network_ctx == network_ctx || network_ctx == NULL) {
+                       wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry "
+                                  "for " MACSTR, MAC2STR(entry->aa));
+                       if (prev)
+                               prev->next = entry->next;
+                       else
+                               pmksa->pmksa = entry->next;
+                       tmp = entry;
+                       entry = entry->next;
+                       wpa_sm_remove_pmkid(pmksa->sm, tmp->aa, tmp->pmkid);
+                       pmksa_cache_free_entry(pmksa, tmp, 0);
+                       removed++;
+               } else {
+                       prev = entry;
+                       entry = entry->next;
+               }
+       }
+       if (removed)
+               pmksa_cache_set_expiration(pmksa);
+}
+
+
 /**
  * pmksa_cache_deinit - Free all entries in PMKSA cache
  * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
@@ -274,22 +308,6 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
 }
 
 
-/**
- * pmksa_cache_notify_reconfig - Reconfiguration notification for PMKSA cache
- * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
- *
- * Clear references to old data structures when wpa_supplicant is reconfigured.
- */
-void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa)
-{
-       struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
-       while (entry) {
-               entry->network_ctx = NULL;
-               entry = entry->next;
-       }
-}
-
-
 static struct rsn_pmksa_cache_entry *
 pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
                        const struct rsn_pmksa_cache_entry *old_entry,
index a1447e526d5bcfb72200ee2a901ad543d2c55164..840827d792e53d41cb51cc5b2cdbaba206baa5cf 100644 (file)
@@ -57,7 +57,6 @@ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);
 struct rsn_pmksa_cache_entry *
 pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
                const u8 *aa, const u8 *spa, void *network_ctx, int akmp);
-void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa);
 struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm);
 void pmksa_cache_clear_current(struct wpa_sm *sm);
 int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
@@ -66,6 +65,7 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
 struct rsn_pmksa_cache_entry *
 pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa,
                              void *network_ctx, const u8 *aa);
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx);
 
 #else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
 
@@ -106,10 +106,6 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
        return NULL;
 }
 
-static inline void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa)
-{
-}
-
 static inline void pmksa_cache_clear_current(struct wpa_sm *sm)
 {
 }
@@ -122,6 +118,11 @@ static inline int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
        return -1;
 }
 
+static inline void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa,
+                                    void *network_ctx)
+{
+}
+
 #endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
 
 #endif /* PMKSA_CACHE_H */
index 047dcc11c86901b85e8a77835516a2995bc79754..4ffbac5d2f565333f54887c33fd84ad09d573d27 100644 (file)
@@ -2269,8 +2269,6 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
                sm->ssid_len = 0;
                sm->wpa_ptk_rekey = 0;
        }
-       if (config == NULL || config->network_ctx != sm->network_ctx)
-               pmksa_cache_notify_reconfig(sm->pmksa);
 }
 
 
@@ -2654,3 +2652,11 @@ void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr)
 {
        os_memcpy(sm->rx_replay_counter, replay_ctr, WPA_REPLAY_COUNTER_LEN);
 }
+
+
+void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx)
+{
+#ifndef CONFIG_NO_WPA2
+       pmksa_cache_flush(sm->pmksa, network_ctx);
+#endif /* CONFIG_NO_WPA2 */
+}
index 48090e0c8cd105b975b186dd38434a106180fbb8..a01baf90d390b7e1325fd0d6060919a2089d5ab4 100644 (file)
@@ -136,6 +136,8 @@ int wpa_sm_has_ptk(struct wpa_sm *sm);
 
 void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr);
 
+void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx);
+
 #else /* CONFIG_NO_WPA */
 
 static inline struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
@@ -286,6 +288,11 @@ static inline void wpa_sm_update_replay_ctr(struct wpa_sm *sm,
 {
 }
 
+static inline void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm,
+                                           void *network_ctx)
+{
+}
+
 #endif /* CONFIG_NO_WPA */
 
 #ifdef CONFIG_PEERKEY
index 22c31fdffce55a2c20720f6d7895fb019b96e70f..8b3b4fdb5c27600f9801a6e01c79503650da3a95 100644 (file)
@@ -1395,8 +1395,8 @@ static int wpa_supplicant_ctrl_iface_remove_network(
                        wpas_notify_network_removed(wpa_s, remove_ssid);
                        wpa_config_remove_network(wpa_s->conf, id);
                }
+               eapol_sm_invalidate_cached_session(wpa_s->eapol);
                if (wpa_s->current_ssid) {
-                       eapol_sm_invalidate_cached_session(wpa_s->eapol);
                        wpa_sm_set_config(wpa_s->wpa, NULL);
                        eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
                        wpa_supplicant_disassociate(wpa_s,
@@ -1418,12 +1418,15 @@ static int wpa_supplicant_ctrl_iface_remove_network(
                return -1;
        }
 
-       if (ssid == wpa_s->current_ssid) {
+       if (ssid == wpa_s->current_ssid || wpa_s->current_ssid == NULL) {
                /*
-                * Invalidate the EAP session cache if the current network is
-                * removed.
+                * Invalidate the EAP session cache if the current or
+                * previously used network is removed.
                 */
                eapol_sm_invalidate_cached_session(wpa_s->eapol);
+       }
+
+       if (ssid == wpa_s->current_ssid) {
                wpa_sm_set_config(wpa_s->wpa, NULL);
                eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
 
@@ -1471,10 +1474,12 @@ static int wpa_supplicant_ctrl_iface_set_network(
                return -1;
        }
 
-       if (wpa_s->current_ssid == ssid) {
+       wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
+
+       if (wpa_s->current_ssid == ssid || wpa_s->current_ssid == NULL) {
                /*
                 * Invalidate the EAP session cache if anything in the current
-                * configuration changes.
+                * or previously used configuration changes.
                 */
                eapol_sm_invalidate_cached_session(wpa_s->eapol);
        }
index 0d2f54253bd3a69d3d6bfd57e9db8848313493dd..ed466bdc4c80a5d09dd0f636dd3654fe2306b84c 100644 (file)
@@ -22,6 +22,7 @@
 #include "dbus/dbus_common.h"
 #include "dbus/dbus_old.h"
 #include "dbus/dbus_new.h"
+#include "rsn_supp/wpa.h"
 #include "driver_i.h"
 #include "scan.h"
 #include "p2p_supplicant.h"
@@ -238,6 +239,7 @@ void wpas_notify_persistent_group_removed(struct wpa_supplicant *wpa_s,
 void wpas_notify_network_removed(struct wpa_supplicant *wpa_s,
                                 struct wpa_ssid *ssid)
 {
+       wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
        if (wpa_s->global->p2p_group_formation != wpa_s)
                wpas_dbus_unregister_network(wpa_s, ssid->id);
 }
index 006cfb07a023f71466398c827dae5c41bf05db3b..e50c8399aa38cb5c2b51a4d9c0261f71e809bf2a 100644 (file)
@@ -726,6 +726,7 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
        }
        eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
        wpa_sm_set_config(wpa_s->wpa, NULL);
+       wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
        wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
        rsn_preauth_deinit(wpa_s->wpa);