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