xref: /freebsd/contrib/wpa/src/ap/wpa_auth_ie.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
1e28a4053SRui Paulo /*
2e28a4053SRui Paulo  * hostapd - WPA/RSN IE and KDE definitions
385732ac8SCy Schubert  * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
4e28a4053SRui Paulo  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
7e28a4053SRui Paulo  */
8e28a4053SRui Paulo 
9e28a4053SRui Paulo #include "utils/includes.h"
10e28a4053SRui Paulo 
11e28a4053SRui Paulo #include "utils/common.h"
12e28a4053SRui Paulo #include "common/ieee802_11_defs.h"
13*a90b9d01SCy Schubert #include "drivers/driver.h"
14e28a4053SRui Paulo #include "eapol_auth/eapol_auth_sm.h"
15e28a4053SRui Paulo #include "ap_config.h"
16e28a4053SRui Paulo #include "ieee802_11.h"
17e28a4053SRui Paulo #include "wpa_auth.h"
18e28a4053SRui Paulo #include "pmksa_cache_auth.h"
19e28a4053SRui Paulo #include "wpa_auth_ie.h"
20e28a4053SRui Paulo #include "wpa_auth_i.h"
21e28a4053SRui Paulo 
22e28a4053SRui Paulo 
23f05cddf9SRui Paulo #ifdef CONFIG_RSN_TESTING
24f05cddf9SRui Paulo int rsn_testing = 0;
25f05cddf9SRui Paulo #endif /* CONFIG_RSN_TESTING */
26f05cddf9SRui Paulo 
27f05cddf9SRui Paulo 
wpa_write_wpa_ie(struct wpa_auth_config * conf,u8 * buf,size_t len)28e28a4053SRui Paulo static int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len)
29e28a4053SRui Paulo {
30e28a4053SRui Paulo 	struct wpa_ie_hdr *hdr;
31e28a4053SRui Paulo 	int num_suites;
32e28a4053SRui Paulo 	u8 *pos, *count;
33f05cddf9SRui Paulo 	u32 suite;
34e28a4053SRui Paulo 
35e28a4053SRui Paulo 	hdr = (struct wpa_ie_hdr *) buf;
36e28a4053SRui Paulo 	hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC;
37e28a4053SRui Paulo 	RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE);
38e28a4053SRui Paulo 	WPA_PUT_LE16(hdr->version, WPA_VERSION);
39e28a4053SRui Paulo 	pos = (u8 *) (hdr + 1);
40e28a4053SRui Paulo 
41f05cddf9SRui Paulo 	suite = wpa_cipher_to_suite(WPA_PROTO_WPA, conf->wpa_group);
42f05cddf9SRui Paulo 	if (suite == 0) {
43e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
44e28a4053SRui Paulo 			   conf->wpa_group);
45e28a4053SRui Paulo 		return -1;
46e28a4053SRui Paulo 	}
47f05cddf9SRui Paulo 	RSN_SELECTOR_PUT(pos, suite);
48e28a4053SRui Paulo 	pos += WPA_SELECTOR_LEN;
49e28a4053SRui Paulo 
50e28a4053SRui Paulo 	count = pos;
51e28a4053SRui Paulo 	pos += 2;
52e28a4053SRui Paulo 
53f05cddf9SRui Paulo 	num_suites = wpa_cipher_put_suites(pos, conf->wpa_pairwise);
54e28a4053SRui Paulo 	if (num_suites == 0) {
55e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
56e28a4053SRui Paulo 			   conf->wpa_pairwise);
57e28a4053SRui Paulo 		return -1;
58e28a4053SRui Paulo 	}
59f05cddf9SRui Paulo 	pos += num_suites * WPA_SELECTOR_LEN;
60e28a4053SRui Paulo 	WPA_PUT_LE16(count, num_suites);
61e28a4053SRui Paulo 
62e28a4053SRui Paulo 	num_suites = 0;
63e28a4053SRui Paulo 	count = pos;
64e28a4053SRui Paulo 	pos += 2;
65e28a4053SRui Paulo 
66e28a4053SRui Paulo 	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
67e28a4053SRui Paulo 		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
68e28a4053SRui Paulo 		pos += WPA_SELECTOR_LEN;
69e28a4053SRui Paulo 		num_suites++;
70e28a4053SRui Paulo 	}
71e28a4053SRui Paulo 	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
72e28a4053SRui Paulo 		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
73e28a4053SRui Paulo 		pos += WPA_SELECTOR_LEN;
74e28a4053SRui Paulo 		num_suites++;
75e28a4053SRui Paulo 	}
76e28a4053SRui Paulo 
77e28a4053SRui Paulo 	if (num_suites == 0) {
78e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
79e28a4053SRui Paulo 			   conf->wpa_key_mgmt);
80e28a4053SRui Paulo 		return -1;
81e28a4053SRui Paulo 	}
82e28a4053SRui Paulo 	WPA_PUT_LE16(count, num_suites);
83e28a4053SRui Paulo 
84e28a4053SRui Paulo 	/* WPA Capabilities; use defaults, so no need to include it */
85e28a4053SRui Paulo 
86e28a4053SRui Paulo 	hdr->len = (pos - buf) - 2;
87e28a4053SRui Paulo 
88e28a4053SRui Paulo 	return pos - buf;
89e28a4053SRui Paulo }
90e28a4053SRui Paulo 
91e28a4053SRui Paulo 
wpa_own_rsn_capab(struct wpa_auth_config * conf)92c1d255d3SCy Schubert static u16 wpa_own_rsn_capab(struct wpa_auth_config *conf)
93c1d255d3SCy Schubert {
94c1d255d3SCy Schubert 	u16 capab = 0;
95c1d255d3SCy Schubert 
96c1d255d3SCy Schubert 	if (conf->rsn_preauth)
97c1d255d3SCy Schubert 		capab |= WPA_CAPABILITY_PREAUTH;
98c1d255d3SCy Schubert 	if (conf->wmm_enabled) {
99c1d255d3SCy Schubert 		/* 4 PTKSA replay counters when using WMM */
100c1d255d3SCy Schubert 		capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
101c1d255d3SCy Schubert 	}
102c1d255d3SCy Schubert 	if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
103c1d255d3SCy Schubert 		capab |= WPA_CAPABILITY_MFPC;
104c1d255d3SCy Schubert 		if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
105c1d255d3SCy Schubert 			capab |= WPA_CAPABILITY_MFPR;
106c1d255d3SCy Schubert 	}
107c1d255d3SCy Schubert #ifdef CONFIG_OCV
108c1d255d3SCy Schubert 	if (conf->ocv)
109c1d255d3SCy Schubert 		capab |= WPA_CAPABILITY_OCVC;
110c1d255d3SCy Schubert #endif /* CONFIG_OCV */
111c1d255d3SCy Schubert #ifdef CONFIG_RSN_TESTING
112c1d255d3SCy Schubert 	if (rsn_testing)
113c1d255d3SCy Schubert 		capab |= BIT(8) | BIT(15);
114c1d255d3SCy Schubert #endif /* CONFIG_RSN_TESTING */
115c1d255d3SCy Schubert 	if (conf->extended_key_id)
116c1d255d3SCy Schubert 		capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
117c1d255d3SCy Schubert 
118c1d255d3SCy Schubert 	return capab;
119c1d255d3SCy Schubert }
120c1d255d3SCy Schubert 
121c1d255d3SCy Schubert 
wpa_write_rsn_ie(struct wpa_auth_config * conf,u8 * buf,size_t len,const u8 * pmkid)122e28a4053SRui Paulo int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
123e28a4053SRui Paulo 		     const u8 *pmkid)
124e28a4053SRui Paulo {
125e28a4053SRui Paulo 	struct rsn_ie_hdr *hdr;
126f05cddf9SRui Paulo 	int num_suites, res;
127e28a4053SRui Paulo 	u8 *pos, *count;
128f05cddf9SRui Paulo 	u32 suite;
129e28a4053SRui Paulo 
130e28a4053SRui Paulo 	hdr = (struct rsn_ie_hdr *) buf;
131e28a4053SRui Paulo 	hdr->elem_id = WLAN_EID_RSN;
132e28a4053SRui Paulo 	WPA_PUT_LE16(hdr->version, RSN_VERSION);
133e28a4053SRui Paulo 	pos = (u8 *) (hdr + 1);
134e28a4053SRui Paulo 
135f05cddf9SRui Paulo 	suite = wpa_cipher_to_suite(WPA_PROTO_RSN, conf->wpa_group);
136f05cddf9SRui Paulo 	if (suite == 0) {
137e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
138e28a4053SRui Paulo 			   conf->wpa_group);
139e28a4053SRui Paulo 		return -1;
140e28a4053SRui Paulo 	}
141f05cddf9SRui Paulo 	RSN_SELECTOR_PUT(pos, suite);
142e28a4053SRui Paulo 	pos += RSN_SELECTOR_LEN;
143e28a4053SRui Paulo 
144e28a4053SRui Paulo 	num_suites = 0;
145e28a4053SRui Paulo 	count = pos;
146e28a4053SRui Paulo 	pos += 2;
147e28a4053SRui Paulo 
148f05cddf9SRui Paulo #ifdef CONFIG_RSN_TESTING
149f05cddf9SRui Paulo 	if (rsn_testing) {
150f05cddf9SRui Paulo 		RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1));
151e28a4053SRui Paulo 		pos += RSN_SELECTOR_LEN;
152e28a4053SRui Paulo 		num_suites++;
153e28a4053SRui Paulo 	}
154f05cddf9SRui Paulo #endif /* CONFIG_RSN_TESTING */
155f05cddf9SRui Paulo 
156f05cddf9SRui Paulo 	res = rsn_cipher_put_suites(pos, conf->rsn_pairwise);
157f05cddf9SRui Paulo 	num_suites += res;
158f05cddf9SRui Paulo 	pos += res * RSN_SELECTOR_LEN;
159f05cddf9SRui Paulo 
160f05cddf9SRui Paulo #ifdef CONFIG_RSN_TESTING
161f05cddf9SRui Paulo 	if (rsn_testing) {
162f05cddf9SRui Paulo 		RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2));
163e28a4053SRui Paulo 		pos += RSN_SELECTOR_LEN;
164e28a4053SRui Paulo 		num_suites++;
165e28a4053SRui Paulo 	}
166f05cddf9SRui Paulo #endif /* CONFIG_RSN_TESTING */
167e28a4053SRui Paulo 
168e28a4053SRui Paulo 	if (num_suites == 0) {
169e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
170e28a4053SRui Paulo 			   conf->rsn_pairwise);
171e28a4053SRui Paulo 		return -1;
172e28a4053SRui Paulo 	}
173e28a4053SRui Paulo 	WPA_PUT_LE16(count, num_suites);
174e28a4053SRui Paulo 
175e28a4053SRui Paulo 	num_suites = 0;
176e28a4053SRui Paulo 	count = pos;
177e28a4053SRui Paulo 	pos += 2;
178e28a4053SRui Paulo 
179f05cddf9SRui Paulo #ifdef CONFIG_RSN_TESTING
180f05cddf9SRui Paulo 	if (rsn_testing) {
181f05cddf9SRui Paulo 		RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1));
182f05cddf9SRui Paulo 		pos += RSN_SELECTOR_LEN;
183f05cddf9SRui Paulo 		num_suites++;
184f05cddf9SRui Paulo 	}
185f05cddf9SRui Paulo #endif /* CONFIG_RSN_TESTING */
186f05cddf9SRui Paulo 
187e28a4053SRui Paulo 	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
188e28a4053SRui Paulo 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
189e28a4053SRui Paulo 		pos += RSN_SELECTOR_LEN;
190e28a4053SRui Paulo 		num_suites++;
191e28a4053SRui Paulo 	}
192e28a4053SRui Paulo 	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
193e28a4053SRui Paulo 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
194e28a4053SRui Paulo 		pos += RSN_SELECTOR_LEN;
195e28a4053SRui Paulo 		num_suites++;
196e28a4053SRui Paulo 	}
19785732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP
198e28a4053SRui Paulo 	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
199e28a4053SRui Paulo 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
200e28a4053SRui Paulo 		pos += RSN_SELECTOR_LEN;
201e28a4053SRui Paulo 		num_suites++;
202e28a4053SRui Paulo 	}
20385732ac8SCy Schubert #ifdef CONFIG_SHA384
20485732ac8SCy Schubert 	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
20585732ac8SCy Schubert 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384);
20685732ac8SCy Schubert 		pos += RSN_SELECTOR_LEN;
20785732ac8SCy Schubert 		num_suites++;
20885732ac8SCy Schubert 	}
20985732ac8SCy Schubert #endif /* CONFIG_SHA384 */
210e28a4053SRui Paulo 	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
211e28a4053SRui Paulo 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
212e28a4053SRui Paulo 		pos += RSN_SELECTOR_LEN;
213e28a4053SRui Paulo 		num_suites++;
214e28a4053SRui Paulo 	}
21585732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */
216*a90b9d01SCy Schubert #ifdef CONFIG_SHA384
217*a90b9d01SCy Schubert 	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA384) {
218*a90b9d01SCy Schubert 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA384);
219*a90b9d01SCy Schubert 		pos += RSN_SELECTOR_LEN;
220*a90b9d01SCy Schubert 		num_suites++;
221*a90b9d01SCy Schubert 	}
222*a90b9d01SCy Schubert #endif /* CONFIG_SHA384 */
223e28a4053SRui Paulo 	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
224e28a4053SRui Paulo 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
225e28a4053SRui Paulo 		pos += RSN_SELECTOR_LEN;
226e28a4053SRui Paulo 		num_suites++;
227e28a4053SRui Paulo 	}
228e28a4053SRui Paulo 	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
229e28a4053SRui Paulo 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
230e28a4053SRui Paulo 		pos += RSN_SELECTOR_LEN;
231e28a4053SRui Paulo 		num_suites++;
232e28a4053SRui Paulo 	}
233f05cddf9SRui Paulo #ifdef CONFIG_SAE
234f05cddf9SRui Paulo 	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
235f05cddf9SRui Paulo 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
236f05cddf9SRui Paulo 		pos += RSN_SELECTOR_LEN;
237f05cddf9SRui Paulo 		num_suites++;
238f05cddf9SRui Paulo 	}
239*a90b9d01SCy Schubert 	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) {
240*a90b9d01SCy Schubert 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE_EXT_KEY);
241*a90b9d01SCy Schubert 		pos += RSN_SELECTOR_LEN;
242*a90b9d01SCy Schubert 		num_suites++;
243*a90b9d01SCy Schubert 	}
244f05cddf9SRui Paulo 	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
245f05cddf9SRui Paulo 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
246f05cddf9SRui Paulo 		pos += RSN_SELECTOR_LEN;
247f05cddf9SRui Paulo 		num_suites++;
248f05cddf9SRui Paulo 	}
249*a90b9d01SCy Schubert 	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY) {
250*a90b9d01SCy Schubert 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY);
251*a90b9d01SCy Schubert 		pos += RSN_SELECTOR_LEN;
252*a90b9d01SCy Schubert 		num_suites++;
253*a90b9d01SCy Schubert 	}
254f05cddf9SRui Paulo #endif /* CONFIG_SAE */
2555b9c547cSRui Paulo 	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
2565b9c547cSRui Paulo 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B);
2575b9c547cSRui Paulo 		pos += RSN_SELECTOR_LEN;
2585b9c547cSRui Paulo 		num_suites++;
2595b9c547cSRui Paulo 	}
2605b9c547cSRui Paulo 	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
2615b9c547cSRui Paulo 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192);
2625b9c547cSRui Paulo 		pos += RSN_SELECTOR_LEN;
2635b9c547cSRui Paulo 		num_suites++;
2645b9c547cSRui Paulo 	}
26585732ac8SCy Schubert #ifdef CONFIG_FILS
26685732ac8SCy Schubert 	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FILS_SHA256) {
26785732ac8SCy Schubert 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA256);
26885732ac8SCy Schubert 		pos += RSN_SELECTOR_LEN;
26985732ac8SCy Schubert 		num_suites++;
27085732ac8SCy Schubert 	}
27185732ac8SCy Schubert 	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FILS_SHA384) {
27285732ac8SCy Schubert 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FILS_SHA384);
27385732ac8SCy Schubert 		pos += RSN_SELECTOR_LEN;
27485732ac8SCy Schubert 		num_suites++;
27585732ac8SCy Schubert 	}
27685732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP
27785732ac8SCy Schubert 	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) {
27885732ac8SCy Schubert 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA256);
27985732ac8SCy Schubert 		pos += RSN_SELECTOR_LEN;
28085732ac8SCy Schubert 		num_suites++;
28185732ac8SCy Schubert 	}
28285732ac8SCy Schubert 	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) {
28385732ac8SCy Schubert 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_FILS_SHA384);
28485732ac8SCy Schubert 		pos += RSN_SELECTOR_LEN;
28585732ac8SCy Schubert 		num_suites++;
28685732ac8SCy Schubert 	}
28785732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */
28885732ac8SCy Schubert #endif /* CONFIG_FILS */
28985732ac8SCy Schubert #ifdef CONFIG_OWE
29085732ac8SCy Schubert 	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) {
29185732ac8SCy Schubert 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OWE);
29285732ac8SCy Schubert 		pos += RSN_SELECTOR_LEN;
29385732ac8SCy Schubert 		num_suites++;
29485732ac8SCy Schubert 	}
29585732ac8SCy Schubert #endif /* CONFIG_OWE */
29685732ac8SCy Schubert #ifdef CONFIG_DPP
29785732ac8SCy Schubert 	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_DPP) {
29885732ac8SCy Schubert 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_DPP);
29985732ac8SCy Schubert 		pos += RSN_SELECTOR_LEN;
30085732ac8SCy Schubert 		num_suites++;
30185732ac8SCy Schubert 	}
30285732ac8SCy Schubert #endif /* CONFIG_DPP */
30385732ac8SCy Schubert #ifdef CONFIG_HS20
30485732ac8SCy Schubert 	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_OSEN) {
30585732ac8SCy Schubert 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN);
30685732ac8SCy Schubert 		pos += RSN_SELECTOR_LEN;
30785732ac8SCy Schubert 		num_suites++;
30885732ac8SCy Schubert 	}
30985732ac8SCy Schubert #endif /* CONFIG_HS20 */
310c1d255d3SCy Schubert #ifdef CONFIG_PASN
311c1d255d3SCy Schubert 	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PASN) {
312c1d255d3SCy Schubert 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PASN);
313c1d255d3SCy Schubert 		pos += RSN_SELECTOR_LEN;
314c1d255d3SCy Schubert 		num_suites++;
315c1d255d3SCy Schubert 	}
316c1d255d3SCy Schubert #endif /* CONFIG_PASN */
317f05cddf9SRui Paulo 
318f05cddf9SRui Paulo #ifdef CONFIG_RSN_TESTING
319f05cddf9SRui Paulo 	if (rsn_testing) {
320f05cddf9SRui Paulo 		RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2));
321f05cddf9SRui Paulo 		pos += RSN_SELECTOR_LEN;
322f05cddf9SRui Paulo 		num_suites++;
323f05cddf9SRui Paulo 	}
324f05cddf9SRui Paulo #endif /* CONFIG_RSN_TESTING */
325e28a4053SRui Paulo 
326e28a4053SRui Paulo 	if (num_suites == 0) {
327e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
328e28a4053SRui Paulo 			   conf->wpa_key_mgmt);
329e28a4053SRui Paulo 		return -1;
330e28a4053SRui Paulo 	}
331e28a4053SRui Paulo 	WPA_PUT_LE16(count, num_suites);
332e28a4053SRui Paulo 
333e28a4053SRui Paulo 	/* RSN Capabilities */
334c1d255d3SCy Schubert 	WPA_PUT_LE16(pos, wpa_own_rsn_capab(conf));
335e28a4053SRui Paulo 	pos += 2;
336e28a4053SRui Paulo 
337e28a4053SRui Paulo 	if (pmkid) {
338780fb4a2SCy Schubert 		if (2 + PMKID_LEN > buf + len - pos)
339e28a4053SRui Paulo 			return -1;
340e28a4053SRui Paulo 		/* PMKID Count */
341e28a4053SRui Paulo 		WPA_PUT_LE16(pos, 1);
342e28a4053SRui Paulo 		pos += 2;
343e28a4053SRui Paulo 		os_memcpy(pos, pmkid, PMKID_LEN);
344e28a4053SRui Paulo 		pos += PMKID_LEN;
345e28a4053SRui Paulo 	}
346e28a4053SRui Paulo 
347325151a3SRui Paulo 	if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION &&
348325151a3SRui Paulo 	    conf->group_mgmt_cipher != WPA_CIPHER_AES_128_CMAC) {
349780fb4a2SCy Schubert 		if (2 + 4 > buf + len - pos)
350e28a4053SRui Paulo 			return -1;
351e28a4053SRui Paulo 		if (pmkid == NULL) {
352e28a4053SRui Paulo 			/* PMKID Count */
353e28a4053SRui Paulo 			WPA_PUT_LE16(pos, 0);
354e28a4053SRui Paulo 			pos += 2;
355e28a4053SRui Paulo 		}
356e28a4053SRui Paulo 
357e28a4053SRui Paulo 		/* Management Group Cipher Suite */
3585b9c547cSRui Paulo 		switch (conf->group_mgmt_cipher) {
3595b9c547cSRui Paulo 		case WPA_CIPHER_AES_128_CMAC:
360e28a4053SRui Paulo 			RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
3615b9c547cSRui Paulo 			break;
3625b9c547cSRui Paulo 		case WPA_CIPHER_BIP_GMAC_128:
3635b9c547cSRui Paulo 			RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_GMAC_128);
3645b9c547cSRui Paulo 			break;
3655b9c547cSRui Paulo 		case WPA_CIPHER_BIP_GMAC_256:
3665b9c547cSRui Paulo 			RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_GMAC_256);
3675b9c547cSRui Paulo 			break;
3685b9c547cSRui Paulo 		case WPA_CIPHER_BIP_CMAC_256:
3695b9c547cSRui Paulo 			RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_CMAC_256);
3705b9c547cSRui Paulo 			break;
3715b9c547cSRui Paulo 		default:
3725b9c547cSRui Paulo 			wpa_printf(MSG_DEBUG,
3735b9c547cSRui Paulo 				   "Invalid group management cipher (0x%x)",
3745b9c547cSRui Paulo 				   conf->group_mgmt_cipher);
3755b9c547cSRui Paulo 			return -1;
3765b9c547cSRui Paulo 		}
377e28a4053SRui Paulo 		pos += RSN_SELECTOR_LEN;
378e28a4053SRui Paulo 	}
379e28a4053SRui Paulo 
380f05cddf9SRui Paulo #ifdef CONFIG_RSN_TESTING
381f05cddf9SRui Paulo 	if (rsn_testing) {
382f05cddf9SRui Paulo 		/*
383f05cddf9SRui Paulo 		 * Fill in any defined fields and add extra data to the end of
384f05cddf9SRui Paulo 		 * the element.
385f05cddf9SRui Paulo 		 */
386f05cddf9SRui Paulo 		int pmkid_count_set = pmkid != NULL;
387f05cddf9SRui Paulo 		if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION)
388f05cddf9SRui Paulo 			pmkid_count_set = 1;
389f05cddf9SRui Paulo 		/* PMKID Count */
390f05cddf9SRui Paulo 		WPA_PUT_LE16(pos, 0);
391f05cddf9SRui Paulo 		pos += 2;
392f05cddf9SRui Paulo 		if (conf->ieee80211w == NO_MGMT_FRAME_PROTECTION) {
393f05cddf9SRui Paulo 			/* Management Group Cipher Suite */
394f05cddf9SRui Paulo 			RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
395f05cddf9SRui Paulo 			pos += RSN_SELECTOR_LEN;
396f05cddf9SRui Paulo 		}
397f05cddf9SRui Paulo 
398f05cddf9SRui Paulo 		os_memset(pos, 0x12, 17);
399f05cddf9SRui Paulo 		pos += 17;
400f05cddf9SRui Paulo 	}
401f05cddf9SRui Paulo #endif /* CONFIG_RSN_TESTING */
402f05cddf9SRui Paulo 
403e28a4053SRui Paulo 	hdr->len = (pos - buf) - 2;
404e28a4053SRui Paulo 
405e28a4053SRui Paulo 	return pos - buf;
406e28a4053SRui Paulo }
407e28a4053SRui Paulo 
408e28a4053SRui Paulo 
wpa_write_rsnxe(struct wpa_auth_config * conf,u8 * buf,size_t len)409c1d255d3SCy Schubert int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len)
410c1d255d3SCy Schubert {
411c1d255d3SCy Schubert 	u8 *pos = buf;
412*a90b9d01SCy Schubert 	u32 capab = 0, tmp;
413c1d255d3SCy Schubert 	size_t flen;
414c1d255d3SCy Schubert 
415c1d255d3SCy Schubert 	if (wpa_key_mgmt_sae(conf->wpa_key_mgmt) &&
416*a90b9d01SCy Schubert 	    (conf->sae_pwe == SAE_PWE_HASH_TO_ELEMENT ||
417*a90b9d01SCy Schubert 	     conf->sae_pwe == SAE_PWE_BOTH || conf->sae_pk ||
418*a90b9d01SCy Schubert 	     wpa_key_mgmt_sae_ext_key(conf->wpa_key_mgmt))) {
419c1d255d3SCy Schubert 		capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
420c1d255d3SCy Schubert #ifdef CONFIG_SAE_PK
421c1d255d3SCy Schubert 		if (conf->sae_pk)
422c1d255d3SCy Schubert 			capab |= BIT(WLAN_RSNX_CAPAB_SAE_PK);
423c1d255d3SCy Schubert #endif /* CONFIG_SAE_PK */
424c1d255d3SCy Schubert 	}
425c1d255d3SCy Schubert 
426c1d255d3SCy Schubert 	if (conf->secure_ltf)
427c1d255d3SCy Schubert 		capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF);
428c1d255d3SCy Schubert 	if (conf->secure_rtt)
429c1d255d3SCy Schubert 		capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
430c1d255d3SCy Schubert 	if (conf->prot_range_neg)
431*a90b9d01SCy Schubert 		capab |= BIT(WLAN_RSNX_CAPAB_URNM_MFPR);
432*a90b9d01SCy Schubert 	if (conf->ssid_protection)
433*a90b9d01SCy Schubert 		capab |= BIT(WLAN_RSNX_CAPAB_SSID_PROTECTION);
434c1d255d3SCy Schubert 
435c1d255d3SCy Schubert 	if (!capab)
436c1d255d3SCy Schubert 		return 0; /* no supported extended RSN capabilities */
437*a90b9d01SCy Schubert 	tmp = capab;
438*a90b9d01SCy Schubert 	flen = 0;
439*a90b9d01SCy Schubert 	while (tmp) {
440*a90b9d01SCy Schubert 		flen++;
441*a90b9d01SCy Schubert 		tmp >>= 8;
442*a90b9d01SCy Schubert 	}
443c1d255d3SCy Schubert 	if (len < 2 + flen)
444c1d255d3SCy Schubert 		return -1;
445c1d255d3SCy Schubert 	capab |= flen - 1; /* bit 0-3 = Field length (n - 1) */
446c1d255d3SCy Schubert 
447c1d255d3SCy Schubert 	*pos++ = WLAN_EID_RSNX;
448c1d255d3SCy Schubert 	*pos++ = flen;
449*a90b9d01SCy Schubert 	while (capab) {
450*a90b9d01SCy Schubert 		*pos++ = capab & 0xff;
451c1d255d3SCy Schubert 		capab >>= 8;
452*a90b9d01SCy Schubert 	}
453c1d255d3SCy Schubert 
454c1d255d3SCy Schubert 	return pos - buf;
455c1d255d3SCy Schubert }
456c1d255d3SCy Schubert 
457c1d255d3SCy Schubert 
wpa_write_osen(struct wpa_auth_config * conf,u8 * eid)4585b9c547cSRui Paulo static u8 * wpa_write_osen(struct wpa_auth_config *conf, u8 *eid)
4595b9c547cSRui Paulo {
4605b9c547cSRui Paulo 	u8 *len;
4615b9c547cSRui Paulo 	u16 capab;
4625b9c547cSRui Paulo 
4635b9c547cSRui Paulo 	*eid++ = WLAN_EID_VENDOR_SPECIFIC;
4645b9c547cSRui Paulo 	len = eid++; /* to be filled */
4655b9c547cSRui Paulo 	WPA_PUT_BE24(eid, OUI_WFA);
4665b9c547cSRui Paulo 	eid += 3;
4675b9c547cSRui Paulo 	*eid++ = HS20_OSEN_OUI_TYPE;
4685b9c547cSRui Paulo 
4695b9c547cSRui Paulo 	/* Group Data Cipher Suite */
4705b9c547cSRui Paulo 	RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
4715b9c547cSRui Paulo 	eid += RSN_SELECTOR_LEN;
4725b9c547cSRui Paulo 
4735b9c547cSRui Paulo 	/* Pairwise Cipher Suite Count and List */
4745b9c547cSRui Paulo 	WPA_PUT_LE16(eid, 1);
4755b9c547cSRui Paulo 	eid += 2;
4765b9c547cSRui Paulo 	RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_CCMP);
4775b9c547cSRui Paulo 	eid += RSN_SELECTOR_LEN;
4785b9c547cSRui Paulo 
4795b9c547cSRui Paulo 	/* AKM Suite Count and List */
4805b9c547cSRui Paulo 	WPA_PUT_LE16(eid, 1);
4815b9c547cSRui Paulo 	eid += 2;
4825b9c547cSRui Paulo 	RSN_SELECTOR_PUT(eid, RSN_AUTH_KEY_MGMT_OSEN);
4835b9c547cSRui Paulo 	eid += RSN_SELECTOR_LEN;
4845b9c547cSRui Paulo 
4855b9c547cSRui Paulo 	/* RSN Capabilities */
4865b9c547cSRui Paulo 	capab = 0;
4875b9c547cSRui Paulo 	if (conf->wmm_enabled) {
4885b9c547cSRui Paulo 		/* 4 PTKSA replay counters when using WMM */
4895b9c547cSRui Paulo 		capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
4905b9c547cSRui Paulo 	}
4915b9c547cSRui Paulo 	if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
4925b9c547cSRui Paulo 		capab |= WPA_CAPABILITY_MFPC;
4935b9c547cSRui Paulo 		if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
4945b9c547cSRui Paulo 			capab |= WPA_CAPABILITY_MFPR;
4955b9c547cSRui Paulo 	}
4964bc52338SCy Schubert #ifdef CONFIG_OCV
4974bc52338SCy Schubert 	if (conf->ocv)
4984bc52338SCy Schubert 		capab |= WPA_CAPABILITY_OCVC;
4994bc52338SCy Schubert #endif /* CONFIG_OCV */
5005b9c547cSRui Paulo 	WPA_PUT_LE16(eid, capab);
5015b9c547cSRui Paulo 	eid += 2;
5025b9c547cSRui Paulo 
5035b9c547cSRui Paulo 	*len = eid - len - 1;
5045b9c547cSRui Paulo 
5055b9c547cSRui Paulo 	return eid;
5065b9c547cSRui Paulo }
5075b9c547cSRui Paulo 
5085b9c547cSRui Paulo 
wpa_auth_gen_wpa_ie(struct wpa_authenticator * wpa_auth)509e28a4053SRui Paulo int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
510e28a4053SRui Paulo {
511e28a4053SRui Paulo 	u8 *pos, buf[128];
512e28a4053SRui Paulo 	int res;
513e28a4053SRui Paulo 
514325151a3SRui Paulo #ifdef CONFIG_TESTING_OPTIONS
515325151a3SRui Paulo 	if (wpa_auth->conf.own_ie_override_len) {
516325151a3SRui Paulo 		wpa_hexdump(MSG_DEBUG, "WPA: Forced own IE(s) for testing",
517325151a3SRui Paulo 			    wpa_auth->conf.own_ie_override,
518325151a3SRui Paulo 			    wpa_auth->conf.own_ie_override_len);
519325151a3SRui Paulo 		os_free(wpa_auth->wpa_ie);
520325151a3SRui Paulo 		wpa_auth->wpa_ie =
521325151a3SRui Paulo 			os_malloc(wpa_auth->conf.own_ie_override_len);
522325151a3SRui Paulo 		if (wpa_auth->wpa_ie == NULL)
523325151a3SRui Paulo 			return -1;
524325151a3SRui Paulo 		os_memcpy(wpa_auth->wpa_ie, wpa_auth->conf.own_ie_override,
525325151a3SRui Paulo 			  wpa_auth->conf.own_ie_override_len);
526325151a3SRui Paulo 		wpa_auth->wpa_ie_len = wpa_auth->conf.own_ie_override_len;
527325151a3SRui Paulo 		return 0;
528325151a3SRui Paulo 	}
529325151a3SRui Paulo #endif /* CONFIG_TESTING_OPTIONS */
530325151a3SRui Paulo 
531e28a4053SRui Paulo 	pos = buf;
532e28a4053SRui Paulo 
5335b9c547cSRui Paulo 	if (wpa_auth->conf.wpa == WPA_PROTO_OSEN) {
5345b9c547cSRui Paulo 		pos = wpa_write_osen(&wpa_auth->conf, pos);
5355b9c547cSRui Paulo 	}
536e28a4053SRui Paulo 	if (wpa_auth->conf.wpa & WPA_PROTO_RSN) {
537e28a4053SRui Paulo 		res = wpa_write_rsn_ie(&wpa_auth->conf,
538e28a4053SRui Paulo 				       pos, buf + sizeof(buf) - pos, NULL);
539e28a4053SRui Paulo 		if (res < 0)
540e28a4053SRui Paulo 			return res;
541e28a4053SRui Paulo 		pos += res;
542c1d255d3SCy Schubert 		res = wpa_write_rsnxe(&wpa_auth->conf, pos,
543c1d255d3SCy Schubert 				      buf + sizeof(buf) - pos);
544c1d255d3SCy Schubert 		if (res < 0)
545c1d255d3SCy Schubert 			return res;
546c1d255d3SCy Schubert 		pos += res;
547e28a4053SRui Paulo 	}
54885732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP
549f05cddf9SRui Paulo 	if (wpa_key_mgmt_ft(wpa_auth->conf.wpa_key_mgmt)) {
550e28a4053SRui Paulo 		res = wpa_write_mdie(&wpa_auth->conf, pos,
551e28a4053SRui Paulo 				     buf + sizeof(buf) - pos);
552e28a4053SRui Paulo 		if (res < 0)
553e28a4053SRui Paulo 			return res;
554e28a4053SRui Paulo 		pos += res;
555e28a4053SRui Paulo 	}
55685732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */
557e28a4053SRui Paulo 	if (wpa_auth->conf.wpa & WPA_PROTO_WPA) {
558e28a4053SRui Paulo 		res = wpa_write_wpa_ie(&wpa_auth->conf,
559e28a4053SRui Paulo 				       pos, buf + sizeof(buf) - pos);
560e28a4053SRui Paulo 		if (res < 0)
561e28a4053SRui Paulo 			return res;
562e28a4053SRui Paulo 		pos += res;
563e28a4053SRui Paulo 	}
564e28a4053SRui Paulo 
565e28a4053SRui Paulo 	os_free(wpa_auth->wpa_ie);
566e28a4053SRui Paulo 	wpa_auth->wpa_ie = os_malloc(pos - buf);
567e28a4053SRui Paulo 	if (wpa_auth->wpa_ie == NULL)
568e28a4053SRui Paulo 		return -1;
569e28a4053SRui Paulo 	os_memcpy(wpa_auth->wpa_ie, buf, pos - buf);
570e28a4053SRui Paulo 	wpa_auth->wpa_ie_len = pos - buf;
571e28a4053SRui Paulo 
572e28a4053SRui Paulo 	return 0;
573e28a4053SRui Paulo }
574e28a4053SRui Paulo 
575e28a4053SRui Paulo 
wpa_add_kde(u8 * pos,u32 kde,const u8 * data,size_t data_len,const u8 * data2,size_t data2_len)576e28a4053SRui Paulo u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len,
577e28a4053SRui Paulo 		 const u8 *data2, size_t data2_len)
578e28a4053SRui Paulo {
579e28a4053SRui Paulo 	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
580e28a4053SRui Paulo 	*pos++ = RSN_SELECTOR_LEN + data_len + data2_len;
581e28a4053SRui Paulo 	RSN_SELECTOR_PUT(pos, kde);
582e28a4053SRui Paulo 	pos += RSN_SELECTOR_LEN;
583e28a4053SRui Paulo 	os_memcpy(pos, data, data_len);
584e28a4053SRui Paulo 	pos += data_len;
585e28a4053SRui Paulo 	if (data2) {
586e28a4053SRui Paulo 		os_memcpy(pos, data2, data2_len);
587e28a4053SRui Paulo 		pos += data2_len;
588e28a4053SRui Paulo 	}
589e28a4053SRui Paulo 	return pos;
590e28a4053SRui Paulo }
591e28a4053SRui Paulo 
592e28a4053SRui Paulo 
593e28a4053SRui Paulo struct wpa_auth_okc_iter_data {
594e28a4053SRui Paulo 	struct rsn_pmksa_cache_entry *pmksa;
595e28a4053SRui Paulo 	const u8 *aa;
596e28a4053SRui Paulo 	const u8 *spa;
597e28a4053SRui Paulo 	const u8 *pmkid;
598e28a4053SRui Paulo };
599e28a4053SRui Paulo 
600e28a4053SRui Paulo 
wpa_auth_okc_iter(struct wpa_authenticator * a,void * ctx)601e28a4053SRui Paulo static int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx)
602e28a4053SRui Paulo {
603e28a4053SRui Paulo 	struct wpa_auth_okc_iter_data *data = ctx;
604e28a4053SRui Paulo 	data->pmksa = pmksa_cache_get_okc(a->pmksa, data->aa, data->spa,
605e28a4053SRui Paulo 					  data->pmkid);
606e28a4053SRui Paulo 	if (data->pmksa)
607e28a4053SRui Paulo 		return 1;
608e28a4053SRui Paulo 	return 0;
609e28a4053SRui Paulo }
610e28a4053SRui Paulo 
611e28a4053SRui Paulo 
612c1d255d3SCy Schubert enum wpa_validate_result
wpa_validate_wpa_ie(struct wpa_authenticator * wpa_auth,struct wpa_state_machine * sm,int freq,const u8 * wpa_ie,size_t wpa_ie_len,const u8 * rsnxe,size_t rsnxe_len,const u8 * mdie,size_t mdie_len,const u8 * owe_dh,size_t owe_dh_len,struct wpa_state_machine * assoc_sm)613c1d255d3SCy Schubert wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
6144bc52338SCy Schubert 		    struct wpa_state_machine *sm, int freq,
615e28a4053SRui Paulo 		    const u8 *wpa_ie, size_t wpa_ie_len,
616c1d255d3SCy Schubert 		    const u8 *rsnxe, size_t rsnxe_len,
61785732ac8SCy Schubert 		    const u8 *mdie, size_t mdie_len,
618*a90b9d01SCy Schubert 		    const u8 *owe_dh, size_t owe_dh_len,
619*a90b9d01SCy Schubert 		    struct wpa_state_machine *assoc_sm)
620e28a4053SRui Paulo {
621c1d255d3SCy Schubert 	struct wpa_auth_config *conf = &wpa_auth->conf;
622e28a4053SRui Paulo 	struct wpa_ie_data data;
623e28a4053SRui Paulo 	int ciphers, key_mgmt, res, version;
624e28a4053SRui Paulo 	u32 selector;
625e28a4053SRui Paulo 	size_t i;
626e28a4053SRui Paulo 	const u8 *pmkid = NULL;
627e28a4053SRui Paulo 
628e28a4053SRui Paulo 	if (wpa_auth == NULL || sm == NULL)
629e28a4053SRui Paulo 		return WPA_NOT_ENABLED;
630e28a4053SRui Paulo 
631e28a4053SRui Paulo 	if (wpa_ie == NULL || wpa_ie_len < 1)
632e28a4053SRui Paulo 		return WPA_INVALID_IE;
633e28a4053SRui Paulo 
634e28a4053SRui Paulo 	if (wpa_ie[0] == WLAN_EID_RSN)
635e28a4053SRui Paulo 		version = WPA_PROTO_RSN;
636e28a4053SRui Paulo 	else
637e28a4053SRui Paulo 		version = WPA_PROTO_WPA;
638e28a4053SRui Paulo 
639e28a4053SRui Paulo 	if (!(wpa_auth->conf.wpa & version)) {
640e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "Invalid WPA proto (%d) from " MACSTR,
641e28a4053SRui Paulo 			   version, MAC2STR(sm->addr));
642e28a4053SRui Paulo 		return WPA_INVALID_PROTO;
643e28a4053SRui Paulo 	}
644e28a4053SRui Paulo 
645e28a4053SRui Paulo 	if (version == WPA_PROTO_RSN) {
646e28a4053SRui Paulo 		res = wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, &data);
6474bc52338SCy Schubert 		if (!data.has_pairwise)
6484bc52338SCy Schubert 			data.pairwise_cipher = wpa_default_rsn_cipher(freq);
6494bc52338SCy Schubert 		if (!data.has_group)
6504bc52338SCy Schubert 			data.group_cipher = wpa_default_rsn_cipher(freq);
6514bc52338SCy Schubert 
6524bc52338SCy Schubert 		if (wpa_key_mgmt_ft(data.key_mgmt) && !mdie &&
6534bc52338SCy Schubert 		    !wpa_key_mgmt_only_ft(data.key_mgmt)) {
6544bc52338SCy Schubert 			/* Workaround for some HP and Epson printers that seem
6554bc52338SCy Schubert 			 * to incorrectly copy the FT-PSK + WPA-PSK AKMs from AP
6564bc52338SCy Schubert 			 * advertised RSNE to Association Request frame. */
6574bc52338SCy Schubert 			wpa_printf(MSG_DEBUG,
6584bc52338SCy Schubert 				   "RSN: FT set in RSNE AKM but MDE is missing from "
6594bc52338SCy Schubert 				   MACSTR
6604bc52338SCy Schubert 				   " - ignore FT AKM(s) because there's also a non-FT AKM",
6614bc52338SCy Schubert 				   MAC2STR(sm->addr));
6624bc52338SCy Schubert 			data.key_mgmt &= ~WPA_KEY_MGMT_FT;
6634bc52338SCy Schubert 		}
664e28a4053SRui Paulo 
665e28a4053SRui Paulo 		selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
666e28a4053SRui Paulo 		if (0) {
667e28a4053SRui Paulo 		}
6685b9c547cSRui Paulo 		else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
6695b9c547cSRui Paulo 			selector = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
6705b9c547cSRui Paulo 		else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
6715b9c547cSRui Paulo 			selector = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
67285732ac8SCy Schubert #ifdef CONFIG_FILS
67385732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP
67485732ac8SCy Schubert 		else if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384)
67585732ac8SCy Schubert 			selector = RSN_AUTH_KEY_MGMT_FT_FILS_SHA384;
67685732ac8SCy Schubert 		else if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256)
67785732ac8SCy Schubert 			selector = RSN_AUTH_KEY_MGMT_FT_FILS_SHA256;
67885732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */
67985732ac8SCy Schubert 		else if (data.key_mgmt & WPA_KEY_MGMT_FILS_SHA384)
68085732ac8SCy Schubert 			selector = RSN_AUTH_KEY_MGMT_FILS_SHA384;
68185732ac8SCy Schubert 		else if (data.key_mgmt & WPA_KEY_MGMT_FILS_SHA256)
68285732ac8SCy Schubert 			selector = RSN_AUTH_KEY_MGMT_FILS_SHA256;
68385732ac8SCy Schubert #endif /* CONFIG_FILS */
68485732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP
68585732ac8SCy Schubert #ifdef CONFIG_SHA384
68685732ac8SCy Schubert 		else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384)
68785732ac8SCy Schubert 			selector = RSN_AUTH_KEY_MGMT_FT_802_1X_SHA384;
68885732ac8SCy Schubert #endif /* CONFIG_SHA384 */
689e28a4053SRui Paulo 		else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
690e28a4053SRui Paulo 			selector = RSN_AUTH_KEY_MGMT_FT_802_1X;
691e28a4053SRui Paulo 		else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK)
692e28a4053SRui Paulo 			selector = RSN_AUTH_KEY_MGMT_FT_PSK;
69385732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */
694e28a4053SRui Paulo 		else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
695e28a4053SRui Paulo 			selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
696e28a4053SRui Paulo 		else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
697e28a4053SRui Paulo 			selector = RSN_AUTH_KEY_MGMT_PSK_SHA256;
698f05cddf9SRui Paulo #ifdef CONFIG_SAE
699f05cddf9SRui Paulo 		else if (data.key_mgmt & WPA_KEY_MGMT_SAE)
700f05cddf9SRui Paulo 			selector = RSN_AUTH_KEY_MGMT_SAE;
701*a90b9d01SCy Schubert 		else if (data.key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY)
702*a90b9d01SCy Schubert 			selector = RSN_AUTH_KEY_MGMT_SAE_EXT_KEY;
703f05cddf9SRui Paulo 		else if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE)
704f05cddf9SRui Paulo 			selector = RSN_AUTH_KEY_MGMT_FT_SAE;
705*a90b9d01SCy Schubert 		else if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY)
706*a90b9d01SCy Schubert 			selector = RSN_AUTH_KEY_MGMT_FT_SAE_EXT_KEY;
707f05cddf9SRui Paulo #endif /* CONFIG_SAE */
708e28a4053SRui Paulo 		else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X)
709e28a4053SRui Paulo 			selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
710e28a4053SRui Paulo 		else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
711e28a4053SRui Paulo 			selector = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
71285732ac8SCy Schubert #ifdef CONFIG_OWE
71385732ac8SCy Schubert 		else if (data.key_mgmt & WPA_KEY_MGMT_OWE)
71485732ac8SCy Schubert 			selector = RSN_AUTH_KEY_MGMT_OWE;
71585732ac8SCy Schubert #endif /* CONFIG_OWE */
71685732ac8SCy Schubert #ifdef CONFIG_DPP
71785732ac8SCy Schubert 		else if (data.key_mgmt & WPA_KEY_MGMT_DPP)
71885732ac8SCy Schubert 			selector = RSN_AUTH_KEY_MGMT_DPP;
71985732ac8SCy Schubert #endif /* CONFIG_DPP */
72085732ac8SCy Schubert #ifdef CONFIG_HS20
72185732ac8SCy Schubert 		else if (data.key_mgmt & WPA_KEY_MGMT_OSEN)
72285732ac8SCy Schubert 			selector = RSN_AUTH_KEY_MGMT_OSEN;
72385732ac8SCy Schubert #endif /* CONFIG_HS20 */
724*a90b9d01SCy Schubert #ifdef CONFIG_SHA384
725*a90b9d01SCy Schubert 		else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA384)
726*a90b9d01SCy Schubert 			selector = RSN_AUTH_KEY_MGMT_802_1X_SHA384;
727*a90b9d01SCy Schubert #endif /* CONFIG_SHA384 */
728e28a4053SRui Paulo 		wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
729e28a4053SRui Paulo 
730f05cddf9SRui Paulo 		selector = wpa_cipher_to_suite(WPA_PROTO_RSN,
731f05cddf9SRui Paulo 					       data.pairwise_cipher);
732f05cddf9SRui Paulo 		if (!selector)
733e28a4053SRui Paulo 			selector = RSN_CIPHER_SUITE_CCMP;
734e28a4053SRui Paulo 		wpa_auth->dot11RSNAPairwiseCipherSelected = selector;
735e28a4053SRui Paulo 
736f05cddf9SRui Paulo 		selector = wpa_cipher_to_suite(WPA_PROTO_RSN,
737f05cddf9SRui Paulo 					       data.group_cipher);
738f05cddf9SRui Paulo 		if (!selector)
739e28a4053SRui Paulo 			selector = RSN_CIPHER_SUITE_CCMP;
740e28a4053SRui Paulo 		wpa_auth->dot11RSNAGroupCipherSelected = selector;
741e28a4053SRui Paulo 	} else {
742e28a4053SRui Paulo 		res = wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, &data);
743e28a4053SRui Paulo 
744e28a4053SRui Paulo 		selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X;
745e28a4053SRui Paulo 		if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X)
746e28a4053SRui Paulo 			selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X;
747e28a4053SRui Paulo 		else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
748e28a4053SRui Paulo 			selector = WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X;
749e28a4053SRui Paulo 		wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
750e28a4053SRui Paulo 
751f05cddf9SRui Paulo 		selector = wpa_cipher_to_suite(WPA_PROTO_WPA,
752f05cddf9SRui Paulo 					       data.pairwise_cipher);
753f05cddf9SRui Paulo 		if (!selector)
754f05cddf9SRui Paulo 			selector = RSN_CIPHER_SUITE_TKIP;
755e28a4053SRui Paulo 		wpa_auth->dot11RSNAPairwiseCipherSelected = selector;
756e28a4053SRui Paulo 
757f05cddf9SRui Paulo 		selector = wpa_cipher_to_suite(WPA_PROTO_WPA,
758f05cddf9SRui Paulo 					       data.group_cipher);
759f05cddf9SRui Paulo 		if (!selector)
760e28a4053SRui Paulo 			selector = WPA_CIPHER_SUITE_TKIP;
761e28a4053SRui Paulo 		wpa_auth->dot11RSNAGroupCipherSelected = selector;
762e28a4053SRui Paulo 	}
763e28a4053SRui Paulo 	if (res) {
764e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "Failed to parse WPA/RSN IE from "
765e28a4053SRui Paulo 			   MACSTR " (res=%d)", MAC2STR(sm->addr), res);
766e28a4053SRui Paulo 		wpa_hexdump(MSG_DEBUG, "WPA/RSN IE", wpa_ie, wpa_ie_len);
767e28a4053SRui Paulo 		return WPA_INVALID_IE;
768e28a4053SRui Paulo 	}
769e28a4053SRui Paulo 
770e28a4053SRui Paulo 	if (data.group_cipher != wpa_auth->conf.wpa_group) {
771e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "Invalid WPA group cipher (0x%x) from "
772e28a4053SRui Paulo 			   MACSTR, data.group_cipher, MAC2STR(sm->addr));
773e28a4053SRui Paulo 		return WPA_INVALID_GROUP;
774e28a4053SRui Paulo 	}
775e28a4053SRui Paulo 
776e28a4053SRui Paulo 	key_mgmt = data.key_mgmt & wpa_auth->conf.wpa_key_mgmt;
777e28a4053SRui Paulo 	if (!key_mgmt) {
778e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "Invalid WPA key mgmt (0x%x) from "
779e28a4053SRui Paulo 			   MACSTR, data.key_mgmt, MAC2STR(sm->addr));
780e28a4053SRui Paulo 		return WPA_INVALID_AKMP;
781e28a4053SRui Paulo 	}
782e28a4053SRui Paulo 	if (0) {
783e28a4053SRui Paulo 	}
7845b9c547cSRui Paulo 	else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
7855b9c547cSRui Paulo 		sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
7865b9c547cSRui Paulo 	else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
7875b9c547cSRui Paulo 		sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B;
78885732ac8SCy Schubert #ifdef CONFIG_FILS
78985732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP
79085732ac8SCy Schubert 	else if (key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384)
79185732ac8SCy Schubert 		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA384;
79285732ac8SCy Schubert 	else if (data.key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256)
79385732ac8SCy Schubert 		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA256;
79485732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */
79585732ac8SCy Schubert 	else if (key_mgmt & WPA_KEY_MGMT_FILS_SHA384)
79685732ac8SCy Schubert 		sm->wpa_key_mgmt = WPA_KEY_MGMT_FILS_SHA384;
79785732ac8SCy Schubert 	else if (key_mgmt & WPA_KEY_MGMT_FILS_SHA256)
79885732ac8SCy Schubert 		sm->wpa_key_mgmt = WPA_KEY_MGMT_FILS_SHA256;
79985732ac8SCy Schubert #endif /* CONFIG_FILS */
80085732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP
80185732ac8SCy Schubert #ifdef CONFIG_SHA384
80285732ac8SCy Schubert 	else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384)
80385732ac8SCy Schubert 		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
80485732ac8SCy Schubert #endif /* CONFIG_SHA384 */
805e28a4053SRui Paulo 	else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
806e28a4053SRui Paulo 		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
807e28a4053SRui Paulo 	else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
808e28a4053SRui Paulo 		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK;
80985732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */
810*a90b9d01SCy Schubert #ifdef CONFIG_SHA384
811*a90b9d01SCy Schubert 	else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA384)
812*a90b9d01SCy Schubert 		sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA384;
813*a90b9d01SCy Schubert #endif /* CONFIG_SHA384 */
814e28a4053SRui Paulo 	else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
815e28a4053SRui Paulo 		sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
816e28a4053SRui Paulo 	else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
817e28a4053SRui Paulo 		sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
818f05cddf9SRui Paulo #ifdef CONFIG_SAE
819f05cddf9SRui Paulo 	else if (key_mgmt & WPA_KEY_MGMT_SAE)
820f05cddf9SRui Paulo 		sm->wpa_key_mgmt = WPA_KEY_MGMT_SAE;
821*a90b9d01SCy Schubert 	else if (key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY)
822*a90b9d01SCy Schubert 		sm->wpa_key_mgmt = WPA_KEY_MGMT_SAE_EXT_KEY;
823f05cddf9SRui Paulo 	else if (key_mgmt & WPA_KEY_MGMT_FT_SAE)
824f05cddf9SRui Paulo 		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_SAE;
825*a90b9d01SCy Schubert 	else if (key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY)
826*a90b9d01SCy Schubert 		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_SAE_EXT_KEY;
827f05cddf9SRui Paulo #endif /* CONFIG_SAE */
828e28a4053SRui Paulo 	else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X)
829e28a4053SRui Paulo 		sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
83085732ac8SCy Schubert #ifdef CONFIG_OWE
83185732ac8SCy Schubert 	else if (key_mgmt & WPA_KEY_MGMT_OWE)
83285732ac8SCy Schubert 		sm->wpa_key_mgmt = WPA_KEY_MGMT_OWE;
83385732ac8SCy Schubert #endif /* CONFIG_OWE */
83485732ac8SCy Schubert #ifdef CONFIG_DPP
83585732ac8SCy Schubert 	else if (key_mgmt & WPA_KEY_MGMT_DPP)
83685732ac8SCy Schubert 		sm->wpa_key_mgmt = WPA_KEY_MGMT_DPP;
83785732ac8SCy Schubert #endif /* CONFIG_DPP */
83885732ac8SCy Schubert #ifdef CONFIG_HS20
83985732ac8SCy Schubert 	else if (key_mgmt & WPA_KEY_MGMT_OSEN)
84085732ac8SCy Schubert 		sm->wpa_key_mgmt = WPA_KEY_MGMT_OSEN;
84185732ac8SCy Schubert #endif /* CONFIG_HS20 */
842e28a4053SRui Paulo 	else
843e28a4053SRui Paulo 		sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
844e28a4053SRui Paulo 
845e28a4053SRui Paulo 	if (version == WPA_PROTO_RSN)
846e28a4053SRui Paulo 		ciphers = data.pairwise_cipher & wpa_auth->conf.rsn_pairwise;
847e28a4053SRui Paulo 	else
848e28a4053SRui Paulo 		ciphers = data.pairwise_cipher & wpa_auth->conf.wpa_pairwise;
849e28a4053SRui Paulo 	if (!ciphers) {
850e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "Invalid %s pairwise cipher (0x%x) "
851e28a4053SRui Paulo 			   "from " MACSTR,
852e28a4053SRui Paulo 			   version == WPA_PROTO_RSN ? "RSN" : "WPA",
853e28a4053SRui Paulo 			   data.pairwise_cipher, MAC2STR(sm->addr));
854e28a4053SRui Paulo 		return WPA_INVALID_PAIRWISE;
855e28a4053SRui Paulo 	}
856e28a4053SRui Paulo 
857e28a4053SRui Paulo 	if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) {
858e28a4053SRui Paulo 		if (!(data.capabilities & WPA_CAPABILITY_MFPC)) {
859e28a4053SRui Paulo 			wpa_printf(MSG_DEBUG, "Management frame protection "
860e28a4053SRui Paulo 				   "required, but client did not enable it");
861e28a4053SRui Paulo 			return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
862e28a4053SRui Paulo 		}
863e28a4053SRui Paulo 
8645b9c547cSRui Paulo 		if (data.mgmt_group_cipher != wpa_auth->conf.group_mgmt_cipher)
8655b9c547cSRui Paulo 		{
866e28a4053SRui Paulo 			wpa_printf(MSG_DEBUG, "Unsupported management group "
867e28a4053SRui Paulo 				   "cipher %d", data.mgmt_group_cipher);
868e28a4053SRui Paulo 			return WPA_INVALID_MGMT_GROUP_CIPHER;
869e28a4053SRui Paulo 		}
870e28a4053SRui Paulo 	}
871e28a4053SRui Paulo 
87285732ac8SCy Schubert #ifdef CONFIG_SAE
87385732ac8SCy Schubert 	if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_OPTIONAL &&
87485732ac8SCy Schubert 	    wpa_auth->conf.sae_require_mfp &&
87585732ac8SCy Schubert 	    wpa_key_mgmt_sae(sm->wpa_key_mgmt) &&
87685732ac8SCy Schubert 	    !(data.capabilities & WPA_CAPABILITY_MFPC)) {
87785732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
87885732ac8SCy Schubert 			   "Management frame protection required with SAE, but client did not enable it");
87985732ac8SCy Schubert 		return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
88085732ac8SCy Schubert 	}
88185732ac8SCy Schubert #endif /* CONFIG_SAE */
88285732ac8SCy Schubert 
8834bc52338SCy Schubert #ifdef CONFIG_OCV
884c1d255d3SCy Schubert 	if (wpa_auth->conf.ocv && (data.capabilities & WPA_CAPABILITY_OCVC) &&
8854bc52338SCy Schubert 	    !(data.capabilities & WPA_CAPABILITY_MFPC)) {
886c1d255d3SCy Schubert 		/* Some legacy MFP incapable STAs wrongly copy OCVC bit from
887c1d255d3SCy Schubert 		 * AP RSN capabilities. To improve interoperability with such
888c1d255d3SCy Schubert 		 * legacy STAs allow connection without enabling OCV when the
889c1d255d3SCy Schubert 		 * workaround mode (ocv=2) is enabled.
890c1d255d3SCy Schubert 		 */
891c1d255d3SCy Schubert 		if (wpa_auth->conf.ocv == 2) {
892c1d255d3SCy Schubert 			wpa_printf(MSG_DEBUG,
893c1d255d3SCy Schubert 				   "Allow connecting MFP incapable and OCV capable STA without enabling OCV");
894c1d255d3SCy Schubert 			wpa_auth_set_ocv(sm, 0);
895c1d255d3SCy Schubert 		} else {
8964bc52338SCy Schubert 			wpa_printf(MSG_DEBUG,
8974bc52338SCy Schubert 				   "Management frame protection required with OCV, but client did not enable it");
8984bc52338SCy Schubert 			return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
8994bc52338SCy Schubert 		}
900c1d255d3SCy Schubert 	} else {
901c1d255d3SCy Schubert 		wpa_auth_set_ocv(sm, (data.capabilities & WPA_CAPABILITY_OCVC) ?
902c1d255d3SCy Schubert 				 wpa_auth->conf.ocv : 0);
903c1d255d3SCy Schubert 	}
9044bc52338SCy Schubert #endif /* CONFIG_OCV */
9054bc52338SCy Schubert 
906e28a4053SRui Paulo 	if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION ||
907e28a4053SRui Paulo 	    !(data.capabilities & WPA_CAPABILITY_MFPC))
908e28a4053SRui Paulo 		sm->mgmt_frame_prot = 0;
909e28a4053SRui Paulo 	else
910e28a4053SRui Paulo 		sm->mgmt_frame_prot = 1;
911*a90b9d01SCy Schubert 	sm->mfpr = !!(data.capabilities & WPA_CAPABILITY_MFPR);
91285732ac8SCy Schubert 
91385732ac8SCy Schubert 	if (sm->mgmt_frame_prot && (ciphers & WPA_CIPHER_TKIP)) {
91485732ac8SCy Schubert 		    wpa_printf(MSG_DEBUG,
91585732ac8SCy Schubert 			       "Management frame protection cannot use TKIP");
91685732ac8SCy Schubert 		    return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
91785732ac8SCy Schubert 	}
918e28a4053SRui Paulo 
91985732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP
920e28a4053SRui Paulo 	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
921e28a4053SRui Paulo 		if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) {
922e28a4053SRui Paulo 			wpa_printf(MSG_DEBUG, "RSN: Trying to use FT, but "
923e28a4053SRui Paulo 				   "MDIE not included");
924e28a4053SRui Paulo 			return WPA_INVALID_MDIE;
925e28a4053SRui Paulo 		}
926e28a4053SRui Paulo 		if (os_memcmp(mdie, wpa_auth->conf.mobility_domain,
927e28a4053SRui Paulo 			      MOBILITY_DOMAIN_ID_LEN) != 0) {
928e28a4053SRui Paulo 			wpa_hexdump(MSG_DEBUG, "RSN: Attempted to use unknown "
929e28a4053SRui Paulo 				    "MDIE", mdie, MOBILITY_DOMAIN_ID_LEN);
930e28a4053SRui Paulo 			return WPA_INVALID_MDIE;
931e28a4053SRui Paulo 		}
93285732ac8SCy Schubert 	} else if (mdie != NULL) {
93385732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
93485732ac8SCy Schubert 			   "RSN: Trying to use non-FT AKM suite, but MDIE included");
93585732ac8SCy Schubert 		return WPA_INVALID_AKMP;
936e28a4053SRui Paulo 	}
93785732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */
93885732ac8SCy Schubert 
93985732ac8SCy Schubert #ifdef CONFIG_OWE
94085732ac8SCy Schubert 	if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE && !owe_dh) {
94185732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
94285732ac8SCy Schubert 			   "OWE: No Diffie-Hellman Parameter element");
94385732ac8SCy Schubert 		return WPA_INVALID_AKMP;
94485732ac8SCy Schubert 	}
94585732ac8SCy Schubert #endif /* CONFIG_OWE */
946e28a4053SRui Paulo 
947c1d255d3SCy Schubert #ifdef CONFIG_DPP2
948c1d255d3SCy Schubert 	if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP &&
949c1d255d3SCy Schubert 	    ((conf->dpp_pfs == 1 && !owe_dh) ||
950c1d255d3SCy Schubert 	     (conf->dpp_pfs == 2 && owe_dh))) {
951c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "DPP: PFS %s",
952c1d255d3SCy Schubert 			   conf->dpp_pfs == 1 ? "required" : "not allowed");
953c1d255d3SCy Schubert 		return WPA_DENIED_OTHER_REASON;
954c1d255d3SCy Schubert 	}
955c1d255d3SCy Schubert #endif /* CONFIG_DPP2 */
956c1d255d3SCy Schubert 
9575b9c547cSRui Paulo 	sm->pairwise = wpa_pick_pairwise_cipher(ciphers, 0);
9585b9c547cSRui Paulo 	if (sm->pairwise < 0)
9595b9c547cSRui Paulo 		return WPA_INVALID_PAIRWISE;
960e28a4053SRui Paulo 
961e28a4053SRui Paulo 	/* TODO: clear WPA/WPA2 state if STA changes from one to another */
962e28a4053SRui Paulo 	if (wpa_ie[0] == WLAN_EID_RSN)
963e28a4053SRui Paulo 		sm->wpa = WPA_VERSION_WPA2;
964e28a4053SRui Paulo 	else
965e28a4053SRui Paulo 		sm->wpa = WPA_VERSION_WPA;
966e28a4053SRui Paulo 
967*a90b9d01SCy Schubert 	if (assoc_sm) {
968*a90b9d01SCy Schubert 		/* For ML association link STA cannot choose a different
969*a90b9d01SCy Schubert 		 * AKM or pairwise cipher from association STA */
970*a90b9d01SCy Schubert 		if (sm->wpa_key_mgmt != assoc_sm->wpa_key_mgmt)
971*a90b9d01SCy Schubert 			return WPA_INVALID_AKMP;
972*a90b9d01SCy Schubert 		if (sm->pairwise != assoc_sm->pairwise)
973*a90b9d01SCy Schubert 			return WPA_INVALID_PAIRWISE;
974*a90b9d01SCy Schubert 	}
975*a90b9d01SCy Schubert 
9764bc52338SCy Schubert #if defined(CONFIG_IEEE80211R_AP) && defined(CONFIG_FILS)
9774bc52338SCy Schubert 	if ((sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA256 ||
9784bc52338SCy Schubert 	     sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_FILS_SHA384) &&
9794bc52338SCy Schubert 	    (sm->auth_alg == WLAN_AUTH_FILS_SK ||
9804bc52338SCy Schubert 	     sm->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
9814bc52338SCy Schubert 	     sm->auth_alg == WLAN_AUTH_FILS_PK) &&
9824bc52338SCy Schubert 	    (data.num_pmkid != 1 || !data.pmkid || !sm->pmk_r1_name_valid ||
9834bc52338SCy Schubert 	     os_memcmp_const(data.pmkid, sm->pmk_r1_name,
9844bc52338SCy Schubert 			     WPA_PMK_NAME_LEN) != 0)) {
9854bc52338SCy Schubert 		wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
9864bc52338SCy Schubert 				 "No PMKR1Name match for FILS+FT");
9874bc52338SCy Schubert 		return WPA_INVALID_PMKID;
9884bc52338SCy Schubert 	}
9894bc52338SCy Schubert #endif /* CONFIG_IEEE80211R_AP && CONFIG_FILS */
9904bc52338SCy Schubert 
991e28a4053SRui Paulo 	sm->pmksa = NULL;
992e28a4053SRui Paulo 	for (i = 0; i < data.num_pmkid; i++) {
993e28a4053SRui Paulo 		wpa_hexdump(MSG_DEBUG, "RSN IE: STA PMKID",
994e28a4053SRui Paulo 			    &data.pmkid[i * PMKID_LEN], PMKID_LEN);
995e28a4053SRui Paulo 		sm->pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sm->addr,
996e28a4053SRui Paulo 						 &data.pmkid[i * PMKID_LEN]);
997e28a4053SRui Paulo 		if (sm->pmksa) {
998e28a4053SRui Paulo 			pmkid = sm->pmksa->pmkid;
999e28a4053SRui Paulo 			break;
1000e28a4053SRui Paulo 		}
1001e28a4053SRui Paulo 	}
1002e28a4053SRui Paulo 	for (i = 0; sm->pmksa == NULL && wpa_auth->conf.okc &&
1003e28a4053SRui Paulo 		     i < data.num_pmkid; i++) {
1004e28a4053SRui Paulo 		struct wpa_auth_okc_iter_data idata;
1005e28a4053SRui Paulo 		idata.pmksa = NULL;
1006e28a4053SRui Paulo 		idata.aa = wpa_auth->addr;
1007e28a4053SRui Paulo 		idata.spa = sm->addr;
1008e28a4053SRui Paulo 		idata.pmkid = &data.pmkid[i * PMKID_LEN];
1009e28a4053SRui Paulo 		wpa_auth_for_each_auth(wpa_auth, wpa_auth_okc_iter, &idata);
1010e28a4053SRui Paulo 		if (idata.pmksa) {
1011e28a4053SRui Paulo 			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
1012e28a4053SRui Paulo 					 "OKC match for PMKID");
1013e28a4053SRui Paulo 			sm->pmksa = pmksa_cache_add_okc(wpa_auth->pmksa,
1014e28a4053SRui Paulo 							idata.pmksa,
1015e28a4053SRui Paulo 							wpa_auth->addr,
1016e28a4053SRui Paulo 							idata.pmkid);
1017e28a4053SRui Paulo 			pmkid = idata.pmkid;
1018e28a4053SRui Paulo 			break;
1019e28a4053SRui Paulo 		}
1020e28a4053SRui Paulo 	}
10215b9c547cSRui Paulo 	if (sm->pmksa && pmkid) {
1022780fb4a2SCy Schubert 		struct vlan_description *vlan;
1023780fb4a2SCy Schubert 
1024780fb4a2SCy Schubert 		vlan = sm->pmksa->vlan_desc;
1025e28a4053SRui Paulo 		wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
1026780fb4a2SCy Schubert 				 "PMKID found from PMKSA cache eap_type=%d vlan=%d%s",
1027e28a4053SRui Paulo 				 sm->pmksa->eap_type_authsrv,
1028780fb4a2SCy Schubert 				 vlan ? vlan->untagged : 0,
1029780fb4a2SCy Schubert 				 (vlan && vlan->tagged[0]) ? "+" : "");
1030e28a4053SRui Paulo 		os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmkid, PMKID_LEN);
1031e28a4053SRui Paulo 	}
1032e28a4053SRui Paulo 
103385732ac8SCy Schubert #ifdef CONFIG_SAE
1034*a90b9d01SCy Schubert 	if (sm->wpa_key_mgmt == WPA_KEY_MGMT_SAE ||
1035*a90b9d01SCy Schubert 	    sm->wpa_key_mgmt == WPA_KEY_MGMT_SAE_EXT_KEY) {
1036*a90b9d01SCy Schubert 		u64 drv_flags = 0;
1037*a90b9d01SCy Schubert 		u64 drv_flags2 = 0;
1038*a90b9d01SCy Schubert 		bool ap_sae_offload = false;
1039*a90b9d01SCy Schubert 
1040*a90b9d01SCy Schubert 		if (wpa_auth->cb->get_drv_flags &&
1041*a90b9d01SCy Schubert 		    wpa_auth->cb->get_drv_flags(wpa_auth->cb_ctx, &drv_flags,
1042*a90b9d01SCy Schubert 						&drv_flags2) == 0)
1043*a90b9d01SCy Schubert 			ap_sae_offload =
1044*a90b9d01SCy Schubert 				!!(drv_flags2 &
1045*a90b9d01SCy Schubert 				   WPA_DRIVER_FLAGS2_SAE_OFFLOAD_AP);
1046*a90b9d01SCy Schubert 
1047*a90b9d01SCy Schubert 		if (!ap_sae_offload && data.num_pmkid && !sm->pmksa) {
104885732ac8SCy Schubert 			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
104985732ac8SCy Schubert 					 "No PMKSA cache entry found for SAE");
105085732ac8SCy Schubert 			return WPA_INVALID_PMKID;
105185732ac8SCy Schubert 		}
1052*a90b9d01SCy Schubert 	}
105385732ac8SCy Schubert #endif /* CONFIG_SAE */
105485732ac8SCy Schubert 
105585732ac8SCy Schubert #ifdef CONFIG_DPP
105685732ac8SCy Schubert 	if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && !sm->pmksa) {
105785732ac8SCy Schubert 		wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
105885732ac8SCy Schubert 				 "No PMKSA cache entry found for DPP");
105985732ac8SCy Schubert 		return WPA_INVALID_PMKID;
106085732ac8SCy Schubert 	}
106185732ac8SCy Schubert #endif /* CONFIG_DPP */
106285732ac8SCy Schubert 
1063c1d255d3SCy Schubert 	if (conf->extended_key_id && sm->wpa == WPA_VERSION_WPA2 &&
1064c1d255d3SCy Schubert 	    sm->pairwise != WPA_CIPHER_TKIP &&
1065c1d255d3SCy Schubert 	    (data.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST)) {
1066c1d255d3SCy Schubert 		sm->use_ext_key_id = true;
1067c1d255d3SCy Schubert 		if (conf->extended_key_id == 2 &&
1068c1d255d3SCy Schubert 		    !wpa_key_mgmt_ft(sm->wpa_key_mgmt) &&
1069c1d255d3SCy Schubert 		    !wpa_key_mgmt_fils(sm->wpa_key_mgmt))
1070c1d255d3SCy Schubert 			sm->keyidx_active = 1;
1071c1d255d3SCy Schubert 		else
1072c1d255d3SCy Schubert 			sm->keyidx_active = 0;
1073c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
1074c1d255d3SCy Schubert 			   "RSN: Extended Key ID supported (start with %d)",
1075c1d255d3SCy Schubert 			   sm->keyidx_active);
1076c1d255d3SCy Schubert 	} else {
1077c1d255d3SCy Schubert 		sm->use_ext_key_id = false;
1078c1d255d3SCy Schubert 	}
1079c1d255d3SCy Schubert 
1080e28a4053SRui Paulo 	if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) {
1081e28a4053SRui Paulo 		os_free(sm->wpa_ie);
1082e28a4053SRui Paulo 		sm->wpa_ie = os_malloc(wpa_ie_len);
1083e28a4053SRui Paulo 		if (sm->wpa_ie == NULL)
1084e28a4053SRui Paulo 			return WPA_ALLOC_FAIL;
1085e28a4053SRui Paulo 	}
1086e28a4053SRui Paulo 	os_memcpy(sm->wpa_ie, wpa_ie, wpa_ie_len);
1087e28a4053SRui Paulo 	sm->wpa_ie_len = wpa_ie_len;
1088e28a4053SRui Paulo 
1089c1d255d3SCy Schubert 	if (rsnxe && rsnxe_len) {
1090c1d255d3SCy Schubert 		if (!sm->rsnxe || sm->rsnxe_len < rsnxe_len) {
1091c1d255d3SCy Schubert 			os_free(sm->rsnxe);
1092c1d255d3SCy Schubert 			sm->rsnxe = os_malloc(rsnxe_len);
1093c1d255d3SCy Schubert 			if (!sm->rsnxe)
1094c1d255d3SCy Schubert 				return WPA_ALLOC_FAIL;
1095c1d255d3SCy Schubert 		}
1096c1d255d3SCy Schubert 		os_memcpy(sm->rsnxe, rsnxe, rsnxe_len);
1097c1d255d3SCy Schubert 		sm->rsnxe_len = rsnxe_len;
1098c1d255d3SCy Schubert 	} else {
1099c1d255d3SCy Schubert 		os_free(sm->rsnxe);
1100c1d255d3SCy Schubert 		sm->rsnxe = NULL;
1101c1d255d3SCy Schubert 		sm->rsnxe_len = 0;
1102c1d255d3SCy Schubert 	}
1103c1d255d3SCy Schubert 
1104e28a4053SRui Paulo 	return WPA_IE_OK;
1105e28a4053SRui Paulo }
1106e28a4053SRui Paulo 
1107e28a4053SRui Paulo 
11085b9c547cSRui Paulo #ifdef CONFIG_HS20
wpa_validate_osen(struct wpa_authenticator * wpa_auth,struct wpa_state_machine * sm,const u8 * osen_ie,size_t osen_ie_len)11095b9c547cSRui Paulo int wpa_validate_osen(struct wpa_authenticator *wpa_auth,
11105b9c547cSRui Paulo 		      struct wpa_state_machine *sm,
11115b9c547cSRui Paulo 		      const u8 *osen_ie, size_t osen_ie_len)
11125b9c547cSRui Paulo {
11135b9c547cSRui Paulo 	if (wpa_auth == NULL || sm == NULL)
11145b9c547cSRui Paulo 		return -1;
11155b9c547cSRui Paulo 
11165b9c547cSRui Paulo 	/* TODO: parse OSEN element */
11175b9c547cSRui Paulo 	sm->wpa_key_mgmt = WPA_KEY_MGMT_OSEN;
11185b9c547cSRui Paulo 	sm->mgmt_frame_prot = 1;
11195b9c547cSRui Paulo 	sm->pairwise = WPA_CIPHER_CCMP;
11205b9c547cSRui Paulo 	sm->wpa = WPA_VERSION_WPA2;
11215b9c547cSRui Paulo 
11225b9c547cSRui Paulo 	if (sm->wpa_ie == NULL || sm->wpa_ie_len < osen_ie_len) {
11235b9c547cSRui Paulo 		os_free(sm->wpa_ie);
11245b9c547cSRui Paulo 		sm->wpa_ie = os_malloc(osen_ie_len);
11255b9c547cSRui Paulo 		if (sm->wpa_ie == NULL)
11265b9c547cSRui Paulo 			return -1;
11275b9c547cSRui Paulo 	}
11285b9c547cSRui Paulo 
11295b9c547cSRui Paulo 	os_memcpy(sm->wpa_ie, osen_ie, osen_ie_len);
11305b9c547cSRui Paulo 	sm->wpa_ie_len = osen_ie_len;
11315b9c547cSRui Paulo 
11325b9c547cSRui Paulo 	return 0;
11335b9c547cSRui Paulo }
11345b9c547cSRui Paulo 
11355b9c547cSRui Paulo #endif /* CONFIG_HS20 */
11365b9c547cSRui Paulo 
11375b9c547cSRui Paulo 
wpa_auth_uses_mfp(struct wpa_state_machine * sm)1138e28a4053SRui Paulo int wpa_auth_uses_mfp(struct wpa_state_machine *sm)
1139e28a4053SRui Paulo {
1140e28a4053SRui Paulo 	return sm ? sm->mgmt_frame_prot : 0;
1141e28a4053SRui Paulo }
114285732ac8SCy Schubert 
114385732ac8SCy Schubert 
11444bc52338SCy Schubert #ifdef CONFIG_OCV
11454bc52338SCy Schubert 
wpa_auth_set_ocv(struct wpa_state_machine * sm,int ocv)11464bc52338SCy Schubert void wpa_auth_set_ocv(struct wpa_state_machine *sm, int ocv)
11474bc52338SCy Schubert {
11484bc52338SCy Schubert 	if (sm)
11494bc52338SCy Schubert 		sm->ocv_enabled = ocv;
11504bc52338SCy Schubert }
11514bc52338SCy Schubert 
11524bc52338SCy Schubert 
wpa_auth_uses_ocv(struct wpa_state_machine * sm)11534bc52338SCy Schubert int wpa_auth_uses_ocv(struct wpa_state_machine *sm)
11544bc52338SCy Schubert {
11554bc52338SCy Schubert 	return sm ? sm->ocv_enabled : 0;
11564bc52338SCy Schubert }
11574bc52338SCy Schubert 
11584bc52338SCy Schubert #endif /* CONFIG_OCV */
11594bc52338SCy Schubert 
11604bc52338SCy Schubert 
116185732ac8SCy Schubert #ifdef CONFIG_OWE
wpa_auth_write_assoc_resp_owe(struct wpa_state_machine * sm,u8 * pos,size_t max_len,const u8 * req_ies,size_t req_ies_len)116285732ac8SCy Schubert u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm,
116385732ac8SCy Schubert 				   u8 *pos, size_t max_len,
116485732ac8SCy Schubert 				   const u8 *req_ies, size_t req_ies_len)
116585732ac8SCy Schubert {
116685732ac8SCy Schubert 	int res;
116785732ac8SCy Schubert 	struct wpa_auth_config *conf;
116885732ac8SCy Schubert 
116985732ac8SCy Schubert 	if (!sm)
117085732ac8SCy Schubert 		return pos;
117185732ac8SCy Schubert 	conf = &sm->wpa_auth->conf;
117285732ac8SCy Schubert 
117385732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
117485732ac8SCy Schubert 	if (conf->own_ie_override_len) {
117585732ac8SCy Schubert 		if (max_len < conf->own_ie_override_len)
117685732ac8SCy Schubert 			return NULL;
117785732ac8SCy Schubert 		wpa_hexdump(MSG_DEBUG, "WPA: Forced own IE(s) for testing",
117885732ac8SCy Schubert 			    conf->own_ie_override, conf->own_ie_override_len);
117985732ac8SCy Schubert 		os_memcpy(pos, conf->own_ie_override,
118085732ac8SCy Schubert 			  conf->own_ie_override_len);
118185732ac8SCy Schubert 		return pos + conf->own_ie_override_len;
118285732ac8SCy Schubert 	}
118385732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
118485732ac8SCy Schubert 
118585732ac8SCy Schubert 	res = wpa_write_rsn_ie(conf, pos, max_len,
118685732ac8SCy Schubert 			       sm->pmksa ? sm->pmksa->pmkid : NULL);
118785732ac8SCy Schubert 	if (res < 0)
118885732ac8SCy Schubert 		return pos;
118985732ac8SCy Schubert 	return pos + res;
119085732ac8SCy Schubert }
119185732ac8SCy Schubert #endif /* CONFIG_OWE */
1192206b73d0SCy Schubert 
1193206b73d0SCy Schubert 
1194206b73d0SCy Schubert #ifdef CONFIG_FILS
1195c1d255d3SCy Schubert 
wpa_auth_write_assoc_resp_fils(struct wpa_state_machine * sm,u8 * pos,size_t max_len,const u8 * req_ies,size_t req_ies_len)1196206b73d0SCy Schubert u8 * wpa_auth_write_assoc_resp_fils(struct wpa_state_machine *sm,
1197206b73d0SCy Schubert 				    u8 *pos, size_t max_len,
1198206b73d0SCy Schubert 				    const u8 *req_ies, size_t req_ies_len)
1199206b73d0SCy Schubert {
1200206b73d0SCy Schubert 	int res;
1201206b73d0SCy Schubert 
1202206b73d0SCy Schubert 	if (!sm ||
1203206b73d0SCy Schubert 	    sm->wpa_key_mgmt & (WPA_KEY_MGMT_FT_FILS_SHA256 |
1204206b73d0SCy Schubert 				WPA_KEY_MGMT_FT_FILS_SHA384))
1205206b73d0SCy Schubert 		return pos;
1206206b73d0SCy Schubert 
1207206b73d0SCy Schubert 	res = wpa_write_rsn_ie(&sm->wpa_auth->conf, pos, max_len, NULL);
1208206b73d0SCy Schubert 	if (res < 0)
1209206b73d0SCy Schubert 		return pos;
1210206b73d0SCy Schubert 	return pos + res;
1211206b73d0SCy Schubert }
1212c1d255d3SCy Schubert 
1213c1d255d3SCy Schubert 
wpa_auth_write_fd_rsn_info(struct wpa_authenticator * wpa_auth,u8 * fd_rsn_info)1214c1d255d3SCy Schubert bool wpa_auth_write_fd_rsn_info(struct wpa_authenticator *wpa_auth,
1215c1d255d3SCy Schubert 				u8 *fd_rsn_info)
1216c1d255d3SCy Schubert {
1217c1d255d3SCy Schubert 	struct wpa_auth_config *conf;
1218c1d255d3SCy Schubert 	u32 selectors = 0;
1219c1d255d3SCy Schubert 	u8 *pos = fd_rsn_info;
1220c1d255d3SCy Schubert 	int i, res;
1221c1d255d3SCy Schubert 	u32 cipher, suite, selector, mask;
1222c1d255d3SCy Schubert 	u8 tmp[10 * RSN_SELECTOR_LEN];
1223c1d255d3SCy Schubert 
1224c1d255d3SCy Schubert 	if (!wpa_auth)
1225c1d255d3SCy Schubert 		return false;
1226c1d255d3SCy Schubert 	conf = &wpa_auth->conf;
1227c1d255d3SCy Schubert 
1228c1d255d3SCy Schubert 	if (!(conf->wpa & WPA_PROTO_RSN))
1229c1d255d3SCy Schubert 		return false;
1230c1d255d3SCy Schubert 
1231c1d255d3SCy Schubert 	/* RSN Capability (B0..B15) */
1232c1d255d3SCy Schubert 	WPA_PUT_LE16(pos, wpa_own_rsn_capab(conf));
1233c1d255d3SCy Schubert 	pos += 2;
1234c1d255d3SCy Schubert 
1235c1d255d3SCy Schubert 	/* Group Data Cipher Suite Selector (B16..B21) */
1236c1d255d3SCy Schubert 	suite = wpa_cipher_to_suite(WPA_PROTO_RSN, conf->wpa_group);
1237c1d255d3SCy Schubert 	if (suite == RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED)
1238c1d255d3SCy Schubert 		cipher = 63; /* No cipher suite selected */
1239c1d255d3SCy Schubert 	else if ((suite >> 8) == 0x000fac && ((suite & 0xff) <= 13))
1240c1d255d3SCy Schubert 		cipher = suite & 0xff;
1241c1d255d3SCy Schubert 	else
1242c1d255d3SCy Schubert 		cipher = 62; /* vendor specific */
1243c1d255d3SCy Schubert 	selectors |= cipher;
1244c1d255d3SCy Schubert 
1245c1d255d3SCy Schubert 	/* Group Management Cipher Suite Selector (B22..B27) */
1246c1d255d3SCy Schubert 	cipher = 63; /* Default to no cipher suite selected */
1247c1d255d3SCy Schubert 	if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
1248c1d255d3SCy Schubert 		switch (conf->group_mgmt_cipher) {
1249c1d255d3SCy Schubert 		case WPA_CIPHER_AES_128_CMAC:
1250c1d255d3SCy Schubert 			cipher = RSN_CIPHER_SUITE_AES_128_CMAC & 0xff;
1251c1d255d3SCy Schubert 			break;
1252c1d255d3SCy Schubert 		case WPA_CIPHER_BIP_GMAC_128:
1253c1d255d3SCy Schubert 			cipher = RSN_CIPHER_SUITE_BIP_GMAC_128 & 0xff;
1254c1d255d3SCy Schubert 			break;
1255c1d255d3SCy Schubert 		case WPA_CIPHER_BIP_GMAC_256:
1256c1d255d3SCy Schubert 			cipher = RSN_CIPHER_SUITE_BIP_GMAC_256 & 0xff;
1257c1d255d3SCy Schubert 			break;
1258c1d255d3SCy Schubert 		case WPA_CIPHER_BIP_CMAC_256:
1259c1d255d3SCy Schubert 			cipher = RSN_CIPHER_SUITE_BIP_CMAC_256 & 0xff;
1260c1d255d3SCy Schubert 			break;
1261c1d255d3SCy Schubert 		}
1262c1d255d3SCy Schubert 	}
1263c1d255d3SCy Schubert 	selectors |= cipher << 6;
1264c1d255d3SCy Schubert 
1265c1d255d3SCy Schubert 	/* Pairwise Cipher Suite Selector (B28..B33) */
1266c1d255d3SCy Schubert 	cipher = 63; /* Default to no cipher suite selected */
1267c1d255d3SCy Schubert 	res = rsn_cipher_put_suites(tmp, conf->rsn_pairwise);
1268c1d255d3SCy Schubert 	if (res == 1 && tmp[0] == 0x00 && tmp[1] == 0x0f && tmp[2] == 0xac &&
1269c1d255d3SCy Schubert 	    tmp[3] <= 13)
1270c1d255d3SCy Schubert 		cipher = tmp[3];
1271c1d255d3SCy Schubert 	selectors |= cipher << 12;
1272c1d255d3SCy Schubert 
1273c1d255d3SCy Schubert 	/* AKM Suite Selector (B34..B39) */
1274c1d255d3SCy Schubert 	selector = 0; /* default to AKM from RSNE in Beacon/Probe Response */
1275c1d255d3SCy Schubert 	mask = WPA_KEY_MGMT_FILS_SHA256 | WPA_KEY_MGMT_FILS_SHA384 |
1276c1d255d3SCy Schubert 		WPA_KEY_MGMT_FT_FILS_SHA384;
1277c1d255d3SCy Schubert 	if ((conf->wpa_key_mgmt & mask) && (conf->wpa_key_mgmt & ~mask) == 0) {
1278c1d255d3SCy Schubert 		suite = conf->wpa_key_mgmt & mask;
1279c1d255d3SCy Schubert 		if (suite == WPA_KEY_MGMT_FILS_SHA256)
1280c1d255d3SCy Schubert 			selector = 1; /* 00-0f-ac:14 */
1281c1d255d3SCy Schubert 		else if (suite == WPA_KEY_MGMT_FILS_SHA384)
1282c1d255d3SCy Schubert 			selector = 2; /* 00-0f-ac:15 */
1283c1d255d3SCy Schubert 		else if (suite == (WPA_KEY_MGMT_FILS_SHA256 |
1284c1d255d3SCy Schubert 				   WPA_KEY_MGMT_FILS_SHA384))
1285c1d255d3SCy Schubert 			selector = 3; /* 00-0f-ac:14 or 00-0f-ac:15 */
1286c1d255d3SCy Schubert 		else if (suite == WPA_KEY_MGMT_FT_FILS_SHA384)
1287c1d255d3SCy Schubert 			selector = 4; /* 00-0f-ac:17 */
1288c1d255d3SCy Schubert 	}
1289c1d255d3SCy Schubert 	selectors |= selector << 18;
1290c1d255d3SCy Schubert 
1291c1d255d3SCy Schubert 	for (i = 0; i < 3; i++) {
1292c1d255d3SCy Schubert 		*pos++ = selectors & 0xff;
1293c1d255d3SCy Schubert 		selectors >>= 8;
1294c1d255d3SCy Schubert 	}
1295c1d255d3SCy Schubert 
1296c1d255d3SCy Schubert 	return true;
1297c1d255d3SCy Schubert }
1298c1d255d3SCy Schubert 
1299206b73d0SCy Schubert #endif /* CONFIG_FILS */
1300