Parcourir la source

Added support for global driver data (shared by multiple interfaces)

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.
Jouni Malinen il y a 16 ans
Parent
commit
ac305589a3

+ 35 - 0
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 */

+ 4 - 1
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 */
 };

+ 4 - 1
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 */
 };
 
 

+ 29 - 3
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
 };

+ 34 - 1
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) {

+ 4 - 0
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);
 	}