]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - src/drivers/driver_test.c
Use generic driver event notification for AP mode assoc/disassoc
[thirdparty/hostap.git] / src / drivers / driver_test.c
index d955033694519ea62e676320f1f541e907ccf9c2..818c197183ea3774bc7f9a4173aa0ca1a9f080e7 100644 (file)
@@ -18,7 +18,7 @@
 #include <winsock2.h>
 #endif /* CONFIG_NATIVE_WINDOWS */
 
-#include "includes.h"
+#include "utils/includes.h"
 
 #ifndef CONFIG_NATIVE_WINDOWS
 #include <sys/un.h>
 #define DRIVER_TEST_UNIX
 #endif /* CONFIG_NATIVE_WINDOWS */
 
-#include "common.h"
-#include "driver.h"
-#include "l2_packet/l2_packet.h"
-#include "eloop.h"
-#include "crypto/sha1.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/trace.h"
 #include "common/ieee802_11_defs.h"
+#include "crypto/sha1.h"
+#include "l2_packet/l2_packet.h"
+#include "driver.h"
 
 
 struct test_client_socket {
@@ -60,12 +61,15 @@ struct test_driver_bss {
 };
 
 struct wpa_driver_test_global {
-       int dummy;
+       int bss_add_used;
+       u8 req_addr[ETH_ALEN];
 };
 
 struct wpa_driver_test_data {
        struct wpa_driver_test_global *global;
        void *ctx;
+       WPA_TRACE_REF(ctx);
+       char ifname[IFNAMSIZ + 1];
        u8 own_addr[ETH_ALEN];
        int test_socket;
 #ifdef DRIVER_TEST_UNIX
@@ -96,6 +100,14 @@ struct wpa_driver_test_data {
        struct test_client_socket *cli;
        struct test_driver_bss *bss;
        int udp_port;
+
+       int alloc_iface_idx;
+
+       int probe_req_report;
+       unsigned int remain_on_channel_freq;
+       unsigned int remain_on_channel_duration;
+
+       int current_freq;
 };
 
 
@@ -104,33 +116,15 @@ 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);
-
-#ifdef CONFIG_AP
-void ap_mgmt_rx(void *ctx, u8 *buf, size_t len, u16 stype,
-               struct hostapd_frame_info *fi);
-void ap_mgmt_tx_cb(void *ctx, u8 *buf, size_t len, u16 stype, int ok);
-
-#else /* CONFIG_AP */
-#ifndef HOSTAPD
-static inline void ap_mgmt_rx(void *ctx, u8 *buf, size_t len, u16 stype,
-                             struct hostapd_frame_info *fi)
-{
-}
-
-static inline void ap_mgmt_tx_cb(void *ctx, u8 *buf, size_t len, u16 stype,
-                                int ok)
-{
-}
-#endif /* HOSTAPD */
-#endif /* CONFIG_AP */
+static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx);
 
 
 static void test_driver_free_bss(struct test_driver_bss *bss)
 {
-       free(bss->ie);
-       free(bss->wps_beacon_ie);
-       free(bss->wps_probe_resp_ie);
-       free(bss);
+       os_free(bss->ie);
+       os_free(bss->wps_beacon_ie);
+       os_free(bss->wps_probe_resp_ie);
+       os_free(bss);
 }
 
 
