diff options
author | Fernando Fernandez Mancera <ffmancera@riseup.net> | 2023-07-27 16:15:47 +0200 |
---|---|---|
committer | Fernando Fernandez Mancera <ffmancera@riseup.net> | 2023-08-02 00:54:27 +0200 |
commit | fe48a4b35cf6373ba033134944da10aa51d1d85a (patch) | |
tree | 3dd172687f6bc92c188dfc00849b3c35abd99fbf | |
parent | d3620dd286ce1c0c46aa71f6ed2956e50dc0bf32 (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.xml | 7 | ||||
-rw-r--r-- | src/core/devices/wifi/nm-wifi-ap.c | 41 | ||||
-rw-r--r-- | src/core/devices/wifi/nm-wifi-ap.h | 3 | ||||
-rw-r--r-- | src/core/nm-core-utils.c | 85 | ||||
-rw-r--r-- | src/core/nm-core-utils.h | 1 | ||||
-rw-r--r-- | src/core/supplicant/nm-supplicant-interface.c | 11 | ||||
-rw-r--r-- | src/core/supplicant/nm-supplicant-types.h | 2 | ||||
-rw-r--r-- | src/libnm-client-impl/libnm.ver | 5 | ||||
-rw-r--r-- | src/libnm-client-impl/nm-access-point.c | 39 | ||||
-rw-r--r-- | src/libnm-client-public/nm-access-point.h | 4 |
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); |