xref: /linux/drivers/net/wireless/intel/iwlwifi/mld/tests/utils.c (revision 1a9239bb4253f9076b5b4b2a1a4e8d7defd77a95)
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 
iwlmld_kunit_test_init(struct kunit * test)23 int iwlmld_kunit_test_init(struct kunit *test)
24 {
25 	struct iwl_mld *mld;
26 	struct iwl_trans *trans;
27 	const struct iwl_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 
IWL_MLD_ALLOC_FN(link,bss_conf)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 
IWL_MLD_ALLOC_FN(vif,vif)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 *
iwlmld_kunit_add_link(struct ieee80211_vif * vif,int link_id)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 *
iwlmld_kunit_add_chanctx_from_def(struct cfg80211_chan_def * def)149 iwlmld_kunit_add_chanctx_from_def(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 
iwlmld_kunit_assign_chanctx_to_link(struct ieee80211_vif * vif,struct ieee80211_bss_conf * link,struct ieee80211_chanctx_conf * ctx)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 
IWL_MLD_ALLOC_FN(link_sta,link_sta)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 *
iwlmld_kunit_alloc_link_sta(struct ieee80211_sta * sta,int link_id)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 *
iwlmld_kunit_add_sta(struct ieee80211_vif * vif,int link_id)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 */
iwlmld_kunit_move_sta_state(struct ieee80211_vif * vif,struct ieee80211_sta * sta,enum ieee80211_sta_state 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 
iwlmld_kunit_setup_sta(struct ieee80211_vif * vif,enum ieee80211_sta_state state,int link_id)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 
iwlmld_kunit_set_vif_associated(struct ieee80211_vif * vif)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 *
iwlmld_kunit_setup_assoc(bool mlo,struct iwl_mld_kunit_link * assoc_link)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->band,
350 					    assoc_link->bandwidth);
351 
352 	wiphy_lock(mld->wiphy);
353 	iwlmld_kunit_assign_chanctx_to_link(vif, link, chan_ctx);
354 	wiphy_unlock(mld->wiphy);
355 
356 	/* The AP sta will now be pointer to by mld_vif->ap_sta */
357 	iwlmld_kunit_setup_sta(vif, IEEE80211_STA_AUTHORIZED, assoc_link->id);
358 
359 	iwlmld_kunit_set_vif_associated(vif);
360 
361 	return vif;
362 }
363 
364 struct ieee80211_vif *
iwlmld_kunit_setup_mlo_assoc(u16 valid_links,struct iwl_mld_kunit_link * assoc_link)365 iwlmld_kunit_setup_mlo_assoc(u16 valid_links,
366 			     struct iwl_mld_kunit_link *assoc_link)
367 {
368 	struct kunit *test = kunit_get_current_test();
369 	struct ieee80211_vif *vif;
370 
371 	KUNIT_ASSERT_TRUE(test,
372 			  hweight16(valid_links) == 1 ||
373 			  hweight16(valid_links) == 2);
374 	KUNIT_ASSERT_TRUE(test, valid_links & BIT(assoc_link->id));
375 
376 	vif = iwlmld_kunit_setup_assoc(true, assoc_link);
377 
378 	/* Add the other link, if applicable */
379 	if (hweight16(valid_links) > 1) {
380 		u8 other_link_id = ffs(valid_links & ~BIT(assoc_link->id)) - 1;
381 
382 		iwlmld_kunit_add_link(vif, other_link_id);
383 	}
384 
385 	return vif;
386 }
387 
388 struct ieee80211_vif *
iwlmld_kunit_setup_non_mlo_assoc(struct iwl_mld_kunit_link * assoc_link)389 iwlmld_kunit_setup_non_mlo_assoc(struct iwl_mld_kunit_link *assoc_link)
390 {
391 	return iwlmld_kunit_setup_assoc(false, assoc_link);
392 }
393 
394 struct iwl_rx_packet *
_iwl_mld_kunit_create_pkt(const void * notif,size_t notif_sz)395 _iwl_mld_kunit_create_pkt(const void *notif, size_t notif_sz)
396 {
397 	struct kunit *test = kunit_get_current_test();
398 	struct iwl_rx_packet *pkt;
399 
400 	KUNIT_ALLOC_AND_ASSERT_SIZE(test, pkt, sizeof(pkt) + notif_sz);
401 
402 	memcpy(pkt->data, notif, notif_sz);
403 	pkt->len_n_flags = cpu_to_le32(sizeof(pkt->hdr) + notif_sz);
404 
405 	return pkt;
406 }
407 
iwlmld_kunit_assoc_emlsr(struct iwl_mld_kunit_link * link1,struct iwl_mld_kunit_link * link2)408 struct ieee80211_vif *iwlmld_kunit_assoc_emlsr(struct iwl_mld_kunit_link *link1,
409 					       struct iwl_mld_kunit_link *link2)
410 {
411 	struct kunit *test = kunit_get_current_test();
412 	struct iwl_mld *mld = test->priv;
413 	struct ieee80211_vif *vif;
414 	struct ieee80211_bss_conf *link;
415 	struct ieee80211_chanctx_conf *chan_ctx;
416 	struct ieee80211_sta *sta;
417 	struct iwl_mld_vif *mld_vif;
418 	u16 valid_links = BIT(link1->id) | BIT(link2->id);
419 
420 	KUNIT_ASSERT_TRUE(test, hweight16(valid_links) == 2);
421 
422 	vif = iwlmld_kunit_setup_mlo_assoc(valid_links, link1);
423 	mld_vif = iwl_mld_vif_from_mac80211(vif);
424 
425 	/* Activate second link */
426 	wiphy_lock(mld->wiphy);
427 
428 	link = wiphy_dereference(mld->wiphy, vif->link_conf[link2->id]);
429 	KUNIT_EXPECT_NOT_NULL(test, link);
430 
431 	chan_ctx = iwlmld_kunit_add_chanctx(link2->band, link2->bandwidth);
432 	iwlmld_kunit_assign_chanctx_to_link(vif, link, chan_ctx);
433 
434 	wiphy_unlock(mld->wiphy);
435 
436 	/* And other link sta */
437 	sta = mld_vif->ap_sta;
438 	KUNIT_EXPECT_NOT_NULL(test, sta);
439 
440 	iwlmld_kunit_alloc_link_sta(sta, link2->id);
441 
442 	return vif;
443 }
444 
iwlmld_kunit_gen_element(u8 id,const void * data,size_t len)445 struct element *iwlmld_kunit_gen_element(u8 id, const void *data, size_t len)
446 {
447 	struct kunit *test = kunit_get_current_test();
448 	struct element *elem;
449 
450 	KUNIT_ALLOC_AND_ASSERT_SIZE(test, elem, sizeof(*elem) + len);
451 
452 	elem->id = id;
453 	elem->datalen = len;
454 	memcpy(elem->data, data, len);
455 
456 	return elem;
457 }
458 
iwlmld_kunit_get_phy_of_link(struct ieee80211_vif * vif,u8 link_id)459 struct iwl_mld_phy *iwlmld_kunit_get_phy_of_link(struct ieee80211_vif *vif,
460 						 u8 link_id)
461 {
462 	struct kunit *test = kunit_get_current_test();
463 	struct iwl_mld *mld = test->priv;
464 	struct ieee80211_chanctx_conf *chanctx;
465 	struct ieee80211_bss_conf *link =
466 		wiphy_dereference(mld->wiphy, vif->link_conf[link_id]);
467 
468 	KUNIT_EXPECT_NOT_NULL(test, link);
469 
470 	chanctx = wiphy_dereference(mld->wiphy, link->chanctx_conf);
471 	KUNIT_EXPECT_NOT_NULL(test, chanctx);
472 
473 	return iwl_mld_phy_from_mac80211(chanctx);
474 }
475