AP: Save EAPOL received before Association Response ACK

There is a race condition in which AP might receive the EAPOL-Start
frame (from the just-associated station) before the TX completion of the
Association Response frame. This in turn will cause the EAPOL-Start
frame to get dropped, and potentially failing the connection.

Solve this by saving EAPOL frames from authenticated-but-not-associated
stations, and handling them during the Association Response frame TX
completion processing.

Signed-off-by: Eliad Peller <eliad@wizery.com>
This commit is contained in:
Eliad Peller 2016-03-06 11:29:16 +02:00 committed by Jouni Malinen
parent c0ca24fc30
commit f2accfe708
3 changed files with 62 additions and 0 deletions

View file

@ -861,6 +861,29 @@ ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta)
}
static void ieee802_1x_save_eapol(struct sta_info *sta, const u8 *buf,
size_t len)
{
if (sta->pending_eapol_rx) {
wpabuf_free(sta->pending_eapol_rx->buf);
} else {
sta->pending_eapol_rx =
os_malloc(sizeof(*sta->pending_eapol_rx));
if (!sta->pending_eapol_rx)
return;
}
sta->pending_eapol_rx->buf = wpabuf_alloc_copy(buf, len);
if (!sta->pending_eapol_rx->buf) {
os_free(sta->pending_eapol_rx);
sta->pending_eapol_rx = NULL;
return;
}
os_get_reltime(&sta->pending_eapol_rx->rx_time);
}
/**
* ieee802_1x_receive - Process the EAPOL frames from the Supplicant
* @hapd: hostapd BSS data
@ -891,6 +914,13 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) {
wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not "
"associated/Pre-authenticating STA");
if (sta && (sta->flags & WLAN_STA_AUTH)) {
wpa_printf(MSG_DEBUG, "Saving EAPOL frame from " MACSTR
" for later use", MAC2STR(sta->addr));
ieee802_1x_save_eapol(sta, buf, len);
}
return;
}
@ -1183,6 +1213,12 @@ void ieee802_1x_free_station(struct hostapd_data *hapd, struct sta_info *sta)
eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta);
#endif /* CONFIG_HS20 */
if (sta->pending_eapol_rx) {
wpabuf_free(sta->pending_eapol_rx->buf);
os_free(sta->pending_eapol_rx);
sta->pending_eapol_rx = NULL;
}
if (sm == NULL)
return;