blob: 1f71583ed6e08d1f1ed5473e88fc1e2891b64cc4 [file] [log] [blame]
/*
* A mock driver used for exercising wpa_supplicant code.
*
* Copyright (c) 2016 The Fuchsia Authors
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*
*/
#include "includes.h"
#include <stdbool.h>
#include "common.h"
#include "driver.h"
#include "eloop.h"
#include "os.h"
static const u8 MOCK_BSSID[ETH_ALEN] = {0, 1, 2, 3, 4, 5};
static const u8 MOCK_SSID[6] = {'M', 'o', 'c', 'k', 'A', 'p'};
// TODO(alangardner): queue wpa_supplicant_event calls on eloop
struct mock_driver_data {
void *ctx;
struct wpa_driver_capa capa;
struct wpa_scan_results *scan_results;
bool associated;
};
static int mock_driver_send_ether(void *priv, const u8 *dst, const u8 *src,
u16 proto, const u8 *data, size_t data_len) {
return 0;
}
static void mock_driver_enabled(void *eloop_data, void *user_ctx) {
struct mock_driver_data *drv = eloop_data;
wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL);
wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL);
}
static void mock_driver_scan_completed(void *eloop_data, void *user_ctx) {
struct mock_driver_data *drv = eloop_data;
wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL);
}
static void mock_driver_disassociated(void *eloop_data, void *user_ctx) {
struct mock_driver_data *drv = eloop_data;
drv->associated = false;
wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
}
static void mock_driver_associated(void *eloop_data, void *user_ctx) {
struct mock_driver_data *drv = eloop_data;
drv->associated = true;
wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
eloop_register_timeout(5, 0, mock_driver_disassociated, drv, NULL);
}
static void mock_driver_capa(struct mock_driver_data *drv) {
drv->capa.key_mgmt =
WPA_DRIVER_CAPA_KEY_MGMT_WPA | WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 |
WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP;
drv->capa.flags |= WPA_DRIVER_FLAGS_AP;
drv->capa.max_scan_ssids = 1;
drv->capa.auth =
WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED | WPA_DRIVER_AUTH_LEAP;
}
static void mock_scan_results(struct mock_driver_data *drv) {
int ssid_len = sizeof(MOCK_SSID) / sizeof(*MOCK_SSID);
int bssid_len = sizeof(MOCK_BSSID) / sizeof(*MOCK_BSSID);
int ie_len = 2 + ssid_len;
struct wpa_scan_res *result = os_zalloc(sizeof(struct wpa_scan_res));
result->flags = 0;
os_memcpy(&result->bssid, MOCK_BSSID, bssid_len);
result->freq = 2412; // Channel 1
result->beacon_int = 100;
result->caps = 0;
result->qual = 0;
result->noise = 0;
result->level = 0;
// Note: 'tsf' and 'age' will get updated when scan is called
result->est_throughput = 0;
result->snr = 0;
result->ie_len = ie_len;
result->beacon_ie_len = 0;
u8 *pos = (u8 *)(result + 1);
*pos++ = WLAN_EID_SSID;
*pos++ = ssid_len;
os_memcpy(pos, MOCK_SSID, ssid_len);
pos += ssid_len;
drv->scan_results = os_zalloc(sizeof(struct wpa_scan_results));
drv->scan_results->num = 1;
drv->scan_results->res = os_calloc(1, sizeof(struct wpa_scan_res *));
drv->scan_results->res[0] = result;
}
static void *mock_driver_init(void *ctx, const char *ifname) {
wpa_printf(MSG_DEBUG, "MOCK INIT");
struct mock_driver_data *drv = os_zalloc(sizeof(struct mock_driver_data));
if (drv == NULL) {
wpa_printf(MSG_ERROR, "Could not allocate memory for mock driver data");
return NULL;
}
drv->ctx = ctx;
mock_driver_capa(drv);
mock_scan_results(drv);
drv->associated = false;
eloop_register_timeout(0, 0, mock_driver_enabled, drv, NULL);
return drv;
}
static void mock_driver_deinit(void *priv) {
struct mock_driver_data *drv = priv;
wpa_scan_results_free(drv->scan_results);
os_free(drv);
}
static int mock_driver_get_capa(void *priv, struct wpa_driver_capa *capa) {
wpa_printf(MSG_DEBUG, "MOCK GET CAPA");
struct mock_driver_data *drv = priv;
os_memcpy(capa, &drv->capa, sizeof(*capa));
return 0;
}
static int mock_driver_scan(void *priv, struct wpa_driver_scan_params *params) {
wpa_printf(MSG_DEBUG, "MOCK SCAN");
struct mock_driver_data *drv = priv;
eloop_register_timeout(0, 0, mock_driver_scan_completed, drv, NULL);
return 0;
}
static struct wpa_scan_results *mock_driver_get_scan_results(void *priv) {
wpa_printf(MSG_DEBUG, "MOCK GET SCAN RESULTS");
struct mock_driver_data *drv = priv;
return drv->scan_results;
}
static int mock_driver_associate(void *priv,
struct wpa_driver_associate_params *params) {
struct mock_driver_data *drv = priv;
eloop_register_timeout(0, 0, mock_driver_associated, drv, NULL);
return 0;
}
static int mock_driver_get_bssid(void *priv, u8 *bssid) {
struct mock_driver_data *drv = priv;
if (drv->associated) {
os_memcpy(bssid, &MOCK_BSSID, ETH_ALEN);
} else {
os_memset(bssid, 0, ETH_ALEN);
}
return 0;
}
static int mock_driver_get_ssid(void *priv, u8 *ssid) {
struct mock_driver_data *drv = priv;
if (drv->associated) {
os_memcpy(ssid, &MOCK_SSID, sizeof(MOCK_SSID));
return sizeof(MOCK_SSID);
} else {
return 0;
}
}
const struct wpa_driver_ops wpa_driver_mock_ops = {
.name = "mock",
.desc = "simulates a working driver for testing",
.send_ether = mock_driver_send_ether,
.init = mock_driver_init,
.deinit = mock_driver_deinit,
.get_capa = mock_driver_get_capa,
.scan2 = mock_driver_scan,
.get_scan_results2 = mock_driver_get_scan_results,
.associate = mock_driver_associate,
.get_bssid = mock_driver_get_bssid,
.get_ssid = mock_driver_get_ssid,
};