diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 9037c2004..67d0181d3 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -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 */ diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c index 34710ef18..20425bbd4 100644 --- a/src/drivers/driver_ndis.c +++ b/src/drivers/driver_ndis.c @@ -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 */ }; diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c index 9c98ed304..8aa05aab7 100644 --- a/src/drivers/driver_privsep.c +++ b/src/drivers/driver_privsep.c @@ -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 */ }; diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c index feeb8a280..b055b27b6 100644 --- a/src/drivers/driver_test.c +++ b/src/drivers/driver_test.c @@ -35,7 +35,12 @@ #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 }; diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 6701f84d3..9813a47a3 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -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) { diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 3232198f1..dcfa59b9c 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -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); }