1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * KUnit tests for channel helper functions 4 * 5 * Copyright (C) 2023-2024, 2026 Intel Corporation 6 */ 7 #include <net/cfg80211.h> 8 #include <kunit/test.h> 9 10 MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); 11 12 static struct ieee80211_channel chan_2ghz_1 = { 13 .band = NL80211_BAND_2GHZ, 14 .center_freq = 2412, 15 }; 16 17 static struct ieee80211_channel chan_6ghz_1 = { 18 .band = NL80211_BAND_6GHZ, 19 .center_freq = 5955, 20 }; 21 22 static struct ieee80211_channel chan_6ghz_5 = { 23 .band = NL80211_BAND_6GHZ, 24 .center_freq = 5975, 25 }; 26 27 static struct ieee80211_channel chan_6ghz_105 = { 28 .band = NL80211_BAND_6GHZ, 29 .center_freq = 6475, 30 }; 31 32 static const struct chandef_compat_case { 33 const char *desc; 34 /* leave c1 empty for tests for identical */ 35 struct cfg80211_chan_def c1, c2; 36 /* we test both ways around, so c2 should always be the compat one */ 37 bool compat; 38 } chandef_compat_cases[] = { 39 { 40 .desc = "identical non-HT", 41 .c2 = { 42 .width = NL80211_CHAN_WIDTH_20_NOHT, 43 .chan = &chan_6ghz_1, 44 .center_freq1 = 5955, 45 }, 46 .compat = true, 47 }, 48 { 49 .desc = "identical 20 MHz", 50 .c2 = { 51 .width = NL80211_CHAN_WIDTH_20, 52 .chan = &chan_6ghz_1, 53 .center_freq1 = 5955, 54 }, 55 .compat = true, 56 }, 57 { 58 .desc = "identical 40 MHz", 59 .c2 = { 60 .width = NL80211_CHAN_WIDTH_40, 61 .chan = &chan_6ghz_1, 62 .center_freq1 = 5955 + 10, 63 }, 64 .compat = true, 65 }, 66 { 67 .desc = "identical 80 MHz", 68 .c2 = { 69 .width = NL80211_CHAN_WIDTH_80, 70 .chan = &chan_6ghz_1, 71 .center_freq1 = 5955 + 10 + 20, 72 }, 73 .compat = true, 74 }, 75 { 76 .desc = "identical 160 MHz", 77 .c2 = { 78 .width = NL80211_CHAN_WIDTH_160, 79 .chan = &chan_6ghz_1, 80 .center_freq1 = 5955 + 10 + 20 + 40, 81 }, 82 .compat = true, 83 }, 84 { 85 .desc = "identical 320 MHz", 86 .c2 = { 87 .width = NL80211_CHAN_WIDTH_320, 88 .chan = &chan_6ghz_1, 89 .center_freq1 = 5955 + 10 + 20 + 40 + 80, 90 }, 91 .compat = true, 92 }, 93 { 94 .desc = "20 MHz in 320 MHz\n", 95 .c1 = { 96 .width = NL80211_CHAN_WIDTH_20, 97 .chan = &chan_6ghz_1, 98 .center_freq1 = 5955, 99 }, 100 .c2 = { 101 .width = NL80211_CHAN_WIDTH_320, 102 .chan = &chan_6ghz_1, 103 .center_freq1 = 5955 + 10 + 20 + 40 + 80, 104 }, 105 .compat = true, 106 }, 107 { 108 .desc = "different 20 MHz", 109 .c1 = { 110 .width = NL80211_CHAN_WIDTH_20, 111 .chan = &chan_6ghz_1, 112 .center_freq1 = 5955, 113 }, 114 .c2 = { 115 .width = NL80211_CHAN_WIDTH_20, 116 .chan = &chan_6ghz_5, 117 .center_freq1 = 5975, 118 }, 119 }, 120 { 121 .desc = "different primary 320 MHz", 122 .c1 = { 123 .width = NL80211_CHAN_WIDTH_320, 124 .chan = &chan_6ghz_105, 125 .center_freq1 = 6475 + 110, 126 }, 127 .c2 = { 128 .width = NL80211_CHAN_WIDTH_320, 129 .chan = &chan_6ghz_105, 130 .center_freq1 = 6475 - 50, 131 }, 132 }, 133 { 134 /* similar to previous test but one has lower BW */ 135 .desc = "matching primary 160 MHz", 136 .c1 = { 137 .width = NL80211_CHAN_WIDTH_160, 138 .chan = &chan_6ghz_105, 139 .center_freq1 = 6475 + 30, 140 }, 141 .c2 = { 142 .width = NL80211_CHAN_WIDTH_320, 143 .chan = &chan_6ghz_105, 144 .center_freq1 = 6475 - 50, 145 }, 146 .compat = true, 147 }, 148 { 149 .desc = "matching primary 160 MHz & punctured secondary 160 Mhz", 150 .c1 = { 151 .width = NL80211_CHAN_WIDTH_160, 152 .chan = &chan_6ghz_105, 153 .center_freq1 = 6475 + 30, 154 }, 155 .c2 = { 156 .width = NL80211_CHAN_WIDTH_320, 157 .chan = &chan_6ghz_105, 158 .center_freq1 = 6475 - 50, 159 .punctured = 0xf, 160 }, 161 .compat = true, 162 }, 163 { 164 .desc = "matching primary 160 MHz & punctured matching", 165 .c1 = { 166 .width = NL80211_CHAN_WIDTH_160, 167 .chan = &chan_6ghz_105, 168 .center_freq1 = 6475 + 30, 169 .punctured = 0xc0, 170 }, 171 .c2 = { 172 .width = NL80211_CHAN_WIDTH_320, 173 .chan = &chan_6ghz_105, 174 .center_freq1 = 6475 - 50, 175 .punctured = 0xc000, 176 }, 177 .compat = true, 178 }, 179 { 180 .desc = "matching primary 160 MHz & punctured not matching", 181 .c1 = { 182 .width = NL80211_CHAN_WIDTH_160, 183 .chan = &chan_6ghz_105, 184 .center_freq1 = 6475 + 30, 185 .punctured = 0x80, 186 }, 187 .c2 = { 188 .width = NL80211_CHAN_WIDTH_320, 189 .chan = &chan_6ghz_105, 190 .center_freq1 = 6475 - 50, 191 .punctured = 0xc000, 192 }, 193 }, 194 }; 195 196 KUNIT_ARRAY_PARAM_DESC(chandef_compat, chandef_compat_cases, desc) 197 198 static void test_chandef_compat(struct kunit *test) 199 { 200 const struct chandef_compat_case *params = test->param_value; 201 const struct cfg80211_chan_def *ret, *expect; 202 struct cfg80211_chan_def c1 = params->c1; 203 204 /* tests with identical ones */ 205 if (!params->c1.chan) 206 c1 = params->c2; 207 208 KUNIT_EXPECT_EQ(test, cfg80211_chandef_valid(&c1), true); 209 KUNIT_EXPECT_EQ(test, cfg80211_chandef_valid(¶ms->c2), true); 210 211 expect = params->compat ? ¶ms->c2 : NULL; 212 213 ret = cfg80211_chandef_compatible(&c1, ¶ms->c2); 214 KUNIT_EXPECT_PTR_EQ(test, ret, expect); 215 216 if (!params->c1.chan) 217 expect = &c1; 218 219 ret = cfg80211_chandef_compatible(¶ms->c2, &c1); 220 KUNIT_EXPECT_PTR_EQ(test, ret, expect); 221 } 222 223 static const struct chandef_dbe_case { 224 const char *desc; 225 struct cfg80211_chan_def c; 226 u8 dbe[3]; 227 bool fails; 228 u16 cf1; 229 } chandef_dbe_cases[] = { 230 { 231 .desc = "non-HT failure", 232 .c = { 233 .width = NL80211_CHAN_WIDTH_20_NOHT, 234 .chan = &chan_6ghz_1, 235 .center_freq1 = 5955, 236 }, 237 .dbe[0] = IEEE80211_UHR_DBE_OPER_BW_40, 238 .fails = true, 239 }, 240 { 241 .desc = "2.4 GHz fails", 242 .c = { 243 .width = NL80211_CHAN_WIDTH_20, 244 .chan = &chan_2ghz_1, 245 .center_freq1 = 2412, 246 }, 247 .dbe[0] = IEEE80211_UHR_DBE_OPER_BW_40, 248 .fails = true, 249 }, 250 { 251 .desc = "DBE narrower", 252 .c = { 253 .width = NL80211_CHAN_WIDTH_320, 254 .chan = &chan_6ghz_1, 255 .center_freq1 = 5955 + 10 + 20 + 40 + 80, 256 }, 257 .dbe[0] = IEEE80211_UHR_DBE_OPER_BW_160, 258 .fails = true, 259 }, 260 { 261 .desc = "DBE to 320-1", 262 .c = { 263 .width = NL80211_CHAN_WIDTH_160, 264 .chan = &chan_6ghz_105, 265 .center_freq1 = 6475 + 30, 266 }, 267 .dbe[0] = IEEE80211_UHR_DBE_OPER_BW_320_1, 268 .cf1 = 6425, 269 }, 270 { 271 .desc = "DBE to 320-2", 272 .c = { 273 .width = NL80211_CHAN_WIDTH_160, 274 .chan = &chan_6ghz_105, 275 .center_freq1 = 6475 + 30, 276 }, 277 .dbe[0] = IEEE80211_UHR_DBE_OPER_BW_320_2, 278 .cf1 = 6585, 279 }, 280 { 281 .desc = "bad disabled subchannel bitmap - not enough in BSS (1)", 282 .c = { 283 .width = NL80211_CHAN_WIDTH_160, 284 .chan = &chan_6ghz_105, 285 .center_freq1 = 6475 + 30, 286 .punctured = 0x0001, 287 }, 288 .dbe[0] = IEEE80211_UHR_DBE_OPER_BW_320_1 | 289 IEEE80211_UHR_DBE_OPER_DIS_SUBCHANNEL_BITMAP_PRES, 290 /* DBE disabled subchannel bitmap == 0 */ 291 .fails = true, 292 }, 293 { 294 .desc = "bad disabled subchannel bitmap - too much in BSS (1)", 295 .c = { 296 .width = NL80211_CHAN_WIDTH_160, 297 .chan = &chan_6ghz_105, 298 .center_freq1 = 6475 + 30, 299 .punctured = 0x0001, 300 }, 301 .dbe[0] = IEEE80211_UHR_DBE_OPER_BW_320_1 | 302 IEEE80211_UHR_DBE_OPER_DIS_SUBCHANNEL_BITMAP_PRES, 303 /* DBE disabled subchannel bitmap == 0x0300 */ 304 .dbe[2] = 0x03, 305 .fails = true, 306 }, 307 { 308 .desc = "bad disabled subchannel bitmap - not enough in BSS (2)", 309 .c = { 310 .width = NL80211_CHAN_WIDTH_160, 311 .chan = &chan_6ghz_105, 312 .center_freq1 = 6475 + 30, 313 .punctured = 0x0001, 314 }, 315 .dbe[0] = IEEE80211_UHR_DBE_OPER_BW_320_2 | 316 IEEE80211_UHR_DBE_OPER_DIS_SUBCHANNEL_BITMAP_PRES, 317 /* DBE disabled subchannel bitmap == 0 */ 318 .fails = true, 319 }, 320 { 321 .desc = "bad disabled subchannel bitmap - too much in BSS (2)", 322 .c = { 323 .width = NL80211_CHAN_WIDTH_160, 324 .chan = &chan_6ghz_105, 325 .center_freq1 = 6475 + 30, 326 .punctured = 0x0001, 327 }, 328 .dbe[0] = IEEE80211_UHR_DBE_OPER_BW_320_2 | 329 IEEE80211_UHR_DBE_OPER_DIS_SUBCHANNEL_BITMAP_PRES, 330 /* DBE disabled subchannel bitmap == 0x03 */ 331 .dbe[1] = 0x03, 332 .fails = true, 333 }, 334 { 335 .desc = "bad disabled subchannel bitmap - bad bitmap", 336 .c = { 337 .width = NL80211_CHAN_WIDTH_160, 338 .chan = &chan_6ghz_105, 339 .center_freq1 = 6475 + 30, 340 .punctured = 0x0001, 341 }, 342 .dbe[0] = IEEE80211_UHR_DBE_OPER_BW_320_1 | 343 IEEE80211_UHR_DBE_OPER_DIS_SUBCHANNEL_BITMAP_PRES, 344 /* DBE disabled subchannel bitmap == 0x1100 */ 345 .dbe[2] = 0x11, 346 .fails = true, 347 }, 348 { 349 .desc = "good disabled subchannel bitmap (1)", 350 .c = { 351 .width = NL80211_CHAN_WIDTH_160, 352 .chan = &chan_6ghz_105, 353 .center_freq1 = 6475 + 30, 354 .punctured = 0x0003, 355 }, 356 .dbe[0] = IEEE80211_UHR_DBE_OPER_BW_320_1 | 357 IEEE80211_UHR_DBE_OPER_DIS_SUBCHANNEL_BITMAP_PRES, 358 /* DBE disabled subchannel bitmap == 0x0300 */ 359 .dbe[2] = 0x03, 360 .cf1 = 6425, 361 }, 362 { 363 .desc = "good disabled subchannel bitmap (2)", 364 .c = { 365 .width = NL80211_CHAN_WIDTH_160, 366 .chan = &chan_6ghz_105, 367 .center_freq1 = 6475 + 30, 368 .punctured = 0x0003, 369 }, 370 .dbe[0] = IEEE80211_UHR_DBE_OPER_BW_320_2 | 371 IEEE80211_UHR_DBE_OPER_DIS_SUBCHANNEL_BITMAP_PRES, 372 /* DBE disabled subchannel bitmap == 0x0003 */ 373 .dbe[1] = 0x03, 374 .cf1 = 6585, 375 }, 376 }; 377 378 KUNIT_ARRAY_PARAM_DESC(chandef_dbe, chandef_dbe_cases, desc) 379 380 static void test_chandef_dbe(struct kunit *test) 381 { 382 const struct chandef_dbe_case *params = test->param_value; 383 struct cfg80211_chan_def c = params->c; 384 int ret; 385 386 KUNIT_EXPECT_EQ(test, cfg80211_chandef_valid(¶ms->c), true); 387 388 ret = cfg80211_chandef_add_dbe(&c, (void *)params->dbe); 389 KUNIT_EXPECT_EQ(test, ret != 0, params->fails); 390 391 if (params->fails) 392 return; 393 394 KUNIT_EXPECT_EQ(test, c.center_freq1, params->cf1); 395 } 396 397 static struct kunit_case chandef_test_cases[] = { 398 KUNIT_CASE_PARAM(test_chandef_compat, chandef_compat_gen_params), 399 KUNIT_CASE_PARAM(test_chandef_dbe, chandef_dbe_gen_params), 400 {} 401 }; 402 403 static struct kunit_suite chandef = { 404 .name = "cfg80211-chandef", 405 .test_cases = chandef_test_cases, 406 }; 407 408 kunit_test_suite(chandef); 409