Add Beacon configuration for wpa_supplicant AP mode
[wpasupplicant] / src / drivers / driver_test.c
index 8c0b430..4c38122 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - testing driver interface
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * See README and COPYING for more details.
  */
 
+/* Make dure we get winsock2.h for Windows build to get sockaddr_storage */
+#include "build_config.h"
+#ifdef CONFIG_NATIVE_WINDOWS
+#include <winsock2.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
+
 #include "includes.h"
+
+#ifndef CONFIG_NATIVE_WINDOWS
 #include <sys/un.h>
 #include <dirent.h>
 #include <sys/stat.h>
+#define DRIVER_TEST_UNIX
+#endif /* CONFIG_NATIVE_WINDOWS */
 
 #include "common.h"
 #include "driver.h"
 #include "ieee802_11_defs.h"
 
 
+struct wpa_driver_test_global {
+       int dummy;
+};
+
 struct wpa_driver_test_data {
+       struct wpa_driver_test_global *global;
        void *ctx;
        u8 own_addr[ETH_ALEN];
        int test_socket;
+#ifdef DRIVER_TEST_UNIX
        struct sockaddr_un hostapd_addr;
+#endif /* DRIVER_TEST_UNIX */
        int hostapd_addr_set;
+       struct sockaddr_in hostapd_addr_udp;
+       int hostapd_addr_udp_set;
        char *own_socket_path;
        char *test_dir;
        u8 bssid[ETH_ALEN];
@@ -44,6 +63,10 @@ struct wpa_driver_test_data {
        size_t assoc_wpa_ie_len;
        int use_mlme;
        int associated;
+       u8 *probe_req_ie;
+       size_t probe_req_ie_len;
+       int ibss;
+       int privacy;
 };
 
 
@@ -51,6 +74,7 @@ static void wpa_driver_test_poll(void *eloop_ctx, void *timeout_ctx)
 {
        struct wpa_driver_test_data *drv = eloop_ctx;
 
+#ifdef DRIVER_TEST_UNIX
        if (drv->associated && drv->hostapd_addr_set) {
                struct stat st;
                if (stat(drv->hostapd_addr.sun_path, &st) < 0) {
@@ -60,6 +84,7 @@ static void wpa_driver_test_poll(void *eloop_ctx, void *timeout_ctx)
                        wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
                }
        }
+#endif /* DRIVER_TEST_UNIX */
 
        eloop_register_timeout(1, 0, wpa_driver_test_poll, drv, NULL);
 }
@@ -79,20 +104,48 @@ static void wpa_driver_test_scan_timeout(void *eloop_ctx, void *timeout_ctx)
 }
 
 
