]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: cfg80211: separate NPCA validity from chandef validity
authorJohannes Berg <johannes.berg@intel.com>
Tue, 28 Apr 2026 09:25:40 +0000 (11:25 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 5 May 2026 12:49:04 +0000 (14:49 +0200)
When considering both NPCA and DBE, it can appear that the
NPCA configuration is invalid, e.g. for an 80 MHz BSS channel
with DBE to 160 MHz:

     | primary channel
     |       NPCA primary channel
     |       |
     V       V
   | p |   | n |   |   |   |   |   |
   | BSS channel   |
   | DBE channel                   |

Now the NPCA primary channel is in the same half as the primary
channel, and the NPCA puncturing bitmap could be completely
invalid as a puncturing bitmap when considering the overall
channel.

Split out the validity checks from cfg80211_chandef_valid() to
a new cfg80211_chandef_npca_valid() function that just checks
the NPCA configuration against the BSS chandef.

Link: https://patch.msgid.link/20260428112708.1225df131557.If3a6afadcce05d215b72fd82175f72373a0f6d24@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/net/cfg80211.h
net/mac80211/mlme.c
net/wireless/chan.c

index e807999fc8e8a7bff3af8e5fbecac91650bb5172..ddcf559430dd6087c400c52efbc77ef99c7d81ba 100644 (file)
@@ -849,6 +849,10 @@ struct key_params {
  * struct cfg80211_chan_def - channel definition
  * @chan: the (control) channel
  * @npca_chan: the NPCA primary channel
+ *     Note that if DBE is in use, this channel may appear to be
+ *     inside the primary half of the chandef. Implementations
+ *     can use the position of this channel to understand how
+ *     NPCA is used.
  * @width: channel width
  * @center_freq1: center frequency of first segment
  * @center_freq2: center frequency of second segment
@@ -864,6 +868,8 @@ struct key_params {
  * @npca_punctured: NPCA puncturing bitmap, like @punctured but for
  *     NPCA transmissions. If NPCA is used (@npca_chan is not %NULL)
  *     this will be a superset of the @punctured bimap.
+ *     Note that if DBE is used, this bitmap is also shifted to be in
+ *     accordance with the overall chandef bandwidth.
  * @s1g_primary_2mhz: Indicates if the control channel pointed to
  *     by 'chan' exists as a 1MHz primary subchannel within an
  *     S1G 2MHz primary channel.
@@ -1154,6 +1160,23 @@ int cfg80211_chandef_primary(const struct cfg80211_chan_def *chandef,
                             enum nl80211_chan_width primary_chan_width,
                             u16 *punctured);
 
+/**
+ * cfg80211_chandef_npca_valid - check that NPCA information is valid
+ * @wiphy: the wiphy to check for, for channel pointer lookup
+ * @chandef: the BSS channel chandef to check against
+ * @npca: NPCA information, can be %NULL in which case this
+ *     always returns %true
+ *
+ * Note that DBE must not have been configured into the chandef yet
+ * before checking NPCA, i.e. @chandef must represent the BSS channel.
+ *
+ * Returns: %true if the NPCA channel and puncturing bitmap are valid
+ *     according to the chandef, %false otherwise
+ */
+bool cfg80211_chandef_npca_valid(struct wiphy *wiphy,
+                                const struct cfg80211_chan_def *chandef,
+                                const struct ieee80211_uhr_npca_info *npca);
+
 /**
  * cfg80211_chandef_add_npca - parse and add NPCA information to chandef
  * @wiphy: the wiphy this will be used for, for channel pointer lookup
index 3db8a499a1c8285dae4a45cee62ee0f5d3445485..a818568d34b90f169d80d3c1908099d8910037a2 100644 (file)
@@ -406,7 +406,10 @@ check_uhr:
 
                npca = ieee80211_uhr_npca_info(uhr_oper);
 
-               if (cfg80211_chandef_add_npca(sdata->local->hw.wiphy,
+               /* DBE is not considered yet, so this works */
+               if (!cfg80211_chandef_npca_valid(sdata->local->hw.wiphy,
+                                                &npca_chandef, npca) ||
+                   cfg80211_chandef_add_npca(sdata->local->hw.wiphy,
                                              &npca_chandef, npca)) {
                        sdata_info(sdata,
                                   "AP UHR NPCA settings invalid, disabling UHR\n");
index 5289a4ddacd6c76f76c363052fffd2086d198ef8..ed35b55b1b6704a8b0b51e2583df549a3e80cf33 100644 (file)
@@ -460,9 +460,6 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
                return false;
 
        if (chandef->npca_chan) {
-               bool pri_upper, npca_upper;
-               u32 cf1;
-
                switch (chandef->width) {
                case NL80211_CHAN_WIDTH_80:
                case NL80211_CHAN_WIDTH_160:
@@ -471,24 +468,6 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
                default:
                        return false;
                }
-
-               if (!cfg80211_chandef_valid_control_freq(chandef,
-                                                        chandef->npca_chan->center_freq))
-                       return false;
-
-               cf1 = chandef->center_freq1;
-               pri_upper = chandef->chan->center_freq > cf1;
-               npca_upper = chandef->npca_chan->center_freq > cf1;
-
-               if (pri_upper == npca_upper)
-                       return false;
-
-               if (!valid_puncturing_bitmap(chandef,
-                                            chandef->npca_chan->center_freq,
-                                            chandef->npca_punctured) ||
-                   (chandef->punctured & chandef->npca_punctured) !=
-                   chandef->punctured)
-                       return false;
        } else if (chandef->npca_punctured) {
                return false;
        }
@@ -556,6 +535,44 @@ int cfg80211_chandef_primary(const struct cfg80211_chan_def *c,
 }
 EXPORT_SYMBOL(cfg80211_chandef_primary);
 
+bool cfg80211_chandef_npca_valid(struct wiphy *wiphy,
+                                const struct cfg80211_chan_def *chandef,
+                                const struct ieee80211_uhr_npca_info *npca)
+{
+       struct cfg80211_chan_def tmp = *chandef;
+       bool pri_upper, npca_upper;
+       u32 cf1;
+
+       if (chandef->npca_chan || chandef->npca_punctured)
+               return false;
+
+       if (!npca)
+               return true;
+
+       if (cfg80211_chandef_add_npca(wiphy, &tmp, npca))
+               return false;
+
+       if (!cfg80211_chandef_valid_control_freq(&tmp,
+                                                tmp.npca_chan->center_freq))
+               return false;
+
+       cf1 = tmp.center_freq1;
+       pri_upper = tmp.chan->center_freq > cf1;
+       npca_upper = tmp.npca_chan->center_freq > cf1;
+
+       if (pri_upper == npca_upper)
+               return false;
+
+       if (!valid_puncturing_bitmap(&tmp,
+                                    tmp.npca_chan->center_freq,
+                                    tmp.npca_punctured) ||
+           (tmp.punctured & tmp.npca_punctured) != tmp.punctured)
+               return false;
+
+       return true;
+}
+EXPORT_SYMBOL(cfg80211_chandef_npca_valid);
+
 int cfg80211_chandef_add_npca(struct wiphy *wiphy,
                              struct cfg80211_chan_def *chandef,
                              const struct ieee80211_uhr_npca_info *npca)