]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Enable sharing of scan result events among virtual interfaces
authorBen Greear <greearb@candelatech.com>
Fri, 26 Nov 2010 19:46:30 +0000 (21:46 +0200)
committerJouni Malinen <j@w1.fi>
Fri, 26 Nov 2010 19:46:30 +0000 (21:46 +0200)
When controlling multiple virtual interfaces on the same physical
radio, share the scan results events with sibling interfaces. This
decreases the time it takes to connect many virtual interfaces.

This is currently only supported on Linux with cfg80211-based
drivers when using nl80211 or wext driver interface.

Signed-off-by: Ben Greear <greearb@candelatech.com>
src/drivers/driver.h
src/drivers/driver_ndis.c
src/drivers/driver_nl80211.c
src/drivers/driver_wext.c
src/drivers/driver_wext.h
wpa_supplicant/events.c

index eaaef00a366ffac07b8ba7d3d8bfab4fafd2e21d..956403a15ecf3c0682bd7d31d145deff0839a806 100644 (file)
@@ -1924,6 +1924,19 @@ struct wpa_driver_ops {
         * set_intra_bss - Enables/Disables intra BSS bridging
         */
        int (*set_intra_bss)(void *priv, int enabled);
+
+       /**
+        * get_radio_name - Get physical radio name for the device
+        * @priv: Private driver interface data
+        * Returns: Radio name or %NULL if not known
+        *
+        * The returned data must not be modified by the caller. It is assumed
+        * that any interface that has the same radio name as another is
+        * sharing the same physical radio. This information can be used to
+        * share scan results etc. information between the virtual interfaces
+        * to speed up various operations.
+        */
+       const char * (*get_radio_name)(void *priv);
 };
 
 
index 5bfd613690773f21cfa8be7027d3f5989f3594e6..34bfa2bc0247d3307625fbf235b9027be6b58375 100644 (file)
@@ -3309,5 +3309,6 @@ const struct wpa_driver_ops wpa_driver_ndis_ops = {
        NULL /* set_noa */,
        NULL /* set_p2p_powersave */,
        NULL /* ampdu */,
-       NULL /* set_intra_bss */
+       NULL /* set_intra_bss */,
+       NULL /* get_radio_name */
 };
index a53cbe04a6f1eb29f0bd06cc503eba0e90be2321..0621458699e4b002056ee1d6923467d07394cfd7 100644 (file)
@@ -18,6 +18,9 @@
 
 #include "includes.h"
 #include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 #include <net/if.h>
 #include <netlink/genl/genl.h>
 #include <netlink/genl/family.h>
@@ -116,6 +119,7 @@ struct wpa_driver_nl80211_data {
        struct nl80211_global *global;
        struct dl_list list;
        u8 addr[ETH_ALEN];
+       char phyname[32];
        void *ctx;
        struct netlink_data *netlink;
        int ioctl_sock; /* socket for ioctl() use */
@@ -1654,6 +1658,39 @@ static void wpa_driver_nl80211_rfkill_unblocked(void *ctx)
 }
 
 
