[PATCH 1/3] AP: add station to driver before sending Assoc Resp

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


Station could receive Assoc Resp from AP and start
sending frames back (e.g. NullFunc saying it goes
to sleep) to AP before the AP processed TX_STATUS
for the Assoc Resp. Depending on device driver and
event ordering the station could end up being
Deauthenticated with reason 7 (class 3 from
non-assoc sta) by the AP.

Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
---
 src/ap/ieee802_11.c | 96 ++++++++++++++++++++++++++++++++---------------------
 1 file changed, 59 insertions(+), 37 deletions(-)

diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index db20c8679093..957fd02eff24 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1561,6 +1561,40 @@ 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)
+{
+	/*
+	 * Remove the STA entry in order to make sure the STA PS state gets
+	 * cleared and configuration gets updated in case of reassociation back
+	 * to the same AP.
+	 */
+	hostapd_drv_sta_remove(hapd, sta->addr);
+
+#ifdef CONFIG_IEEE80211N
+	if (sta->flags & WLAN_STA_HT)
+		hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
+#endif /* CONFIG_IEEE80211N */
+#ifdef CONFIG_IEEE80211AC
+	if (sta->flags & WLAN_STA_VHT)
+		hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
+#endif /* CONFIG_IEEE80211AC */
+
+	if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability,
+			    sta->supported_rates, sta->supported_rates_len,
+			    sta->listen_interval,
+			    sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
+			    sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
+			    sta->flags, sta->qosinfo, sta->vht_opmode)) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_NOTICE,
+			       "Could not add STA to kernel driver");
+		return -1;
+	}
+
+	return 0;
+}
+
+
 static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
 			    u16 status_code, int reassoc, const u8 *ies,
 			    size_t ies_len)
@@ -1784,7 +1818,7 @@ static void handle_assoc(struct hostapd_data *hapd,
 
 	if (hapd->tkip_countermeasures) {
 		resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
-		goto fail;
+		goto send_resp;
 	}
 
 	if (listen_interval > hapd->conf->max_listen_interval) {
@@ -1793,20 +1827,20 @@ static void handle_assoc(struct hostapd_data *hapd,
 			       "Too large Listen Interval (%d)",
 			       listen_interval);
 		resp = WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE;
-		goto fail;
+		goto send_resp;
 	}
 
 	/* followed by SSID and Supported rates; and HT capabilities if 802.11n
 	 * is used */
 	resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
 	if (resp != WLAN_STATUS_SUCCESS)
-		goto fail;
+		goto send_resp;
 
 	if (hostapd_get_aid(hapd, sta) < 0) {
 		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_INFO, "No room for more AIDs");
 		resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
-		goto fail;
+		goto send_resp;
 	}
 
 	sta->capability = capab_info;
@@ -1879,8 +1913,28 @@ static void handle_assoc(struct hostapd_data *hapd,
 	 * remove the STA immediately. */
 	sta->timeout_next = STA_NULLFUNC;
 
- fail:
+send_resp:
+	if (resp == WLAN_STATUS_SUCCESS) {
+		/* TODO: The station shouldn't be considered as Associated
+		 * until after Assoc Resp ACK is delivered. However some
+		 * drivers can get racy and end up deauthing stations before
+		 * hostap adds the station entry.
+		 *
+		 * Currently stations are transitioned from non-existent into
+		 * associated state right away. Ideally this should be split so
+		 * that station can have 2 transitions: non-existent ->
+		 * authenticated, authenticated -> associated.
+		 */
+		res = add_pre_assoc_sta(hapd, sta);
+		if (res)
+			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
 	send_assoc_resp(hapd, sta, resp, reassoc, pos, left);
+
+	if (resp != WLAN_STATUS_SUCCESS)
+		ap_sta_disconnect(hapd, sta, sta->addr,
+				  WLAN_REASON_DISASSOC_AP_BUSY);
 }
 
 
@@ -2415,38 +2469,6 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
 	sta->sa_query_timed_out = 0;
 #endif /* CONFIG_IEEE80211W */
 
-	/*
-	 * Remove the STA entry in order to make sure the STA PS state gets
-	 * cleared and configuration gets updated in case of reassociation back
-	 * to the same AP.
-	 */
-	hostapd_drv_sta_remove(hapd, sta->addr);
-
-#ifdef CONFIG_IEEE80211N
-	if (sta->flags & WLAN_STA_HT)
-		hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
-#endif /* CONFIG_IEEE80211N */
-#ifdef CONFIG_IEEE80211AC
-	if (sta->flags & WLAN_STA_VHT)
-		hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap);
-#endif /* CONFIG_IEEE80211AC */
-
-	if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability,
-			    sta->supported_rates, sta->supported_rates_len,
-			    sta->listen_interval,
-			    sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
-			    sta->flags & WLAN_STA_VHT ? &vht_cap : NULL,
-			    sta->flags, sta->qosinfo, sta->vht_opmode)) {
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-			       HOSTAPD_LEVEL_NOTICE,
-			       "Could not add STA to kernel driver");
-
-		ap_sta_disconnect(hapd, sta, sta->addr,
-				  WLAN_REASON_DISASSOC_AP_BUSY);
-
-		return;
-	}
-
 	if (sta->flags & WLAN_STA_WDS) {
 		int ret;
 		char ifname_wds[IFNAMSIZ + 1];
-- 
2.1.4




More information about the Hostap mailing list