]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
FT: Remove and re-add STA entry after FT protocol success with PMF
authorJouni Malinen <j@w1.fi>
Sat, 4 Apr 2020 18:50:37 +0000 (21:50 +0300)
committerJouni Malinen <j@w1.fi>
Sat, 4 Apr 2020 18:53:10 +0000 (21:53 +0300)
Allow STA entry to be removed and re-added to the driver with PMF is
used with FT. Previously, this case resulted in cfg80211 rejecting STA
entry update after successful FT protocol use if the association had not
been dropped and it could not be dropped for the PMF case in
handle_auth().

Signed-off-by: Jouni Malinen <j@w1.fi>
src/ap/ieee802_11.c
src/ap/sta_info.c
src/ap/sta_info.h
src/ap/wpa_auth.c
src/ap/wpa_auth.h
src/ap/wpa_auth_ft.c
src/ap/wpa_auth_glue.c
src/ap/wpa_auth_i.h

index 045a6cbcde46394bd5894b77770641dab17844cf..2a5f6e5ec7a235b426bf1753f0d06a4377a9f44d 100644 (file)
@@ -2526,32 +2526,10 @@ static void handle_auth(struct hostapd_data *hapd,
            (!(sta->flags & WLAN_STA_MFP) || !ap_sta_is_authorized(sta)) &&
            !(hapd->conf->mesh & MESH_ENABLED) &&
            !(sta->added_unassoc)) {
-               /*
-                * If a station that is already associated to the AP, is trying
-                * to authenticate again, remove the STA entry, in order to make
-                * sure the STA PS state gets cleared and configuration gets
-                * updated. To handle this, station's added_unassoc flag is
-                * cleared once the station has completed association.
-                */
-               ap_sta_set_authorized(hapd, sta, 0);
-               hostapd_drv_sta_remove(hapd, sta->addr);
-               sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH |
-                               WLAN_STA_AUTHORIZED);
-
-               if (hostapd_sta_add(hapd, sta->addr, 0, 0,
-                                   sta->supported_rates,
-                                   sta->supported_rates_len,
-                                   0, NULL, NULL, NULL, 0,
-                                   sta->flags, 0, 0, 0, 0)) {
-                       hostapd_logger(hapd, sta->addr,
-                                      HOSTAPD_MODULE_IEEE80211,
-                                      HOSTAPD_LEVEL_NOTICE,
-                                      "Could not add STA to kernel driver");
+               if (ap_sta_re_add(hapd, sta) < 0) {
                        resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
                        goto fail;
                }
-
-               sta->added_unassoc = 1;
        }
 
        switch (auth_alg) {
index 903be28d46db3cc9297a071aac28dc278478575c..93f1f0c201e14d31f0c69de5c133ff8d09359b17 100644 (file)
@@ -1497,3 +1497,33 @@ int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
        return eloop_is_timeout_registered(ap_sta_delayed_1x_auth_fail_cb,
                                           hapd, sta);
 }
+
+
+int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta)
+{
+       /*
+        * If a station that is already associated to the AP, is trying to
+        * authenticate again, remove the STA entry, in order to make sure the
+        * STA PS state gets cleared and configuration gets updated. To handle
+        * this, station's added_unassoc flag is cleared once the station has
+        * completed association.
+        */
+       ap_sta_set_authorized(hapd, sta, 0);
+       hostapd_drv_sta_remove(hapd, sta->addr);
+       sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_AUTH | WLAN_STA_AUTHORIZED);
+
+       if (hostapd_sta_add(hapd, sta->addr, 0, 0,
+                           sta->supported_rates,
+                           sta->supported_rates_len,
+                           0, NULL, NULL, NULL, 0,
+                           sta->flags, 0, 0, 0, 0)) {
+               hostapd_logger(hapd, sta->addr,
+                              HOSTAPD_MODULE_IEEE80211,
+                              HOSTAPD_LEVEL_NOTICE,
+                              "Could not add STA to kernel driver");
+               return -1;
+       }
+
+       sta->added_unassoc = 1;
+       return 0;
+}
index 8ff6ac62fef3f7658b4cca4a53150c3442c84636..308aa29d992cc1d9e2a672ec5251ca7670d9ee46 100644 (file)
@@ -358,5 +358,6 @@ void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
                                            struct sta_info *sta);
 int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
                                                   struct sta_info *sta);
+int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta);
 
 #endif /* STA_INFO_H */
index e0ffb271880baa780bf8280943a3b55fbcfefe51..070236a89c898d9c0640a3b0899521d6d6136f26 100644 (file)
@@ -1836,7 +1836,7 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
 #ifdef CONFIG_IEEE80211R_AP
                wpa_printf(MSG_DEBUG,
                           "FT: Retry PTK configuration after association");
-               wpa_ft_install_ptk(sm);
+               wpa_ft_install_ptk(sm, 1);
 
                /* Using FT protocol, not WPA auth state machine */
                sm->ft_completed = 1;
