1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * KUnit tests for management frame acceptance |
4 | * |
5 | * Copyright (C) 2023 Intel Corporation |
6 | */ |
7 | #include <kunit/test.h> |
8 | #include <kunit/skbuff.h> |
9 | #include "../ieee80211_i.h" |
10 | #include "../sta_info.h" |
11 | |
12 | MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING); |
13 | |
14 | static const struct mfp_test_case { |
15 | const char *desc; |
16 | bool sta, mfp, decrypted, unicast, assoc; |
17 | u8 category; |
18 | u8 stype; |
19 | u8 action; |
20 | ieee80211_rx_result result; |
21 | } accept_mfp_cases[] = { |
22 | /* regular public action */ |
23 | { |
24 | .desc = "public action: accept unicast from unknown peer" , |
25 | .stype = IEEE80211_STYPE_ACTION, |
26 | .category = WLAN_CATEGORY_PUBLIC, |
27 | .action = WLAN_PUB_ACTION_DSE_ENABLEMENT, |
28 | .unicast = true, |
29 | .result = RX_CONTINUE, |
30 | }, |
31 | { |
32 | .desc = "public action: accept multicast from unknown peer" , |
33 | .stype = IEEE80211_STYPE_ACTION, |
34 | .category = WLAN_CATEGORY_PUBLIC, |
35 | .action = WLAN_PUB_ACTION_DSE_ENABLEMENT, |
36 | .unicast = false, |
37 | .result = RX_CONTINUE, |
38 | }, |
39 | { |
40 | .desc = "public action: accept unicast without MFP" , |
41 | .stype = IEEE80211_STYPE_ACTION, |
42 | .category = WLAN_CATEGORY_PUBLIC, |
43 | .action = WLAN_PUB_ACTION_DSE_ENABLEMENT, |
44 | .unicast = true, |
45 | .sta = true, |
46 | .result = RX_CONTINUE, |
47 | }, |
48 | { |
49 | .desc = "public action: accept multicast without MFP" , |
50 | .stype = IEEE80211_STYPE_ACTION, |
51 | .category = WLAN_CATEGORY_PUBLIC, |
52 | .action = WLAN_PUB_ACTION_DSE_ENABLEMENT, |
53 | .unicast = false, |
54 | .sta = true, |
55 | .result = RX_CONTINUE, |
56 | }, |
57 | { |
58 | .desc = "public action: drop unicast with MFP" , |
59 | .stype = IEEE80211_STYPE_ACTION, |
60 | .category = WLAN_CATEGORY_PUBLIC, |
61 | .action = WLAN_PUB_ACTION_DSE_ENABLEMENT, |
62 | .unicast = true, |
63 | .sta = true, |
64 | .mfp = true, |
65 | .result = RX_DROP_U_UNPROT_UNICAST_PUB_ACTION, |
66 | }, |
67 | { |
68 | .desc = "public action: accept multicast with MFP" , |
69 | .stype = IEEE80211_STYPE_ACTION, |
70 | .category = WLAN_CATEGORY_PUBLIC, |
71 | .action = WLAN_PUB_ACTION_DSE_ENABLEMENT, |
72 | .unicast = false, |
73 | .sta = true, |
74 | .mfp = true, |
75 | .result = RX_CONTINUE, |
76 | }, |
77 | /* protected dual of public action */ |
78 | { |
79 | .desc = "protected dual: drop unicast from unknown peer" , |
80 | .stype = IEEE80211_STYPE_ACTION, |
81 | .category = WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION, |
82 | .action = WLAN_PUB_ACTION_DSE_ENABLEMENT, |
83 | .unicast = true, |
84 | .result = RX_DROP_U_UNPROT_DUAL, |
85 | }, |
86 | { |
87 | .desc = "protected dual: drop multicast from unknown peer" , |
88 | .stype = IEEE80211_STYPE_ACTION, |
89 | .category = WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION, |
90 | .action = WLAN_PUB_ACTION_DSE_ENABLEMENT, |
91 | .unicast = false, |
92 | .result = RX_DROP_U_UNPROT_DUAL, |
93 | }, |
94 | { |
95 | .desc = "protected dual: drop unicast without MFP" , |
96 | .stype = IEEE80211_STYPE_ACTION, |
97 | .category = WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION, |
98 | .action = WLAN_PUB_ACTION_DSE_ENABLEMENT, |
99 | .unicast = true, |
100 | .sta = true, |
101 | .result = RX_DROP_U_UNPROT_DUAL, |
102 | }, |
103 | { |
104 | .desc = "protected dual: drop multicast without MFP" , |
105 | .stype = IEEE80211_STYPE_ACTION, |
106 | .category = WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION, |
107 | .action = WLAN_PUB_ACTION_DSE_ENABLEMENT, |
108 | .unicast = false, |
109 | .sta = true, |
110 | .result = RX_DROP_U_UNPROT_DUAL, |
111 | }, |
112 | { |
113 | .desc = "protected dual: drop undecrypted unicast with MFP" , |
114 | .stype = IEEE80211_STYPE_ACTION, |
115 | .category = WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION, |
116 | .action = WLAN_PUB_ACTION_DSE_ENABLEMENT, |
117 | .unicast = true, |
118 | .sta = true, |
119 | .mfp = true, |
120 | .result = RX_DROP_U_UNPROT_DUAL, |
121 | }, |
122 | { |
123 | .desc = "protected dual: drop undecrypted multicast with MFP" , |
124 | .stype = IEEE80211_STYPE_ACTION, |
125 | .category = WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION, |
126 | .action = WLAN_PUB_ACTION_DSE_ENABLEMENT, |
127 | .unicast = false, |
128 | .sta = true, |
129 | .mfp = true, |
130 | .result = RX_DROP_U_UNPROT_DUAL, |
131 | }, |
132 | { |
133 | .desc = "protected dual: accept unicast with MFP" , |
134 | .stype = IEEE80211_STYPE_ACTION, |
135 | .category = WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION, |
136 | .action = WLAN_PUB_ACTION_DSE_ENABLEMENT, |
137 | .decrypted = true, |
138 | .unicast = true, |
139 | .sta = true, |
140 | .mfp = true, |
141 | .result = RX_CONTINUE, |
142 | }, |
143 | { |
144 | .desc = "protected dual: accept multicast with MFP" , |
145 | .stype = IEEE80211_STYPE_ACTION, |
146 | .category = WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION, |
147 | .action = WLAN_PUB_ACTION_DSE_ENABLEMENT, |
148 | .decrypted = true, |
149 | .unicast = false, |
150 | .sta = true, |
151 | .mfp = true, |
152 | .result = RX_CONTINUE, |
153 | }, |
154 | /* deauth/disassoc before keys are set */ |
155 | { |
156 | .desc = "deauth: accept unicast with MFP but w/o key" , |
157 | .stype = IEEE80211_STYPE_DEAUTH, |
158 | .sta = true, |
159 | .mfp = true, |
160 | .unicast = true, |
161 | .result = RX_CONTINUE, |
162 | }, |
163 | { |
164 | .desc = "disassoc: accept unicast with MFP but w/o key" , |
165 | .stype = IEEE80211_STYPE_DEAUTH, |
166 | .sta = true, |
167 | .mfp = true, |
168 | .unicast = true, |
169 | .result = RX_CONTINUE, |
170 | }, |
171 | /* non-public robust action frame ... */ |
172 | { |
173 | .desc = "BA action: drop unicast before assoc" , |
174 | .stype = IEEE80211_STYPE_ACTION, |
175 | .category = WLAN_CATEGORY_BACK, |
176 | .unicast = true, |
177 | .sta = true, |
178 | .result = RX_DROP_U_UNPROT_ROBUST_ACTION, |
179 | }, |
180 | { |
181 | .desc = "BA action: drop unprotected after assoc" , |
182 | .stype = IEEE80211_STYPE_ACTION, |
183 | .category = WLAN_CATEGORY_BACK, |
184 | .unicast = true, |
185 | .sta = true, |
186 | .mfp = true, |
187 | .result = RX_DROP_U_UNPROT_UCAST_MGMT, |
188 | }, |
189 | { |
190 | .desc = "BA action: accept unprotected without MFP" , |
191 | .stype = IEEE80211_STYPE_ACTION, |
192 | .category = WLAN_CATEGORY_BACK, |
193 | .unicast = true, |
194 | .sta = true, |
195 | .assoc = true, |
196 | .mfp = false, |
197 | .result = RX_CONTINUE, |
198 | }, |
199 | { |
200 | .desc = "BA action: drop unprotected with MFP" , |
201 | .stype = IEEE80211_STYPE_ACTION, |
202 | .category = WLAN_CATEGORY_BACK, |
203 | .unicast = true, |
204 | .sta = true, |
205 | .mfp = true, |
206 | .result = RX_DROP_U_UNPROT_UCAST_MGMT, |
207 | }, |
208 | }; |
209 | |
210 | KUNIT_ARRAY_PARAM_DESC(accept_mfp, accept_mfp_cases, desc); |
211 | |
212 | static void accept_mfp(struct kunit *test) |
213 | { |
214 | static struct sta_info sta; |
215 | const struct mfp_test_case *params = test->param_value; |
216 | struct ieee80211_rx_data rx = { |
217 | .sta = params->sta ? &sta : NULL, |
218 | }; |
219 | struct ieee80211_rx_status *status; |
220 | struct ieee80211_hdr_3addr hdr = { |
221 | .frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
222 | params->stype), |
223 | .addr1 = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, |
224 | .addr2 = { 0x12, 0x22, 0x33, 0x44, 0x55, 0x66 }, |
225 | /* A3/BSSID doesn't matter here */ |
226 | }; |
227 | |
228 | memset(&sta, 0, sizeof(sta)); |
229 | |
230 | if (!params->sta) { |
231 | KUNIT_ASSERT_FALSE(test, params->mfp); |
232 | KUNIT_ASSERT_FALSE(test, params->decrypted); |
233 | } |
234 | |
235 | if (params->mfp) |
236 | set_sta_flag(sta: &sta, flag: WLAN_STA_MFP); |
237 | |
238 | if (params->assoc) |
239 | set_bit(nr: WLAN_STA_ASSOC, addr: &sta._flags); |
240 | |
241 | rx.skb = kunit_zalloc_skb(test, len: 128, GFP_KERNEL); |
242 | KUNIT_ASSERT_NOT_NULL(test, rx.skb); |
243 | status = IEEE80211_SKB_RXCB(skb: rx.skb); |
244 | |
245 | if (params->decrypted) { |
246 | status->flag |= RX_FLAG_DECRYPTED; |
247 | if (params->unicast) |
248 | hdr.frame_control |= |
249 | cpu_to_le16(IEEE80211_FCTL_PROTECTED); |
250 | } |
251 | |
252 | if (params->unicast) |
253 | hdr.addr1[0] = 0x02; |
254 | |
255 | skb_put_data(skb: rx.skb, data: &hdr, len: sizeof(hdr)); |
256 | |
257 | switch (params->stype) { |
258 | case IEEE80211_STYPE_ACTION: |
259 | skb_put_u8(skb: rx.skb, val: params->category); |
260 | skb_put_u8(skb: rx.skb, val: params->action); |
261 | break; |
262 | case IEEE80211_STYPE_DEAUTH: |
263 | case IEEE80211_STYPE_DISASSOC: { |
264 | __le16 reason = cpu_to_le16(WLAN_REASON_UNSPECIFIED); |
265 | |
266 | skb_put_data(skb: rx.skb, data: &reason, len: sizeof(reason)); |
267 | } |
268 | break; |
269 | } |
270 | |
271 | KUNIT_EXPECT_EQ(test, |
272 | (__force u32)ieee80211_drop_unencrypted_mgmt(&rx), |
273 | (__force u32)params->result); |
274 | } |
275 | |
276 | static struct kunit_case mfp_test_cases[] = { |
277 | KUNIT_CASE_PARAM(accept_mfp, accept_mfp_gen_params), |
278 | {} |
279 | }; |
280 | |
281 | static struct kunit_suite mfp = { |
282 | .name = "mac80211-mfp" , |
283 | .test_cases = mfp_test_cases, |
284 | }; |
285 | |
286 | kunit_test_suite(mfp); |
287 | |