From f2b0092b5b231514d4aa6dba347e3a16c5fd96a5 Mon Sep 17 00:00:00 2001 From: James Kalbfleisch Date: Wed, 8 Mar 2017 16:08:32 -0500 Subject: [PATCH 01/12] wifi: parse BSS IEs for 80211n and 80211ac data rates Currently, 'nmcli dev wifi list' does not show the user any rates above 54Mbps. Now, we can check the IEs passed to NM from the wpa_supplicant, pull the mcs rate and channel width information, and determine a maximum possible data rate for 11n and 11ac APs. https://bugzilla.gnome.org/show_bug.cgi?id=779771 --- src/devices/wifi/nm-wifi-ap.c | 342 ++++++++++++++++++++++++++++++++++ 1 file changed, 342 insertions(+) diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index 7de0838f97..37f82365fd 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -435,6 +435,339 @@ security_from_vardict (GVariant *security) return flags; } +static guint32 +get_max_ht20_rate(int mcs) +{ + if (mcs == 0) + return 6500000; + if (mcs == (1 || 8)) + return 13000000; + if (mcs == (2 || 16)) + return 19500000; + if (mcs == (3 || 9 || 24)) + return 26000000; + if (mcs == (4 || 10 || 17)) + return 39000000; + if (mcs == (5 || 11 || 25)) + return 52000000; + if (mcs == (6 || 18)) + return 58500000; + if (mcs == 7) + return 65000000; + if (mcs == (12 || 19 || 26)) + return 78000000; + if (mcs == (13 || 27)) + return 104000000; + if (mcs == (14 || 20)) + return 117000000; + if (mcs == 15) + return 130000000; + if (mcs == (21 || 28)) + return 156000000; + if (mcs == 22) + return 175500000; + if (mcs == 23) + return 195000000; + if (mcs == 29) + return 208000000; + if (mcs == 30) + return 234000000; + if (mcs == 31) + return 260000000; + + return 0; +} + +static guint32 +get_max_ht40_rate(int mcs) +{ + if (mcs == 0) + return 13500000; + if (mcs == (1 || 8)) + return 27000000; + if (mcs == 2) + return 40500000; + if (mcs == (3 || 9 || 24)) + return 54000000; + if (mcs == (4 || 10 || 17)) + return 81000000; + if (mcs == (5 || 11 || 25)) + return 108000000; + if (mcs == (6 || 18)) + return 121500000; + if (mcs == 7) + return 135000000; + if (mcs == (12 || 19 || 26)) + return 162000000; + if (mcs == (13 || 27)) + return 216000000; + if (mcs == (14 || 20)) + return 243000000; + if (mcs == 15) + return 270000000; + if (mcs == 16) + return 40500000; + if (mcs == (21 || 28)) + return 324000000; + if (mcs == 22) + return 364500000; + if (mcs == 23) + return 405000000; + if (mcs == 29) + return 432000000; + if (mcs == 30) + return 486000000; + if (mcs == 31) + return 540000000; + + return 0; +} + +static guint32 +get_max_vht80_rate_ss1(int mcs) +{ + if (mcs == 0) + return 29300000; + if (mcs == 1) + return 58500000; + if (mcs == 2) + return 87800000; + if (mcs == 3) + return 117000000; + if (mcs == 4) + return 175500000; + if (mcs == 5) + return 234000000; + if (mcs == 6) + return 263300000; + if (mcs == 7) + return 292500000; + if (mcs == 8) + return 351000000; + if (mcs == 9) + return 390000000; + return 0; +} + +static guint32 +get_max_vht80_rate_ss2(int mcs) +{ + + if (mcs == 0) + return 58500000; + if (mcs == 1) + return 117000000; + if (mcs == 2) + return 175500000; + if (mcs == 3) + return 234000000; + if (mcs == 4) + return 351000000; + if (mcs == 5) + return 468000000; + if (mcs == 6) + return 526500000; + if (mcs == 7) + return 585000000; + if (mcs == 8) + return 702000000; + if (mcs == 9) + return 780000000; + return 0; +} + +static guint32 +get_max_vht80_rate_ss3(int mcs) +{ + + if (mcs == 0) + return 87800000; + if (mcs == 1) + return 175500000; + if (mcs == 2) + return 263300000; + if (mcs == 3) + return 351000000; + if (mcs == 4) + return 526500000; + if (mcs == 5) + return 702000000; + if (mcs == 6) + return 0; + if (mcs == 7) + return 877500000; + if (mcs == 8) + return 105300000; + if (mcs == 9) + return 117000000; + return 0; +} + +static guint32 +get_max_vht160_rate_ss1(int mcs) +{ + if (mcs == 0) + return 58500000; + if (mcs == 1) + return 117000000; + if (mcs == 2) + return 175500000; + if (mcs == 3) + return 234000000; + if (mcs == 4) + return 351000000; + if (mcs == 5) + return 468000000; + if (mcs == 6) + return 526500000; + if (mcs == 7) + return 585000000; + if (mcs == 8) + return 702000000; + if (mcs == 9) + return 780000000; + return 0; +} + +static guint32 +get_max_vht160_rate_ss2(int mcs) +{ + + if (mcs == 0) + return 117000000; + if (mcs == 1) + return 234000000; + if (mcs == 2) + return 351000000; + if (mcs == 3) + return 468000000; + if (mcs == 4) + return 702000000; + if (mcs == 5) + return 936000000; + if (mcs == 6) + return 1053000000; + if (mcs == 7) + return 1170000000; + if (mcs == 8) + return 1404000000; + if (mcs == 9) + return 1560000000; + return 0; +} + +static guint32 +get_max_vht160_rate_ss3(int mcs) +{ + + if (mcs == 0) + return 175500000; + if (mcs == 1) + return 351000000; + if (mcs == 2) + return 526500000; + if (mcs == 3) + return 702000000; + if (mcs == 4) + return 1053000000; + if (mcs == 5) + return 1404000000; + if (mcs == 6) + return 1579500000; + if (mcs == 7) + return 1755000000; + if (mcs == 8) + return 2106000000; + if (mcs == 9) + return 0; + return 0; +} + +static guint32 +get_max_ht_rate(guint16 ht_cap_info, const guint8 * supported_mcs_set){ + guint32 mcs,i,j; + + /* Find the maximum supported mcs rate */ + mcs = -1; + for (i = 0; i <= 15; i++){ + for (j = 0; j <= 7; j++){ + if (*supported_mcs_set & (1 << j)) + mcs++; + } + supported_mcs_set++; + } + + /* Check for 40Mhz wide channel support */ + if (ht_cap_info & (1 << 1)) + return get_max_ht40_rate(mcs); + else + return get_max_ht20_rate(mcs); + +} + +static guint32 +get_max_vht_rate(guint32 vht_cap,guint16 tx_map){ + guint32 mcs = 7, ss = 1; + + /* Check for mcs rates 8 and 9 support */ + if (tx_map & 0x2a) + mcs = 9; + else if (tx_map & 0x15) + mcs = 8; + + /* Check for 160Mhz wide channel support and + * spatial stream support */ + if ( vht_cap & (1 << 2)){ + if (tx_map & 0x30) + return get_max_vht160_rate_ss3(mcs); + else if (tx_map & 0x0C) + return get_max_vht160_rate_ss2(mcs); + else + return get_max_vht160_rate_ss1(mcs); + } else { + if (tx_map & 0x30) + return get_max_vht80_rate_ss3(mcs); + else if (tx_map & 0x0C) + return get_max_vht80_rate_ss2(mcs); + else + return get_max_vht80_rate_ss1(mcs); + } + + return 0; +} + +#define IEEE_80211_IE_HT_CAP 45 +#define IEEE_80211_IE_VHT_CAP 191 + +static guint32 +get_max_rate(const guint8 *bytes, gsize len){ + guint8 id, elem_len; + guint32 max_rate = 0; + + while (len >= 2) { + id = *bytes++; + elem_len = *bytes++; + len -= 2; + + if (elem_len > len) { + return -1; + } + + if (id == IEEE_80211_IE_HT_CAP){ + max_rate = get_max_ht_rate(*bytes,bytes+3); + } + + if (id == IEEE_80211_IE_VHT_CAP) { + max_rate = get_max_vht_rate(*bytes,*(bytes+8)); + } + + len -= elem_len; + bytes += elem_len; + } + + return max_rate; +} + gboolean nm_wifi_ap_update_from_properties (NMWifiAP *ap, const char *supplicant_path, @@ -513,6 +846,15 @@ nm_wifi_ap_update_from_properties (NMWifiAP *ap, g_variant_unref (v); } + v = g_variant_lookup_value (properties, "IEs", G_VARIANT_TYPE_BYTESTRING); + if (v){ + bytes = g_variant_get_fixed_array (v, &len, 1); + guint32 max_rate = get_max_rate(bytes,len); + if (max_rate > 0) + nm_wifi_ap_set_max_bitrate (ap, max_rate / 1000); + g_variant_unref(v); + } + v = g_variant_lookup_value (properties, "WPA", G_VARIANT_TYPE_VARDICT); if (v) { changed |= nm_wifi_ap_set_wpa_flags (ap, priv->wpa_flags | security_from_vardict (v)); From f27a0711e622a2a540f30dca288864fcd435a4a9 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 9 Mar 2017 11:08:30 +0100 Subject: [PATCH 02/12] wifi/trivial: fix whitespace and style --- src/devices/wifi/nm-wifi-ap.c | 277 +++++++++++++++++----------------- 1 file changed, 136 insertions(+), 141 deletions(-) diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index 37f82365fd..5f774e4eaa 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -71,7 +71,7 @@ typedef struct { /* Non-scanned attributes */ bool fake:1; /* Whether or not the AP is from a scan */ bool hotspot:1; /* Whether the AP is a local device's hotspot network */ - gint32 last_seen; /* Timestamp when the AP was seen lastly (obtained via nm_utils_get_monotonic_timestamp_s()) */ + gint32 last_seen; /* Timestamp when the AP was seen lastly (obtained via nm_utils_get_monotonic_timestamp_s()) */ } NMWifiAPPrivate; struct _NMWifiAP { @@ -79,7 +79,7 @@ struct _NMWifiAP { NMWifiAPPrivate _priv; }; -struct _NMWifiAPClass{ +struct _NMWifiAPClass { NMExportedObjectClass parent; }; @@ -436,123 +436,120 @@ security_from_vardict (GVariant *security) } static guint32 -get_max_ht20_rate(int mcs) +get_max_ht20_rate (int mcs) { - if (mcs == 0) - return 6500000; - if (mcs == (1 || 8)) - return 13000000; - if (mcs == (2 || 16)) - return 19500000; - if (mcs == (3 || 9 || 24)) - return 26000000; - if (mcs == (4 || 10 || 17)) - return 39000000; - if (mcs == (5 || 11 || 25)) - return 52000000; - if (mcs == (6 || 18)) - return 58500000; - if (mcs == 7) - return 65000000; - if (mcs == (12 || 19 || 26)) - return 78000000; - if (mcs == (13 || 27)) - return 104000000; - if (mcs == (14 || 20)) - return 117000000; - if (mcs == 15) - return 130000000; - if (mcs == (21 || 28)) - return 156000000; - if (mcs == 22) - return 175500000; - if (mcs == 23) - return 195000000; - if (mcs == 29) - return 208000000; - if (mcs == 30) - return 234000000; + if (mcs == 0) + return 6500000; + if (mcs == (1 || 8)) + return 13000000; + if (mcs == (2 || 16)) + return 19500000; + if (mcs == (3 || 9 || 24)) + return 26000000; + if (mcs == (4 || 10 || 17)) + return 39000000; + if (mcs == (5 || 11 || 25)) + return 52000000; + if (mcs == (6 || 18)) + return 58500000; + if (mcs == 7) + return 65000000; + if (mcs == (12 || 19 || 26)) + return 78000000; + if (mcs == (13 || 27)) + return 104000000; + if (mcs == (14 || 20)) + return 117000000; + if (mcs == 15) + return 130000000; + if (mcs == (21 || 28)) + return 156000000; + if (mcs == 22) + return 175500000; + if (mcs == 23) + return 195000000; + if (mcs == 29) + return 208000000; + if (mcs == 30) + return 234000000; if (mcs == 31) return 260000000; - return 0; } static guint32 -get_max_ht40_rate(int mcs) +get_max_ht40_rate (int mcs) { - if (mcs == 0) - return 13500000; - if (mcs == (1 || 8)) - return 27000000; - if (mcs == 2) - return 40500000; - if (mcs == (3 || 9 || 24)) - return 54000000; - if (mcs == (4 || 10 || 17)) - return 81000000; - if (mcs == (5 || 11 || 25)) - return 108000000; - if (mcs == (6 || 18)) - return 121500000; - if (mcs == 7) - return 135000000; - if (mcs == (12 || 19 || 26)) - return 162000000; - if (mcs == (13 || 27)) - return 216000000; - if (mcs == (14 || 20)) - return 243000000; - if (mcs == 15) - return 270000000; - if (mcs == 16) - return 40500000; - if (mcs == (21 || 28)) - return 324000000; - if (mcs == 22) - return 364500000; - if (mcs == 23) - return 405000000; - if (mcs == 29) - return 432000000; - if (mcs == 30) - return 486000000; - if (mcs == 31) - return 540000000; - + if (mcs == 0) + return 13500000; + if (mcs == (1 || 8)) + return 27000000; + if (mcs == 2) + return 40500000; + if (mcs == (3 || 9 || 24)) + return 54000000; + if (mcs == (4 || 10 || 17)) + return 81000000; + if (mcs == (5 || 11 || 25)) + return 108000000; + if (mcs == (6 || 18)) + return 121500000; + if (mcs == 7) + return 135000000; + if (mcs == (12 || 19 || 26)) + return 162000000; + if (mcs == (13 || 27)) + return 216000000; + if (mcs == (14 || 20)) + return 243000000; + if (mcs == 15) + return 270000000; + if (mcs == 16) + return 40500000; + if (mcs == (21 || 28)) + return 324000000; + if (mcs == 22) + return 364500000; + if (mcs == 23) + return 405000000; + if (mcs == 29) + return 432000000; + if (mcs == 30) + return 486000000; + if (mcs == 31) + return 540000000; return 0; } static guint32 -get_max_vht80_rate_ss1(int mcs) +get_max_vht80_rate_ss1 (int mcs) { - if (mcs == 0) - return 29300000; - if (mcs == 1) - return 58500000; - if (mcs == 2) - return 87800000; - if (mcs == 3) - return 117000000; - if (mcs == 4) - return 175500000; - if (mcs == 5) - return 234000000; - if (mcs == 6) - return 263300000; - if (mcs == 7) - return 292500000; - if (mcs == 8) - return 351000000; + if (mcs == 0) + return 29300000; + if (mcs == 1) + return 58500000; + if (mcs == 2) + return 87800000; + if (mcs == 3) + return 117000000; + if (mcs == 4) + return 175500000; + if (mcs == 5) + return 234000000; + if (mcs == 6) + return 263300000; + if (mcs == 7) + return 292500000; + if (mcs == 8) + return 351000000; if (mcs == 9) return 390000000; - return 0; + return 0; } static guint32 -get_max_vht80_rate_ss2(int mcs) +get_max_vht80_rate_ss2 (int mcs) { - if (mcs == 0) return 58500000; if (mcs == 1) @@ -577,9 +574,8 @@ get_max_vht80_rate_ss2(int mcs) } static guint32 -get_max_vht80_rate_ss3(int mcs) +get_max_vht80_rate_ss3 (int mcs) { - if (mcs == 0) return 87800000; if (mcs == 1) @@ -604,35 +600,34 @@ get_max_vht80_rate_ss3(int mcs) } static guint32 -get_max_vht160_rate_ss1(int mcs) +get_max_vht160_rate_ss1 (int mcs) { if (mcs == 0) - return 58500000; + return 58500000; if (mcs == 1) - return 117000000; + return 117000000; if (mcs == 2) - return 175500000; + return 175500000; if (mcs == 3) - return 234000000; + return 234000000; if (mcs == 4) - return 351000000; + return 351000000; if (mcs == 5) - return 468000000; + return 468000000; if (mcs == 6) - return 526500000; + return 526500000; if (mcs == 7) - return 585000000; + return 585000000; if (mcs == 8) - return 702000000; + return 702000000; if (mcs == 9) return 780000000; return 0; } static guint32 -get_max_vht160_rate_ss2(int mcs) +get_max_vht160_rate_ss2 (int mcs) { - if (mcs == 0) return 117000000; if (mcs == 1) @@ -657,9 +652,8 @@ get_max_vht160_rate_ss2(int mcs) } static guint32 -get_max_vht160_rate_ss3(int mcs) +get_max_vht160_rate_ss3 (int mcs) { - if (mcs == 0) return 175500000; if (mcs == 1) @@ -684,13 +678,14 @@ get_max_vht160_rate_ss3(int mcs) } static guint32 -get_max_ht_rate(guint16 ht_cap_info, const guint8 * supported_mcs_set){ - guint32 mcs,i,j; +get_max_ht_rate (guint16 ht_cap_info, const guint8 *supported_mcs_set) +{ + guint32 mcs, i, j; /* Find the maximum supported mcs rate */ mcs = -1; - for (i = 0; i <= 15; i++){ - for (j = 0; j <= 7; j++){ + for (i = 0; i <= 15; i++) { + for (j = 0; j <= 7; j++) { if (*supported_mcs_set & (1 << j)) mcs++; } @@ -699,14 +694,15 @@ get_max_ht_rate(guint16 ht_cap_info, const guint8 * supported_mcs_set){ /* Check for 40Mhz wide channel support */ if (ht_cap_info & (1 << 1)) - return get_max_ht40_rate(mcs); + return get_max_ht40_rate (mcs); else - return get_max_ht20_rate(mcs); + return get_max_ht20_rate (mcs); } static guint32 -get_max_vht_rate(guint32 vht_cap,guint16 tx_map){ +get_max_vht_rate (guint32 vht_cap, guint16 tx_map) +{ guint32 mcs = 7, ss = 1; /* Check for mcs rates 8 and 9 support */ @@ -717,30 +713,31 @@ get_max_vht_rate(guint32 vht_cap,guint16 tx_map){ /* Check for 160Mhz wide channel support and * spatial stream support */ - if ( vht_cap & (1 << 2)){ + if (vht_cap & (1 << 2)) { if (tx_map & 0x30) - return get_max_vht160_rate_ss3(mcs); + return get_max_vht160_rate_ss3 (mcs); else if (tx_map & 0x0C) - return get_max_vht160_rate_ss2(mcs); + return get_max_vht160_rate_ss2 (mcs); else - return get_max_vht160_rate_ss1(mcs); + return get_max_vht160_rate_ss1 (mcs); } else { if (tx_map & 0x30) - return get_max_vht80_rate_ss3(mcs); + return get_max_vht80_rate_ss3 (mcs); else if (tx_map & 0x0C) - return get_max_vht80_rate_ss2(mcs); + return get_max_vht80_rate_ss2 (mcs); else - return get_max_vht80_rate_ss1(mcs); + return get_max_vht80_rate_ss1 (mcs); } return 0; } -#define IEEE_80211_IE_HT_CAP 45 +#define IEEE_80211_IE_HT_CAP 45 #define IEEE_80211_IE_VHT_CAP 191 static guint32 -get_max_rate(const guint8 *bytes, gsize len){ +get_max_rate (const guint8 *bytes, gsize len) +{ guint8 id, elem_len; guint32 max_rate = 0; @@ -753,13 +750,11 @@ get_max_rate(const guint8 *bytes, gsize len){ return -1; } - if (id == IEEE_80211_IE_HT_CAP){ - max_rate = get_max_ht_rate(*bytes,bytes+3); - } + if (id == IEEE_80211_IE_HT_CAP) + max_rate = get_max_ht_rate (*bytes, bytes+3); - if (id == IEEE_80211_IE_VHT_CAP) { - max_rate = get_max_vht_rate(*bytes,*(bytes+8)); - } + if (id == IEEE_80211_IE_VHT_CAP) + max_rate = get_max_vht_rate (*bytes, *(bytes+8)); len -= elem_len; bytes += elem_len; @@ -847,12 +842,12 @@ nm_wifi_ap_update_from_properties (NMWifiAP *ap, } v = g_variant_lookup_value (properties, "IEs", G_VARIANT_TYPE_BYTESTRING); - if (v){ + if (v) { bytes = g_variant_get_fixed_array (v, &len, 1); - guint32 max_rate = get_max_rate(bytes,len); + guint32 max_rate = get_max_rate (bytes, len); if (max_rate > 0) nm_wifi_ap_set_max_bitrate (ap, max_rate / 1000); - g_variant_unref(v); + g_variant_unref (v); } v = g_variant_lookup_value (properties, "WPA", G_VARIANT_TYPE_VARDICT); From 6c534af4d7aa1702f3dfb5a0eec4dd87ffbba362 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 9 Mar 2017 11:08:30 +0100 Subject: [PATCH 03/12] wifi: fix compiler warnings --- src/devices/wifi/nm-wifi-ap.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index 5f774e4eaa..139d1e9a76 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -703,7 +703,7 @@ get_max_ht_rate (guint16 ht_cap_info, const guint8 *supported_mcs_set) static guint32 get_max_vht_rate (guint32 vht_cap, guint16 tx_map) { - guint32 mcs = 7, ss = 1; + guint32 mcs = 7; /* Check for mcs rates 8 and 9 support */ if (tx_map & 0x2a) @@ -843,8 +843,10 @@ nm_wifi_ap_update_from_properties (NMWifiAP *ap, v = g_variant_lookup_value (properties, "IEs", G_VARIANT_TYPE_BYTESTRING); if (v) { + guint32 max_rate; + bytes = g_variant_get_fixed_array (v, &len, 1); - guint32 max_rate = get_max_rate (bytes, len); + max_rate = get_max_rate (bytes, len); if (max_rate > 0) nm_wifi_ap_set_max_bitrate (ap, max_rate / 1000); g_variant_unref (v); From 534a96d82ae1e453125045d3f4b06404572fb50f Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 9 Mar 2017 11:24:49 +0100 Subject: [PATCH 04/12] wifi: set changed flag for max-rate in nm_wifi_ap_update_from_properties() --- src/devices/wifi/nm-wifi-ap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index 139d1e9a76..6d5d5a4500 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -848,7 +848,7 @@ nm_wifi_ap_update_from_properties (NMWifiAP *ap, bytes = g_variant_get_fixed_array (v, &len, 1); max_rate = get_max_rate (bytes, len); if (max_rate > 0) - nm_wifi_ap_set_max_bitrate (ap, max_rate / 1000); + changed |= nm_wifi_ap_set_max_bitrate (ap, max_rate / 1000); g_variant_unref (v); } From 3d8bc3bc01b08e3a0fdea4778d0e28c4eca9c9d8 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 9 Mar 2017 11:44:29 +0100 Subject: [PATCH 05/12] wifi: replace "if" checks for rate with switch statement Also, fix "if (mcs == (12 || 19 || 26))". --- src/devices/wifi/nm-wifi-ap.c | 334 ++++++++++++++-------------------- 1 file changed, 140 insertions(+), 194 deletions(-) diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index 6d5d5a4500..bc6d0c665d 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -438,242 +438,188 @@ security_from_vardict (GVariant *security) static guint32 get_max_ht20_rate (int mcs) { - if (mcs == 0) - return 6500000; - if (mcs == (1 || 8)) - return 13000000; - if (mcs == (2 || 16)) - return 19500000; - if (mcs == (3 || 9 || 24)) - return 26000000; - if (mcs == (4 || 10 || 17)) - return 39000000; - if (mcs == (5 || 11 || 25)) - return 52000000; - if (mcs == (6 || 18)) - return 58500000; - if (mcs == 7) - return 65000000; - if (mcs == (12 || 19 || 26)) - return 78000000; - if (mcs == (13 || 27)) - return 104000000; - if (mcs == (14 || 20)) - return 117000000; - if (mcs == 15) - return 130000000; - if (mcs == (21 || 28)) - return 156000000; - if (mcs == 22) - return 175500000; - if (mcs == 23) - return 195000000; - if (mcs == 29) - return 208000000; - if (mcs == 30) - return 234000000; - if (mcs == 31) - return 260000000; + switch (mcs) { + case 0: return 6500000; + case 1: + case 8: return 13000000; + case 2: + case 16: return 19500000; + case 3: + case 9: + case 24: return 26000000; + case 4: + case 10: + case 17: return 39000000; + case 5: + case 11: + case 25: return 52000000; + case 6: + case 18: return 58500000; + case 7: return 65000000; + case 12: + case 19: + case 26: return 78000000; + case 13: + case 27: return 104000000; + case 14: + case 20: return 117000000; + case 15: return 130000000; + case 21: + case 28: return 156000000; + case 22: return 175500000; + case 23: return 195000000; + case 29: return 208000000; + case 30: return 234000000; + case 31: return 260000000; + } return 0; } static guint32 get_max_ht40_rate (int mcs) { - if (mcs == 0) - return 13500000; - if (mcs == (1 || 8)) - return 27000000; - if (mcs == 2) - return 40500000; - if (mcs == (3 || 9 || 24)) - return 54000000; - if (mcs == (4 || 10 || 17)) - return 81000000; - if (mcs == (5 || 11 || 25)) - return 108000000; - if (mcs == (6 || 18)) - return 121500000; - if (mcs == 7) - return 135000000; - if (mcs == (12 || 19 || 26)) - return 162000000; - if (mcs == (13 || 27)) - return 216000000; - if (mcs == (14 || 20)) - return 243000000; - if (mcs == 15) - return 270000000; - if (mcs == 16) - return 40500000; - if (mcs == (21 || 28)) - return 324000000; - if (mcs == 22) - return 364500000; - if (mcs == 23) - return 405000000; - if (mcs == 29) - return 432000000; - if (mcs == 30) - return 486000000; - if (mcs == 31) - return 540000000; + switch (mcs) { + case 0: return 13500000; + case 1: + case 8: return 27000000; + case 2: return 40500000; + case 3: + case 9: + case 24: return 54000000; + case 4: + case 10: + case 17: return 81000000; + case 5: + case 11: + case 25: return 108000000; + case 6: + case 18: return 121500000; + case 7: return 135000000; + case 12: + case 19: + case 26: return 162000000; + case 13: + case 27: return 216000000; + case 14: + case 20: return 243000000; + case 15: return 270000000; + case 16: return 40500000; + case 21: + case 28: return 324000000; + case 22: return 364500000; + case 23: return 405000000; + case 29: return 432000000; + case 30: return 486000000; + case 31: return 540000000; + } return 0; } static guint32 get_max_vht80_rate_ss1 (int mcs) { - if (mcs == 0) - return 29300000; - if (mcs == 1) - return 58500000; - if (mcs == 2) - return 87800000; - if (mcs == 3) - return 117000000; - if (mcs == 4) - return 175500000; - if (mcs == 5) - return 234000000; - if (mcs == 6) - return 263300000; - if (mcs == 7) - return 292500000; - if (mcs == 8) - return 351000000; - if (mcs == 9) - return 390000000; + switch (mcs) { + case 0: return 29300000; + case 1: return 58500000; + case 2: return 87800000; + case 3: return 117000000; + case 4: return 175500000; + case 5: return 234000000; + case 6: return 263300000; + case 7: return 292500000; + case 8: return 351000000; + case 9: return 390000000; + } return 0; } static guint32 get_max_vht80_rate_ss2 (int mcs) { - if (mcs == 0) - return 58500000; - if (mcs == 1) - return 117000000; - if (mcs == 2) - return 175500000; - if (mcs == 3) - return 234000000; - if (mcs == 4) - return 351000000; - if (mcs == 5) - return 468000000; - if (mcs == 6) - return 526500000; - if (mcs == 7) - return 585000000; - if (mcs == 8) - return 702000000; - if (mcs == 9) - return 780000000; + switch (mcs) { + case 0: return 58500000; + case 1: return 117000000; + case 2: return 175500000; + case 3: return 234000000; + case 4: return 351000000; + case 5: return 468000000; + case 6: return 526500000; + case 7: return 585000000; + case 8: return 702000000; + case 9: return 780000000; + } return 0; } static guint32 get_max_vht80_rate_ss3 (int mcs) { - if (mcs == 0) - return 87800000; - if (mcs == 1) - return 175500000; - if (mcs == 2) - return 263300000; - if (mcs == 3) - return 351000000; - if (mcs == 4) - return 526500000; - if (mcs == 5) - return 702000000; - if (mcs == 6) - return 0; - if (mcs == 7) - return 877500000; - if (mcs == 8) - return 105300000; - if (mcs == 9) - return 117000000; + switch (mcs) { + case 0: return 87800000; + case 1: return 175500000; + case 2: return 263300000; + case 3: return 351000000; + case 4: return 526500000; + case 5: return 702000000; + case 6: return 0; + case 7: return 877500000; + case 8: return 105300000; + case 9: return 117000000; + } return 0; } static guint32 get_max_vht160_rate_ss1 (int mcs) { - if (mcs == 0) - return 58500000; - if (mcs == 1) - return 117000000; - if (mcs == 2) - return 175500000; - if (mcs == 3) - return 234000000; - if (mcs == 4) - return 351000000; - if (mcs == 5) - return 468000000; - if (mcs == 6) - return 526500000; - if (mcs == 7) - return 585000000; - if (mcs == 8) - return 702000000; - if (mcs == 9) - return 780000000; + switch (mcs) { + case 0: return 58500000; + case 1: return 117000000; + case 2: return 175500000; + case 3: return 234000000; + case 4: return 351000000; + case 5: return 468000000; + case 6: return 526500000; + case 7: return 585000000; + case 8: return 702000000; + case 9: return 780000000; + } return 0; } static guint32 get_max_vht160_rate_ss2 (int mcs) { - if (mcs == 0) - return 117000000; - if (mcs == 1) - return 234000000; - if (mcs == 2) - return 351000000; - if (mcs == 3) - return 468000000; - if (mcs == 4) - return 702000000; - if (mcs == 5) - return 936000000; - if (mcs == 6) - return 1053000000; - if (mcs == 7) - return 1170000000; - if (mcs == 8) - return 1404000000; - if (mcs == 9) - return 1560000000; + switch (mcs) { + case 0: return 117000000; + case 1: return 234000000; + case 2: return 351000000; + case 3: return 468000000; + case 4: return 702000000; + case 5: return 936000000; + case 6: return 1053000000; + case 7: return 1170000000; + case 8: return 1404000000; + case 9: return 1560000000; + } return 0; } static guint32 get_max_vht160_rate_ss3 (int mcs) { - if (mcs == 0) - return 175500000; - if (mcs == 1) - return 351000000; - if (mcs == 2) - return 526500000; - if (mcs == 3) - return 702000000; - if (mcs == 4) - return 1053000000; - if (mcs == 5) - return 1404000000; - if (mcs == 6) - return 1579500000; - if (mcs == 7) - return 1755000000; - if (mcs == 8) - return 2106000000; - if (mcs == 9) - return 0; + switch (mcs) { + case 0: return 175500000; + case 1: return 351000000; + case 2: return 526500000; + case 3: return 702000000; + case 4: return 1053000000; + case 5: return 1404000000; + case 6: return 1579500000; + case 7: return 1755000000; + case 8: return 2106000000; + case 9: return 0; + } return 0; } From b0016d47f16fc58e8f4722fd5e6b946c655d1295 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 9 Mar 2017 11:50:34 +0100 Subject: [PATCH 06/12] wifi: fix unsigned error return value for get_max_rate() Signal error via 0, not -1. Also, if the length of the array is unexpected, error out. --- src/devices/wifi/nm-wifi-ap.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index bc6d0c665d..886a85ddbb 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -687,14 +687,16 @@ get_max_rate (const guint8 *bytes, gsize len) guint8 id, elem_len; guint32 max_rate = 0; - while (len >= 2) { + while (len) { + if (len < 2) + return 0; + id = *bytes++; elem_len = *bytes++; len -= 2; - if (elem_len > len) { - return -1; - } + if (elem_len > len) + return 0; if (id == IEEE_80211_IE_HT_CAP) max_rate = get_max_ht_rate (*bytes, bytes+3); From 5bd7ff2ec059ed99d1ab81fc71ff9b20aa5c8a14 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 9 Mar 2017 22:11:55 +0100 Subject: [PATCH 07/12] wifi: collect maximum max-bitrate in nm_wifi_ap_update_from_properties() --- src/devices/wifi/nm-wifi-ap.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index 886a85ddbb..303a610320 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -720,11 +720,13 @@ nm_wifi_ap_update_from_properties (NMWifiAP *ap, const guint8 *bytes; GVariant *v; gsize len; + gsize i; gboolean b = FALSE; const char *s; gint16 i16; guint16 u16; gboolean changed = FALSE; + guint32 max_rate; g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); g_return_val_if_fail (properties, FALSE); @@ -773,32 +775,23 @@ nm_wifi_ap_update_from_properties (NMWifiAP *ap, g_variant_unref (v); } + max_rate = 0; v = g_variant_lookup_value (properties, "Rates", G_VARIANT_TYPE ("au")); if (v) { const guint32 *rates = g_variant_get_fixed_array (v, &len, sizeof (guint32)); - guint32 maxrate = 0; - int i; - /* Find the max AP rate */ - for (i = 0; i < len; i++) { - if (rates[i] > maxrate) - maxrate = rates[i]; - } - if (maxrate) - changed |= nm_wifi_ap_set_max_bitrate (ap, maxrate / 1000); + for (i = 0; i < len; i++) + max_rate = NM_MAX (max_rate, rates[i]); g_variant_unref (v); } - v = g_variant_lookup_value (properties, "IEs", G_VARIANT_TYPE_BYTESTRING); if (v) { - guint32 max_rate; - bytes = g_variant_get_fixed_array (v, &len, 1); - max_rate = get_max_rate (bytes, len); - if (max_rate > 0) - changed |= nm_wifi_ap_set_max_bitrate (ap, max_rate / 1000); + max_rate = NM_MAX (max_rate, get_max_rate (bytes, len)); g_variant_unref (v); } + if (max_rate) + changed |= nm_wifi_ap_set_max_bitrate (ap, max_rate / 1000); v = g_variant_lookup_value (properties, "WPA", G_VARIANT_TYPE_VARDICT); if (v) { From 0c6097ccbe0af832eaab50beb637a8c75108fd46 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 9 Mar 2017 23:28:36 +0100 Subject: [PATCH 08/12] wifi/trivial: rename get_max_rate*() functions --- src/devices/wifi/nm-wifi-ap.c | 44 +++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index 303a610320..99b8681f06 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -435,8 +435,10 @@ security_from_vardict (GVariant *security) return flags; } +/*****************************************************************************/ + static guint32 -get_max_ht20_rate (int mcs) +get_max_rate_ht_20 (int mcs) { switch (mcs) { case 0: return 6500000; @@ -476,7 +478,7 @@ get_max_ht20_rate (int mcs) } static guint32 -get_max_ht40_rate (int mcs) +get_max_rate_ht_40 (int mcs) { switch (mcs) { case 0: return 13500000; @@ -516,7 +518,7 @@ get_max_ht40_rate (int mcs) } static guint32 -get_max_vht80_rate_ss1 (int mcs) +get_max_rate_vht_80_ss1 (int mcs) { switch (mcs) { case 0: return 29300000; @@ -534,7 +536,7 @@ get_max_vht80_rate_ss1 (int mcs) } static guint32 -get_max_vht80_rate_ss2 (int mcs) +get_max_rate_vht_80_ss2 (int mcs) { switch (mcs) { case 0: return 58500000; @@ -552,7 +554,7 @@ get_max_vht80_rate_ss2 (int mcs) } static guint32 -get_max_vht80_rate_ss3 (int mcs) +get_max_rate_vht_80_ss3 (int mcs) { switch (mcs) { case 0: return 87800000; @@ -570,7 +572,7 @@ get_max_vht80_rate_ss3 (int mcs) } static guint32 -get_max_vht160_rate_ss1 (int mcs) +get_max_rate_vht_160_ss1 (int mcs) { switch (mcs) { case 0: return 58500000; @@ -588,7 +590,7 @@ get_max_vht160_rate_ss1 (int mcs) } static guint32 -get_max_vht160_rate_ss2 (int mcs) +get_max_rate_vht_160_ss2 (int mcs) { switch (mcs) { case 0: return 117000000; @@ -606,7 +608,7 @@ get_max_vht160_rate_ss2 (int mcs) } static guint32 -get_max_vht160_rate_ss3 (int mcs) +get_max_rate_vht_160_ss3 (int mcs) { switch (mcs) { case 0: return 175500000; @@ -624,7 +626,7 @@ get_max_vht160_rate_ss3 (int mcs) } static guint32 -get_max_ht_rate (guint16 ht_cap_info, const guint8 *supported_mcs_set) +get_max_rate_ht (guint16 ht_cap_info, const guint8 *supported_mcs_set) { guint32 mcs, i, j; @@ -640,14 +642,14 @@ get_max_ht_rate (guint16 ht_cap_info, const guint8 *supported_mcs_set) /* Check for 40Mhz wide channel support */ if (ht_cap_info & (1 << 1)) - return get_max_ht40_rate (mcs); + return get_max_rate_ht_40 (mcs); else - return get_max_ht20_rate (mcs); + return get_max_rate_ht_20 (mcs); } static guint32 -get_max_vht_rate (guint32 vht_cap, guint16 tx_map) +get_max_rate_vht (guint32 vht_cap, guint16 tx_map) { guint32 mcs = 7; @@ -661,18 +663,18 @@ get_max_vht_rate (guint32 vht_cap, guint16 tx_map) * spatial stream support */ if (vht_cap & (1 << 2)) { if (tx_map & 0x30) - return get_max_vht160_rate_ss3 (mcs); + return get_max_rate_vht_160_ss3 (mcs); else if (tx_map & 0x0C) - return get_max_vht160_rate_ss2 (mcs); + return get_max_rate_vht_160_ss2 (mcs); else - return get_max_vht160_rate_ss1 (mcs); + return get_max_rate_vht_160_ss1 (mcs); } else { if (tx_map & 0x30) - return get_max_vht80_rate_ss3 (mcs); + return get_max_rate_vht_80_ss3 (mcs); else if (tx_map & 0x0C) - return get_max_vht80_rate_ss2 (mcs); + return get_max_rate_vht_80_ss2 (mcs); else - return get_max_vht80_rate_ss1 (mcs); + return get_max_rate_vht_80_ss1 (mcs); } return 0; @@ -699,10 +701,10 @@ get_max_rate (const guint8 *bytes, gsize len) return 0; if (id == IEEE_80211_IE_HT_CAP) - max_rate = get_max_ht_rate (*bytes, bytes+3); + max_rate = get_max_rate_ht (*bytes, bytes+3); if (id == IEEE_80211_IE_VHT_CAP) - max_rate = get_max_vht_rate (*bytes, *(bytes+8)); + max_rate = get_max_rate_vht (*bytes, *(bytes+8)); len -= elem_len; bytes += elem_len; @@ -711,6 +713,8 @@ get_max_rate (const guint8 *bytes, gsize len) return max_rate; } +/*****************************************************************************/ + gboolean nm_wifi_ap_update_from_properties (NMWifiAP *ap, const char *supplicant_path, From 961d572472dce5b7ae0cae7d614f66548322cdbc Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 9 Mar 2017 23:42:21 +0100 Subject: [PATCH 09/12] wifi: rename ieee80211_eid capability defines IEEE_80211_IE_VHT_CAP has zero hits searching the internet. WLAN_EID_VHT_CAPABILITY is how the same define is called by kernel's "include/linux/ieee80211.h". Use the same name as kernel. Also, collect the maximum of @max_rate. --- src/devices/wifi/nm-wifi-ap.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index 99b8681f06..a923cf245a 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -680,8 +680,9 @@ get_max_rate_vht (guint32 vht_cap, guint16 tx_map) return 0; } -#define IEEE_80211_IE_HT_CAP 45 -#define IEEE_80211_IE_VHT_CAP 191 +/* Management Frame Information Element IDs, ieee80211_eid */ +#define WLAN_EID_HT_CAPABILITY 45 +#define WLAN_EID_VHT_CAPABILITY 191 static guint32 get_max_rate (const guint8 *bytes, gsize len) @@ -700,11 +701,14 @@ get_max_rate (const guint8 *bytes, gsize len) if (elem_len > len) return 0; - if (id == IEEE_80211_IE_HT_CAP) - max_rate = get_max_rate_ht (*bytes, bytes+3); - - if (id == IEEE_80211_IE_VHT_CAP) - max_rate = get_max_rate_vht (*bytes, *(bytes+8)); + switch (id) { + case WLAN_EID_HT_CAPABILITY: + max_rate = NM_MAX (max_rate, get_max_rate_ht (*bytes, bytes+3)); + break; + case WLAN_EID_VHT_CAPABILITY: + max_rate = NM_MAX (max_rate, get_max_rate_vht (*bytes, *(bytes+8))); + break; + } len -= elem_len; bytes += elem_len; From 2b64961d05cbda26f94d5ec8f587a6e896a4479e Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 10 Mar 2017 00:24:16 +0100 Subject: [PATCH 10/12] wifi: avoid buffer overflow reading IEs --- src/devices/wifi/nm-wifi-ap.c | 66 ++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 17 deletions(-) diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index a923cf245a..91fc65ed12 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -625,10 +625,21 @@ get_max_rate_vht_160_ss3 (int mcs) return 0; } -static guint32 -get_max_rate_ht (guint16 ht_cap_info, const guint8 *supported_mcs_set) +static gboolean +get_max_rate_ht (const guint8 *bytes, guint len, guint32 *out_maxrate) { - guint32 mcs, i, j; + guint32 mcs, i, j, m; + guint8 ht_cap_info; + const guint8 *supported_mcs_set; + + /* https://mrncciew.com/2014/10/19/cwap-ht-capabilities-ie/ + http://luci.subsignal.org/~jow/802.11n-2009.pdf */ + + if (len != 26) + return FALSE; + + ht_cap_info = bytes[0]; + supported_mcs_set = &bytes[3]; /* Find the maximum supported mcs rate */ mcs = -1; @@ -642,42 +653,57 @@ get_max_rate_ht (guint16 ht_cap_info, const guint8 *supported_mcs_set) /* Check for 40Mhz wide channel support */ if (ht_cap_info & (1 << 1)) - return get_max_rate_ht_40 (mcs); + m = get_max_rate_ht_40 (mcs); else - return get_max_rate_ht_20 (mcs); + m = get_max_rate_ht_20 (mcs); + *out_maxrate = m; + return TRUE; } -static guint32 -get_max_rate_vht (guint32 vht_cap, guint16 tx_map) +static gboolean +get_max_rate_vht (const guint8 *bytes, guint len, guint32 *out_maxrate) { - guint32 mcs = 7; + guint32 mcs, m; + guint8 vht_cap, tx_map; + + /* https://tda802dot11.blogspot.it/2014/10/vht-capabilities-element-vht.html + * http://chimera.labs.oreilly.com/books/1234000001739/ch03.html#management_frames */ + + if (len != 12) + return FALSE; + + vht_cap = bytes[0]; + tx_map = bytes[8]; /* Check for mcs rates 8 and 9 support */ if (tx_map & 0x2a) mcs = 9; else if (tx_map & 0x15) mcs = 8; + else + mcs = 7; /* Check for 160Mhz wide channel support and * spatial stream support */ if (vht_cap & (1 << 2)) { if (tx_map & 0x30) - return get_max_rate_vht_160_ss3 (mcs); + m = get_max_rate_vht_160_ss3 (mcs); else if (tx_map & 0x0C) - return get_max_rate_vht_160_ss2 (mcs); + m = get_max_rate_vht_160_ss2 (mcs); else - return get_max_rate_vht_160_ss1 (mcs); + m = get_max_rate_vht_160_ss1 (mcs); } else { if (tx_map & 0x30) - return get_max_rate_vht_80_ss3 (mcs); + m = get_max_rate_vht_80_ss3 (mcs); else if (tx_map & 0x0C) - return get_max_rate_vht_80_ss2 (mcs); + m = get_max_rate_vht_80_ss2 (mcs); else - return get_max_rate_vht_80_ss1 (mcs); + m = get_max_rate_vht_80_ss1 (mcs); } - return 0; + *out_maxrate = m; + return TRUE; } /* Management Frame Information Element IDs, ieee80211_eid */ @@ -691,6 +717,8 @@ get_max_rate (const guint8 *bytes, gsize len) guint32 max_rate = 0; while (len) { + guint32 m; + if (len < 2) return 0; @@ -703,10 +731,14 @@ get_max_rate (const guint8 *bytes, gsize len) switch (id) { case WLAN_EID_HT_CAPABILITY: - max_rate = NM_MAX (max_rate, get_max_rate_ht (*bytes, bytes+3)); + if (!get_max_rate_ht (bytes, elem_len, &m)) + return 0; + max_rate = NM_MAX (max_rate, m); break; case WLAN_EID_VHT_CAPABILITY: - max_rate = NM_MAX (max_rate, get_max_rate_vht (*bytes, *(bytes+8))); + if (!get_max_rate_vht (bytes, elem_len, &m)) + return 0; + max_rate = NM_MAX (max_rate, m); break; } From cd91b7e1190177942252dd1a759be82037a7a2a7 Mon Sep 17 00:00:00 2001 From: James Kalbfleisch Date: Mon, 27 Mar 2017 13:11:56 -0400 Subject: [PATCH 11/12] wifi: parse the first 77 bits of the supported mcs set --- src/devices/wifi/nm-wifi-ap.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index 91fc65ed12..e477c8e86d 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -628,7 +628,7 @@ get_max_rate_vht_160_ss3 (int mcs) static gboolean get_max_rate_ht (const guint8 *bytes, guint len, guint32 *out_maxrate) { - guint32 mcs, i, j, m; + guint32 mcs, i, m; guint8 ht_cap_info; const guint8 *supported_mcs_set; @@ -643,12 +643,12 @@ get_max_rate_ht (const guint8 *bytes, guint len, guint32 *out_maxrate) /* Find the maximum supported mcs rate */ mcs = -1; - for (i = 0; i <= 15; i++) { - for (j = 0; j <= 7; j++) { - if (*supported_mcs_set & (1 << j)) - mcs++; - } - supported_mcs_set++; + for (i = 0; i <= 76; i++) { + unsigned int mcs_octet = i/8; + unsigned int MCS_RATE_BIT = 1 << i % 8; + + if (supported_mcs_set[mcs_octet] & MCS_RATE_BIT) + mcs = i; } /* Check for 40Mhz wide channel support */ From 21c22f2f96311fbd9d2d1e3951e52a96356757e8 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Wed, 5 Apr 2017 09:13:38 +0200 Subject: [PATCH 12/12] wifi: fix HT max rate calculation The rates of MCSs are not monotonically increasing. --- src/devices/wifi/nm-wifi-ap.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index e477c8e86d..c45eaafa93 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -628,36 +628,40 @@ get_max_rate_vht_160_ss3 (int mcs) static gboolean get_max_rate_ht (const guint8 *bytes, guint len, guint32 *out_maxrate) { - guint32 mcs, i, m; + guint32 mcs, i; guint8 ht_cap_info; const guint8 *supported_mcs_set; + guint32 rate; - /* https://mrncciew.com/2014/10/19/cwap-ht-capabilities-ie/ - http://luci.subsignal.org/~jow/802.11n-2009.pdf */ + /* http://standards.ieee.org/getieee802/download/802.11-2012.pdf + * https://mrncciew.com/2014/10/19/cwap-ht-capabilities-ie/ + */ if (len != 26) return FALSE; ht_cap_info = bytes[0]; supported_mcs_set = &bytes[3]; + *out_maxrate = 0; /* Find the maximum supported mcs rate */ mcs = -1; for (i = 0; i <= 76; i++) { - unsigned int mcs_octet = i/8; + unsigned int mcs_octet = i / 8; unsigned int MCS_RATE_BIT = 1 << i % 8; - if (supported_mcs_set[mcs_octet] & MCS_RATE_BIT) - mcs = i; + if (supported_mcs_set[mcs_octet] & MCS_RATE_BIT) { + /* Check for 40Mhz wide channel support */ + if (ht_cap_info & (1 << 1)) + rate = get_max_rate_ht_40 (i); + else + rate = get_max_rate_ht_20 (i); + + if (rate > *out_maxrate) + *out_maxrate = rate; + } } - /* Check for 40Mhz wide channel support */ - if (ht_cap_info & (1 << 1)) - m = get_max_rate_ht_40 (mcs); - else - m = get_max_rate_ht_20 (mcs); - - *out_maxrate = m; return TRUE; }