[PATCH] Find correct driver for interface additions/removals

Roy Marples roy at marples.name
Tue Mar 15 06:02:08 PDT 2016


Hi Jouni

On 13/03/2016 19:09, Jouni Malinen wrote:
> On Sun, Mar 13, 2016 at 05:31:39PM +0000, Roy Marples wrote:
>> On Sunday 06 March 2016 22:27:21 Jouni Malinen wrote:
>>> This seems to break one of the hwsim test cases (autogo_ifdown) since
> 
>> That should not be the case.
>> I have re-configured my Linux system so that the majority of the tests pass, 
>> however it takes an awful long time to run them all.
>> Is there a way to run a specific test by itself relatively easily so I can work 
>> on this more easily?
> 
> If you are using the VM option:
> 
> ./vm-run.sh autogo_ifdown
> 
> and on the host without VM:
> 
> sudo ./run-tests.py autogo_ifdown

Thanks!

I used the latter case. For reference, I had to wrap the test between
start and stop calls as well (incase anyone else asks) like so:

sudo ./start.sh
sudo ./run-tests.py autogo_ifdown
sudo ./stop.sh

To pass the test case, the easiest solution is to add ifindex to the
returned data, add a function call to the driver to return the ifindex
and ensure they match (if the driver does infact have the function).

I ran the test 20 times, and it passed each time.
Hopefully you can apply the attaced patch now :)
I will re-submit my interface matching patch shortly as it now needs
re-factoring slightly.

Roy
-------------- next part --------------
commit 1cf54797b0c5c1f79f4efeeb640f7ebbd7576b94
Author: Roy Marples <roy at marples.name>
Date:   Tue Mar 15 12:50:02 2016 +0000

    Interface additions/removals are not guaranteed to be for the
    driver listening to the kernel events.
    As such, send the events to wpa_supplicant_event_global()
    which can then pick the correct interface registered with
    wpa_supplicant to send the event to.
    
    Signed-off-by: Roy Marples <roy at marples.name>

diff --git a/hostapd/main.c b/hostapd/main.c
index 25dc20b..1d9e63e 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -171,7 +171,8 @@ static int hostapd_driver_init(struct hostapd_iface *iface)
 
 		if (global.drv_priv[i] == NULL &&
 		    wpa_drivers[i]->global_init) {
-			global.drv_priv[i] = wpa_drivers[i]->global_init();
+			global.drv_priv[i] =
+				wpa_drivers[i]->global_init(iface->interfaces);
 			if (global.drv_priv[i] == NULL) {
 				wpa_printf(MSG_ERROR, "Failed to initialize "
 					   "driver '%s'",
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index f54d1ad..69eebcf 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -1353,4 +1353,29 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 	}
 }
 
+
+void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
+				 union wpa_event_data *data)
+{
+	struct hapd_interfaces *interfaces = ctx;
+	struct hostapd_data *hapd;
+
+	if (event != EVENT_INTERFACE_STATUS)
+		return;
+
+	hapd = hostapd_get_iface(interfaces, data->interface_status.ifname);
+	if (hapd != NULL && hapd->driver->get_ifindex != NULL) {
+		unsigned int ifindex;
+
+		ifindex = hapd->driver->get_ifindex(hapd->drv_priv);
+		if (ifindex != data->interface_status.ifindex) {
+			wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+				"interface status ifindex %d mis-match (%d)",
+				ifindex, data->interface_status.ifindex);
+			return;
+		}
+	}
+	if (hapd != NULL)
+		wpa_supplicant_event(hapd, event, data);
+}
 #endif /* HOSTAPD */
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 55ca9e8..ee80f4f 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -3090,6 +3090,8 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
 	hostapd_enable_iface(iface);
 }
 
+#endif /* NEED_AP_MLME */
+
 
 struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,
 					const char *ifname)
@@ -3110,8 +3112,6 @@ struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,
 	return NULL;
 }
 
