Add mock driver

Create mock driver that simulates hardware events to exercise the scan,
associate, disassociate code paths.

Change-Id: I7d6696b0df530d57ad7dd619a2256b2da78a9e31
diff --git a/src/drivers/driver_mock.c b/src/drivers/driver_mock.c
new file mode 100644
index 0000000..1f71583
--- /dev/null
+++ b/src/drivers/driver_mock.c
@@ -0,0 +1,184 @@
+/*
+ * 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,
+};
diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c
index a98af9a..4276588 100644
--- a/src/drivers/drivers.c
+++ b/src/drivers/drivers.c
@@ -9,30 +9,29 @@
 #include "utils/includes.h"
 #include "utils/common.h"
 #include "driver.h"
-
 #ifdef CONFIG_DRIVER_WEXT
 extern struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */
-#endif /* CONFIG_DRIVER_WEXT */
+#endif                                            /* CONFIG_DRIVER_WEXT */
 #ifdef CONFIG_DRIVER_NL80211
 extern struct wpa_driver_ops wpa_driver_nl80211_ops; /* driver_nl80211.c */
-#endif /* CONFIG_DRIVER_NL80211 */
+#endif                                               /* CONFIG_DRIVER_NL80211 */
 #ifdef CONFIG_DRIVER_HOSTAP
 extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */
-#endif /* CONFIG_DRIVER_HOSTAP */
+#endif                                              /* CONFIG_DRIVER_HOSTAP */
 #ifdef CONFIG_DRIVER_BSD
 extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
-#endif /* CONFIG_DRIVER_BSD */
+#endif                                           /* CONFIG_DRIVER_BSD */
 #ifdef CONFIG_DRIVER_OPENBSD
 extern struct wpa_driver_ops wpa_driver_openbsd_ops; /* driver_openbsd.c */
-#endif /* CONFIG_DRIVER_OPENBSD */
+#endif                                               /* CONFIG_DRIVER_OPENBSD */
 #ifdef CONFIG_DRIVER_NDIS
 extern struct wpa_driver_ops wpa_driver_ndis_ops; /* driver_ndis.c */
-#endif /* CONFIG_DRIVER_NDIS */
+#endif                                            /* CONFIG_DRIVER_NDIS */
 #ifdef CONFIG_DRIVER_WIRED
 extern struct wpa_driver_ops wpa_driver_wired_ops; /* driver_wired.c */
-#endif /* CONFIG_DRIVER_WIRED */
+#endif                                             /* CONFIG_DRIVER_WIRED */
 #ifdef CONFIG_DRIVER_MACSEC_QCA
- /* driver_macsec_qca.c */
+/* driver_macsec_qca.c */
 extern struct wpa_driver_ops wpa_driver_macsec_qca_ops;
 #endif /* CONFIG_DRIVER_MACSEC_QCA */
 #ifdef CONFIG_DRIVER_ROBOSWITCH
@@ -41,46 +40,49 @@
 #endif /* CONFIG_DRIVER_ROBOSWITCH */
 #ifdef CONFIG_DRIVER_ATHEROS
 extern struct wpa_driver_ops wpa_driver_atheros_ops; /* driver_atheros.c */
-#endif /* CONFIG_DRIVER_ATHEROS */
+#endif                                               /* CONFIG_DRIVER_ATHEROS */
 #ifdef CONFIG_DRIVER_NONE
 extern struct wpa_driver_ops wpa_driver_none_ops; /* driver_none.c */
-#endif /* CONFIG_DRIVER_NONE */
+#endif                                            /* CONFIG_DRIVER_NONE */
+#ifdef CONFIG_DRIVER_MOCK
+extern struct wpa_driver_ops wpa_driver_mock_ops; /* driver_mock.c */
+#endif                                            /* CONFIG_DRIVER_MOCK */
 
