From patchwork Tue Mar 15 13:02:08 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roy Marples X-Patchwork-Id: 597527 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from bombadil.infradead.org (unknown [198.137.202.9]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3qPZZX631dz9ssM for ; Wed, 16 Mar 2016 00:04:20 +1100 (AEDT) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1afocR-00045E-GL; Tue, 15 Mar 2016 13:02:39 +0000 Received: from uberserver.marples.name ([2a01:348:31:1::2] helo=mail.marples.name) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1afocH-0003k6-5r for hostap@lists.infradead.org; Tue, 15 Mar 2016 13:02:38 +0000 Received: from [IPv6:2a01:348:31:2:10e6:83ed:8aa4:7a57] (unknown [IPv6:2a01:348:31:2:10e6:83ed:8aa4:7a57]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.marples.name (Postfix) with ESMTPSA id 8F6109FBFE; Tue, 15 Mar 2016 13:02:05 +0000 (GMT) Subject: Re: [PATCH] Find correct driver for interface additions/removals To: Jouni Malinen References: <56BB7A07.2090806@marples.name> <20160306202721.GA16380@w1.fi> <4446710.axceUgRIUo@uberpc.marples.name> <20160313190912.GB5295@w1.fi> From: Roy Marples Message-ID: <56E807D0.7010502@marples.name> Date: Tue, 15 Mar 2016 13:02:08 +0000 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:38.0) Gecko/20100101 Thunderbird/38.6.0 MIME-Version: 1.0 In-Reply-To: <20160313190912.GB5295@w1.fi> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160315_060230_510328_7170CBDF X-CRM114-Status: GOOD ( 27.53 ) X-Spam-Score: -1.2 (-) X-Spam-Report: SpamAssassin version 3.4.0 on bombadil.infradead.org summary: Content analysis details: (-1.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- 0.7 SPF_SOFTFAIL SPF: sender does not match SPF record (softfail) -0.0 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] X-BeenThere: hostap@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: hostap@lists.infradead.org Sender: "Hostap" Errors-To: hostap-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org 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 commit 1cf54797b0c5c1f79f4efeeb640f7ebbd7576b94 Author: Roy Marples 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 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);