[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