wifi: parse access point announced bandwidth
Parse the access point announced bandwidth in MHz. This is considering both HT and VHT. Please notice that for VHT 80+80 MHz we are representing it as 160 MHz.
This commit is contained in:
@@ -79,6 +79,13 @@
|
||||
-->
|
||||
<property name="MaxBitrate" type="u" access="read"/>
|
||||
|
||||
<!--
|
||||
Bandwidth:
|
||||
|
||||
The bandwidth announced by the access point in MHz.
|
||||
-->
|
||||
<property name="Bandwidth" type="u" access="read"/>
|
||||
|
||||
<!--
|
||||
Strength:
|
||||
|
||||
|
@@ -36,6 +36,7 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMWifiAP,
|
||||
PROP_HW_ADDRESS,
|
||||
PROP_MODE,
|
||||
PROP_MAX_BITRATE,
|
||||
PROP_BANDWIDTH,
|
||||
PROP_STRENGTH,
|
||||
PROP_LAST_SEEN, );
|
||||
|
||||
@@ -47,6 +48,7 @@ struct _NMWifiAPPrivate {
|
||||
guint8 strength;
|
||||
guint32 freq; /* Frequency in MHz; ie 2412 (== 2.412 GHz) */
|
||||
guint32 max_bitrate; /* Maximum bitrate of the AP in Kbit/s (ie 54000 Kb/s == 54Mbit/s) */
|
||||
guint32 bandwidth; /* Bandwidth of the AP in MHz */
|
||||
|
||||
gint64
|
||||
last_seen_msec; /* Timestamp when the AP was seen lastly (in nm_utils_get_monotonic_timestamp_*() scale).
|
||||
@@ -277,6 +279,32 @@ nm_wifi_ap_get_max_bitrate(NMWifiAP *ap)
|
||||
return NM_WIFI_AP_GET_PRIVATE(ap)->max_bitrate;
|
||||
}
|
||||
|
||||
guint32
|
||||
nm_wifi_ap_get_bandwidth(NMWifiAP *ap)
|
||||
{
|
||||
g_return_val_if_fail(NM_IS_WIFI_AP(ap), 0);
|
||||
g_return_val_if_fail(nm_dbus_object_is_exported(NM_DBUS_OBJECT(ap)), 0);
|
||||
|
||||
return NM_WIFI_AP_GET_PRIVATE(ap)->bandwidth;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_wifi_ap_set_bandwidth(NMWifiAP *ap, guint32 bandwidth)
|
||||
{
|
||||
NMWifiAPPrivate *priv;
|
||||
|
||||
g_return_val_if_fail(NM_IS_WIFI_AP(ap), FALSE);
|
||||
|
||||
priv = NM_WIFI_AP_GET_PRIVATE(ap);
|
||||
|
||||
if (priv->bandwidth != bandwidth) {
|
||||
priv->bandwidth = bandwidth;
|
||||
_notify(ap, PROP_BANDWIDTH);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_wifi_ap_set_max_bitrate(NMWifiAP *ap, guint32 bitrate)
|
||||
{
|
||||
@@ -393,6 +421,7 @@ nm_wifi_ap_update_from_properties(NMWifiAP *ap, const NMSupplicantBssInfo *bss_i
|
||||
}
|
||||
|
||||
changed |= nm_wifi_ap_set_max_bitrate(ap, bss_info->max_rate);
|
||||
changed |= nm_wifi_ap_set_bandwidth(ap, bss_info->bandwidth);
|
||||
|
||||
if (priv->metered != bss_info->metered) {
|
||||
priv->metered = bss_info->metered;
|
||||
@@ -683,6 +712,9 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
|
||||
case PROP_MAX_BITRATE:
|
||||
g_value_set_uint(value, priv->max_bitrate);
|
||||
break;
|
||||
case PROP_BANDWIDTH:
|
||||
g_value_set_uint(value, priv->bandwidth);
|
||||
break;
|
||||
case PROP_STRENGTH:
|
||||
g_value_set_uchar(value, priv->strength);
|
||||
break;
|
||||
@@ -873,6 +905,7 @@ static const NMDBusInterfaceInfoExtended interface_info_access_point = {
|
||||
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("MaxBitrate",
|
||||
"u",
|
||||
NM_WIFI_AP_MAX_BITRATE),
|
||||
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Bandwidth", "u", NM_WIFI_AP_BANDWIDTH),
|
||||
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Strength", "y", NM_WIFI_AP_STRENGTH),
|
||||
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("LastSeen",
|
||||
"i",
|
||||
@@ -979,6 +1012,14 @@ nm_wifi_ap_class_init(NMWifiAPClass *ap_class)
|
||||
-1,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
obj_properties[PROP_BANDWIDTH] = g_param_spec_uint(NM_WIFI_AP_BANDWIDTH,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
G_MAXUINT32,
|
||||
0,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
|
||||
}
|
||||
|
||||
|
@@ -27,6 +27,7 @@
|
||||
#define NM_WIFI_AP_HW_ADDRESS "hw-address"
|
||||
#define NM_WIFI_AP_MODE "mode"
|
||||
#define NM_WIFI_AP_MAX_BITRATE "max-bitrate"
|
||||
#define NM_WIFI_AP_BANDWIDTH "bandwidth"
|
||||
#define NM_WIFI_AP_STRENGTH "strength"
|
||||
#define NM_WIFI_AP_LAST_SEEN "last-seen"
|
||||
|
||||
@@ -78,6 +79,8 @@ guint32 nm_wifi_ap_get_freq(NMWifiAP *ap);
|
||||
gboolean nm_wifi_ap_set_freq(NMWifiAP *ap, guint32 freq);
|
||||
guint32 nm_wifi_ap_get_max_bitrate(NMWifiAP *ap);
|
||||
gboolean nm_wifi_ap_set_max_bitrate(NMWifiAP *ap, guint32 bitrate);
|
||||
guint32 nm_wifi_ap_get_bandwidth(NMWifiAP *ap);
|
||||
gboolean nm_wifi_ap_set_bandwidth(NMWifiAP *ap, guint32 bandwidth);
|
||||
gboolean nm_wifi_ap_get_fake(const NMWifiAP *ap);
|
||||
gboolean nm_wifi_ap_set_fake(NMWifiAP *ap, gboolean fake);
|
||||
NM80211ApFlags nm_wifi_ap_get_flags(const NMWifiAP *self);
|
||||
|
@@ -4779,15 +4779,91 @@ get_max_rate_vht(const guint8 *bytes, guint len, guint32 *out_maxrate)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_bandwidth_ht(const guint8 *bytes, guint len, guint32 *out_bandwidth)
|
||||
{
|
||||
guint8 ht_op_flag_group;
|
||||
|
||||
/* http://standards.ieee.org/getieee802/download/802.11-2012.pdf
|
||||
* https://mrncciew.com/2014/11/04/cwap-ht-operations-ie/
|
||||
* IEEE std 802.11-2020 section 9.4.2.56
|
||||
*/
|
||||
|
||||
if (len != 22)
|
||||
return FALSE;
|
||||
|
||||
ht_op_flag_group = bytes[1];
|
||||
|
||||
/* Check bit for 20Mhz or 40Mhz */
|
||||
if (ht_op_flag_group & (1 << 2))
|
||||
*out_bandwidth = 40;
|
||||
else
|
||||
*out_bandwidth = 20;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_bandwidth_vht(const guint8 *bytes, guint len, guint32 *out_bandwidth)
|
||||
{
|
||||
guint8 sta_channel_width;
|
||||
guint8 ccfs0;
|
||||
guint8 ccfs1;
|
||||
|
||||
/* http://chimera.labs.oreilly.com/books/1234000001739/ch03.html#management_frames
|
||||
* https://community.arubanetworks.com/community-home/librarydocuments/viewdocument?DocumentKey=799aad1b-d9c4-421a-a492-a111e8680d34&CommunityKey=39a6bdf4-2376-46f9-853a-49420d2d0caa&tab=librarydocuments
|
||||
* IEEE Std 802.11-2020 section 9.4.2.158
|
||||
*/
|
||||
|
||||
if (len < 3)
|
||||
return FALSE;
|
||||
|
||||
sta_channel_width = bytes[0];
|
||||
ccfs0 = bytes[1];
|
||||
ccfs1 = bytes[2];
|
||||
switch (sta_channel_width) {
|
||||
case 0:
|
||||
/* we rely on HT Operation IE value*/
|
||||
return FALSE;
|
||||
case 1:
|
||||
if (ccfs1 == 0)
|
||||
*out_bandwidth = 80;
|
||||
else if (abs(ccfs1 - ccfs0) == 8)
|
||||
*out_bandwidth = 160;
|
||||
else if (abs(ccfs1 - ccfs0) > 16)
|
||||
/* we are considering 80+80 as 160 */
|
||||
*out_bandwidth = 160;
|
||||
else
|
||||
/* falling back to 80 MHz */
|
||||
*out_bandwidth = 80;
|
||||
break;
|
||||
case 2:
|
||||
/* deprecated */
|
||||
*out_bandwidth = 160;
|
||||
break;
|
||||
case 3:
|
||||
/* deprecated */
|
||||
*out_bandwidth = 160;
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Management Frame Information Element IDs, ieee80211_eid */
|
||||
#define WLAN_EID_HT_CAPABILITY 45
|
||||
#define WLAN_EID_HT_OPERATION 61
|
||||
#define WLAN_EID_VHT_CAPABILITY 191
|
||||
#define WLAN_EID_VHT_OPERATION 192
|
||||
#define WLAN_EID_VENDOR_SPECIFIC 221
|
||||
|
||||
void
|
||||
nm_wifi_utils_parse_ies(const guint8 *bytes,
|
||||
gsize len,
|
||||
guint32 *out_max_rate,
|
||||
guint32 *out_bandwidth,
|
||||
gboolean *out_metered,
|
||||
gboolean *out_owe_transition_mode)
|
||||
{
|
||||
@@ -4795,6 +4871,7 @@ nm_wifi_utils_parse_ies(const guint8 *bytes,
|
||||
guint32 m;
|
||||
|
||||
NM_SET_OUT(out_max_rate, 0);
|
||||
NM_SET_OUT(out_bandwidth, 0);
|
||||
NM_SET_OUT(out_metered, FALSE);
|
||||
NM_SET_OUT(out_owe_transition_mode, FALSE);
|
||||
|
||||
@@ -4816,12 +4893,20 @@ nm_wifi_utils_parse_ies(const guint8 *bytes,
|
||||
*out_max_rate = NM_MAX(*out_max_rate, m);
|
||||
}
|
||||
break;
|
||||
case WLAN_EID_HT_OPERATION:
|
||||
if (out_bandwidth)
|
||||
get_bandwidth_ht(bytes, elem_len, out_bandwidth);
|
||||
break;
|
||||
case WLAN_EID_VHT_CAPABILITY:
|
||||
if (out_max_rate) {
|
||||
if (get_max_rate_vht(bytes, elem_len, &m))
|
||||
*out_max_rate = NM_MAX(*out_max_rate, m);
|
||||
}
|
||||
break;
|
||||
case WLAN_EID_VHT_OPERATION:
|
||||
if (out_bandwidth)
|
||||
get_bandwidth_vht(bytes, elem_len, out_bandwidth);
|
||||
break;
|
||||
case WLAN_EID_VENDOR_SPECIFIC:
|
||||
if (len == 8 && bytes[0] == 0x00 /* OUI: Microsoft */
|
||||
&& bytes[1] == 0x50 && bytes[2] == 0xf2
|
||||
|
@@ -455,6 +455,7 @@ const char *nm_utils_parse_dns_domain(const char *domain, gboolean *is_routing);
|
||||
void nm_wifi_utils_parse_ies(const guint8 *bytes,
|
||||
gsize len,
|
||||
guint32 *out_max_rate,
|
||||
guint32 *out_bandwidth,
|
||||
gboolean *out_metered,
|
||||
gboolean *out_owe_transition_mode);
|
||||
|
||||
|
@@ -765,9 +765,15 @@ _bss_info_properties_changed(NMSupplicantInterface *self,
|
||||
gboolean p_owe_transition_mode;
|
||||
gboolean p_metered;
|
||||
guint32 rate;
|
||||
guint32 bandwidth;
|
||||
|
||||
arr_data = g_variant_get_fixed_array(v_v, &arr_len, 1);
|
||||
nm_wifi_utils_parse_ies(arr_data, arr_len, &rate, &p_metered, &p_owe_transition_mode);
|
||||
nm_wifi_utils_parse_ies(arr_data,
|
||||
arr_len,
|
||||
&rate,
|
||||
&bandwidth,
|
||||
&p_metered,
|
||||
&p_owe_transition_mode);
|
||||
p_max_rate = NM_MAX(p_max_rate, rate);
|
||||
p_max_rate_has = TRUE;
|
||||
g_variant_unref(v_v);
|
||||
@@ -778,6 +784,7 @@ _bss_info_properties_changed(NMSupplicantInterface *self,
|
||||
bss_info->rsn_flags &= ~NM_802_11_AP_SEC_KEY_MGMT_OWE_TM;
|
||||
|
||||
bss_info->metered = p_metered;
|
||||
bss_info->bandwidth = bandwidth;
|
||||
}
|
||||
|
||||
if (p_max_rate_has)
|
||||
|
@@ -179,6 +179,8 @@ typedef struct _NMSupplicantBssInfo {
|
||||
|
||||
guint32 max_rate;
|
||||
|
||||
guint32 bandwidth;
|
||||
|
||||
guint8 signal_percent;
|
||||
|
||||
NMEtherAddr bssid;
|
||||
|
@@ -1943,3 +1943,8 @@ global:
|
||||
nm_setting_link_get_type;
|
||||
nm_setting_link_new;
|
||||
} libnm_1_42_0;
|
||||
|
||||
libnm_1_46_0 {
|
||||
global:
|
||||
nm_access_point_get_bandwidth;
|
||||
} libnm_1_44_0;
|
||||
|
@@ -30,6 +30,7 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMAccessPoint,
|
||||
PROP_HW_ADDRESS,
|
||||
PROP_MODE,
|
||||
PROP_MAX_BITRATE,
|
||||
PROP_BANDWIDTH,
|
||||
PROP_STRENGTH,
|
||||
PROP_BSSID,
|
||||
PROP_LAST_SEEN, );
|
||||
@@ -43,6 +44,7 @@ typedef struct {
|
||||
guint32 frequency;
|
||||
guint32 mode;
|
||||
guint32 max_bitrate;
|
||||
guint32 bandwidth;
|
||||
gint32 last_seen;
|
||||
guint8 strength;
|
||||
} NMAccessPointPrivate;
|
||||
@@ -198,6 +200,24 @@ nm_access_point_get_max_bitrate(NMAccessPoint *ap)
|
||||
return NM_ACCESS_POINT_GET_PRIVATE(ap)->max_bitrate;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_access_point_get_bandwidth:
|
||||
* @ap: a #NMAccessPoint
|
||||
*
|
||||
* Gets the bandwidth advertised by the access point in MHz.
|
||||
*
|
||||
* Returns: the advertised bandwidth (MHz)
|
||||
*
|
||||
* Since: 1.46
|
||||
**/
|
||||
guint32
|
||||
nm_access_point_get_bandwidth(NMAccessPoint *ap)
|
||||
{
|
||||
g_return_val_if_fail(NM_IS_ACCESS_POINT(ap), 0);
|
||||
|
||||
return NM_ACCESS_POINT_GET_PRIVATE(ap)->bandwidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_access_point_get_strength:
|
||||
* @ap: a #NMAccessPoint
|
||||
@@ -463,6 +483,9 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
|
||||
case PROP_MAX_BITRATE:
|
||||
g_value_set_uint(value, nm_access_point_get_max_bitrate(ap));
|
||||
break;
|
||||
case PROP_BANDWIDTH:
|
||||
g_value_set_uint(value, nm_access_point_get_bandwidth(ap));
|
||||
break;
|
||||
case PROP_STRENGTH:
|
||||
g_value_set_uchar(value, nm_access_point_get_strength(ap));
|
||||
break;
|
||||
@@ -480,6 +503,7 @@ const NMLDBusMetaIface _nml_dbus_meta_iface_nm_accesspoint = NML_DBUS_META_IFACE
|
||||
nm_access_point_get_type,
|
||||
NML_DBUS_META_INTERFACE_PRIO_INSTANTIATE_30,
|
||||
NML_DBUS_META_IFACE_DBUS_PROPERTIES(
|
||||
NML_DBUS_META_PROPERTY_INIT_U("Bandwidth", PROP_BANDWIDTH, NMAccessPoint, _priv.bandwidth),
|
||||
NML_DBUS_META_PROPERTY_INIT_U("Flags", PROP_FLAGS, NMAccessPoint, _priv.flags),
|
||||
NML_DBUS_META_PROPERTY_INIT_U("Frequency", PROP_FREQUENCY, NMAccessPoint, _priv.frequency),
|
||||
NML_DBUS_META_PROPERTY_INIT_FCN("HwAddress",
|
||||
@@ -620,6 +644,21 @@ nm_access_point_class_init(NMAccessPointClass *ap_class)
|
||||
0,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* NMAccessPoint:bandwidth:
|
||||
*
|
||||
* The channel bandwidth announced by the AP in MHz.
|
||||
*
|
||||
* Since: 1.46
|
||||
**/
|
||||
obj_properties[PROP_BANDWIDTH] = g_param_spec_uint(NM_ACCESS_POINT_BANDWIDTH,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
G_MAXUINT32,
|
||||
0,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* NMAccessPoint:strength:
|
||||
*
|
||||
|
@@ -35,6 +35,7 @@ G_BEGIN_DECLS
|
||||
#define NM_ACCESS_POINT_MAX_BITRATE "max-bitrate"
|
||||
#define NM_ACCESS_POINT_STRENGTH "strength"
|
||||
#define NM_ACCESS_POINT_LAST_SEEN "last-seen"
|
||||
#define NM_ACCESS_POINT_BANDWIDTH "bandwidth"
|
||||
|
||||
/* DEPRECATED */
|
||||
#define NM_ACCESS_POINT_HW_ADDRESS "hw-address"
|
||||
@@ -59,6 +60,9 @@ guint8 nm_access_point_get_strength(NMAccessPoint *ap);
|
||||
NM_AVAILABLE_IN_1_2
|
||||
int nm_access_point_get_last_seen(NMAccessPoint *ap);
|
||||
|
||||
NM_AVAILABLE_IN_1_46
|
||||
guint32 nm_access_point_get_bandwidth(NMAccessPoint *ap);
|
||||
|
||||
GPtrArray *nm_access_point_filter_connections(NMAccessPoint *ap, const GPtrArray *connections);
|
||||
|
||||
gboolean nm_access_point_connection_valid(NMAccessPoint *ap, NMConnection *connection);
|
||||
|
Reference in New Issue
Block a user