[PATCH] Find correct driver for interface additions/removals
Roy Marples
roy at marples.name
Wed Feb 10 09:57:27 PST 2016
commit 278fb32de92640a145b02c7bcf116921826931bf
Author: Roy Marples <roy at marples.name>
Date: Wed Feb 10 17:15:15 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 1b9002c..49df944 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 9f53660..b9fc423 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -1331,4 +1331,14 @@ 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;
+
+ hapd = hostapd_get_iface(interfaces, data->interface_status.ifname);
+ if (hapd != NULL)
+ wpa_supplicant_event(hapd, event, data);
+}
#endif /* HOSTAPD */
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index a848f35..205a71f 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -3074,6 +3074,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)
@@ -3094,9 +3096,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)
{
size_t i;
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index a4f6704..9362347 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -2074,6 +2074,7 @@ struct wpa_driver_ops {
/**
* global_init - Global driver initialization
+ * @ctx: Pointer to global context
* Returns: Pointer to private data (global), %NULL on failure
*
* This optional function is called to initialize the driver wrapper
@@ -2083,7 +2084,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
@@ -4723,6 +4724,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; this is the ctx variable registered
+ * with struct wpa_driver_ops::global_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 ctx.
+ */
+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 99f3504..f79fcc6 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;
@@ -88,6 +89,21 @@ 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)
{
@@ -1222,24 +1238,32 @@ 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:
- event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+ drv = bsd_get_drvindex(global, ifan->ifan_index);
+ if (drv == NULL)
+ return;
drv->ifindex = 0;
+ event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+ break;
+ case IFAN_ARRIVAL:
+ drv = bsd_get_drvname(global, ifan->ifan_name);
+ if (drv != NULL)
+ drv->ifindex = ifan->ifan_index;
+ 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));
+ wpa_supplicant_event_global(global->ctx, EVENT_INTERFACE_STATUS,
+ &event);
break;
case RTM_IEEE80211:
ifan = (struct if_announcemsghdr *) rtm;
@@ -1615,7 +1633,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 +1641,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 0f312a0..e0c3bde 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -783,7 +783,6 @@ 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)
{
- union wpa_event_data event;
if (os_strcmp(drv->first_bss->ifname, ifname) == 0) {
if (if_nametoindex(drv->first_bss->ifname) == 0) {
@@ -797,19 +796,12 @@ static void wpa_driver_nl80211_event_newlink(
drv->first_bss->ifname);
drv->if_removed = 0;
}
-
- os_memset(&event, 0, sizeof(event));
- 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);
}
static void wpa_driver_nl80211_event_dellink(
struct wpa_driver_nl80211_data *drv, const char *ifname)
{
- union wpa_event_data event;
if (os_strcmp(drv->first_bss->ifname, ifname) == 0) {
if (drv->if_removed) {
@@ -825,11 +817,7 @@ static void wpa_driver_nl80211_event_dellink(
ifname);
}
- os_memset(&event, 0, sizeof(event));
- 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);
+ drv->ifindex = 0;
}
@@ -903,12 +891,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;
@@ -953,6 +935,19 @@ 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) {
+ union wpa_event_data event;
+
+ memset(&event, 0, sizeof(event));
+ os_strlcpy(event.interface_status.ifname, ifname,
+ sizeof(event.interface_status.ifname));
+ event.interface_status.ievent = EVENT_INTERFACE_ADDED;
+ wpa_supplicant_event_global(global->ctx, EVENT_INTERFACE_STATUS,
+ &event);
+ return;
+ }
+
if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
namebuf[0] = '\0';
if (if_indextoname(ifi->ifi_index, namebuf) &&
@@ -1086,13 +1081,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);
@@ -1133,10 +1121,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];
@@ -1151,6 +1138,19 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
}
del_ifidx(drv, brid);
}
+
+ if (ifi->ifi_family != AF_BRIDGE || !brid) {
+ union wpa_event_data event;
+
+ if (drv)
+ wpa_driver_nl80211_event_dellink(drv, ifname);
+ memset(&event, 0, sizeof(event));
+ os_strlcpy(event.interface_status.ifname, ifname,
+ sizeof(event.interface_status.ifname));
+ event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+ wpa_supplicant_event_global(global->ctx, EVENT_INTERFACE_STATUS,
+ &event);
+ }
}
@@ -6731,7 +6731,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;
@@ -6739,6 +6739,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;
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 09e03b3..fc6e638 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 3264dc0..718017a 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -3965,3 +3965,14 @@ 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;
+
+ wpa_s = wpa_supplicant_get_iface(ctx, data->interface_status.ifname);
+ 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..96ef58a 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,20 @@ 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;
+
+ for (iface = global->interfaces; iface; iface = iface->next) {
+ if (os_strcmp(iface->ifname, data->interface_status.ifname) == 0)
+ break;
+ }
+ 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 +1097,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 +1145,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 +1161,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 f362638..11f330d 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -3086,7 +3086,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