1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /*
3  * KUnit tests for channel helper functions
4  *
5  * Copyright (C) 2024 Intel Corporation
6  */
7 #include <kunit/test.h>
8 #include "utils.h"
9 #include "iwl-trans.h"
10 #include "mld.h"
11 #include "sta.h"
12 
13 static const struct is_dup_case {
14 	const char *desc;
15 	struct {
16 		/* ieee80211_hdr fields */
17 		__le16 fc;
18 		__le16 seq;
19 		u8 tid;
20 		bool multicast;
21 		/* iwl_rx_mpdu_desc fields */
22 		bool is_amsdu;
23 		u8 sub_frame_idx;
24 	} rx_pkt;
25 	struct {
26 		__le16 last_seq;
27 		u8 last_sub_frame_idx;
28 		u8 tid;
29 	} dup_data_state;
30 	struct {
31 		bool is_dup;
32 		u32 rx_status_flag;
33 	} result;
34 } is_dup_cases[] = {
35 	{
36 		.desc = "Control frame",
37 		.rx_pkt = {
38 			.fc = __cpu_to_le16(IEEE80211_FTYPE_CTL),
39 		},
40 		.result = {
41 			.is_dup = false,
42 			.rx_status_flag = 0,
43 		}
44 	},
45 	{
46 		.desc = "Null func frame",
47 		.rx_pkt = {
48 			.fc = __cpu_to_le16(IEEE80211_FTYPE_DATA |
49 					    IEEE80211_STYPE_NULLFUNC),
50 		},
51 		.result = {
52 			.is_dup = false,
53 			.rx_status_flag = 0,
54 		}
55 	},
56 	{
57 		.desc = "Multicast data",
58 		.rx_pkt = {
59 			.fc = __cpu_to_le16(IEEE80211_FTYPE_DATA),
60 			.multicast = true,
61 		},
62 		.result = {
63 			.is_dup = false,
64 			.rx_status_flag = 0,
65 		}
66 	},
67 	{
68 		.desc = "QoS null func frame",
69 		.rx_pkt = {
70 			.fc = __cpu_to_le16(IEEE80211_FTYPE_DATA |
71 					    IEEE80211_STYPE_QOS_NULLFUNC),
72 		},
73 		.result = {
74 			.is_dup = false,
75 			.rx_status_flag = 0,
76 		}
77 	},
78 	{
79 		.desc = "QoS data new sequence",
80 		.rx_pkt = {
81 			.fc = __cpu_to_le16(IEEE80211_FTYPE_DATA |
82 					    IEEE80211_STYPE_QOS_DATA),
83 			.seq = __cpu_to_le16(0x101),
84 		},
85 		.dup_data_state = {
86 			.last_seq = __cpu_to_le16(0x100),
87 			.last_sub_frame_idx = 0,
88 		},
89 		.result = {
90 			.is_dup = false,
91 			.rx_status_flag = RX_FLAG_DUP_VALIDATED,
92 		},
93 	},
94 	{
95 		.desc = "QoS data same sequence, no retry",
96 		.rx_pkt = {
97 			.fc = __cpu_to_le16(IEEE80211_FTYPE_DATA |
98 					    IEEE80211_STYPE_QOS_DATA),
99 			.seq = __cpu_to_le16(0x100),
100 		},
101 		.dup_data_state = {
102 			.last_seq = __cpu_to_le16(0x100),
103 			.last_sub_frame_idx = 0,
104 		},
105 		.result = {
106 			.is_dup = false,
107 			.rx_status_flag = RX_FLAG_DUP_VALIDATED,
108 		},
109 	},
110 	{
111 		.desc = "QoS data same sequence, has retry",
112 		.rx_pkt = {
113 			.fc = __cpu_to_le16(IEEE80211_FTYPE_DATA |
114 					    IEEE80211_STYPE_QOS_DATA |
115 					    IEEE80211_FCTL_RETRY),
116 			.seq = __cpu_to_le16(0x100),
117 		},
118 		.dup_data_state = {
119 			.last_seq = __cpu_to_le16(0x100),
120 			.last_sub_frame_idx = 0,
121 		},
122 		.result = {
123 			.is_dup = true,
124 			.rx_status_flag = 0,
125 		},
126 	},
127 	{
128 		.desc = "QoS data invalid tid",
129 		.rx_pkt = {
130 			.fc = __cpu_to_le16(IEEE80211_FTYPE_DATA |
131 					    IEEE80211_STYPE_QOS_DATA),
132 			.seq = __cpu_to_le16(0x100),
133 			.tid = IWL_MAX_TID_COUNT + 1,
134 		},
135 		.result = {
136 			.is_dup = true,
137 			.rx_status_flag = 0,
138 		},
139 	},
140 	{
141 		.desc = "non-QoS data, same sequence, same tid, no retry",
142 		.rx_pkt = {
143 			/* Driver will use tid = IWL_MAX_TID_COUNT */
144 			.fc = __cpu_to_le16(IEEE80211_FTYPE_DATA),
145 			.seq = __cpu_to_le16(0x100),
146 		},
147 		.dup_data_state = {
148 			.tid = IWL_MAX_TID_COUNT,
149 			.last_seq = __cpu_to_le16(0x100),
150 			.last_sub_frame_idx = 0,
151 		},
152 		.result = {
153 			.is_dup = false,
154 			.rx_status_flag = RX_FLAG_DUP_VALIDATED,
155 		},
156 	},
157 	{
158 		.desc = "non-QoS data, same sequence, same tid, has retry",
159 		.rx_pkt = {
160 			/* Driver will use tid = IWL_MAX_TID_COUNT */
161 			.fc = __cpu_to_le16(IEEE80211_FTYPE_DATA |
162 					    IEEE80211_FCTL_RETRY),
163 			.seq = __cpu_to_le16(0x100),
164 		},
165 		.dup_data_state = {
166 			.tid = IWL_MAX_TID_COUNT,
167 			.last_seq = __cpu_to_le16(0x100),
168 			.last_sub_frame_idx = 0,
169 		},
170 		.result = {
171 			.is_dup = true,
172 			.rx_status_flag = 0,
173 		},
174 	},
175 	{
176 		.desc = "non-QoS data, same sequence on different tid's",
177 		.rx_pkt = {
178 			/* Driver will use tid = IWL_MAX_TID_COUNT */
179 			.fc = __cpu_to_le16(IEEE80211_FTYPE_DATA),
180 			.seq = __cpu_to_le16(0x100),
181 		},
182 		.dup_data_state = {
183 			.tid = 7,
184 			.last_seq = __cpu_to_le16(0x100),
185 			.last_sub_frame_idx = 0,
186 		},
187 		.result = {
188 			.is_dup = false,
189 			.rx_status_flag = RX_FLAG_DUP_VALIDATED,
190 		},
191 	},
192 	{
193 		.desc = "A-MSDU new subframe, allow same PN",
194 		.rx_pkt = {
195 			.fc = __cpu_to_le16(IEEE80211_FTYPE_DATA |
196 					    IEEE80211_STYPE_QOS_DATA),
197 			.seq = __cpu_to_le16(0x100),
198 			.is_amsdu = true,
199 			.sub_frame_idx = 1,
200 		},
201 		.dup_data_state = {
202 			.last_seq = __cpu_to_le16(0x100),
203 			.last_sub_frame_idx = 0,
204 		},
205 		.result = {
206 			.is_dup = false,
207 			.rx_status_flag = RX_FLAG_ALLOW_SAME_PN |
208 					  RX_FLAG_DUP_VALIDATED,
209 		},
210 	},
211 	{
212 		.desc = "A-MSDU subframe with smaller idx, disallow same PN",
213 		.rx_pkt = {
214 			.fc = __cpu_to_le16(IEEE80211_FTYPE_DATA |
215 					    IEEE80211_STYPE_QOS_DATA),
216 			.seq = __cpu_to_le16(0x100),
217 			.is_amsdu = true,
218 			.sub_frame_idx = 1,
219 		},
220 		.dup_data_state = {
221 			.last_seq = __cpu_to_le16(0x100),
222 			.last_sub_frame_idx = 2,
223 		},
224 		.result = {
225 			.is_dup = false,
226 			.rx_status_flag = RX_FLAG_DUP_VALIDATED,
227 		},
228 	},
229 	{
230 		.desc = "A-MSDU same subframe, no retry, disallow same PN",
231 		.rx_pkt = {
232 			.fc = __cpu_to_le16(IEEE80211_FTYPE_DATA |
233 					    IEEE80211_STYPE_QOS_DATA),
234 			.seq = __cpu_to_le16(0x100),
235 			.is_amsdu = true,
236 			.sub_frame_idx = 0,
237 		},
238 		.dup_data_state = {
239 			.last_seq = __cpu_to_le16(0x100),
240 			.last_sub_frame_idx = 0,
241 		},
242 		.result = {
243 			.is_dup = false,
244 			.rx_status_flag = RX_FLAG_DUP_VALIDATED,
245 		},
246 	},
247 	{
248 		.desc = "A-MSDU same subframe, has retry",
249 		.rx_pkt = {
250 			.fc = __cpu_to_le16(IEEE80211_FTYPE_DATA |
251 					    IEEE80211_STYPE_QOS_DATA |
252 					    IEEE80211_FCTL_RETRY),
253 			.seq = __cpu_to_le16(0x100),
254 			.is_amsdu = true,
255 			.sub_frame_idx = 0,
256 		},
257 		.dup_data_state = {
258 			.last_seq = __cpu_to_le16(0x100),
259 			.last_sub_frame_idx = 0,
260 		},
261 		.result = {
262 			.is_dup = true,
263 			.rx_status_flag = 0,
264 		},
265 	},
266 };
267 
268 KUNIT_ARRAY_PARAM_DESC(test_is_dup, is_dup_cases, desc);
269 
270 static void
setup_dup_data_state(struct ieee80211_sta * sta)271 setup_dup_data_state(struct ieee80211_sta *sta)
272 {
273 	struct kunit *test = kunit_get_current_test();
274 	const struct is_dup_case *param = (const void *)(test->param_value);
275 	struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
276 	u8 tid = param->dup_data_state.tid;
277 	struct iwl_mld_rxq_dup_data *dup_data;
278 
279 	/* Allocate dup_data only for 1 queue */
280 	KUNIT_ALLOC_AND_ASSERT(test, dup_data);
281 
282 	/* Initialize dup data, see iwl_mld_alloc_dup_data */
283 	memset(dup_data->last_seq, 0xff, sizeof(dup_data->last_seq));
284 
285 	dup_data->last_seq[tid] = param->dup_data_state.last_seq;
286 	dup_data->last_sub_frame_idx[tid] =
287 		param->dup_data_state.last_sub_frame_idx;
288 
289 	mld_sta->dup_data = dup_data;
290 }
291 
setup_rx_pkt(const struct is_dup_case * param,struct ieee80211_hdr * hdr,struct iwl_rx_mpdu_desc * mpdu_desc)292 static void setup_rx_pkt(const struct is_dup_case *param,
293 			 struct ieee80211_hdr *hdr,
294 			 struct iwl_rx_mpdu_desc *mpdu_desc)
295 {
296 	u8 tid = param->rx_pkt.tid;
297 
298 	/* Set "new rx packet" header */
299 	hdr->frame_control = param->rx_pkt.fc;
300 	hdr->seq_ctrl = param->rx_pkt.seq;
301 
302 	if (ieee80211_is_data_qos(hdr->frame_control)) {
303 		u8 *qc = ieee80211_get_qos_ctl(hdr);
304 
305 		qc[0] = tid & IEEE80211_QOS_CTL_TID_MASK;
306 	}
307 
308 	if (param->rx_pkt.multicast)
309 		hdr->addr1[0] = 0x1;
310 
311 	/* Set mpdu_desc */
312 	mpdu_desc->amsdu_info = param->rx_pkt.sub_frame_idx &
313 				IWL_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK;
314 	if (param->rx_pkt.is_amsdu)
315 		mpdu_desc->mac_flags2 |= IWL_RX_MPDU_MFLG2_AMSDU;
316 }
317 
test_is_dup(struct kunit * test)318 static void test_is_dup(struct kunit *test)
319 {
320 	const struct is_dup_case *param = (const void *)(test->param_value);
321 	struct iwl_mld *mld = test->priv;
322 	struct iwl_rx_mpdu_desc mpdu_desc = { };
323 	struct ieee80211_rx_status rx_status = { };
324 	struct ieee80211_vif *vif;
325 	struct ieee80211_sta *sta;
326 	struct ieee80211_hdr hdr;
327 
328 	vif = iwlmld_kunit_add_vif(false, NL80211_IFTYPE_STATION);
329 	sta = iwlmld_kunit_setup_sta(vif, IEEE80211_STA_AUTHORIZED, -1);
330 
331 	/* Prepare test case state */
332 	setup_dup_data_state(sta);
333 	setup_rx_pkt(param, &hdr, &mpdu_desc);
334 
335 	KUNIT_EXPECT_EQ(test,
336 			iwl_mld_is_dup(mld, sta, &hdr, &mpdu_desc, &rx_status,
337 				       0), /* assuming only 1 queue */
338 			param->result.is_dup);
339 	KUNIT_EXPECT_EQ(test, rx_status.flag, param->result.rx_status_flag);
340 }
341 
342 static struct kunit_case is_dup_test_cases[] = {
343 	KUNIT_CASE_PARAM(test_is_dup, test_is_dup_gen_params),
344 	{},
345 };
346 
347 static struct kunit_suite is_dup = {
348 	.name = "iwlmld-rx-is-dup",
349 	.test_cases = is_dup_test_cases,
350 	.init = iwlmld_kunit_test_init,
351 };
352 
353 kunit_test_suite(is_dup);
354