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:
parent
c0ca24fc30
commit
f2accfe708
3 changed files with 62 additions and 0 deletions
|
@ -2782,6 +2782,25 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
|
||||||
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
|
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
|
||||||
hapd->new_assoc_sta_cb(hapd, sta, !new_assoc);
|
hapd->new_assoc_sta_cb(hapd, sta, !new_assoc);
|
||||||
ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
|
ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
|
||||||
|
|
||||||
|
if (sta->pending_eapol_rx) {
|
||||||
|
struct os_reltime now, age;
|
||||||
|
|
||||||
|
os_get_reltime(&now);
|
||||||
|
os_reltime_sub(&now, &sta->pending_eapol_rx->rx_time, &age);
|
||||||
|
if (age.sec == 0 && age.usec < 200000) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"Process pending EAPOL frame that was received from " MACSTR " just before association notification",
|
||||||
|
MAC2STR(sta->addr));
|
||||||
|
ieee802_1x_receive(
|
||||||
|
hapd, mgmt->da,
|
||||||
|
wpabuf_head(sta->pending_eapol_rx->buf),
|
||||||
|
wpabuf_len(sta->pending_eapol_rx->buf));
|
||||||
|
}
|
||||||
|
wpabuf_free(sta->pending_eapol_rx->buf);
|
||||||
|
os_free(sta->pending_eapol_rx);
|
||||||
|
sta->pending_eapol_rx = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
* ieee802_1x_receive - Process the EAPOL frames from the Supplicant
|
||||||
* @hapd: hostapd BSS data
|
* @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))) {
|
!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) {
|
||||||
wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not "
|
wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not "
|
||||||
"associated/Pre-authenticating STA");
|
"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;
|
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);
|
eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta);
|
||||||
#endif /* CONFIG_HS20 */
|
#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)
|
if (sm == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,11 @@ struct mbo_non_pref_chan_info {
|
||||||
u8 channels[];
|
u8 channels[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct pending_eapol_rx {
|
||||||
|
struct wpabuf *buf;
|
||||||
|
struct os_reltime rx_time;
|
||||||
|
};
|
||||||
|
|
||||||
struct sta_info {
|
struct sta_info {
|
||||||
struct sta_info *next; /* next entry in sta list */
|
struct sta_info *next; /* next entry in sta list */
|
||||||
struct sta_info *hnext; /* next entry in hash table list */
|
struct sta_info *hnext; /* next entry in hash table list */
|
||||||
|
@ -113,6 +118,8 @@ struct sta_info {
|
||||||
/* IEEE 802.1X related data */
|
/* IEEE 802.1X related data */
|
||||||
struct eapol_state_machine *eapol_sm;
|
struct eapol_state_machine *eapol_sm;
|
||||||
|
|
||||||
|
struct pending_eapol_rx *pending_eapol_rx;
|
||||||
|
|
||||||
u64 acct_session_id;
|
u64 acct_session_id;
|
||||||
struct os_reltime acct_session_start;
|
struct os_reltime acct_session_start;
|
||||||
int acct_session_started;
|
int acct_session_started;
|
||||||
|
|
Loading…
Reference in a new issue