@@ -314,9 +308,12 @@ static int wpa_driver_test_send_mlme(void *priv, const u8 *data,
        int ret = 0;
        struct ieee80211_hdr *hdr;
        u16 fc;
+       char cmd[50];
+       int freq;
 #ifdef HOSTAPD
        char desttxt[30];
 #endif /* HOSTAPD */
+       union wpa_event_data event;
 
        wpa_hexdump(MSG_MSGDUMP, "test_send_mlme", data, data_len);
        if (drv->test_socket < 0 || data_len < 10) {
@@ -335,8 +332,15 @@ static int wpa_driver_test_send_mlme(void *priv, const u8 *data,
        snprintf(desttxt, sizeof(desttxt), MACSTR, MAC2STR(dest));
 #endif /* HOSTAPD */
 
-       io[0].iov_base = "MLME ";
-       io[0].iov_len = 5;
+       if (drv->remain_on_channel_freq)
+               freq = drv->remain_on_channel_freq;
+       else
+               freq = drv->current_freq;
+       wpa_printf(MSG_DEBUG, "test_driver(%s): MLME TX on freq %d MHz",
+                  drv->ifname, freq);
+       os_snprintf(cmd, sizeof(cmd), "MLME freq=%d ", freq);
+       io[0].iov_base = cmd;
+       io[0].iov_len = os_strlen(cmd);
        io[1].iov_base = (void *) data;
        io[1].iov_len = data_len;
 
@@ -456,15 +460,15 @@ static int wpa_driver_test_send_mlme(void *priv, const u8 *data,
 
        hdr = (struct ieee80211_hdr *) data;
        fc = le_to_host16(hdr->frame_control);
-#ifdef HOSTAPD
-       hostapd_mgmt_tx_cb(drv->ctx, (u8 *) data, data_len,
-                          WLAN_FC_GET_STYPE(fc), ret >= 0);
-#else /* HOSTAPD */
-       if (drv->ap) {
-               ap_mgmt_tx_cb(drv->ctx, (u8 *) data, data_len,
-                             WLAN_FC_GET_STYPE(fc), ret >= 0);
-       }
-#endif /* HOSTAPD */
+
+       os_memset(&event, 0, sizeof(event));
+       event.tx_status.type = WLAN_FC_GET_TYPE(fc);
+       event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
+       event.tx_status.dst = hdr->addr1;
+       event.tx_status.data = data;
+       event.tx_status.data_len = data_len;
+       event.tx_status.ack = ret >= 0;
+       wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event);
 
        return ret;
 }
@@ -480,6 +484,7 @@ static void test_driver_scan(struct wpa_driver_test_data *drv,
        u8 sa[ETH_ALEN];
        u8 ie[512];
        size_t ielen;
+       union wpa_event_data event;
 
        /* data: optional [ ' ' | STA-addr | ' ' | IEs(hex) ] */
 
@@ -506,9 +511,11 @@ static void test_driver_scan(struct wpa_driver_test_data *drv,
                           MAC2STR(sa));
                wpa_hexdump(MSG_MSGDUMP, "test_driver: scan IEs", ie, ielen);
 
-#ifdef HOSTAPD
-               hostapd_probe_req_rx(drv->ctx, sa, ie, ielen);
-#endif /* HOSTAPD */
+               os_memset(&event, 0, sizeof(event));
+               event.rx_probe_req.sa = sa;
+               event.rx_probe_req.ie = ie;
+               event.rx_probe_req.ie_len = ielen;
+               wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ, &event);
        }
 
        for (bss = drv->bss; bss; bss = bss->next) {
@@ -563,7 +570,7 @@ static void test_driver_assoc(struct wpa_driver_test_data *drv,
        if (hwaddr_aton(data, cli->addr)) {
                printf("test_socket: Invalid MAC address '%s' in ASSOC\n",
                       data);
-               free(cli);
+               os_free(cli);
                return;
        }
        pos = data + 17;
@@ -575,7 +582,7 @@ static void test_driver_assoc(struct wpa_driver_test_data *drv,
                ssid_len = (pos2 - pos) / 2;
                if (hexstr2bin(pos, ssid, ssid_len) < 0) {
                        wpa_printf(MSG_DEBUG, "%s: Invalid SSID", __func__);
-                       free(cli);
+                       os_free(cli);
                        return;
                }
                wpa_hexdump_ascii(MSG_DEBUG, "test_driver_assoc: SSID",
@@ -597,7 +604,7 @@ static void test_driver_assoc(struct wpa_driver_test_data *drv,
        if (bss == NULL) {
                wpa_printf(MSG_DEBUG, "%s: No matching SSID found from "
                           "configured BSSes", __func__);
-               free(cli);
+               os_free(cli);
                return;
        }
 
@@ -615,10 +622,7 @@ static void test_driver_assoc(struct wpa_driver_test_data *drv,
        sendto(drv->test_socket, cmd, strlen(cmd), 0,
               (struct sockaddr *) from, fromlen);
 
-#ifdef HOSTAPD
-       if (hostapd_notif_assoc(bss->bss_ctx, cli->addr, ie, ielen) < 0)
-               wpa_printf(MSG_DEBUG, "test_driver: failed to add new STA");
-#endif /* HOSTAPD */
+       drv_event_assoc(bss->bss_ctx, cli->addr, ie, ielen);
 }
 
 
@@ -631,9 +635,7 @@ static void test_driver_disassoc(struct wpa_driver_test_data *drv,
        if (!cli)
                return;
 
-#ifdef HOSTAPD
-       hostapd_notif_disassoc(drv->ctx, cli->addr);
-#endif /* HOSTAPD */
+       drv_event_disassoc(drv->ctx, cli->addr);
 }
 
 
@@ -645,6 +647,8 @@ static void test_driver_eapol(struct wpa_driver_test_data *drv,
        struct test_client_socket *cli;
 #endif /* HOSTAPD */
        const u8 *src = NULL;
+       union wpa_event_data event;
+       void *ctx;
 
        if (datalen > 14) {
                /* Skip Ethernet header */
@@ -656,19 +660,30 @@ static void test_driver_eapol(struct wpa_driver_test_data *drv,
                data += 14;
                datalen -= 14;
        }
+
+       os_memset(&event, 0, sizeof(event));
+       event.eapol_rx.data = data;
+       event.eapol_rx.data_len = datalen;
+
 #ifdef HOSTAPD
        cli = test_driver_get_cli(drv, from, fromlen);
        if (cli) {
-               hostapd_eapol_receive(cli->bss->bss_ctx, cli->addr, data,
-                                     datalen);
+               event.eapol_rx.src = cli->addr;
+               ctx = cli->bss->bss_ctx;
        } else {
                wpa_printf(MSG_DEBUG, "test_socket: EAPOL from unknown "
                           "client");
+               return;
        }
 #else /* HOSTAPD */
-       if (src)
-               wpa_supplicant_rx_eapol(drv->ctx, src, data, datalen);
+       if (src) {
+               event.eapol_rx.src = src;
+               ctx = drv->ctx;
+       } else
+               return;
 #endif /* HOSTAPD */
+
+       wpa_supplicant_event(ctx, EVENT_EAPOL_RX, &event);
 }
 
 
@@ -705,6 +720,36 @@ static void test_driver_mlme(struct wpa_driver_test_data *drv,
 {
        struct ieee80211_hdr *hdr;
        u16 fc;
+       union wpa_event_data event;
+       int freq = 0, own_freq;
+
+       if (datalen > 6 && os_memcmp(data, "freq=", 5) == 0) {
+               size_t pos;
+               for (pos = 5; pos < datalen; pos++) {
+                       if (data[pos] == ' ')
+                               break;
+               }
+               if (pos < datalen) {
+                       freq = atoi((const char *) &data[5]);
+                       wpa_printf(MSG_DEBUG, "test_driver(%s): MLME RX on "
+                                  "freq %d MHz", drv->ifname, freq);
+                       pos++;
+                       data += pos;
+                       datalen -= pos;
+               }
+       }
+
+       if (drv->remain_on_channel_freq)
+               own_freq = drv->remain_on_channel_freq;
+       else
+               own_freq = drv->current_freq;
+
+       if (freq && own_freq && freq != own_freq) {
+               wpa_printf(MSG_DEBUG, "test_driver(%s): Ignore MLME RX on "
+                          "another frequency %d MHz (own %d MHz)",
+                          drv->ifname, freq, own_freq);
+               return;
+       }
 
        hdr = (struct ieee80211_hdr *) data;
 
@@ -730,11 +775,11 @@ static void test_driver_mlme(struct wpa_driver_test_data *drv,
                           __func__);
                return;
        }
-#ifdef HOSTAPD
-       hostapd_mgmt_rx(drv->ctx, data, datalen, WLAN_FC_GET_STYPE(fc), NULL);
-#else /* HOSTAPD */
-       ap_mgmt_rx(drv->ctx, data, datalen, WLAN_FC_GET_STYPE(fc), NULL);
-#endif /* HOSTAPD */
+
+       os_memset(&event, 0, sizeof(event));
+       event.rx_mgmt.frame = data;
+       event.rx_mgmt.frame_len = datalen;
+       wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
 }
 
 
@@ -783,7 +828,7 @@ test_driver_get_bss(struct wpa_driver_test_data *drv, const char *ifname)
        struct test_driver_bss *bss;
 
        for (bss = drv->bss; bss; bss = bss->next) {
-               if (strcmp(bss->ifname, ifname) == 0)
+               if (os_strcmp(bss->ifname, ifname) == 0)
                        return bss;
        }
        return NULL;
@@ -800,7 +845,7 @@ static int test_driver_set_generic_elem(const char *ifname, void *priv,
        if (bss == NULL)
                return -1;
 
-       free(bss->ie);
+       os_free(bss->ie);
 
        if (elem == NULL) {
                bss->ie = NULL;
@@ -808,7 +853,7 @@ static int test_driver_set_generic_elem(const char *ifname, void *priv,
                return 0;
        }
 
-       bss->ie = malloc(elem_len);
+       bss->ie = os_malloc(elem_len);
        if (bss->ie == NULL) {
                bss->ielen = 0;
                return -1;
@@ -820,64 +865,64 @@ static int test_driver_set_generic_elem(const char *ifname, void *priv,
 }
 
 
-static int test_driver_set_wps_beacon_ie(const char *ifname, void *priv,
-                                        const u8 *ie, size_t len)
+static int test_driver_set_ap_wps_ie(const char *ifname, void *priv,
+                                    const struct wpabuf *beacon,
+                                    const struct wpabuf *proberesp)
 {
        struct wpa_driver_test_data *drv = priv;
        struct test_driver_bss *bss;
 
-       wpa_hexdump(MSG_DEBUG, "test_driver: Beacon WPS IE", ie, len);
        bss = test_driver_get_bss(drv, ifname);
        if (bss == NULL)
                return -1;
 
-       free(bss->wps_beacon_ie);
+       if (beacon == NULL)
+               wpa_printf(MSG_DEBUG, "test_driver: Clear Beacon WPS IE");
+       else
+               wpa_hexdump_buf(MSG_DEBUG, "test_driver: Beacon WPS IE",
+                               beacon);
+
+       os_free(bss->wps_beacon_ie);
 
-       if (ie == NULL) {
+       if (beacon == NULL) {
                bss->wps_beacon_ie = NULL;
                bss->wps_beacon_ie_len = 0;
-               return 0;
-       }
+       } else {
+               bss->wps_beacon_ie = os_malloc(wpabuf_len(beacon));
+               if (bss->wps_beacon_ie == NULL) {
+                       bss->wps_beacon_ie_len = 0;
+                       return -1;
+               }
 
-       bss->wps_beacon_ie = malloc(len);
-       if (bss->wps_beacon_ie == NULL) {
-               bss->wps_beacon_ie_len = 0;
-               return -1;
+               os_memcpy(bss->wps_beacon_ie, wpabuf_head(beacon),
+                         wpabuf_len(beacon));
+               bss->wps_beacon_ie_len = wpabuf_len(beacon);
        }
 
-       memcpy(bss->wps_beacon_ie, ie, len);
-       bss->wps_beacon_ie_len = len;
-       return 0;
-}
-
-
-static int test_driver_set_wps_probe_resp_ie(const char *ifname, void *priv,
-                                            const u8 *ie, size_t len)
-{
-       struct wpa_driver_test_data *drv = priv;
-       struct test_driver_bss *bss;
-
-       wpa_hexdump(MSG_DEBUG, "test_driver: ProbeResp WPS IE", ie, len);
-       bss = test_driver_get_bss(drv, ifname);
-       if (bss == NULL)
-               return -1;
+       if (proberesp == NULL)
+               wpa_printf(MSG_DEBUG, "test_driver: Clear Probe Response WPS "
+                          "IE");
+       else
+               wpa_hexdump_buf(MSG_DEBUG, "test_driver: Probe Response WPS "
+                               "IE", proberesp);
 
-       free(bss->wps_probe_resp_ie);
+       os_free(bss->wps_probe_resp_ie);
 
-       if (ie == NULL) {
+       if (proberesp == NULL) {
                bss->wps_probe_resp_ie = NULL;
                bss->wps_probe_resp_ie_len = 0;
-               return 0;
-       }
+       } else {
+               bss->wps_probe_resp_ie = os_malloc(wpabuf_len(proberesp));
+               if (bss->wps_probe_resp_ie == NULL) {
+                       bss->wps_probe_resp_ie_len = 0;
+                       return -1;
+               }
 
-       bss->wps_probe_resp_ie = malloc(len);
-       if (bss->wps_probe_resp_ie == NULL) {
-               bss->wps_probe_resp_ie_len = 0;
-               return -1;
+               os_memcpy(bss->wps_probe_resp_ie, wpabuf_head(proberesp),
+                         wpabuf_len(proberesp));
+               bss->wps_probe_resp_ie_len = wpabuf_len(proberesp);
        }
 
-       memcpy(bss->wps_probe_resp_ie, ie, len);
-       bss->wps_probe_resp_ie_len = len;
        return 0;
 }
 
@@ -949,6 +994,8 @@ static int test_driver_bss_add(void *priv, const char *ifname, const u8 *bssid,
 
        bss->next = drv->bss;
        drv->bss = bss;
+       drv->global->bss_add_used = 1;
+       os_memcpy(drv->global->req_addr, bssid, ETH_ALEN);
 
        return 0;
 }
@@ -979,7 +1026,7 @@ static int test_driver_bss_remove(void *priv, const char *ifname)
                                prev_c->next = cli->next;
                        else
                                drv->cli = cli->next;
-                       free(cli);
+                       os_free(cli);
                        break;
                }
 
@@ -1029,20 +1076,20 @@ static int test_driver_set_ssid(const char *ifname, void *priv, const u8 *buf,
        wpa_printf(MSG_DEBUG, "%s(ifname=%s)", __func__, ifname);
        wpa_hexdump_ascii(MSG_DEBUG, "test_driver_set_ssid: SSID", buf, len);
 
-       for (bss = drv->bss; bss; bss = bss->next) {
-               if (strcmp(bss->ifname, ifname) != 0)
-                       continue;
-
-               if (len < 0 || (size_t) len > sizeof(bss->ssid))
-                       return -1;
+       bss = test_driver_get_bss(drv, ifname);
+       if (bss == NULL) {
+               wpa_printf(MSG_DEBUG, "%s(ifname=%s): failed to find BSS data",
+                          __func__, ifname);
+               return -1;
+       }
 
-               memcpy(bss->ssid, buf, len);
-               bss->ssid_len = len;
+       if (len < 0 || (size_t) len > sizeof(bss->ssid))
+               return -1;
 
-               return 0;
-       }
+       os_memcpy(bss->ssid, buf, len);
+       bss->ssid_len = len;
 
-       return -1;
+       return 0;
 }
 
 
@@ -1054,16 +1101,13 @@ static int test_driver_set_privacy(const char *ifname, void *priv, int enabled)
        wpa_printf(MSG_DEBUG, "%s(ifname=%s enabled=%d)",
                   __func__, ifname, enabled);
 
-       for (bss = drv->bss; bss; bss = bss->next) {
-               if (strcmp(bss->ifname, ifname) != 0)
-                       continue;
-
-               bss->privacy = enabled;
+       bss = test_driver_get_bss(drv, ifname);
+       if (bss == NULL)
+               return -1;
 
-               return 0;
-       }
+       bss->privacy = enabled;
 
-       return -1;
+       return 0;
 }
 
 
@@ -1102,10 +1146,7 @@ static int test_driver_sta_add(const char *ifname, void *priv,
                return -1;
        }
 
-       for (bss = drv->bss; bss; bss = bss->next) {
-               if (strcmp(ifname, bss->ifname) == 0)
-                       break;
-       }
+       bss = test_driver_get_bss(drv, ifname);
        if (bss == NULL) {
                wpa_printf(MSG_DEBUG, "%s: No matching interface found from "
                           "configured BSSes", __func__);
@@ -1118,6 +1159,32 @@ static int test_driver_sta_add(const char *ifname, void *priv,
 }
 
 
+static struct wpa_driver_test_data * test_alloc_data(void *ctx,
+                                                    const char *ifname)
+{
+       struct wpa_driver_test_data *drv;
+
+       drv = os_zalloc(sizeof(struct wpa_driver_test_data));
+       if (drv == NULL) {
+               wpa_printf(MSG_ERROR, "Could not allocate memory for test "
+                          "driver data");
+               return NULL;
+       }
+
+       drv->ctx = ctx;
+       wpa_trace_add_ref(drv, ctx, ctx);
+       os_strlcpy(drv->ifname, ifname, IFNAMSIZ);
+
+       /* Generate a MAC address to help testing with multiple STAs */
+       drv->own_addr[0] = 0x02; /* locally administered */
+       sha1_prf((const u8 *) ifname, os_strlen(ifname),
+                "test mac addr generation",
+                NULL, 0, drv->own_addr + 1, ETH_ALEN - 1);
+
+       return drv;
+}
+
+
 static void * test_driver_init(struct hostapd_data *hapd,
                               struct wpa_init_params *params)
 {
@@ -1127,30 +1194,22 @@ static void * test_driver_init(struct hostapd_data *hapd,
        struct sockaddr *addr;
        socklen_t alen;
 
-       drv = os_zalloc(sizeof(struct wpa_driver_test_data));
-       if (drv == NULL) {
-               printf("Could not allocate memory for test driver data\n");
+       drv = test_alloc_data(hapd, params->ifname);
+       if (drv == NULL)
                return NULL;
-       }
        drv->ap = 1;
        drv->bss = os_zalloc(sizeof(*drv->bss));
        if (drv->bss == NULL) {
-               printf("Could not allocate memory for test driver BSS data\n");
-               free(drv);
+               wpa_printf(MSG_ERROR, "Could not allocate memory for test "
+                          "driver BSS data");
+               os_free(drv);
                return NULL;
        }
 
-       drv->ctx = hapd;
-
-       /* Generate a MAC address to help testing with multiple APs */
-       params->own_addr[0] = 0x02; /* locally administered */
-       sha1_prf((const u8 *) params->ifname, strlen(params->ifname),
-                "hostapd test bssid generation",
-                params->ssid, params->ssid_len,
-                params->own_addr + 1, ETH_ALEN - 1);
-
+       drv->bss->bss_ctx = hapd;
        os_strlcpy(drv->bss->ifname, params->ifname, IFNAMSIZ);
-       memcpy(drv->bss->bssid, params->own_addr, ETH_ALEN);
+       os_memcpy(drv->bss->bssid, drv->own_addr, ETH_ALEN);
+       os_memcpy(params->own_addr, drv->own_addr, ETH_ALEN);
 
        if (params->test_socket) {
                if (os_strlen(params->test_socket) >=
@@ -1161,8 +1220,8 @@ static void * test_driver_init(struct hostapd_data *hapd,
                }
                if (strncmp(params->test_socket, "DIR:", 4) == 0) {
                        size_t len = strlen(params->test_socket) + 30;
-                       drv->test_dir = strdup(params->test_socket + 4);
-                       drv->own_socket_path = malloc(len);
+                       drv->test_dir = os_strdup(params->test_socket + 4);
+                       drv->own_socket_path = os_malloc(len);
                        if (drv->own_socket_path) {
                                snprintf(drv->own_socket_path, len,
                                         "%s/AP-" MACSTR,
@@ -1172,7 +1231,7 @@ static void * test_driver_init(struct hostapd_data *hapd,
                } else if (strncmp(params->test_socket, "UDP:", 4) == 0) {
                        drv->udp_port = atoi(params->test_socket + 4);
                } else {
-                       drv->own_socket_path = strdup(params->test_socket);
+                       drv->own_socket_path = os_strdup(params->test_socket);
                }
                if (drv->own_socket_path == NULL && drv->udp_port == 0) {
                        wpa_driver_test_deinit(drv);
@@ -1393,8 +1452,9 @@ static struct wpa_scan_results * wpa_driver_test_get_scan_results2(void *priv)
 }
 
 
-static int wpa_driver_test_set_key(const char *ifname, void *priv, wpa_alg alg,
-                                  const u8 *addr, int key_idx, int set_tx,
+static int wpa_driver_test_set_key(const char *ifname, void *priv,
+                                  enum wpa_alg alg, const u8 *addr,
+                                  int key_idx, int set_tx,
                                   const u8 *seq, size_t seq_len,
                                   const u8 *key, size_t key_len)
 {
@@ -1491,6 +1551,7 @@ static int wpa_driver_test_associate(
                bss = drv->bss = os_zalloc(sizeof(*drv->bss));
                if (bss == NULL)
                        return -1;
+               os_strlcpy(bss->ifname, drv->ifname, IFNAMSIZ);
                os_memcpy(bss->bssid, drv->own_addr, ETH_ALEN);
                os_memcpy(bss->ssid, params->ssid, params->ssid_len);
                bss->ssid_len = params->ssid_len;
@@ -1750,6 +1811,7 @@ static void wpa_driver_test_eapol(struct wpa_driver_test_data *drv,
                                  const u8 *data, size_t data_len)
 {
        const u8 *src = drv->bssid;
+       union wpa_event_data event;
 
        if (data_len > 14) {
                /* Skip Ethernet header */
@@ -1757,9 +1819,12 @@ static void wpa_driver_test_eapol(struct wpa_driver_test_data *drv,
                data += 14;
                data_len -= 14;
        }
-#ifndef HOSTAPD
-       wpa_supplicant_rx_eapol(drv->ctx, src, data, data_len);
-#endif /* HOSTAPD */
+
+       os_memset(&event, 0, sizeof(event));
+       event.eapol_rx.src = src;
+       event.eapol_rx.data = data;
+       event.eapol_rx.data_len = data_len;
+       wpa_supplicant_event(drv->ctx, EVENT_EAPOL_RX, &event);
 }
 
 
@@ -1768,11 +1833,60 @@ static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv,
                                 socklen_t fromlen,
                                 const u8 *data, size_t data_len)
 {
-#ifdef CONFIG_CLIENT_MLME
-       struct ieee80211_rx_status rx_status;
-       os_memset(&rx_status, 0, sizeof(rx_status));
-       wpa_supplicant_sta_rx(drv->ctx, data, data_len, &rx_status);
-#endif /* CONFIG_CLIENT_MLME */
+       int freq = 0, own_freq;
+       union wpa_event_data event;
+
+       if (data_len > 6 && os_memcmp(data, "freq=", 5) == 0) {
+               size_t pos;
+               for (pos = 5; pos < data_len; pos++) {
+                       if (data[pos] == ' ')
+                               break;
+               }
+               if (pos < data_len) {
+                       freq = atoi((const char *) &data[5]);
+                       wpa_printf(MSG_DEBUG, "test_driver(%s): MLME RX on "
+                                  "freq %d MHz", drv->ifname, freq);
+                       pos++;
+                       data += pos;
+                       data_len -= pos;
+               }
+       }
+
+       if (drv->remain_on_channel_freq)
+               own_freq = drv->remain_on_channel_freq;
+       else
+               own_freq = drv->current_freq;
+
+       if (freq && own_freq && freq != own_freq) {
+               wpa_printf(MSG_DEBUG, "test_driver(%s): Ignore MLME RX on "
+                          "another frequency %d MHz (own %d MHz)",
+                          drv->ifname, freq, own_freq);
+               return;
+       }
+
+       os_memset(&event, 0, sizeof(event));
+       event.mlme_rx.buf = data;
+       event.mlme_rx.len = data_len;
+       event.mlme_rx.freq = freq;
+       wpa_supplicant_event(drv->ctx, EVENT_MLME_RX, &event);
+
+       if (drv->probe_req_report && data_len >= 24) {
+               const struct ieee80211_mgmt *mgmt;
+               u16 fc;
+
+               mgmt = (const struct ieee80211_mgmt *) data;
+               fc = le_to_host16(mgmt->frame_control);
+               if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+                   WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ) {
+                       os_memset(&event, 0, sizeof(event));
+                       event.rx_probe_req.sa = mgmt->sa;
+                       event.rx_probe_req.ie = mgmt->u.probe_req.variable;
+                       event.rx_probe_req.ie_len =
+                               data_len - (mgmt->u.probe_req.variable - data);
+                       wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ,
+                                            &event);
+               }
+       }
 }
 
 
@@ -1887,12 +2001,12 @@ static void * wpa_driver_test_init2(void *ctx, const char *ifname,
                                    void *global_priv)
 {
        struct wpa_driver_test_data *drv;
+       struct wpa_driver_test_global *global = global_priv;
 
-       drv = os_zalloc(sizeof(*drv));
+       drv = test_alloc_data(ctx, ifname);
        if (drv == NULL)
                return NULL;
        drv->global = global_priv;
-       drv->ctx = ctx;
        drv->test_socket = -1;
 
        /* Set dummy BSSID and SSID for testing. */
@@ -1905,11 +2019,11 @@ static void * wpa_driver_test_init2(void *ctx, const char *ifname,
        os_memcpy(drv->ssid, "test", 5);
        drv->ssid_len = 4;
 
-       /* Generate a MAC address to help testing with multiple STAs */
-       drv->own_addr[0] = 0x02; /* locally administered */
-       sha1_prf((const u8 *) ifname, os_strlen(ifname),
-                "wpa_supplicant test mac addr generation",
-                NULL, 0, drv->own_addr + 1, ETH_ALEN - 1);
+       if (global->bss_add_used) {
+               os_memcpy(drv->own_addr, global->req_addr, ETH_ALEN);
+               global->bss_add_used = 0;
+       }
+
        eloop_register_timeout(1, 0, wpa_driver_test_poll, drv, NULL);
 
        return drv;
@@ -1958,10 +2072,12 @@ 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]);
        os_free(drv->probe_req_ie);
+       wpa_trace_remove_ref(drv, ctx, drv->ctx);
        os_free(drv);
 }
 
@@ -2267,11 +2383,14 @@ static int wpa_driver_test_mlme_setprotection(void *priv, const u8 *addr,
 }
 
 
-static int wpa_driver_test_set_channel(void *priv, hostapd_hw_mode phymode,
+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;
 }
 
@@ -2350,6 +2469,7 @@ static struct hostapd_hw_modes *
 wpa_driver_test_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
 {
        struct hostapd_hw_modes *modes;
+       size_t i;
 
        *num_modes = 3;
        *flags = 0;
@@ -2357,46 +2477,72 @@ wpa_driver_test_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
        if (modes == NULL)
                return NULL;
        modes[0].mode = HOSTAPD_MODE_IEEE80211G;
-       modes[0].num_channels = 1;
-       modes[0].num_rates = 1;
-       modes[0].channels = os_zalloc(sizeof(struct hostapd_channel_data));
-       modes[0].rates = os_zalloc(sizeof(int));
+       modes[0].num_channels = 11;
+       modes[0].num_rates = 12;
+       modes[0].channels =
+               os_zalloc(11 * sizeof(struct hostapd_channel_data));
+       modes[0].rates = os_zalloc(modes[0].num_rates * sizeof(int));
        if (modes[0].channels == NULL || modes[0].rates == NULL)
                goto fail;
-       modes[0].channels[0].chan = 1;
-       modes[0].channels[0].freq = 2412;
-       modes[0].channels[0].flag = 0;
+       for (i = 0; i < 11; i++) {
+               modes[0].channels[i].chan = i + 1;
+               modes[0].channels[i].freq = 2412 + 5 * i;
+               modes[0].channels[i].flag = 0;
+       }
        modes[0].rates[0] = 10;
+       modes[0].rates[1] = 20;
+       modes[0].rates[2] = 55;
+       modes[0].rates[3] = 110;
+       modes[0].rates[4] = 60;
+       modes[0].rates[5] = 90;
+       modes[0].rates[6] = 120;
+       modes[0].rates[7] = 180;
+       modes[0].rates[8] = 240;
+       modes[0].rates[9] = 360;
+       modes[0].rates[10] = 480;
+       modes[0].rates[11] = 540;
 
        modes[1].mode = HOSTAPD_MODE_IEEE80211B;
-       modes[1].num_channels = 1;
-       modes[1].num_rates = 1;
-       modes[1].channels = os_zalloc(sizeof(struct hostapd_channel_data));
-       modes[1].rates = os_zalloc(sizeof(int));
+       modes[1].num_channels = 11;
+       modes[1].num_rates = 4;
+       modes[1].channels =
+               os_zalloc(11 * sizeof(struct hostapd_channel_data));
+       modes[1].rates = os_zalloc(modes[1].num_rates * sizeof(int));
        if (modes[1].channels == NULL || modes[1].rates == NULL)
                goto fail;
-       modes[1].channels[0].chan = 1;
-       modes[1].channels[0].freq = 2412;
-       modes[1].channels[0].flag = 0;
+       for (i = 0; i < 11; i++) {
+               modes[1].channels[i].chan = i + 1;
+               modes[1].channels[i].freq = 2412 + 5 * i;
+               modes[1].channels[i].flag = 0;
+       }
        modes[1].rates[0] = 10;
+       modes[1].rates[1] = 20;
+       modes[1].rates[2] = 55;
+       modes[1].rates[3] = 110;
 
        modes[2].mode = HOSTAPD_MODE_IEEE80211A;
        modes[2].num_channels = 1;
-       modes[2].num_rates = 1;
+       modes[2].num_rates = 8;
        modes[2].channels = os_zalloc(sizeof(struct hostapd_channel_data));
-       modes[2].rates = os_zalloc(sizeof(int));
+       modes[2].rates = os_zalloc(modes[2].num_rates * sizeof(int));
        if (modes[2].channels == NULL || modes[2].rates == NULL)
                goto fail;
        modes[2].channels[0].chan = 60;
        modes[2].channels[0].freq = 5300;
        modes[2].channels[0].flag = 0;
        modes[2].rates[0] = 60;
+       modes[2].rates[1] = 90;
+       modes[2].rates[2] = 120;
+       modes[2].rates[3] = 180;
+       modes[2].rates[4] = 240;
+       modes[2].rates[5] = 360;
+       modes[2].rates[6] = 480;
+       modes[2].rates[7] = 540;
 
        return modes;
 
 fail:
        if (modes) {
-               size_t i;
                for (i = 0; i < *num_modes; i++) {
                        os_free(modes[i].channels);
                        os_free(modes[i].rates);
@@ -2407,6 +2553,141 @@ 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;
+       drv->alloc_iface_idx++;
+       addr[0] = 0x02; /* locally administered */
+       sha1_prf(drv->own_addr, ETH_ALEN, "hostapd test addr generation",
+                (const u8 *) &drv->alloc_iface_idx,
+                sizeof(drv->alloc_iface_idx),
+                addr + 1, ETH_ALEN - 1);
+       return 0;
+}
+
+
+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;
+       wpa_printf(MSG_DEBUG, "%s(report=%d)", __func__, report);
+       drv->probe_req_report = report;
+       return 0;
+}
+
+
 const struct wpa_driver_ops wpa_driver_test_ops = {
        "test",
        "wpa_supplicant test driver",
@@ -2426,8 +2707,7 @@ const struct wpa_driver_ops wpa_driver_test_ops = {
        .set_sta_vlan = test_driver_set_sta_vlan,
        .sta_add = test_driver_sta_add,
        .send_ether = test_driver_send_ether,
-       .set_wps_beacon_ie = test_driver_set_wps_beacon_ie,
-       .set_wps_probe_resp_ie = test_driver_set_wps_probe_resp_ie,
+       .set_ap_wps_ie = test_driver_set_ap_wps_ie,
        .get_bssid = wpa_driver_test_get_bssid,
        .get_ssid = wpa_driver_test_get_ssid,
        .set_key = wpa_driver_test_set_key,
@@ -2451,4 +2731,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,
 };