diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 2935ce739..fdf8ac366 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -40,6 +40,7 @@ #include "blacklist.h" #include "autoscan.h" #include "wnm_sta.h" +#include "offchannel.h" static int wpa_supplicant_global_iface_list(struct wpa_global *global, char *buf, int len); @@ -452,6 +453,10 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, ret = set_disallow_aps(wpa_s, value); } else if (os_strcasecmp(cmd, "no_keep_alive") == 0) { wpa_s->no_keep_alive = !!atoi(value); +#ifdef CONFIG_TESTING_OPTIONS + } else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) { + wpa_s->ext_mgmt_frame_handling = !!atoi(value); +#endif /* CONFIG_TESTING_OPTIONS */ } else { value[-1] = '='; ret = wpa_config_process_global(wpa_s->conf, cmd, -1); @@ -5591,6 +5596,8 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) #ifdef CONFIG_INTERWORKING hs20_cancel_fetch_osu(wpa_s); #endif /* CONFIG_INTERWORKING */ + + wpa_s->ext_mgmt_frame_handling = 0; } @@ -5879,6 +5886,103 @@ static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params, } +#ifdef CONFIG_TESTING_OPTIONS + +static void wpas_ctrl_iface_mgmt_tx_cb(struct wpa_supplicant *wpa_s, + unsigned int freq, const u8 *dst, + const u8 *src, const u8 *bssid, + const u8 *data, size_t data_len, + enum offchannel_send_action_result + result) +{ + wpa_msg(wpa_s, MSG_INFO, "MGMT-TX-STATUS freq=%u dst=" MACSTR + " src=" MACSTR " bssid=" MACSTR " result=%s", + freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid), + result == OFFCHANNEL_SEND_ACTION_SUCCESS ? + "SUCCESS" : (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? + "NO_ACK" : "FAILED")); +} + + +static int wpas_ctrl_iface_mgmt_tx(struct wpa_supplicant *wpa_s, char *cmd) +{ + char *pos, *param; + size_t len; + u8 *buf, da[ETH_ALEN], bssid[ETH_ALEN]; + int res, used; + int freq = 0, no_cck = 0, wait_time = 0; + + /* [freq=] [wait_time=] [no_cck=1] + * */ + + wpa_printf(MSG_DEBUG, "External MGMT TX: %s", cmd); + + pos = cmd; + used = hwaddr_aton2(pos, da); + if (used < 0) + return -1; + pos += used; + while (*pos == ' ') + pos++; + used = hwaddr_aton2(pos, bssid); + if (used < 0) + return -1; + pos += used; + + param = os_strstr(pos, " freq="); + if (param) { + param += 6; + freq = atoi(param); + } + + param = os_strstr(pos, " no_cck="); + if (param) { + param += 8; + no_cck = atoi(param); + } + + param = os_strstr(pos, " wait_time="); + if (param) { + param += 11; + wait_time = atoi(param); + } + + param = os_strstr(pos, " action="); + if (param == NULL) + return -1; + param += 8; + + len = os_strlen(param); + if (len & 1) + return -1; + len /= 2; + + buf = os_malloc(len); + if (buf == NULL) + return -1; + + if (hexstr2bin(param, buf, len) < 0) { + os_free(buf); + return -1; + } + + res = offchannel_send_action(wpa_s, freq, da, wpa_s->own_addr, bssid, + buf, len, wait_time, + wpas_ctrl_iface_mgmt_tx_cb, no_cck); + os_free(buf); + return res; +} + + +static void wpas_ctrl_iface_mgmt_tx_done(struct wpa_supplicant *wpa_s) +{ + wpa_printf(MSG_DEBUG, "External MGMT TX - done waiting"); + offchannel_send_action_done(wpa_s); +} + +#endif /* CONFIG_TESTING_OPTIONS */ + + char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, char *buf, size_t *resp_len) { @@ -6421,6 +6525,13 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "RADIO_WORK ", 11) == 0) { reply_len = wpas_ctrl_radio_work(wpa_s, buf + 11, reply, reply_size); +#ifdef CONFIG_TESTING_OPTIONS + } else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) { + if (wpas_ctrl_iface_mgmt_tx(wpa_s, buf + 8) < 0) + reply_len = -1; + } else if (os_strcmp(buf, "MGMT_TX_DONE") == 0) { + wpas_ctrl_iface_mgmt_tx_done(wpa_s); +#endif /* CONFIG_TESTING_OPTIONS */ } else { os_memcpy(reply, "UNKNOWN COMMAND\n", 16); reply_len = 16; diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 059ffcbee..8f28f8095 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -3137,6 +3137,23 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, u16 fc, stype; const struct ieee80211_mgmt *mgmt; +#ifdef CONFIG_TESTING_OPTIONS + if (wpa_s->ext_mgmt_frame_handling) { + struct rx_mgmt *rx = &data->rx_mgmt; + size_t hex_len = 2 * rx->frame_len + 1; + char *hex = os_malloc(hex_len); + if (hex) { + wpa_snprintf_hex(hex, hex_len, + rx->frame, rx->frame_len); + wpa_msg(wpa_s, MSG_INFO, "MGMT-RX freq=%d datarate=%u ssi_signal=%d %s", + rx->freq, rx->datarate, rx->ssi_signal, + hex); + os_free(hex); + } + break; + } +#endif /* CONFIG_TESTING_OPTIONS */ + mgmt = (const struct ieee80211_mgmt *) data->rx_mgmt.frame; fc = le_to_host16(mgmt->frame_control); diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 376a250b3..fd162d725 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -818,6 +818,7 @@ struct wpa_supplicant { u8 last_gas_dialog_token, prev_gas_dialog_token; unsigned int no_keep_alive:1; + unsigned int ext_mgmt_frame_handling:1; #ifdef CONFIG_WNM u8 wnm_dialog_token;