mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 02:17:36 -04:00
wifi: cfg80211: add a function to parse UHR DBE
Add a function that takes the DBE information and parses it into an existing chandef that should hold the BSS channel. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com> Link: https://patch.msgid.link/20260515141209.4eb1490f5cc6.I3ca9421f1fe4c31073846b1b62017f12c75889de@changeid Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
@@ -1190,6 +1190,16 @@ int cfg80211_chandef_add_npca(struct wiphy *wiphy,
|
||||
struct cfg80211_chan_def *chandef,
|
||||
const struct ieee80211_uhr_npca_info *npca);
|
||||
|
||||
/**
|
||||
* cfg80211_chandef_add_dbe - parse and add DBE information to chandef
|
||||
* @chandef: the chandef to expand
|
||||
* @dbe: the DBE information, must be size-checked if not %NULL
|
||||
*
|
||||
* Returns: 0 for success, a negative error code otherwise
|
||||
*/
|
||||
int cfg80211_chandef_add_dbe(struct cfg80211_chan_def *chandef,
|
||||
const struct ieee80211_uhr_dbe_info *dbe);
|
||||
|
||||
/**
|
||||
* nl80211_send_chandef - sends the channel definition.
|
||||
* @msg: the msg to send channel definition
|
||||
|
||||
@@ -619,6 +619,136 @@ int cfg80211_chandef_add_npca(struct wiphy *wiphy,
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_chandef_add_npca);
|
||||
|
||||
int cfg80211_chandef_add_dbe(struct cfg80211_chan_def *chandef,
|
||||
const struct ieee80211_uhr_dbe_info *dbe)
|
||||
{
|
||||
struct cfg80211_chan_def new_chandef = *chandef;
|
||||
u16 starting_freq, bw_mhz, start_old, start_new;
|
||||
u8 bw, punct_shift;
|
||||
int offset, index;
|
||||
|
||||
if (!dbe)
|
||||
return 0;
|
||||
|
||||
if (!cfg80211_chandef_valid(chandef))
|
||||
return -EINVAL;
|
||||
|
||||
if (chandef->width == NL80211_CHAN_WIDTH_20_NOHT)
|
||||
return -EINVAL;
|
||||
|
||||
bw = u8_get_bits(dbe->params, IEEE80211_UHR_DBE_OPER_BANDWIDTH);
|
||||
|
||||
switch (chandef->chan->band) {
|
||||
case NL80211_BAND_5GHZ:
|
||||
if (bw > IEEE80211_UHR_DBE_OPER_BW_160)
|
||||
return -EINVAL;
|
||||
if (chandef->chan->center_freq < 5745)
|
||||
starting_freq = 5180; /* channel 36 */
|
||||
else
|
||||
starting_freq = 5745; /* channel 149 */
|
||||
break;
|
||||
case NL80211_BAND_6GHZ:
|
||||
starting_freq = 5955; /* channel 1 center */
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (bw) {
|
||||
case IEEE80211_UHR_DBE_OPER_BW_320_2:
|
||||
case IEEE80211_UHR_DBE_OPER_BW_320_1:
|
||||
if (chandef->width == NL80211_CHAN_WIDTH_160)
|
||||
break;
|
||||
fallthrough;
|
||||
case IEEE80211_UHR_DBE_OPER_BW_160:
|
||||
if (chandef->width == NL80211_CHAN_WIDTH_80)
|
||||
break;
|
||||
fallthrough;
|
||||
case IEEE80211_UHR_DBE_OPER_BW_80:
|
||||
if (chandef->width == NL80211_CHAN_WIDTH_40)
|
||||
break;
|
||||
fallthrough;
|
||||
case IEEE80211_UHR_DBE_OPER_BW_40:
|
||||
if (chandef->width == NL80211_CHAN_WIDTH_20)
|
||||
break;
|
||||
fallthrough;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (bw) {
|
||||
case IEEE80211_UHR_DBE_OPER_BW_320_2:
|
||||
/* 320-2 starts shifted by 160 */
|
||||
starting_freq += 160;
|
||||
fallthrough;
|
||||
case IEEE80211_UHR_DBE_OPER_BW_320_1:
|
||||
new_chandef.width = NL80211_CHAN_WIDTH_320;
|
||||
bw_mhz = 320;
|
||||
break;
|
||||
case IEEE80211_UHR_DBE_OPER_BW_160:
|
||||
new_chandef.width = NL80211_CHAN_WIDTH_160;
|
||||
bw_mhz = 160;
|
||||
break;
|
||||
case IEEE80211_UHR_DBE_OPER_BW_80:
|
||||
new_chandef.width = NL80211_CHAN_WIDTH_80;
|
||||
bw_mhz = 80;
|
||||
break;
|
||||
case IEEE80211_UHR_DBE_OPER_BW_40:
|
||||
new_chandef.width = NL80211_CHAN_WIDTH_40;
|
||||
bw_mhz = 40;
|
||||
break;
|
||||
}
|
||||
|
||||
/* this should only happen for 320-2 and misconfigured AP */
|
||||
if (chandef->chan->center_freq < starting_freq)
|
||||
return -EINVAL;
|
||||
|
||||
offset = chandef->chan->center_freq - starting_freq;
|
||||
index = offset / bw_mhz;
|
||||
start_new = starting_freq - 10 + index * bw_mhz;
|
||||
new_chandef.center_freq1 = start_new + bw_mhz / 2;
|
||||
|
||||
start_old = chandef->center_freq1 -
|
||||
cfg80211_chandef_get_width(chandef) / 2;
|
||||
|
||||
/*
|
||||
* If the DBE channel extends downward below the lower
|
||||
* edge of the BSS channel, we need to shift puncturing
|
||||
* bitmaps up to adjust for that.
|
||||
*/
|
||||
if (start_new < start_old)
|
||||
punct_shift = (start_old - start_new) / 20;
|
||||
else
|
||||
punct_shift = 0;
|
||||
|
||||
new_chandef.punctured <<= punct_shift;
|
||||
new_chandef.npca_punctured <<= punct_shift;
|
||||
|
||||
if (dbe->params & IEEE80211_UHR_DBE_OPER_DIS_SUBCHANNEL_BITMAP_PRES) {
|
||||
u16 punct_mask = ((1 << (bw_mhz / 40)) - 1) << punct_shift;
|
||||
u16 punctured = le16_to_cpu(dbe->dis_subch_bmap[0]);
|
||||
|
||||
if ((punctured & punct_mask) != (new_chandef.punctured & punct_mask))
|
||||
return -EINVAL;
|
||||
|
||||
new_chandef.punctured = punctured;
|
||||
}
|
||||
|
||||
if (!cfg80211_chandef_valid(&new_chandef))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* If e.g. a 40 MHz BSS channel (erroneously) occupies the center of the
|
||||
* DBE 80 MHz channel, they would be incompatible; check and reject.
|
||||
*/
|
||||
if (!cfg80211_chandef_compatible(&new_chandef, chandef))
|
||||
return -EINVAL;
|
||||
|
||||
*chandef = new_chandef;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_chandef_add_dbe);
|
||||
|
||||
static const struct cfg80211_chan_def *
|
||||
check_chandef_primary_compat(const struct cfg80211_chan_def *c1,
|
||||
const struct cfg80211_chan_def *c2,
|
||||
|
||||
@@ -2,13 +2,18 @@
|
||||
/*
|
||||
* KUnit tests for channel helper functions
|
||||
*
|
||||
* Copyright (C) 2023-2024 Intel Corporation
|
||||
* Copyright (C) 2023-2024, 2026 Intel Corporation
|
||||
*/
|
||||
#include <net/cfg80211.h>
|
||||
#include <kunit/test.h>
|
||||
|
||||
MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
|
||||
|
||||
static struct ieee80211_channel chan_2ghz_1 = {
|
||||
.band = NL80211_BAND_2GHZ,
|
||||
.center_freq = 2412,
|
||||
};
|
||||
|
||||
static struct ieee80211_channel chan_6ghz_1 = {
|
||||
.band = NL80211_BAND_6GHZ,
|
||||
.center_freq = 5955,
|
||||
@@ -215,14 +220,189 @@ static void test_chandef_compat(struct kunit *test)
|
||||
KUNIT_EXPECT_PTR_EQ(test, ret, expect);
|
||||
}
|
||||
|
||||
static struct kunit_case chandef_compat_test_cases[] = {
|
||||
static const struct chandef_dbe_case {
|
||||
const char *desc;
|
||||
struct cfg80211_chan_def c;
|
||||
u8 dbe[3];
|
||||
bool fails;
|
||||
u16 cf1;
|
||||
} chandef_dbe_cases[] = {
|
||||
{
|
||||
.desc = "non-HT failure",
|
||||
.c = {
|
||||
.width = NL80211_CHAN_WIDTH_20_NOHT,
|
||||
.chan = &chan_6ghz_1,
|
||||
.center_freq1 = 5955,
|
||||
},
|
||||
.dbe[0] = IEEE80211_UHR_DBE_OPER_BW_40,
|
||||
.fails = true,
|
||||
},
|
||||
{
|
||||
.desc = "2.4 GHz fails",
|
||||
.c = {
|
||||
.width = NL80211_CHAN_WIDTH_20,
|
||||
.chan = &chan_2ghz_1,
|
||||
.center_freq1 = 2412,
|
||||
},
|
||||
.dbe[0] = IEEE80211_UHR_DBE_OPER_BW_40,
|
||||
.fails = true,
|
||||
},
|
||||
{
|
||||
.desc = "DBE narrower",
|
||||
.c = {
|
||||
.width = NL80211_CHAN_WIDTH_320,
|
||||
.chan = &chan_6ghz_1,
|
||||
.center_freq1 = 5955 + 10 + 20 + 40 + 80,
|
||||
},
|
||||
.dbe[0] = IEEE80211_UHR_DBE_OPER_BW_160,
|
||||
.fails = true,
|
||||
},
|
||||
{
|
||||
.desc = "DBE to 320-1",
|
||||
.c = {
|
||||
.width = NL80211_CHAN_WIDTH_160,
|
||||
.chan = &chan_6ghz_105,
|
||||
.center_freq1 = 6475 + 30,
|
||||
},
|
||||
.dbe[0] = IEEE80211_UHR_DBE_OPER_BW_320_1,
|
||||
.cf1 = 6425,
|
||||
},
|
||||
{
|
||||
.desc = "DBE to 320-2",
|
||||
.c = {
|
||||
.width = NL80211_CHAN_WIDTH_160,
|
||||
.chan = &chan_6ghz_105,
|
||||
.center_freq1 = 6475 + 30,
|
||||
},
|
||||
.dbe[0] = IEEE80211_UHR_DBE_OPER_BW_320_2,
|
||||
.cf1 = 6585,
|
||||
},
|
||||
{
|
||||
.desc = "bad disabled subchannel bitmap - not enough in BSS (1)",
|
||||
.c = {
|
||||
.width = NL80211_CHAN_WIDTH_160,
|
||||
.chan = &chan_6ghz_105,
|
||||
.center_freq1 = 6475 + 30,
|
||||
.punctured = 0x0001,
|
||||
},
|
||||
.dbe[0] = IEEE80211_UHR_DBE_OPER_BW_320_1 |
|
||||
IEEE80211_UHR_DBE_OPER_DIS_SUBCHANNEL_BITMAP_PRES,
|
||||
/* DBE disabled subchannel bitmap == 0 */
|
||||
.fails = true,
|
||||
},
|
||||
{
|
||||
.desc = "bad disabled subchannel bitmap - too much in BSS (1)",
|
||||
.c = {
|
||||
.width = NL80211_CHAN_WIDTH_160,
|
||||
.chan = &chan_6ghz_105,
|
||||
.center_freq1 = 6475 + 30,
|
||||
.punctured = 0x0001,
|
||||
},
|
||||
.dbe[0] = IEEE80211_UHR_DBE_OPER_BW_320_1 |
|
||||
IEEE80211_UHR_DBE_OPER_DIS_SUBCHANNEL_BITMAP_PRES,
|
||||
/* DBE disabled subchannel bitmap == 0x0300 */
|
||||
.dbe[2] = 0x03,
|
||||
.fails = true,
|
||||
},
|
||||
{
|
||||
.desc = "bad disabled subchannel bitmap - not enough in BSS (2)",
|
||||
.c = {
|
||||
.width = NL80211_CHAN_WIDTH_160,
|
||||
.chan = &chan_6ghz_105,
|
||||
.center_freq1 = 6475 + 30,
|
||||
.punctured = 0x0001,
|
||||
},
|
||||
.dbe[0] = IEEE80211_UHR_DBE_OPER_BW_320_2 |
|
||||
IEEE80211_UHR_DBE_OPER_DIS_SUBCHANNEL_BITMAP_PRES,
|
||||
/* DBE disabled subchannel bitmap == 0 */
|
||||
.fails = true,
|
||||
},
|
||||
{
|
||||
.desc = "bad disabled subchannel bitmap - too much in BSS (2)",
|
||||
.c = {
|
||||
.width = NL80211_CHAN_WIDTH_160,
|
||||
.chan = &chan_6ghz_105,
|
||||
.center_freq1 = 6475 + 30,
|
||||
.punctured = 0x0001,
|
||||
},
|
||||
.dbe[0] = IEEE80211_UHR_DBE_OPER_BW_320_2 |
|
||||
IEEE80211_UHR_DBE_OPER_DIS_SUBCHANNEL_BITMAP_PRES,
|
||||
/* DBE disabled subchannel bitmap == 0x03 */
|
||||
.dbe[1] = 0x03,
|
||||
.fails = true,
|
||||
},
|
||||
{
|
||||
.desc = "bad disabled subchannel bitmap - bad bitmap",
|
||||
.c = {
|
||||
.width = NL80211_CHAN_WIDTH_160,
|
||||
.chan = &chan_6ghz_105,
|
||||
.center_freq1 = 6475 + 30,
|
||||
.punctured = 0x0001,
|
||||
},
|
||||
.dbe[0] = IEEE80211_UHR_DBE_OPER_BW_320_1 |
|
||||
IEEE80211_UHR_DBE_OPER_DIS_SUBCHANNEL_BITMAP_PRES,
|
||||
/* DBE disabled subchannel bitmap == 0x1100 */
|
||||
.dbe[2] = 0x11,
|
||||
.fails = true,
|
||||
},
|
||||
{
|
||||
.desc = "good disabled subchannel bitmap (1)",
|
||||
.c = {
|
||||
.width = NL80211_CHAN_WIDTH_160,
|
||||
.chan = &chan_6ghz_105,
|
||||
.center_freq1 = 6475 + 30,
|
||||
.punctured = 0x0003,
|
||||
},
|
||||
.dbe[0] = IEEE80211_UHR_DBE_OPER_BW_320_1 |
|
||||
IEEE80211_UHR_DBE_OPER_DIS_SUBCHANNEL_BITMAP_PRES,
|
||||
/* DBE disabled subchannel bitmap == 0x0300 */
|
||||
.dbe[2] = 0x03,
|
||||
.cf1 = 6425,
|
||||
},
|
||||
{
|
||||
.desc = "good disabled subchannel bitmap (2)",
|
||||
.c = {
|
||||
.width = NL80211_CHAN_WIDTH_160,
|
||||
.chan = &chan_6ghz_105,
|
||||
.center_freq1 = 6475 + 30,
|
||||
.punctured = 0x0003,
|
||||
},
|
||||
.dbe[0] = IEEE80211_UHR_DBE_OPER_BW_320_2 |
|
||||
IEEE80211_UHR_DBE_OPER_DIS_SUBCHANNEL_BITMAP_PRES,
|
||||
/* DBE disabled subchannel bitmap == 0x0003 */
|
||||
.dbe[1] = 0x03,
|
||||
.cf1 = 6585,
|
||||
},
|
||||
};
|
||||
|
||||
KUNIT_ARRAY_PARAM_DESC(chandef_dbe, chandef_dbe_cases, desc)
|
||||
|
||||
static void test_chandef_dbe(struct kunit *test)
|
||||
{
|
||||
const struct chandef_dbe_case *params = test->param_value;
|
||||
struct cfg80211_chan_def c = params->c;
|
||||
int ret;
|
||||
|
||||
KUNIT_EXPECT_EQ(test, cfg80211_chandef_valid(¶ms->c), true);
|
||||
|
||||
ret = cfg80211_chandef_add_dbe(&c, (void *)params->dbe);
|
||||
KUNIT_EXPECT_EQ(test, ret != 0, params->fails);
|
||||
|
||||
if (params->fails)
|
||||
return;
|
||||
|
||||
KUNIT_EXPECT_EQ(test, c.center_freq1, params->cf1);
|
||||
}
|
||||
|
||||
static struct kunit_case chandef_test_cases[] = {
|
||||
KUNIT_CASE_PARAM(test_chandef_compat, chandef_compat_gen_params),
|
||||
KUNIT_CASE_PARAM(test_chandef_dbe, chandef_dbe_gen_params),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct kunit_suite chandef_compat = {
|
||||
.name = "cfg80211-chandef-compat",
|
||||
.test_cases = chandef_compat_test_cases,
|
||||
static struct kunit_suite chandef = {
|
||||
.name = "cfg80211-chandef",
|
||||
.test_cases = chandef_test_cases,
|
||||
};
|
||||
|
||||
kunit_test_suite(chandef_compat);
|
||||
kunit_test_suite(chandef);
|
||||
|
||||
Reference in New Issue
Block a user