diff --git a/src/drivers/driver.h b/src/drivers/driver.h index eaaef00a3..956403a15 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -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); }; diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c index 5bfd61369..34bfa2bc0 100644 --- a/src/drivers/driver_ndis.c +++ b/src/drivers/driver_ndis.c @@ -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 */ }; diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index a53cbe04a..062145869 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -18,6 +18,9 @@ #include "includes.h" #include +#include +#include +#include #include #include #include @@ -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, }; diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c index f0de6aae3..ecb03aeb5 100644 --- a/src/drivers/driver_wext.c +++ b/src/drivers/driver_wext.c @@ -20,7 +20,9 @@ #include "includes.h" #include +#include #include +#include #include #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, }; diff --git a/src/drivers/driver_wext.h b/src/drivers/driver_wext.h index 6382bbbcd..89c13eb75 100644 --- a/src/drivers/driver_wext.h +++ b/src/drivers/driver_wext.h @@ -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; diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 86f995823..51cd116ea 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -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 */