[PATCH] AP: Drop retransmitted auth/assoc frames

Ilan Peer ilan.peer
Wed Nov 5 00:50:34 PST 2014


It is possible that a station device might miss an ACK for
an authentication or association frame, and thus retransmit the
same frame although the frame is already being processed in the stack.

In such a case, the local AP will process the retransmitted frame although
it has already handled the request, which might cause the station to get
confused and as a result disconnect from the AP, blacklist it etc.

To avoid such a case, save the sequence control of the last processed
management frame and in case of retransmissions drop them.

Signed-off-by: Ilan Peer <ilan.peer at intel.com>
---
 src/ap/ieee802_11.c          | 46 +++++++++++++++++++++++++++++++++++++++-----
 src/ap/sta_info.c            |  2 ++
 src/ap/sta_info.h            |  3 +++
 src/common/ieee802_11_defs.h |  2 ++
 4 files changed, 48 insertions(+), 5 deletions(-)

diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index d59a2b4..bb887e9 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -560,6 +560,7 @@ static void handle_auth(struct hostapd_data *hapd,
 	size_t resp_ies_len = 0;
 	char *identity = NULL;
 	char *radius_cui = NULL;
+	u16 seq_ctrl;
 
 	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
 		wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
@@ -581,6 +582,7 @@ static void handle_auth(struct hostapd_data *hapd,
 	auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
 	status_code = le_to_host16(mgmt->u.auth.status_code);
 	fc = le_to_host16(mgmt->frame_control);
+	seq_ctrl = le_to_host16(mgmt->seq_ctrl);
 
 	if (len >= IEEE80211_HDRLEN + sizeof(mgmt->u.auth) +
 	    2 + WLAN_AUTH_CHALLENGE_LEN &&
@@ -653,10 +655,25 @@ static void handle_auth(struct hostapd_data *hapd,
 		return;
 	}
 
-	sta = ap_sta_add(hapd, mgmt->sa);
-	if (!sta) {
-		resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
-		goto fail;
+	sta = ap_get_sta(hapd, mgmt->sa);
+	if (sta) {
+		if ((fc & WLAN_FC_RETRY) &&
+		    (sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ) &&
+		    (sta->last_seq_ctrl == seq_ctrl)) {
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_DEBUG,
+				       "Dropping repeated authentication frame seq_ctrl=%d",
+				       seq_ctrl);
+			return;
+		}
+	} else {
+		sta = ap_sta_add(hapd, mgmt->sa);
+		if (!sta) {
+			resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+			goto fail;
+		}
+		sta->last_seq_ctrl = seq_ctrl;
 	}
 
 	if (vlan_id > 0) {
@@ -1291,7 +1308,7 @@ static void handle_assoc(struct hostapd_data *hapd,
 			 const struct ieee80211_mgmt *mgmt, size_t len,
 			 int reassoc)
 {
-	u16 capab_info, listen_interval;
+	u16 capab_info, listen_interval, seq_ctrl, fc;
 	u16 resp = WLAN_STATUS_SUCCESS;
 	const u8 *pos;
 	int left, i;
@@ -1345,6 +1362,8 @@ static void handle_assoc(struct hostapd_data *hapd,
 		left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
 		pos = mgmt->u.assoc_req.variable;
 	}
+	fc = le_to_host16(mgmt->frame_control);
+	seq_ctrl = le_to_host16(mgmt->seq_ctrl);
 
 	sta = ap_get_sta(hapd, mgmt->sa);
 #ifdef CONFIG_IEEE80211R
@@ -1367,6 +1386,18 @@ static void handle_assoc(struct hostapd_data *hapd,
 		return;
 	}
 
+	if (sta->flags == WLAN_STA_AUTH) {
+		sta->last_seq_ctrl = seq_ctrl;
+	} else if ((fc & WLAN_FC_RETRY) &&
+		   (sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ) &&
+		   (sta->last_seq_ctrl == seq_ctrl)) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "Dropping repeated association frame seq_ctrl=%d",
+			       seq_ctrl);
+		return;
+	}
+
 	if (hapd->tkip_countermeasures) {
 		resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
 		goto fail;
@@ -1492,6 +1523,7 @@ static void handle_disassoc(struct hostapd_data *hapd,
 	}
 
 	ap_sta_set_authorized(hapd, sta, 0);
+	sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
 	sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
 	wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
@@ -1543,6 +1575,7 @@ static void handle_deauth(struct hostapd_data *hapd,
 	}
 
 	ap_sta_set_authorized(hapd, sta, 0);
+	sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
 	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
 			WLAN_STA_ASSOC_REQ_OK);
 	wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
@@ -1877,6 +1910,7 @@ static void handle_auth_cb(struct hostapd_data *hapd,
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_INFO, "authenticated");
 		sta->flags |= WLAN_STA_AUTH;
+		sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
 	}
 }
 
@@ -1945,6 +1979,8 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
 	if (status != WLAN_STATUS_SUCCESS)
 		return;
 
+	sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
+
 	/* Stop previous accounting session, if one is started, and allocate
 	 * new session id for the new session. */
 	accounting_sta_stop(hapd, sta);
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index ec0e493..aae6b14 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -600,6 +600,7 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
 	sta->ssid = &hapd->conf->ssid;
 	ap_sta_remove_in_other_bss(hapd, sta);
 
+	sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
 	return sta;
 }
 
@@ -663,6 +664,7 @@ void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
 {
 	wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
 		   hapd->conf->iface, MAC2STR(sta->addr));
+	sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
 	sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
 	ap_sta_set_authorized(hapd, sta, 0);
 	sta->timeout_next = STA_DEAUTH;
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 25edd7f..ec195f0 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -152,6 +152,9 @@ struct sta_info {
 #endif /* CONFIG_SAE */
 
 	u32 session_timeout; /* valid only if session_timeout_set == 1 */
+
+	/* last auth/assoc seq. control */
+	u16 last_seq_ctrl;
 };
 
 
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index f5adbc0..5ea4a9d 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -25,6 +25,8 @@
 #define WLAN_FC_GET_TYPE(fc)	(((fc) & 0x000c) >> 2)
 #define WLAN_FC_GET_STYPE(fc)	(((fc) & 0x00f0) >> 4)
 
+#define WLAN_INVALID_MGMT_SEQ   0xFFFF
+
 #define WLAN_GET_SEQ_FRAG(seq) ((seq) & (BIT(3) | BIT(2) | BIT(1) | BIT(0)))
 #define WLAN_GET_SEQ_SEQ(seq) \
 	(((seq) & (~(BIT(3) | BIT(2) | BIT(1) | BIT(0)))) >> 4)
-- 
1.8.3.2




More information about the Hostap mailing list