+static void nl80211_get_phy_name(struct wpa_driver_nl80211_data *drv)
+{
+       /* Find phy (radio) to which this interface belongs */
+       char buf[90], *pos;
+       int f, rv;
+
+       drv->phyname[0] = '\0';
+       snprintf(buf, sizeof(buf) - 1, "/sys/class/net/%s/phy80211/name",
+                drv->first_bss.ifname);
+       f = open(buf, O_RDONLY);
+       if (f < 0) {
+               wpa_printf(MSG_DEBUG, "Could not open file %s: %s",
+                          buf, strerror(errno));
+               return;
+       }
+
+       rv = read(f, drv->phyname, sizeof(drv->phyname) - 1);
+       close(f);
+       if (rv < 0) {
+               wpa_printf(MSG_DEBUG, "Could not read file %s: %s",
+                          buf, strerror(errno));
+               return;
+       }
+
+       drv->phyname[rv] = '\0';
+       pos = os_strchr(drv->phyname, '\n');
+       if (pos)
+               *pos = '\0';
+       wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
+                  drv->first_bss.ifname, drv->phyname);
+}
+
+
 /**
  * wpa_driver_nl80211_init - Initialize nl80211 driver interface
  * @ctx: context to be used when calling wpa_supplicant functions,
@@ -1689,6 +1726,8 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
                return NULL;
        }
 
+       nl80211_get_phy_name(drv);
+
        drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
        if (drv->ioctl_sock < 0) {
                perror("socket(PF_INET,SOCK_DGRAM)");
@@ -6095,6 +6134,14 @@ static void nl80211_global_deinit(void *priv)
 }
 
 
+static const char * nl80211_get_radio_name(void *priv)
+{
+       struct i802_bss *bss = priv;
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       return drv->phyname;
+}
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .name = "nl80211",
        .desc = "Linux nl80211/cfg80211",
@@ -6158,4 +6205,5 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
        .send_frame = nl80211_send_frame,
        .set_intra_bss = nl80211_set_intra_bss,
        .set_param = nl80211_set_param,
+       .get_radio_name = nl80211_get_radio_name,
 };
index f0de6aae3b4067e909a3dd7329fae32a12a9a6a4..ecb03aeb5e6037a3ff1cb179fc4093f6e2e4467e 100644 (file)
@@ -20,7 +20,9 @@
 
 #include "includes.h"
 #include <sys/ioctl.h>
+#include <sys/types.h>
 #include <sys/stat.h>
+#include <fcntl.h>
 #include <net/if_arp.h>
 
 #include "wireless_copy.h"
@@ -724,6 +726,39 @@ static void wpa_driver_wext_rfkill_unblocked(void *ctx)
 }
 
 
+static void wext_get_phy_name(struct wpa_driver_wext_data *drv)
+{
+       /* Find phy (radio) to which this interface belongs */
+       char buf[90], *pos;
+       int f, rv;
+
+       drv->phyname[0] = '\0';
+       snprintf(buf, sizeof(buf) - 1, "/sys/class/net/%s/phy80211/name",
+                drv->ifname);
+       f = open(buf, O_RDONLY);
+       if (f < 0) {
+               wpa_printf(MSG_DEBUG, "Could not open file %s: %s",
+                          buf, strerror(errno));
+               return;
+       }
+
+       rv = read(f, drv->phyname, sizeof(drv->phyname) - 1);
+       close(f);
+       if (rv < 0) {
+               wpa_printf(MSG_DEBUG, "Could not read file %s: %s",
+                          buf, strerror(errno));
+               return;
+       }
+
+       drv->phyname[rv] = '\0';
+       pos = os_strchr(drv->phyname, '\n');
+       if (pos)
+               *pos = '\0';
+       wpa_printf(MSG_DEBUG, "wext: interface %s phy: %s",
+                  drv->ifname, drv->phyname);
+}
+
+
 /**
  * wpa_driver_wext_init - Initialize WE driver interface
  * @ctx: context to be used when calling wpa_supplicant functions,
@@ -749,6 +784,7 @@ void * wpa_driver_wext_init(void *ctx, const char *ifname)
        if (stat(path, &buf) == 0) {
                wpa_printf(MSG_DEBUG, "WEXT: cfg80211-based driver detected");
                drv->cfg80211 = 1;
+               wext_get_phy_name(drv);
        }
 
        drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
@@ -2255,6 +2291,13 @@ int wpa_driver_wext_get_version(struct wpa_driver_wext_data *drv)
 }
 
 
+static const char * wext_get_radio_name(void *priv)
+{
+       struct wpa_driver_wext_data *drv = priv;
+       return drv->phyname;
+}
+
+
 const struct wpa_driver_ops wpa_driver_wext_ops = {
        .name = "wext",
        .desc = "Linux wireless extensions (generic)",
@@ -2274,4 +2317,5 @@ const struct wpa_driver_ops wpa_driver_wext_ops = {
        .flush_pmkid = wpa_driver_wext_flush_pmkid,
        .get_capa = wpa_driver_wext_get_capa,
        .set_operstate = wpa_driver_wext_set_operstate,
+       .get_radio_name = wext_get_radio_name,
 };
index 6382bbbcd87e346afd9c033f0df5e2b9ad7cec51..89c13eb758e82c03cbaa2da2c6294d5d7195a955 100644 (file)
@@ -23,6 +23,7 @@ struct wpa_driver_wext_data {
        int ioctl_sock;
        int mlme_sock;
        char ifname[IFNAMSIZ + 1];
+       char phyname[32];
        int ifindex;
        int ifindex2;
        int if_removed;
index 86f995823c8045efb9547f0bb22239d5cb0d2c90..51cd116ea2954099dfb2abad6c33bbf0c87f94d1 100644 (file)
@@ -828,8 +828,8 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
 }
 
 
-static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
-                                             union wpa_event_data *data)
+static void _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
+                                              union wpa_event_data *data)
 {
        struct wpa_bss *selected;
        struct wpa_ssid *ssid = NULL;
@@ -944,6 +944,44 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
                }
        }
 }
+
+
+static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
+                                             union wpa_event_data *data)
+{
+       const char *rn, *rn2;
+       struct wpa_supplicant *ifs;
+
+       _wpa_supplicant_event_scan_results(wpa_s, data);
+
+       /*
+        * Check other interfaces to see if they have the same radio-name. If
+        * so, they get updated with this same scan info.
+        */
+       if (!wpa_s->driver->get_radio_name)
+               return;
+
+       rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
+       if (rn == NULL || rn[0] == '\0')
+               return;
+
+       wpa_printf(MSG_DEBUG, "%s: Checking for other virtual interfaces "
+                  "sharing same radio (%s) in event_scan_results",
+                  wpa_s->ifname, rn);
+
+       for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+               if (ifs == wpa_s || !ifs->driver->get_radio_name)
+                       continue;
+
+               rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
+               if (rn2 && os_strcmp(rn, rn2) == 0) {
+                       wpa_printf(MSG_DEBUG, "%s: Updating scan results from "
+                                  "sibling", ifs->ifname);
+                       _wpa_supplicant_event_scan_results(ifs, data);
+               }
+       }
+}
+
 #endif /* CONFIG_NO_SCAN_PROCESSING */