xref: /freebsd/contrib/wpa/wpa_supplicant/pasn_supplicant.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
1c1d255d3SCy Schubert /*
2c1d255d3SCy Schubert  * wpa_supplicant - PASN processing
3c1d255d3SCy Schubert  *
4c1d255d3SCy Schubert  * Copyright (C) 2019 Intel Corporation
5c1d255d3SCy Schubert  *
6c1d255d3SCy Schubert  * This software may be distributed under the terms of the BSD license.
7c1d255d3SCy Schubert  * See README for more details.
8c1d255d3SCy Schubert  */
9c1d255d3SCy Schubert 
10c1d255d3SCy Schubert #include "includes.h"
11c1d255d3SCy Schubert 
12c1d255d3SCy Schubert #include "common/ieee802_11_defs.h"
13c1d255d3SCy Schubert #include "common/ieee802_11_common.h"
14c1d255d3SCy Schubert #include "common/dragonfly.h"
15c1d255d3SCy Schubert #include "common/ptksa_cache.h"
16c1d255d3SCy Schubert #include "utils/eloop.h"
17c1d255d3SCy Schubert #include "drivers/driver.h"
18c1d255d3SCy Schubert #include "crypto/crypto.h"
19c1d255d3SCy Schubert #include "crypto/random.h"
20c1d255d3SCy Schubert #include "eap_common/eap_defs.h"
21c1d255d3SCy Schubert #include "rsn_supp/wpa.h"
22c1d255d3SCy Schubert #include "rsn_supp/pmksa_cache.h"
23c1d255d3SCy Schubert #include "wpa_supplicant_i.h"
24c1d255d3SCy Schubert #include "driver_i.h"
25c1d255d3SCy Schubert #include "bss.h"
26*a90b9d01SCy Schubert #include "scan.h"
27c1d255d3SCy Schubert #include "config.h"
28c1d255d3SCy Schubert 
29c1d255d3SCy Schubert static const int dot11RSNAConfigPMKLifetime = 43200;
30c1d255d3SCy Schubert 
31c1d255d3SCy Schubert struct wpa_pasn_auth_work {
32*a90b9d01SCy Schubert 	u8 own_addr[ETH_ALEN];
33*a90b9d01SCy Schubert 	u8 peer_addr[ETH_ALEN];
34c1d255d3SCy Schubert 	int akmp;
35c1d255d3SCy Schubert 	int cipher;
36c1d255d3SCy Schubert 	u16 group;
37c1d255d3SCy Schubert 	int network_id;
38c1d255d3SCy Schubert 	struct wpabuf *comeback;
39c1d255d3SCy Schubert };
40c1d255d3SCy Schubert 
41c1d255d3SCy Schubert 
wpas_pasn_send_mlme(void * ctx,const u8 * data,size_t data_len,int noack,unsigned int freq,unsigned int wait)42*a90b9d01SCy Schubert static int wpas_pasn_send_mlme(void *ctx, const u8 *data, size_t data_len,
43*a90b9d01SCy Schubert 			       int noack, unsigned int freq, unsigned int wait)
44*a90b9d01SCy Schubert {
45*a90b9d01SCy Schubert 	struct wpa_supplicant *wpa_s = ctx;
46*a90b9d01SCy Schubert 
47*a90b9d01SCy Schubert 	return wpa_drv_send_mlme(wpa_s, data, data_len, noack, freq, wait);
48*a90b9d01SCy Schubert }
49*a90b9d01SCy Schubert 
50*a90b9d01SCy Schubert 
wpas_pasn_free_auth_work(struct wpa_pasn_auth_work * awork)51c1d255d3SCy Schubert static void wpas_pasn_free_auth_work(struct wpa_pasn_auth_work *awork)
52c1d255d3SCy Schubert {
53c1d255d3SCy Schubert 	wpabuf_free(awork->comeback);
54c1d255d3SCy Schubert 	awork->comeback = NULL;
55c1d255d3SCy Schubert 	os_free(awork);
56c1d255d3SCy Schubert }
57c1d255d3SCy Schubert 
58c1d255d3SCy Schubert 
wpas_pasn_auth_work_timeout(void * eloop_ctx,void * timeout_ctx)59c1d255d3SCy Schubert static void wpas_pasn_auth_work_timeout(void *eloop_ctx, void *timeout_ctx)
60c1d255d3SCy Schubert {
61c1d255d3SCy Schubert 	struct wpa_supplicant *wpa_s = eloop_ctx;
62c1d255d3SCy Schubert 
63c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "PASN: Auth work timeout - stopping auth");
64c1d255d3SCy Schubert 
65c1d255d3SCy Schubert 	wpas_pasn_auth_stop(wpa_s);
66*a90b9d01SCy Schubert 
67*a90b9d01SCy Schubert 	wpas_pasn_auth_work_done(wpa_s, PASN_STATUS_FAILURE);
68c1d255d3SCy Schubert }
69c1d255d3SCy Schubert 
70c1d255d3SCy Schubert 
wpas_pasn_cancel_auth_work(struct wpa_supplicant * wpa_s)71c1d255d3SCy Schubert static void wpas_pasn_cancel_auth_work(struct wpa_supplicant *wpa_s)
72c1d255d3SCy Schubert {
73c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "PASN: Cancel pasn-start-auth work");
74c1d255d3SCy Schubert 
75c1d255d3SCy Schubert 	/* Remove pending/started work */
76c1d255d3SCy Schubert 	radio_remove_works(wpa_s, "pasn-start-auth", 0);
77c1d255d3SCy Schubert }
78c1d255d3SCy Schubert 
79c1d255d3SCy Schubert 
wpas_pasn_auth_status(struct wpa_supplicant * wpa_s,const u8 * peer_addr,int akmp,int cipher,u8 status,struct wpabuf * comeback,u16 comeback_after)80*a90b9d01SCy Schubert static void wpas_pasn_auth_status(struct wpa_supplicant *wpa_s,
81*a90b9d01SCy Schubert 				  const u8 *peer_addr,
82c1d255d3SCy Schubert 				  int akmp, int cipher, u8 status,
83c1d255d3SCy Schubert 				  struct wpabuf *comeback,
84c1d255d3SCy Schubert 				  u16 comeback_after)
85c1d255d3SCy Schubert {
86c1d255d3SCy Schubert 	if (comeback) {
87c1d255d3SCy Schubert 		size_t comeback_len = wpabuf_len(comeback);
88c1d255d3SCy Schubert 		size_t buflen = comeback_len * 2 + 1;
89c1d255d3SCy Schubert 		char *comeback_txt = os_malloc(buflen);
90c1d255d3SCy Schubert 
91c1d255d3SCy Schubert 		if (comeback_txt) {
92c1d255d3SCy Schubert 			wpa_snprintf_hex(comeback_txt, buflen,
93c1d255d3SCy Schubert 					 wpabuf_head(comeback), comeback_len);
94c1d255d3SCy Schubert 
95c1d255d3SCy Schubert 			wpa_msg(wpa_s, MSG_INFO, PASN_AUTH_STATUS MACSTR
96c1d255d3SCy Schubert 				" akmp=%s, status=%u comeback_after=%u comeback=%s",
97*a90b9d01SCy Schubert 				MAC2STR(peer_addr),
98c1d255d3SCy Schubert 				wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN),
99c1d255d3SCy Schubert 				status, comeback_after, comeback_txt);
100c1d255d3SCy Schubert 
101c1d255d3SCy Schubert 			os_free(comeback_txt);
102c1d255d3SCy Schubert 			return;
103c1d255d3SCy Schubert 		}
104c1d255d3SCy Schubert 	}
105c1d255d3SCy Schubert 
106c1d255d3SCy Schubert 	wpa_msg(wpa_s, MSG_INFO,
107c1d255d3SCy Schubert 		PASN_AUTH_STATUS MACSTR " akmp=%s, status=%u",
108*a90b9d01SCy Schubert 		MAC2STR(peer_addr), wpa_key_mgmt_txt(akmp, WPA_PROTO_RSN),
109c1d255d3SCy Schubert 		status);
110c1d255d3SCy Schubert }
111c1d255d3SCy Schubert 
112c1d255d3SCy Schubert 
113c1d255d3SCy Schubert #ifdef CONFIG_SAE
114c1d255d3SCy Schubert 
115*a90b9d01SCy Schubert static struct sae_pt *
wpas_pasn_sae_derive_pt(struct wpa_ssid * ssid,int group)116*a90b9d01SCy Schubert wpas_pasn_sae_derive_pt(struct wpa_ssid *ssid, int group)
117c1d255d3SCy Schubert {
118c1d255d3SCy Schubert 	const char *password = ssid->sae_password;
119c1d255d3SCy Schubert 	int groups[2] = { group, 0 };
120c1d255d3SCy Schubert 
121c1d255d3SCy Schubert 	if (!password)
122c1d255d3SCy Schubert 		password = ssid->passphrase;
123c1d255d3SCy Schubert 
124c1d255d3SCy Schubert 	if (!password) {
125c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: SAE without a password");
126*a90b9d01SCy Schubert 		return NULL;
127*a90b9d01SCy Schubert 	}
128*a90b9d01SCy Schubert 
129*a90b9d01SCy Schubert 	return sae_derive_pt(groups, ssid->ssid, ssid->ssid_len,
130*a90b9d01SCy Schubert 			    (const u8 *) password, os_strlen(password),
131*a90b9d01SCy Schubert 			    ssid->sae_password_id);
132*a90b9d01SCy Schubert }
133*a90b9d01SCy Schubert 
134*a90b9d01SCy Schubert 
wpas_pasn_sae_setup_pt(struct wpa_ssid * ssid,int group)135*a90b9d01SCy Schubert static int wpas_pasn_sae_setup_pt(struct wpa_ssid *ssid, int group)
136*a90b9d01SCy Schubert {
137*a90b9d01SCy Schubert 	if (!ssid->sae_password && !ssid->passphrase) {
138*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: SAE without a password");
139c1d255d3SCy Schubert 		return -1;
140c1d255d3SCy Schubert 	}
141c1d255d3SCy Schubert 
142c1d255d3SCy Schubert 	if (ssid->pt)
143c1d255d3SCy Schubert 		return 0; /* PT already derived */
144c1d255d3SCy Schubert 
145*a90b9d01SCy Schubert 	ssid->pt = wpas_pasn_sae_derive_pt(ssid, group);
146c1d255d3SCy Schubert 
147c1d255d3SCy Schubert 	return ssid->pt ? 0 : -1;
148c1d255d3SCy Schubert }
149c1d255d3SCy Schubert 
150c1d255d3SCy Schubert #endif /* CONFIG_SAE */
151c1d255d3SCy Schubert 
152c1d255d3SCy Schubert 
wpas_pasn_get_params_from_bss(struct wpa_supplicant * wpa_s,struct pasn_peer * peer)153*a90b9d01SCy Schubert static int wpas_pasn_get_params_from_bss(struct wpa_supplicant *wpa_s,
154*a90b9d01SCy Schubert 					 struct pasn_peer *peer)
155c1d255d3SCy Schubert {
156c1d255d3SCy Schubert 	int ret;
157*a90b9d01SCy Schubert 	const u8 *rsne, *rsnxe;
158c1d255d3SCy Schubert 	struct wpa_bss *bss;
159c1d255d3SCy Schubert 	struct wpa_ie_data rsne_data;
160*a90b9d01SCy Schubert 	int sel, key_mgmt, pairwise_cipher;
161*a90b9d01SCy Schubert 	int network_id = 0, group = 19;
162*a90b9d01SCy Schubert 	struct wpa_ssid *ssid = NULL;
163*a90b9d01SCy Schubert 	size_t ssid_str_len = 0;
164*a90b9d01SCy Schubert 	const u8 *ssid_str = NULL;
165*a90b9d01SCy Schubert 	const u8 *peer_addr = peer->peer_addr;
166c1d255d3SCy Schubert 
167*a90b9d01SCy Schubert 	bss = wpa_bss_get_bssid(wpa_s, peer_addr);
168*a90b9d01SCy Schubert 	if (!bss) {
169*a90b9d01SCy Schubert 		wpa_supplicant_update_scan_results(wpa_s, peer_addr);
170*a90b9d01SCy Schubert 		bss = wpa_bss_get_bssid(wpa_s, peer_addr);
171*a90b9d01SCy Schubert 		if (!bss) {
172*a90b9d01SCy Schubert 			wpa_printf(MSG_DEBUG, "PASN: BSS not found");
173c1d255d3SCy Schubert 			return -1;
174*a90b9d01SCy Schubert 		}
175*a90b9d01SCy Schubert 	}
176c1d255d3SCy Schubert 
177*a90b9d01SCy Schubert 	rsne = wpa_bss_get_ie(bss, WLAN_EID_RSN);
178*a90b9d01SCy Schubert 	if (!rsne) {
179*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: BSS without RSNE");
180c1d255d3SCy Schubert 		return -1;
181c1d255d3SCy Schubert 	}
182c1d255d3SCy Schubert 
183*a90b9d01SCy Schubert 	ret = wpa_parse_wpa_ie(rsne, *(rsne + 1) + 2, &rsne_data);
184*a90b9d01SCy Schubert 	if (ret) {
185*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: Failed parsing RSNE data");
186*a90b9d01SCy Schubert 		return -1;
187*a90b9d01SCy Schubert 	}
188c1d255d3SCy Schubert 
189*a90b9d01SCy Schubert 	rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
190c1d255d3SCy Schubert 
191*a90b9d01SCy Schubert 	ssid_str_len = bss->ssid_len;
192*a90b9d01SCy Schubert 	ssid_str = bss->ssid;
193*a90b9d01SCy Schubert 
194*a90b9d01SCy Schubert 	/* Get the network configuration based on the obtained SSID */
195*a90b9d01SCy Schubert 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
196*a90b9d01SCy Schubert 		if (!wpas_network_disabled(wpa_s, ssid) &&
197*a90b9d01SCy Schubert 		    ssid_str_len == ssid->ssid_len &&
198*a90b9d01SCy Schubert 		    os_memcmp(ssid_str, ssid->ssid, ssid_str_len) == 0)
199*a90b9d01SCy Schubert 			break;
200*a90b9d01SCy Schubert 	}
201*a90b9d01SCy Schubert 
202*a90b9d01SCy Schubert 	if (ssid)
203*a90b9d01SCy Schubert 		network_id = ssid->id;
204*a90b9d01SCy Schubert 
205*a90b9d01SCy Schubert 	sel = rsne_data.pairwise_cipher;
206*a90b9d01SCy Schubert 	if (ssid && ssid->pairwise_cipher)
207*a90b9d01SCy Schubert 		sel &= ssid->pairwise_cipher;
208*a90b9d01SCy Schubert 
209*a90b9d01SCy Schubert 	wpa_printf(MSG_DEBUG, "PASN: peer pairwise 0x%x, select 0x%x",
210*a90b9d01SCy Schubert 		   rsne_data.pairwise_cipher, sel);
211*a90b9d01SCy Schubert 
212*a90b9d01SCy Schubert 	pairwise_cipher = wpa_pick_pairwise_cipher(sel, 1);
213*a90b9d01SCy Schubert 	if (pairwise_cipher < 0) {
214*a90b9d01SCy Schubert 		wpa_msg(wpa_s, MSG_WARNING,
215*a90b9d01SCy Schubert 			"PASN: Failed to select pairwise cipher");
216*a90b9d01SCy Schubert 		return -1;
217*a90b9d01SCy Schubert 	}
218*a90b9d01SCy Schubert 
219*a90b9d01SCy Schubert 	sel = rsne_data.key_mgmt;
220*a90b9d01SCy Schubert 	if (ssid && ssid->key_mgmt)
221*a90b9d01SCy Schubert 		sel &= ssid->key_mgmt;
222*a90b9d01SCy Schubert 
223*a90b9d01SCy Schubert 	wpa_printf(MSG_DEBUG, "PASN: peer AKMP 0x%x, select 0x%x",
224*a90b9d01SCy Schubert 		   rsne_data.key_mgmt, sel);
225*a90b9d01SCy Schubert #ifdef CONFIG_SAE
226*a90b9d01SCy Schubert 	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE) || !ssid)
227*a90b9d01SCy Schubert 		sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_SAE_EXT_KEY |
228*a90b9d01SCy Schubert 			 WPA_KEY_MGMT_FT_SAE | WPA_KEY_MGMT_FT_SAE_EXT_KEY);
229*a90b9d01SCy Schubert #endif /* CONFIG_SAE */
230*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211R
231*a90b9d01SCy Schubert 	if (!(wpa_s->drv_flags & (WPA_DRIVER_FLAGS_SME |
232*a90b9d01SCy Schubert 				  WPA_DRIVER_FLAGS_UPDATE_FT_IES)))
233*a90b9d01SCy Schubert 		sel &= ~WPA_KEY_MGMT_FT;
234*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211R */
235*a90b9d01SCy Schubert 	if (0) {
236*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211R
237*a90b9d01SCy Schubert #ifdef CONFIG_SHA384
238*a90b9d01SCy Schubert 	} else if ((sel & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) &&
239*a90b9d01SCy Schubert 		   os_strcmp(wpa_supplicant_get_eap_mode(wpa_s), "LEAP") != 0) {
240*a90b9d01SCy Schubert 		key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
241*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT FT/802.1X-SHA384");
242*a90b9d01SCy Schubert 		if (ssid && !ssid->ft_eap_pmksa_caching &&
243*a90b9d01SCy Schubert 		    pmksa_cache_get_current(wpa_s->wpa)) {
244*a90b9d01SCy Schubert 			/* PMKSA caching with FT may have interoperability
245*a90b9d01SCy Schubert 			 * issues, so disable that case by default for now.
246*a90b9d01SCy Schubert 			 */
247c1d255d3SCy Schubert 			wpa_printf(MSG_DEBUG,
248*a90b9d01SCy Schubert 				   "PASN: Disable PMKSA caching for FT/802.1X connection");
249*a90b9d01SCy Schubert 			pmksa_cache_clear_current(wpa_s->wpa);
250c1d255d3SCy Schubert 		}
251*a90b9d01SCy Schubert #endif /* CONFIG_SHA384 */
252*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211R */
253*a90b9d01SCy Schubert #ifdef CONFIG_SAE
254*a90b9d01SCy Schubert 	} else if ((sel & WPA_KEY_MGMT_SAE_EXT_KEY) &&
255*a90b9d01SCy Schubert 		   (ieee802_11_rsnx_capab(rsnxe,
256*a90b9d01SCy Schubert 					   WLAN_RSNX_CAPAB_SAE_H2E)) &&
257*a90b9d01SCy Schubert 		   (wpas_pasn_sae_setup_pt(ssid, group) == 0)) {
258*a90b9d01SCy Schubert 		key_mgmt = WPA_KEY_MGMT_SAE_EXT_KEY;
259*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT SAE (ext key)");
260*a90b9d01SCy Schubert 	} else if ((sel & WPA_KEY_MGMT_SAE) &&
261*a90b9d01SCy Schubert 		   (ieee802_11_rsnx_capab(rsnxe,
262*a90b9d01SCy Schubert 					   WLAN_RSNX_CAPAB_SAE_H2E)) &&
263*a90b9d01SCy Schubert 		   (wpas_pasn_sae_setup_pt(ssid, group) == 0)) {
264*a90b9d01SCy Schubert 		key_mgmt = WPA_KEY_MGMT_SAE;
265*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT SAE");
266*a90b9d01SCy Schubert #endif /* CONFIG_SAE */
267*a90b9d01SCy Schubert #ifdef CONFIG_FILS
268*a90b9d01SCy Schubert 	} else if (sel & WPA_KEY_MGMT_FILS_SHA384) {
269*a90b9d01SCy Schubert 		key_mgmt = WPA_KEY_MGMT_FILS_SHA384;
270*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT FILS-SHA384");
271*a90b9d01SCy Schubert 	} else if (sel & WPA_KEY_MGMT_FILS_SHA256) {
272*a90b9d01SCy Schubert 		key_mgmt = WPA_KEY_MGMT_FILS_SHA256;
273*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT FILS-SHA256");
274*a90b9d01SCy Schubert #endif /* CONFIG_FILS */
275*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211R
276*a90b9d01SCy Schubert 	} else if ((sel & WPA_KEY_MGMT_FT_IEEE8021X) &&
277*a90b9d01SCy Schubert 		   os_strcmp(wpa_supplicant_get_eap_mode(wpa_s), "LEAP") != 0) {
278*a90b9d01SCy Schubert 		key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
279*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT FT/802.1X");
280*a90b9d01SCy Schubert 		if (ssid && !ssid->ft_eap_pmksa_caching &&
281*a90b9d01SCy Schubert 		    pmksa_cache_get_current(wpa_s->wpa)) {
282*a90b9d01SCy Schubert 			/* PMKSA caching with FT may have interoperability
283*a90b9d01SCy Schubert 			 * issues, so disable that case by default for now.
284*a90b9d01SCy Schubert 			 */
285c1d255d3SCy Schubert 			wpa_printf(MSG_DEBUG,
286*a90b9d01SCy Schubert 				   "PASN: Disable PMKSA caching for FT/802.1X connection");
287*a90b9d01SCy Schubert 			pmksa_cache_clear_current(wpa_s->wpa);
288*a90b9d01SCy Schubert 		}
289*a90b9d01SCy Schubert 	} else if (sel & WPA_KEY_MGMT_FT_PSK) {
290*a90b9d01SCy Schubert 		key_mgmt = WPA_KEY_MGMT_FT_PSK;
291*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT FT/PSK");
292*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211R */
293*a90b9d01SCy Schubert 	} else if (sel & WPA_KEY_MGMT_PASN) {
294*a90b9d01SCy Schubert 		key_mgmt = WPA_KEY_MGMT_PASN;
295*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: using KEY_MGMT PASN");
296*a90b9d01SCy Schubert 	} else {
297*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: invalid AKMP");
298c1d255d3SCy Schubert 		return -1;
299c1d255d3SCy Schubert 	}
300c1d255d3SCy Schubert 
301*a90b9d01SCy Schubert 	peer->akmp = key_mgmt;
302*a90b9d01SCy Schubert 	peer->cipher = pairwise_cipher;
303*a90b9d01SCy Schubert 	peer->network_id = network_id;
304*a90b9d01SCy Schubert 	peer->group = group;
305c1d255d3SCy Schubert 	return 0;
306c1d255d3SCy Schubert }
307c1d255d3SCy Schubert 
308c1d255d3SCy Schubert 
wpas_pasn_set_keys_from_cache(struct wpa_supplicant * wpa_s,const u8 * own_addr,const u8 * peer_addr,int cipher,int akmp)309*a90b9d01SCy Schubert static int wpas_pasn_set_keys_from_cache(struct wpa_supplicant *wpa_s,
310*a90b9d01SCy Schubert 					 const u8 *own_addr,
311*a90b9d01SCy Schubert 					 const u8 *peer_addr,
312*a90b9d01SCy Schubert 					 int cipher, int akmp)
313c1d255d3SCy Schubert {
314*a90b9d01SCy Schubert 	struct ptksa_cache_entry *entry;
315c1d255d3SCy Schubert 
316*a90b9d01SCy Schubert 	entry = ptksa_cache_get(wpa_s->ptksa, peer_addr, cipher);
317*a90b9d01SCy Schubert 	if (!entry) {
318*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: peer " MACSTR
319*a90b9d01SCy Schubert 			   " not present in PTKSA cache", MAC2STR(peer_addr));
320*a90b9d01SCy Schubert 		return -1;
321c1d255d3SCy Schubert 	}
322c1d255d3SCy Schubert 
323*a90b9d01SCy Schubert 	if (!ether_addr_equal(entry->own_addr, own_addr)) {
324c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
325*a90b9d01SCy Schubert 			   "PASN: own addr " MACSTR " and PTKSA entry own addr "
326*a90b9d01SCy Schubert 			   MACSTR " differ",
327*a90b9d01SCy Schubert 			   MAC2STR(own_addr), MAC2STR(entry->own_addr));
328*a90b9d01SCy Schubert 		return -1;
329c1d255d3SCy Schubert 	}
330c1d255d3SCy Schubert 
331*a90b9d01SCy Schubert 	wpa_printf(MSG_DEBUG, "PASN: " MACSTR " present in PTKSA cache",
332*a90b9d01SCy Schubert 		   MAC2STR(peer_addr));
333*a90b9d01SCy Schubert 	wpa_drv_set_secure_ranging_ctx(wpa_s, own_addr, peer_addr, cipher,
334*a90b9d01SCy Schubert 				       entry->ptk.tk_len,
335*a90b9d01SCy Schubert 				       entry->ptk.tk,
336*a90b9d01SCy Schubert 				       entry->ptk.ltf_keyseed_len,
337*a90b9d01SCy Schubert 				       entry->ptk.ltf_keyseed, 0);
338*a90b9d01SCy Schubert 	return 0;
339c1d255d3SCy Schubert }
340c1d255d3SCy Schubert 
341c1d255d3SCy Schubert 
wpas_pasn_configure_next_peer(struct wpa_supplicant * wpa_s,struct pasn_auth * pasn_params)342*a90b9d01SCy Schubert static void wpas_pasn_configure_next_peer(struct wpa_supplicant *wpa_s,
343*a90b9d01SCy Schubert 					  struct pasn_auth *pasn_params)
344c1d255d3SCy Schubert {
345*a90b9d01SCy Schubert 	struct pasn_peer *peer;
346*a90b9d01SCy Schubert 	u8 comeback_len = 0;
347*a90b9d01SCy Schubert 	const u8 *comeback = NULL;
348c1d255d3SCy Schubert 
349*a90b9d01SCy Schubert 	if (!pasn_params)
350*a90b9d01SCy Schubert 		return;
351c1d255d3SCy Schubert 
352*a90b9d01SCy Schubert 	while (wpa_s->pasn_count < pasn_params->num_peers) {
353*a90b9d01SCy Schubert 		peer = &pasn_params->peer[wpa_s->pasn_count];
354c1d255d3SCy Schubert 
355*a90b9d01SCy Schubert 		if (ether_addr_equal(wpa_s->bssid, peer->peer_addr)) {
356*a90b9d01SCy Schubert 			wpa_printf(MSG_DEBUG,
357*a90b9d01SCy Schubert 				   "PASN: Associated peer is not expected");
358*a90b9d01SCy Schubert 			peer->status = PASN_STATUS_FAILURE;
359*a90b9d01SCy Schubert 			wpa_s->pasn_count++;
360*a90b9d01SCy Schubert 			continue;
361c1d255d3SCy Schubert 		}
362c1d255d3SCy Schubert 
363*a90b9d01SCy Schubert 		if (wpas_pasn_set_keys_from_cache(wpa_s, peer->own_addr,
364*a90b9d01SCy Schubert 						  peer->peer_addr,
365*a90b9d01SCy Schubert 						  peer->cipher,
366*a90b9d01SCy Schubert 						  peer->akmp) == 0) {
367*a90b9d01SCy Schubert 			peer->status = PASN_STATUS_SUCCESS;
368*a90b9d01SCy Schubert 			wpa_s->pasn_count++;
369*a90b9d01SCy Schubert 			continue;
370c1d255d3SCy Schubert 		}
371c1d255d3SCy Schubert 
372*a90b9d01SCy Schubert 		if (wpas_pasn_get_params_from_bss(wpa_s, peer)) {
373*a90b9d01SCy Schubert 			peer->status = PASN_STATUS_FAILURE;
374*a90b9d01SCy Schubert 			wpa_s->pasn_count++;
375*a90b9d01SCy Schubert 			continue;
376c1d255d3SCy Schubert 		}
377c1d255d3SCy Schubert 
378*a90b9d01SCy Schubert 		if (wpas_pasn_auth_start(wpa_s, peer->own_addr,
379*a90b9d01SCy Schubert 					 peer->peer_addr, peer->akmp,
380*a90b9d01SCy Schubert 					 peer->cipher, peer->group,
381*a90b9d01SCy Schubert 					 peer->network_id,
382*a90b9d01SCy Schubert 					 comeback, comeback_len)) {
383*a90b9d01SCy Schubert 			peer->status = PASN_STATUS_FAILURE;
384*a90b9d01SCy Schubert 			wpa_s->pasn_count++;
385*a90b9d01SCy Schubert 			continue;
386*a90b9d01SCy Schubert 		}
387*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: Sent PASN auth start for " MACSTR,
388*a90b9d01SCy Schubert 			   MAC2STR(peer->peer_addr));
389*a90b9d01SCy Schubert 		return;
390*a90b9d01SCy Schubert 	}
391*a90b9d01SCy Schubert 
392*a90b9d01SCy Schubert 	if (wpa_s->pasn_count == pasn_params->num_peers) {
393*a90b9d01SCy Schubert 		wpa_drv_send_pasn_resp(wpa_s, pasn_params);
394*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: Response sent");
395*a90b9d01SCy Schubert 		os_free(wpa_s->pasn_params);
396*a90b9d01SCy Schubert 		wpa_s->pasn_params = NULL;
397*a90b9d01SCy Schubert 	}
398*a90b9d01SCy Schubert }
399*a90b9d01SCy Schubert 
400*a90b9d01SCy Schubert 
wpas_pasn_auth_work_done(struct wpa_supplicant * wpa_s,int status)401*a90b9d01SCy Schubert void wpas_pasn_auth_work_done(struct wpa_supplicant *wpa_s, int status)
402*a90b9d01SCy Schubert {
403*a90b9d01SCy Schubert 	if (!wpa_s->pasn_params)
404*a90b9d01SCy Schubert 		return;
405*a90b9d01SCy Schubert 
406*a90b9d01SCy Schubert 	wpa_s->pasn_params->peer[wpa_s->pasn_count].status = status;
407*a90b9d01SCy Schubert 	wpa_s->pasn_count++;
408*a90b9d01SCy Schubert 	wpas_pasn_configure_next_peer(wpa_s, wpa_s->pasn_params);
409*a90b9d01SCy Schubert }
410*a90b9d01SCy Schubert 
411*a90b9d01SCy Schubert 
wpas_pasn_delete_peers(struct wpa_supplicant * wpa_s,struct pasn_auth * pasn_params)412*a90b9d01SCy Schubert static void wpas_pasn_delete_peers(struct wpa_supplicant *wpa_s,
413*a90b9d01SCy Schubert 				   struct pasn_auth *pasn_params)
414*a90b9d01SCy Schubert {
415*a90b9d01SCy Schubert 	struct pasn_peer *peer;
416*a90b9d01SCy Schubert 	unsigned int i;
417*a90b9d01SCy Schubert 
418*a90b9d01SCy Schubert 	if (!pasn_params)
419*a90b9d01SCy Schubert 		return;
420*a90b9d01SCy Schubert 
421*a90b9d01SCy Schubert 	for (i = 0; i < pasn_params->num_peers; i++) {
422*a90b9d01SCy Schubert 		peer = &pasn_params->peer[i];
423*a90b9d01SCy Schubert 		ptksa_cache_flush(wpa_s->ptksa, peer->peer_addr,
424*a90b9d01SCy Schubert 				  WPA_CIPHER_NONE);
425*a90b9d01SCy Schubert 	}
426*a90b9d01SCy Schubert }
427*a90b9d01SCy Schubert 
428*a90b9d01SCy Schubert 
429*a90b9d01SCy Schubert #ifdef CONFIG_FILS
wpas_pasn_initiate_eapol(struct pasn_data * pasn,struct wpa_ssid * ssid)430*a90b9d01SCy Schubert static void wpas_pasn_initiate_eapol(struct pasn_data *pasn,
431*a90b9d01SCy Schubert 				     struct wpa_ssid *ssid)
432*a90b9d01SCy Schubert {
433*a90b9d01SCy Schubert 	struct eapol_config eapol_conf;
434*a90b9d01SCy Schubert 
435*a90b9d01SCy Schubert 	wpa_printf(MSG_DEBUG, "PASN: FILS: Initiating EAPOL");
436*a90b9d01SCy Schubert 
437*a90b9d01SCy Schubert 	eapol_sm_notify_eap_success(pasn->eapol, false);
438*a90b9d01SCy Schubert 	eapol_sm_notify_eap_fail(pasn->eapol, false);
439*a90b9d01SCy Schubert 	eapol_sm_notify_portControl(pasn->eapol, Auto);
440*a90b9d01SCy Schubert 
441*a90b9d01SCy Schubert 	os_memset(&eapol_conf, 0, sizeof(eapol_conf));
442*a90b9d01SCy Schubert 	eapol_conf.fast_reauth = pasn->fast_reauth;
443*a90b9d01SCy Schubert 	eapol_conf.workaround = ssid->eap_workaround;
444*a90b9d01SCy Schubert 
445*a90b9d01SCy Schubert 	eapol_sm_notify_config(pasn->eapol, &ssid->eap, &eapol_conf);
446*a90b9d01SCy Schubert }
447*a90b9d01SCy Schubert #endif /* CONFIG_FILS */
448*a90b9d01SCy Schubert 
449c1d255d3SCy Schubert 
wpas_pasn_reset(struct wpa_supplicant * wpa_s)450c1d255d3SCy Schubert static void wpas_pasn_reset(struct wpa_supplicant *wpa_s)
451c1d255d3SCy Schubert {
452*a90b9d01SCy Schubert 	struct pasn_data *pasn = &wpa_s->pasn;
453c1d255d3SCy Schubert 
454c1d255d3SCy Schubert 	wpas_pasn_cancel_auth_work(wpa_s);
455c1d255d3SCy Schubert 	wpa_s->pasn_auth_work = NULL;
456c1d255d3SCy Schubert 	eloop_cancel_timeout(wpas_pasn_auth_work_timeout, wpa_s, NULL);
457c1d255d3SCy Schubert 
458*a90b9d01SCy Schubert 	wpa_pasn_reset(pasn);
459c1d255d3SCy Schubert }
460c1d255d3SCy Schubert 
461c1d255d3SCy Schubert 
wpas_pasn_allowed(struct wpa_supplicant * wpa_s,const u8 * peer_addr,int akmp,int cipher)462c1d255d3SCy Schubert static struct wpa_bss * wpas_pasn_allowed(struct wpa_supplicant *wpa_s,
463*a90b9d01SCy Schubert 					  const u8 *peer_addr, int akmp,
464*a90b9d01SCy Schubert 					  int cipher)
465c1d255d3SCy Schubert {
466c1d255d3SCy Schubert 	struct wpa_bss *bss;
467c1d255d3SCy Schubert 	const u8 *rsne;
468c1d255d3SCy Schubert 	struct wpa_ie_data rsne_data;
469c1d255d3SCy Schubert 	int ret;
470c1d255d3SCy Schubert 
471*a90b9d01SCy Schubert 	if (ether_addr_equal(wpa_s->bssid, peer_addr)) {
472c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
473c1d255d3SCy Schubert 			   "PASN: Not doing authentication with current BSS");
474c1d255d3SCy Schubert 		return NULL;
475c1d255d3SCy Schubert 	}
476c1d255d3SCy Schubert 
477*a90b9d01SCy Schubert 	bss = wpa_bss_get_bssid_latest(wpa_s, peer_addr);
478c1d255d3SCy Schubert 	if (!bss) {
479c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: BSS not found");
480c1d255d3SCy Schubert 		return NULL;
481c1d255d3SCy Schubert 	}
482c1d255d3SCy Schubert 
483c1d255d3SCy Schubert 	rsne = wpa_bss_get_ie(bss, WLAN_EID_RSN);
484c1d255d3SCy Schubert 	if (!rsne) {
485c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: BSS without RSNE");
486c1d255d3SCy Schubert 		return NULL;
487c1d255d3SCy Schubert 	}
488c1d255d3SCy Schubert 
489c1d255d3SCy Schubert 	ret = wpa_parse_wpa_ie(rsne, *(rsne + 1) + 2, &rsne_data);
490c1d255d3SCy Schubert 	if (ret) {
491c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: Failed parsing RSNE data");
492c1d255d3SCy Schubert 		return NULL;
493c1d255d3SCy Schubert 	}
494c1d255d3SCy Schubert 
495c1d255d3SCy Schubert 	if (!(rsne_data.key_mgmt & akmp) ||
496c1d255d3SCy Schubert 	    !(rsne_data.pairwise_cipher & cipher)) {
497c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
498c1d255d3SCy Schubert 			   "PASN: AP does not support requested AKMP or cipher");
499c1d255d3SCy Schubert 		return NULL;
500c1d255d3SCy Schubert 	}
501c1d255d3SCy Schubert 
502c1d255d3SCy Schubert 	return bss;
503c1d255d3SCy Schubert }
504c1d255d3SCy Schubert 
505c1d255d3SCy Schubert 
wpas_pasn_auth_start_cb(struct wpa_radio_work * work,int deinit)506c1d255d3SCy Schubert static void wpas_pasn_auth_start_cb(struct wpa_radio_work *work, int deinit)
507c1d255d3SCy Schubert {
508c1d255d3SCy Schubert 	struct wpa_supplicant *wpa_s = work->wpa_s;
509c1d255d3SCy Schubert 	struct wpa_pasn_auth_work *awork = work->ctx;
510*a90b9d01SCy Schubert 	struct pasn_data *pasn = &wpa_s->pasn;
511*a90b9d01SCy Schubert 	struct wpa_ssid *ssid;
512c1d255d3SCy Schubert 	struct wpa_bss *bss;
513c1d255d3SCy Schubert 	const u8 *rsne, *rsnxe;
514*a90b9d01SCy Schubert #ifdef CONFIG_FILS
515*a90b9d01SCy Schubert 	const u8 *indic;
516*a90b9d01SCy Schubert 	u16 fils_info;
517*a90b9d01SCy Schubert #endif /* CONFIG_FILS */
518*a90b9d01SCy Schubert 	u16 capab = 0;
519*a90b9d01SCy Schubert 	bool derive_kdk;
520c1d255d3SCy Schubert 	int ret;
521c1d255d3SCy Schubert 
522c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "PASN: auth_start_cb: deinit=%d", deinit);
523c1d255d3SCy Schubert 
524c1d255d3SCy Schubert 	if (deinit) {
525c1d255d3SCy Schubert 		if (work->started) {
526c1d255d3SCy Schubert 			eloop_cancel_timeout(wpas_pasn_auth_work_timeout,
527c1d255d3SCy Schubert 					     wpa_s, NULL);
528c1d255d3SCy Schubert 			wpa_s->pasn_auth_work = NULL;
529c1d255d3SCy Schubert 		}
530c1d255d3SCy Schubert 
531c1d255d3SCy Schubert 		wpas_pasn_free_auth_work(awork);
532c1d255d3SCy Schubert 		return;
533c1d255d3SCy Schubert 	}
534c1d255d3SCy Schubert 
535c1d255d3SCy Schubert 	/*
536c1d255d3SCy Schubert 	 * It is possible that by the time the callback is called, the PASN
537c1d255d3SCy Schubert 	 * authentication is not allowed, e.g., a connection with the AP was
538c1d255d3SCy Schubert 	 * established.
539c1d255d3SCy Schubert 	 */
540*a90b9d01SCy Schubert 	bss = wpas_pasn_allowed(wpa_s, awork->peer_addr, awork->akmp,
541c1d255d3SCy Schubert 				awork->cipher);
542c1d255d3SCy Schubert 	if (!bss) {
543c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: auth_start_cb: Not allowed");
544c1d255d3SCy Schubert 		goto fail;
545c1d255d3SCy Schubert 	}
546c1d255d3SCy Schubert 
547c1d255d3SCy Schubert 	rsne = wpa_bss_get_ie(bss, WLAN_EID_RSN);
548c1d255d3SCy Schubert 	if (!rsne) {
549c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: BSS without RSNE");
550c1d255d3SCy Schubert 		goto fail;
551c1d255d3SCy Schubert 	}
552c1d255d3SCy Schubert 
553c1d255d3SCy Schubert 	rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
554c1d255d3SCy Schubert 
555*a90b9d01SCy Schubert 	derive_kdk = (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_STA) &&
556*a90b9d01SCy Schubert 		ieee802_11_rsnx_capab(rsnxe,
557*a90b9d01SCy Schubert 				      WLAN_RSNX_CAPAB_SECURE_LTF);
558*a90b9d01SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
559*a90b9d01SCy Schubert 	if (!derive_kdk)
560*a90b9d01SCy Schubert 		derive_kdk = wpa_s->conf->force_kdk_derivation;
561*a90b9d01SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
562*a90b9d01SCy Schubert 	if (derive_kdk)
563*a90b9d01SCy Schubert 		pasn_enable_kdk_derivation(pasn);
564*a90b9d01SCy Schubert 	else
565*a90b9d01SCy Schubert 		pasn_disable_kdk_derivation(pasn);
566*a90b9d01SCy Schubert 
567*a90b9d01SCy Schubert 	wpa_printf(MSG_DEBUG, "PASN: kdk_len=%zu", pasn->kdk_len);
568*a90b9d01SCy Schubert 
569*a90b9d01SCy Schubert 	if ((wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_STA) &&
570*a90b9d01SCy Schubert 	    ieee802_11_rsnx_capab(rsnxe, WLAN_RSNX_CAPAB_SECURE_LTF))
571*a90b9d01SCy Schubert 		pasn->secure_ltf = true;
572*a90b9d01SCy Schubert 	else
573*a90b9d01SCy Schubert 		pasn->secure_ltf = false;
574*a90b9d01SCy Schubert 
575*a90b9d01SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
576*a90b9d01SCy Schubert 	pasn->corrupt_mic = wpa_s->conf->pasn_corrupt_mic;
577*a90b9d01SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
578*a90b9d01SCy Schubert 
579*a90b9d01SCy Schubert 	capab |= BIT(WLAN_RSNX_CAPAB_SAE_H2E);
580*a90b9d01SCy Schubert 	if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_STA)
581*a90b9d01SCy Schubert 		capab |= BIT(WLAN_RSNX_CAPAB_SECURE_LTF);
582*a90b9d01SCy Schubert 	if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_RTT_STA)
583*a90b9d01SCy Schubert 		capab |= BIT(WLAN_RSNX_CAPAB_SECURE_RTT);
584*a90b9d01SCy Schubert 	if (wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_STA)
585*a90b9d01SCy Schubert 		capab |= BIT(WLAN_RSNX_CAPAB_URNM_MFPR);
586*a90b9d01SCy Schubert 	pasn_set_rsnxe_caps(pasn, capab);
587*a90b9d01SCy Schubert 	pasn_register_callbacks(pasn, wpa_s, wpas_pasn_send_mlme, NULL);
588*a90b9d01SCy Schubert 	ssid = wpa_config_get_network(wpa_s->conf, awork->network_id);
589*a90b9d01SCy Schubert 
590*a90b9d01SCy Schubert #ifdef CONFIG_SAE
591*a90b9d01SCy Schubert 	if (awork->akmp == WPA_KEY_MGMT_SAE) {
592*a90b9d01SCy Schubert 		if (!ssid) {
593*a90b9d01SCy Schubert 			wpa_printf(MSG_DEBUG,
594*a90b9d01SCy Schubert 				   "PASN: No network profile found for SAE");
595*a90b9d01SCy Schubert 			goto fail;
596*a90b9d01SCy Schubert 		}
597*a90b9d01SCy Schubert 		pasn_set_pt(pasn, wpas_pasn_sae_derive_pt(ssid, awork->group));
598*a90b9d01SCy Schubert 		if (!pasn->pt) {
599*a90b9d01SCy Schubert 			wpa_printf(MSG_DEBUG, "PASN: Failed to derive PT");
600*a90b9d01SCy Schubert 			goto fail;
601*a90b9d01SCy Schubert 		}
602*a90b9d01SCy Schubert 		pasn->network_id = ssid->id;
603*a90b9d01SCy Schubert 	}
604*a90b9d01SCy Schubert #endif /* CONFIG_SAE */
605*a90b9d01SCy Schubert 
606*a90b9d01SCy Schubert #ifdef CONFIG_FILS
607*a90b9d01SCy Schubert 	/* Prepare needed information for wpas_pasn_wd_fils_auth(). */
608*a90b9d01SCy Schubert 	if (awork->akmp == WPA_KEY_MGMT_FILS_SHA256 ||
609*a90b9d01SCy Schubert 	    awork->akmp == WPA_KEY_MGMT_FILS_SHA384) {
610*a90b9d01SCy Schubert 		indic = wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION);
611*a90b9d01SCy Schubert 		if (!ssid) {
612*a90b9d01SCy Schubert 			wpa_printf(MSG_DEBUG, "PASN: FILS: No network block");
613*a90b9d01SCy Schubert 		} else if (!indic || indic[1] < 2) {
614*a90b9d01SCy Schubert 			wpa_printf(MSG_DEBUG,
615*a90b9d01SCy Schubert 				   "PASN: Missing FILS Indication IE");
616*a90b9d01SCy Schubert 		} else {
617*a90b9d01SCy Schubert 			fils_info = WPA_GET_LE16(indic + 2);
618*a90b9d01SCy Schubert 			if ((fils_info & BIT(9)) && ssid) {
619*a90b9d01SCy Schubert 				pasn->eapol = wpa_s->eapol;
620*a90b9d01SCy Schubert 				pasn->network_id = ssid->id;
621*a90b9d01SCy Schubert 				wpas_pasn_initiate_eapol(pasn, ssid);
622*a90b9d01SCy Schubert 				pasn->fils_eapol = true;
623*a90b9d01SCy Schubert 			} else {
624*a90b9d01SCy Schubert 				wpa_printf(MSG_DEBUG,
625*a90b9d01SCy Schubert 					   "PASN: FILS auth without PFS not supported");
626*a90b9d01SCy Schubert 			}
627*a90b9d01SCy Schubert 		}
628*a90b9d01SCy Schubert 		pasn->fast_reauth = wpa_s->conf->fast_reauth;
629*a90b9d01SCy Schubert 	}
630*a90b9d01SCy Schubert #endif /* CONFIG_FILS */
631*a90b9d01SCy Schubert 
632*a90b9d01SCy Schubert 	pasn_set_initiator_pmksa(pasn, wpa_sm_get_pmksa_cache(wpa_s->wpa));
633*a90b9d01SCy Schubert 
634*a90b9d01SCy Schubert 	if (wpa_key_mgmt_ft(awork->akmp)) {
635*a90b9d01SCy Schubert #ifdef CONFIG_IEEE80211R
636*a90b9d01SCy Schubert 		ret = wpa_pasn_ft_derive_pmk_r1(wpa_s->wpa, awork->akmp,
637*a90b9d01SCy Schubert 						awork->peer_addr,
638*a90b9d01SCy Schubert 						pasn->pmk_r1,
639*a90b9d01SCy Schubert 						&pasn->pmk_r1_len,
640*a90b9d01SCy Schubert 						pasn->pmk_r1_name);
641*a90b9d01SCy Schubert 		if (ret) {
642*a90b9d01SCy Schubert 			wpa_printf(MSG_DEBUG,
643*a90b9d01SCy Schubert 				   "PASN: FT: Failed to derive keys");
644*a90b9d01SCy Schubert 			goto fail;
645*a90b9d01SCy Schubert 		}
646*a90b9d01SCy Schubert #else /* CONFIG_IEEE80211R */
647*a90b9d01SCy Schubert 		goto fail;
648*a90b9d01SCy Schubert #endif /* CONFIG_IEEE80211R */
649*a90b9d01SCy Schubert 	}
650*a90b9d01SCy Schubert 
651*a90b9d01SCy Schubert 
652*a90b9d01SCy Schubert 	ret = wpas_pasn_start(pasn, awork->own_addr, awork->peer_addr,
653*a90b9d01SCy Schubert 			      awork->peer_addr, awork->akmp, awork->cipher,
654c1d255d3SCy Schubert 			      awork->group, bss->freq, rsne, *(rsne + 1) + 2,
655c1d255d3SCy Schubert 			      rsnxe, rsnxe ? *(rsnxe + 1) + 2 : 0,
656*a90b9d01SCy Schubert 			      awork->comeback);
657c1d255d3SCy Schubert 	if (ret) {
658c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
659c1d255d3SCy Schubert 			   "PASN: Failed to start PASN authentication");
660c1d255d3SCy Schubert 		goto fail;
661c1d255d3SCy Schubert 	}
662*a90b9d01SCy Schubert 	eloop_register_timeout(2, 0, wpas_pasn_auth_work_timeout, wpa_s, NULL);
663c1d255d3SCy Schubert 
664c1d255d3SCy Schubert 	/* comeback token is no longer needed at this stage */
665c1d255d3SCy Schubert 	wpabuf_free(awork->comeback);
666c1d255d3SCy Schubert 	awork->comeback = NULL;
667c1d255d3SCy Schubert 
668c1d255d3SCy Schubert 	wpa_s->pasn_auth_work = work;
669c1d255d3SCy Schubert 	return;
670c1d255d3SCy Schubert fail:
671c1d255d3SCy Schubert 	wpas_pasn_free_auth_work(awork);
672c1d255d3SCy Schubert 	work->ctx = NULL;
673c1d255d3SCy Schubert 	radio_work_done(work);
674c1d255d3SCy Schubert }
675c1d255d3SCy Schubert 
676c1d255d3SCy Schubert 
wpas_pasn_auth_start(struct wpa_supplicant * wpa_s,const u8 * own_addr,const u8 * peer_addr,int akmp,int cipher,u16 group,int network_id,const u8 * comeback,size_t comeback_len)677*a90b9d01SCy Schubert int wpas_pasn_auth_start(struct wpa_supplicant *wpa_s,
678*a90b9d01SCy Schubert 			 const u8 *own_addr, const u8 *peer_addr,
679c1d255d3SCy Schubert 			 int akmp, int cipher, u16 group, int network_id,
680c1d255d3SCy Schubert 			 const u8 *comeback, size_t comeback_len)
681c1d255d3SCy Schubert {
682c1d255d3SCy Schubert 	struct wpa_pasn_auth_work *awork;
683c1d255d3SCy Schubert 	struct wpa_bss *bss;
684c1d255d3SCy Schubert 
685c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "PASN: Start: " MACSTR " akmp=0x%x, cipher=0x%x",
686*a90b9d01SCy Schubert 		   MAC2STR(peer_addr), akmp, cipher);
687c1d255d3SCy Schubert 
688c1d255d3SCy Schubert 	/*
689c1d255d3SCy Schubert 	 * TODO: Consider modifying the offchannel logic to handle additional
690c1d255d3SCy Schubert 	 * Management frames other then Action frames. For now allow PASN only
691c1d255d3SCy Schubert 	 * with drivers that support off-channel TX.
692c1d255d3SCy Schubert 	 */
693c1d255d3SCy Schubert 	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX)) {
694c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
695c1d255d3SCy Schubert 			   "PASN: Driver does not support offchannel TX");
696c1d255d3SCy Schubert 		return -1;
697c1d255d3SCy Schubert 	}
698c1d255d3SCy Schubert 
699c1d255d3SCy Schubert 	if (radio_work_pending(wpa_s, "pasn-start-auth")) {
700c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
701c1d255d3SCy Schubert 			   "PASN: send_auth: Work is already pending");
702c1d255d3SCy Schubert 		return -1;
703c1d255d3SCy Schubert 	}
704c1d255d3SCy Schubert 
705c1d255d3SCy Schubert 	if (wpa_s->pasn_auth_work) {
706c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: send_auth: Already in progress");
707c1d255d3SCy Schubert 		return -1;
708c1d255d3SCy Schubert 	}
709c1d255d3SCy Schubert 
710*a90b9d01SCy Schubert 	bss = wpas_pasn_allowed(wpa_s, peer_addr, akmp, cipher);
711c1d255d3SCy Schubert 	if (!bss)
712c1d255d3SCy Schubert 		return -1;
713c1d255d3SCy Schubert 
714c1d255d3SCy Schubert 	wpas_pasn_reset(wpa_s);
715c1d255d3SCy Schubert 
716c1d255d3SCy Schubert 	awork = os_zalloc(sizeof(*awork));
717c1d255d3SCy Schubert 	if (!awork)
718c1d255d3SCy Schubert 		return -1;
719c1d255d3SCy Schubert 
720*a90b9d01SCy Schubert 	os_memcpy(awork->own_addr, own_addr, ETH_ALEN);
721*a90b9d01SCy Schubert 	os_memcpy(awork->peer_addr, peer_addr, ETH_ALEN);
722c1d255d3SCy Schubert 	awork->akmp = akmp;
723c1d255d3SCy Schubert 	awork->cipher = cipher;
724c1d255d3SCy Schubert 	awork->group = group;
725c1d255d3SCy Schubert 	awork->network_id = network_id;
726c1d255d3SCy Schubert 
727c1d255d3SCy Schubert 	if (comeback && comeback_len) {
728c1d255d3SCy Schubert 		awork->comeback = wpabuf_alloc_copy(comeback, comeback_len);
729c1d255d3SCy Schubert 		if (!awork->comeback) {
730c1d255d3SCy Schubert 			wpas_pasn_free_auth_work(awork);
731c1d255d3SCy Schubert 			return -1;
732c1d255d3SCy Schubert 		}
733c1d255d3SCy Schubert 	}
734c1d255d3SCy Schubert 
735c1d255d3SCy Schubert 	if (radio_add_work(wpa_s, bss->freq, "pasn-start-auth", 1,
736c1d255d3SCy Schubert 			   wpas_pasn_auth_start_cb, awork) < 0) {
737c1d255d3SCy Schubert 		wpas_pasn_free_auth_work(awork);
738c1d255d3SCy Schubert 		return -1;
739c1d255d3SCy Schubert 	}
740c1d255d3SCy Schubert 
741c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "PASN: Auth work successfully added");
742c1d255d3SCy Schubert 	return 0;
743c1d255d3SCy Schubert }
744c1d255d3SCy Schubert 
745c1d255d3SCy Schubert 
wpas_pasn_auth_stop(struct wpa_supplicant * wpa_s)746c1d255d3SCy Schubert void wpas_pasn_auth_stop(struct wpa_supplicant *wpa_s)
747c1d255d3SCy Schubert {
748*a90b9d01SCy Schubert 	struct pasn_data *pasn = &wpa_s->pasn;
749c1d255d3SCy Schubert 
750c1d255d3SCy Schubert 	if (!wpa_s->pasn.ecdh)
751c1d255d3SCy Schubert 		return;
752c1d255d3SCy Schubert 
753c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "PASN: Stopping authentication");
754c1d255d3SCy Schubert 
755*a90b9d01SCy Schubert 	wpas_pasn_auth_status(wpa_s, pasn->peer_addr, pasn_get_akmp(pasn),
756*a90b9d01SCy Schubert 			      pasn_get_cipher(pasn),
757c1d255d3SCy Schubert 			      pasn->status, pasn->comeback,
758c1d255d3SCy Schubert 			      pasn->comeback_after);
759c1d255d3SCy Schubert 
760c1d255d3SCy Schubert 	wpas_pasn_reset(wpa_s);
761c1d255d3SCy Schubert }
762c1d255d3SCy Schubert 
763c1d255d3SCy Schubert 
wpas_pasn_immediate_retry(struct wpa_supplicant * wpa_s,struct pasn_data * pasn,struct wpa_pasn_params_data * params)764c1d255d3SCy Schubert static int wpas_pasn_immediate_retry(struct wpa_supplicant *wpa_s,
765*a90b9d01SCy Schubert 				     struct pasn_data *pasn,
766c1d255d3SCy Schubert 				     struct wpa_pasn_params_data *params)
767c1d255d3SCy Schubert {
768*a90b9d01SCy Schubert 	int akmp = pasn_get_akmp(pasn);
769*a90b9d01SCy Schubert 	int cipher = pasn_get_cipher(pasn);
770c1d255d3SCy Schubert 	u16 group = pasn->group;
771*a90b9d01SCy Schubert 	u8 own_addr[ETH_ALEN];
772*a90b9d01SCy Schubert 	u8 peer_addr[ETH_ALEN];
773c1d255d3SCy Schubert 
774c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "PASN: Immediate retry");
775*a90b9d01SCy Schubert 	os_memcpy(own_addr, pasn->own_addr, ETH_ALEN);
776*a90b9d01SCy Schubert 	os_memcpy(peer_addr, pasn->peer_addr, ETH_ALEN);
777c1d255d3SCy Schubert 	wpas_pasn_reset(wpa_s);
778c1d255d3SCy Schubert 
779*a90b9d01SCy Schubert 	return wpas_pasn_auth_start(wpa_s, own_addr, peer_addr, akmp, cipher,
780*a90b9d01SCy Schubert 				    group, pasn->network_id,
781c1d255d3SCy Schubert 				    params->comeback, params->comeback_len);
782c1d255d3SCy Schubert }
783c1d255d3SCy Schubert 
784c1d255d3SCy Schubert 
wpas_pasn_deauth_cb(struct ptksa_cache_entry * entry)785*a90b9d01SCy Schubert static void wpas_pasn_deauth_cb(struct ptksa_cache_entry *entry)
786*a90b9d01SCy Schubert {
787*a90b9d01SCy Schubert 	struct wpa_supplicant *wpa_s = entry->ctx;
788*a90b9d01SCy Schubert 	u8 own_addr[ETH_ALEN];
789*a90b9d01SCy Schubert 	u8 peer_addr[ETH_ALEN];
790*a90b9d01SCy Schubert 
791*a90b9d01SCy Schubert 	/* Use a copy of the addresses from the entry to avoid issues with the
792*a90b9d01SCy Schubert 	 * entry getting freed during deauthentication processing. */
793*a90b9d01SCy Schubert 	os_memcpy(own_addr, entry->own_addr, ETH_ALEN);
794*a90b9d01SCy Schubert 	os_memcpy(peer_addr, entry->addr, ETH_ALEN);
795*a90b9d01SCy Schubert 	wpas_pasn_deauthenticate(wpa_s, own_addr, peer_addr);
796*a90b9d01SCy Schubert }
797*a90b9d01SCy Schubert 
798*a90b9d01SCy Schubert 
wpas_pasn_auth_rx(struct wpa_supplicant * wpa_s,const struct ieee80211_mgmt * mgmt,size_t len)799c1d255d3SCy Schubert int wpas_pasn_auth_rx(struct wpa_supplicant *wpa_s,
800c1d255d3SCy Schubert 		      const struct ieee80211_mgmt *mgmt, size_t len)
801c1d255d3SCy Schubert {
802*a90b9d01SCy Schubert 	struct pasn_data *pasn = &wpa_s->pasn;
803*a90b9d01SCy Schubert 	struct wpa_pasn_params_data pasn_data;
804*a90b9d01SCy Schubert 	int ret;
805c1d255d3SCy Schubert 
806*a90b9d01SCy Schubert 	if (!wpa_s->pasn_auth_work)
807c1d255d3SCy Schubert 		return -2;
808c1d255d3SCy Schubert 
809*a90b9d01SCy Schubert 	pasn_register_callbacks(pasn, wpa_s, wpas_pasn_send_mlme, NULL);
810*a90b9d01SCy Schubert 	ret = wpa_pasn_auth_rx(pasn, (const u8 *) mgmt, len, &pasn_data);
811*a90b9d01SCy Schubert 	if (ret == 0) {
812*a90b9d01SCy Schubert 		ptksa_cache_add(wpa_s->ptksa, pasn->own_addr, pasn->peer_addr,
813*a90b9d01SCy Schubert 				pasn_get_cipher(pasn),
814*a90b9d01SCy Schubert 				dot11RSNAConfigPMKLifetime,
815*a90b9d01SCy Schubert 				pasn_get_ptk(pasn),
816*a90b9d01SCy Schubert 				wpa_s->pasn_params ? wpas_pasn_deauth_cb : NULL,
817*a90b9d01SCy Schubert 				wpa_s->pasn_params ? wpa_s : NULL,
818*a90b9d01SCy Schubert 				pasn_get_akmp(pasn));
819c1d255d3SCy Schubert 
820*a90b9d01SCy Schubert 		if (pasn->pmksa_entry)
821*a90b9d01SCy Schubert 			wpa_sm_set_cur_pmksa(wpa_s->wpa, pasn->pmksa_entry);
822c1d255d3SCy Schubert 	}
823c1d255d3SCy Schubert 
824*a90b9d01SCy Schubert 	forced_memzero(pasn_get_ptk(pasn), sizeof(pasn->ptk));
825c1d255d3SCy Schubert 
826*a90b9d01SCy Schubert 	if (ret == -1) {
827c1d255d3SCy Schubert 		wpas_pasn_auth_stop(wpa_s);
828*a90b9d01SCy Schubert 		wpas_pasn_auth_work_done(wpa_s, PASN_STATUS_FAILURE);
829c1d255d3SCy Schubert 	}
830c1d255d3SCy Schubert 
831*a90b9d01SCy Schubert 	if (ret == 1)
832*a90b9d01SCy Schubert 		ret = wpas_pasn_immediate_retry(wpa_s, pasn, &pasn_data);
833*a90b9d01SCy Schubert 
834*a90b9d01SCy Schubert 	return ret;
835*a90b9d01SCy Schubert }
836*a90b9d01SCy Schubert 
837*a90b9d01SCy Schubert 
wpas_pasn_auth_trigger(struct wpa_supplicant * wpa_s,struct pasn_auth * pasn_auth)838*a90b9d01SCy Schubert void wpas_pasn_auth_trigger(struct wpa_supplicant *wpa_s,
839*a90b9d01SCy Schubert 			    struct pasn_auth *pasn_auth)
840*a90b9d01SCy Schubert {
841*a90b9d01SCy Schubert 	struct pasn_peer *src, *dst;
842*a90b9d01SCy Schubert 	unsigned int i, num_peers = pasn_auth->num_peers;
843*a90b9d01SCy Schubert 
844*a90b9d01SCy Schubert 	if (wpa_s->pasn_params) {
845c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
846*a90b9d01SCy Schubert 			   "PASN: auth_trigger: Already in progress");
847*a90b9d01SCy Schubert 		return;
848c1d255d3SCy Schubert 	}
849c1d255d3SCy Schubert 
850*a90b9d01SCy Schubert 	if (!num_peers || num_peers > WPAS_MAX_PASN_PEERS) {
851c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
852*a90b9d01SCy Schubert 			   "PASN: auth trigger: Invalid number of peers");
853*a90b9d01SCy Schubert 		return;
854c1d255d3SCy Schubert 	}
855c1d255d3SCy Schubert 
856*a90b9d01SCy Schubert 	wpa_s->pasn_params = os_zalloc(sizeof(struct pasn_auth));
857*a90b9d01SCy Schubert 	if (!wpa_s->pasn_params) {
858c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
859*a90b9d01SCy Schubert 			   "PASN: auth trigger: Failed to allocate a buffer");
860*a90b9d01SCy Schubert 		return;
861c1d255d3SCy Schubert 	}
862c1d255d3SCy Schubert 
863*a90b9d01SCy Schubert 	wpa_s->pasn_count = 0;
864*a90b9d01SCy Schubert 	wpa_s->pasn_params->num_peers = num_peers;
865c1d255d3SCy Schubert 
866*a90b9d01SCy Schubert 	for (i = 0; i < num_peers; i++) {
867*a90b9d01SCy Schubert 		dst = &wpa_s->pasn_params->peer[i];
868*a90b9d01SCy Schubert 		src = &pasn_auth->peer[i];
869*a90b9d01SCy Schubert 		os_memcpy(dst->own_addr, wpa_s->own_addr, ETH_ALEN);
870*a90b9d01SCy Schubert 		os_memcpy(dst->peer_addr, src->peer_addr, ETH_ALEN);
871*a90b9d01SCy Schubert 		dst->ltf_keyseed_required = src->ltf_keyseed_required;
872*a90b9d01SCy Schubert 		dst->status = PASN_STATUS_SUCCESS;
873c1d255d3SCy Schubert 
874*a90b9d01SCy Schubert 		if (!is_zero_ether_addr(src->own_addr)) {
875*a90b9d01SCy Schubert 			os_memcpy(dst->own_addr, src->own_addr, ETH_ALEN);
876*a90b9d01SCy Schubert 			wpa_printf(MSG_DEBUG, "PASN: Own (source) MAC addr: "
877*a90b9d01SCy Schubert 				   MACSTR, MAC2STR(dst->own_addr));
878c1d255d3SCy Schubert 		}
879c1d255d3SCy Schubert 	}
880c1d255d3SCy Schubert 
881*a90b9d01SCy Schubert 	if (pasn_auth->action == PASN_ACTION_DELETE_SECURE_RANGING_CONTEXT) {
882*a90b9d01SCy Schubert 		wpas_pasn_delete_peers(wpa_s, wpa_s->pasn_params);
883*a90b9d01SCy Schubert 		os_free(wpa_s->pasn_params);
884*a90b9d01SCy Schubert 		wpa_s->pasn_params = NULL;
885*a90b9d01SCy Schubert 	} else if (pasn_auth->action == PASN_ACTION_AUTH) {
886*a90b9d01SCy Schubert 		wpas_pasn_configure_next_peer(wpa_s, wpa_s->pasn_params);
887c1d255d3SCy Schubert 	}
888c1d255d3SCy Schubert }
889c1d255d3SCy Schubert 
890c1d255d3SCy Schubert 
wpas_pasn_auth_tx_status(struct wpa_supplicant * wpa_s,const u8 * data,size_t data_len,u8 acked)891c1d255d3SCy Schubert int wpas_pasn_auth_tx_status(struct wpa_supplicant *wpa_s,
892c1d255d3SCy Schubert 			     const u8 *data, size_t data_len, u8 acked)
893c1d255d3SCy Schubert 
894c1d255d3SCy Schubert {
895*a90b9d01SCy Schubert 	struct pasn_data *pasn = &wpa_s->pasn;
896*a90b9d01SCy Schubert 	int ret;
897c1d255d3SCy Schubert 
898c1d255d3SCy Schubert 	if (!wpa_s->pasn_auth_work) {
899c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
900c1d255d3SCy Schubert 			   "PASN: auth_tx_status: no work in progress");
901c1d255d3SCy Schubert 		return -1;
902c1d255d3SCy Schubert 	}
903c1d255d3SCy Schubert 
904*a90b9d01SCy Schubert 	ret = wpa_pasn_auth_tx_status(pasn, data, data_len, acked);
905*a90b9d01SCy Schubert 	if (ret != 1)
906*a90b9d01SCy Schubert 		return ret;
907c1d255d3SCy Schubert 
908*a90b9d01SCy Schubert 	if (!wpa_s->pasn_params) {
909c1d255d3SCy Schubert 		wpas_pasn_auth_stop(wpa_s);
910*a90b9d01SCy Schubert 		return 0;
911c1d255d3SCy Schubert 	}
912c1d255d3SCy Schubert 
913*a90b9d01SCy Schubert 	wpas_pasn_set_keys_from_cache(wpa_s, pasn->own_addr, pasn->peer_addr,
914*a90b9d01SCy Schubert 				      pasn_get_cipher(pasn),
915*a90b9d01SCy Schubert 				      pasn_get_akmp(pasn));
916*a90b9d01SCy Schubert 	wpas_pasn_auth_stop(wpa_s);
917*a90b9d01SCy Schubert 	wpas_pasn_auth_work_done(wpa_s, PASN_STATUS_SUCCESS);
918*a90b9d01SCy Schubert 
919c1d255d3SCy Schubert 	return 0;
920c1d255d3SCy Schubert }
921c1d255d3SCy Schubert 
922c1d255d3SCy Schubert 
wpas_pasn_deauthenticate(struct wpa_supplicant * wpa_s,const u8 * own_addr,const u8 * peer_addr)923*a90b9d01SCy Schubert int wpas_pasn_deauthenticate(struct wpa_supplicant *wpa_s, const u8 *own_addr,
924*a90b9d01SCy Schubert 			     const u8 *peer_addr)
925c1d255d3SCy Schubert {
926c1d255d3SCy Schubert 	struct wpa_bss *bss;
927c1d255d3SCy Schubert 	struct wpabuf *buf;
928c1d255d3SCy Schubert 	struct ieee80211_mgmt *deauth;
929c1d255d3SCy Schubert 	int ret;
930c1d255d3SCy Schubert 
931*a90b9d01SCy Schubert 	if (ether_addr_equal(wpa_s->bssid, peer_addr)) {
932c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
933c1d255d3SCy Schubert 			   "PASN: Cannot deauthenticate from current BSS");
934c1d255d3SCy Schubert 		return -1;
935c1d255d3SCy Schubert 	}
936c1d255d3SCy Schubert 
937*a90b9d01SCy Schubert 	wpa_drv_set_secure_ranging_ctx(wpa_s, own_addr, peer_addr, 0, 0, NULL,
938*a90b9d01SCy Schubert 				       0, NULL, 1);
939c1d255d3SCy Schubert 
940*a90b9d01SCy Schubert 	wpa_printf(MSG_DEBUG, "PASN: deauth: Flushing all PTKSA entries for "
941*a90b9d01SCy Schubert 		   MACSTR, MAC2STR(peer_addr));
942*a90b9d01SCy Schubert 	ptksa_cache_flush(wpa_s->ptksa, peer_addr, WPA_CIPHER_NONE);
943*a90b9d01SCy Schubert 
944*a90b9d01SCy Schubert 	bss = wpa_bss_get_bssid(wpa_s, peer_addr);
945c1d255d3SCy Schubert 	if (!bss) {
946c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: deauth: BSS not found");
947c1d255d3SCy Schubert 		return -1;
948c1d255d3SCy Schubert 	}
949c1d255d3SCy Schubert 
950c1d255d3SCy Schubert 	buf = wpabuf_alloc(64);
951c1d255d3SCy Schubert 	if (!buf) {
952c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG, "PASN: deauth: Failed wpabuf allocate");
953c1d255d3SCy Schubert 		return -1;
954c1d255d3SCy Schubert 	}
955c1d255d3SCy Schubert 
956c1d255d3SCy Schubert 	deauth = wpabuf_put(buf, offsetof(struct ieee80211_mgmt,
957c1d255d3SCy Schubert 					  u.deauth.variable));
958c1d255d3SCy Schubert 
959c1d255d3SCy Schubert 	deauth->frame_control = host_to_le16((WLAN_FC_TYPE_MGMT << 2) |
960c1d255d3SCy Schubert 					     (WLAN_FC_STYPE_DEAUTH << 4));
961c1d255d3SCy Schubert 
962*a90b9d01SCy Schubert 	os_memcpy(deauth->da, peer_addr, ETH_ALEN);
963*a90b9d01SCy Schubert 	os_memcpy(deauth->sa, own_addr, ETH_ALEN);
964*a90b9d01SCy Schubert 	os_memcpy(deauth->bssid, peer_addr, ETH_ALEN);
965c1d255d3SCy Schubert 	deauth->u.deauth.reason_code =
966c1d255d3SCy Schubert 		host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
967c1d255d3SCy Schubert 
968c1d255d3SCy Schubert 	/*
969c1d255d3SCy Schubert 	 * Since we do not expect any response from the AP, implement the
970c1d255d3SCy Schubert 	 * Deauthentication frame transmission using direct call to the driver
971c1d255d3SCy Schubert 	 * without a radio work.
972c1d255d3SCy Schubert 	 */
973c1d255d3SCy Schubert 	ret = wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1,
974c1d255d3SCy Schubert 				bss->freq, 0);
975c1d255d3SCy Schubert 
976c1d255d3SCy Schubert 	wpabuf_free(buf);
977c1d255d3SCy Schubert 	wpa_printf(MSG_DEBUG, "PASN: deauth: send_mlme ret=%d", ret);
978c1d255d3SCy Schubert 
979c1d255d3SCy Schubert 	return ret;
980c1d255d3SCy Schubert }
981