+#ifdef DRIVER_TEST_UNIX
 static void wpa_driver_scan_dir(struct wpa_driver_test_data *drv,
                                const char *path)
 {
        struct dirent *dent;
        DIR *dir;
        struct sockaddr_un addr;
+       char cmd[512], *pos, *end;
+       int ret;
 
        dir = opendir(path);
        if (dir == NULL)
                return;
 
+       end = cmd + sizeof(cmd);
+       pos = cmd;
+       ret = os_snprintf(pos, end - pos, "SCAN " MACSTR,
+                         MAC2STR(drv->own_addr));
+       if (ret >= 0 && ret < end - pos)
+               pos += ret;
+       if (drv->probe_req_ie) {
+               ret = os_snprintf(pos, end - pos, " ");
+               if (ret >= 0 && ret < end - pos)
+                       pos += ret;
+               pos += wpa_snprintf_hex(pos, end - pos, drv->probe_req_ie,
+                                       drv->probe_req_ie_len);
+       }
+       end[-1] = '\0';
+
        while ((dent = readdir(dir))) {
-               if (os_strncmp(dent->d_name, "AP-", 3) != 0)
+               if (os_strncmp(dent->d_name, "AP-", 3) != 0 &&
+                   os_strncmp(dent->d_name, "STA-", 4) != 0)
                        continue;
+               if (drv->own_socket_path) {
+                       size_t olen, dlen;
+                       olen = os_strlen(drv->own_socket_path);
+                       dlen = os_strlen(dent->d_name);
+                       if (olen >= dlen &&
+                           os_strcmp(dent->d_name,
+                                     drv->own_socket_path + olen - dlen) == 0)
+                               continue;
+               }
                wpa_printf(MSG_DEBUG, "%s: SCAN %s", __func__, dent->d_name);
 
                os_memset(&addr, 0, sizeof(addr));
@@ -100,22 +153,32 @@ static void wpa_driver_scan_dir(struct wpa_driver_test_data *drv,
                os_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s",
                            path, dent->d_name);
 
-               if (sendto(drv->test_socket, "SCAN", 4, 0,
+               if (sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
                           (struct sockaddr *) &addr, sizeof(addr)) < 0) {
                        perror("sendto(test_socket)");
                }
        }
        closedir(dir);
 }
+#endif /* DRIVER_TEST_UNIX */
 
 
-static int wpa_driver_test_scan(void *priv, const u8 *ssid, size_t ssid_len)
+static int wpa_driver_test_scan(void *priv,
+                               struct wpa_driver_scan_params *params)
 {
        struct wpa_driver_test_data *drv = priv;
+       size_t i;
+
        wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv);
+       for (i = 0; i < params->num_ssids; i++)
+               wpa_hexdump(MSG_DEBUG, "Scan SSID",
+                           params->ssids[i].ssid, params->ssids[i].ssid_len);
+       wpa_hexdump(MSG_DEBUG, "Scan extra IE(s)",
+                   params->extra_ies, params->extra_ies_len);
 
        drv->num_scanres = 0;
 
+#ifdef DRIVER_TEST_UNIX
        if (drv->test_socket >= 0 && drv->test_dir)
                wpa_driver_scan_dir(drv, drv->test_dir);
 
@@ -125,6 +188,14 @@ static int wpa_driver_test_scan(void *priv, const u8 *ssid, size_t ssid_len)
                   sizeof(drv->hostapd_addr)) < 0) {
                perror("sendto(test_socket)");
        }
