diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index b36e68dd6..134ae0620 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -2782,6 +2782,25 @@ static void handle_assoc_cb(struct hostapd_data *hapd, wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); hapd->new_assoc_sta_cb(hapd, sta, !new_assoc); 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; + } } diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c index c774d5cc7..42b029951 100644 --- a/src/ap/ieee802_1x.c +++ b/src/ap/ieee802_1x.c @@ -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; diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h index cd89e9989..70a59ccd7 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -56,6 +56,11 @@ struct mbo_non_pref_chan_info { u8 channels[]; }; +struct pending_eapol_rx { + struct wpabuf *buf; + struct os_reltime rx_time; +}; + struct sta_info { struct sta_info *next; /* next entry in sta list */ struct sta_info *hnext; /* next entry in hash table list */ @@ -113,6 +118,8 @@ struct sta_info { /* IEEE 802.1X related data */ struct eapol_state_machine *eapol_sm; + struct pending_eapol_rx *pending_eapol_rx; + u64 acct_session_id; struct os_reltime acct_session_start; int acct_session_started;