wifi: merge branch 'th/wifi-ap-max-rate-bgo779771'

https://bugzilla.gnome.org/show_bug.cgi?id=779771
This commit is contained in:
Beniamino Galvani 2017-04-10 13:38:12 +02:00
commit 608ac31e87

View file

@ -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;
};
@ -435,6 +435,326 @@ security_from_vardict (GVariant *security)
return flags;
}
/*****************************************************************************/
static guint32
get_max_rate_ht_20 (int mcs)
{
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_rate_ht_40 (int mcs)
{
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_rate_vht_80_ss1 (int mcs)
{
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_rate_vht_80_ss2 (int mcs)
{
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_rate_vht_80_ss3 (int mcs)
{
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_rate_vht_160_ss1 (int mcs)
{
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_rate_vht_160_ss2 (int mcs)
{
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_rate_vht_160_ss3 (int mcs)
{
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;
}
static gboolean
get_max_rate_ht (const guint8 *bytes, guint len, guint32 *out_maxrate)
{
guint32 mcs, i;
guint8 ht_cap_info;
const guint8 *supported_mcs_set;
guint32 rate;
/* 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_RATE_BIT = 1 << i % 8;
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;
}
}
return TRUE;
}
static gboolean
get_max_rate_vht (const guint8 *bytes, guint len, guint32 *out_maxrate)
{
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)
m = get_max_rate_vht_160_ss3 (mcs);
else if (tx_map & 0x0C)
m = get_max_rate_vht_160_ss2 (mcs);
else
m = get_max_rate_vht_160_ss1 (mcs);
} else {
if (tx_map & 0x30)
m = get_max_rate_vht_80_ss3 (mcs);
else if (tx_map & 0x0C)
m = get_max_rate_vht_80_ss2 (mcs);
else
m = get_max_rate_vht_80_ss1 (mcs);
}
*out_maxrate = m;
return TRUE;
}
/* 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)
{
guint8 id, elem_len;
guint32 max_rate = 0;
while (len) {
guint32 m;
if (len < 2)
return 0;
id = *bytes++;
elem_len = *bytes++;
len -= 2;
if (elem_len > len)
return 0;
switch (id) {
case WLAN_EID_HT_CAPABILITY:
if (!get_max_rate_ht (bytes, elem_len, &m))
return 0;
max_rate = NM_MAX (max_rate, m);
break;
case WLAN_EID_VHT_CAPABILITY:
if (!get_max_rate_vht (bytes, elem_len, &m))
return 0;
max_rate = NM_MAX (max_rate, m);
break;
}
len -= elem_len;
bytes += elem_len;
}
return max_rate;
}
/*****************************************************************************/
gboolean
nm_wifi_ap_update_from_properties (NMWifiAP *ap,
const char *supplicant_path,
@ -444,11 +764,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);
@ -497,21 +819,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) {
bytes = g_variant_get_fixed_array (v, &len, 1);
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) {