diff --git a/src/nm-device-wifi.c b/src/nm-device-wifi.c index dc76dc29db..895d4d1765 100644 --- a/src/nm-device-wifi.c +++ b/src/nm-device-wifi.c @@ -829,6 +829,11 @@ get_active_ap (NMDeviceWifi *self, const GByteArray *ssid; GSList *iter; int i = 0; + NMAccessPoint *match_nofreq = NULL; + gboolean found_a_band = FALSE; + gboolean found_bg_band = FALSE; + NM80211Mode devmode; + guint32 devfreq; nm_device_wifi_get_bssid (self, &bssid); nm_log_dbg (LOGD_WIFI, "(%s): active BSSID: %02x:%02x:%02x:%02x:%02x:%02x", @@ -847,6 +852,9 @@ get_active_ap (NMDeviceWifi *self, ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : "(none)", ssid ? "'" : ""); + devmode = nm_device_wifi_get_mode (self); + devfreq = nm_device_wifi_get_frequency (self); + /* When matching hidden APs, do a second pass that ignores the SSID check, * because NM might not yet know the SSID of the hidden AP in the scan list * and therefore it won't get matched the first time around. @@ -859,8 +867,8 @@ get_active_ap (NMDeviceWifi *self, NMAccessPoint *ap = NM_AP (iter->data); const struct ether_addr *ap_bssid = nm_ap_get_address (ap); const GByteArray *ap_ssid = nm_ap_get_ssid (ap); - NM80211Mode devmode, apmode; - guint32 devfreq, apfreq; + NM80211Mode apmode; + guint32 apfreq; nm_log_dbg (LOGD_WIFI, " AP: %s%s%s %02x:%02x:%02x:%02x:%02x:%02x", ap_ssid ? "'" : "", @@ -885,7 +893,6 @@ get_active_ap (NMDeviceWifi *self, continue; } - devmode = nm_device_wifi_get_mode (self); apmode = nm_ap_get_mode (ap); if (devmode != apmode) { nm_log_dbg (LOGD_WIFI, " mode mismatch (device %d, ap %d)", @@ -893,11 +900,18 @@ get_active_ap (NMDeviceWifi *self, continue; } - devfreq = nm_device_wifi_get_frequency (self); apfreq = nm_ap_get_freq (ap); if (devfreq != apfreq) { nm_log_dbg (LOGD_WIFI, " frequency mismatch (device %u, ap %u)", devfreq, apfreq); + + if (match_nofreq == NULL) + match_nofreq = ap; + + if (apfreq > 4000) + found_a_band = TRUE; + else if (apfreq > 2000) + found_bg_band = TRUE; continue; } @@ -907,6 +921,32 @@ get_active_ap (NMDeviceWifi *self, } } + /* Some proprietary drivers (wl.o) report tuned frequency (like when + * scanning) instead of the associated AP's frequency. This is a great + * example of how WEXT is underspecified. We use frequency to find the + * active AP in the scan list because some configurations use the same + * SSID/BSSID on the 2GHz and 5GHz bands simultaneously, and we need to + * make sure we get the right AP in the right band. This configuration + * is uncommon though, and the frequency check penalizes closed drivers we + * can't fix. Because we're not total dicks, ignore the frequency condition + * if the associated BSSID/SSID exists only in one band since that's most + * likely the AP we want. + */ + if (match_nofreq && (found_a_band != found_bg_band)) { + const struct ether_addr *ap_bssid = nm_ap_get_address (match_nofreq); + const GByteArray *ap_ssid = nm_ap_get_ssid (match_nofreq); + + nm_log_dbg (LOGD_WIFI, " matched %s%s%s %02x:%02x:%02x:%02x:%02x:%02x", + ap_ssid ? "'" : "", + ap_ssid ? nm_utils_escape_ssid (ap_ssid->data, ap_ssid->len) : "(none)", + ap_ssid ? "'" : "", + ap_bssid->ether_addr_octet[0], ap_bssid->ether_addr_octet[1], + ap_bssid->ether_addr_octet[2], ap_bssid->ether_addr_octet[3], + ap_bssid->ether_addr_octet[4], ap_bssid->ether_addr_octet[5]); + + return match_nofreq; + } + nm_log_dbg (LOGD_WIFI, " No matching AP found."); return NULL; }