driver_test: Optional support for using UDP socket
[mech_eap.git] / src / drivers / driver_test.c
index 8c0b430..01c57d1 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
@@ -31,6 +31,8 @@ struct wpa_driver_test_data {
        int test_socket;
        struct sockaddr_un hostapd_addr;
        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 +46,8 @@ 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;
 };
 
 
@@ -85,11 +89,28 @@ static void wpa_driver_scan_dir(struct wpa_driver_test_data *drv,
        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)
                        continue;
@@ -100,7 +121,7 @@ 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)");
                }
@@ -126,6 +147,13 @@ static int wpa_driver_test_scan(void *priv, const u8 *ssid, size_t ssid_len)
                perror("sendto(test_socket)");
        }
 
+       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,
                               drv->ctx);
@@ -223,7 +251,8 @@ static int wpa_driver_test_associate(
                drv->hostapd_addr_set = 1;
        }
 
-       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,12 +269,20 @@ 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,
+               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;
                }
+               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;
@@ -564,6 +601,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);
 }
 
@@ -620,6 +658,50 @@ static int wpa_driver_test_attach(struct wpa_driver_test_data *drv,
 }
 
 
+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;
@@ -657,9 +739,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");
@@ -713,8 +810,13 @@ static int wpa_driver_test_send_eapol(void *priv, const u8 *dest, u16 proto,
        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) {
+                       msg.msg_name = &drv->hostapd_addr_udp;
+                       msg.msg_namelen = sizeof(drv->hostapd_addr_udp);
+               } else {
+                       msg.msg_name = &drv->hostapd_addr;
+                       msg.msg_namelen = sizeof(drv->hostapd_addr);
+               }
        } else {
                struct stat st;
                os_memset(&addr, 0, sizeof(addr));
@@ -936,6 +1038,27 @@ int wpa_driver_test_set_bssid(void *priv, const u8 *bssid)
 #endif /* CONFIG_CLIENT_MLME */
 
 
+int wpa_driver_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;
+}
+
+
 const struct wpa_driver_ops wpa_driver_test_ops = {
        "test",
        "wpa_supplicant test driver",
@@ -984,6 +1107,7 @@ 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_set_probe_req_ie,
+       NULL /* set_mode */,
+       NULL /* set_country */
 };