[PATCH] supplicant: Enable delaying reception of some EAPOL messages.
greearb at candelatech.com
greearb at candelatech.com
Wed Jan 25 10:19:36 PST 2017
From: Ben Greear <greearb at candelatech.com>
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 at candelatech.com>
---
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
More information about the Hostap
mailing list