File Index
Files and directories
Sign in
FILE

utils.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/wireless/intel/iwlwifi/mld/tests/utils.c C
  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
 23int 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
 71IWL_MLD_ALLOC_FN(link, bss_conf)
 72
 73static 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
 97IWL_MLD_ALLOC_FN(vif, vif)
 98
 99/* Helper function to add and initialize a VIF for KUnit tests */
100struct 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 */
132struct ieee80211_bss_conf *
133iwlmld_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
148struct ieee80211_chanctx_conf *
149iwlmld_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
177void 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
202IWL_MLD_ALLOC_FN(link_sta, link_sta)
203
204static 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
229static struct ieee80211_link_sta *
230iwlmld_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 */
250static struct ieee80211_sta *
251iwlmld_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 */
281static 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
302struct 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
323static 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
331static struct ieee80211_vif *
332iwlmld_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
363struct ieee80211_vif *
364iwlmld_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
387struct ieee80211_vif *
388iwlmld_kunit_setup_non_mlo_assoc(struct iwl_mld_kunit_link *assoc_link)
389{
390	return iwlmld_kunit_setup_assoc(false, assoc_link);
391}
392
393struct 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
407struct 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
444struct 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
458struct 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
475static 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
484KUNIT_ARRAY_PARAM_DESC(chandef, chandef_cases, desc);
485
486static 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
493static struct kunit_case chandef_test_cases[] = {
494	KUNIT_CASE_PARAM(test_iwl_mld_chandef_valid, chandef_gen_params),
495	{}
496};
497
498static struct kunit_suite chandef_tests = {
499	.name = "iwlmld_valid_test_chandefs",
500	.test_cases = chandef_test_cases,
501};
502
503kunit_test_suite(chandef_tests);
~/ Read-only file preview.