wpa_supplicant: Allow external management frame processing for testing
authorJouni Malinen <j@w1.fi>
Sat, 8 Mar 2014 18:21:21 +0000 (20:21 +0200)
committerJouni Malinen <j@w1.fi>
Sat, 8 Mar 2014 18:21:21 +0000 (20:21 +0200)
This enables more convenient protocol testing of AP and P2P
functionality in various error cases and unexpected sequences without
having to implement each test scenario within wpa_supplicant.
ext_mgmt_frame_handle parameter can be set to 1 to move all management
frame processing into an external program through control interface
events (MGMT-RX and MGMT-TX-STATUS) and command (MGMT_TX). This is
similar to the test interface that was added to hostapd previously, but
allows more control on offchannel operations and more direct integration
with the internal P2P module.

Signed-off-by: Jouni Malinen <j@w1.fi>
wpa_supplicant/ctrl_iface.c
wpa_supplicant/events.c
wpa_supplicant/wpa_supplicant_i.h

index 2935ce7..fdf8ac3 100644 (file)
@@ -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;
+
+       /* <DA> <BSSID> [freq=<MHz>] [wait_time=<ms>] [no_cck=1]
+        *    <action=Action frame payload> */
+
+       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;
index 059ffcb..8f28f80 100644 (file)
@@ -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);
index 376a250..fd162d7 100644 (file)
@@ -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;