/* * WPA Supplicant - testing driver interface * Copyright (c) 2004-2008, Jouni Malinen * * 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 * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * 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 #endif /* CONFIG_NATIVE_WINDOWS */ #include "includes.h" #ifndef CONFIG_NATIVE_WINDOWS #include #include #include #define DRIVER_TEST_UNIX #endif /* CONFIG_NATIVE_WINDOWS */ #include "common.h" #include "driver.h" #include "l2_packet/l2_packet.h" #include "eloop.h" #include "sha1.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]; u8 ssid[32]; size_t ssid_len; #define MAX_SCAN_RESULTS 30 struct wpa_scan_res *scanres[MAX_SCAN_RESULTS]; size_t num_scanres; int use_associnfo; u8 assoc_wpa_ie[80]; size_t assoc_wpa_ie_len; int use_mlme; int associated; u8 *probe_req_ie; size_t probe_req_ie_len; }; 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) { wpa_printf(MSG_DEBUG, "%s: lost connection to AP: %s", __func__, strerror(errno)); drv->associated = 0; wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); } } #endif /* DRIVER_TEST_UNIX */ eloop_register_timeout(1, 0, wpa_driver_test_poll, drv, NULL); } static int wpa_driver_test_set_wpa(void *priv, int enabled) { wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); return 0; } static void wpa_driver_test_scan_timeout(void *eloop_ctx, void *timeout_ctx) { wpa_printf(MSG_DEBUG, "Scan timeout - try to get results"); wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); } #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) continue; wpa_printf(MSG_DEBUG, "%s: SCAN %s", __func__, dent->d_name); os_memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; os_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", path, dent->d_name); 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) { struct wpa_driver_test_data *drv = priv; wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv); drv->num_scanres = 0; #ifdef DRIVER_TEST_UNIX if (drv->test_socket >= 0 && drv->test_dir) wpa_driver_scan_dir(drv, drv->test_dir); if (drv->test_socket >= 0 && drv->hostapd_addr_set && sendto(drv->test_socket, "SCAN", 4, 0, (struct sockaddr *) &drv->hostapd_addr, 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, drv->ctx); return 0; } static struct wpa_scan_results * wpa_driver_test_get_scan_results2(void *priv) { struct wpa_driver_test_data *drv = priv; struct wpa_scan_results *res; size_t i; res = os_zalloc(sizeof(*res)); if (res == NULL) return NULL; res->res = os_zalloc(drv->num_scanres * sizeof(struct wpa_scan_res *)); if (res->res == NULL) { os_free(res); return NULL; } for (i = 0; i < drv->num_scanres; i++) { struct wpa_scan_res *r; if (drv->scanres[i] == NULL) continue; r = os_malloc(sizeof(*r) + drv->scanres[i]->ie_len); if (r == NULL) break; os_memcpy(r, drv->scanres[i], sizeof(*r) + drv->scanres[i]->ie_len); res->res[res->num++] = r; } return res; } static int wpa_driver_test_set_key(void *priv, 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) { wpa_printf(MSG_DEBUG, "%s: priv=%p alg=%d key_idx=%d set_tx=%d", __func__, priv, alg, key_idx, set_tx); if (addr) { wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr)); } if (seq) { wpa_hexdump(MSG_DEBUG, " seq", seq, seq_len); } if (key) { wpa_hexdump(MSG_DEBUG, " key", key, key_len); } return 0; } static int wpa_driver_test_associate( void *priv, struct wpa_driver_associate_params *params) { struct wpa_driver_test_data *drv = priv; wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d " "group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d", __func__, priv, params->freq, params->pairwise_suite, params->group_suite, params->key_mgmt_suite, params->auth_alg, params->mode); if (params->bssid) { wpa_printf(MSG_DEBUG, " bssid=" MACSTR, MAC2STR(params->bssid)); } if (params->ssid) { wpa_hexdump_ascii(MSG_DEBUG, " ssid", params->ssid, params->ssid_len); } if (params->wpa_ie) { wpa_hexdump(MSG_DEBUG, " wpa_ie", params->wpa_ie, params->wpa_ie_len); drv->assoc_wpa_ie_len = params->wpa_ie_len; if (drv->assoc_wpa_ie_len > sizeof(drv->assoc_wpa_ie)) drv->assoc_wpa_ie_len = sizeof(drv->assoc_wpa_ie); os_memcpy(drv->assoc_wpa_ie, params->wpa_ie, drv->assoc_wpa_ie_len); } else drv->assoc_wpa_ie_len = 0; #ifdef DRIVER_TEST_UNIX if (drv->test_dir && params->bssid) { os_memset(&drv->hostapd_addr, 0, sizeof(drv->hostapd_addr)); drv->hostapd_addr.sun_family = AF_UNIX; os_snprintf(drv->hostapd_addr.sun_path, sizeof(drv->hostapd_addr.sun_path), "%s/AP-" MACSTR, drv->test_dir, MAC2STR(params->bssid)); drv->hostapd_addr_set = 1; } #endif /* DRIVER_TEST_UNIX */ 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); pos = cmd; ret = os_snprintf(pos, end - pos, "ASSOC " MACSTR " ", MAC2STR(drv->own_addr)); if (ret >= 0 && ret < end - pos) pos += ret; pos += wpa_snprintf_hex(pos, end - pos, params->ssid, params->ssid_len); ret = os_snprintf(pos, end - pos, " "); if (ret >= 0 && ret < end - pos) pos += ret; pos += wpa_snprintf_hex(pos, end - pos, params->wpa_ie, params->wpa_ie_len); end[-1] = '\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; wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL); } return 0; } static int wpa_driver_test_get_bssid(void *priv, u8 *bssid) { struct wpa_driver_test_data *drv = priv; os_memcpy(bssid, drv->bssid, ETH_ALEN); return 0; } static int wpa_driver_test_get_ssid(void *priv, u8 *ssid) { struct wpa_driver_test_data *drv = priv; os_memcpy(ssid, drv->ssid, 32); return drv->ssid_len; } 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, sizeof(drv->hostapd_addr)) < 0) { 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; } static int wpa_driver_test_deauthenticate(void *priv, const u8 *addr, int reason_code) { struct wpa_driver_test_data *drv = priv; wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d", __func__, MAC2STR(addr), reason_code); os_memset(drv->bssid, 0, ETH_ALEN); drv->associated = 0; wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); return wpa_driver_test_send_disassoc(drv); } static int wpa_driver_test_disassociate(void *priv, const u8 *addr, int reason_code) { struct wpa_driver_test_data *drv = priv; wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d", __func__, MAC2STR(addr), reason_code); os_memset(drv->bssid, 0, ETH_ALEN); drv->associated = 0; wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); return wpa_driver_test_send_disassoc(drv); } static void wpa_driver_test_scanresp(struct wpa_driver_test_data *drv, struct sockaddr *from, socklen_t fromlen, const char *data) { struct wpa_scan_res *res; const char *pos, *pos2; size_t len; u8 *ie_pos, *ie_start, *ie_end; #define MAX_IE_LEN 1000 wpa_printf(MSG_DEBUG, "test_driver: SCANRESP %s", data); if (drv->num_scanres >= MAX_SCAN_RESULTS) { wpa_printf(MSG_DEBUG, "test_driver: No room for the new scan " "result"); return; } /* SCANRESP BSSID SSID IEs */ res = os_zalloc(sizeof(*res) + MAX_IE_LEN); if (res == NULL) return; ie_start = ie_pos = (u8 *) (res + 1); ie_end = ie_pos + MAX_IE_LEN; if (hwaddr_aton(data, res->bssid)) { wpa_printf(MSG_DEBUG, "test_driver: invalid BSSID in scanres"); os_free(res); return; } pos = data + 17; while (*pos == ' ') pos++; pos2 = os_strchr(pos, ' '); if (pos2 == NULL) { wpa_printf(MSG_DEBUG, "test_driver: invalid SSID termination " "in scanres"); os_free(res); return; } len = (pos2 - pos) / 2; if (len > 32) len = 32; /* * Generate SSID IE from the SSID field since this IE is not included * in the main IE field. */ *ie_pos++ = WLAN_EID_SSID; *ie_pos++ = len; if (hexstr2bin(pos, ie_pos, len) < 0) { wpa_printf(MSG_DEBUG, "test_driver: invalid SSID in scanres"); os_free(res); return; } ie_pos += len; pos = pos2 + 1; pos2 = os_strchr(pos, ' '); if (pos2 == NULL) len = os_strlen(pos) / 2; else len = (pos2 - pos) / 2; if ((int) len > ie_end - ie_pos) len = ie_end - ie_pos; if (hexstr2bin(pos, ie_pos, len) < 0) { wpa_printf(MSG_DEBUG, "test_driver: invalid IEs in scanres"); os_free(res); return; } ie_pos += len; res->ie_len = ie_pos - ie_start; if (pos2) { pos = pos2 + 1; while (*pos == ' ') pos++; if (os_strncmp(pos, "PRIVACY", 7) == 0) res->caps |= IEEE80211_CAP_PRIVACY; } os_free(drv->scanres[drv->num_scanres]); drv->scanres[drv->num_scanres++] = res; } static void wpa_driver_test_assocresp(struct wpa_driver_test_data *drv, struct sockaddr *from, socklen_t fromlen, const char *data) { /* ASSOCRESP BSSID */ if (hwaddr_aton(data, drv->bssid)) { wpa_printf(MSG_DEBUG, "test_driver: invalid BSSID in " "assocresp"); } if (drv->use_associnfo) { union wpa_event_data event; os_memset(&event, 0, sizeof(event)); event.assoc_info.req_ies = drv->assoc_wpa_ie; event.assoc_info.req_ies_len = drv->assoc_wpa_ie_len; wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &event); } drv->associated = 1; wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL); } static void wpa_driver_test_disassoc(struct wpa_driver_test_data *drv, struct sockaddr *from, socklen_t fromlen) { drv->associated = 0; wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); } static void wpa_driver_test_eapol(struct wpa_driver_test_data *drv, struct sockaddr *from, socklen_t fromlen, const u8 *data, size_t data_len) { const u8 *src = drv->bssid; if (data_len > 14) { /* Skip Ethernet header */ src = data + ETH_ALEN; data += 14; data_len -= 14; } wpa_supplicant_rx_eapol(drv->ctx, src, data, data_len); } static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv, struct sockaddr *from, 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 */ } 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_storage from; socklen_t fromlen = sizeof(from); const size_t buflen = 2000; buf = os_malloc(buflen); if (buf == NULL) return; res = recvfrom(sock, buf, buflen - 1, 0, (struct sockaddr *) &from, &fromlen); if (res < 0) { perror("recvfrom(test_socket)"); os_free(buf); return; } buf[res] = '\0'; wpa_printf(MSG_DEBUG, "test_driver: received %u bytes", res); if (os_strncmp(buf, "SCANRESP ", 9) == 0) { wpa_driver_test_scanresp(drv, (struct sockaddr *) &from, fromlen, buf + 9); } else if (os_strncmp(buf, "ASSOCRESP ", 10) == 0) { wpa_driver_test_assocresp(drv, (struct sockaddr *) &from, fromlen, buf + 10); } else if (os_strcmp(buf, "DISASSOC") == 0) { wpa_driver_test_disassoc(drv, (struct sockaddr *) &from, fromlen); } else if (os_strcmp(buf, "DEAUTH") == 0) { wpa_driver_test_disassoc(drv, (struct sockaddr *) &from, fromlen); } else if (os_strncmp(buf, "EAPOL ", 6) == 0) { 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, (struct sockaddr *) &from, fromlen, (const u8 *) buf + 5, res - 5); } else { wpa_hexdump_ascii(MSG_DEBUG, "Unknown test_socket command", (u8 *) buf, res); } os_free(buf); } 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; /* Set dummy BSSID and SSID for testing. */ drv->bssid[0] = 0x02; drv->bssid[1] = 0x00; drv->bssid[2] = 0x00; drv->bssid[3] = 0x00; drv->bssid[4] = 0x00; drv->bssid[5] = 0x01; 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); eloop_register_timeout(1, 0, wpa_driver_test_poll, drv, NULL); return drv; } static void wpa_driver_test_close_test_socket(struct wpa_driver_test_data *drv) { if (drv->test_socket >= 0) { eloop_unregister_read_sock(drv->test_socket); close(drv->test_socket); drv->test_socket = -1; } if (drv->own_socket_path) { unlink(drv->own_socket_path); os_free(drv->own_socket_path); drv->own_socket_path = NULL; } } static void wpa_driver_test_deinit(void *priv) { struct wpa_driver_test_data *drv = priv; int i; 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); 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); } 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; os_free(drv->own_socket_path); if (dir) { len = os_strlen(dir) + 30; drv->own_socket_path = os_malloc(len); if (drv->own_socket_path == NULL) return -1; os_snprintf(drv->own_socket_path, len, "%s/STA-" MACSTR, dir, MAC2STR(drv->own_addr)); } else { drv->own_socket_path = os_malloc(100); if (drv->own_socket_path == NULL) return -1; os_snprintf(drv->own_socket_path, 100, "/tmp/wpa_supplicant_test-%d-%d", getpid(), counter++); } drv->test_socket = socket(PF_UNIX, SOCK_DGRAM, 0); if (drv->test_socket < 0) { perror("socket(PF_UNIX)"); os_free(drv->own_socket_path); drv->own_socket_path = NULL; return -1; } os_memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path)); if (bind(drv->test_socket, (struct sockaddr *) &addr, sizeof(addr)) < 0) { perror("bind(PF_UNIX)"); close(drv->test_socket); unlink(drv->own_socket_path); os_free(drv->own_socket_path); drv->own_socket_path = NULL; return -1; } eloop_register_read_sock(drv->test_socket, 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; 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) len = pos2 - pos; else len = os_strlen(pos); if (len > sizeof(drv->hostapd_addr.sun_path)) return -1; os_memset(&drv->hostapd_addr, 0, sizeof(drv->hostapd_addr)); drv->hostapd_addr.sun_family = AF_UNIX; 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) { char *end; os_free(drv->test_dir); drv->test_dir = os_strdup(pos + 9); if (drv->test_dir == NULL) return -1; end = os_strchr(drv->test_dir, ' '); if (end) *end = '\0'; 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"); drv->use_associnfo = 1; } #ifdef CONFIG_CLIENT_MLME if (os_strstr(param, "use_mlme=1")) { wpa_printf(MSG_DEBUG, "test_driver: Use internal MLME"); drv->use_mlme = 1; } #endif /* CONFIG_CLIENT_MLME */ return 0; } static const u8 * wpa_driver_test_get_mac_addr(void *priv) { struct wpa_driver_test_data *drv = priv; wpa_printf(MSG_DEBUG, "%s", __func__); return drv->own_addr; } 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; char *msg; size_t msg_len; struct l2_ethhdr eth; 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); os_memset(ð, 0, sizeof(eth)); os_memcpy(eth.h_dest, dest, ETH_ALEN); os_memcpy(eth.h_source, drv->own_addr, ETH_ALEN); eth.h_proto = host_to_be16(proto); 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, ð, sizeof(eth)); os_memcpy(msg + 6 + sizeof(eth), data, data_len); if (os_memcmp(dest, drv->bssid, ETH_ALEN) == 0 || drv->test_dir == NULL) { 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_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_un.sun_path, &st) < 0) { os_snprintf(addr_un.sun_path, sizeof(addr_un.sun_path), "%s/AP-" MACSTR, drv->test_dir, MAC2STR(dest)); } addr = (struct sockaddr *) &addr_un; alen = sizeof(addr_un); #else /* DRIVER_TEST_UNIX */ os_free(msg); return -1; #endif /* DRIVER_TEST_UNIX */ } 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; } static int wpa_driver_test_get_capa(void *priv, struct wpa_driver_capa *capa) { struct wpa_driver_test_data *drv = priv; os_memset(capa, 0, sizeof(*capa)); capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK | WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE | WPA_DRIVER_CAPA_KEY_MGMT_FT | WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK; capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 | WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP; capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED | WPA_DRIVER_AUTH_LEAP; if (drv->use_mlme) capa->flags |= WPA_DRIVER_FLAGS_USER_SPACE_MLME; return 0; } static int wpa_driver_test_mlme_setprotection(void *priv, const u8 *addr, int protect_type, int key_type) { wpa_printf(MSG_DEBUG, "%s: protect_type=%d key_type=%d", __func__, protect_type, key_type); if (addr) { wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, MAC2STR(addr)); } return 0; } #ifdef CONFIG_CLIENT_MLME static struct wpa_hw_modes * wpa_driver_test_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags) { struct wpa_hw_modes *modes; *num_modes = 1; *flags = 0; modes = os_zalloc(*num_modes * sizeof(struct wpa_hw_modes)); if (modes == NULL) return NULL; modes[0].mode = WPA_MODE_IEEE80211G; modes[0].num_channels = 1; modes[0].num_rates = 1; modes[0].channels = os_zalloc(sizeof(struct wpa_channel_data)); modes[0].rates = os_zalloc(sizeof(struct wpa_rate_data)); if (modes[0].channels == NULL || modes[0].rates == NULL) { wpa_supplicant_sta_free_hw_features(modes, *num_modes); return NULL; } modes[0].channels[0].chan = 1; modes[0].channels[0].freq = 2412; modes[0].channels[0].flag = WPA_CHAN_W_SCAN | WPA_CHAN_W_ACTIVE_SCAN; modes[0].rates[0].rate = 10; modes[0].rates[0].flags = WPA_RATE_BASIC | WPA_RATE_SUPPORTED | WPA_RATE_CCK | WPA_RATE_MANDATORY; return modes; } 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); return 0; } static int wpa_driver_test_send_mlme(void *priv, const u8 *data, size_t data_len) { struct wpa_driver_test_data *drv = priv; struct msghdr msg; struct iovec io[2]; struct sockaddr_un addr; const u8 *dest; struct dirent *dent; DIR *dir; wpa_hexdump(MSG_MSGDUMP, "test_send_mlme", data, data_len); if (data_len < 10) return -1; dest = data + 4; io[0].iov_base = "MLME "; io[0].iov_len = 5; io[1].iov_base = (u8 *) data; io[1].iov_len = data_len; os_memset(&msg, 0, sizeof(msg)); msg.msg_iov = io; msg.msg_iovlen = 2; if (os_memcmp(dest, drv->bssid, ETH_ALEN) == 0 || drv->test_dir == NULL) { 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); if (dir == NULL) return -1; while ((dent = readdir(dir))) { #ifdef _DIRENT_HAVE_D_TYPE /* Skip the file if it is not a socket. * Also accept DT_UNKNOWN (0) in case * the C library or underlying file * system does not support d_type. */ if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN) continue; #endif /* _DIRENT_HAVE_D_TYPE */ if (os_strcmp(dent->d_name, ".") == 0 || os_strcmp(dent->d_name, "..") == 0) continue; wpa_printf(MSG_DEBUG, "%s: Send broadcast MLME to %s", __func__, dent->d_name); os_memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; os_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", drv->test_dir, dent->d_name); msg.msg_name = &addr; msg.msg_namelen = sizeof(addr); if (sendmsg(drv->test_socket, &msg, 0) < 0) perror("sendmsg(test_socket)"); } closedir(dir); return 0; } else { struct stat st; os_memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; os_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/AP-" MACSTR, drv->test_dir, MAC2STR(dest)); if (stat(addr.sun_path, &st) < 0) { os_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/STA-" MACSTR, drv->test_dir, MAC2STR(dest)); } msg.msg_name = &addr; msg.msg_namelen = sizeof(addr); } if (sendmsg(drv->test_socket, &msg, 0) < 0) { perror("sendmsg(test_socket)"); return -1; } return 0; } static int wpa_driver_test_mlme_add_sta(void *priv, const u8 *addr, const u8 *supp_rates, size_t supp_rates_len) { wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, MAC2STR(addr)); return 0; } static int wpa_driver_test_mlme_remove_sta(void *priv, const u8 *addr) { wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, MAC2STR(addr)); return 0; } static int wpa_driver_test_set_ssid(void *priv, const u8 *ssid, size_t ssid_len) { wpa_printf(MSG_DEBUG, "%s", __func__); return 0; } static int wpa_driver_test_set_bssid(void *priv, const u8 *bssid) { wpa_printf(MSG_DEBUG, "%s: bssid=" MACSTR, __func__, MAC2STR(bssid)); return 0; } #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", wpa_driver_test_get_bssid, wpa_driver_test_get_ssid, wpa_driver_test_set_wpa, wpa_driver_test_set_key, NULL /* init */, wpa_driver_test_deinit, wpa_driver_test_set_param, NULL /* set_countermeasures */, NULL /* set_drop_unencrypted */, wpa_driver_test_scan, NULL /* get_scan_results */, wpa_driver_test_deauthenticate, wpa_driver_test_disassociate, wpa_driver_test_associate, NULL /* set_auth_alg */, NULL /* add_pmkid */, NULL /* remove_pmkid */, NULL /* flush_pmkid */, wpa_driver_test_get_capa, NULL /* poll */, NULL /* get_ifname */, wpa_driver_test_get_mac_addr, wpa_driver_test_send_eapol, NULL /* set_operstate */, wpa_driver_test_mlme_setprotection, #ifdef CONFIG_CLIENT_MLME wpa_driver_test_get_hw_feature_data, wpa_driver_test_set_channel, wpa_driver_test_set_ssid, wpa_driver_test_set_bssid, wpa_driver_test_send_mlme, wpa_driver_test_mlme_add_sta, wpa_driver_test_mlme_remove_sta, #else /* CONFIG_CLIENT_MLME */ NULL /* get_hw_feature_data */, NULL /* set_channel */, NULL /* set_ssid */, NULL /* set_bssid */, NULL /* send_mlme */, NULL /* mlme_add_sta */, NULL /* mlme_remove_sta */, #endif /* CONFIG_CLIENT_MLME */ NULL /* update_ft_ies */, NULL /* send_ft_action */, wpa_driver_test_get_scan_results2, 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 };