diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 045a6cbcd..2a5f6e5ec 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -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) { diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c index 903be28d4..93f1f0c20 100644 --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c @@ -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; +} diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h index 8ff6ac62f..308aa29d9 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -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 */ diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index e0ffb2718..070236a89 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -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; diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index 868aaa1fa..fafabe9c5 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -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, diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index 476a2be69..6f6c18eec 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -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"); diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index 7a1ed24e8..79880e478 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -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, diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h index bc59d6a4c..813612e74 100644 --- a/src/ap/wpa_auth_i.h +++ b/src/ap/wpa_auth_i.h @@ -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 */