From: Ben Greear <greearb@xxxxxxxxxxxxxxx> This is nice for testing a peer's handling of EAPOL delays. Also improve the os_reltime logic a bit, based on looking at the code while adding some helper methods. Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx> --- src/utils/os.h | 21 +++++++ wpa_supplicant/config.c | 13 +++++ wpa_supplicant/config.h | 7 +++ wpa_supplicant/wpa_supplicant.c | 114 +++++++++++++++++++++++++++++++++++++ wpa_supplicant/wpa_supplicant.conf | 12 ++++ wpa_supplicant/wpa_supplicant_i.h | 14 +++++ 6 files changed, 181 insertions(+) diff --git a/src/utils/os.h b/src/utils/os.h index e8f0b79..25f7498 100644 --- a/src/utils/os.h +++ b/src/utils/os.h @@ -83,8 +83,29 @@ static inline void os_reltime_sub(struct os_reltime *a, struct os_reltime *b, res->sec--; res->usec += 1000000; } + else if (res->usec > 1000000) { + /* Deal with subtracting negative value */ + res->sec++; + res->usec -= 1000000; + } } +static inline void os_reltime_add_ms(struct os_reltime *a, os_time_t ms_to_add) +{ + os_time_t sec = ms_to_add / 1000000; + os_time_t usec = (ms_to_add % 1000000) * 1000; + a->sec += sec; + a->usec += usec; + if (a->usec > 1000000) { + a->sec++; + a->usec -= 1000000; + } + else if (a->usec < 0) { + /* added negative value? */ + a->sec--; + a->usec += 1000000; + } +} static inline void os_reltime_age(struct os_reltime *start, struct os_reltime *age) diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index d56b6da..04d6613 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -3843,6 +3843,13 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, config->corrupt_eapol_4_of_4 = DEFAULT_IGNORE_AUTH_RESP; config->corrupt_eapol_2_of_2 = DEFAULT_IGNORE_AUTH_RESP; config->corrupt_eapol_key_req = DEFAULT_IGNORE_AUTH_RESP; + + config->delay_eapol_1_of_4_min = DEFAULT_IGNORE_AUTH_RESP; + config->delay_eapol_1_of_4_max = DEFAULT_IGNORE_AUTH_RESP; + config->delay_eapol_3_of_4_min = DEFAULT_IGNORE_AUTH_RESP; + config->delay_eapol_3_of_4_max = DEFAULT_IGNORE_AUTH_RESP; + config->delay_eapol_1_of_2_min = DEFAULT_IGNORE_AUTH_RESP; + config->delay_eapol_1_of_2_max = DEFAULT_IGNORE_AUTH_RESP; #endif return config; @@ -4572,6 +4579,12 @@ static const struct global_parse_data global_fields[] = { { INT(corrupt_eapol_4_of_4), 0 }, { INT(corrupt_eapol_2_of_2), 0 }, { INT(corrupt_eapol_key_req), 0 }, + { INT(delay_eapol_1_of_4_min), 0 }, + { INT(delay_eapol_1_of_4_max), 0 }, + { INT(delay_eapol_3_of_4_min), 0 }, + { INT(delay_eapol_3_of_4_max), 0 }, + { INT(delay_eapol_1_of_2_min), 0 }, + { INT(delay_eapol_1_of_2_max), 0 }, #endif { INT(accept_external_scan_results), 0 }, { STR(wowlan_triggers), 0 }, diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index 1e31255..9e72642 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -897,6 +897,13 @@ struct wpa_config { unsigned short corrupt_eapol_2_of_2; unsigned short corrupt_eapol_key_req; + unsigned short delay_eapol_1_of_4_min; + unsigned short delay_eapol_1_of_4_max; + unsigned short delay_eapol_3_of_4_min; + unsigned short delay_eapol_3_of_4_max; + unsigned short delay_eapol_1_of_2_min; + unsigned short delay_eapol_1_of_2_max; + #endif /** diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 7c2ebd3..2ac5942 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -112,6 +112,12 @@ const char *const wpa_supplicant_full_license5 = "\n"; #endif /* CONFIG_NO_STDOUT_DEBUG */ +#ifdef CONFIG_TESTING_OPTIONS +static void delayed_eapol_timer(void *eloop_ctxt, void *timeout_ctxt); +void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, + const u8 *buf, size_t len); +#endif + /* Configure default/group WEP keys for static WEP */ int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { @@ -439,6 +445,13 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) #ifdef CONFIG_TESTING_OPTIONS l2_packet_deinit(wpa_s->l2_test); wpa_s->l2_test = NULL; + while (!dl_list_empty(&wpa_s->delayed_eapol_list)) { + struct delayed_msg *dm = dl_list_first(&wpa_s->delayed_eapol_list, + struct delayed_msg, list); + dl_list_del(&dm->list); + os_free(dm); + } + eloop_cancel_timeout(delayed_eapol_timer, wpa_s, NULL); #endif /* CONFIG_TESTING_OPTIONS */ if (wpa_s->conf != NULL) { @@ -3483,6 +3496,60 @@ static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s, return -1; } +#ifdef CONFIG_TESTING_OPTIONS +u16 rnd_min_max_delay(u16 min, u16 max) +{ + u16 rv = min; + if (max > min) { + int diff = max - min; + unsigned long rnd = os_random(); + rv += (rnd % (diff + 1)); + } + + return rv; +} + +void wpa_refresh_delayed_msg_timer(struct wpa_supplicant *wpa_s) +{ + if (dl_list_empty(&wpa_s->delayed_eapol_list)) { + eloop_cancel_timeout(delayed_eapol_timer, wpa_s, NULL); + } + else { + struct delayed_msg *dm = dl_list_first(&wpa_s->delayed_eapol_list, + struct delayed_msg, list); + struct os_reltime now, diff; + memset(&diff, 0, sizeof(diff)); + os_get_reltime(&now); + if (os_reltime_before(&now, &dm->txtime)) { + os_reltime_sub(&dm->txtime, &now, &diff); + } + + eloop_cancel_timeout(delayed_eapol_timer, wpa_s, NULL); + eloop_register_timeout(diff.sec, diff.usec, delayed_eapol_timer, wpa_s, NULL); + } +} + +static void delayed_eapol_timer(void *eloop_ctxt, void *timeout_ctxt) +{ + struct wpa_supplicant *wpa_s = eloop_ctxt; + if (!dl_list_empty(&wpa_s->delayed_eapol_list)) { + struct delayed_msg *dm = dl_list_first(&wpa_s->delayed_eapol_list, + struct delayed_msg, list); + struct os_reltime now; + os_get_reltime(&now); + if (!os_reltime_before(&now, &dm->txtime)) { + /* peel one off and transmit it */ + dl_list_del(&dm->list); + /* Ensure it is not delayed again. */ + wpa_s->delays_disabled = 1; + wpa_supplicant_rx_eapol(wpa_s, dm->src_addr, dm->msg, dm->msg_len); + wpa_s->delays_disabled = 0; + os_free(dm); + } + } + wpa_refresh_delayed_msg_timer(wpa_s); +} +#endif /** * wpa_supplicant_rx_eapol - Deliver a received EAPOL frame to wpa_supplicant @@ -3504,6 +3571,7 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, struct wpa_supplicant *wpa_s = ctx; #ifdef CONFIG_TESTING_OPTIONS enum eapol_key_msg_type emt; + u16 delay_ms = 0; #endif wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr)); @@ -3539,6 +3607,49 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr, return; } } + + /* Check for delayed eapol pkts */ + if (wpa_s->delays_disabled) + goto after_delay_check; + + if (emt == EAPOL_MSG_TYPE_1_OF_4) { + if (wpa_s->conf->delay_eapol_1_of_4_min) { + delay_ms = rnd_min_max_delay(wpa_s->conf->delay_eapol_1_of_4_min, + wpa_s->conf->delay_eapol_1_of_4_max); + wpa_dbg(wpa_s, MSG_INFO, "RX EAPOL - delay eapol 1 of 4 by %d ms!", delay_ms); + } + } + else if (emt == EAPOL_MSG_TYPE_3_OF_4) { + if (wpa_s->conf->delay_eapol_3_of_4_min) { + delay_ms = rnd_min_max_delay(wpa_s->conf->delay_eapol_3_of_4_min, + wpa_s->conf->delay_eapol_3_of_4_max); + wpa_dbg(wpa_s, MSG_INFO, "RX EAPOL - delay eapol 3 of 4 by %d ms!", delay_ms); + } + } + else if (emt == EAPOL_MSG_TYPE_GROUP_1_OF_2) { + if (wpa_s->conf->delay_eapol_1_of_2_min) { + delay_ms = rnd_min_max_delay(wpa_s->conf->delay_eapol_1_of_2_min, + wpa_s->conf->delay_eapol_1_of_2_max); + wpa_dbg(wpa_s, MSG_INFO, "RX EAPOL - delay eapol 1 of 2 by %d ms!", delay_ms); + } + } + + if (delay_ms || !dl_list_empty(&wpa_s->delayed_eapol_list)) { + struct delayed_msg *dm = os_malloc(sizeof(*dm)); + if (!dm) { + wpa_dbg(wpa_s, MSG_INFO, "RX EAPOL - OOM trying to alloc delayed msg, dropping!"); + return; + } + os_get_reltime(&dm->txtime); + os_reltime_add_ms(&dm->txtime, delay_ms); + memcpy(dm->src_addr, src_addr, ETH_ALEN); + memcpy(dm->msg, buf, len); + dm->msg_len = len; + dl_list_add_tail(&wpa_s->delayed_eapol_list, &dm->list); + wpa_refresh_delayed_msg_timer(wpa_s); + return; + } +after_delay_check: #endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_PEERKEY @@ -3831,6 +3942,9 @@ wpa_supplicant_alloc(struct wpa_supplicant *parent) wpa_s->sched_scanning = 0; dl_list_init(&wpa_s->bss_tmp_disallowed); +#ifdef CONFIG_TESTING_OPTIONS + dl_list_init(&wpa_s->delayed_eapol_list); +#endif return wpa_s; } diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index 500d575..551f76e 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -1385,6 +1385,18 @@ fast_reauth=1 #corrupt_eapol_2_of_2=1000 #corrupt_eapol_key_req=1000 +# Delay processing received EAPOL messages by some miliseconds. +# If max > min, then a random value between min and max (inclusive) +# will be selected. EAPOL messages will not be reordered based on this, +# so if one frame is delayed, and a second one arrives for this station, +# then the second one will be queued behind the delayed frame regardless +# of any other delay configuration. +#delay_eapol_1_of_4_min=10 +#delay_eapol_1_of_4_max=1000 +#delay_eapol_3_of_4_min=10 +#delay_eapol_3_of_4_max=1000 +#delay_eapol_1_of_2_min=10 +#delay_eapol_1_of_2_max=1000 # Example blocks: diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index b41626a..6055370 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -460,6 +460,16 @@ struct beacon_rep_data { struct bitfield *eids; }; +#ifdef CONFIG_TESTING_OPTIONS +struct delayed_msg { + struct dl_list list; + + u8 msg[2000]; + u8 src_addr[ETH_ALEN]; + size_t msg_len; + struct os_reltime txtime; /* can transmit on or after this time */ +}; +#endif /** * struct wpa_supplicant - Internal data for wpa_supplicant interface @@ -1051,6 +1061,10 @@ struct wpa_supplicant { unsigned int reject_btm_req_reason; unsigned int p2p_go_csa_on_inv:1; unsigned int ignore_assoc_disallow:1; + + unsigned int delays_disabled:1; + struct dl_list delayed_eapol_list; /* list head: struct delayed_eapol_msg */ + #endif /* CONFIG_TESTING_OPTIONS */ struct wmm_ac_assoc_data *wmm_ac_assoc_info; -- 1.9.3 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap