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 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 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 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