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:
parent
c577db2afd
commit
6859f1cb24
6 changed files with 148 additions and 3 deletions
|
@ -1924,6 +1924,19 @@ struct wpa_driver_ops {
|
||||||
* set_intra_bss - Enables/Disables intra BSS bridging
|
* set_intra_bss - Enables/Disables intra BSS bridging
|
||||||
*/
|
*/
|
||||||
int (*set_intra_bss)(void *priv, int enabled);
|
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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3309,5 +3309,6 @@ const struct wpa_driver_ops wpa_driver_ndis_ops = {
|
||||||
NULL /* set_noa */,
|
NULL /* set_noa */,
|
||||||
NULL /* set_p2p_powersave */,
|
NULL /* set_p2p_powersave */,
|
||||||
NULL /* ampdu */,
|
NULL /* ampdu */,
|
||||||
NULL /* set_intra_bss */
|
NULL /* set_intra_bss */,
|
||||||
|
NULL /* get_radio_name */
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <netlink/genl/genl.h>
|
#include <netlink/genl/genl.h>
|
||||||
#include <netlink/genl/family.h>
|
#include <netlink/genl/family.h>
|
||||||
|
@ -116,6 +119,7 @@ struct wpa_driver_nl80211_data {
|
||||||
struct nl80211_global *global;
|
struct nl80211_global *global;
|
||||||
struct dl_list list;
|
struct dl_list list;
|
||||||
u8 addr[ETH_ALEN];
|
u8 addr[ETH_ALEN];
|
||||||
|
char phyname[32];
|
||||||
void *ctx;
|
void *ctx;
|
||||||
struct netlink_data *netlink;
|
struct netlink_data *netlink;
|
||||||
int ioctl_sock; /* socket for ioctl() use */
|
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
|
* wpa_driver_nl80211_init - Initialize nl80211 driver interface
|
||||||
* @ctx: context to be used when calling wpa_supplicant functions,
|
* @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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nl80211_get_phy_name(drv);
|
||||||
|
|
||||||
drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
|
drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
|
||||||
if (drv->ioctl_sock < 0) {
|
if (drv->ioctl_sock < 0) {
|
||||||
perror("socket(PF_INET,SOCK_DGRAM)");
|
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 = {
|
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
|
||||||
.name = "nl80211",
|
.name = "nl80211",
|
||||||
.desc = "Linux nl80211/cfg80211",
|
.desc = "Linux nl80211/cfg80211",
|
||||||
|
@ -6158,4 +6205,5 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
|
||||||
.send_frame = nl80211_send_frame,
|
.send_frame = nl80211_send_frame,
|
||||||
.set_intra_bss = nl80211_set_intra_bss,
|
.set_intra_bss = nl80211_set_intra_bss,
|
||||||
.set_param = nl80211_set_param,
|
.set_param = nl80211_set_param,
|
||||||
|
.get_radio_name = nl80211_get_radio_name,
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,7 +20,9 @@
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <net/if_arp.h>
|
#include <net/if_arp.h>
|
||||||
|
|
||||||
#include "wireless_copy.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
|
* wpa_driver_wext_init - Initialize WE driver interface
|
||||||
* @ctx: context to be used when calling wpa_supplicant functions,
|
* @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) {
|
if (stat(path, &buf) == 0) {
|
||||||
wpa_printf(MSG_DEBUG, "WEXT: cfg80211-based driver detected");
|
wpa_printf(MSG_DEBUG, "WEXT: cfg80211-based driver detected");
|
||||||
drv->cfg80211 = 1;
|
drv->cfg80211 = 1;
|
||||||
|
wext_get_phy_name(drv);
|
||||||
}
|
}
|
||||||
|
|
||||||
drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
|
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 = {
|
const struct wpa_driver_ops wpa_driver_wext_ops = {
|
||||||
.name = "wext",
|
.name = "wext",
|
||||||
.desc = "Linux wireless extensions (generic)",
|
.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,
|
.flush_pmkid = wpa_driver_wext_flush_pmkid,
|
||||||
.get_capa = wpa_driver_wext_get_capa,
|
.get_capa = wpa_driver_wext_get_capa,
|
||||||
.set_operstate = wpa_driver_wext_set_operstate,
|
.set_operstate = wpa_driver_wext_set_operstate,
|
||||||
|
.get_radio_name = wext_get_radio_name,
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,6 +23,7 @@ struct wpa_driver_wext_data {
|
||||||
int ioctl_sock;
|
int ioctl_sock;
|
||||||
int mlme_sock;
|
int mlme_sock;
|
||||||
char ifname[IFNAMSIZ + 1];
|
char ifname[IFNAMSIZ + 1];
|
||||||
|
char phyname[32];
|
||||||
int ifindex;
|
int ifindex;
|
||||||
int ifindex2;
|
int ifindex2;
|
||||||
int if_removed;
|
int if_removed;
|
||||||
|
|
|
@ -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,
|
static void _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
|
||||||
union wpa_event_data *data)
|
union wpa_event_data *data)
|
||||||
{
|
{
|
||||||
struct wpa_bss *selected;
|
struct wpa_bss *selected;
|
||||||
struct wpa_ssid *ssid = NULL;
|
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 */
|
#endif /* CONFIG_NO_SCAN_PROCESSING */
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue