aboutsummaryrefslogtreecommitdiffstats
path: root/hostapd/wpa.c
diff options
context:
space:
mode:
authorJouni Malinen <jouni.malinen@atheros.com>2008-12-16 12:17:33 (GMT)
committerJouni Malinen <j@w1.fi>2008-12-16 12:17:33 (GMT)
commit22a299ee9d192d06c235428d017234539fbf6a62 (patch)
tree6de9bf6c3829726dd517fe418ef205821104a847 /hostapd/wpa.c
parent3d799c0b2cb79f4980b14eea6de80d11ddb75c45 (diff)
downloadhostap-06-22a299ee9d192d06c235428d017234539fbf6a62.zip
hostap-06-22a299ee9d192d06c235428d017234539fbf6a62.tar.gz
hostap-06-22a299ee9d192d06c235428d017234539fbf6a62.tar.bz2
Improve EAPOL-Key handshake stability with retransmitted frames
Accept response to any pending request, not just the last one. This gives the Supplicant more time to reply since hostapd will now allow up to three seconds for the reply to the first EAPOL-Key frame transmission (and two seconds for the first retry and one second for the last) while the previous version invalidated any old request immediately when sending a retransmitted frame. If the Supplicant replies to more than one request, only the first reply to arrive at the Authenticator will be processed. As far as the Supplicant is concerned, this behavior does not differ from the previous one except for being less likely to cause unneeded retransmissions of EAPOL-Key frames. This can help in cases where power saving is used when the group key is rekeyed or when there is excessive traffic on the channel that can delay (or drop) EAPOL-Key frames.
Diffstat (limited to 'hostapd/wpa.c')
-rw-r--r--hostapd/wpa.c52
1 files changed, 41 insertions, 11 deletions
diff --git a/hostapd/wpa.c b/hostapd/wpa.c
index 946552c..4f56354 100644
--- a/hostapd/wpa.c
+++ b/hostapd/wpa.c
@@ -498,7 +498,7 @@ void wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
#endif /* CONFIG_IEEE80211R */
if (sm->started) {
- os_memset(sm->key_replay_counter, 0, WPA_REPLAY_COUNTER_LEN);
+ os_memset(&sm->key_replay, 0, sizeof(sm->key_replay));
sm->ReAuthenticationRequest = TRUE;
wpa_sm_step(sm);
return;
@@ -574,6 +574,21 @@ static void wpa_request_new_ptk(struct wpa_state_machine *sm)
}
+static int wpa_replay_counter_valid(struct wpa_state_machine *sm,
+ const u8 *replay_counter)
+{
+ int i;
+ for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
+ if (!sm->key_replay[i].valid)
+ break;
+ if (os_memcmp(replay_counter, sm->key_replay[i].counter,
+ WPA_REPLAY_COUNTER_LEN) == 0)
+ return 1;
+ }
+ return 0;
+}
+
+
void wpa_receive(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
u8 *data, size_t data_len)
@@ -672,14 +687,18 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
}
if (!(key_info & WPA_KEY_INFO_REQUEST) &&
- (!sm->key_replay_counter_valid ||
- os_memcmp(key->replay_counter, sm->key_replay_counter,
- WPA_REPLAY_COUNTER_LEN) != 0)) {
+ !wpa_replay_counter_valid(sm, key->replay_counter)) {
+ int i;
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
"received EAPOL-Key %s with unexpected "
"replay counter", msgtxt);
- wpa_hexdump(MSG_DEBUG, "expected replay counter",
- sm->key_replay_counter, WPA_REPLAY_COUNTER_LEN);
+ for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
+ if (!sm->key_replay[i].valid)
+ break;
+ wpa_hexdump(MSG_DEBUG, "pending replay counter",
+ sm->key_replay[i].counter,
+ WPA_REPLAY_COUNTER_LEN);
+ }
wpa_hexdump(MSG_DEBUG, "received replay counter",
key->replay_counter, WPA_REPLAY_COUNTER_LEN);
return;
@@ -842,8 +861,12 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
wpa_rekey_gtk(wpa_auth, NULL);
}
} else {
- /* Do not allow the same key replay counter to be reused. */
- sm->key_replay_counter_valid = FALSE;
+ /* Do not allow the same key replay counter to be reused. This
+ * does also invalidate all other pending replay counters if
+ * retransmissions were used, i.e., we will only process one of
+ * the pending replies and ignore rest if more than one is
+ * received. */
+ sm->key_replay[0].valid = FALSE;
}
#ifdef CONFIG_PEERKEY
@@ -914,6 +937,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
int key_data_len, pad_len = 0;
u8 *buf, *pos;
int version, pairwise;
+ int i;
len = sizeof(struct ieee802_1x_hdr) + sizeof(struct wpa_eapol_key);
@@ -986,10 +1010,16 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
WPA_PUT_BE16(key->key_length, 0);
/* FIX: STSL: what to use as key_replay_counter? */
- inc_byte_array(sm->key_replay_counter, WPA_REPLAY_COUNTER_LEN);
- os_memcpy(key->replay_counter, sm->key_replay_counter,
+ for (i = RSNA_MAX_EAPOL_RETRIES - 1; i > 0; i--) {
+ sm->key_replay[i].valid = sm->key_replay[i - 1].valid;
+ os_memcpy(sm->key_replay[i].counter,
+ sm->key_replay[i - 1].counter,
+ WPA_REPLAY_COUNTER_LEN);
+ }
+ inc_byte_array(sm->key_replay[0].counter, WPA_REPLAY_COUNTER_LEN);
+ os_memcpy(key->replay_counter, sm->key_replay[0].counter,
WPA_REPLAY_COUNTER_LEN);
- sm->key_replay_counter_valid = TRUE;
+ sm->key_replay[0].valid = TRUE;
if (nonce)
os_memcpy(key->key_nonce, nonce, WPA_NONCE_LEN);