+#endif /* DRIVER_TEST_UNIX */
+
+       if (drv->test_socket >= 0 && drv->hostapd_addr_udp_set &&
+           sendto(drv->test_socket, "SCAN", 4, 0,
+                  (struct sockaddr *) &drv->hostapd_addr_udp,
+                  sizeof(drv->hostapd_addr_udp)) < 0) {
+               perror("sendto(test_socket)");
+       }
 
        eloop_cancel_timeout(wpa_driver_test_scan_timeout, drv, drv->ctx);
        eloop_register_timeout(1, 0, wpa_driver_test_scan_timeout, drv,
@@ -213,7 +284,21 @@ static int wpa_driver_test_associate(
        } else
                drv->assoc_wpa_ie_len = 0;
 
-       if (drv->test_dir && params->bssid) {
+       drv->ibss = params->mode == IEEE80211_MODE_IBSS;
+       drv->privacy = params->key_mgmt_suite &
+               (WPA_KEY_MGMT_IEEE8021X |
+                WPA_KEY_MGMT_PSK |
+                WPA_KEY_MGMT_WPA_NONE |
+                WPA_KEY_MGMT_FT_IEEE8021X |
+                WPA_KEY_MGMT_FT_PSK |
+                WPA_KEY_MGMT_IEEE8021X_SHA256 |
+                WPA_KEY_MGMT_PSK_SHA256);
+       if (params->wep_key_len[params->wep_tx_keyidx])
+               drv->privacy = 1;
+
+#ifdef DRIVER_TEST_UNIX
+       if (drv->test_dir && params->bssid &&
+           params->mode != IEEE80211_MODE_IBSS) {
                os_memset(&drv->hostapd_addr, 0, sizeof(drv->hostapd_addr));
                drv->hostapd_addr.sun_family = AF_UNIX;
                os_snprintf(drv->hostapd_addr.sun_path,
@@ -222,8 +307,10 @@ static int wpa_driver_test_associate(
                            drv->test_dir, MAC2STR(params->bssid));
                drv->hostapd_addr_set = 1;
        }
+#endif /* DRIVER_TEST_UNIX */
 
-       if (drv->test_socket >= 0 && drv->hostapd_addr_set) {
+       if (drv->test_socket >= 0 &&
+           (drv->hostapd_addr_set || drv->hostapd_addr_udp_set)) {
                char cmd[200], *pos, *end;
                int ret;
                end = cmd + sizeof(cmd);
@@ -240,17 +327,38 @@ static int wpa_driver_test_associate(
                pos += wpa_snprintf_hex(pos, end - pos, params->wpa_ie,
                                        params->wpa_ie_len);
                end[-1] = '\0';
-               if (sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
+#ifdef DRIVER_TEST_UNIX
+               if (drv->hostapd_addr_set &&
+                   sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
                           (struct sockaddr *) &drv->hostapd_addr,
                           sizeof(drv->hostapd_addr)) < 0) {
                        perror("sendto(test_socket)");
                        return -1;
                }
+#endif /* DRIVER_TEST_UNIX */
+               if (drv->hostapd_addr_udp_set &&
+                   sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
+                          (struct sockaddr *) &drv->hostapd_addr_udp,
+                          sizeof(drv->hostapd_addr_udp)) < 0) {
+                       perror("sendto(test_socket)");
+                       return -1;
+               }
 
                os_memcpy(drv->ssid, params->ssid, params->ssid_len);
                drv->ssid_len = params->ssid_len;
        } else {
                drv->associated = 1;
+               if (params->mode == IEEE80211_MODE_IBSS) {
+                       os_memcpy(drv->ssid, params->ssid, params->ssid_len);
+                       drv->ssid_len = params->ssid_len;
+                       if (params->bssid)
+                               os_memcpy(drv->bssid, params->bssid, ETH_ALEN);
+                       else {
+                               os_get_random(drv->bssid, ETH_ALEN);
+                               drv->bssid[0] &= ~0x01;
+                               drv->bssid[0] |= 0x02;
+                       }
+               }
                wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
        }
 
@@ -276,6 +384,7 @@ static int wpa_driver_test_get_ssid(void *priv, u8 *ssid)
 
 static int wpa_driver_test_send_disassoc(struct wpa_driver_test_data *drv)
 {
+#ifdef DRIVER_TEST_UNIX
        if (drv->test_socket >= 0 &&
            sendto(drv->test_socket, "DISASSOC", 8, 0,
                   (struct sockaddr *) &drv->hostapd_addr,
@@ -283,6 +392,14 @@ static int wpa_driver_test_send_disassoc(struct wpa_driver_test_data *drv)
                perror("sendto(test_socket)");
                return -1;
        }
+#endif /* DRIVER_TEST_UNIX */
+       if (drv->test_socket >= 0 && drv->hostapd_addr_udp_set &&
+           sendto(drv->test_socket, "DISASSOC", 8, 0,
+                  (struct sockaddr *) &drv->hostapd_addr_udp,
+                  sizeof(drv->hostapd_addr_udp)) < 0) {
+               perror("sendto(test_socket)");
+               return -1;
+       }
        return 0;
 }
 
@@ -314,7 +431,7 @@ static int wpa_driver_test_disassociate(void *priv, const u8 *addr,
 
 
 static void wpa_driver_test_scanresp(struct wpa_driver_test_data *drv,
-                                    struct sockaddr_un *from,
+                                    struct sockaddr *from,
                                     socklen_t fromlen,
                                     const char *data)
 {
@@ -391,8 +508,10 @@ static void wpa_driver_test_scanresp(struct wpa_driver_test_data *drv,
                pos = pos2 + 1;
                while (*pos == ' ')
                        pos++;
-               if (os_strncmp(pos, "PRIVACY", 7) == 0)
+               if (os_strstr(pos, "PRIVACY"))
                        res->caps |= IEEE80211_CAP_PRIVACY;
+               if (os_strstr(pos, "IBSS"))
+                       res->caps |= IEEE80211_CAP_IBSS;
        }
 
        os_free(drv->scanres[drv->num_scanres]);
@@ -401,7 +520,7 @@ static void wpa_driver_test_scanresp(struct wpa_driver_test_data *drv,
 
 
 static void wpa_driver_test_assocresp(struct wpa_driver_test_data *drv,
-                                     struct sockaddr_un *from,
+                                     struct sockaddr *from,
                                      socklen_t fromlen,
                                      const char *data)
 {
@@ -423,7 +542,7 @@ static void wpa_driver_test_assocresp(struct wpa_driver_test_data *drv,
 
 
 static void wpa_driver_test_disassoc(struct wpa_driver_test_data *drv,
-                                    struct sockaddr_un *from,
+                                    struct sockaddr *from,
                                     socklen_t fromlen)
 {
        drv->associated = 0;
@@ -432,7 +551,7 @@ static void wpa_driver_test_disassoc(struct wpa_driver_test_data *drv,
 
 
 static void wpa_driver_test_eapol(struct wpa_driver_test_data *drv,
-                                 struct sockaddr_un *from,
+                                 struct sockaddr *from,
                                  socklen_t fromlen,
                                  const u8 *data, size_t data_len)
 {
@@ -449,7 +568,7 @@ static void wpa_driver_test_eapol(struct wpa_driver_test_data *drv,
 
 
 static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv,
-                                struct sockaddr_un *from,
+                                struct sockaddr *from,
                                 socklen_t fromlen,
                                 const u8 *data, size_t data_len)
 {
@@ -461,13 +580,61 @@ static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv,
 }
 
 
+static void wpa_driver_test_scan_cmd(struct wpa_driver_test_data *drv,
+                                    struct sockaddr *from,
+                                    socklen_t fromlen,
+                                    const u8 *data, size_t data_len)
+{
+       char buf[512], *pos, *end;
+       int ret;
+
+       /* data: optional [ STA-addr | ' ' | IEs(hex) ] */
+
+       if (!drv->ibss)
+               return;
+
+       pos = buf;
+       end = buf + sizeof(buf);
+
+       /* reply: SCANRESP BSSID SSID IEs */
+       ret = snprintf(pos, end - pos, "SCANRESP " MACSTR " ",
+                      MAC2STR(drv->bssid));
+       if (ret < 0 || ret >= end - pos)
+               return;
+       pos += ret;
+       pos += wpa_snprintf_hex(pos, end - pos,
+                               drv->ssid, drv->ssid_len);
+       ret = snprintf(pos, end - pos, " ");
+       if (ret < 0 || ret >= end - pos)
+               return;
+       pos += ret;
+       pos += wpa_snprintf_hex(pos, end - pos, drv->assoc_wpa_ie,
+                               drv->assoc_wpa_ie_len);
+
+       if (drv->privacy) {
+               ret = snprintf(pos, end - pos, " PRIVACY");
+               if (ret < 0 || ret >= end - pos)
+                       return;
+               pos += ret;
+       }
+
+       ret = snprintf(pos, end - pos, " IBSS");
+       if (ret < 0 || ret >= end - pos)
+               return;
+       pos += ret;
+
+       sendto(drv->test_socket, buf, pos - buf, 0,
+              (struct sockaddr *) from, fromlen);
+}
+
+
 static void wpa_driver_test_receive_unix(int sock, void *eloop_ctx,
                                         void *sock_ctx)
 {
        struct wpa_driver_test_data *drv = eloop_ctx;
        char *buf;
        int res;
-       struct sockaddr_un from;
+       struct sockaddr_storage from;
        socklen_t fromlen = sizeof(from);
        const size_t buflen = 2000;
 
@@ -486,19 +653,27 @@ static void wpa_driver_test_receive_unix(int sock, void *eloop_ctx,
        wpa_printf(MSG_DEBUG, "test_driver: received %u bytes", res);
 
        if (os_strncmp(buf, "SCANRESP ", 9) == 0) {
-               wpa_driver_test_scanresp(drv, &from, fromlen, buf + 9);
+               wpa_driver_test_scanresp(drv, (struct sockaddr *) &from,
+                                        fromlen, buf + 9);
        } else if (os_strncmp(buf, "ASSOCRESP ", 10) == 0) {
-               wpa_driver_test_assocresp(drv, &from, fromlen, buf + 10);
+               wpa_driver_test_assocresp(drv, (struct sockaddr *) &from,
+                                         fromlen, buf + 10);
        } else if (os_strcmp(buf, "DISASSOC") == 0) {
-               wpa_driver_test_disassoc(drv, &from, fromlen);
+               wpa_driver_test_disassoc(drv, (struct sockaddr *) &from,
+                                        fromlen);
        } else if (os_strcmp(buf, "DEAUTH") == 0) {
-               wpa_driver_test_disassoc(drv, &from, fromlen);
+               wpa_driver_test_disassoc(drv, (struct sockaddr *) &from,
+                                        fromlen);
        } else if (os_strncmp(buf, "EAPOL ", 6) == 0) {
-               wpa_driver_test_eapol(drv, &from, fromlen,
+               wpa_driver_test_eapol(drv, (struct sockaddr *) &from, fromlen,
                                      (const u8 *) buf + 6, res - 6);
        } else if (os_strncmp(buf, "MLME ", 5) == 0) {
-               wpa_driver_test_mlme(drv, &from, fromlen,
+               wpa_driver_test_mlme(drv, (struct sockaddr *) &from, fromlen,
                                     (const u8 *) buf + 5, res - 5);
+       } else if (os_strncmp(buf, "SCAN ", 5) == 0) {
+               wpa_driver_test_scan_cmd(drv, (struct sockaddr *) &from,
+                                        fromlen,
+                                        (const u8 *) buf + 5, res - 5);
        } else {
                wpa_hexdump_ascii(MSG_DEBUG, "Unknown test_socket command",
                                  (u8 *) buf, res);
@@ -507,13 +682,15 @@ static void wpa_driver_test_receive_unix(int sock, void *eloop_ctx,
 }
 
 
-static void * wpa_driver_test_init(void *ctx, const char *ifname)
+static void * wpa_driver_test_init2(void *ctx, const char *ifname,
+                                   void *global_priv)
 {
        struct wpa_driver_test_data *drv;
 
        drv = os_zalloc(sizeof(*drv));
        if (drv == NULL)
                return NULL;
+       drv->global = global_priv;
        drv->ctx = ctx;
        drv->test_socket = -1;
 
@@ -564,6 +741,7 @@ static void wpa_driver_test_deinit(void *priv)
        os_free(drv->test_dir);
        for (i = 0; i < MAX_SCAN_RESULTS; i++)
                os_free(drv->scanres[i]);
+       os_free(drv->probe_req_ie);
        os_free(drv);
 }
 
@@ -571,6 +749,7 @@ static void wpa_driver_test_deinit(void *priv)
 static int wpa_driver_test_attach(struct wpa_driver_test_data *drv,
                                  const char *dir)
 {
+#ifdef DRIVER_TEST_UNIX
        static unsigned int counter = 0;
        struct sockaddr_un addr;
        size_t len;
@@ -617,22 +796,73 @@ static int wpa_driver_test_attach(struct wpa_driver_test_data *drv,
                                 wpa_driver_test_receive_unix, drv, NULL);
 
        return 0;
+#else /* DRIVER_TEST_UNIX */
+       return -1;
+#endif /* DRIVER_TEST_UNIX */
+}
+
+
+static int wpa_driver_test_attach_udp(struct wpa_driver_test_data *drv,
+                                     char *dst)
+{
+       char *pos;
+
+       pos = os_strchr(dst, ':');
+       if (pos == NULL)
+               return -1;
+       *pos++ = '\0';
+       wpa_printf(MSG_DEBUG, "%s: addr=%s port=%s", __func__, dst, pos);
+
+       drv->test_socket = socket(PF_INET, SOCK_DGRAM, 0);
+       if (drv->test_socket < 0) {
+               perror("socket(PF_INET)");
+               return -1;
+       }
+
+       os_memset(&drv->hostapd_addr_udp, 0, sizeof(drv->hostapd_addr_udp));
+       drv->hostapd_addr_udp.sin_family = AF_INET;
+#if defined(CONFIG_NATIVE_WINDOWS) || defined(CONFIG_ANSI_C_EXTRA)
+       {
+               int a[4];
+               u8 *pos;
+               sscanf(dst, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]);
+               pos = (u8 *) &drv->hostapd_addr_udp.sin_addr;
+               *pos++ = a[0];
+               *pos++ = a[1];
+               *pos++ = a[2];
+               *pos++ = a[3];
+       }
+#else /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
+       inet_aton(dst, &drv->hostapd_addr_udp.sin_addr);
+#endif /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
+       drv->hostapd_addr_udp.sin_port = htons(atoi(pos));
+
+       drv->hostapd_addr_udp_set = 1;
+
+       eloop_register_read_sock(drv->test_socket,
+                                wpa_driver_test_receive_unix, drv, NULL);
+
+       return 0;
 }
 
 
 static int wpa_driver_test_set_param(void *priv, const char *param)
 {
        struct wpa_driver_test_data *drv = priv;
-       const char *pos, *pos2;
-       size_t len;
+       const char *pos;
 
        wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param);
        if (param == NULL)
                return 0;
 
        wpa_driver_test_close_test_socket(drv);
+
+#ifdef DRIVER_TEST_UNIX
        pos = os_strstr(param, "test_socket=");
        if (pos) {
+               const char *pos2;
+               size_t len;
+
                pos += 12;
                pos2 = os_strchr(pos, ' ');
                if (pos2)
@@ -646,6 +876,7 @@ static int wpa_driver_test_set_param(void *priv, const char *param)
                os_memcpy(drv->hostapd_addr.sun_path, pos, len);
                drv->hostapd_addr_set = 1;
        }
+#endif /* DRIVER_TEST_UNIX */
 
        pos = os_strstr(param, "test_dir=");
        if (pos) {
@@ -657,9 +888,24 @@ static int wpa_driver_test_set_param(void *priv, const char *param)
                end = os_strchr(drv->test_dir, ' ');
                if (end)
                        *end = '\0';
-               wpa_driver_test_attach(drv, drv->test_dir);
-       } else
-               wpa_driver_test_attach(drv, NULL);
+               if (wpa_driver_test_attach(drv, drv->test_dir))
+                       return -1;
+       } else {
+               pos = os_strstr(param, "test_udp=");
+               if (pos) {
+                       char *dst, *epos;
+                       dst = os_strdup(pos + 9);
+                       if (dst == NULL)
+                               return -1;
+                       epos = os_strchr(dst, ' ');
+                       if (epos)
+                               *epos = '\0';
+                       if (wpa_driver_test_attach_udp(drv, dst))
+                               return -1;
+                       os_free(dst);
+               } else if (wpa_driver_test_attach(drv, NULL))
+                       return -1;
+       }
 
        if (os_strstr(param, "use_associnfo=1")) {
                wpa_printf(MSG_DEBUG, "test_driver: Use AssocInfo events");
@@ -689,10 +935,14 @@ static int wpa_driver_test_send_eapol(void *priv, const u8 *dest, u16 proto,
                                      const u8 *data, size_t data_len)
 {
        struct wpa_driver_test_data *drv = priv;
-       struct msghdr msg;
-       struct iovec io[3];
+       char *msg;
+       size_t msg_len;
        struct l2_ethhdr eth;
-       struct sockaddr_un addr;
+       struct sockaddr *addr;
+       socklen_t alen;
+#ifdef DRIVER_TEST_UNIX
+       struct sockaddr_un addr_un;
+#endif /* DRIVER_TEST_UNIX */
 
        wpa_hexdump(MSG_MSGDUMP, "test_send_eapol TX frame", data, data_len);
 
@@ -701,40 +951,55 @@ static int wpa_driver_test_send_eapol(void *priv, const u8 *dest, u16 proto,
        os_memcpy(eth.h_source, drv->own_addr, ETH_ALEN);
        eth.h_proto = host_to_be16(proto);
 
-       io[0].iov_base = "EAPOL ";
-       io[0].iov_len = 6;
-       io[1].iov_base = (u8 *) &eth;
-       io[1].iov_len = sizeof(eth);
-       io[2].iov_base = (u8 *) data;
-       io[2].iov_len = data_len;
+       msg_len = 6 + sizeof(eth) + data_len;
+       msg = os_malloc(msg_len);
+       if (msg == NULL)
+               return -1;
+       os_memcpy(msg, "EAPOL ", 6);
+       os_memcpy(msg + 6, &eth, sizeof(eth));
+       os_memcpy(msg + 6 + sizeof(eth), data, data_len);
 
-       os_memset(&msg, 0, sizeof(msg));
-       msg.msg_iov = io;
-       msg.msg_iovlen = 3;
        if (os_memcmp(dest, drv->bssid, ETH_ALEN) == 0 ||
            drv->test_dir == NULL) {
-               msg.msg_name = &drv->hostapd_addr;
-               msg.msg_namelen = sizeof(drv->hostapd_addr);
+               if (drv->hostapd_addr_udp_set) {
+                       addr = (struct sockaddr *) &drv->hostapd_addr_udp;
+                       alen = sizeof(drv->hostapd_addr_udp);
+               } else {
+#ifdef DRIVER_TEST_UNIX
+                       addr = (struct sockaddr *) &drv->hostapd_addr;
+                       alen = sizeof(drv->hostapd_addr);
+#else /* DRIVER_TEST_UNIX */
+                       os_free(msg);
+                       return -1;
+#endif /* DRIVER_TEST_UNIX */
+               }
        } else {
+#ifdef DRIVER_TEST_UNIX
                struct stat st;
-               os_memset(&addr, 0, sizeof(addr));
-               addr.sun_family = AF_UNIX;
-               os_snprintf(addr.sun_path, sizeof(addr.sun_path),
+               os_memset(&addr_un, 0, sizeof(addr_un));
+               addr_un.sun_family = AF_UNIX;
+               os_snprintf(addr_un.sun_path, sizeof(addr_un.sun_path),
                            "%s/STA-" MACSTR, drv->test_dir, MAC2STR(dest));
-               if (stat(addr.sun_path, &st) < 0) {
-                       os_snprintf(addr.sun_path, sizeof(addr.sun_path),
+               if (stat(addr_un.sun_path, &st) < 0) {
+                       os_snprintf(addr_un.sun_path, sizeof(addr_un.sun_path),
                                    "%s/AP-" MACSTR,
                                    drv->test_dir, MAC2STR(dest));
                }
-               msg.msg_name = &addr;
-               msg.msg_namelen = sizeof(addr);
+               addr = (struct sockaddr *) &addr_un;
+               alen = sizeof(addr_un);
+#else /* DRIVER_TEST_UNIX */
+               os_free(msg);
+               return -1;
+#endif /* DRIVER_TEST_UNIX */
        }
 
-       if (sendmsg(drv->test_socket, &msg, 0) < 0) {
+       if (sendto(drv->test_socket, msg, msg_len, 0, addr, alen) < 0) {
                perror("sendmsg(test_socket)");
+               os_free(msg);
                return -1;
        }
 
+       os_free(msg);
        return 0;
 }
 
@@ -759,6 +1024,7 @@ static int wpa_driver_test_get_capa(void *priv, struct wpa_driver_capa *capa)
                WPA_DRIVER_AUTH_LEAP;
        if (drv->use_mlme)
                capa->flags |= WPA_DRIVER_FLAGS_USER_SPACE_MLME;
+       capa->max_scan_ssids = 2;
 
        return 0;
 }
@@ -811,8 +1077,8 @@ wpa_driver_test_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
 }
 
 
-int wpa_driver_test_set_channel(void *priv, wpa_hw_mode phymode, int chan,
-                               int freq)
+static int wpa_driver_test_set_channel(void *priv, wpa_hw_mode phymode,
+                                      int chan, int freq)
 {
        wpa_printf(MSG_DEBUG, "%s: phymode=%d chan=%d freq=%d",
                   __func__, phymode, chan, freq);
@@ -846,8 +1112,15 @@ static int wpa_driver_test_send_mlme(void *priv, const u8 *data,
        msg.msg_iovlen = 2;
        if (os_memcmp(dest, drv->bssid, ETH_ALEN) == 0 ||
            drv->test_dir == NULL) {
-               msg.msg_name = &drv->hostapd_addr;
-               msg.msg_namelen = sizeof(drv->hostapd_addr);
+               if (drv->hostapd_addr_udp_set) {
+                       msg.msg_name = &drv->hostapd_addr_udp;
+                       msg.msg_namelen = sizeof(drv->hostapd_addr_udp);
+               } else {
+#ifdef DRIVER_TEST_UNIX
+                       msg.msg_name = &drv->hostapd_addr;
+                       msg.msg_namelen = sizeof(drv->hostapd_addr);
+#endif /* DRIVER_TEST_UNIX */
+               }
        } else if (os_memcmp(dest, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)
        {
                dir = opendir(drv->test_dir);
@@ -921,14 +1194,15 @@ static int wpa_driver_test_mlme_remove_sta(void *priv, const u8 *addr)
 }
 
 
-int wpa_driver_test_set_ssid(void *priv, const u8 *ssid, size_t ssid_len)
+static int wpa_driver_test_set_ssid(void *priv, const u8 *ssid,
+                                   size_t ssid_len)
 {
        wpa_printf(MSG_DEBUG, "%s", __func__);
        return 0;
 }
 
 
-int wpa_driver_test_set_bssid(void *priv, const u8 *bssid)
+static int wpa_driver_test_set_bssid(void *priv, const u8 *bssid)
 {
        wpa_printf(MSG_DEBUG, "%s: bssid=" MACSTR, __func__, MAC2STR(bssid));
        return 0;
@@ -936,6 +1210,67 @@ int wpa_driver_test_set_bssid(void *priv, const u8 *bssid)
 #endif /* CONFIG_CLIENT_MLME */
 
 
+static int wpa_driver_test_set_probe_req_ie(void *priv, const u8 *ies,
+                                           size_t ies_len)
+{
+       struct wpa_driver_test_data *drv = priv;
+
+       os_free(drv->probe_req_ie);
+       if (ies) {
+               drv->probe_req_ie = os_malloc(ies_len);
+               if (drv->probe_req_ie == NULL) {
+                       drv->probe_req_ie_len = 0;
+                       return -1;
+               }
+               os_memcpy(drv->probe_req_ie, ies, ies_len);
+               drv->probe_req_ie_len = ies_len;
+       } else {
+               drv->probe_req_ie = NULL;
+               drv->probe_req_ie_len = 0;
+       }
+       return 0;
+}
+
+
+static void * wpa_driver_test_global_init(void)
+{
+       struct wpa_driver_test_global *global;
+
+       global = os_zalloc(sizeof(*global));
+       return global;
+}
+
+
+static void wpa_driver_test_global_deinit(void *priv)
+{
+       struct wpa_driver_test_global *global = priv;
+       os_free(global);
+}
+
+
+static struct wpa_interface_info *
+wpa_driver_test_get_interfaces(void *global_priv)
+{
+       /* struct wpa_driver_test_global *global = priv; */
+       struct wpa_interface_info *iface;
+
+       iface = os_zalloc(sizeof(*iface));
+       if (iface == NULL)
+               return iface;
+       iface->ifname = os_strdup("sta0");
+       iface->desc = os_strdup("test interface 0");
+       iface->drv_name = "test";
+       iface->next = os_zalloc(sizeof(*iface));
+       if (iface->next) {
+               iface->next->ifname = os_strdup("sta1");
+               iface->next->desc = os_strdup("test interface 1");
+               iface->next->drv_name = "test";
+       }
+
+       return iface;
+}
+
+
 const struct wpa_driver_ops wpa_driver_test_ops = {
        "test",
        "wpa_supplicant test driver",
@@ -943,12 +1278,12 @@ const struct wpa_driver_ops wpa_driver_test_ops = {
        wpa_driver_test_get_ssid,
        wpa_driver_test_set_wpa,
        wpa_driver_test_set_key,
-       wpa_driver_test_init,
+       NULL /* init */,
        wpa_driver_test_deinit,
        wpa_driver_test_set_param,
        NULL /* set_countermeasures */,
        NULL /* set_drop_unencrypted */,
-       wpa_driver_test_scan,
+       NULL /* scan */,
        NULL /* get_scan_results */,
        wpa_driver_test_deauthenticate,
        wpa_driver_test_disassociate,
@@ -984,6 +1319,15 @@ const struct wpa_driver_ops wpa_driver_test_ops = {
        NULL /* update_ft_ies */,
        NULL /* send_ft_action */,
        wpa_driver_test_get_scan_results2,
-       NULL /* set_probe_req_ie */,
-       NULL /* set_mode */
+       wpa_driver_test_set_probe_req_ie,
+       NULL /* set_mode */,
+       NULL /* set_country */,
+       wpa_driver_test_global_init,
+       wpa_driver_test_global_deinit,
+       wpa_driver_test_init2,
+       wpa_driver_test_get_interfaces,
+       wpa_driver_test_scan,
+       NULL /* authenticate */,
+       NULL /* set_beacon */,
+       NULL /* set_beacon_int */
 };