summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFernando Fernandez Mancera <ffmancera@riseup.net>2023-07-27 16:15:47 +0200
committerFernando Fernandez Mancera <ffmancera@riseup.net>2023-08-02 00:54:27 +0200
commitfe48a4b35cf6373ba033134944da10aa51d1d85a (patch)
tree3dd172687f6bc92c188dfc00849b3c35abd99fbf
parentd3620dd286ce1c0c46aa71f6ed2956e50dc0bf32 (diff)
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.
-rw-r--r--introspection/org.freedesktop.NetworkManager.AccessPoint.xml7
-rw-r--r--src/core/devices/wifi/nm-wifi-ap.c41
-rw-r--r--src/core/devices/wifi/nm-wifi-ap.h3
-rw-r--r--src/core/nm-core-utils.c85
-rw-r--r--src/core/nm-core-utils.h1
-rw-r--r--src/core/supplicant/nm-supplicant-interface.c11
-rw-r--r--src/core/supplicant/nm-supplicant-types.h2
-rw-r--r--src/libnm-client-impl/libnm.ver5
-rw-r--r--src/libnm-client-impl/nm-access-point.c39
-rw-r--r--src/libnm-client-public/nm-access-point.h4
10 files changed, 196 insertions, 2 deletions
diff --git a/introspection/org.freedesktop.NetworkManager.AccessPoint.xml b/introspection/org.freedesktop.NetworkManager.AccessPoint.xml
index 7340bda308..287bfaa9a4 100644
--- a/introspection/org.freedesktop.NetworkManager.AccessPoint.xml
+++ b/introspection/org.freedesktop.NetworkManager.AccessPoint.xml
@@ -80,6 +80,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:
The current signal quality of the access point, in percent.
diff --git a/src/core/devices/wifi/nm-wifi-ap.c b/src/core/devices/wifi/nm-wifi-ap.c
index 825a5aa8f1..d4d3815e7a 100644
--- a/src/core/devices/wifi/nm-wifi-ap.c
+++ b/src/core/devices/wifi/nm-wifi-ap.c
@@ -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);
}
diff --git a/src/core/devices/wifi/nm-wifi-ap.h b/src/core/devices/wifi/nm-wifi-ap.h
index 93dc8edf3e..0f229640b5 100644
--- a/src/core/devices/wifi/nm-wifi-ap.h
+++ b/src/core/devices/wifi/nm-wifi-ap.h
@@ -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);
diff --git a/src/core/nm-core-utils.c b/src/core/nm-core-utils.c
index 5442efbf88..822f138055 100644
--- a/src/core/nm-core-utils.c
+++ b/src/core/nm-core-utils.c
@@ -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
diff --git a/src/core/nm-core-utils.h b/src/core/nm-core-utils.h
index 5511250422..d73cfd6467 100644
--- a/src/core/nm-core-utils.h
+++ b/src/core/nm-core-utils.h
@@ -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);
diff --git a/src/core/supplicant/nm-supplicant-interface.c b/src/core/supplicant/nm-supplicant-interface.c
index 18525724f4..e7bdfd49df 100644
--- a/src/core/supplicant/nm-supplicant-interface.c
+++ b/src/core/supplicant/nm-supplicant-interface.c
@@ -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);
@@ -777,7 +783,8 @@ _bss_info_properties_changed(NMSupplicantInterface *self,
else
bss_info->rsn_flags &= ~NM_802_11_AP_SEC_KEY_MGMT_OWE_TM;
- bss_info->metered = p_metered;
+ bss_info->metered = p_metered;
+ bss_info->bandwidth = bandwidth;
}
if (p_max_rate_has)
diff --git a/src/core/supplicant/nm-supplicant-types.h b/src/core/supplicant/nm-supplicant-types.h
index 1ae67e1382..1f04c12b82 100644
--- a/src/core/supplicant/nm-supplicant-types.h
+++ b/src/core/supplicant/nm-supplicant-types.h
@@ -179,6 +179,8 @@ typedef struct _NMSupplicantBssInfo {
guint32 max_rate;
+ guint32 bandwidth;
+
guint8 signal_percent;
NMEtherAddr bssid;
diff --git a/src/libnm-client-impl/libnm.ver b/src/libnm-client-impl/libnm.ver
index 919ffc74b8..acbfb4a6e6 100644
--- a/src/libnm-client-impl/libnm.ver
+++ b/src/libnm-client-impl/libnm.ver
@@ -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;
diff --git a/src/libnm-client-impl/nm-access-point.c b/src/libnm-client-impl/nm-access-point.c
index 94b38f0300..a06bee4846 100644
--- a/src/libnm-client-impl/nm-access-point.c
+++ b/src/libnm-client-impl/nm-access-point.c
@@ -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;
@@ -199,6 +201,24 @@ nm_access_point_get_max_bitrate(NMAccessPoint *ap)
}
/**
+ * 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",
@@ -621,6 +645,21 @@ nm_access_point_class_init(NMAccessPointClass *ap_class)
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:
*
* The current signal strength of the access point.
diff --git a/src/libnm-client-public/nm-access-point.h b/src/libnm-client-public/nm-access-point.h
index 5a78e34f73..f2cc1a4cc5 100644
--- a/src/libnm-client-public/nm-access-point.h
+++ b/src/libnm-client-public/nm-access-point.h
@@ -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);