xref: /linux/net/mac80211/tests/mfp.c (revision b58b13f156c00c2457035b7071eaaac105fe6836)
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, WLAN_STA_MFP);
237 
238 	if (params->assoc)
239 		set_bit(WLAN_STA_ASSOC, &sta._flags);
240 
241 	rx.skb = kunit_zalloc_skb(test, 128, GFP_KERNEL);
242 	KUNIT_ASSERT_NOT_NULL(test, rx.skb);
243 	status = IEEE80211_SKB_RXCB(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(rx.skb, &hdr, sizeof(hdr));
256 
257 	switch (params->stype) {
258 	case IEEE80211_STYPE_ACTION:
259 		skb_put_u8(rx.skb, params->category);
260 		skb_put_u8(rx.skb, 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(rx.skb, &reason, 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