From 9d4ff04af3667522cc78210d28ee373748d40797 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 10 Oct 2014 18:01:15 +0300 Subject: [PATCH] Add external EAPOL transmission option for testing purposes The new ext_eapol_frame_io parameter can be used to configure hostapd and wpa_supplicant to use control interface for receiving and transmitting EAPOL frames. This makes it easier to implement automated test cases for protocol testing. This functionality is included only in CONFIG_TESTING_OPTIONS=y builds. Signed-off-by: Jouni Malinen --- hostapd/ctrl_iface.c | 43 ++++++++++++++++++++++++++ src/ap/hostapd.h | 3 +- src/ap/ieee802_1x.c | 14 +++++++++ src/ap/wpa_auth_glue.c | 30 ++++++++++++++++++ wpa_supplicant/ap.c | 4 +++ wpa_supplicant/ctrl_iface.c | 51 +++++++++++++++++++++++++++++++ wpa_supplicant/wpa_supplicant_i.h | 1 + wpa_supplicant/wpas_glue.c | 15 +++++++++ 8 files changed, 160 insertions(+), 1 deletion(-) diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 591c39575..ec456c811 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -1074,6 +1074,8 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) #ifdef CONFIG_TESTING_OPTIONS } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) { hapd->ext_mgmt_frame_handling = atoi(value); + } else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) { + hapd->ext_eapol_frame_io = atoi(value); #endif /* CONFIG_TESTING_OPTIONS */ } else { struct sta_info *sta; @@ -1249,6 +1251,44 @@ static int hostapd_ctrl_iface_mgmt_tx(struct hostapd_data *hapd, char *cmd) return res; } + +static int hostapd_ctrl_iface_eapol_rx(struct hostapd_data *hapd, char *cmd) +{ + char *pos; + u8 src[ETH_ALEN], *buf; + int used; + size_t len; + + wpa_printf(MSG_DEBUG, "External EAPOL RX: %s", cmd); + + pos = cmd; + used = hwaddr_aton2(pos, src); + 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 == NULL) + return -1; + + if (hexstr2bin(pos, buf, len) < 0) { + os_free(buf); + return -1; + } + + ieee802_1x_receive(hapd, src, buf, len); + os_free(buf); + + return 0; +} + #endif /* CONFIG_TESTING_OPTIONS */ @@ -1551,6 +1591,9 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, } else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) { if (hostapd_ctrl_iface_mgmt_tx(hapd, buf + 8)) reply_len = -1; + } else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) { + if (hostapd_ctrl_iface_eapol_rx(hapd, buf + 9) < 0) + reply_len = -1; #endif /* CONFIG_TESTING_OPTIONS */ } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) { if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12)) diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 3c8727b18..dfc7e2ea9 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -247,7 +247,8 @@ struct hostapd_data { #endif /* CONFIG_SAE */ #ifdef CONFIG_TESTING_OPTIONS - int ext_mgmt_frame_handling; + unsigned int ext_mgmt_frame_handling:1; + unsigned int ext_eapol_frame_io:1; #endif /* CONFIG_TESTING_OPTIONS */ }; diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c index 2d09b67b1..02d8ae584 100644 --- a/src/ap/ieee802_1x.c +++ b/src/ap/ieee802_1x.c @@ -66,6 +66,20 @@ static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta, if (wpa_auth_pairwise_set(sta->wpa_sm)) encrypt = 1; +#ifdef CONFIG_TESTING_OPTIONS + if (hapd->ext_eapol_frame_io) { + size_t hex_len = 2 * len + 1; + char *hex = os_malloc(hex_len); + + if (hex) { + wpa_snprintf_hex(hex, hex_len, buf, len); + wpa_msg(hapd->msg_ctx, MSG_INFO, + "EAPOL-TX " MACSTR " %s", + MAC2STR(sta->addr), hex); + os_free(hex); + } + } else +#endif /* CONFIG_TESTING_OPTIONS */ if (sta->flags & WLAN_STA_PREAUTH) { rsn_preauth_send(hapd, sta, buf, len); } else { diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index 6ee9a4f83..8592b90b2 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -299,6 +299,21 @@ static int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr, struct sta_info *sta; u32 flags = 0; +#ifdef CONFIG_TESTING_OPTIONS + if (hapd->ext_eapol_frame_io) { + size_t hex_len = 2 * data_len + 1; + char *hex = os_malloc(hex_len); + + if (hex == NULL) + return -1; + wpa_snprintf_hex(hex, hex_len, data, data_len); + wpa_msg(hapd->msg_ctx, MSG_INFO, "EAPOL-TX " MACSTR " %s", + MAC2STR(addr), hex); + os_free(hex); + return 0; + } +#endif /* CONFIG_TESTING_OPTIONS */ + sta = ap_get_sta(hapd, addr); if (sta) flags = hostapd_sta_flags_to_drv(sta->flags); @@ -404,6 +419,21 @@ static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto, struct l2_ethhdr *buf; int ret; +#ifdef CONFIG_TESTING_OPTIONS + if (hapd->ext_eapol_frame_io && proto == ETH_P_EAPOL) { + size_t hex_len = 2 * data_len + 1; + char *hex = os_malloc(hex_len); + + if (hex == NULL) + return -1; + wpa_snprintf_hex(hex, hex_len, data, data_len); + wpa_msg(hapd->msg_ctx, MSG_INFO, "EAPOL-TX " MACSTR " %s", + MAC2STR(dst), hex); + os_free(hex); + return 0; + } +#endif /* CONFIG_TESTING_OPTIONS */ + #ifdef CONFIG_IEEE80211R if (proto == ETH_P_RRB && hapd->iface->interfaces && hapd->iface->interfaces->for_each_interface) { diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index 7c9349883..7555c4265 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -629,6 +629,10 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, #endif /* CONFIG_P2P */ hapd_iface->bss[i]->setup_complete_cb = wpas_ap_configured_cb; hapd_iface->bss[i]->setup_complete_cb_ctx = wpa_s; +#ifdef CONFIG_TESTING_OPTIONS + hapd_iface->bss[i]->ext_eapol_frame_io = + wpa_s->ext_eapol_frame_io; +#endif /* CONFIG_TESTING_OPTIONS */ } os_memcpy(hapd_iface->bss[0]->own_addr, wpa_s->own_addr, ETH_ALEN); diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 98d3ce475..aa44c8651 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -15,6 +15,7 @@ #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "common/wpa_ctrl.h" +#include "ap/hostapd.h" #include "eap_peer/eap.h" #include "eapol_supp/eapol_supp_sm.h" #include "rsn_supp/wpa.h" @@ -420,6 +421,14 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, #ifdef CONFIG_TESTING_OPTIONS } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) { wpa_s->ext_mgmt_frame_handling = !!atoi(value); + } else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) { + wpa_s->ext_eapol_frame_io = !!atoi(value); +#ifdef CONFIG_AP + if (wpa_s->ap_iface) { + wpa_s->ap_iface->bss[0]->ext_eapol_frame_io = + wpa_s->ext_eapol_frame_io; + } +#endif /* CONFIG_AP */ #endif /* CONFIG_TESTING_OPTIONS */ #ifndef CONFIG_NO_CONFIG_BLOBS } else if (os_strcmp(cmd, "blob") == 0) { @@ -5794,6 +5803,7 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) #endif /* CONFIG_INTERWORKING */ wpa_s->ext_mgmt_frame_handling = 0; + wpa_s->ext_eapol_frame_io = 0; } @@ -6244,6 +6254,44 @@ static int wpas_ctrl_iface_driver_event(struct wpa_supplicant *wpa_s, char *cmd) return 0; } + +static int wpas_ctrl_iface_eapol_rx(struct wpa_supplicant *wpa_s, char *cmd) +{ + char *pos; + u8 src[ETH_ALEN], *buf; + int used; + size_t len; + + wpa_printf(MSG_DEBUG, "External EAPOL RX: %s", cmd); + + pos = cmd; + used = hwaddr_aton2(pos, src); + 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 == NULL) + return -1; + + if (hexstr2bin(pos, buf, len) < 0) { + os_free(buf); + return -1; + } + + wpa_supplicant_rx_eapol(wpa_s, src, buf, len); + os_free(buf); + + return 0; +} + #endif /* CONFIG_TESTING_OPTIONS */ @@ -7017,6 +7065,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "DRIVER_EVENT ", 13) == 0) { if (wpas_ctrl_iface_driver_event(wpa_s, buf + 13) < 0) reply_len = -1; + } else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) { + if (wpas_ctrl_iface_eapol_rx(wpa_s, buf + 9) < 0) + reply_len = -1; #endif /* CONFIG_TESTING_OPTIONS */ } else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) { if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0) diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 0346d84d4..6974ba269 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -844,6 +844,7 @@ struct wpa_supplicant { unsigned int no_keep_alive:1; unsigned int ext_mgmt_frame_handling:1; + unsigned int ext_eapol_frame_io:1; #ifdef CONFIG_WNM u8 wnm_dialog_token; diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c index 38279b1f0..fcfa9fba5 100644 --- a/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant/wpas_glue.c @@ -96,6 +96,21 @@ static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type, static 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) { + size_t hex_len = 2 * len + 1; + char *hex = os_malloc(hex_len); + + if (hex == NULL) + return -1; + wpa_snprintf_hex(hex, hex_len, buf, len); + wpa_msg(wpa_s, MSG_INFO, "EAPOL-TX " MACSTR " %s", + MAC2STR(dest), hex); + os_free(hex); + return 0; + } +#endif /* CONFIG_TESTING_OPTIONS */ + if (wpa_s->l2) { return l2_packet_send(wpa_s->l2, dest, proto, buf, len); }