diff --git a/hostapd/config_file.c b/hostapd/config_file.c index fd9bc0e9f..d73a73782 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -4675,6 +4675,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, line, pos); return 1; } + } else if (os_strcmp(buf, "pasn_comeback_after") == 0) { + bss->pasn_comeback_after = atoi(pos); #endif /* CONFIG_PASN */ } else { wpa_printf(MSG_ERROR, diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index d19db5a15..7932cb862 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -2051,6 +2051,13 @@ own_ip_addr=127.0.0.1 # http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-10 #pasn_groups=19 20 21 +# PASN comeback after time in TUs +# In case the AP is temporarily unable to handle a PASN authentication exchange +# due to a too large number of parallel operations, this value indicates to the +# peer after how many TUs it can try the PASN exchange again. +# (default: 10 TUs) +#pasn_comeback_after=10 + ##### IEEE 802.11r configuration ############################################## # Mobility Domain identifier (dot11FTMobilityDomainID, MDID) diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 452386b7e..7b6249bbe 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -165,6 +165,11 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) #ifdef CONFIG_TESTING_OPTIONS bss->sae_commit_status = -1; #endif /* CONFIG_TESTING_OPTIONS */ + +#ifdef CONFIG_PASN + /* comeback after 10 TUs */ + bss->pasn_comeback_after = 10; +#endif /* CONFIG_PASN */ } diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 8aeb03107..f86cf26ca 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -880,6 +880,12 @@ struct hostapd_bss_config { #endif /* CONFIG_TESTING_OPTIONS */ int *pasn_groups; + + /* + * The time in TUs after which the non-AP STA is requested to retry the + * PASN authentication in case there are too many parallel operations. + */ + u16 pasn_comeback_after; #endif /* CONFIG_PASN */ unsigned int unsol_bcast_probe_resp_interval; diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 72d102f44..877d03e3a 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -702,13 +702,15 @@ static int use_anti_clogging(struct hostapd_data *hapd) for (sta = hapd->sta_list; sta; sta = sta->next) { #ifdef CONFIG_SAE - if (!sta->sae) - continue; - if (sta->sae->state != SAE_COMMITTED && - sta->sae->state != SAE_CONFIRMED) - continue; - open++; + if (sta->sae && + (sta->sae->state == SAE_COMMITTED || + sta->sae->state == SAE_CONFIRMED)) + open++; #endif /* CONFIG_SAE */ +#ifdef CONFIG_PASN + if (sta->pasn && sta->pasn->ecdh) + open++; +#endif /* CONFIG_PASN */ if (open >= hapd->conf->anti_clogging_threshold) return 1; } @@ -806,7 +808,8 @@ static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd, if (buf == NULL) return NULL; - wpabuf_put_le16(buf, group); /* Finite Cyclic Group */ + if (group) + wpabuf_put_le16(buf, group); /* Finite Cyclic Group */ if (h2e) { /* Encapsulate Anti-clogging Token field in a container IE */ @@ -2891,6 +2894,54 @@ pasn_derive_keys(struct hostapd_data *hapd, struct sta_info *sta, } +static void handle_auth_pasn_comeback(struct hostapd_data *hapd, + struct sta_info *sta, u16 group) +{ + struct wpabuf *buf, *comeback; + int ret; + + wpa_printf(MSG_DEBUG, + "PASN: Building comeback frame 2. Comeback after=%u", + hapd->conf->pasn_comeback_after); + + buf = wpabuf_alloc(1500); + if (!buf) + return; + + wpa_pasn_build_auth_header(buf, hapd->own_addr, hapd->own_addr, + sta->addr, 2, + WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY); + + /* + * Do not include the group as a part of the token since it is not going + * to be used. + */ + comeback = auth_build_token_req(hapd, 0, sta->addr, 0); + if (!comeback) { + wpa_printf(MSG_DEBUG, + "PASN: Failed sending auth with comeback"); + wpabuf_free(buf); + return; + } + + wpa_pasn_add_parameter_ie(buf, group, + WPA_PASN_WRAPPED_DATA_NO, + NULL, 0, comeback, + hapd->conf->pasn_comeback_after); + wpabuf_free(comeback); + + wpa_printf(MSG_DEBUG, + "PASN: comeback: STA=" MACSTR, MAC2STR(sta->addr)); + + ret = hostapd_drv_send_mlme(hapd, wpabuf_head(buf), wpabuf_len(buf), 0, + NULL, 0, 0); + if (ret) + wpa_printf(MSG_INFO, "PASN: Failed to send comeback frame 2"); + + wpabuf_free(buf); +} + + static int handle_auth_pasn_resp(struct hostapd_data *hapd, struct sta_info *sta, struct rsn_pmksa_cache_entry *pmksa, @@ -3133,6 +3184,25 @@ static void handle_auth_pasn_1(struct hostapd_data *hapd, struct sta_info *sta, goto send_resp; } + if (pasn_params.comeback) { + wpa_printf(MSG_DEBUG, "PASN: Checking peer comeback token"); + + ret = check_comeback_token(hapd, sta->addr, + pasn_params.comeback, + pasn_params.comeback_len); + + if (ret) { + wpa_printf(MSG_DEBUG, "PASN: Invalid comeback token"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto send_resp; + } + } else if (use_anti_clogging(hapd)) { + wpa_printf(MSG_DEBUG, "PASN: Respond with comeback"); + handle_auth_pasn_comeback(hapd, sta, pasn_params.group); + ap_free_sta(hapd, sta); + return; + } + sta->pasn->ecdh = crypto_ecdh_init(pasn_params.group); if (!sta->pasn->ecdh) { wpa_printf(MSG_DEBUG, "PASN: Failed to init ECDH");