AP: Save EAPOL received before Association Response ACK
authorEliad Peller <eliad@wizery.com>
Sun, 6 Mar 2016 09:29:16 +0000 (11:29 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 6 Mar 2016 15:08:12 +0000 (17:08 +0200)
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>
src/ap/ieee802_11.c
src/ap/ieee802_1x.c
src/ap/sta_info.h

index b36e68d..134ae06 100644 (file)
@@ -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;
+       }
 }
 
 
index c774d5c..42b0299 100644 (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;
 
index cd89e99..70a59cc 100644 (file)
@@ -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;