-#endif /* NEED_AP_MLME */
-
 
 void hostapd_periodic_iface(struct hostapd_iface *iface)
 {
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 642276c..d59e099 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1958,6 +1958,14 @@ struct wpa_driver_ops {
 	void (*poll)(void *priv);
 
 	/**
+	 * get_ifindex - Get interface index
+	 * @priv: private driver interface data
+	 *
+	 * Returns: Pointer to the interface index.
+	 */
+	unsigned int (*get_ifindex)(void *priv);
+
+	/**
 	 * get_ifname - Get interface name
 	 * @priv: private driver interface data
 	 *
@@ -2091,6 +2099,7 @@ struct wpa_driver_ops {
 
 	/**
 	 * global_init - Global driver initialization
+	 * @ctx: wpa_global pointer
 	 * Returns: Pointer to private data (global), %NULL on failure
 	 *
 	 * This optional function is called to initialize the driver wrapper
@@ -2100,7 +2109,7 @@ struct wpa_driver_ops {
 	 * use init2() function instead of init() to get the pointer to global
 	 * data available to per-interface initializer.
 	 */
-	void * (*global_init)(void);
+	void * (*global_init)(void *ctx);
 
 	/**
 	 * global_deinit - Global driver deinitialization
@@ -4269,6 +4278,7 @@ union wpa_event_data {
 	 * struct interface_status - Data for EVENT_INTERFACE_STATUS
 	 */
 	struct interface_status {
+		unsigned int ifindex;
 		char ifname[100];
 		enum {
 			EVENT_INTERFACE_ADDED, EVENT_INTERFACE_REMOVED
@@ -4745,6 +4755,17 @@ union wpa_event_data {
 void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 			  union wpa_event_data *data);
 
+/**
+ * wpa_supplicant_event_global - Report a driver event for wpa_supplicant
+ * @ctx: Context pointer (wpa_s); this is the ctx variable registered
+ *	with struct wpa_driver_ops::init()
+ * @event: event type (defined above)
+ * @data: possible extra data for the event
+ *
+ * Same as wpa_supplicant_event, but we search for the interface in wpa_global.
+ */
+void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
+				 union wpa_event_data *data);
 
 /*
  * The following inline functions are provided for convenience to simplify
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index a6ca9a8..6802de3 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -48,6 +48,7 @@
 #include "l2_packet/l2_packet.h"
 
 struct bsd_driver_global {
+	void		*ctx;
 	int		sock;			/* socket for 802.11 ioctls */
 	int		route;			/* routing socket for events */
 	char		*event_buf;
@@ -64,6 +65,7 @@ struct bsd_driver_data {
 	char	ifname[IFNAMSIZ+1];	/* interface name */
 	int	flags;
 	unsigned int ifindex;		/* interface index */
+	int	if_removed;		/* has the interface been removed? */
 	void	*ctx;
 	struct wpa_driver_capa capa;	/* driver capability */
 	int	is_ap;			/* Access point mode */
@@ -88,13 +90,28 @@ bsd_get_drvindex(void *priv, unsigned int ifindex)
 	return NULL;
 }
 
+#ifndef HOSTAPD
+static struct bsd_driver_data *
+bsd_get_drvname(void *priv, const char *ifname)
+{
+	struct bsd_driver_global *global = priv;
+	struct bsd_driver_data *drv;
+
+	dl_list_for_each(drv, &global->ifaces, struct bsd_driver_data, list) {
+		if (os_strcmp(drv->ifname, ifname) == 0)
+			return drv;
+	}
+	return NULL;
+}
+#endif
+
 static int
 bsd_set80211(void *priv, int op, int val, const void *arg, int arg_len)
 {
 	struct bsd_driver_data *drv = priv;
 	struct ieee80211req ireq;
 
-	if (drv->ifindex == 0)
+	if (drv->ifindex == 0 || drv->if_removed)
 		return -1;
 
 	os_memset(&ireq, 0, sizeof(ireq));
@@ -1222,24 +1239,43 @@ wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
 	switch (rtm->rtm_type) {
 	case RTM_IFANNOUNCE:
 		ifan = (struct if_announcemsghdr *) rtm;
-		drv = bsd_get_drvindex(global, ifan->ifan_index);
-		if (drv == NULL)
-			return;
-		os_strlcpy(event.interface_status.ifname, drv->ifname,
-			   sizeof(event.interface_status.ifname));
 		switch (ifan->ifan_what) {
 		case IFAN_DEPARTURE:
+			drv = bsd_get_drvindex(global, ifan->ifan_index);
+			if (drv != NULL)
+				drv->if_removed = 1;
 			event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
-			drv->ifindex = 0;
+			break;
+		case IFAN_ARRIVAL:
+			drv = bsd_get_drvname(global, ifan->ifan_name);
+			if (drv != NULL) {
+				drv->ifindex = ifan->ifan_index;
+				drv->if_removed = 0;
+			}
+			event.interface_status.ievent = EVENT_INTERFACE_ADDED;
 			break;
 		default:
+			wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: unknown action");
 			return;
 		}
 		wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s",
-			   event.interface_status.ifname,
+			   ifan->ifan_name,
 			   ifan->ifan_what == IFAN_DEPARTURE ?
 				"removed" : "added");
-		wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
+		os_strlcpy(event.interface_status.ifname, ifan->ifan_name,
+			   sizeof(event.interface_status.ifname));
+		if (drv) {
+			wpa_supplicant_event(drv->ctx,
+					     EVENT_INTERFACE_STATUS,
+					     &event);
+			/* Set ifindex to zero after sending the event as the
+			 * event might query the driver to ensure a match. */
+			if (ifan->ifan_what == IFAN_DEPARTURE)
+				drv->ifindex = 0;
+		} else
+			wpa_supplicant_event_global(global->ctx,
+						    EVENT_INTERFACE_STATUS,
+						    &event);
 		break;
 	case RTM_IEEE80211:
 		ifan = (struct if_announcemsghdr *) rtm;
@@ -1582,7 +1618,7 @@ wpa_driver_bsd_deinit(void *priv)
 {
 	struct bsd_driver_data *drv = priv;
 
-	if (drv->ifindex != 0) {
+	if (drv->ifindex != 0 && !drv->if_removed) {
 		wpa_driver_bsd_set_wpa(drv, 0);
 
 		/* NB: mark interface down */
@@ -1615,7 +1651,7 @@ wpa_driver_bsd_get_capa(void *priv, struct wpa_driver_capa *capa)
 #endif /* HOSTAPD */
 
 static void *
-bsd_global_init(void)
+bsd_global_init(void *ctx)
 {
 	struct bsd_driver_global *global;
 
@@ -1623,6 +1659,7 @@ bsd_global_init(void)
 	if (global == NULL)
 		return NULL;
 
+	global->ctx = ctx;
 	dl_list_init(&global->ifaces);
 
 	global->sock = socket(PF_INET, SOCK_DGRAM, 0);
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 5fb6652..656b497 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -763,6 +763,15 @@ static void nl80211_put_wiphy_data_ap(struct i802_bss *bss)
 }
 
 
+static unsigned int wpa_driver_nl80211_get_ifindex(void *priv)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+
+	return (unsigned int)drv->ifindex;
+}
+
+
 static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
 {
 	struct i802_bss *bss = priv;
@@ -786,11 +795,12 @@ static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
 
 
 static void wpa_driver_nl80211_event_newlink(
-	struct wpa_driver_nl80211_data *drv, const char *ifname)
+	struct nl80211_global *global,
+	struct wpa_driver_nl80211_data *drv, int ifindex, const char *ifname)
 {
 	union wpa_event_data event;
 
-	if (os_strcmp(drv->first_bss->ifname, ifname) == 0) {
+	if (drv && os_strcmp(drv->first_bss->ifname, ifname) == 0) {
 		if (if_nametoindex(drv->first_bss->ifname) == 0) {
 			wpa_printf(MSG_DEBUG, "nl80211: Interface %s does not exist - ignore RTM_NEWLINK",
 				   drv->first_bss->ifname);
@@ -804,19 +814,26 @@ static void wpa_driver_nl80211_event_newlink(
 	}
 
 	os_memset(&event, 0, sizeof(event));
+	event.interface_status.ifindex = (unsigned int)ifindex;
 	os_strlcpy(event.interface_status.ifname, ifname,
 		   sizeof(event.interface_status.ifname));
 	event.interface_status.ievent = EVENT_INTERFACE_ADDED;
-	wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
+	if (drv)
+		wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS,
+				     &event);
+	else
+		wpa_supplicant_event_global(global->ctx, EVENT_INTERFACE_STATUS,
+					    &event);
 }
 
 
 static void wpa_driver_nl80211_event_dellink(
-	struct wpa_driver_nl80211_data *drv, const char *ifname)
+	struct nl80211_global *global,
+	struct wpa_driver_nl80211_data *drv, int ifindex, const char *ifname)
 {
 	union wpa_event_data event;
 
-	if (os_strcmp(drv->first_bss->ifname, ifname) == 0) {
+	if (drv && os_strcmp(drv->first_bss->ifname, ifname) == 0) {
 		if (drv->if_removed) {
 			wpa_printf(MSG_DEBUG, "nl80211: if_removed already set - ignore RTM_DELLINK event for %s",
 				   ifname);
@@ -831,10 +848,16 @@ static void wpa_driver_nl80211_event_dellink(
 	}
 
 	os_memset(&event, 0, sizeof(event));
+	event.interface_status.ifindex = (unsigned int)ifindex;
 	os_strlcpy(event.interface_status.ifname, ifname,
 		   sizeof(event.interface_status.ifname));
 	event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
-	wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
+	if (drv)
+		wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS,
+				     &event);
+	else
+		wpa_supplicant_event_global(global->ctx, EVENT_INTERFACE_STATUS,
+					    &event);
 }
 
 
@@ -894,7 +917,6 @@ nl80211_find_drv(struct nl80211_global *global, int idx, u8 *buf, size_t len)
 	return NULL;
 }
 
-
 static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
 						 struct ifinfomsg *ifi,
 						 u8 *buf, size_t len)
@@ -908,12 +930,6 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
 	char ifname[IFNAMSIZ + 1];
 	char extra[100], *pos, *end;
 
-	drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
-	if (!drv) {
-		wpa_printf(MSG_DEBUG, "nl80211: Ignore RTM_NEWLINK event for foreign ifindex %d",
-			   ifi->ifi_index);
-		return;
-	}
 
 	extra[0] = '\0';
 	pos = extra;
@@ -958,6 +974,10 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
 		   (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
 		   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
 
+	drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
+	if (drv == NULL)
+		goto event_newlink;
+
 	if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
 		namebuf[0] = '\0';
 		if (if_indextoname(ifi->ifi_index, namebuf) &&
@@ -1052,10 +1072,12 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
 				       -1, IF_OPER_UP);
 	}
 
+event_newlink:
 	if (ifname[0])
-		wpa_driver_nl80211_event_newlink(drv, ifname);
+		wpa_driver_nl80211_event_newlink(global, drv,
+						 ifi->ifi_index, ifname);
 
-	if (ifi->ifi_family == AF_BRIDGE && brid) {
+	if (ifi->ifi_family == AF_BRIDGE && brid && drv) {
 		struct i802_bss *bss;
 
 		/* device has been added to bridge */
@@ -1091,13 +1113,6 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
 	char ifname[IFNAMSIZ + 1];
 	char extra[100], *pos, *end;
 
-	drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
-	if (!drv) {
-		wpa_printf(MSG_DEBUG, "nl80211: Ignore RTM_DELLINK event for foreign ifindex %d",
-			   ifi->ifi_index);
-		return;
-	}
-
 	extra[0] = '\0';
 	pos = extra;
 	end = pos + sizeof(extra);
@@ -1138,10 +1153,9 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
 		   (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
 		   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
 
-	if (ifname[0] && (ifi->ifi_family != AF_BRIDGE || !brid))
-		wpa_driver_nl80211_event_dellink(drv, ifname);
+	drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
 
-	if (ifi->ifi_family == AF_BRIDGE && brid) {
+	if (ifi->ifi_family == AF_BRIDGE && brid && drv) {
 		/* device has been removed from bridge */
 		char namebuf[IFNAMSIZ];
 
@@ -1156,6 +1170,10 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
 		}
 		del_ifidx(drv, brid, ifi->ifi_index);
 	}
+
+	if (ifi->ifi_family != AF_BRIDGE || !brid)
+		wpa_driver_nl80211_event_dellink(global, drv,
+						 ifi->ifi_index, ifname);
 }
 
 
@@ -6856,7 +6874,7 @@ static int nl80211_set_param(void *priv, const char *param)
 }
 
 
-static void * nl80211_global_init(void)
+static void * nl80211_global_init(void *ctx)
 {
 	struct nl80211_global *global;
 	struct netlink_config *cfg;
@@ -6864,6 +6882,7 @@ static void * nl80211_global_init(void)
 	global = os_zalloc(sizeof(*global));
 	if (global == NULL)
 		return NULL;
+	global->ctx = ctx;
 	global->ioctl_sock = -1;
 	dl_list_init(&global->interfaces);
 	global->if_add_ifindex = -1;
@@ -9035,6 +9054,7 @@ static int nl80211_set_prob_oper_freq(void *priv, unsigned int freq)
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.name = "nl80211",
 	.desc = "Linux nl80211/cfg80211",
+	.get_ifindex = wpa_driver_nl80211_get_ifindex,
 	.get_bssid = wpa_driver_nl80211_get_bssid,
 	.get_ssid = wpa_driver_nl80211_get_ssid,
 	.set_key = driver_nl80211_set_key,
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 430369f..3f65569 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -25,6 +25,7 @@
 #endif /* CONFIG_LIBNL20 */
 
 struct nl80211_global {
+	void *ctx;
 	struct dl_list interfaces;
 	int if_add_ifindex;
 	u64 if_add_wdevid;
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index ac3c118..f4cdfba 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -4006,3 +4006,30 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 		break;
 	}
 }
+
+
+void
+wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
+			    union wpa_event_data *data)
+{
+	struct wpa_supplicant *wpa_s;
+
+	if (event != EVENT_INTERFACE_STATUS)
+		return;
+
+	wpa_s = wpa_supplicant_get_iface(ctx, data->interface_status.ifname);
+	if (wpa_s != NULL && wpa_s->driver->get_ifindex != NULL) {
+		unsigned int ifindex;
+
+		ifindex = wpa_s->driver->get_ifindex(wpa_s->drv_priv);
+		if (ifindex != data->interface_status.ifindex) {
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"interface status ifindex %d mis-match (%d)",
+				ifindex, data->interface_status.ifindex);
+			return;
+		}
+	}
+
+	if (wpa_s != NULL)
+		wpa_supplicant_event(wpa_s, event, data);
+}
diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
index 3f91cc1..4e720ba 100644
--- a/wpa_supplicant/wpa_priv.c
+++ b/wpa_supplicant/wpa_priv.c
@@ -29,6 +29,8 @@ struct wpa_priv_interface {
 	char *sock_name;
 	int fd;
 
+	void *ctx;
+
 	const struct wpa_driver_ops *driver;
 	void *drv_priv;
 	void *drv_global_priv;
@@ -40,6 +42,9 @@ struct wpa_priv_interface {
 	struct sockaddr_un l2_addr;
 };
 
+struct wpa_priv_global {
+	struct wpa_priv_interface *interfaces;
+};
 
 static void wpa_priv_cmd_register(struct wpa_priv_interface *iface,
 				  struct sockaddr_un *from)
@@ -65,7 +70,7 @@ static void wpa_priv_cmd_register(struct wpa_priv_interface *iface,
 
 	if (iface->driver->init2) {
 		if (iface->driver->global_init) {
-			iface->drv_global_priv = iface->driver->global_init();
+			iface->drv_global_priv = iface->driver->global_init(iface->ctx);
 			if (!iface->drv_global_priv) {
 				wpa_printf(MSG_INFO,
 					   "Failed to initialize driver global context");
@@ -638,7 +643,7 @@ static void wpa_priv_interface_deinit(struct wpa_priv_interface *iface)
 
 
 static struct wpa_priv_interface *
-wpa_priv_interface_init(const char *dir, const char *params)
+wpa_priv_interface_init(void *ctx, const char *dir, const char *params)
 {
 	struct wpa_priv_interface *iface;
 	char *pos;
@@ -654,6 +659,7 @@ wpa_priv_interface_init(const char *dir, const char *params)
 	if (iface == NULL)
 		return NULL;
 	iface->fd = -1;
+	iface->ctx = ctx;
 
 	len = pos - params;
 	iface->driver_name = dup_binstr(params, len);
@@ -1002,6 +1008,36 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 }
 
 
+void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
+				 union wpa_event_data *data)
+{
+	struct wpa_priv_global *global = ctx;
+	struct wpa_priv_interface *iface;
+
+	if (event != EVENT_INTERFACE_STATUS)
+		return;
+
+	for (iface = global->interfaces; iface; iface = iface->next) {
+		if (os_strcmp(iface->ifname, data->interface_status.ifname) == 0)
+			break;
+	}
+	if (iface != NULL && iface->driver->get_ifindex != NULL) {
+		unsigned int ifindex;
+
+		ifindex = iface->driver->get_ifindex(iface->drv_priv);
+		if (ifindex != data->interface_status.ifindex) {
+			wpa_printf(MSG_DEBUG,
+				"%s: interface status ifindex %d mis-match (%d)",
+				iface->ifname,
+				ifindex, data->interface_status.ifindex);
+			return;
+		}
+	}
+	if (iface != NULL)
+		wpa_supplicant_event(iface, event, data);
+}
+
+
 void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
 			     const u8 *buf, size_t len)
 {
@@ -1077,13 +1113,17 @@ int main(int argc, char *argv[])
 	char *pid_file = NULL;
 	int daemonize = 0;
 	char *ctrl_dir = "/var/run/wpa_priv";
-	struct wpa_priv_interface *interfaces = NULL, *iface;
+	struct wpa_priv_global global;
+	struct wpa_priv_interface *iface;
 
 	if (os_program_init())
 		return -1;
 
 	wpa_priv_fd_workaround();
 
+	os_memset(&global, 0, sizeof(global));
+	global.interfaces = NULL;
+
 	for (;;) {
 		c = getopt(argc, argv, "Bc:dP:");
 		if (c < 0)
@@ -1121,11 +1161,11 @@ int main(int argc, char *argv[])
 
 	for (i = optind; i < argc; i++) {
 		wpa_printf(MSG_DEBUG, "Adding driver:interface %s", argv[i]);
-		iface = wpa_priv_interface_init(ctrl_dir, argv[i]);
+		iface = wpa_priv_interface_init(&global, ctrl_dir, argv[i]);
 		if (iface == NULL)
 			goto out;
-		iface->next = interfaces;
-		interfaces = iface;
+		iface->next = global.interfaces;
+		global.interfaces = iface;
 	}
 
 	if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue())
@@ -1137,7 +1177,7 @@ int main(int argc, char *argv[])
 	ret = 0;
 
 out:
-	iface = interfaces;
+	iface = global.interfaces;
 	while (iface) {
 		struct wpa_priv_interface *prev = iface;
 		iface = iface->next;
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 136cb58..7b43600 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -3143,7 +3143,7 @@ static int select_driver(struct wpa_supplicant *wpa_s, int i)
 	struct wpa_global *global = wpa_s->global;
 
 	if (wpa_drivers[i]->global_init && global->drv_priv[i] == NULL) {
-		global->drv_priv[i] = wpa_drivers[i]->global_init();
+		global->drv_priv[i] = wpa_drivers[i]->global_init(global);
 		if (global->drv_priv[i] == NULL) {
 			wpa_printf(MSG_ERROR, "Failed to initialize driver "
 				   "'%s'", wpa_drivers[i]->name);


More information about the Hostap mailing list