From 1c5aa2579dd8978b4e4c652d8e5a6fcbe098ccbb Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 1 Feb 2021 16:57:14 +0200 Subject: [PATCH] Add EAPOL_TX command to extend ext_eapol_frame_io possibilities This makes it convenient for an external test script to use ext_eapol_frame_io=1 to delay and/or modify transmission of EAPOL-Key msg 1/4 without having to use separate frame injection mechanisms. Signed-off-by: Jouni Malinen --- hostapd/ctrl_iface.c | 49 +++++++++++++++++++++++++++++++++++++ src/ap/wpa_auth.h | 3 +++ src/ap/wpa_auth_glue.c | 6 ++--- wpa_supplicant/ctrl_iface.c | 43 ++++++++++++++++++++++++++++++++ wpa_supplicant/wpas_glue.c | 4 +-- wpa_supplicant/wpas_glue.h | 2 ++ 6 files changed, 102 insertions(+), 5 deletions(-) diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 911098066..4a2d60627 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -1946,6 +1946,52 @@ static int hostapd_ctrl_iface_eapol_rx(struct hostapd_data *hapd, char *cmd) } +static int hostapd_ctrl_iface_eapol_tx(struct hostapd_data *hapd, char *cmd) +{ + char *pos, *pos2; + u8 dst[ETH_ALEN], *buf; + int used, ret; + size_t len; + unsigned int prev; + int encrypt = 0; + + wpa_printf(MSG_DEBUG, "External EAPOL TX: %s", cmd); + + pos = cmd; + used = hwaddr_aton2(pos, dst); + if (used < 0) + return -1; + pos += used; + while (*pos == ' ') + pos++; + + pos2 = os_strchr(pos, ' '); + if (pos2) { + len = pos2 - pos; + encrypt = os_strstr(pos2, "encrypt=1") != NULL; + } else { + len = os_strlen(pos); + } + if (len & 1) + return -1; + len /= 2; + + buf = os_malloc(len); + if (!buf || hexstr2bin(pos, buf, len) < 0) { + os_free(buf); + return -1; + } + + prev = hapd->ext_eapol_frame_io; + hapd->ext_eapol_frame_io = 0; + ret = hostapd_wpa_auth_send_eapol(hapd, dst, buf, len, encrypt); + hapd->ext_eapol_frame_io = prev; + os_free(buf); + + return ret; +} + + static u16 ipv4_hdr_checksum(const void *buf, size_t len) { size_t i; @@ -3651,6 +3697,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, } else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) { if (hostapd_ctrl_iface_eapol_rx(hapd, buf + 9) < 0) reply_len = -1; + } else if (os_strncmp(buf, "EAPOL_TX ", 9) == 0) { + if (hostapd_ctrl_iface_eapol_tx(hapd, buf + 9) < 0) + reply_len = -1; } else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) { if (hostapd_ctrl_iface_data_test_config(hapd, buf + 17) < 0) reply_len = -1; diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index ec3e0b5d7..fe47723b9 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -556,6 +556,9 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm, int wpa_auth_rekey_ptk(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm); int wpa_auth_rekey_gtk(struct wpa_authenticator *wpa_auth); +int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr, + const u8 *data, size_t data_len, + int encrypt); void wpa_auth_set_ptk_rekey_timer(struct wpa_state_machine *sm); void wpa_auth_set_ft_rsnxe_used(struct wpa_authenticator *wpa_auth, int val); diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index c3b2e81e2..7ca292530 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -505,9 +505,9 @@ static int hostapd_wpa_auth_get_seqnum(void *ctx, const u8 *addr, int idx, } -static int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr, - const u8 *data, size_t data_len, - int encrypt) +int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr, + const u8 *data, size_t data_len, + int encrypt) { struct hostapd_data *hapd = ctx; struct sta_info *sta; diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index bf83e4168..ba91cfb11 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -39,6 +39,7 @@ #include "driver_i.h" #include "wps_supplicant.h" #include "ibss_rsn.h" +#include "wpas_glue.h" #include "ap.h" #include "p2p_supplicant.h" #include "p2p/p2p.h" @@ -9519,6 +9520,45 @@ static int wpas_ctrl_iface_eapol_rx(struct wpa_supplicant *wpa_s, char *cmd) } +static int wpas_ctrl_iface_eapol_tx(struct wpa_supplicant *wpa_s, char *cmd) +{ + char *pos; + u8 dst[ETH_ALEN], *buf; + int used, ret; + size_t len; + unsigned int prev; + + wpa_printf(MSG_DEBUG, "External EAPOL TX: %s", cmd); + + pos = cmd; + used = hwaddr_aton2(pos, dst); + if (used < 0) + return -1; + pos += used; + while (*pos == ' ') + pos++; + + len = os_strlen(pos); + if (len & 1) + return -1; + len /= 2; + + buf = os_malloc(len); + if (!buf || hexstr2bin(pos, buf, len) < 0) { + os_free(buf); + return -1; + } + + prev = wpa_s->ext_eapol_frame_io; + wpa_s->ext_eapol_frame_io = 0; + ret = wpa_ether_send(wpa_s, dst, ETH_P_EAPOL, buf, len); + wpa_s->ext_eapol_frame_io = prev; + os_free(buf); + + return ret; +} + + static u16 ipv4_hdr_checksum(const void *buf, size_t len) { size_t i; @@ -11514,6 +11554,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) { if (wpas_ctrl_iface_eapol_rx(wpa_s, buf + 9) < 0) reply_len = -1; + } else if (os_strncmp(buf, "EAPOL_TX ", 9) == 0) { + if (wpas_ctrl_iface_eapol_tx(wpa_s, buf + 9) < 0) + reply_len = -1; } else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) { if (wpas_ctrl_iface_data_test_config(wpa_s, buf + 17) < 0) reply_len = -1; diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c index 240e3d2d9..968186978 100644 --- a/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant/wpas_glue.c @@ -95,8 +95,8 @@ static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type, * @len: Frame payload length * Returns: >=0 on success, <0 on failure */ -static int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest, - u16 proto, const u8 *buf, size_t len) +int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest, + u16 proto, const u8 *buf, size_t len) { #ifdef CONFIG_TESTING_OPTIONS if (wpa_s->ext_eapol_frame_io && proto == ETH_P_EAPOL) { diff --git a/wpa_supplicant/wpas_glue.h b/wpa_supplicant/wpas_glue.h index 5585e5615..338af4e65 100644 --- a/wpa_supplicant/wpas_glue.h +++ b/wpa_supplicant/wpas_glue.h @@ -15,6 +15,8 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s); int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s); void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); +int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest, + u16 proto, const u8 *buf, size_t len); const char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field, const char *default_txt,