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