FT: Remove and re-add STA entry after FT protocol success with PMF

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>
This commit is contained in:
Jouni Malinen 2020-04-04 21:50:37 +03:00
parent af23f3a849
commit d867e11811
8 changed files with 78 additions and 27 deletions

View file

@ -2526,32 +2526,10 @@ static void handle_auth(struct hostapd_data *hapd,
(!(sta->flags & WLAN_STA_MFP) || !ap_sta_is_authorized(sta)) && (!(sta->flags & WLAN_STA_MFP) || !ap_sta_is_authorized(sta)) &&
!(hapd->conf->mesh & MESH_ENABLED) && !(hapd->conf->mesh & MESH_ENABLED) &&
!(sta->added_unassoc)) { !(sta->added_unassoc)) {
/* if (ap_sta_re_add(hapd, sta) < 0) {
* 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");
resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
goto fail; goto fail;
} }
sta->added_unassoc = 1;
} }
switch (auth_alg) { switch (auth_alg) {

View 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, return eloop_is_timeout_registered(ap_sta_delayed_1x_auth_fail_cb,
hapd, sta); 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;
}

View file

@ -358,5 +358,6 @@ void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
struct sta_info *sta); struct sta_info *sta);
int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd, int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
struct sta_info *sta); struct sta_info *sta);
int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta);
#endif /* STA_INFO_H */ #endif /* STA_INFO_H */

View file

@ -1836,7 +1836,7 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
#ifdef CONFIG_IEEE80211R_AP #ifdef CONFIG_IEEE80211R_AP
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
"FT: Retry PTK configuration after association"); "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 */ /* Using FT protocol, not WPA auth state machine */
sm->ft_completed = 1; sm->ft_completed = 1;

View file

@ -301,6 +301,7 @@ struct wpa_auth_callbacks {
int *bandwidth, int *seg1_idx); int *bandwidth, int *seg1_idx);
#ifdef CONFIG_IEEE80211R_AP #ifdef CONFIG_IEEE80211R_AP
struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr); 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, int (*set_vlan)(void *ctx, const u8 *sta_addr,
struct vlan_description *vlan); struct vlan_description *vlan);
int (*get_vlan)(void *ctx, const u8 *sta_addr, int (*get_vlan)(void *ctx, const u8 *sta_addr,

View 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; enum wpa_alg alg;
int klen; int klen;
@ -2769,6 +2778,9 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
return; 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 /* 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 * most likely without this.. At the moment, STA entry is added only
* after association has been completed. This function will be called * after association has been completed. This function will be called
@ -3140,7 +3152,7 @@ pmk_r1_derived:
sm->pairwise = pairwise; sm->pairwise = pairwise;
sm->PTK_valid = TRUE; sm->PTK_valid = TRUE;
sm->tk_already_set = FALSE; 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) { if (wpa_ft_set_vlan(sm->wpa_auth, sm->addr, &vlan) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to configure VLAN"); wpa_printf(MSG_DEBUG, "FT: Failed to configure VLAN");

View 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, static int hostapd_wpa_auth_set_vlan(void *ctx, const u8 *sta_addr,
struct vlan_description *vlan) struct vlan_description *vlan)
{ {
@ -1399,6 +1427,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
#ifdef CONFIG_IEEE80211R_AP #ifdef CONFIG_IEEE80211R_AP
.send_ft_action = hostapd_wpa_auth_send_ft_action, .send_ft_action = hostapd_wpa_auth_send_ft_action,
.add_sta = hostapd_wpa_auth_add_sta, .add_sta = hostapd_wpa_auth_add_sta,
.add_sta_ft = hostapd_wpa_auth_add_sta_ft,
.add_tspec = hostapd_wpa_auth_add_tspec, .add_tspec = hostapd_wpa_auth_add_tspec,
.set_vlan = hostapd_wpa_auth_set_vlan, .set_vlan = hostapd_wpa_auth_set_vlan,
.get_vlan = hostapd_wpa_auth_get_vlan, .get_vlan = hostapd_wpa_auth_get_vlan,

View 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); 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); 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_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, int wpa_ft_store_pmk_fils(struct wpa_state_machine *sm, const u8 *pmk_r0,
const u8 *pmk_r0_name); const u8 *pmk_r0_name);
#endif /* CONFIG_IEEE80211R_AP */ #endif /* CONFIG_IEEE80211R_AP */