Cumulative patch from commit f51f54a007e0de1d413dee3523472d3bbeed2ecc
f51f54a nl80211: Resubscribe to nl80211 events on global nl_event socket
48ec694 Fix Linux packet socket workaround to not close the socket too easily
0d2030e Use estimated throughput to improve roaming selection
1d747e2 Add snr and est_throughput to the BSS entries
a1b790e Select AP based on estimated maximum throughput
ab647ff Add wpa_supplicant Makefile target libwpa_ctrl.a
abae2d1 trace: Initialize alloc_list even without os_program_init() call
891dfb3 Add helper function to clear and free wpa_psk list
71d77ad Update current BSS level when signal change event occurs
f1609f1 wpa_supplicant: Cancel sched_scan when stopping countermeasures
abb8d08 nl80211: Add support for configuring P2P GO CTWindow
0b8bcaa P2P: Allow configuring CTWindow when working as GO
c77ffc6 TDLS: Ignore extra padding in all packets
5ce6ac1 Inteworking: Add support to update the ANQP Capability List into the BSS
185ada4 HS 2.0: Add support to update the HS20 Capability List into the BSS
7fe7a3a wpa_gui: Debug enhancement
2b892d4 Add forgotten network profile parameters to config file writing
563ee18 IBSS: Add support for VHT80 configuration
ada157f Make hostapd_set_freq_params() common
98479dc IBSS: Update operating frequency if joining an existing IBSS
4d9e6fb IBSS: Add fixed_freq network parameter
6f5e1b0 Use priority list instead of global for PNO
97fc2dc Allow libnl-3.0 include path be specified
f92446f P2PS: Add P2PS interface info
59b416c Add optional reassoc-to-same-BSS optimization
c4da67d Fix passive_scan config parameter writing
715d5c4 hs20-osu-client: Ensure NULL checks are done before dereferencing
58d405f Fix OCSP debug messages
710dfb4 OpenSSL: Fix OCSP error path
bd7bb43 HTTP: Fix OCSP error path
946572c Android: Remove commented out non-Android build parameters
15ada7f Android: Remove libxml2 config defines
ebe8d3f Android: Silence unused function parameter warnings
dbd10da Android: Fix hs20-osu-client build on Android 5.0
a926295 HS 2.0R2: Fix permissions for SP/<fqdn> directory on Android
480994d nl80211: Allocate QCA vendor subcmds for DFS radar detected and CAC events
c165cb4 Drop all hostapd STA entries on interface disabled event
106fa1e nl80211: Indicate interface-down event only for the main netdev
eeb1cb2 VLAN: Clean up RTM_NEW/DELLINK processing
47e5fbd hostapd: Avoid sending client probe on removed client
3478273 Re-configure WPA2 group keys on hostapd interface re-enable
f33c860 Re-enable beaconing on interface disable+enable
fc99fab nl80211: Print a debug log entry on NL80211_CMD_PROBE_CLIENT failures
0d2f324 P2P: Fix send_action_in_progress clearing in corner cases
9ff8dda Add hostapd UPDATE_BEACON ctrl_iface command
e0761c5 nl80211: Allocate QCA vendor subcmd for DFS CAC Start event
1db718b nl80211: Test vendor command and event
10263dc Add control interface commands for fetching wpa_config values
f91a512 Add INTERWORKING_ADD_NETWORK command
c612ae9 AP: Do not reply to Probe Request frames with DS Params mismatch
5b74e08 P2P: Document P2P_CONNECT-auto
99650ca Add STOP_AP control interface command
6b00512 P2P: Add event messages for P2P_CONNECT-fallback-to-GO-Neg
b0e669b P2P: Fix P2P_CONNECT-auto fallback to GO Neg with group interface
bf51f4f mesh: Fix remaining BLOCKED state after SAE auth failure
79ddb20 mesh: Add a monitor event on SAE authentication getting blocked
dd2cbaf mesh: Add a monitor event for SAE authentication failure
0cb5f8d mesh: Fix inactivity timer for 32 bit system
11e2ddb mesh: Remove duplicated no_auto_peer update
1e52983 D-Bus: Fix network block type change
4fada12 Fix HT40 co-ex scanning issue on hostapd error path
23ed011 Fix Linux packat socket regression work around
663ae2f Don't write to wpa_supplicant.conf directly
d9a9bc0 IBSS: Do not enable HT with WEP or TKIP
0d7eb43 ACS: Accept channel if any (rather than all) survey results are valid
68fa00c ACS: Allow specific channels to be preferred
6f41a25 ACS: Use weighted average for 2.4 GHz adjacent channel interference
Change-Id: Ie1cabd28dcfdefafa02e81477e34badae6f7e629
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index c1f3efc..30a6657 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -1605,8 +1605,8 @@
struct wpa_scan_res **_wb = (void *) b;
struct wpa_scan_res *wa = *_wa;
struct wpa_scan_res *wb = *_wb;
- int wpa_a, wpa_b, maxrate_a, maxrate_b;
- int snr_a, snr_b;
+ int wpa_a, wpa_b;
+ int snr_a, snr_b, snr_a_full, snr_b_full;
/* WPA/WPA2 support preferred */
wpa_a = wpa_scan_get_vendor_ie(wa, WPA_IE_VENDOR_TYPE) != NULL ||
@@ -1628,22 +1628,22 @@
return -1;
if (wa->flags & wb->flags & WPA_SCAN_LEVEL_DBM) {
- snr_a = MIN(wa->level - wa->noise, GREAT_SNR);
- snr_b = MIN(wb->level - wb->noise, GREAT_SNR);
+ snr_a_full = wa->snr;
+ snr_a = MIN(wa->snr, GREAT_SNR);
+ snr_b_full = wb->snr;
+ snr_b = MIN(wa->snr, GREAT_SNR);
} else {
/* Level is not in dBm, so we can't calculate
* SNR. Just use raw level (units unknown). */
- snr_a = wa->level;
- snr_b = wb->level;
+ snr_a = snr_a_full = wa->level;
+ snr_b = snr_b_full = wb->level;
}
/* if SNR is close, decide by max rate or frequency band */
if ((snr_a && snr_b && abs(snr_b - snr_a) < 5) ||
(wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) {
- maxrate_a = wpa_scan_get_max_rate(wa);
- maxrate_b = wpa_scan_get_max_rate(wb);
- if (maxrate_a != maxrate_b)
- return maxrate_b - maxrate_a;
+ if (wa->est_throughput != wb->est_throughput)
+ return wb->est_throughput - wa->est_throughput;
if (IS_5GHZ(wa->freq) ^ IS_5GHZ(wb->freq))
return IS_5GHZ(wa->freq) ? -1 : 1;
}
@@ -1651,9 +1651,9 @@
/* all things being equal, use SNR; if SNRs are
* identical, use quality values since some drivers may only report
* that value and leave the signal level zero */
- if (snr_b == snr_a)
+ if (snr_b_full == snr_a_full)
return wb->qual - wa->qual;
- return snr_b - snr_a;
+ return snr_b_full - snr_a_full;
#undef MIN
}
@@ -1720,20 +1720,21 @@
struct wpa_scan_res *r = scan_res->res[i];
u8 *pos;
if (r->flags & WPA_SCAN_LEVEL_DBM) {
- int snr = r->level - r->noise;
int noise_valid = !(r->flags & WPA_SCAN_NOISE_INVALID);
wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d "
- "noise=%d%s level=%d snr=%d%s flags=0x%x age=%u",
+ "noise=%d%s level=%d snr=%d%s flags=0x%x age=%u est=%u",
MAC2STR(r->bssid), r->freq, r->qual,
r->noise, noise_valid ? "" : "~", r->level,
- snr, snr >= GREAT_SNR ? "*" : "", r->flags,
- r->age);
+ r->snr, r->snr >= GREAT_SNR ? "*" : "",
+ r->flags,
+ r->age, r->est_throughput);
} else {
wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d "
- "noise=%d level=%d flags=0x%x age=%u",
+ "noise=%d level=%d flags=0x%x age=%u est=%u",
MAC2STR(r->bssid), r->freq, r->qual,
- r->noise, r->level, r->flags, r->age);
+ r->noise, r->level, r->flags, r->age,
+ r->est_throughput);
}
pos = (u8 *) (r + 1);
if (r->ie_len)
@@ -1808,6 +1809,180 @@
#define DEFAULT_NOISE_FLOOR_2GHZ (-89)
#define DEFAULT_NOISE_FLOOR_5GHZ (-92)
+static void scan_snr(struct wpa_scan_res *res)
+{
+ if (res->flags & WPA_SCAN_NOISE_INVALID) {
+ res->noise = IS_5GHZ(res->freq) ?
+ DEFAULT_NOISE_FLOOR_5GHZ :
+ DEFAULT_NOISE_FLOOR_2GHZ;
+ }
+
+ if (res->flags & WPA_SCAN_LEVEL_DBM) {
+ res->snr = res->level - res->noise;
+ } else {
+ /* Level is not in dBm, so we can't calculate
+ * SNR. Just use raw level (units unknown). */
+ res->snr = res->level;
+ }
+}
+
+
+static unsigned int max_ht20_rate(int snr)
+{
+ if (snr < 6)
+ return 6500; /* HT20 MCS0 */
+ if (snr < 8)
+ return 13000; /* HT20 MCS1 */
+ if (snr < 13)
+ return 19500; /* HT20 MCS2 */
+ if (snr < 17)
+ return 26000; /* HT20 MCS3 */
+ if (snr < 20)
+ return 39000; /* HT20 MCS4 */
+ if (snr < 23)
+ return 52000; /* HT20 MCS5 */
+ if (snr < 24)
+ return 58500; /* HT20 MCS6 */
+ return 65000; /* HT20 MCS7 */
+}
+
+
+static unsigned int max_ht40_rate(int snr)
+{
+ if (snr < 3)
+ return 13500; /* HT40 MCS0 */
+ if (snr < 6)
+ return 27000; /* HT40 MCS1 */
+ if (snr < 10)
+ return 40500; /* HT40 MCS2 */
+ if (snr < 15)
+ return 54000; /* HT40 MCS3 */
+ if (snr < 17)
+ return 81000; /* HT40 MCS4 */
+ if (snr < 22)
+ return 108000; /* HT40 MCS5 */
+ if (snr < 22)
+ return 121500; /* HT40 MCS6 */
+ return 135000; /* HT40 MCS7 */
+}
+
+
+static unsigned int max_vht80_rate(int snr)
+{
+ if (snr < 1)
+ return 0;
+ if (snr < 2)
+ return 29300; /* VHT80 MCS0 */
+ if (snr < 5)
+ return 58500; /* VHT80 MCS1 */
+ if (snr < 9)
+ return 87800; /* VHT80 MCS2 */
+ if (snr < 11)
+ return 117000; /* VHT80 MCS3 */
+ if (snr < 15)
+ return 175500; /* VHT80 MCS4 */
+ if (snr < 16)
+ return 234000; /* VHT80 MCS5 */
+ if (snr < 18)
+ return 263300; /* VHT80 MCS6 */
+ if (snr < 20)
+ return 292500; /* VHT80 MCS7 */
+ if (snr < 22)
+ return 351000; /* VHT80 MCS8 */
+ return 390000; /* VHT80 MCS9 */
+}
+
+
+static void scan_est_throughput(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_res *res)
+{
+ enum local_hw_capab capab = wpa_s->hw_capab;
+ int rate; /* max legacy rate in 500 kb/s units */
+ const u8 *ie;
+ unsigned int est, tmp;
+ int snr = res->snr;
+
+ if (res->est_throughput)
+ return;
+
+ /* Get maximum legacy rate */
+ rate = wpa_scan_get_max_rate(res);
+
+ /* Limit based on estimated SNR */
+ if (rate > 1 * 2 && snr < 1)
+ rate = 1 * 2;
+ else if (rate > 2 * 2 && snr < 4)
+ rate = 2 * 2;
+ else if (rate > 6 * 2 && snr < 5)
+ rate = 6 * 2;
+ else if (rate > 9 * 2 && snr < 6)
+ rate = 9 * 2;
+ else if (rate > 12 * 2 && snr < 7)
+ rate = 12 * 2;
+ else if (rate > 18 * 2 && snr < 10)
+ rate = 18 * 2;
+ else if (rate > 24 * 2 && snr < 11)
+ rate = 24 * 2;
+ else if (rate > 36 * 2 && snr < 15)
+ rate = 36 * 2;
+ else if (rate > 48 * 2 && snr < 19)
+ rate = 48 * 2;
+ else if (rate > 54 * 2 && snr < 21)
+ rate = 54 * 2;
+ est = rate * 500;
+
+ if (capab == CAPAB_HT || capab == CAPAB_HT40 || capab == CAPAB_VHT) {
+ ie = wpa_scan_get_ie(res, WLAN_EID_HT_CAP);
+ if (ie) {
+ tmp = max_ht20_rate(snr);
+ if (tmp > est)
+ est = tmp;
+ }
+ }
+
+ if (capab == CAPAB_HT40 || capab == CAPAB_VHT) {
+ ie = wpa_scan_get_ie(res, WLAN_EID_HT_OPERATION);
+ if (ie && ie[1] >= 2 &&
+ (ie[3] & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) {
+ tmp = max_ht40_rate(snr);
+ if (tmp > est)
+ est = tmp;
+ }
+ }
+
+ if (capab == CAPAB_VHT) {
+ /* Use +1 to assume VHT is always faster than HT */
+ ie = wpa_scan_get_ie(res, WLAN_EID_VHT_CAP);
+ if (ie) {
+ tmp = max_ht20_rate(snr) + 1;
+ if (tmp > est)
+ est = tmp;
+
+ ie = wpa_scan_get_ie(res, WLAN_EID_HT_OPERATION);
+ if (ie && ie[1] >= 2 &&
+ (ie[3] &
+ HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) {
+ tmp = max_ht40_rate(snr) + 1;
+ if (tmp > est)
+ est = tmp;
+ }
+
+ ie = wpa_scan_get_ie(res, WLAN_EID_VHT_OPERATION);
+ if (ie && ie[1] >= 1 &&
+ (ie[2] & VHT_OPMODE_CHANNEL_WIDTH_MASK)) {
+ tmp = max_vht80_rate(snr) + 1;
+ if (tmp > est)
+ est = tmp;
+ }
+ }
+ }
+
+ /* TODO: channel utilization and AP load (e.g., from AP Beacon) */
+
+ res->est_throughput = est;
+}
+
+
/**
* wpa_supplicant_get_scan_results - Get scan results
* @wpa_s: Pointer to wpa_supplicant data
@@ -1844,12 +2019,8 @@
for (i = 0; i < scan_res->num; i++) {
struct wpa_scan_res *scan_res_item = scan_res->res[i];
- if (scan_res_item->flags & WPA_SCAN_NOISE_INVALID) {
- scan_res_item->noise =
- IS_5GHZ(scan_res_item->freq) ?
- DEFAULT_NOISE_FLOOR_5GHZ :
- DEFAULT_NOISE_FLOOR_2GHZ;
- }
+ scan_snr(scan_res_item);
+ scan_est_throughput(wpa_s, scan_res_item);
}
#ifdef CONFIG_WPS
@@ -2036,7 +2207,7 @@
int wpas_start_pno(struct wpa_supplicant *wpa_s)
{
- int ret, interval;
+ int ret, interval, prio;
size_t i, num_ssid, num_match_ssid;
struct wpa_ssid *ssid;
struct wpa_driver_scan_params params;
@@ -2101,8 +2272,10 @@
sizeof(struct wpa_driver_scan_filter));
if (params.filter_ssids == NULL)
return -1;
+
i = 0;
- ssid = wpa_s->conf->ssid;
+ prio = 0;
+ ssid = wpa_s->conf->pssid[prio];
while (ssid) {
if (!wpas_network_disabled(wpa_s, ssid)) {
if (ssid->scan_ssid && params.num_ssids < num_ssid) {
@@ -2120,7 +2293,12 @@
if (i == num_match_ssid)
break;
}
- ssid = ssid->next;
+ if (ssid->pnext)
+ ssid = ssid->pnext;
+ else if (prio + 1 == wpa_s->conf->num_prio)
+ break;
+ else
+ ssid = wpa_s->conf->pssid[++prio];
}
if (wpa_s->conf->filter_rssi)