index 868aaa1faa70e4aa9bb04cc8356b75cbfe9212cf..fafabe9c5395960deae8d105fa9d5013306c5f9f 100644 (file)
@@ -301,6 +301,7 @@ struct wpa_auth_callbacks {
                                 int *bandwidth, int *seg1_idx);
 #ifdef CONFIG_IEEE80211R_AP
        struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
+       int (*add_sta_ft)(void *ctx, const u8 *sta_addr);
        int (*set_vlan)(void *ctx, const u8 *sta_addr,
                        struct vlan_description *vlan);
        int (*get_vlan)(void *ctx, const u8 *sta_addr,
index 476a2be698d72ab8c5a17d9080c47e6c9f77104d..6f6c18eecbc831003e7d122f7c8e80ed24ab3188 100644 (file)
@@ -2747,7 +2747,16 @@ static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
 }
 
 
-void wpa_ft_install_ptk(struct wpa_state_machine *sm)
+static inline int wpa_auth_add_sta_ft(struct wpa_authenticator *wpa_auth,
+                                     const u8 *addr)
+{
+       if (!wpa_auth->cb->add_sta_ft)
+               return -1;
+       return wpa_auth->cb->add_sta_ft(wpa_auth->cb_ctx, addr);
+}
+
+
+void wpa_ft_install_ptk(struct wpa_state_machine *sm, int retry)
 {
        enum wpa_alg alg;
        int klen;
@@ -2769,6 +2778,9 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
                return;
        }
 
+       if (!retry)
+               wpa_auth_add_sta_ft(sm->wpa_auth, sm->addr);
+
        /* FIX: add STA entry to kernel/driver here? The set_key will fail
         * most likely without this.. At the moment, STA entry is added only
         * after association has been completed. This function will be called
@@ -3140,7 +3152,7 @@ pmk_r1_derived:
        sm->pairwise = pairwise;
        sm->PTK_valid = TRUE;
        sm->tk_already_set = FALSE;
-       wpa_ft_install_ptk(sm);
+       wpa_ft_install_ptk(sm, 0);
 
        if (wpa_ft_set_vlan(sm->wpa_auth, sm->addr, &vlan) < 0) {
                wpa_printf(MSG_DEBUG, "FT: Failed to configure VLAN");
index 7a1ed24e8880d39b0effcd7fbb9eb1142240d72f..79880e4784dcf394821097c23ee6de64067fd0d7 100644 (file)
@@ -1038,6 +1038,34 @@ hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr)
 }
 
 
+static int hostapd_wpa_auth_add_sta_ft(void *ctx, const u8 *sta_addr)
+{
+       struct hostapd_data *hapd = ctx;
+       struct sta_info *sta;
+
+       sta = ap_get_sta(hapd, sta_addr);
+       if (!sta)
+               return -1;
+
+       if (FULL_AP_CLIENT_STATE_SUPP(hapd->iface->drv_flags) &&
+           (sta->flags & WLAN_STA_MFP) && ap_sta_is_authorized(sta) &&
+           !(hapd->conf->mesh & MESH_ENABLED) && !(sta->added_unassoc)) {
+               /* We could not do this in handle_auth() since there was a
+                * PMF-enabled association for the STA and the new
+                * authentication attempt was not yet fully processed. Now that
+                * we are ready to configure the TK to the driver,
+                * authentication has succeeded and we can clean up the driver
+                * STA entry to avoid issues with any maintained state from the
+                * previous association. */
+               wpa_printf(MSG_DEBUG,
+                          "FT: Remove and re-add driver STA entry after successful FT authentication");
+               return ap_sta_re_add(hapd, sta);
+       }
+
+       return 0;
+}
+
+
 static int hostapd_wpa_auth_set_vlan(void *ctx, const u8 *sta_addr,
                                     struct vlan_description *vlan)
 {
@@ -1399,6 +1427,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
 #ifdef CONFIG_IEEE80211R_AP
                .send_ft_action = hostapd_wpa_auth_send_ft_action,
                .add_sta = hostapd_wpa_auth_add_sta,
+               .add_sta_ft = hostapd_wpa_auth_add_sta_ft,
                .add_tspec = hostapd_wpa_auth_add_tspec,
                .set_vlan = hostapd_wpa_auth_set_vlan,
                .get_vlan = hostapd_wpa_auth_get_vlan,
index bc59d6a4c0f039263023966eb6b8536ddd57d822..813612e742f58fe5616513e648960ffa8f2258f1 100644 (file)
@@ -300,7 +300,7 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384,
 int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk);
 struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void);
 void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache);
-void wpa_ft_install_ptk(struct wpa_state_machine *sm);
+void wpa_ft_install_ptk(struct wpa_state_machine *sm, int retry);
 int wpa_ft_store_pmk_fils(struct wpa_state_machine *sm, const u8 *pmk_r0,
                          const u8 *pmk_r0_name);
 #endif /* CONFIG_IEEE80211R_AP */