xref: /linux/net/wireless/tests/chan.c (revision d6f6d7123355388f2f41c1b6c108bfdba18b0cfc)
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(&params->c2), true);
210 
211 	expect = params->compat ? &params->c2 : NULL;
212 
213 	ret = cfg80211_chandef_compatible(&c1, &params->c2);
214 	KUNIT_EXPECT_PTR_EQ(test, ret, expect);
215 
216 	if (!params->c1.chan)
217 		expect = &c1;
218 
219 	ret = cfg80211_chandef_compatible(&params->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(&params->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