[PATCH v2] AP: save EAPOL received before assoc resp

Eliad Peller eliad at wizery.com
Sun Mar 6 01:29:16 PST 2016


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 assoc response.

This in turn will cause the EAPOL-Start frame to get
dropped, and potentially failing the connection.

Solve this by saving EAPOLs from authenticated-but-not-
associated stations, and handling them during the assoc
response tx completion processing.

Signed-off-by: Eliad Peller <eliad at wizery.com>
---
v2:
* remove wpa_supplicant from commit message
* remove redundant saved sta address
* use a single malloc (along with new function and struct)
  to save the relevant data

 src/ap/ieee802_11.c | 18 ++++++++++++++++++
 src/ap/ieee802_1x.c | 33 +++++++++++++++++++++++++++++++++
 src/ap/sta_info.h   |  7 +++++++
 3 files changed, 58 insertions(+)

diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index b36e68d..06827a5 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -2782,6 +2782,24 @@ 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 just before "
+				   "association notification");
+			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 c774d5c..97e5600 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -860,6 +860,27 @@ ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta)
 				sta->identity, sta->radius_cui);
 }
 
+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);
+		os_free(sta->pending_eapol_rx);
+	}
+
+	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
@@ -891,6 +912,12 @@ 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 for later use");
+			ieee802_1x_save_eapol(sta, buf, len);
+		}
+
 		return;
 	}
 
@@ -1183,6 +1210,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 cd89e99..70a59cc 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;
-- 
2.6.3




More information about the Hostap mailing list