Accumulative patch from commit f5f37d3a4fc2df2a24676b4f95afca15ed793cba
Author: Jouni Malinen <j@w1.fi>
Date: Sun Nov 25 22:05:32 2012 +0200
Fix REAUTHENTICATE command after PMKSA caching
The current PMKSA cache entry needs to be clear to allow EAPOL
reauthentication to be started in case this association used PMKSA
caching.
- Remove old WPS_OOB NCF
- WPS: Add preliminary NFC connection handover support for Enrollee
- WPS: Reenable the networks disabled during wpa_wpas_reassoc
- P2P: Avoid multi-channel scans when they are not needed
- P2P: Allow discoverable interval for p2p_find to be configured
- P2P: Allow all channels with multi-channel concurrency
- Bonjour changes
- Remove disassociate
- HS 2.0 changes
- Add preliminary support for using SQLite for eap_user database
- Add SAE support
- Add disallow_aps parameter to disallow BSSIDs/SSIDs
Change-Id: I85358a05b39d46b8db49acdad667e771c580b05c
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index 9783e7c..df67583 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -25,7 +25,7 @@
struct wpa_sm *sm; /* TODO: get rid of this reference(?) */
void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx,
- int replace);
+ enum pmksa_free_reason reason);
void *ctx;
};
@@ -41,11 +41,11 @@
static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *entry,
- int replace)
+ enum pmksa_free_reason reason)
{
wpa_sm_remove_pmkid(pmksa->sm, entry->aa, entry->pmkid);
pmksa->pmksa_count--;
- pmksa->free_cb(entry, pmksa->ctx, replace);
+ pmksa->free_cb(entry, pmksa->ctx, reason);
_pmksa_cache_free_entry(entry);
}
@@ -61,7 +61,7 @@
pmksa->pmksa = entry->next;
wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
MACSTR, MAC2STR(entry->aa));
- pmksa_cache_free_entry(pmksa, entry, 0);
+ pmksa_cache_free_entry(pmksa, entry, PMKSA_EXPIRE);
}
pmksa_cache_set_expiration(pmksa);
@@ -164,22 +164,9 @@
pmksa->pmksa = pos->next;
else
prev->next = pos->next;
- if (pos == pmksa->sm->cur_pmksa) {
- /* We are about to replace the current PMKSA
- * cache entry. This happens when the PMKSA
- * caching attempt fails, so we don't want to
- * force pmksa_cache_free_entry() to disconnect
- * at this point. Let's just make sure the old
- * PMKSA cache entry will not be used in the
- * future.
- */
- wpa_printf(MSG_DEBUG, "RSN: replacing current "
- "PMKSA entry");
- pmksa->sm->cur_pmksa = NULL;
- }
wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
"the current AP");
- pmksa_cache_free_entry(pmksa, pos, 1);
+ pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE);
/*
* If OKC is used, there may be other PMKSA cache
@@ -214,7 +201,7 @@
"PMKSA cache entry (for " MACSTR ") to "
"make room for new one",
MAC2STR(pos->aa));
- pmksa_cache_free_entry(pmksa, pos, 0);
+ pmksa_cache_free_entry(pmksa, pos, PMKSA_FREE);
}
}
@@ -265,7 +252,7 @@
pmksa->pmksa = entry->next;
tmp = entry;
entry = entry->next;
- pmksa_cache_free_entry(pmksa, tmp, 0);
+ pmksa_cache_free_entry(pmksa, tmp, PMKSA_FREE);
removed++;
} else {
prev = entry;
@@ -507,7 +494,7 @@
*/
struct rsn_pmksa_cache *
pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
- void *ctx, int replace),
+ void *ctx, enum pmksa_free_reason reason),
void *ctx, struct wpa_sm *sm)
{
struct rsn_pmksa_cache *pmksa;
diff --git a/src/rsn_supp/pmksa_cache.h b/src/rsn_supp/pmksa_cache.h
index 9245aab..f318c52 100644
--- a/src/rsn_supp/pmksa_cache.h
+++ b/src/rsn_supp/pmksa_cache.h
@@ -38,11 +38,17 @@
struct rsn_pmksa_cache;
+enum pmksa_free_reason {
+ PMKSA_FREE,
+ PMKSA_REPLACE,
+ PMKSA_EXPIRE,
+};
+
#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
struct rsn_pmksa_cache *
pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
- void *ctx, int replace),
+ void *ctx, enum pmksa_free_reason reason),
void *ctx, struct wpa_sm *sm);
void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa);
struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
@@ -66,7 +72,7 @@
static inline struct rsn_pmksa_cache *
pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
- void *ctx, int replace),
+ void *ctx, int reason),
void *ctx, struct wpa_sm *sm)
{
return (void *) -1;
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 5cf32df..3c45f3a 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -783,7 +783,7 @@
rsn_ie, rsn_ie_len);
}
- wpa_sm_disassociate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS);
+ wpa_sm_deauthenticate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS);
}
@@ -1836,6 +1836,10 @@
case WPA_KEY_MGMT_PSK_SHA256:
return RSN_AUTH_KEY_MGMT_PSK_SHA256;
#endif /* CONFIG_IEEE80211W */
+ case WPA_KEY_MGMT_CCKM:
+ return (sm->proto == WPA_PROTO_RSN ?
+ RSN_AUTH_KEY_MGMT_CCKM:
+ WPA_AUTH_KEY_MGMT_CCKM);
case WPA_KEY_MGMT_WPA_NONE:
return WPA_AUTH_KEY_MGMT_NONE;
default:
@@ -1931,25 +1935,40 @@
static void wpa_sm_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
- void *ctx, int replace)
+ void *ctx, enum pmksa_free_reason reason)
{
struct wpa_sm *sm = ctx;
+ int deauth = 0;
- if (sm->cur_pmksa == entry ||
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA cache entry free_cb: "
+ MACSTR " reason=%d", MAC2STR(entry->aa), reason);
+
+ if (sm->cur_pmksa == entry) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: %s current PMKSA entry",
+ reason == PMKSA_REPLACE ? "replaced" : "removed");
+ pmksa_cache_clear_current(sm);
+
+ /*
+ * If an entry is simply being replaced, there's no need to
+ * deauthenticate because it will be immediately re-added.
+ * This happens when EAP authentication is completed again
+ * (reauth or failed PMKSA caching attempt).
+ */
+ if (reason != PMKSA_REPLACE)
+ deauth = 1;
+ }
+
+ if (reason == PMKSA_EXPIRE &&
(sm->pmk_len == entry->pmk_len &&
os_memcmp(sm->pmk, entry->pmk, sm->pmk_len) == 0)) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
- "RSN: removed current PMKSA entry");
- sm->cur_pmksa = NULL;
+ "RSN: deauthenticating due to expired PMK");
+ pmksa_cache_clear_current(sm);
+ deauth = 1;
+ }
- if (replace) {
- /* A new entry is being added, so no need to
- * deauthenticate in this case. This happens when EAP
- * authentication is completed again (reauth or failed
- * PMKSA caching attempt). */
- return;
- }
-
+ if (deauth) {
os_memset(sm->pmk, 0, sizeof(sm->pmk));
wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
}
@@ -2080,6 +2099,7 @@
void wpa_sm_notify_disassoc(struct wpa_sm *sm)
{
rsn_preauth_deinit(sm);
+ pmksa_cache_clear_current(sm);
if (wpa_sm_get_state(sm) == WPA_4WAY_HANDSHAKE)
sm->dot11RSNA4WayHandshakeFailures++;
#ifdef CONFIG_TDLS
@@ -2372,6 +2392,22 @@
if (ret < 0 || ret >= end - pos)
return pos - buf;
pos += ret;
+
+ if (sm->mfp != NO_MGMT_FRAME_PROTECTION && sm->ap_rsn_ie) {
+ struct wpa_ie_data rsn;
+ if (wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &rsn)
+ >= 0 &&
+ rsn.capabilities & (WPA_CAPABILITY_MFPR |
+ WPA_CAPABILITY_MFPC)) {
+ ret = os_snprintf(pos, end - pos, "pmf=%d\n",
+ (rsn.capabilities &
+ WPA_CAPABILITY_MFPR) ? 2 : 1);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+ }
+
return pos - buf;
}
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 1077b5a..8afdf39 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -24,7 +24,6 @@
void (*set_state)(void *ctx, enum wpa_states state);
enum wpa_states (*get_state)(void *ctx);
void (*deauthenticate)(void * ctx, int reason_code);
- void (*disassociate)(void *ctx, int reason_code);
int (*set_key)(void *ctx, enum wpa_alg alg,
const u8 *addr, int key_idx, int set_tx,
const u8 *seq, size_t seq_len,
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index c30d09e..9f9e641 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -143,12 +143,6 @@
sm->ctx->deauthenticate(sm->ctx->ctx, reason_code);
}
-static inline void wpa_sm_disassociate(struct wpa_sm *sm, int reason_code)
-{
- WPA_ASSERT(sm->ctx->disassociate);
- sm->ctx->disassociate(sm->ctx->ctx, reason_code);
-}
-
static inline int wpa_sm_set_key(struct wpa_sm *sm, enum wpa_alg alg,
const u8 *addr, int key_idx, int set_tx,
const u8 *seq, size_t seq_len,
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 6a8f9f1..3d75365 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -83,6 +83,8 @@
RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
} else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE);
+ } else if (key_mgmt == WPA_KEY_MGMT_CCKM) {
+ RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_CCKM);
} else {
wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
key_mgmt);
@@ -152,6 +154,8 @@
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
} else if (key_mgmt == WPA_KEY_MGMT_PSK) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
+ } else if (key_mgmt == WPA_KEY_MGMT_CCKM) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_CCKM);
#ifdef CONFIG_IEEE80211R
} else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
@@ -164,6 +168,12 @@
} else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+ } else if (key_mgmt == WPA_KEY_MGMT_SAE) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
+ } else if (key_mgmt == WPA_KEY_MGMT_FT_SAE) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
+#endif /* CONFIG_SAE */
} else {
wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
key_mgmt);