diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index a923cf245..91fc65ed1 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; }