1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * KUnit tests for channel helper functions
4 *
5 * Copyright (C) 2024 Intel Corporation
6 */
7 #include <net/mac80211.h>
8 #include "../mvm.h"
9 #include <kunit/test.h>
10
11 MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING);
12
13 static struct wiphy wiphy = {
14 .mtx = __MUTEX_INITIALIZER(wiphy.mtx),
15 };
16
17 static struct ieee80211_hw hw = {
18 .wiphy = &wiphy,
19 };
20
21 static struct ieee80211_channel chan_5ghz = {
22 .band = NL80211_BAND_5GHZ,
23 };
24
25 static struct ieee80211_channel chan_6ghz = {
26 .band = NL80211_BAND_6GHZ,
27 };
28
29 static struct ieee80211_channel chan_2ghz = {
30 .band = NL80211_BAND_2GHZ,
31 };
32
33 static struct cfg80211_chan_def chandef_a = {};
34
35 static struct cfg80211_chan_def chandef_b = {};
36
37 static struct iwl_mvm_phy_ctxt ctx = {};
38
39 static struct iwl_mvm_vif_link_info mvm_link = {
40 .phy_ctxt = &ctx,
41 .active = true
42 };
43
44 static struct cfg80211_bss bss = {};
45
46 static struct ieee80211_bss_conf link_conf = {.bss = &bss};
47
48 static const struct iwl_fw_cmd_version entry = {
49 .group = LEGACY_GROUP,
50 .cmd = BT_PROFILE_NOTIFICATION,
51 .notif_ver = 4
52 };
53
54 static struct iwl_fw fw = {
55 .ucode_capa = {
56 .n_cmd_versions = 1,
57 .cmd_versions = &entry,
58 },
59 };
60
61 static struct iwl_mvm mvm = {
62 .hw = &hw,
63 .fw = &fw,
64 };
65
66 static const struct link_grading_case {
67 const char *desc;
68 const struct cfg80211_chan_def chandef;
69 s32 signal;
70 s16 channel_util;
71 int chan_load_by_us;
72 unsigned int grade;
73 } link_grading_cases[] = {
74 {
75 .desc = "UHB, RSSI below range, no factors",
76 .chandef = {
77 .chan = &chan_6ghz,
78 .width = NL80211_CHAN_WIDTH_20,
79 },
80 .signal = -100,
81 .grade = 177,
82 },
83 {
84 .desc = "LB, RSSI in range, no factors",
85 .chandef = {
86 .chan = &chan_2ghz,
87 .width = NL80211_CHAN_WIDTH_20,
88 },
89 .signal = -84,
90 .grade = 344,
91 },
92 {
93 .desc = "HB, RSSI above range, no factors",
94 .chandef = {
95 .chan = &chan_5ghz,
96 .width = NL80211_CHAN_WIDTH_20,
97 },
98 .signal = -50,
99 .grade = 3442,
100 },
101 {
102 .desc = "HB, BSS Load IE (20 percent), inactive link, no puncturing factor",
103 .chandef = {
104 .chan = &chan_5ghz,
105 .width = NL80211_CHAN_WIDTH_20,
106 },
107 .signal = -66,
108 .channel_util = 51,
109 .grade = 1836,
110 },
111 {
112 .desc = "LB, BSS Load IE (20 percent), active link, chan_load_by_us=10 percent. No puncturing factor",
113 .chandef = {
114 .chan = &chan_2ghz,
115 .width = NL80211_CHAN_WIDTH_20,
116 },
117 .signal = -61,
118 .channel_util = 51,
119 .chan_load_by_us = 10,
120 .grade = 2061,
121 },
122 {
123 .desc = "UHB, BSS Load IE (40 percent), active link, chan_load_by_us=50 (invalid) percent. No puncturing factor",
124 .chandef = {
125 .chan = &chan_6ghz,
126 .width = NL80211_CHAN_WIDTH_20,
127 },
128 .signal = -66,
129 .channel_util = 102,
130 .chan_load_by_us = 50,
131 .grade = 1552,
132 },
133 { .desc = "HB, 80 MHz, no channel load factor, punctured percentage 0",
134 .chandef = {
135 .chan = &chan_5ghz,
136 .width = NL80211_CHAN_WIDTH_80,
137 .punctured = 0x0000
138 },
139 .signal = -72,
140 .grade = 1750,
141 },
142 { .desc = "HB, 160 MHz, no channel load factor, punctured percentage 25",
143 .chandef = {
144 .chan = &chan_5ghz,
145 .width = NL80211_CHAN_WIDTH_160,
146 .punctured = 0x3
147 },
148 .signal = -72,
149 .grade = 1312,
150 },
151 { .desc = "UHB, 320 MHz, no channel load factor, punctured percentage 12.5 (2/16)",
152 .chandef = {
153 .chan = &chan_6ghz,
154 .width = NL80211_CHAN_WIDTH_320,
155 .punctured = 0x3
156 },
157 .signal = -72,
158 .grade = 1806,
159 },
160 { .desc = "HB, 160 MHz, channel load 20, channel load by us 10, punctured percentage 25",
161 .chandef = {
162 .chan = &chan_5ghz,
163 .width = NL80211_CHAN_WIDTH_160,
164 .punctured = 0x3
165 },
166 .channel_util = 51,
167 .chan_load_by_us = 10,
168 .signal = -72,
169 .grade = 1179,
170 },
171 };
172
KUNIT_ARRAY_PARAM_DESC(link_grading,link_grading_cases,desc)173 KUNIT_ARRAY_PARAM_DESC(link_grading, link_grading_cases, desc)
174
175 static void setup_link_conf(struct kunit *test)
176 {
177 const struct link_grading_case *params = test->param_value;
178 size_t vif_size = sizeof(struct ieee80211_vif) +
179 sizeof(struct iwl_mvm_vif);
180 struct ieee80211_vif *vif = kunit_kzalloc(test, vif_size, GFP_KERNEL);
181 struct ieee80211_bss_load_elem *bss_load;
182 struct element *element;
183 size_t ies_size = sizeof(struct cfg80211_bss_ies) + sizeof(*bss_load) + sizeof(element);
184 struct cfg80211_bss_ies *ies;
185 struct iwl_mvm_vif *mvmvif;
186
187 KUNIT_ASSERT_NOT_NULL(test, vif);
188
189 mvmvif = iwl_mvm_vif_from_mac80211(vif);
190 if (params->chan_load_by_us > 0) {
191 ctx.channel_load_by_us = params->chan_load_by_us;
192 mvmvif->link[0] = &mvm_link;
193 }
194
195 link_conf.vif = vif;
196 link_conf.chanreq.oper = params->chandef;
197 bss.signal = DBM_TO_MBM(params->signal);
198
199 ies = kunit_kzalloc(test, ies_size, GFP_KERNEL);
200 KUNIT_ASSERT_NOT_NULL(test, ies);
201 ies->len = sizeof(*bss_load) + sizeof(struct element);
202
203 element = (void *)ies->data;
204 element->datalen = sizeof(*bss_load);
205 element->id = 11;
206
207 bss_load = (void *)element->data;
208 bss_load->channel_util = params->channel_util;
209
210 rcu_assign_pointer(bss.ies, ies);
211 rcu_assign_pointer(bss.beacon_ies, ies);
212 }
213
test_link_grading(struct kunit * test)214 static void test_link_grading(struct kunit *test)
215 {
216 const struct link_grading_case *params = test->param_value;
217 unsigned int ret;
218
219 setup_link_conf(test);
220
221 rcu_read_lock();
222 ret = iwl_mvm_get_link_grade(&link_conf);
223 rcu_read_unlock();
224
225 KUNIT_EXPECT_EQ(test, ret, params->grade);
226
227 kunit_kfree(test, link_conf.vif);
228 RCU_INIT_POINTER(bss.ies, NULL);
229 }
230
231 static struct kunit_case link_grading_test_cases[] = {
232 KUNIT_CASE_PARAM(test_link_grading, link_grading_gen_params),
233 {}
234 };
235
236 static struct kunit_suite link_grading = {
237 .name = "iwlmvm-link-grading",
238 .test_cases = link_grading_test_cases,
239 };
240
241 kunit_test_suite(link_grading);
242
243 static const struct valid_link_pair_case {
244 const char *desc;
245 bool bt;
246 struct ieee80211_channel *chan_a;
247 struct ieee80211_channel *chan_b;
248 enum nl80211_chan_width cw_a;
249 enum nl80211_chan_width cw_b;
250 s32 sig_a;
251 s32 sig_b;
252 bool csa_a;
253 bool valid;
254 } valid_link_pair_cases[] = {
255 {
256 .desc = "HB + UHB, valid.",
257 .chan_a = &chan_6ghz,
258 .chan_b = &chan_5ghz,
259 .valid = true,
260 },
261 {
262 .desc = "LB + HB, no BT.",
263 .chan_a = &chan_2ghz,
264 .chan_b = &chan_5ghz,
265 .valid = false,
266 },
267 {
268 .desc = "LB + HB, with BT.",
269 .bt = true,
270 .chan_a = &chan_2ghz,
271 .chan_b = &chan_5ghz,
272 .valid = false,
273 },
274 {
275 .desc = "Same band",
276 .chan_a = &chan_2ghz,
277 .chan_b = &chan_2ghz,
278 .valid = false,
279 },
280 {
281 .desc = "RSSI: LB, 20 MHz, low",
282 .chan_a = &chan_2ghz,
283 .cw_a = NL80211_CHAN_WIDTH_20,
284 .sig_a = -68,
285 .chan_b = &chan_5ghz,
286 .valid = false,
287 },
288 {
289 .desc = "RSSI: UHB, 20 MHz, high",
290 .chan_a = &chan_6ghz,
291 .cw_a = NL80211_CHAN_WIDTH_20,
292 .sig_a = -66,
293 .chan_b = &chan_5ghz,
294 .cw_b = NL80211_CHAN_WIDTH_20,
295 .valid = true,
296 },
297 {
298 .desc = "RSSI: UHB, 40 MHz, low",
299 .chan_a = &chan_6ghz,
300 .cw_a = NL80211_CHAN_WIDTH_40,
301 .sig_a = -65,
302 .chan_b = &chan_5ghz,
303 .cw_b = NL80211_CHAN_WIDTH_40,
304 .valid = false,
305 },
306 {
307 .desc = "RSSI: UHB, 40 MHz, high",
308 .chan_a = &chan_6ghz,
309 .cw_a = NL80211_CHAN_WIDTH_40,
310 .sig_a = -63,
311 .chan_b = &chan_5ghz,
312 .cw_b = NL80211_CHAN_WIDTH_40,
313 .valid = true,
314 },
315 {
316 .desc = "RSSI: UHB, 80 MHz, low",
317 .chan_a = &chan_6ghz,
318 .cw_a = NL80211_CHAN_WIDTH_80,
319 .sig_a = -62,
320 .chan_b = &chan_5ghz,
321 .cw_b = NL80211_CHAN_WIDTH_80,
322 .valid = false,
323 },
324 {
325 .desc = "RSSI: UHB, 80 MHz, high",
326 .chan_a = &chan_6ghz,
327 .cw_a = NL80211_CHAN_WIDTH_80,
328 .sig_a = -60,
329 .chan_b = &chan_5ghz,
330 .cw_b = NL80211_CHAN_WIDTH_80,
331 .valid = true,
332 },
333 {
334 .desc = "RSSI: UHB, 160 MHz, low",
335 .chan_a = &chan_6ghz,
336 .cw_a = NL80211_CHAN_WIDTH_160,
337 .sig_a = -59,
338 .chan_b = &chan_5ghz,
339 .cw_b = NL80211_CHAN_WIDTH_160,
340 .valid = false,
341 },
342 {
343 .desc = "RSSI: HB, 160 MHz, high",
344 .chan_a = &chan_6ghz,
345 .cw_a = NL80211_CHAN_WIDTH_160,
346 .sig_a = -5,
347 .chan_b = &chan_5ghz,
348 .cw_b = NL80211_CHAN_WIDTH_160,
349 .valid = true,
350 },
351 {
352 .desc = "CSA active",
353 .chan_a = &chan_6ghz,
354 .cw_a = NL80211_CHAN_WIDTH_160,
355 .sig_a = -5,
356 .chan_b = &chan_5ghz,
357 .cw_b = NL80211_CHAN_WIDTH_160,
358 .valid = false,
359 /* same as previous entry with valid=true except for CSA */
360 .csa_a = true,
361 },
362 };
363
KUNIT_ARRAY_PARAM_DESC(valid_link_pair,valid_link_pair_cases,desc)364 KUNIT_ARRAY_PARAM_DESC(valid_link_pair, valid_link_pair_cases, desc)
365
366 static void test_valid_link_pair(struct kunit *test)
367 {
368 const struct valid_link_pair_case *params = test->param_value;
369 size_t vif_size = sizeof(struct ieee80211_vif) +
370 sizeof(struct iwl_mvm_vif);
371 struct ieee80211_vif *vif = kunit_kzalloc(test, vif_size, GFP_KERNEL);
372 struct iwl_trans *trans = kunit_kzalloc(test, sizeof(struct iwl_trans),
373 GFP_KERNEL);
374 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
375 struct iwl_mvm_link_sel_data link_a = {
376 .chandef = &chandef_a,
377 .link_id = 1,
378 .signal = params->sig_a,
379 };
380 struct iwl_mvm_link_sel_data link_b = {
381 .chandef = &chandef_b,
382 .link_id = 5,
383 .signal = params->sig_b,
384 };
385 struct ieee80211_bss_conf *conf;
386 bool result;
387
388 KUNIT_ASSERT_NOT_NULL(test, vif);
389 KUNIT_ASSERT_NOT_NULL(test, trans);
390
391 chandef_a.chan = params->chan_a;
392 chandef_b.chan = params->chan_b;
393
394 chandef_a.width = params->cw_a ?: NL80211_CHAN_WIDTH_20;
395 chandef_b.width = params->cw_b ?: NL80211_CHAN_WIDTH_20;
396
397 mvm.trans = trans;
398
399 mvm.last_bt_notif.wifi_loss_low_rssi = params->bt;
400 mvmvif->mvm = &mvm;
401
402 conf = kunit_kzalloc(test, sizeof(*vif->link_conf[0]), GFP_KERNEL);
403 KUNIT_ASSERT_NOT_NULL(test, conf);
404 conf->chanreq.oper = chandef_a;
405 conf->csa_active = params->csa_a;
406 vif->link_conf[link_a.link_id] = (void __rcu *)conf;
407
408 conf = kunit_kzalloc(test, sizeof(*vif->link_conf[0]), GFP_KERNEL);
409 KUNIT_ASSERT_NOT_NULL(test, conf);
410 conf->chanreq.oper = chandef_b;
411 vif->link_conf[link_b.link_id] = (void __rcu *)conf;
412
413 wiphy_lock(&wiphy);
414 result = iwl_mvm_mld_valid_link_pair(vif, &link_a, &link_b);
415 wiphy_unlock(&wiphy);
416
417 KUNIT_EXPECT_EQ(test, result, params->valid);
418
419 kunit_kfree(test, vif);
420 kunit_kfree(test, trans);
421 }
422
423 static struct kunit_case valid_link_pair_test_cases[] = {
424 KUNIT_CASE_PARAM(test_valid_link_pair, valid_link_pair_gen_params),
425 {},
426 };
427
428 static struct kunit_suite valid_link_pair = {
429 .name = "iwlmvm-valid-link-pair",
430 .test_cases = valid_link_pair_test_cases,
431 };
432
433 kunit_test_suite(valid_link_pair);
434