Enable sharing of scan result events among virtual interfaces

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>
This commit is contained in:
Ben Greear 2010-11-26 21:46:30 +02:00 committed by Jouni Malinen
parent c577db2afd
commit 6859f1cb24
6 changed files with 148 additions and 3 deletions

View 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);
};

View 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 */
};

View 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,
};

View 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,
};

View 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;

View 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 */