[PATCH 3/3] AP: save eapol for later use (fix EAPOL Start race)

Michal Kazior michal.kazior
Thu Jul 9 05:26:26 PDT 2015


From: Eliad Peller <eliad at wizery.com>

Some drivers can report TX_STATUS and first EAPOL
Rx in reversed order. This would cause hostap to
drop the EAPOL and delay or fail association.

Cc: Eliad Peller <eliad at wizery.com>
Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 src/ap/hostapd.c    |  3 +++
 src/ap/hostapd.h    |  5 +++++
 src/ap/ieee802_11.c | 40 +++++++++++++++++++++++++++++++++++++---
 src/ap/ieee802_1x.c | 11 +++++++++++
 4 files changed, 56 insertions(+), 3 deletions(-)

diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 5abe5edd894d..caff2dcf8e41 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -261,6 +261,9 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
 	os_free(hapd->probereq_cb);
 	hapd->probereq_cb = NULL;
 
+	wpabuf_free(hapd->pending_eapol_rx);
+	hapd->pending_eapol_rx = NULL;
+
 #ifdef CONFIG_P2P
 	wpabuf_free(hapd->p2p_beacon_ie);
 	hapd->p2p_beacon_ie = NULL;
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index be5c7a8918d5..b708d98b6ec6 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -177,6 +177,11 @@ struct hostapd_data {
 	int beacon_set_done;
 	struct wpabuf *wps_beacon_ie;
 	struct wpabuf *wps_probe_resp_ie;
+
+	struct wpabuf *pending_eapol_rx;
+	struct os_time pending_eapol_rx_time;
+	u8 pending_eapol_rx_src[ETH_ALEN];
+
 #ifdef CONFIG_WPS
 	unsigned int ap_pin_failures;
 	unsigned int ap_pin_failures_consecutive;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index cf3567fd3031..c25c777f8ef7 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1563,6 +1563,9 @@ static void send_deauth(struct hostapd_data *hapd, const u8 *addr,
 
 static int add_pre_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta)
 {
+	struct ieee80211_ht_capabilities ht_cap;
+	struct ieee80211_vht_capabilities vht_cap;
+
 	/*
 	 * Remove the STA entry in order to make sure the STA PS state gets
 	 * cleared and configuration gets updated in case of reassociation back
@@ -1722,7 +1725,7 @@ static void handle_assoc(struct hostapd_data *hapd,
 	u16 capab_info, listen_interval, seq_ctrl, fc;
 	u16 resp = WLAN_STATUS_SUCCESS;
 	const u8 *pos;
-	int left, i;
+	int left, i, res;
 	struct sta_info *sta;
 
 	if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
@@ -2398,6 +2401,38 @@ static void hostapd_set_wds_encryption(struct hostapd_data *hapd,
 }
 
 
+#define PENDING_EAPOL_TIMEOUT_SEC 1
+
+static void handle_pending_eapol(struct hostapd_data *hapd,
+				 const struct ieee80211_mgmt *mgmt)
+{
+	struct os_time now, age;
+
+	if (!hapd->pending_eapol_rx)
+		return;
+
+	os_get_time(&now);
+	os_time_sub(&now, &hapd->pending_eapol_rx_time, &age);
+
+	if (age.sec >= PENDING_EAPOL_TIMEOUT_SEC)
+		goto free;
+
+	if (os_memcmp(hapd->pending_eapol_rx_src, mgmt->da, ETH_ALEN))
+		goto free;
+
+	wpa_printf(MSG_DEBUG, "Process pending EAPOL "
+		"frame that was received just before "
+		"association notification");
+	ieee802_1x_receive(hapd, hapd->pending_eapol_rx_src,
+			   wpabuf_head(hapd->pending_eapol_rx),
+			   wpabuf_len(hapd->pending_eapol_rx));
+
+free:
+	wpabuf_free(hapd->pending_eapol_rx);
+	hapd->pending_eapol_rx = NULL;
+}
+
+
 static void handle_assoc_cb(struct hostapd_data *hapd,
 			    const struct ieee80211_mgmt *mgmt,
 			    size_t len, int reassoc, int ok)
@@ -2405,8 +2440,6 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
 	u16 status;
 	struct sta_info *sta;
 	int new_assoc = 1;
-	struct ieee80211_ht_capabilities ht_cap;
-	struct ieee80211_vht_capabilities vht_cap;
 
 	if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
 				      sizeof(mgmt->u.assoc_resp))) {
@@ -2505,6 +2538,7 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
 	hapd->new_assoc_sta_cb(hapd, sta, !new_assoc);
 
 	ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
+	handle_pending_eapol(hapd, mgmt);
 }
 
 
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index d45b98f1f288..089bebe55591 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -855,6 +855,17 @@ 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->flags & WLAN_STA_ASSOC_REQ_OK) {
+			wpa_printf(MSG_DEBUG, "Saving EAPOL for later use");
+			wpabuf_free(hapd->pending_eapol_rx);
+			hapd->pending_eapol_rx = wpabuf_alloc_copy(buf, len);
+			if (hapd->pending_eapol_rx) {
+				os_get_time(&hapd->pending_eapol_rx_time);
+				os_memcpy(hapd->pending_eapol_rx_src, sa,
+					  ETH_ALEN);
+			}
+		}
+
 		return;
 	}
 
-- 
2.1.4




More information about the Hostap mailing list