From patchwork Tue Feb 16 09:54:33 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilan Peer X-Patchwork-Id: 583233 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2001:1868:205::9]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 7FFEC140557 for ; Tue, 16 Feb 2016 18:59:09 +1100 (AEDT) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1aVaX3-0003Nz-Ho; Tue, 16 Feb 2016 07:58:49 +0000 Received: from mga03.intel.com ([134.134.136.65]) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1aVaWx-0003Hp-AL for hostap@lists.infradead.org; Tue, 16 Feb 2016 07:58:45 +0000 Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga103.jf.intel.com with ESMTP; 15 Feb 2016 23:58:25 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.22,454,1449561600"; d="scan'208";a="885818100" Received: from unknown (HELO JED00377.ger.corp.intel.com) ([10.12.217.192]) by orsmga001.jf.intel.com with ESMTP; 15 Feb 2016 23:58:25 -0800 From: Ilan Peer To: hostap@lists.infradead.org Subject: [PATCH v3 3/3] AP: Set STA assoc flag in the driver before sending Assoc Resp frame Date: Tue, 16 Feb 2016 11:54:33 +0200 Message-Id: <1455616473-26801-3-git-send-email-ilan.peer@intel.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1455616473-26801-1-git-send-email-ilan.peer@intel.com> References: <1455616473-26801-1-git-send-email-ilan.peer@intel.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160215_235843_566461_B1D3D5A2 X-CRM114-Status: GOOD ( 21.96 ) X-Spam-Score: -6.9 (------) X-Spam-Report: SpamAssassin version 3.4.0 on bombadil.infradead.org summary: Content analysis details: (-6.9 points) pts rule name description ---- ---------------------- -------------------------------------------------- -5.0 RCVD_IN_DNSWL_HI RBL: Sender listed at http://www.dnswl.org/, high trust [134.134.136.65 listed in list.dnswl.org] -0.0 RCVD_IN_MSPIKE_H3 RBL: Good reputation (+3) [134.134.136.65 listed in wl.mailspike.net] -0.0 SPF_PASS SPF: sender matches SPF record -0.0 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] -0.0 RCVD_IN_MSPIKE_WL Mailspike good senders X-BeenThere: hostap@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Andrei Otcheretianski MIME-Version: 1.0 Sender: "Hostap" Errors-To: hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org From: Andrei Otcheretianski Previously, stations were added to the driver only after the (Re)Association Response frame was acked. In the time period between the station has acked the (Re)Association Response frame and the time the station was added to the kernel, the station can already start sending Data frames, which will be dropped by the hardware/driver. In addition to the data loss, the driver may ignore NDPs with PM bit set from this STA. Fix this by setting/adding the STA with associated flag set to the driver before the AP sends the (Re)Association Response frame with status success. If the (Re)Association Response frame wasn't acked, remove the station from the driver. Note that setting a station to associated state before the non-AP station acknowledged the association response is not compatible with the IEEE 802.11 standard that specifically states that a non-AP station should transition to authenticated/associated state only after it acknowledged the association response frame. However, consider this as a workaround for the issue described above as: 1. The station would be removed in case it did not acknowledge the association response frame. 2. All data frames would be dropped until the station is set to authorized and there are no known issues with processing the other class 3 data frames during the short window before the acknowledgement is seen. Signed-off-by: Andrei Otcheretianski --- src/ap/ieee802_11.c | 161 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 95 insertions(+), 66 deletions(-) diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 1638d51..1df49f5 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -1723,6 +1723,62 @@ static void send_deauth(struct hostapd_data *hapd, const u8 *addr, } +static int add_associated_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. + * This is relevant for cases, such as FT over the DS, where a station + * re-associates back to the same AP but skips the authentication flow. + * Or, if working with a driver that doesn't support full AP client + * state. + */ + if (!sta->added_unassoc) + 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 */ + + /* + * Add the station with forced WLAN_STA_ASSOC flag. The sta->flags + * will be set when the assoc. resp. ACK is processed. + */ + 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 | WLAN_STA_ASSOC, sta->qosinfo, + sta->vht_opmode, sta->added_unassoc)) { + hostapd_logger(hapd, sta->addr, + HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_NOTICE, + "Could not %s STA to kernel driver", + sta->added_unassoc ? "set" : "add"); + + if (sta->added_unassoc) { + hostapd_drv_sta_remove(hapd, sta->addr); + sta->added_unassoc = 0; + } + + return -1; + } + + sta->added_unassoc = 0; + + return 0; +} + + static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, u16 status_code, int reassoc, const u8 *ies, size_t ies_len) @@ -2060,9 +2116,34 @@ static void handle_assoc(struct hostapd_data *hapd, sta->timeout_next = STA_NULLFUNC; fail: + /* + * In case of successful response add the station to the driver, + * otherwise the kernel may ignore data frames before we process the + * ack. In case of failure, this station will be removed. + * + * Note that this is incompatible with the IEEE 802.11 standard that + * states that a non-AP station should transition to the + * authenticated/associated state only after the station acknowledged + * the association response frame. However still do this as: + * + * 1. In case that the station does not acknowledge the association + * frame it would be removed. + * 2. Data frames would be dropped in the kernel until the station is + * set to authorized, and there are no significant known issues with + * processing other non-data class 3 frames. + */ + if (resp == WLAN_STATUS_SUCCESS && add_associated_sta(hapd, sta)) + resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; + reply_res = send_assoc_resp(hapd, sta, resp, reassoc, pos, left); - if (sta->added_unassoc && (resp != WLAN_STATUS_SUCCESS || - reply_res != WLAN_STATUS_SUCCESS)) { + + /* + * Remove the station in case of failure tx a successful response (it + * was added associated to the driver) or if the station was previously + * added unassociated. + */ + if ((reply_res != WLAN_STATUS_SUCCESS && + resp == WLAN_STATUS_SUCCESS) || sta->added_unassoc) { hostapd_drv_sta_remove(hapd, sta->addr); sta->added_unassoc = 0; } @@ -2558,8 +2639,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; sta = ap_get_sta(hapd, mgmt->da); if (!sta) { @@ -2573,21 +2652,26 @@ static void handle_assoc_cb(struct hostapd_data *hapd, wpa_printf(MSG_INFO, "handle_assoc_cb(reassoc=%d) - too short payload (len=%lu)", reassoc, (unsigned long) len); - goto remove_sta; + hostapd_drv_sta_remove(hapd, sta->addr); + return; } + if (reassoc) + status = le_to_host16(mgmt->u.reassoc_resp.status_code); + else + status = le_to_host16(mgmt->u.assoc_resp.status_code); + if (!ok) { hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "did not acknowledge association response"); sta->flags &= ~WLAN_STA_ASSOC_REQ_OK; - goto remove_sta; - } + /* The STA is added only in case of SUCCESS */ + if (status == WLAN_STATUS_SUCCESS) + hostapd_drv_sta_remove(hapd, sta->addr); - if (reassoc) - status = le_to_host16(mgmt->u.reassoc_resp.status_code); - else - status = le_to_host16(mgmt->u.assoc_resp.status_code); + return; + } if (status != WLAN_STATUS_SUCCESS) return; @@ -2623,54 +2707,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. - * - * This is relevant for cases, such as FT over the DS, where a station - * reassociates back to the same AP but skips the authentication flow - * and if working with a driver that doesn't support full AP client - * state. - */ - if (!sta->added_unassoc) - 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, - sta->added_unassoc)) { - hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_NOTICE, - "Could not %s STA to kernel driver", - sta->added_unassoc ? "set" : "add"); - ap_sta_disconnect(hapd, sta, sta->addr, - WLAN_REASON_DISASSOC_AP_BUSY); - if (sta->added_unassoc) - goto remove_sta; - return; - } - - /* - * added_unassoc flag is set for a station that was added to the driver - * in unassociated state. Clear this flag once the station has completed - * association, to make sure the STA entry will be cleared from the - * driver in case of reassocition back to the same AP. - */ - sta->added_unassoc = 0; - if (sta->flags & WLAN_STA_WDS) { int ret; char ifname_wds[IFNAMSIZ + 1]; @@ -2702,14 +2738,7 @@ static void handle_assoc_cb(struct hostapd_data *hapd, else 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); - -remove_sta: - if (sta->added_unassoc) { - hostapd_drv_sta_remove(hapd, sta->addr); - sta->added_unassoc = 0; - } }