-
-const struct wpa_driver_ops *const wpa_drivers[] =
-{
+const struct wpa_driver_ops *const wpa_drivers[] = {
 #ifdef CONFIG_DRIVER_NL80211
-	&wpa_driver_nl80211_ops,
+    &wpa_driver_nl80211_ops,
 #endif /* CONFIG_DRIVER_NL80211 */
 #ifdef CONFIG_DRIVER_WEXT
-	&wpa_driver_wext_ops,
+    &wpa_driver_wext_ops,
 #endif /* CONFIG_DRIVER_WEXT */
 #ifdef CONFIG_DRIVER_HOSTAP
-	&wpa_driver_hostap_ops,
+    &wpa_driver_hostap_ops,
 #endif /* CONFIG_DRIVER_HOSTAP */
 #ifdef CONFIG_DRIVER_BSD
-	&wpa_driver_bsd_ops,
+    &wpa_driver_bsd_ops,
 #endif /* CONFIG_DRIVER_BSD */
 #ifdef CONFIG_DRIVER_OPENBSD
-	&wpa_driver_openbsd_ops,
+    &wpa_driver_openbsd_ops,
 #endif /* CONFIG_DRIVER_OPENBSD */
 #ifdef CONFIG_DRIVER_NDIS
-	&wpa_driver_ndis_ops,
+    &wpa_driver_ndis_ops,
 #endif /* CONFIG_DRIVER_NDIS */
 #ifdef CONFIG_DRIVER_WIRED
-	&wpa_driver_wired_ops,
+    &wpa_driver_wired_ops,
 #endif /* CONFIG_DRIVER_WIRED */
 #ifdef CONFIG_DRIVER_MACSEC_QCA
-	&wpa_driver_macsec_qca_ops,
+    &wpa_driver_macsec_qca_ops,
 #endif /* CONFIG_DRIVER_MACSEC_QCA */
 #ifdef CONFIG_DRIVER_ROBOSWITCH
-	&wpa_driver_roboswitch_ops,
+    &wpa_driver_roboswitch_ops,
 #endif /* CONFIG_DRIVER_ROBOSWITCH */
 #ifdef CONFIG_DRIVER_ATHEROS
-	&wpa_driver_atheros_ops,
+    &wpa_driver_atheros_ops,
 #endif /* CONFIG_DRIVER_ATHEROS */
 #ifdef CONFIG_DRIVER_NONE
-	&wpa_driver_none_ops,
+    &wpa_driver_none_ops,
 #endif /* CONFIG_DRIVER_NONE */
-	NULL
-};
+#ifdef CONFIG_DRIVER_MOCK
+    &wpa_driver_mock_ops,
+#endif /* CONFIG_DRIVER_MOCK */
+    NULL};
diff --git a/wpa_supplicant/BUILD.gn b/wpa_supplicant/BUILD.gn
index 1eb68e3..62fe29e 100644
--- a/wpa_supplicant/BUILD.gn
+++ b/wpa_supplicant/BUILD.gn
@@ -38,7 +38,7 @@
   defines = [
     "CONFIG_BACKEND_FILE",
     "CONFIG_CRYPTO_INTERNAL",
-    "CONFIG_DRIVER_NONE",
+    "CONFIG_DRIVER_MOCK",
     "CONFIG_NO_PBKDF2",
     "CONFIG_NO_CONFIG_BLOBS",
     "CONFIG_NO_SCAN_PROCESSING",
@@ -64,7 +64,7 @@
     "../src/crypto/sha256-tlsprf.c",
     "../src/crypto/tls_none.c",
     "../src/drivers/driver_common.c",
-    "../src/drivers/driver_none.c",
+    "../src/drivers/driver_mock.c",
     "../src/drivers/drivers.c",
     "../src/l2_packet/l2_packet_none.c",
     "../src/utils/common.c",
diff --git a/wpa_supplicant/main_fuchsia.c b/wpa_supplicant/main_fuchsia.c
index 884e336..16a2a51 100644
--- a/wpa_supplicant/main_fuchsia.c
+++ b/wpa_supplicant/main_fuchsia.c
@@ -9,6 +9,7 @@
 #include "includes.h"
 
 #include "common.h"
+#include "config.h"
 #include "wpa_supplicant_i.h"
 
 int main(int argc, char *argv[]) {
@@ -18,17 +19,27 @@
   struct wpa_global *global;
 
   memset(&params, 0, sizeof(params));
-  params.wpa_debug_level = MSG_DEBUG;
+  params.wpa_debug_level = MSG_EXCESSIVE;
 
   global = wpa_supplicant_init(&params);
   if (global == NULL) return -1;
 
   memset(&iface, 0, sizeof(iface));
-  iface.ifname = "none";
+  iface.ifname = "mock";
   iface.ctrl_interface = "";
 
   if (wpa_supplicant_add_iface(global, &iface, NULL) == NULL) exitcode = -1;
 
+  if (exitcode == 0) {
+    struct wpa_supplicant *supplicant = global->ifaces;
+    struct wpa_ssid *ssid = wpa_config_add_network(supplicant->conf);
+    wpa_config_set_network_defaults(ssid);
+    wpa_config_set_quoted(ssid, "ssid", "MockAp");
+    wpa_config_set(ssid, "key_mgmt", "NONE", 0);
+  }
+
+  // TODO(alangardner): Create option to terminate
+
   if (exitcode == 0) exitcode = wpa_supplicant_run(global);
 
   wpa_supplicant_deinit(global);