summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeniamino Galvani <bgalvani@redhat.com>2024-03-22 10:12:43 +0100
committerBeniamino Galvani <bgalvani@redhat.com>2024-04-02 16:12:57 +0200
commit4cd4ab518e3062cb2c8430193246eaa298f71687 (patch)
tree9c67119897cf468d53253106bad85cb9a4cc56e4
parent8ca7433a14be8154afe96fa8ddff8fddddd23aad (diff)
wifi: fix enumeration of 6 GHz channels from wiphybg/wifi-bands
Command NL80211_CMD_GET_WIPHY without any flag only returns channels in the 2 GHz and 5 GHz bands, for backwards compatibility with old userspace tools. To get the full list we need to pass attribute NL80211_ATTR_SPLIT_WIPHY_DUMP (added in Linux 3.9 released in 2013), and allow the handler to be called multiple times. https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/1500
-rw-r--r--NEWS1
-rw-r--r--src/libnm-platform/wifi/nm-wifi-utils-nl80211.c94
2 files changed, 53 insertions, 42 deletions
diff --git a/NEWS b/NEWS
index e2bdb9cb5c..5dd05ed1bd 100644
--- a/NEWS
+++ b/NEWS
@@ -15,6 +15,7 @@ USE AT YOUR OWN RISK. NOT RECOMMENDED FOR PRODUCTION USE!
visible in nmcli via "nmcli -f all device show $DEV".
* Deprecated 802-11-wireless and 802-11-wired property 'mac-address-blacklist'
and introduced the 'mac-address-denylist' property.
+* Fix detection of 6 GHz band capability for WiFi devices
=============================================
NetworkManager-1.46
diff --git a/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c b/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c
index 3b90d180ae..3c00898a27 100644
--- a/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c
+++ b/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c
@@ -567,6 +567,7 @@ struct nl80211_device_info {
int phy;
Nl80211Freq *freqs;
int num_freqs;
+ int num_freqs_alloc;
guint32 freq;
guint32 caps;
gboolean can_scan;
@@ -610,7 +611,6 @@ nl80211_wiphy_info_handler(const struct nl_msg *msg, void *arg)
struct nlattr *nl_freq;
int rem_freq;
int rem_band;
- guint num_alloc;
#ifdef NL80211_FREQUENCY_ATTR_NO_IR
G_STATIC_ASSERT_EXPR(NL80211_FREQUENCY_ATTR_PASSIVE_SCAN == NL80211_FREQUENCY_ATTR_NO_IR
@@ -622,22 +622,16 @@ nl80211_wiphy_info_handler(const struct nl_msg *msg, void *arg)
if (nla_parse_arr(tb, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL) < 0)
return NL_SKIP;
- if (tb[NL80211_ATTR_WIPHY] == NULL || tb[NL80211_ATTR_WIPHY_BANDS] == NULL)
+ if (!tb[NL80211_ATTR_WIPHY])
return NL_SKIP;
info->phy = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
if (tb[NL80211_ATTR_WIPHY_FREQ])
info->freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
- else
- info->freq = 0;
- if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]) {
+ if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
info->can_scan_ssid = nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]) > 0;
- } else {
- /* old kernel that only had mac80211, so assume it can */
- info->can_scan_ssid = TRUE;
- }
if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) {
struct nlattr *nl_cmd;
@@ -664,51 +658,57 @@ nl80211_wiphy_info_handler(const struct nl_msg *msg, void *arg)
}
}
- /* Read supported frequencies */
- num_alloc = 32;
- info->num_freqs = 0;
- info->freqs = g_new(Nl80211Freq, num_alloc);
+ if (tb[NL80211_ATTR_WIPHY_BANDS]) {
+ /* Read supported frequencies */
- nla_for_each_nested (nl_band, tb[NL80211_ATTR_WIPHY_BANDS], rem_band) {
- if (nla_parse_nested_arr(tb_band, nl_band, NULL) < 0)
- return NL_SKIP;
+ if (!info->freqs) {
+ info->num_freqs = 0;
+ info->num_freqs_alloc = 32;
+ info->freqs = g_new(Nl80211Freq, info->num_freqs_alloc);
+ }
- nla_for_each_nested (nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
- Nl80211Freq *f;
+ nla_for_each_nested (nl_band, tb[NL80211_ATTR_WIPHY_BANDS], rem_band) {
+ if (nla_parse_nested_arr(tb_band, nl_band, NULL) < 0)
+ return NL_SKIP;
- if (nla_parse_nested_arr(tb_freq, nl_freq, freq_policy) < 0)
+ if (!tb_band[NL80211_BAND_ATTR_FREQS])
continue;
- if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
- continue;
+ nla_for_each_nested (nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
+ Nl80211Freq *f;
- if (info->num_freqs >= num_alloc) {
- num_alloc *= 2;
- info->freqs = g_renew(Nl80211Freq, info->freqs, num_alloc);
- }
+ if (nla_parse_nested_arr(tb_freq, nl_freq, freq_policy) < 0)
+ continue;
+
+ if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
+ continue;
- f = &info->freqs[info->num_freqs];
- *f = (Nl80211Freq){
- .freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]),
- .disabled = !!tb_freq[NL80211_FREQUENCY_ATTR_DISABLED],
- .no_ir = !!tb_freq[NL80211_FREQUENCY_ATTR_NO_IR],
- };
+ if (info->num_freqs >= info->num_freqs_alloc) {
+ info->num_freqs_alloc *= 2;
+ info->freqs = g_renew(Nl80211Freq, info->freqs, info->num_freqs_alloc);
+ }
- info->caps |= _NM_WIFI_DEVICE_CAP_FREQ_VALID;
+ f = &info->freqs[info->num_freqs];
+ *f = (Nl80211Freq){
+ .freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]),
+ .disabled = !!tb_freq[NL80211_FREQUENCY_ATTR_DISABLED],
+ .no_ir = !!tb_freq[NL80211_FREQUENCY_ATTR_NO_IR],
+ };
- if (f->freq >= 2401 && f->freq <= 2495)
- info->caps |= _NM_WIFI_DEVICE_CAP_FREQ_2GHZ;
- if (f->freq >= 5150 && f->freq < 5950)
- info->caps |= _NM_WIFI_DEVICE_CAP_FREQ_5GHZ;
- if (f->freq >= 5950 && f->freq <= 7125)
- info->caps |= _NM_WIFI_DEVICE_CAP_FREQ_6GHZ;
+ info->caps |= _NM_WIFI_DEVICE_CAP_FREQ_VALID;
- info->num_freqs++;
+ if (f->freq >= 2401 && f->freq <= 2495)
+ info->caps |= _NM_WIFI_DEVICE_CAP_FREQ_2GHZ;
+ if (f->freq >= 5150 && f->freq < 5950)
+ info->caps |= _NM_WIFI_DEVICE_CAP_FREQ_5GHZ;
+ if (f->freq >= 5950 && f->freq <= 7125)
+ info->caps |= _NM_WIFI_DEVICE_CAP_FREQ_6GHZ;
+
+ info->num_freqs++;
+ }
}
}
- info->freqs = g_renew(Nl80211Freq, info->freqs, info->num_freqs);
-
/* Read security/encryption support */
if (tb[NL80211_ATTR_CIPHER_SUITES]) {
guint32 *ciphers = nla_data(tb[NL80211_ATTR_CIPHER_SUITES]);
@@ -874,7 +874,10 @@ nm_wifi_utils_nl80211_new(struct nl_sock *genl, guint16 genl_family_id, int ifin
self->phy = -1;
- msg = nl80211_alloc_msg(self, NL80211_CMD_GET_WIPHY, 0);
+ msg = nl80211_alloc_msg(self, NL80211_CMD_GET_WIPHY, NLM_F_DUMP);
+ NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
+
+ device_info.can_scan_ssid = TRUE;
device_info.self = self;
if (nl80211_send_and_recv(self, msg, nl80211_wiphy_info_handler, &device_info) < 0) {
@@ -882,6 +885,10 @@ nm_wifi_utils_nl80211_new(struct nl_sock *genl, guint16 genl_family_id, int ifin
return NULL;
}
+ if (device_info.freqs) {
+ device_info.freqs = g_renew(Nl80211Freq, device_info.freqs, device_info.num_freqs);
+ }
+
if (!device_info.success) {
_LOGD("NL80211_CMD_GET_WIPHY request indicated failure");
return NULL;
@@ -915,4 +922,7 @@ nm_wifi_utils_nl80211_new(struct nl_sock *genl, guint16 genl_family_id, int ifin
_LOGD("using nl80211 for Wi-Fi device control");
return (NMWifiUtils *) g_steal_pointer(&self);
+
+nla_put_failure:
+ g_return_val_if_reached(NULL);
}