1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 /* 3 * KUnit tests for channel helper functions 4 * 5 * Copyright (C) 2024-2025 Intel Corporation 6 */ 7 #include <kunit/test.h> 8 #include <kunit/test-bug.h> 9 10 #include "utils.h" 11 12 #include <linux/device.h> 13 14 #include "fw/api/scan.h" 15 #include "fw/api/mac-cfg.h" 16 #include "iwl-trans.h" 17 #include "mld.h" 18 #include "iface.h" 19 #include "link.h" 20 #include "phy.h" 21 #include "sta.h" 22 23 int iwlmld_kunit_test_init(struct kunit *test) 24 { 25 struct iwl_mld *mld; 26 struct iwl_trans *trans; 27 const struct iwl_rf_cfg *cfg; 28 struct iwl_fw *fw; 29 struct ieee80211_hw *hw; 30 31 KUNIT_ALLOC_AND_ASSERT(test, trans); 32 KUNIT_ALLOC_AND_ASSERT(test, trans->dev); 33 KUNIT_ALLOC_AND_ASSERT(test, cfg); 34 KUNIT_ALLOC_AND_ASSERT(test, fw); 35 KUNIT_ALLOC_AND_ASSERT(test, hw); 36 KUNIT_ALLOC_AND_ASSERT(test, hw->wiphy); 37 38 mutex_init(&hw->wiphy->mtx); 39 40 /* Allocate and initialize the mld structure */ 41 KUNIT_ALLOC_AND_ASSERT(test, mld); 42 iwl_construct_mld(mld, trans, cfg, fw, hw, NULL); 43 44 fw->ucode_capa.num_stations = IWL_STATION_COUNT_MAX; 45 fw->ucode_capa.num_links = IWL_FW_MAX_LINK_ID + 1; 46 47 mld->fwrt.trans = trans; 48 mld->fwrt.fw = fw; 49 mld->fwrt.dev = trans->dev; 50 51 /* TODO: add priv_size to hw allocation and setup hw->priv to enable 52 * testing mac80211 callbacks 53 */ 54 55 KUNIT_ALLOC_AND_ASSERT(test, mld->nvm_data); 56 KUNIT_ALLOC_AND_ASSERT_SIZE(test, mld->scan.cmd, 57 sizeof(struct iwl_scan_req_umac_v17)); 58 mld->scan.cmd_size = sizeof(struct iwl_scan_req_umac_v17); 59 60 /* This is not the state at the end of the regular opmode_start, 61 * but it is more common to need it. Explicitly undo this if needed. 62 */ 63 mld->trans->state = IWL_TRANS_FW_ALIVE; 64 mld->fw_status.running = true; 65 66 /* Avoid passing mld struct around */ 67 test->priv = mld; 68 return 0; 69 } 70 71 IWL_MLD_ALLOC_FN(link, bss_conf) 72 73 static void iwlmld_kunit_init_link(struct ieee80211_vif *vif, 74 struct ieee80211_bss_conf *link, 75 struct iwl_mld_link *mld_link, int link_id) 76 { 77 struct kunit *test = kunit_get_current_test(); 78 struct iwl_mld *mld = test->priv; 79 struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); 80 int ret; 81 82 /* setup mac80211 link */ 83 rcu_assign_pointer(vif->link_conf[link_id], link); 84 link->link_id = link_id; 85 link->vif = vif; 86 link->beacon_int = 100; 87 link->dtim_period = 3; 88 link->qos = true; 89 90 /* and mld_link */ 91 ret = iwl_mld_allocate_link_fw_id(mld, &mld_link->fw_id, link); 92 KUNIT_ASSERT_EQ(test, ret, 0); 93 rcu_assign_pointer(mld_vif->link[link_id], mld_link); 94 rcu_assign_pointer(vif->link_conf[link_id], link); 95 } 96 97 IWL_MLD_ALLOC_FN(vif, vif) 98 99 /* Helper function to add and initialize a VIF for KUnit tests */ 100 struct ieee80211_vif *iwlmld_kunit_add_vif(bool mlo, enum nl80211_iftype type) 101 { 102 struct kunit *test = kunit_get_current_test(); 103 struct iwl_mld *mld = test->priv; 104 struct ieee80211_vif *vif; 105 struct iwl_mld_vif *mld_vif; 106 int ret; 107 108 /* TODO: support more types */ 109 KUNIT_ASSERT_EQ(test, type, NL80211_IFTYPE_STATION); 110 111 KUNIT_ALLOC_AND_ASSERT_SIZE(test, vif, 112 sizeof(*vif) + sizeof(*mld_vif)); 113 114 vif->type = type; 115 mld_vif = iwl_mld_vif_from_mac80211(vif); 116 mld_vif->mld = mld; 117 118 ret = iwl_mld_allocate_vif_fw_id(mld, &mld_vif->fw_id, vif); 119 KUNIT_ASSERT_EQ(test, ret, 0); 120 121 /* TODO: revisit (task=EHT) */ 122 if (mlo) 123 return vif; 124 125 /* Initialize the default link */ 126 iwlmld_kunit_init_link(vif, &vif->bss_conf, &mld_vif->deflink, 0); 127 128 return vif; 129 } 130 131 /* Use only for MLO vif */ 132 struct ieee80211_bss_conf * 133 iwlmld_kunit_add_link(struct ieee80211_vif *vif, int link_id) 134 { 135 struct kunit *test = kunit_get_current_test(); 136 struct ieee80211_bss_conf *link; 137 struct iwl_mld_link *mld_link; 138 139 KUNIT_ALLOC_AND_ASSERT(test, link); 140 KUNIT_ALLOC_AND_ASSERT(test, mld_link); 141 142 iwlmld_kunit_init_link(vif, link, mld_link, link_id); 143 vif->valid_links |= BIT(link_id); 144 145 return link; 146 } 147 148 struct ieee80211_chanctx_conf * 149 iwlmld_kunit_add_chanctx(const struct cfg80211_chan_def *def) 150 { 151 struct kunit *test = kunit_get_current_test(); 152 struct iwl_mld *mld = test->priv; 153 struct ieee80211_chanctx_conf *ctx; 154 struct iwl_mld_phy *phy; 155 int fw_id; 156 157 KUNIT_ALLOC_AND_ASSERT_SIZE(test, ctx, sizeof(*ctx) + sizeof(*phy)); 158 159 /* Setup the chanctx conf */ 160 ctx->def = *def; 161 ctx->min_def = *def; 162 ctx->ap = *def; 163 164 /* and the iwl_mld_phy */ 165 phy = iwl_mld_phy_from_mac80211(ctx); 166 167 fw_id = iwl_mld_allocate_fw_phy_id(mld); 168 KUNIT_ASSERT_GE(test, fw_id, 0); 169 170 phy->fw_id = fw_id; 171 phy->mld = mld; 172 phy->chandef = *def; 173 174 return ctx; 175 } 176 177 void iwlmld_kunit_assign_chanctx_to_link(struct ieee80211_vif *vif, 178 struct ieee80211_bss_conf *link, 179 struct ieee80211_chanctx_conf *ctx) 180 { 181 struct kunit *test = kunit_get_current_test(); 182 struct iwl_mld *mld = test->priv; 183 struct iwl_mld_link *mld_link; 184 185 KUNIT_EXPECT_NULL(test, rcu_access_pointer(link->chanctx_conf)); 186 rcu_assign_pointer(link->chanctx_conf, ctx); 187 188 lockdep_assert_wiphy(mld->wiphy); 189 190 mld_link = iwl_mld_link_from_mac80211(link); 191 192 KUNIT_EXPECT_NULL(test, rcu_access_pointer(mld_link->chan_ctx)); 193 KUNIT_EXPECT_FALSE(test, mld_link->active); 194 195 rcu_assign_pointer(mld_link->chan_ctx, ctx); 196 mld_link->active = true; 197 198 if (ieee80211_vif_is_mld(vif)) 199 vif->active_links |= BIT(link->link_id); 200 } 201 202 IWL_MLD_ALLOC_FN(link_sta, link_sta) 203 204 static void iwlmld_kunit_add_link_sta(struct ieee80211_sta *sta, 205 struct ieee80211_link_sta *link_sta, 206 struct iwl_mld_link_sta *mld_link_sta, 207 u8 link_id) 208 { 209 struct kunit *test = kunit_get_current_test(); 210 struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta); 211 struct iwl_mld *mld = test->priv; 212 u8 fw_id; 213 int ret; 214 215 /* initialize mac80211's link_sta */ 216 link_sta->link_id = link_id; 217 rcu_assign_pointer(sta->link[link_id], link_sta); 218 219 link_sta->sta = sta; 220 221 /* and the iwl_mld_link_sta */ 222 ret = iwl_mld_allocate_link_sta_fw_id(mld, &fw_id, link_sta); 223 KUNIT_ASSERT_EQ(test, ret, 0); 224 mld_link_sta->fw_id = fw_id; 225 226 rcu_assign_pointer(mld_sta->link[link_id], mld_link_sta); 227 } 228 229 static struct ieee80211_link_sta * 230 iwlmld_kunit_alloc_link_sta(struct ieee80211_sta *sta, int link_id) 231 { 232 struct kunit *test = kunit_get_current_test(); 233 struct ieee80211_link_sta *link_sta; 234 struct iwl_mld_link_sta *mld_link_sta; 235 236 /* Only valid for MLO */ 237 KUNIT_ASSERT_TRUE(test, sta->valid_links); 238 239 KUNIT_ALLOC_AND_ASSERT(test, link_sta); 240 KUNIT_ALLOC_AND_ASSERT(test, mld_link_sta); 241 242 iwlmld_kunit_add_link_sta(sta, link_sta, mld_link_sta, link_id); 243 244 sta->valid_links |= BIT(link_id); 245 246 return link_sta; 247 } 248 249 /* Allocate and initialize a STA with the first link_sta */ 250 static struct ieee80211_sta * 251 iwlmld_kunit_add_sta(struct ieee80211_vif *vif, int link_id) 252 { 253 struct kunit *test = kunit_get_current_test(); 254 struct ieee80211_sta *sta; 255 struct iwl_mld_sta *mld_sta; 256 257 /* Allocate memory for ieee80211_sta with embedded iwl_mld_sta */ 258 KUNIT_ALLOC_AND_ASSERT_SIZE(test, sta, sizeof(*sta) + sizeof(*mld_sta)); 259 260 /* TODO: allocate and initialize the TXQs ? */ 261 262 mld_sta = iwl_mld_sta_from_mac80211(sta); 263 mld_sta->vif = vif; 264 mld_sta->mld = test->priv; 265 266 /* TODO: adjust for internal stations */ 267 mld_sta->sta_type = STATION_TYPE_PEER; 268 269 if (link_id >= 0) { 270 iwlmld_kunit_add_link_sta(sta, &sta->deflink, 271 &mld_sta->deflink, link_id); 272 sta->valid_links = BIT(link_id); 273 } else { 274 iwlmld_kunit_add_link_sta(sta, &sta->deflink, 275 &mld_sta->deflink, 0); 276 } 277 return sta; 278 } 279 280 /* Move s STA to a state */ 281 static void iwlmld_kunit_move_sta_state(struct ieee80211_vif *vif, 282 struct ieee80211_sta *sta, 283 enum ieee80211_sta_state state) 284 { 285 struct kunit *test = kunit_get_current_test(); 286 struct iwl_mld_sta *mld_sta; 287 struct iwl_mld_vif *mld_vif; 288 289 /* The sta will be removed automatically at the end of the test */ 290 KUNIT_ASSERT_NE(test, state, IEEE80211_STA_NOTEXIST); 291 292 mld_sta = iwl_mld_sta_from_mac80211(sta); 293 mld_sta->sta_state = state; 294 295 mld_vif = iwl_mld_vif_from_mac80211(mld_sta->vif); 296 mld_vif->authorized = state == IEEE80211_STA_AUTHORIZED; 297 298 if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) 299 mld_vif->ap_sta = sta; 300 } 301 302 struct ieee80211_sta *iwlmld_kunit_setup_sta(struct ieee80211_vif *vif, 303 enum ieee80211_sta_state state, 304 int link_id) 305 { 306 struct kunit *test = kunit_get_current_test(); 307 struct ieee80211_sta *sta; 308 309 /* The sta will be removed automatically at the end of the test */ 310 KUNIT_ASSERT_NE(test, state, IEEE80211_STA_NOTEXIST); 311 312 /* First - allocate and init the STA */ 313 sta = iwlmld_kunit_add_sta(vif, link_id); 314 315 /* Now move it all the way to the wanted state */ 316 for (enum ieee80211_sta_state _state = IEEE80211_STA_NONE; 317 _state <= state; _state++) 318 iwlmld_kunit_move_sta_state(vif, sta, state); 319 320 return sta; 321 } 322 323 static void iwlmld_kunit_set_vif_associated(struct ieee80211_vif *vif) 324 { 325 /* TODO: setup chanreq */ 326 /* TODO setup capabilities */ 327 328 vif->cfg.assoc = 1; 329 } 330 331 static struct ieee80211_vif * 332 iwlmld_kunit_setup_assoc(bool mlo, struct iwl_mld_kunit_link *assoc_link) 333 { 334 struct kunit *test = kunit_get_current_test(); 335 struct iwl_mld *mld = test->priv; 336 struct ieee80211_vif *vif; 337 struct ieee80211_bss_conf *link; 338 struct ieee80211_chanctx_conf *chan_ctx; 339 340 KUNIT_ASSERT_TRUE(test, mlo || assoc_link->id == 0); 341 342 vif = iwlmld_kunit_add_vif(mlo, NL80211_IFTYPE_STATION); 343 344 if (mlo) 345 link = iwlmld_kunit_add_link(vif, assoc_link->id); 346 else 347 link = &vif->bss_conf; 348 349 chan_ctx = iwlmld_kunit_add_chanctx(assoc_link->chandef); 350 351 wiphy_lock(mld->wiphy); 352 iwlmld_kunit_assign_chanctx_to_link(vif, link, chan_ctx); 353 wiphy_unlock(mld->wiphy); 354 355 /* The AP sta will now be pointer to by mld_vif->ap_sta */ 356 iwlmld_kunit_setup_sta(vif, IEEE80211_STA_AUTHORIZED, assoc_link->id); 357 358 iwlmld_kunit_set_vif_associated(vif); 359 360 return vif; 361 } 362 363 struct ieee80211_vif * 364 iwlmld_kunit_setup_mlo_assoc(u16 valid_links, 365 struct iwl_mld_kunit_link *assoc_link) 366 { 367 struct kunit *test = kunit_get_current_test(); 368 struct ieee80211_vif *vif; 369 370 KUNIT_ASSERT_TRUE(test, 371 hweight16(valid_links) == 1 || 372 hweight16(valid_links) == 2); 373 KUNIT_ASSERT_TRUE(test, valid_links & BIT(assoc_link->id)); 374 375 vif = iwlmld_kunit_setup_assoc(true, assoc_link); 376 377 /* Add the other link, if applicable */ 378 if (hweight16(valid_links) > 1) { 379 u8 other_link_id = ffs(valid_links & ~BIT(assoc_link->id)) - 1; 380 381 iwlmld_kunit_add_link(vif, other_link_id); 382 } 383 384 return vif; 385 } 386 387 struct ieee80211_vif * 388 iwlmld_kunit_setup_non_mlo_assoc(struct iwl_mld_kunit_link *assoc_link) 389 { 390 return iwlmld_kunit_setup_assoc(false, assoc_link); 391 } 392 393 struct iwl_rx_packet * 394 _iwl_mld_kunit_create_pkt(const void *notif, size_t notif_sz) 395 { 396 struct kunit *test = kunit_get_current_test(); 397 struct iwl_rx_packet *pkt; 398 399 KUNIT_ALLOC_AND_ASSERT_SIZE(test, pkt, sizeof(pkt) + notif_sz); 400 401 memcpy(pkt->data, notif, notif_sz); 402 pkt->len_n_flags = cpu_to_le32(sizeof(pkt->hdr) + notif_sz); 403 404 return pkt; 405 } 406 407 struct ieee80211_vif *iwlmld_kunit_assoc_emlsr(struct iwl_mld_kunit_link *link1, 408 struct iwl_mld_kunit_link *link2) 409 { 410 struct kunit *test = kunit_get_current_test(); 411 struct iwl_mld *mld = test->priv; 412 struct ieee80211_vif *vif; 413 struct ieee80211_bss_conf *link; 414 struct ieee80211_chanctx_conf *chan_ctx; 415 struct ieee80211_sta *sta; 416 struct iwl_mld_vif *mld_vif; 417 u16 valid_links = BIT(link1->id) | BIT(link2->id); 418 419 KUNIT_ASSERT_TRUE(test, hweight16(valid_links) == 2); 420 421 vif = iwlmld_kunit_setup_mlo_assoc(valid_links, link1); 422 mld_vif = iwl_mld_vif_from_mac80211(vif); 423 424 /* Activate second link */ 425 wiphy_lock(mld->wiphy); 426 427 link = wiphy_dereference(mld->wiphy, vif->link_conf[link2->id]); 428 KUNIT_EXPECT_NOT_NULL(test, link); 429 430 chan_ctx = iwlmld_kunit_add_chanctx(link2->chandef); 431 iwlmld_kunit_assign_chanctx_to_link(vif, link, chan_ctx); 432 433 wiphy_unlock(mld->wiphy); 434 435 /* And other link sta */ 436 sta = mld_vif->ap_sta; 437 KUNIT_EXPECT_NOT_NULL(test, sta); 438 439 iwlmld_kunit_alloc_link_sta(sta, link2->id); 440 441 return vif; 442 } 443 444 struct element *iwlmld_kunit_gen_element(u8 id, const void *data, size_t len) 445 { 446 struct kunit *test = kunit_get_current_test(); 447 struct element *elem; 448 449 KUNIT_ALLOC_AND_ASSERT_SIZE(test, elem, sizeof(*elem) + len); 450 451 elem->id = id; 452 elem->datalen = len; 453 memcpy(elem->data, data, len); 454 455 return elem; 456 } 457 458 struct iwl_mld_phy *iwlmld_kunit_get_phy_of_link(struct ieee80211_vif *vif, 459 u8 link_id) 460 { 461 struct kunit *test = kunit_get_current_test(); 462 struct iwl_mld *mld = test->priv; 463 struct ieee80211_chanctx_conf *chanctx; 464 struct ieee80211_bss_conf *link = 465 wiphy_dereference(mld->wiphy, vif->link_conf[link_id]); 466 467 KUNIT_EXPECT_NOT_NULL(test, link); 468 469 chanctx = wiphy_dereference(mld->wiphy, link->chanctx_conf); 470 KUNIT_EXPECT_NOT_NULL(test, chanctx); 471 472 return iwl_mld_phy_from_mac80211(chanctx); 473 } 474 475 static const struct chandef_case { 476 const char *desc; 477 const struct cfg80211_chan_def *chandef; 478 } chandef_cases[] = { 479 #define CHANDEF(c, ...) { .desc = "chandef " #c " valid", .chandef = &c, }, 480 CHANDEF_LIST 481 #undef CHANDEF 482 }; 483 484 KUNIT_ARRAY_PARAM_DESC(chandef, chandef_cases, desc); 485 486 static void test_iwl_mld_chandef_valid(struct kunit *test) 487 { 488 const struct chandef_case *params = test->param_value; 489 490 KUNIT_EXPECT_EQ(test, true, cfg80211_chandef_valid(params->chandef)); 491 } 492 493 static struct kunit_case chandef_test_cases[] = { 494 KUNIT_CASE_PARAM(test_iwl_mld_chandef_valid, chandef_gen_params), 495 {} 496 }; 497 498 static struct kunit_suite chandef_tests = { 499 .name = "iwlmld_valid_test_chandefs", 500 .test_cases = chandef_test_cases, 501 }; 502 503 kunit_test_suite(chandef_tests); 504