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>
* 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
* @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.
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
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");
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:
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;
}
}
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)