xref: /linux/drivers/net/wireless/intel/iwlwifi/mld/tests/agg.c (revision 1a9239bb4253f9076b5b4b2a1a4e8d7defd77a95)
1*d1e879ecSMiri Korenblit // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2*d1e879ecSMiri Korenblit /*
3*d1e879ecSMiri Korenblit  * KUnit tests for channel helper functions
4*d1e879ecSMiri Korenblit  *
5*d1e879ecSMiri Korenblit  * Copyright (C) 2024 Intel Corporation
6*d1e879ecSMiri Korenblit  */
7*d1e879ecSMiri Korenblit #include <kunit/test.h>
8*d1e879ecSMiri Korenblit #include <kunit/static_stub.h>
9*d1e879ecSMiri Korenblit #include <kunit/skbuff.h>
10*d1e879ecSMiri Korenblit 
11*d1e879ecSMiri Korenblit #include "utils.h"
12*d1e879ecSMiri Korenblit #include "mld.h"
13*d1e879ecSMiri Korenblit #include "sta.h"
14*d1e879ecSMiri Korenblit #include "agg.h"
15*d1e879ecSMiri Korenblit #include "rx.h"
16*d1e879ecSMiri Korenblit 
17*d1e879ecSMiri Korenblit #define FC_QOS_DATA (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA)
18*d1e879ecSMiri Korenblit #define BA_WINDOW_SIZE 64
19*d1e879ecSMiri Korenblit #define QUEUE 0
20*d1e879ecSMiri Korenblit 
21*d1e879ecSMiri Korenblit static const struct reorder_buffer_case {
22*d1e879ecSMiri Korenblit 	const char *desc;
23*d1e879ecSMiri Korenblit 	struct {
24*d1e879ecSMiri Korenblit 		/* ieee80211_hdr fields */
25*d1e879ecSMiri Korenblit 		u16 fc;
26*d1e879ecSMiri Korenblit 		u8 tid;
27*d1e879ecSMiri Korenblit 		bool multicast;
28*d1e879ecSMiri Korenblit 		/* iwl_rx_mpdu_desc fields */
29*d1e879ecSMiri Korenblit 		u16 nssn;
30*d1e879ecSMiri Korenblit 		/* used also for setting hdr::seq_ctrl */
31*d1e879ecSMiri Korenblit 		u16 sn;
32*d1e879ecSMiri Korenblit 		u8 baid;
33*d1e879ecSMiri Korenblit 		bool amsdu;
34*d1e879ecSMiri Korenblit 		bool last_subframe;
35*d1e879ecSMiri Korenblit 		bool old_sn;
36*d1e879ecSMiri Korenblit 		bool dup;
37*d1e879ecSMiri Korenblit 	} rx_pkt;
38*d1e879ecSMiri Korenblit 	struct {
39*d1e879ecSMiri Korenblit 		bool valid;
40*d1e879ecSMiri Korenblit 		u16 head_sn;
41*d1e879ecSMiri Korenblit 		u8 baid;
42*d1e879ecSMiri Korenblit 		u16 num_entries;
43*d1e879ecSMiri Korenblit 		/* The test prepares the reorder buffer with fake skbs based
44*d1e879ecSMiri Korenblit 		 * on the sequence numbers provided in @entries array.
45*d1e879ecSMiri Korenblit 		 */
46*d1e879ecSMiri Korenblit 		struct {
47*d1e879ecSMiri Korenblit 			u16 sn;
48*d1e879ecSMiri Korenblit 			/* Set add_subframes > 0 to simulate an A-MSDU by
49*d1e879ecSMiri Korenblit 			 * queueing additional @add_subframes skbs in the
50*d1e879ecSMiri Korenblit 			 * appropriate reorder buffer entry (based on the @sn)
51*d1e879ecSMiri Korenblit 			 */
52*d1e879ecSMiri Korenblit 			u8 add_subframes;
53*d1e879ecSMiri Korenblit 		} entries[BA_WINDOW_SIZE];
54*d1e879ecSMiri Korenblit 	} reorder_buf_state;
55*d1e879ecSMiri Korenblit 	struct {
56*d1e879ecSMiri Korenblit 		enum iwl_mld_reorder_result reorder_res;
57*d1e879ecSMiri Korenblit 		u16 head_sn;
58*d1e879ecSMiri Korenblit 		u16 num_stored;
59*d1e879ecSMiri Korenblit 		u16 skb_release_order[BA_WINDOW_SIZE];
60*d1e879ecSMiri Korenblit 		u16 skb_release_order_count;
61*d1e879ecSMiri Korenblit 	} expected;
62*d1e879ecSMiri Korenblit } reorder_buffer_cases[] = {
63*d1e879ecSMiri Korenblit 	{
64*d1e879ecSMiri Korenblit 		.desc = "RX packet with invalid BAID",
65*d1e879ecSMiri Korenblit 		.rx_pkt = {
66*d1e879ecSMiri Korenblit 			.fc = FC_QOS_DATA,
67*d1e879ecSMiri Korenblit 			.baid = IWL_RX_REORDER_DATA_INVALID_BAID,
68*d1e879ecSMiri Korenblit 		},
69*d1e879ecSMiri Korenblit 		.reorder_buf_state = {
70*d1e879ecSMiri Korenblit 			.valid = true,
71*d1e879ecSMiri Korenblit 		},
72*d1e879ecSMiri Korenblit 		.expected = {
73*d1e879ecSMiri Korenblit 			/* Invalid BAID should not be buffered. The frame is
74*d1e879ecSMiri Korenblit 			 * passed to the network stack immediately.
75*d1e879ecSMiri Korenblit 			 */
76*d1e879ecSMiri Korenblit 			.reorder_res = IWL_MLD_PASS_SKB,
77*d1e879ecSMiri Korenblit 			.num_stored = 0,
78*d1e879ecSMiri Korenblit 		},
79*d1e879ecSMiri Korenblit 	},
80*d1e879ecSMiri Korenblit 	{
81*d1e879ecSMiri Korenblit 		.desc = "RX Multicast packet",
82*d1e879ecSMiri Korenblit 		.rx_pkt = {
83*d1e879ecSMiri Korenblit 			.fc = FC_QOS_DATA,
84*d1e879ecSMiri Korenblit 			.multicast = true,
85*d1e879ecSMiri Korenblit 		},
86*d1e879ecSMiri Korenblit 		.reorder_buf_state = {
87*d1e879ecSMiri Korenblit 			.valid = true,
88*d1e879ecSMiri Korenblit 		},
89*d1e879ecSMiri Korenblit 		.expected = {
90*d1e879ecSMiri Korenblit 			/* Multicast packets are not buffered. The packet is
91*d1e879ecSMiri Korenblit 			 * passed to the network stack immediately.
92*d1e879ecSMiri Korenblit 			 */
93*d1e879ecSMiri Korenblit 			.reorder_res = IWL_MLD_PASS_SKB,
94*d1e879ecSMiri Korenblit 			.num_stored = 0,
95*d1e879ecSMiri Korenblit 		},
96*d1e879ecSMiri Korenblit 	},
97*d1e879ecSMiri Korenblit 	{
98*d1e879ecSMiri Korenblit 		.desc = "RX non-QoS data",
99*d1e879ecSMiri Korenblit 		.rx_pkt = {
100*d1e879ecSMiri Korenblit 			.fc = IEEE80211_FTYPE_DATA,
101*d1e879ecSMiri Korenblit 		},
102*d1e879ecSMiri Korenblit 		.reorder_buf_state = {
103*d1e879ecSMiri Korenblit 			.valid = true,
104*d1e879ecSMiri Korenblit 		},
105*d1e879ecSMiri Korenblit 		.expected = {
106*d1e879ecSMiri Korenblit 			/* non-QoS data frames do not require reordering.
107*d1e879ecSMiri Korenblit 			 * The packet is passed to the network stack
108*d1e879ecSMiri Korenblit 			 * immediately.
109*d1e879ecSMiri Korenblit 			 */
110*d1e879ecSMiri Korenblit 		.reorder_res = IWL_MLD_PASS_SKB,
111*d1e879ecSMiri Korenblit 		},
112*d1e879ecSMiri Korenblit 	},
113*d1e879ecSMiri Korenblit 	{
114*d1e879ecSMiri Korenblit 		.desc = "RX old SN packet, reorder buffer is not yet valid",
115*d1e879ecSMiri Korenblit 		.rx_pkt = {
116*d1e879ecSMiri Korenblit 			.fc = FC_QOS_DATA,
117*d1e879ecSMiri Korenblit 			.old_sn = true,
118*d1e879ecSMiri Korenblit 		},
119*d1e879ecSMiri Korenblit 		.reorder_buf_state = {
120*d1e879ecSMiri Korenblit 			.valid = false,
121*d1e879ecSMiri Korenblit 		},
122*d1e879ecSMiri Korenblit 		.expected = {
123*d1e879ecSMiri Korenblit 			/* The buffer is invalid and the RX packet has an old
124*d1e879ecSMiri Korenblit 			 * SN. The packet is passed to the network stack
125*d1e879ecSMiri Korenblit 			 * immediately.
126*d1e879ecSMiri Korenblit 			 */
127*d1e879ecSMiri Korenblit 			.reorder_res = IWL_MLD_PASS_SKB,
128*d1e879ecSMiri Korenblit 		},
129*d1e879ecSMiri Korenblit 	},
130*d1e879ecSMiri Korenblit 	{
131*d1e879ecSMiri Korenblit 		.desc = "RX old SN packet, reorder buffer valid",
132*d1e879ecSMiri Korenblit 		.rx_pkt = {
133*d1e879ecSMiri Korenblit 			.fc = FC_QOS_DATA,
134*d1e879ecSMiri Korenblit 			.old_sn = true,
135*d1e879ecSMiri Korenblit 		},
136*d1e879ecSMiri Korenblit 		.reorder_buf_state = {
137*d1e879ecSMiri Korenblit 			.valid = true,
138*d1e879ecSMiri Korenblit 			.head_sn = 100,
139*d1e879ecSMiri Korenblit 		},
140*d1e879ecSMiri Korenblit 		.expected = {
141*d1e879ecSMiri Korenblit 			/* The buffer is valid and the RX packet has an old SN.
142*d1e879ecSMiri Korenblit 			 * The packet should be dropped.
143*d1e879ecSMiri Korenblit 			 */
144*d1e879ecSMiri Korenblit 			.reorder_res = IWL_MLD_DROP_SKB,
145*d1e879ecSMiri Korenblit 			.num_stored = 0,
146*d1e879ecSMiri Korenblit 			.head_sn = 100,
147*d1e879ecSMiri Korenblit 		},
148*d1e879ecSMiri Korenblit 	},
149*d1e879ecSMiri Korenblit 	{
150*d1e879ecSMiri Korenblit 		.desc = "RX duplicate packet",
151*d1e879ecSMiri Korenblit 		.rx_pkt = {
152*d1e879ecSMiri Korenblit 			.fc = FC_QOS_DATA,
153*d1e879ecSMiri Korenblit 			.dup = true,
154*d1e879ecSMiri Korenblit 		},
155*d1e879ecSMiri Korenblit 		.reorder_buf_state = {
156*d1e879ecSMiri Korenblit 			.valid = true,
157*d1e879ecSMiri Korenblit 			.head_sn = 100,
158*d1e879ecSMiri Korenblit 		},
159*d1e879ecSMiri Korenblit 		.expected = {
160*d1e879ecSMiri Korenblit 			/* Duplicate packets should be dropped */
161*d1e879ecSMiri Korenblit 			.reorder_res = IWL_MLD_DROP_SKB,
162*d1e879ecSMiri Korenblit 			.num_stored = 0,
163*d1e879ecSMiri Korenblit 			.head_sn = 100,
164*d1e879ecSMiri Korenblit 		},
165*d1e879ecSMiri Korenblit 	},
166*d1e879ecSMiri Korenblit 	{
167*d1e879ecSMiri Korenblit 		.desc = "RX In-order packet, sn < nssn",
168*d1e879ecSMiri Korenblit 		.rx_pkt = {
169*d1e879ecSMiri Korenblit 			.fc = FC_QOS_DATA,
170*d1e879ecSMiri Korenblit 			.sn = 100,
171*d1e879ecSMiri Korenblit 			.nssn = 101,
172*d1e879ecSMiri Korenblit 		},
173*d1e879ecSMiri Korenblit 		.reorder_buf_state = {
174*d1e879ecSMiri Korenblit 			.valid = true,
175*d1e879ecSMiri Korenblit 			.head_sn = 100,
176*d1e879ecSMiri Korenblit 		},
177*d1e879ecSMiri Korenblit 		.expected = {
178*d1e879ecSMiri Korenblit 			/* 1. Reorder buffer is empty.
179*d1e879ecSMiri Korenblit 			 * 2. RX packet SN is in order and less than NSSN.
180*d1e879ecSMiri Korenblit 			 * Packet is released to the network stack immediately
181*d1e879ecSMiri Korenblit 			 * and buffer->head_sn is updated to NSSN.
182*d1e879ecSMiri Korenblit 			 */
183*d1e879ecSMiri Korenblit 			.reorder_res = IWL_MLD_PASS_SKB,
184*d1e879ecSMiri Korenblit 			.num_stored = 0,
185*d1e879ecSMiri Korenblit 			.head_sn = 101,
186*d1e879ecSMiri Korenblit 		},
187*d1e879ecSMiri Korenblit 	},
188*d1e879ecSMiri Korenblit 	{
189*d1e879ecSMiri Korenblit 		.desc = "RX In-order packet, sn == head_sn",
190*d1e879ecSMiri Korenblit 		.rx_pkt = {
191*d1e879ecSMiri Korenblit 			.fc = FC_QOS_DATA,
192*d1e879ecSMiri Korenblit 			.sn = 101,
193*d1e879ecSMiri Korenblit 			.nssn = 100,
194*d1e879ecSMiri Korenblit 		},
195*d1e879ecSMiri Korenblit 		.reorder_buf_state = {
196*d1e879ecSMiri Korenblit 			.valid = true,
197*d1e879ecSMiri Korenblit 			.head_sn = 101,
198*d1e879ecSMiri Korenblit 		},
199*d1e879ecSMiri Korenblit 		.expected = {
200*d1e879ecSMiri Korenblit 			/* 1. Reorder buffer is empty.
201*d1e879ecSMiri Korenblit 			 * 2. RX packet SN is equal to buffer->head_sn.
202*d1e879ecSMiri Korenblit 			 * Packet is released to the network stack immediately
203*d1e879ecSMiri Korenblit 			 * and buffer->head_sn is incremented.
204*d1e879ecSMiri Korenblit 			 */
205*d1e879ecSMiri Korenblit 			.reorder_res = IWL_MLD_PASS_SKB,
206*d1e879ecSMiri Korenblit 			.num_stored = 0,
207*d1e879ecSMiri Korenblit 			.head_sn = 102,
208*d1e879ecSMiri Korenblit 		},
209*d1e879ecSMiri Korenblit 	},
210*d1e879ecSMiri Korenblit 	{
211*d1e879ecSMiri Korenblit 		.desc = "RX In-order packet, IEEE80211_MAX_SN wrap around",
212*d1e879ecSMiri Korenblit 		.rx_pkt = {
213*d1e879ecSMiri Korenblit 			.fc = FC_QOS_DATA,
214*d1e879ecSMiri Korenblit 			.sn = IEEE80211_MAX_SN,
215*d1e879ecSMiri Korenblit 			.nssn = IEEE80211_MAX_SN - 1,
216*d1e879ecSMiri Korenblit 		},
217*d1e879ecSMiri Korenblit 		.reorder_buf_state = {
218*d1e879ecSMiri Korenblit 			.valid = true,
219*d1e879ecSMiri Korenblit 			.head_sn = IEEE80211_MAX_SN,
220*d1e879ecSMiri Korenblit 		},
221*d1e879ecSMiri Korenblit 		.expected = {
222*d1e879ecSMiri Korenblit 			/* 1. Reorder buffer is empty.
223*d1e879ecSMiri Korenblit 			 * 2. RX SN == buffer->head_sn == IEEE80211_MAX_SN
224*d1e879ecSMiri Korenblit 			 * Packet is released to the network stack immediately
225*d1e879ecSMiri Korenblit 			 * and buffer->head_sn is incremented correctly (wraps
226*d1e879ecSMiri Korenblit 			 * around to 0).
227*d1e879ecSMiri Korenblit 			 */
228*d1e879ecSMiri Korenblit 			.reorder_res = IWL_MLD_PASS_SKB,
229*d1e879ecSMiri Korenblit 			.num_stored = 0,
230*d1e879ecSMiri Korenblit 			.head_sn = 0,
231*d1e879ecSMiri Korenblit 		},
232*d1e879ecSMiri Korenblit 	},
233*d1e879ecSMiri Korenblit 	{
234*d1e879ecSMiri Korenblit 		.desc = "RX Out-of-order packet, pending packet in buffer",
235*d1e879ecSMiri Korenblit 		.rx_pkt = {
236*d1e879ecSMiri Korenblit 			.fc = FC_QOS_DATA,
237*d1e879ecSMiri Korenblit 			.sn = 100,
238*d1e879ecSMiri Korenblit 			.nssn = 102,
239*d1e879ecSMiri Korenblit 		},
240*d1e879ecSMiri Korenblit 		.reorder_buf_state = {
241*d1e879ecSMiri Korenblit 			.valid = true,
242*d1e879ecSMiri Korenblit 			.head_sn = 100,
243*d1e879ecSMiri Korenblit 			.num_entries = 1,
244*d1e879ecSMiri Korenblit 			.entries[0].sn = 101,
245*d1e879ecSMiri Korenblit 		},
246*d1e879ecSMiri Korenblit 		.expected = {
247*d1e879ecSMiri Korenblit 			/* 1. Reorder buffer contains one packet with SN=101.
248*d1e879ecSMiri Korenblit 			 * 2. RX packet SN = buffer->head_sn.
249*d1e879ecSMiri Korenblit 			 * Both packets are released (in order) to the network
250*d1e879ecSMiri Korenblit 			 * stack as there are no gaps.
251*d1e879ecSMiri Korenblit 			 */
252*d1e879ecSMiri Korenblit 			.reorder_res = IWL_MLD_BUFFERED_SKB,
253*d1e879ecSMiri Korenblit 			.num_stored = 0,
254*d1e879ecSMiri Korenblit 			.head_sn = 102,
255*d1e879ecSMiri Korenblit 			.skb_release_order = {100, 101},
256*d1e879ecSMiri Korenblit 			.skb_release_order_count = 2,
257*d1e879ecSMiri Korenblit 		},
258*d1e879ecSMiri Korenblit 	},
259*d1e879ecSMiri Korenblit 	{
260*d1e879ecSMiri Korenblit 		.desc = "RX Out-of-order packet, pending packet in buffer (wrap around)",
261*d1e879ecSMiri Korenblit 		.rx_pkt = {
262*d1e879ecSMiri Korenblit 			.fc = FC_QOS_DATA,
263*d1e879ecSMiri Korenblit 			.sn = 0,
264*d1e879ecSMiri Korenblit 			.nssn = 1,
265*d1e879ecSMiri Korenblit 		},
266*d1e879ecSMiri Korenblit 		.reorder_buf_state = {
267*d1e879ecSMiri Korenblit 			.valid = true,
268*d1e879ecSMiri Korenblit 			.head_sn = IEEE80211_MAX_SN - 1,
269*d1e879ecSMiri Korenblit 			.num_entries = 1,
270*d1e879ecSMiri Korenblit 			.entries[0].sn = IEEE80211_MAX_SN,
271*d1e879ecSMiri Korenblit 		},
272*d1e879ecSMiri Korenblit 		.expected = {
273*d1e879ecSMiri Korenblit 			/* 1. Reorder buffer contains one packet with
274*d1e879ecSMiri Korenblit 			 *    SN=IEEE80211_MAX_SN.
275*d1e879ecSMiri Korenblit 			 * 2. RX Packet SN = 0 (after wrap around)
276*d1e879ecSMiri Korenblit 			 * Both packets are released (in order) to the network
277*d1e879ecSMiri Korenblit 			 * stack as there are no gaps.
278*d1e879ecSMiri Korenblit 			 */
279*d1e879ecSMiri Korenblit 			.reorder_res = IWL_MLD_BUFFERED_SKB,
280*d1e879ecSMiri Korenblit 			.num_stored = 0,
281*d1e879ecSMiri Korenblit 			.head_sn = 1,
282*d1e879ecSMiri Korenblit 			.skb_release_order = { 4095, 0 },
283*d1e879ecSMiri Korenblit 			.skb_release_order_count = 2,
284*d1e879ecSMiri Korenblit 		},
285*d1e879ecSMiri Korenblit 	},
286*d1e879ecSMiri Korenblit 	{
287*d1e879ecSMiri Korenblit 		.desc = "RX Out-of-order packet, filling 1/2 holes in buffer, release RX packet",
288*d1e879ecSMiri Korenblit 		.rx_pkt = {
289*d1e879ecSMiri Korenblit 			.fc = FC_QOS_DATA,
290*d1e879ecSMiri Korenblit 			.sn = 100,
291*d1e879ecSMiri Korenblit 			.nssn = 101,
292*d1e879ecSMiri Korenblit 		},
293*d1e879ecSMiri Korenblit 		.reorder_buf_state = {
294*d1e879ecSMiri Korenblit 			.valid = true,
295*d1e879ecSMiri Korenblit 			.head_sn = 100,
296*d1e879ecSMiri Korenblit 			.num_entries = 1,
297*d1e879ecSMiri Korenblit 			.entries[0].sn = 102,
298*d1e879ecSMiri Korenblit 		},
299*d1e879ecSMiri Korenblit 		.expected = {
300*d1e879ecSMiri Korenblit 			/* 1. Reorder buffer contains one packet with SN=102.
301*d1e879ecSMiri Korenblit 			 * 2. There are 2 holes at SN={100, 101}.
302*d1e879ecSMiri Korenblit 			 * Only the RX packet (SN=100) is released, there is
303*d1e879ecSMiri Korenblit 			 * still a hole at 101.
304*d1e879ecSMiri Korenblit 			 */
305*d1e879ecSMiri Korenblit 			.reorder_res = IWL_MLD_BUFFERED_SKB,
306*d1e879ecSMiri Korenblit 			.num_stored = 1,
307*d1e879ecSMiri Korenblit 			.head_sn = 101,
308*d1e879ecSMiri Korenblit 			.skb_release_order = {100},
309*d1e879ecSMiri Korenblit 			.skb_release_order_count = 1,
310*d1e879ecSMiri Korenblit 		},
311*d1e879ecSMiri Korenblit 	},
312*d1e879ecSMiri Korenblit 	{
313*d1e879ecSMiri Korenblit 		.desc = "RX Out-of-order packet, filling 1/2 holes, release 2 packets",
314*d1e879ecSMiri Korenblit 		.rx_pkt = {
315*d1e879ecSMiri Korenblit 			.fc = FC_QOS_DATA,
316*d1e879ecSMiri Korenblit 			.sn = 102,
317*d1e879ecSMiri Korenblit 			.nssn = 103,
318*d1e879ecSMiri Korenblit 		},
319*d1e879ecSMiri Korenblit 		.reorder_buf_state = {
320*d1e879ecSMiri Korenblit 			.valid = true,
321*d1e879ecSMiri Korenblit 			.head_sn = 100,
322*d1e879ecSMiri Korenblit 			.num_entries = 3,
323*d1e879ecSMiri Korenblit 			.entries[0].sn = 101,
324*d1e879ecSMiri Korenblit 			.entries[1].sn = 104,
325*d1e879ecSMiri Korenblit 			.entries[2].sn = 105,
326*d1e879ecSMiri Korenblit 		},
327*d1e879ecSMiri Korenblit 		.expected = {
328*d1e879ecSMiri Korenblit 			/* 1. Reorder buffer contains three packets.
329*d1e879ecSMiri Korenblit 			 * 2. RX packet fills one of two holes (at SN=102).
330*d1e879ecSMiri Korenblit 			 * Two packets are released (until the next hole at
331*d1e879ecSMiri Korenblit 			 * SN=103).
332*d1e879ecSMiri Korenblit 			 */
333*d1e879ecSMiri Korenblit 			.reorder_res = IWL_MLD_BUFFERED_SKB,
334*d1e879ecSMiri Korenblit 			.num_stored = 2,
335*d1e879ecSMiri Korenblit 			.head_sn = 103,
336*d1e879ecSMiri Korenblit 			.skb_release_order = {101, 102},
337*d1e879ecSMiri Korenblit 			.skb_release_order_count = 2,
338*d1e879ecSMiri Korenblit 		},
339*d1e879ecSMiri Korenblit 	},
340*d1e879ecSMiri Korenblit 		{
341*d1e879ecSMiri Korenblit 		.desc = "RX Out-of-order packet, filling 1/1 holes, no packets released",
342*d1e879ecSMiri Korenblit 		.rx_pkt = {
343*d1e879ecSMiri Korenblit 			.fc = FC_QOS_DATA,
344*d1e879ecSMiri Korenblit 			.sn = 102,
345*d1e879ecSMiri Korenblit 			.nssn = 100,
346*d1e879ecSMiri Korenblit 		},
347*d1e879ecSMiri Korenblit 		.reorder_buf_state = {
348*d1e879ecSMiri Korenblit 			.valid = true,
349*d1e879ecSMiri Korenblit 			.head_sn = 100,
350*d1e879ecSMiri Korenblit 			.num_entries = 3,
351*d1e879ecSMiri Korenblit 			.entries[0].sn = 101,
352*d1e879ecSMiri Korenblit 			.entries[1].sn = 103,
353*d1e879ecSMiri Korenblit 			.entries[2].sn = 104,
354*d1e879ecSMiri Korenblit 		},
355*d1e879ecSMiri Korenblit 		.expected = {
356*d1e879ecSMiri Korenblit 			/* 1. Reorder buffer contains three packets:
357*d1e879ecSMiri Korenblit 			 *    SN={101, 103, 104}.
358*d1e879ecSMiri Korenblit 			 * 2. RX packet fills a hole (SN=102), but NSSN is
359*d1e879ecSMiri Korenblit 			 *    smaller than buffered frames.
360*d1e879ecSMiri Korenblit 			 * No packets can be released yet and buffer->head_sn
361*d1e879ecSMiri Korenblit 			 * is not updated.
362*d1e879ecSMiri Korenblit 			 */
363*d1e879ecSMiri Korenblit 			.reorder_res = IWL_MLD_BUFFERED_SKB,
364*d1e879ecSMiri Korenblit 			.num_stored = 4,
365*d1e879ecSMiri Korenblit 			.head_sn = 100,
366*d1e879ecSMiri Korenblit 		},
367*d1e879ecSMiri Korenblit 	},
368*d1e879ecSMiri Korenblit 	{
369*d1e879ecSMiri Korenblit 		.desc = "RX In-order A-MSDU, last subframe",
370*d1e879ecSMiri Korenblit 		.rx_pkt = {
371*d1e879ecSMiri Korenblit 			.fc = FC_QOS_DATA,
372*d1e879ecSMiri Korenblit 			.sn = 100,
373*d1e879ecSMiri Korenblit 			.nssn = 101,
374*d1e879ecSMiri Korenblit 			.amsdu = true,
375*d1e879ecSMiri Korenblit 			.last_subframe = true,
376*d1e879ecSMiri Korenblit 		},
377*d1e879ecSMiri Korenblit 		.reorder_buf_state = {
378*d1e879ecSMiri Korenblit 			.valid = true,
379*d1e879ecSMiri Korenblit 			.head_sn = 100,
380*d1e879ecSMiri Korenblit 			.num_entries = 1,
381*d1e879ecSMiri Korenblit 			.entries[0] = {
382*d1e879ecSMiri Korenblit 				.sn = 100,
383*d1e879ecSMiri Korenblit 				.add_subframes = 1,
384*d1e879ecSMiri Korenblit 			},
385*d1e879ecSMiri Korenblit 		},
386*d1e879ecSMiri Korenblit 		.expected = {
387*d1e879ecSMiri Korenblit 			/* 1. Reorder buffer contains a 2-sub frames A-MSDU
388*d1e879ecSMiri Korenblit 			 *    at SN=100.
389*d1e879ecSMiri Korenblit 			 * 2. RX packet is the last SN=100 A-MSDU subframe
390*d1e879ecSMiri Korenblit 			 * All packets are released in order (3 x SN=100).
391*d1e879ecSMiri Korenblit 			 */
392*d1e879ecSMiri Korenblit 			.reorder_res = IWL_MLD_BUFFERED_SKB,
393*d1e879ecSMiri Korenblit 			.num_stored = 0,
394*d1e879ecSMiri Korenblit 			.head_sn = 101,
395*d1e879ecSMiri Korenblit 			.skb_release_order = {100, 100, 100},
396*d1e879ecSMiri Korenblit 			.skb_release_order_count = 3,
397*d1e879ecSMiri Korenblit 		},
398*d1e879ecSMiri Korenblit 	},
399*d1e879ecSMiri Korenblit 	{
400*d1e879ecSMiri Korenblit 		.desc = "RX In-order A-MSDU, not the last subframe",
401*d1e879ecSMiri Korenblit 		.rx_pkt = {
402*d1e879ecSMiri Korenblit 			.fc = FC_QOS_DATA,
403*d1e879ecSMiri Korenblit 			.sn = 100,
404*d1e879ecSMiri Korenblit 			.nssn = 101,
405*d1e879ecSMiri Korenblit 			.amsdu = true,
406*d1e879ecSMiri Korenblit 			.last_subframe = false,
407*d1e879ecSMiri Korenblit 		},
408*d1e879ecSMiri Korenblit 		.reorder_buf_state = {
409*d1e879ecSMiri Korenblit 			.valid = true,
410*d1e879ecSMiri Korenblit 			.head_sn = 100,
411*d1e879ecSMiri Korenblit 			.num_entries = 1,
412*d1e879ecSMiri Korenblit 			.entries[0] = {
413*d1e879ecSMiri Korenblit 				.sn = 100,
414*d1e879ecSMiri Korenblit 				.add_subframes = 1,
415*d1e879ecSMiri Korenblit 			},
416*d1e879ecSMiri Korenblit 		},
417*d1e879ecSMiri Korenblit 		.expected = {
418*d1e879ecSMiri Korenblit 			/* 1. Reorder buffer contains a 2-sub frames A-MSDU
419*d1e879ecSMiri Korenblit 			 *    at SN=100.
420*d1e879ecSMiri Korenblit 			 * 2. RX packet additional SN=100 A-MSDU subframe,
421*d1e879ecSMiri Korenblit 			 *    but not the last one
422*d1e879ecSMiri Korenblit 			 * No packets are released and head_sn is not updated.
423*d1e879ecSMiri Korenblit 			 */
424*d1e879ecSMiri Korenblit 			.reorder_res = IWL_MLD_BUFFERED_SKB,
425*d1e879ecSMiri Korenblit 			.num_stored = 3,
426*d1e879ecSMiri Korenblit 			.head_sn = 100,
427*d1e879ecSMiri Korenblit 		},
428*d1e879ecSMiri Korenblit 	},
429*d1e879ecSMiri Korenblit };
430*d1e879ecSMiri Korenblit 
431*d1e879ecSMiri Korenblit KUNIT_ARRAY_PARAM_DESC(test_reorder_buffer, reorder_buffer_cases, desc);
432*d1e879ecSMiri Korenblit 
433*d1e879ecSMiri Korenblit static struct sk_buff_head g_released_skbs;
434*d1e879ecSMiri Korenblit static u16 g_num_released_skbs;
435*d1e879ecSMiri Korenblit 
436*d1e879ecSMiri Korenblit /* Add released skbs from reorder buffer to a global list; This allows us
437*d1e879ecSMiri Korenblit  * to verify the correct release order of packets after they pass through the
438*d1e879ecSMiri Korenblit  * simulated reorder logic.
439*d1e879ecSMiri Korenblit  */
440*d1e879ecSMiri Korenblit static void
fake_iwl_mld_pass_packet_to_mac80211(struct iwl_mld * mld,struct napi_struct * napi,struct sk_buff * skb,int queue,struct ieee80211_sta * sta)441*d1e879ecSMiri Korenblit fake_iwl_mld_pass_packet_to_mac80211(struct iwl_mld *mld,
442*d1e879ecSMiri Korenblit 				     struct napi_struct *napi,
443*d1e879ecSMiri Korenblit 				     struct sk_buff *skb, int queue,
444*d1e879ecSMiri Korenblit 				     struct ieee80211_sta *sta)
445*d1e879ecSMiri Korenblit {
446*d1e879ecSMiri Korenblit 	__skb_queue_tail(&g_released_skbs, skb);
447*d1e879ecSMiri Korenblit 	g_num_released_skbs++;
448*d1e879ecSMiri Korenblit }
449*d1e879ecSMiri Korenblit 
450*d1e879ecSMiri Korenblit static u32
fake_iwl_mld_fw_sta_id_mask(struct iwl_mld * mld,struct ieee80211_sta * sta)451*d1e879ecSMiri Korenblit fake_iwl_mld_fw_sta_id_mask(struct iwl_mld *mld, struct ieee80211_sta *sta)
452*d1e879ecSMiri Korenblit {
453*d1e879ecSMiri Korenblit 	struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
454*d1e879ecSMiri Korenblit 	struct iwl_mld_link_sta *mld_link_sta;
455*d1e879ecSMiri Korenblit 	u8 link_id;
456*d1e879ecSMiri Korenblit 	u32 sta_mask = 0;
457*d1e879ecSMiri Korenblit 
458*d1e879ecSMiri Korenblit 	/* This is the expectation in the real function */
459*d1e879ecSMiri Korenblit 	lockdep_assert_wiphy(mld->wiphy);
460*d1e879ecSMiri Korenblit 
461*d1e879ecSMiri Korenblit 	/* We can't use for_each_sta_active_link */
462*d1e879ecSMiri Korenblit 	for_each_mld_link_sta(mld_sta, mld_link_sta, link_id)
463*d1e879ecSMiri Korenblit 		sta_mask |= BIT(mld_link_sta->fw_id);
464*d1e879ecSMiri Korenblit 	return sta_mask;
465*d1e879ecSMiri Korenblit }
466*d1e879ecSMiri Korenblit 
setup_mpdu_desc(void)467*d1e879ecSMiri Korenblit static struct iwl_rx_mpdu_desc *setup_mpdu_desc(void)
468*d1e879ecSMiri Korenblit {
469*d1e879ecSMiri Korenblit 	struct kunit *test = kunit_get_current_test();
470*d1e879ecSMiri Korenblit 	const struct reorder_buffer_case *param =
471*d1e879ecSMiri Korenblit 		(const void *)(test->param_value);
472*d1e879ecSMiri Korenblit 	struct iwl_rx_mpdu_desc *mpdu_desc;
473*d1e879ecSMiri Korenblit 
474*d1e879ecSMiri Korenblit 	KUNIT_ALLOC_AND_ASSERT(test, mpdu_desc);
475*d1e879ecSMiri Korenblit 
476*d1e879ecSMiri Korenblit 	mpdu_desc->reorder_data |=
477*d1e879ecSMiri Korenblit 		cpu_to_le32(FIELD_PREP(IWL_RX_MPDU_REORDER_BAID_MASK,
478*d1e879ecSMiri Korenblit 				       param->rx_pkt.baid));
479*d1e879ecSMiri Korenblit 	mpdu_desc->reorder_data |=
480*d1e879ecSMiri Korenblit 		cpu_to_le32(FIELD_PREP(IWL_RX_MPDU_REORDER_SN_MASK,
481*d1e879ecSMiri Korenblit 				       param->rx_pkt.sn));
482*d1e879ecSMiri Korenblit 	mpdu_desc->reorder_data |=
483*d1e879ecSMiri Korenblit 		cpu_to_le32(FIELD_PREP(IWL_RX_MPDU_REORDER_NSSN_MASK,
484*d1e879ecSMiri Korenblit 				       param->rx_pkt.nssn));
485*d1e879ecSMiri Korenblit 	if (param->rx_pkt.old_sn)
486*d1e879ecSMiri Korenblit 		mpdu_desc->reorder_data |=
487*d1e879ecSMiri Korenblit 			cpu_to_le32(IWL_RX_MPDU_REORDER_BA_OLD_SN);
488*d1e879ecSMiri Korenblit 
489*d1e879ecSMiri Korenblit 	if (param->rx_pkt.dup)
490*d1e879ecSMiri Korenblit 		mpdu_desc->status |= cpu_to_le32(IWL_RX_MPDU_STATUS_DUPLICATE);
491*d1e879ecSMiri Korenblit 
492*d1e879ecSMiri Korenblit 	if (param->rx_pkt.amsdu) {
493*d1e879ecSMiri Korenblit 		mpdu_desc->mac_flags2 |= IWL_RX_MPDU_MFLG2_AMSDU;
494*d1e879ecSMiri Korenblit 		if (param->rx_pkt.last_subframe)
495*d1e879ecSMiri Korenblit 			mpdu_desc->amsdu_info |=
496*d1e879ecSMiri Korenblit 				IWL_RX_MPDU_AMSDU_LAST_SUBFRAME;
497*d1e879ecSMiri Korenblit 	}
498*d1e879ecSMiri Korenblit 
499*d1e879ecSMiri Korenblit 	return mpdu_desc;
500*d1e879ecSMiri Korenblit }
501*d1e879ecSMiri Korenblit 
alloc_and_setup_skb(u16 fc,u16 seq_ctrl,u8 tid,bool mcast)502*d1e879ecSMiri Korenblit static struct sk_buff *alloc_and_setup_skb(u16 fc, u16 seq_ctrl, u8 tid,
503*d1e879ecSMiri Korenblit 					   bool mcast)
504*d1e879ecSMiri Korenblit {
505*d1e879ecSMiri Korenblit 	struct kunit *test = kunit_get_current_test();
506*d1e879ecSMiri Korenblit 	struct ieee80211_hdr hdr = {
507*d1e879ecSMiri Korenblit 		.frame_control = cpu_to_le16(fc),
508*d1e879ecSMiri Korenblit 		.seq_ctrl = cpu_to_le16(seq_ctrl),
509*d1e879ecSMiri Korenblit 	};
510*d1e879ecSMiri Korenblit 	struct sk_buff *skb;
511*d1e879ecSMiri Korenblit 
512*d1e879ecSMiri Korenblit 	skb = kunit_zalloc_skb(test, 128, GFP_KERNEL);
513*d1e879ecSMiri Korenblit 	KUNIT_ASSERT_NOT_NULL(test, skb);
514*d1e879ecSMiri Korenblit 
515*d1e879ecSMiri Korenblit 	if (ieee80211_is_data_qos(hdr.frame_control)) {
516*d1e879ecSMiri Korenblit 		u8 *qc = ieee80211_get_qos_ctl(&hdr);
517*d1e879ecSMiri Korenblit 
518*d1e879ecSMiri Korenblit 		qc[0] = tid & IEEE80211_QOS_CTL_TID_MASK;
519*d1e879ecSMiri Korenblit 	}
520*d1e879ecSMiri Korenblit 
521*d1e879ecSMiri Korenblit 	if (mcast)
522*d1e879ecSMiri Korenblit 		hdr.addr1[0] = 0x1;
523*d1e879ecSMiri Korenblit 
524*d1e879ecSMiri Korenblit 	skb_set_mac_header(skb, skb->len);
525*d1e879ecSMiri Korenblit 	skb_put_data(skb, &hdr, ieee80211_hdrlen(hdr.frame_control));
526*d1e879ecSMiri Korenblit 
527*d1e879ecSMiri Korenblit 	return skb;
528*d1e879ecSMiri Korenblit }
529*d1e879ecSMiri Korenblit 
530*d1e879ecSMiri Korenblit static struct iwl_mld_reorder_buffer *
setup_reorder_buffer(struct iwl_mld_baid_data * baid_data)531*d1e879ecSMiri Korenblit setup_reorder_buffer(struct iwl_mld_baid_data *baid_data)
532*d1e879ecSMiri Korenblit {
533*d1e879ecSMiri Korenblit 	struct kunit *test = kunit_get_current_test();
534*d1e879ecSMiri Korenblit 	const struct reorder_buffer_case *param =
535*d1e879ecSMiri Korenblit 		(const void *)(test->param_value);
536*d1e879ecSMiri Korenblit 	struct iwl_mld_reorder_buffer *buffer = baid_data->reorder_buf;
537*d1e879ecSMiri Korenblit 	struct iwl_mld_reorder_buf_entry *entries = baid_data->entries;
538*d1e879ecSMiri Korenblit 	struct sk_buff *fake_skb;
539*d1e879ecSMiri Korenblit 
540*d1e879ecSMiri Korenblit 	buffer->valid = param->reorder_buf_state.valid;
541*d1e879ecSMiri Korenblit 	buffer->head_sn = param->reorder_buf_state.head_sn;
542*d1e879ecSMiri Korenblit 	buffer->queue = QUEUE;
543*d1e879ecSMiri Korenblit 
544*d1e879ecSMiri Korenblit 	for (int i = 0; i < baid_data->buf_size; i++)
545*d1e879ecSMiri Korenblit 		__skb_queue_head_init(&entries[i].frames);
546*d1e879ecSMiri Korenblit 
547*d1e879ecSMiri Korenblit 	for (int i = 0; i < param->reorder_buf_state.num_entries; i++) {
548*d1e879ecSMiri Korenblit 		u16 sn = param->reorder_buf_state.entries[i].sn;
549*d1e879ecSMiri Korenblit 		int index = sn % baid_data->buf_size;
550*d1e879ecSMiri Korenblit 		u8 add_subframes =
551*d1e879ecSMiri Korenblit 			param->reorder_buf_state.entries[i].add_subframes;
552*d1e879ecSMiri Korenblit 		/* create 1 skb per entry + additional skbs per num of
553*d1e879ecSMiri Korenblit 		 * requested subframes
554*d1e879ecSMiri Korenblit 		 */
555*d1e879ecSMiri Korenblit 		u8 num_skbs = 1 + add_subframes;
556*d1e879ecSMiri Korenblit 
557*d1e879ecSMiri Korenblit 		for (int j = 0; j < num_skbs; j++) {
558*d1e879ecSMiri Korenblit 			fake_skb = alloc_and_setup_skb(FC_QOS_DATA, sn, 0,
559*d1e879ecSMiri Korenblit 						       false);
560*d1e879ecSMiri Korenblit 			__skb_queue_tail(&entries[index].frames, fake_skb);
561*d1e879ecSMiri Korenblit 			buffer->num_stored++;
562*d1e879ecSMiri Korenblit 		}
563*d1e879ecSMiri Korenblit 	}
564*d1e879ecSMiri Korenblit 
565*d1e879ecSMiri Korenblit 	return buffer;
566*d1e879ecSMiri Korenblit }
567*d1e879ecSMiri Korenblit 
setup_ba_data(struct ieee80211_sta * sta)568*d1e879ecSMiri Korenblit static struct iwl_mld_reorder_buffer *setup_ba_data(struct ieee80211_sta *sta)
569*d1e879ecSMiri Korenblit {
570*d1e879ecSMiri Korenblit 	struct kunit *test = kunit_get_current_test();
571*d1e879ecSMiri Korenblit 	struct iwl_mld *mld = test->priv;
572*d1e879ecSMiri Korenblit 	const struct reorder_buffer_case *param =
573*d1e879ecSMiri Korenblit 		(const void *)(test->param_value);
574*d1e879ecSMiri Korenblit 	struct iwl_mld_baid_data *baid_data = NULL;
575*d1e879ecSMiri Korenblit 	struct iwl_mld_reorder_buffer *buffer;
576*d1e879ecSMiri Korenblit 	u32 reorder_buf_size = BA_WINDOW_SIZE * sizeof(baid_data->entries[0]);
577*d1e879ecSMiri Korenblit 	u8 baid = param->reorder_buf_state.baid;
578*d1e879ecSMiri Korenblit 
579*d1e879ecSMiri Korenblit 	/* Assuming only 1 RXQ */
580*d1e879ecSMiri Korenblit 	KUNIT_ALLOC_AND_ASSERT_SIZE(test, baid_data,
581*d1e879ecSMiri Korenblit 				    sizeof(*baid_data) + reorder_buf_size);
582*d1e879ecSMiri Korenblit 
583*d1e879ecSMiri Korenblit 	baid_data->baid = baid;
584*d1e879ecSMiri Korenblit 	baid_data->tid = param->rx_pkt.tid;
585*d1e879ecSMiri Korenblit 	baid_data->buf_size = BA_WINDOW_SIZE;
586*d1e879ecSMiri Korenblit 
587*d1e879ecSMiri Korenblit 	wiphy_lock(mld->wiphy);
588*d1e879ecSMiri Korenblit 	baid_data->sta_mask = iwl_mld_fw_sta_id_mask(mld, sta);
589*d1e879ecSMiri Korenblit 	wiphy_unlock(mld->wiphy);
590*d1e879ecSMiri Korenblit 
591*d1e879ecSMiri Korenblit 	baid_data->entries_per_queue = BA_WINDOW_SIZE;
592*d1e879ecSMiri Korenblit 
593*d1e879ecSMiri Korenblit 	buffer = setup_reorder_buffer(baid_data);
594*d1e879ecSMiri Korenblit 
595*d1e879ecSMiri Korenblit 	KUNIT_EXPECT_NULL(test, rcu_access_pointer(mld->fw_id_to_ba[baid]));
596*d1e879ecSMiri Korenblit 	rcu_assign_pointer(mld->fw_id_to_ba[baid], baid_data);
597*d1e879ecSMiri Korenblit 
598*d1e879ecSMiri Korenblit 	return buffer;
599*d1e879ecSMiri Korenblit }
600*d1e879ecSMiri Korenblit 
test_reorder_buffer(struct kunit * test)601*d1e879ecSMiri Korenblit static void test_reorder_buffer(struct kunit *test)
602*d1e879ecSMiri Korenblit {
603*d1e879ecSMiri Korenblit 	struct iwl_mld *mld = test->priv;
604*d1e879ecSMiri Korenblit 	const struct reorder_buffer_case *param =
605*d1e879ecSMiri Korenblit 		(const void *)(test->param_value);
606*d1e879ecSMiri Korenblit 	struct iwl_rx_mpdu_desc *mpdu_desc;
607*d1e879ecSMiri Korenblit 	struct ieee80211_vif *vif;
608*d1e879ecSMiri Korenblit 	struct ieee80211_sta *sta;
609*d1e879ecSMiri Korenblit 	struct sk_buff *skb;
610*d1e879ecSMiri Korenblit 	struct iwl_mld_reorder_buffer *buffer;
611*d1e879ecSMiri Korenblit 	enum iwl_mld_reorder_result reorder_res;
612*d1e879ecSMiri Korenblit 	u16 skb_release_order_count = param->expected.skb_release_order_count;
613*d1e879ecSMiri Korenblit 	u16 skb_idx = 0;
614*d1e879ecSMiri Korenblit 
615*d1e879ecSMiri Korenblit 	/* Init globals and activate stubs */
616*d1e879ecSMiri Korenblit 	__skb_queue_head_init(&g_released_skbs);
617*d1e879ecSMiri Korenblit 	g_num_released_skbs = 0;
618*d1e879ecSMiri Korenblit 	kunit_activate_static_stub(test, iwl_mld_fw_sta_id_mask,
619*d1e879ecSMiri Korenblit 				   fake_iwl_mld_fw_sta_id_mask);
620*d1e879ecSMiri Korenblit 	kunit_activate_static_stub(test, iwl_mld_pass_packet_to_mac80211,
621*d1e879ecSMiri Korenblit 				   fake_iwl_mld_pass_packet_to_mac80211);
622*d1e879ecSMiri Korenblit 
623*d1e879ecSMiri Korenblit 	vif = iwlmld_kunit_add_vif(false, NL80211_IFTYPE_STATION);
624*d1e879ecSMiri Korenblit 	sta = iwlmld_kunit_setup_sta(vif, IEEE80211_STA_AUTHORIZED, -1);
625*d1e879ecSMiri Korenblit 
626*d1e879ecSMiri Korenblit 	/* Prepare skb, mpdu_desc, BA data and the reorder buffer */
627*d1e879ecSMiri Korenblit 	skb = alloc_and_setup_skb(param->rx_pkt.fc, param->rx_pkt.sn,
628*d1e879ecSMiri Korenblit 				  param->rx_pkt.tid, param->rx_pkt.multicast);
629*d1e879ecSMiri Korenblit 	buffer = setup_ba_data(sta);
630*d1e879ecSMiri Korenblit 	mpdu_desc = setup_mpdu_desc();
631*d1e879ecSMiri Korenblit 
632*d1e879ecSMiri Korenblit 	rcu_read_lock();
633*d1e879ecSMiri Korenblit 	reorder_res = iwl_mld_reorder(mld, NULL, QUEUE, sta, skb, mpdu_desc);
634*d1e879ecSMiri Korenblit 	rcu_read_unlock();
635*d1e879ecSMiri Korenblit 
636*d1e879ecSMiri Korenblit 	KUNIT_ASSERT_EQ(test, reorder_res, param->expected.reorder_res);
637*d1e879ecSMiri Korenblit 	KUNIT_ASSERT_EQ(test, buffer->num_stored, param->expected.num_stored);
638*d1e879ecSMiri Korenblit 	KUNIT_ASSERT_EQ(test, buffer->head_sn, param->expected.head_sn);
639*d1e879ecSMiri Korenblit 
640*d1e879ecSMiri Korenblit 	/* Verify skbs release order */
641*d1e879ecSMiri Korenblit 	KUNIT_ASSERT_EQ(test, skb_release_order_count, g_num_released_skbs);
642*d1e879ecSMiri Korenblit 	while ((skb = __skb_dequeue(&g_released_skbs))) {
643*d1e879ecSMiri Korenblit 		struct ieee80211_hdr *hdr = (void *)skb_mac_header(skb);
644*d1e879ecSMiri Korenblit 
645*d1e879ecSMiri Korenblit 		KUNIT_ASSERT_EQ(test, le16_to_cpu(hdr->seq_ctrl),
646*d1e879ecSMiri Korenblit 				param->expected.skb_release_order[skb_idx]);
647*d1e879ecSMiri Korenblit 		skb_idx++;
648*d1e879ecSMiri Korenblit 	}
649*d1e879ecSMiri Korenblit 	KUNIT_ASSERT_EQ(test, skb_idx, skb_release_order_count);
650*d1e879ecSMiri Korenblit }
651*d1e879ecSMiri Korenblit 
652*d1e879ecSMiri Korenblit static struct kunit_case reorder_buffer_test_cases[] = {
653*d1e879ecSMiri Korenblit 	KUNIT_CASE_PARAM(test_reorder_buffer, test_reorder_buffer_gen_params),
654*d1e879ecSMiri Korenblit 	{},
655*d1e879ecSMiri Korenblit };
656*d1e879ecSMiri Korenblit 
657*d1e879ecSMiri Korenblit static struct kunit_suite reorder_buffer = {
658*d1e879ecSMiri Korenblit 	.name = "iwlmld-reorder-buffer",
659*d1e879ecSMiri Korenblit 	.test_cases = reorder_buffer_test_cases,
660*d1e879ecSMiri Korenblit 	.init = iwlmld_kunit_test_init,
661*d1e879ecSMiri Korenblit };
662*d1e879ecSMiri Korenblit 
663*d1e879ecSMiri Korenblit kunit_test_suite(reorder_buffer);
664