Added support for global driver data (shared by multiple interfaces)
authorJouni Malinen <j@w1.fi>
Mon, 22 Dec 2008 20:24:31 +0000 (22:24 +0200)
committerJouni Malinen <j@w1.fi>
Mon, 22 Dec 2008 20:24:31 +0000 (22:24 +0200)
Driver wrappers can now register global_init() and global_deinit()
driver_ops handlers to get a global data structure that can be shared
for all interfaces. This allows driver wrappers to initialize some
functionality (e.g., interface monitoring) before any interfaces have
been initialized.

src/drivers/driver.h
src/drivers/driver_ndis.c
src/drivers/driver_privsep.c
src/drivers/driver_test.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant_i.h

index 9037c20..67d0181 100644 (file)
@@ -956,6 +956,41 @@ struct wpa_driver_ops {
         * of setting a regulatory domain.
         */
        int (*set_country)(void *priv, const char *alpha2);
+
+       /**
+        * global_init - Global driver initialization
+        * Returns: Pointer to private data (global), %NULL on failure
+        *
+        * This optional function is called to initialize the driver wrapper
+        * for global data, i.e., data that applies to all interfaces. If this
+        * function is implemented, global_deinit() will also need to be
+        * implemented to free the private data. The driver will also likely
+        * use init2() function instead of init() to get the pointer to global
+        * data available to per-interface initializer.
+        */
+       void * (*global_init)(void);
+
+       /**
+        * global_deinit - Global driver deinitialization
+        * @priv: private driver global data from global_init()
+        *
+        * Terminate any global driver related functionality and free the
+        * global data structure.
+        */
+       void (*global_deinit)(void *priv);
+
+       /**
+        * init2 - Initialize driver interface (with global data)
+        * @ctx: context to be used when calling wpa_supplicant functions,
+        * e.g., wpa_supplicant_event()
+        * @ifname: interface name, e.g., wlan0
+        * @global_priv: private driver global data from global_init()
+        * Returns: Pointer to private data, %NULL on failure
+        *
+        * This function can be used instead of init() if the driver wrapper
+        * uses global data.
+        */
+       void * (*init2)(void *ctx, const char *ifname, void *global_priv);
 };
 
 /* Function to check whether a driver is for wired connections */
index 34710ef..20425bb 100644 (file)
@@ -2884,5 +2884,8 @@ const struct wpa_driver_ops wpa_driver_ndis_ops = {
        wpa_driver_ndis_get_scan_results,
        NULL /* set_probe_req_ie */,
        NULL /* set_mode */,
-       NULL /* set_country */
+       NULL /* set_country */,
+       NULL /* global_init */,
+       NULL /* global_deinit */,
+       NULL /* init2 */
 };
index 9c98ed3..8aa05aa 100644 (file)
@@ -775,7 +775,10 @@ struct wpa_driver_ops wpa_driver_privsep_ops = {
        wpa_driver_privsep_get_scan_results2,
        NULL /* set_probe_req_ie */,
        wpa_driver_privsep_set_mode,
-       NULL /* set_country */
+       NULL /* set_country */,
+       NULL /* global_init */,
+       NULL /* global_deinit */,
+       NULL /* init2 */
 };
 
 
index feeb8a2..b055b27 100644 (file)
 #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;
@@ -579,13 +584,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;
 
@@ -1122,6 +1129,22 @@ int wpa_driver_set_probe_req_ie(void *priv, const u8 *ies, size_t ies_len)
 }
 
 
+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);
+}
+
+
 const struct wpa_driver_ops wpa_driver_test_ops = {
        "test",
        "wpa_supplicant test driver",
@@ -1129,7 +1152,7 @@ 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 */,
@@ -1172,5 +1195,8 @@ const struct wpa_driver_ops wpa_driver_test_ops = {
        wpa_driver_test_get_scan_results2,
        wpa_driver_set_probe_req_ie,
        NULL /* set_mode */,
-       NULL /* set_country */
+       NULL /* set_country */,
+       wpa_driver_test_global_init,
+       wpa_driver_test_global_deinit,
+       wpa_driver_test_init2
 };
index 6701f84..9813a47 100644 (file)
@@ -1999,7 +1999,7 @@ struct wpa_supplicant * wpa_supplicant_get_iface(struct wpa_global *global,
 struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
 {
        struct wpa_global *global;
-       int ret;
+       int ret, i;
 
        if (params == NULL)
                return NULL;
@@ -2054,6 +2054,30 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
                }
        }
 
+       for (i = 0; wpa_supplicant_drivers[i]; i++)
+               global->drv_count++;
+       if (global->drv_count == 0) {
+               wpa_printf(MSG_ERROR, "No drivers enabled");
+               wpa_supplicant_deinit(global);
+               return NULL;
+       }
+       global->drv_priv = os_zalloc(global->drv_count * sizeof(void *));
+       if (global->drv_priv == NULL) {
+               wpa_supplicant_deinit(global);
+               return NULL;
+       }
+       for (i = 0; wpa_supplicant_drivers[i]; i++) {
+               if (!wpa_supplicant_drivers[i]->global_init)
+                       continue;
+               global->drv_priv[i] = wpa_supplicant_drivers[i]->global_init();
+               if (global->drv_priv[i] == NULL) {
+                       wpa_printf(MSG_ERROR, "Failed to initialize driver "
+                                  "'%s'", wpa_supplicant_drivers[i]->name);
+                       wpa_supplicant_deinit(global);
+                       return NULL;
+               }
+       }
+
        return global;
 }
 
@@ -2100,6 +2124,8 @@ int wpa_supplicant_run(struct wpa_global *global)
  */
 void wpa_supplicant_deinit(struct wpa_global *global)
 {
+       int i;
+
        if (global == NULL)
                return;
 
@@ -2113,6 +2139,13 @@ void wpa_supplicant_deinit(struct wpa_global *global)
 
        eap_peer_unregister_methods();
 
+       for (i = 0; wpa_supplicant_drivers[i]; i++) {
+               if (!global->drv_priv[i])
+                       continue;
+               wpa_supplicant_drivers[i]->global_deinit(global->drv_priv[i]);
+       }
+       os_free(global->drv_priv);
+
        eloop_destroy();
 
        if (global->params.pid_file) {
index 3232198..dcfa59b 100644 (file)
@@ -156,6 +156,8 @@ struct wpa_global {
        struct wpa_params params;
        struct ctrl_iface_global_priv *ctrl_iface;
        struct ctrl_iface_dbus_priv *dbus_ctrl_iface;
+       void **drv_priv;
+       size_t drv_count;
 };
 
 
@@ -396,6 +398,8 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s);
 static inline void * wpa_drv_init(struct wpa_supplicant *wpa_s,
                                  const char *ifname)
 {
+       if (wpa_s->driver->init2)
+               return wpa_s->driver->init2(wpa_s, ifname, wpa_s->global);
        if (wpa_s->driver->init) {
                return wpa_s->driver->init(wpa_s, ifname);
        }