]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - src/drivers/driver_test.c
Add driver API functionality for off-channel Action frames
[thirdparty/hostap.git] / src / drivers / driver_test.c
index 5596f20609f7d725ebfbe3552b398e462b813135..77a7c9191d918bd07086b6659682d2ff23123da6 100644 (file)
@@ -104,6 +104,10 @@ struct wpa_driver_test_data {
        int alloc_iface_idx;
 
        int probe_req_report;
+       unsigned int remain_on_channel_freq;
+       unsigned int remain_on_channel_duration;
+
+       int current_freq;
 };
 
 
@@ -112,6 +116,7 @@ static int wpa_driver_test_attach(struct wpa_driver_test_data *drv,
                                  const char *dir, int ap);
 static void wpa_driver_test_close_test_socket(
        struct wpa_driver_test_data *drv);
+static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx);
 
 
 static void test_driver_free_bss(struct test_driver_bss *bss)
@@ -1986,6 +1991,7 @@ static void wpa_driver_test_deinit(void *priv)
        wpa_driver_test_close_test_socket(drv);
        eloop_cancel_timeout(wpa_driver_test_scan_timeout, drv, drv->ctx);
        eloop_cancel_timeout(wpa_driver_test_poll, drv, NULL);
+       eloop_cancel_timeout(test_remain_on_channel_timeout, drv, NULL);
        os_free(drv->test_dir);
        for (i = 0; i < MAX_SCAN_RESULTS; i++)
                os_free(drv->scanres[i]);
@@ -2300,8 +2306,10 @@ static int wpa_driver_test_set_channel(void *priv,
                                       enum hostapd_hw_mode phymode,
                                       int chan, int freq)
 {
+       struct wpa_driver_test_data *drv = priv;
        wpa_printf(MSG_DEBUG, "%s: phymode=%d chan=%d freq=%d",
                   __func__, phymode, chan, freq);
+       drv->current_freq = freq;
        return 0;
 }
 
@@ -2464,6 +2472,56 @@ fail:
 }
 
 
+static int wpa_driver_test_set_freq(void *priv,
+                                   struct hostapd_freq_params *freq)
+{
+       struct wpa_driver_test_data *drv = priv;
+       wpa_printf(MSG_DEBUG, "test: set_freq %u MHz", freq->freq);
+       drv->current_freq = freq->freq;
+       return 0;
+}
+
+
+static int wpa_driver_test_send_action(void *priv, unsigned int freq,
+                                      const u8 *dst, const u8 *src,
+                                      const u8 *data, size_t data_len)
+{
+       struct wpa_driver_test_data *drv = priv;
+       int ret = -1;
+       u8 *buf;
+       struct ieee80211_hdr *hdr;
+
+       wpa_printf(MSG_DEBUG, "test: Send Action frame");
+
+       if ((drv->remain_on_channel_freq &&
+            freq != drv->remain_on_channel_freq) ||
+           (drv->remain_on_channel_freq == 0 &&
+            freq != (unsigned int) drv->current_freq)) {
+               wpa_printf(MSG_DEBUG, "test: Reject Action frame TX on "
+                          "unexpected channel: freq=%u MHz (current_freq=%u "
+                          "MHz, remain-on-channel freq=%u MHz)",
+                          freq, drv->current_freq,
+                          drv->remain_on_channel_freq);
+               return -1;
+       }
+
+       buf = os_zalloc(24 + data_len);
+       if (buf == NULL)
+               return ret;
+       os_memcpy(buf + 24, data, data_len);
+       hdr = (struct ieee80211_hdr *) buf;
+       hdr->frame_control =
+               IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION);
+       os_memcpy(hdr->addr1, dst, ETH_ALEN);
+       os_memcpy(hdr->addr2, src, ETH_ALEN);
+       os_memcpy(hdr->addr3, "\xff\xff\xff\xff\xff\xff", ETH_ALEN);
+
+       ret = wpa_driver_test_send_mlme(priv, buf, 24 + data_len);
+       os_free(buf);
+       return ret;
+}
+
+
 static int wpa_driver_test_alloc_interface_addr(void *priv, u8 *addr)
 {
        struct wpa_driver_test_data *drv = priv;
@@ -2482,6 +2540,64 @@ static void wpa_driver_test_release_interface_addr(void *priv, const u8 *addr)
 }
 
 
+static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_driver_test_data *drv = eloop_ctx;
+       union wpa_event_data data;
+
+       wpa_printf(MSG_DEBUG, "test: Remain-on-channel timeout");
+
+       os_memset(&data, 0, sizeof(data));
+       data.remain_on_channel.freq = drv->remain_on_channel_freq;
+       data.remain_on_channel.duration = drv->remain_on_channel_duration;
+       wpa_supplicant_event(drv->ctx, EVENT_CANCEL_REMAIN_ON_CHANNEL, &data);
+
+       drv->remain_on_channel_freq = 0;
+}
+
+
+static int wpa_driver_test_remain_on_channel(void *priv, unsigned int freq,
+                                            unsigned int duration)
+{
+       struct wpa_driver_test_data *drv = priv;
+       union wpa_event_data data;
+
+       wpa_printf(MSG_DEBUG, "%s(freq=%u, duration=%u)",
+                  __func__, freq, duration);
+       if (drv->remain_on_channel_freq &&
+           drv->remain_on_channel_freq != freq) {
+               wpa_printf(MSG_DEBUG, "test: Refuse concurrent "
+                          "remain_on_channel request");
+               return -1;
+       }
+
+       drv->remain_on_channel_freq = freq;
+       drv->remain_on_channel_duration = duration;
+       eloop_cancel_timeout(test_remain_on_channel_timeout, drv, NULL);
+       eloop_register_timeout(duration / 1000, (duration % 1000) * 1000,
+                              test_remain_on_channel_timeout, drv, NULL);
+
+       os_memset(&data, 0, sizeof(data));
+       data.remain_on_channel.freq = freq;
+       data.remain_on_channel.duration = duration;
+       wpa_supplicant_event(drv->ctx, EVENT_REMAIN_ON_CHANNEL, &data);
+
+       return 0;
+}
+
+
+static int wpa_driver_test_cancel_remain_on_channel(void *priv)
+{
+       struct wpa_driver_test_data *drv = priv;
+       wpa_printf(MSG_DEBUG, "%s", __func__);
+       if (!drv->remain_on_channel_freq)
+               return -1;
+       drv->remain_on_channel_freq = 0;
+       eloop_cancel_timeout(test_remain_on_channel_timeout, drv, NULL);
+       return 0;
+}
+
+
 static int wpa_driver_test_probe_req_report(void *priv, int report)
 {
        struct wpa_driver_test_data *drv = priv;
@@ -2534,7 +2650,11 @@ const struct wpa_driver_ops wpa_driver_test_ops = {
        .init2 = wpa_driver_test_init2,
        .get_interfaces = wpa_driver_test_get_interfaces,
        .scan2 = wpa_driver_test_scan,
+       .set_freq = wpa_driver_test_set_freq,
+       .send_action = wpa_driver_test_send_action,
        .alloc_interface_addr = wpa_driver_test_alloc_interface_addr,
        .release_interface_addr = wpa_driver_test_release_interface_addr,
+       .remain_on_channel = wpa_driver_test_remain_on_channel,
+       .cancel_remain_on_channel = wpa_driver_test_cancel_remain_on_channel,
        .probe_req_report = wpa_driver_test_probe_req_report,
 };