diff --git a/hostapd/Makefile b/hostapd/Makefile index 8404e0cb1..26cc2b513 100644 --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -824,6 +824,10 @@ LIBS += -lsqlite3 LIBS_h += -lsqlite3 endif +ifdef CONFIG_TESTING_OPTIONS +CFLAGS += -DCONFIG_TESTING_OPTIONS +endif + ALL=hostapd hostapd_cli all: verify_config $(ALL) diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 12d627a8a..cd68e3ef9 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -2876,6 +2876,25 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->hs20_operating_class = oper_class; bss->hs20_operating_class_len = oper_class_len; #endif /* CONFIG_HS20 */ +#ifdef CONFIG_TESTING_OPTIONS +#define PARSE_TEST_PROBABILITY(_val) \ + } else if (os_strcmp(buf, #_val) == 0) { \ + char *end; \ + \ + conf->_val = strtod(pos, &end); \ + if (*end || conf->_val < 0.0d || \ + conf->_val > 1.0d) { \ + wpa_printf(MSG_ERROR, \ + "Line %d: Invalid value '%s'", \ + line, pos); \ + errors++; \ + return errors; \ + } + PARSE_TEST_PROBABILITY(ignore_probe_probability) + PARSE_TEST_PROBABILITY(ignore_auth_probability) + PARSE_TEST_PROBABILITY(ignore_assoc_probability) + PARSE_TEST_PROBABILITY(ignore_reassoc_probability) +#endif /* CONFIG_TESTING_OPTIONS */ } else if (os_strcmp(buf, "vendor_elements") == 0) { struct wpabuf *elems; size_t len = os_strlen(pos); diff --git a/hostapd/defconfig b/hostapd/defconfig index b5ddca34c..317fe740e 100644 --- a/hostapd/defconfig +++ b/hostapd/defconfig @@ -267,3 +267,11 @@ CONFIG_IPV6=y # Enable SQLite database support in hlr_auc_gw, EAP-SIM DB, and eap_user_file #CONFIG_SQLITE=y + +# Testing options +# This can be used to enable some testing options (see also the example +# configuration file) that are really useful only for testing clients that +# connect to this hostapd. These options allow, for example, to drop a +# certain percentage of probe requests or auth/(re)assoc frames. +# +#CONFIG_TESTING_OPTIONS=y diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index 17bb7ed78..d4425866b 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -1521,6 +1521,25 @@ own_ip_addr=127.0.0.1 # channels 36-48): #hs20_operating_class=5173 +##### TESTING OPTIONS ######################################################### +# +# The options in this section are only available when the build configuration +# option CONFIG_TESTING_OPTIONS is set while compiling hostapd. They allow +# testing some scenarios that are otherwise difficult to reproduce. +# +# Ignore probe requests sent to hostapd with the given probability, must be a +# floating point number in the range [0, 1). +#ignore_probe_probability=0.0 +# +# Ignore authentication frames with the given probability +#ignore_auth_probability=0.0 +# +# Ignore association requests with the given probability +#ignore_assoc_probability=0.0 +# +# Ignore reassociation requests with the given probability +#ignore_reassoc_probability=0.0 + ##### Multiple BSSID support ################################################## # # Above configuration is using the default interface (wlan#, or multi-SSID VLAN diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 922f56469..70b26a6ee 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -163,6 +163,13 @@ struct hostapd_config * hostapd_config_defaults(void) conf->ap_table_max_size = 255; conf->ap_table_expiration_time = 60; +#ifdef CONFIG_TESTING_OPTIONS + conf->ignore_probe_probability = 0.0d; + conf->ignore_auth_probability = 0.0d; + conf->ignore_assoc_probability = 0.0d; + conf->ignore_reassoc_probability = 0.0d; +#endif /* CONFIG_TESTING_OPTIONS */ + return conf; } diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index d9ef984df..f9629a2cd 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -520,6 +520,13 @@ struct hostapd_config { u8 vht_oper_chwidth; u8 vht_oper_centr_freq_seg0_idx; u8 vht_oper_centr_freq_seg1_idx; + +#ifdef CONFIG_TESTING_OPTIONS + double ignore_probe_probability; + double ignore_auth_probability; + double ignore_assoc_probability; + double ignore_reassoc_probability; +#endif /* CONFIG_TESTING_OPTIONS */ }; diff --git a/src/ap/beacon.c b/src/ap/beacon.c index 4c47c7584..0ef307d34 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -488,6 +488,16 @@ void handle_probe_req(struct hostapd_data *hapd, /* TODO: verify that supp_rates contains at least one matching rate * with AP configuration */ +#ifdef CONFIG_TESTING_OPTIONS + if (hapd->iconf->ignore_probe_probability > 0.0d && + drand48() < hapd->iconf->ignore_probe_probability) { + wpa_printf(MSG_INFO, + "TESTING: ignoring probe request from " MACSTR, + MAC2STR(mgmt->sa)); + return; + } +#endif /* CONFIG_TESTING_OPTIONS */ + resp = hostapd_gen_probe_resp(hapd, sta, mgmt, elems.p2p != NULL, &resp_len); if (resp == NULL) diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 8baa15e70..7bef55fa5 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -557,6 +557,16 @@ static void handle_auth(struct hostapd_data *hapd, return; } +#ifdef CONFIG_TESTING_OPTIONS + if (hapd->iconf->ignore_auth_probability > 0.0d && + drand48() < hapd->iconf->ignore_auth_probability) { + wpa_printf(MSG_INFO, + "TESTING: ignoring auth frame from " MACSTR, + MAC2STR(mgmt->sa)); + return; + } +#endif /* CONFIG_TESTING_OPTIONS */ + auth_alg = le_to_host16(mgmt->u.auth.auth_alg); auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction); status_code = le_to_host16(mgmt->u.auth.status_code); @@ -1226,6 +1236,26 @@ static void handle_assoc(struct hostapd_data *hapd, return; } +#ifdef CONFIG_TESTING_OPTIONS + if (reassoc) { + if (hapd->iconf->ignore_reassoc_probability > 0.0d && + drand48() < hapd->iconf->ignore_reassoc_probability) { + wpa_printf(MSG_INFO, + "TESTING: ignoring reassoc request from " + MACSTR, MAC2STR(mgmt->sa)); + return; + } + } else { + if (hapd->iconf->ignore_assoc_probability > 0.0d && + drand48() < hapd->iconf->ignore_assoc_probability) { + wpa_printf(MSG_INFO, + "TESTING: ignoring assoc request from " + MACSTR, MAC2STR(mgmt->sa)); + return; + } + } +#endif /* CONFIG_TESTING_OPTIONS */ + if (reassoc) { capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info); listen_interval = le_to_host16(