16d49e1aeSJan Lentfer /*
26d49e1aeSJan Lentfer  * WPA Supplicant
3*a1157835SDaniel Fojt  * Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi>
46d49e1aeSJan Lentfer  *
53ff40c12SJohn Marino  * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino  * See README for more details.
76d49e1aeSJan Lentfer  *
86d49e1aeSJan Lentfer  * This file implements functions for registering and unregistering
96d49e1aeSJan Lentfer  * %wpa_supplicant interfaces. In addition, this file contains number of
106d49e1aeSJan Lentfer  * functions for managing network connections.
116d49e1aeSJan Lentfer  */
126d49e1aeSJan Lentfer 
136d49e1aeSJan Lentfer #include "includes.h"
14*a1157835SDaniel Fojt #ifdef CONFIG_MATCH_IFACE
15*a1157835SDaniel Fojt #include <net/if.h>
16*a1157835SDaniel Fojt #include <fnmatch.h>
17*a1157835SDaniel Fojt #endif /* CONFIG_MATCH_IFACE */
186d49e1aeSJan Lentfer 
196d49e1aeSJan Lentfer #include "common.h"
203ff40c12SJohn Marino #include "crypto/random.h"
213ff40c12SJohn Marino #include "crypto/sha1.h"
226d49e1aeSJan Lentfer #include "eapol_supp/eapol_supp_sm.h"
236d49e1aeSJan Lentfer #include "eap_peer/eap.h"
243ff40c12SJohn Marino #include "eap_peer/eap_proxy.h"
253ff40c12SJohn Marino #include "eap_server/eap_methods.h"
263ff40c12SJohn Marino #include "rsn_supp/wpa.h"
276d49e1aeSJan Lentfer #include "eloop.h"
286d49e1aeSJan Lentfer #include "config.h"
293ff40c12SJohn Marino #include "utils/ext_password.h"
306d49e1aeSJan Lentfer #include "l2_packet/l2_packet.h"
316d49e1aeSJan Lentfer #include "wpa_supplicant_i.h"
323ff40c12SJohn Marino #include "driver_i.h"
336d49e1aeSJan Lentfer #include "ctrl_iface.h"
346d49e1aeSJan Lentfer #include "pcsc_funcs.h"
353ff40c12SJohn Marino #include "common/version.h"
363ff40c12SJohn Marino #include "rsn_supp/preauth.h"
373ff40c12SJohn Marino #include "rsn_supp/pmksa_cache.h"
383ff40c12SJohn Marino #include "common/wpa_ctrl.h"
39*a1157835SDaniel Fojt #include "common/ieee802_11_common.h"
403ff40c12SJohn Marino #include "common/ieee802_11_defs.h"
41*a1157835SDaniel Fojt #include "common/hw_features_common.h"
42*a1157835SDaniel Fojt #include "common/gas_server.h"
43*a1157835SDaniel Fojt #include "common/dpp.h"
443ff40c12SJohn Marino #include "p2p/p2p.h"
45*a1157835SDaniel Fojt #include "fst/fst.h"
466d49e1aeSJan Lentfer #include "blacklist.h"
476d49e1aeSJan Lentfer #include "wpas_glue.h"
486d49e1aeSJan Lentfer #include "wps_supplicant.h"
493ff40c12SJohn Marino #include "ibss_rsn.h"
503ff40c12SJohn Marino #include "sme.h"
513ff40c12SJohn Marino #include "gas_query.h"
523ff40c12SJohn Marino #include "ap.h"
533ff40c12SJohn Marino #include "p2p_supplicant.h"
543ff40c12SJohn Marino #include "wifi_display.h"
553ff40c12SJohn Marino #include "notify.h"
563ff40c12SJohn Marino #include "bgscan.h"
573ff40c12SJohn Marino #include "autoscan.h"
583ff40c12SJohn Marino #include "bss.h"
593ff40c12SJohn Marino #include "scan.h"
603ff40c12SJohn Marino #include "offchannel.h"
613ff40c12SJohn Marino #include "hs20_supplicant.h"
623ff40c12SJohn Marino #include "wnm_sta.h"
63*a1157835SDaniel Fojt #include "wpas_kay.h"
64*a1157835SDaniel Fojt #include "mesh.h"
65*a1157835SDaniel Fojt #include "dpp_supplicant.h"
66*a1157835SDaniel Fojt #ifdef CONFIG_MESH
67*a1157835SDaniel Fojt #include "ap/ap_config.h"
68*a1157835SDaniel Fojt #include "ap/hostapd.h"
69*a1157835SDaniel Fojt #endif /* CONFIG_MESH */
706d49e1aeSJan Lentfer 
71*a1157835SDaniel Fojt const char *const wpa_supplicant_version =
726d49e1aeSJan Lentfer "wpa_supplicant v" VERSION_STR "\n"
73*a1157835SDaniel Fojt "Copyright (c) 2003-2019, Jouni Malinen <j@w1.fi> and contributors";
746d49e1aeSJan Lentfer 
75*a1157835SDaniel Fojt const char *const wpa_supplicant_license =
763ff40c12SJohn Marino "This software may be distributed under the terms of the BSD license.\n"
773ff40c12SJohn Marino "See README for more details.\n"
786d49e1aeSJan Lentfer #ifdef EAP_TLS_OPENSSL
796d49e1aeSJan Lentfer "\nThis product includes software developed by the OpenSSL Project\n"
806d49e1aeSJan Lentfer "for use in the OpenSSL Toolkit (http://www.openssl.org/)\n"
816d49e1aeSJan Lentfer #endif /* EAP_TLS_OPENSSL */
826d49e1aeSJan Lentfer ;
836d49e1aeSJan Lentfer 
846d49e1aeSJan Lentfer #ifndef CONFIG_NO_STDOUT_DEBUG
856d49e1aeSJan Lentfer /* Long text divided into parts in order to fit in C89 strings size limits. */
86*a1157835SDaniel Fojt const char *const wpa_supplicant_full_license1 =
873ff40c12SJohn Marino "";
88*a1157835SDaniel Fojt const char *const wpa_supplicant_full_license2 =
893ff40c12SJohn Marino "This software may be distributed under the terms of the BSD license.\n"
906d49e1aeSJan Lentfer "\n"
916d49e1aeSJan Lentfer "Redistribution and use in source and binary forms, with or without\n"
926d49e1aeSJan Lentfer "modification, are permitted provided that the following conditions are\n"
936d49e1aeSJan Lentfer "met:\n"
946d49e1aeSJan Lentfer "\n";
95*a1157835SDaniel Fojt const char *const wpa_supplicant_full_license3 =
966d49e1aeSJan Lentfer "1. Redistributions of source code must retain the above copyright\n"
976d49e1aeSJan Lentfer "   notice, this list of conditions and the following disclaimer.\n"
986d49e1aeSJan Lentfer "\n"
996d49e1aeSJan Lentfer "2. Redistributions in binary form must reproduce the above copyright\n"
1006d49e1aeSJan Lentfer "   notice, this list of conditions and the following disclaimer in the\n"
1016d49e1aeSJan Lentfer "   documentation and/or other materials provided with the distribution.\n"
1026d49e1aeSJan Lentfer "\n";
103*a1157835SDaniel Fojt const char *const wpa_supplicant_full_license4 =
1046d49e1aeSJan Lentfer "3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
1056d49e1aeSJan Lentfer "   names of its contributors may be used to endorse or promote products\n"
1066d49e1aeSJan Lentfer "   derived from this software without specific prior written permission.\n"
1076d49e1aeSJan Lentfer "\n"
1086d49e1aeSJan Lentfer "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
1096d49e1aeSJan Lentfer "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
1106d49e1aeSJan Lentfer "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
1116d49e1aeSJan Lentfer "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n";
112*a1157835SDaniel Fojt const char *const wpa_supplicant_full_license5 =
1136d49e1aeSJan Lentfer "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
1146d49e1aeSJan Lentfer "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
1156d49e1aeSJan Lentfer "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
1166d49e1aeSJan Lentfer "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
1176d49e1aeSJan Lentfer "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
1186d49e1aeSJan Lentfer "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
1196d49e1aeSJan Lentfer "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
1206d49e1aeSJan Lentfer "\n";
1216d49e1aeSJan Lentfer #endif /* CONFIG_NO_STDOUT_DEBUG */
1226d49e1aeSJan Lentfer 
123*a1157835SDaniel Fojt 
124*a1157835SDaniel Fojt static void wpa_bss_tmp_disallow_timeout(void *eloop_ctx, void *timeout_ctx);
125*a1157835SDaniel Fojt #if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
126*a1157835SDaniel Fojt static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s);
127*a1157835SDaniel Fojt #endif /* CONFIG_FILS && IEEE8021X_EAPOL */
128*a1157835SDaniel Fojt 
129*a1157835SDaniel Fojt 
1306d49e1aeSJan Lentfer /* Configure default/group WEP keys for static WEP */
wpa_set_wep_keys(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid)1313ff40c12SJohn Marino int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
1326d49e1aeSJan Lentfer {
1336d49e1aeSJan Lentfer 	int i, set = 0;
1346d49e1aeSJan Lentfer 
1356d49e1aeSJan Lentfer 	for (i = 0; i < NUM_WEP_KEYS; i++) {
1366d49e1aeSJan Lentfer 		if (ssid->wep_key_len[i] == 0)
1376d49e1aeSJan Lentfer 			continue;
1386d49e1aeSJan Lentfer 
1396d49e1aeSJan Lentfer 		set = 1;
1403ff40c12SJohn Marino 		wpa_drv_set_key(wpa_s, WPA_ALG_WEP, NULL,
1413ff40c12SJohn Marino 				i, i == ssid->wep_tx_keyidx, NULL, 0,
1426d49e1aeSJan Lentfer 				ssid->wep_key[i], ssid->wep_key_len[i]);
1436d49e1aeSJan Lentfer 	}
1446d49e1aeSJan Lentfer 
1456d49e1aeSJan Lentfer 	return set;
1466d49e1aeSJan Lentfer }
1476d49e1aeSJan Lentfer 
1486d49e1aeSJan Lentfer 
wpa_supplicant_set_wpa_none_key(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid)1493ff40c12SJohn Marino int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
1506d49e1aeSJan Lentfer 				    struct wpa_ssid *ssid)
1516d49e1aeSJan Lentfer {
1526d49e1aeSJan Lentfer 	u8 key[32];
1536d49e1aeSJan Lentfer 	size_t keylen;
1543ff40c12SJohn Marino 	enum wpa_alg alg;
1556d49e1aeSJan Lentfer 	u8 seq[6] = { 0 };
156*a1157835SDaniel Fojt 	int ret;
1576d49e1aeSJan Lentfer 
1586d49e1aeSJan Lentfer 	/* IBSS/WPA-None uses only one key (Group) for both receiving and
1596d49e1aeSJan Lentfer 	 * sending unicast and multicast packets. */
1606d49e1aeSJan Lentfer 
1613ff40c12SJohn Marino 	if (ssid->mode != WPAS_MODE_IBSS) {
1623ff40c12SJohn Marino 		wpa_msg(wpa_s, MSG_INFO, "WPA: Invalid mode %d (not "
1633ff40c12SJohn Marino 			"IBSS/ad-hoc) for WPA-None", ssid->mode);
1646d49e1aeSJan Lentfer 		return -1;
1656d49e1aeSJan Lentfer 	}
1666d49e1aeSJan Lentfer 
1676d49e1aeSJan Lentfer 	if (!ssid->psk_set) {
1683ff40c12SJohn Marino 		wpa_msg(wpa_s, MSG_INFO, "WPA: No PSK configured for "
1693ff40c12SJohn Marino 			"WPA-None");
1706d49e1aeSJan Lentfer 		return -1;
1716d49e1aeSJan Lentfer 	}
1726d49e1aeSJan Lentfer 
1736d49e1aeSJan Lentfer 	switch (wpa_s->group_cipher) {
1746d49e1aeSJan Lentfer 	case WPA_CIPHER_CCMP:
1756d49e1aeSJan Lentfer 		os_memcpy(key, ssid->psk, 16);
1766d49e1aeSJan Lentfer 		keylen = 16;
1776d49e1aeSJan Lentfer 		alg = WPA_ALG_CCMP;
1786d49e1aeSJan Lentfer 		break;
1793ff40c12SJohn Marino 	case WPA_CIPHER_GCMP:
1803ff40c12SJohn Marino 		os_memcpy(key, ssid->psk, 16);
1813ff40c12SJohn Marino 		keylen = 16;
1823ff40c12SJohn Marino 		alg = WPA_ALG_GCMP;
1833ff40c12SJohn Marino 		break;
1846d49e1aeSJan Lentfer 	case WPA_CIPHER_TKIP:
1856d49e1aeSJan Lentfer 		/* WPA-None uses the same Michael MIC key for both TX and RX */
1866d49e1aeSJan Lentfer 		os_memcpy(key, ssid->psk, 16 + 8);
1876d49e1aeSJan Lentfer 		os_memcpy(key + 16 + 8, ssid->psk + 16, 8);
1886d49e1aeSJan Lentfer 		keylen = 32;
1896d49e1aeSJan Lentfer 		alg = WPA_ALG_TKIP;
1906d49e1aeSJan Lentfer 		break;
1916d49e1aeSJan Lentfer 	default:
1923ff40c12SJohn Marino 		wpa_msg(wpa_s, MSG_INFO, "WPA: Invalid group cipher %d for "
1936d49e1aeSJan Lentfer 			"WPA-None", wpa_s->group_cipher);
1946d49e1aeSJan Lentfer 		return -1;
1956d49e1aeSJan Lentfer 	}
1966d49e1aeSJan Lentfer 
1976d49e1aeSJan Lentfer 	/* TODO: should actually remember the previously used seq#, both for TX
1986d49e1aeSJan Lentfer 	 * and RX from each STA.. */
1996d49e1aeSJan Lentfer 
200*a1157835SDaniel Fojt 	ret = wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen);
201*a1157835SDaniel Fojt 	os_memset(key, 0, sizeof(key));
202*a1157835SDaniel Fojt 	return ret;
2036d49e1aeSJan Lentfer }
2046d49e1aeSJan Lentfer 
2056d49e1aeSJan Lentfer 
wpa_supplicant_timeout(void * eloop_ctx,void * timeout_ctx)2066d49e1aeSJan Lentfer static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
2076d49e1aeSJan Lentfer {
2086d49e1aeSJan Lentfer 	struct wpa_supplicant *wpa_s = eloop_ctx;
2096d49e1aeSJan Lentfer 	const u8 *bssid = wpa_s->bssid;
210*a1157835SDaniel Fojt 	if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
211*a1157835SDaniel Fojt 	    (wpa_s->wpa_state == WPA_AUTHENTICATING ||
212*a1157835SDaniel Fojt 	     wpa_s->wpa_state == WPA_ASSOCIATING))
2136d49e1aeSJan Lentfer 		bssid = wpa_s->pending_bssid;
2146d49e1aeSJan Lentfer 	wpa_msg(wpa_s, MSG_INFO, "Authentication with " MACSTR " timed out.",
2156d49e1aeSJan Lentfer 		MAC2STR(bssid));
2166d49e1aeSJan Lentfer 	wpa_blacklist_add(wpa_s, bssid);
2176d49e1aeSJan Lentfer 	wpa_sm_notify_disassoc(wpa_s->wpa);
2183ff40c12SJohn Marino 	wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
2196d49e1aeSJan Lentfer 	wpa_s->reassociate = 1;
2203ff40c12SJohn Marino 
2213ff40c12SJohn Marino 	/*
2223ff40c12SJohn Marino 	 * If we timed out, the AP or the local radio may be busy.
2233ff40c12SJohn Marino 	 * So, wait a second until scanning again.
2243ff40c12SJohn Marino 	 */
2253ff40c12SJohn Marino 	wpa_supplicant_req_scan(wpa_s, 1, 0);
2266d49e1aeSJan Lentfer }
2276d49e1aeSJan Lentfer 
2286d49e1aeSJan Lentfer 
2296d49e1aeSJan Lentfer /**
2306d49e1aeSJan Lentfer  * wpa_supplicant_req_auth_timeout - Schedule a timeout for authentication
2316d49e1aeSJan Lentfer  * @wpa_s: Pointer to wpa_supplicant data
2326d49e1aeSJan Lentfer  * @sec: Number of seconds after which to time out authentication
2336d49e1aeSJan Lentfer  * @usec: Number of microseconds after which to time out authentication
2346d49e1aeSJan Lentfer  *
2356d49e1aeSJan Lentfer  * This function is used to schedule a timeout for the current authentication
2366d49e1aeSJan Lentfer  * attempt.
2376d49e1aeSJan Lentfer  */
wpa_supplicant_req_auth_timeout(struct wpa_supplicant * wpa_s,int sec,int usec)2386d49e1aeSJan Lentfer void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
2396d49e1aeSJan Lentfer 				     int sec, int usec)
2406d49e1aeSJan Lentfer {
2413ff40c12SJohn Marino 	if (wpa_s->conf->ap_scan == 0 &&
2423ff40c12SJohn Marino 	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED))
2436d49e1aeSJan Lentfer 		return;
2446d49e1aeSJan Lentfer 
2453ff40c12SJohn Marino 	wpa_dbg(wpa_s, MSG_DEBUG, "Setting authentication timeout: %d sec "
2466d49e1aeSJan Lentfer 		"%d usec", sec, usec);
2476d49e1aeSJan Lentfer 	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
248*a1157835SDaniel Fojt 	wpa_s->last_auth_timeout_sec = sec;
2496d49e1aeSJan Lentfer 	eloop_register_timeout(sec, usec, wpa_supplicant_timeout, wpa_s, NULL);
2506d49e1aeSJan Lentfer }
2516d49e1aeSJan Lentfer 
2526d49e1aeSJan Lentfer 
253*a1157835SDaniel Fojt /*
254*a1157835SDaniel Fojt  * wpas_auth_timeout_restart - Restart and change timeout for authentication
255*a1157835SDaniel Fojt  * @wpa_s: Pointer to wpa_supplicant data
256*a1157835SDaniel Fojt  * @sec_diff: difference in seconds applied to original timeout value
257*a1157835SDaniel Fojt  */
wpas_auth_timeout_restart(struct wpa_supplicant * wpa_s,int sec_diff)258*a1157835SDaniel Fojt void wpas_auth_timeout_restart(struct wpa_supplicant *wpa_s, int sec_diff)
259*a1157835SDaniel Fojt {
260*a1157835SDaniel Fojt 	int new_sec = wpa_s->last_auth_timeout_sec + sec_diff;
261*a1157835SDaniel Fojt 
262*a1157835SDaniel Fojt 	if (eloop_is_timeout_registered(wpa_supplicant_timeout, wpa_s, NULL)) {
263*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG,
264*a1157835SDaniel Fojt 			"Authentication timeout restart: %d sec", new_sec);
265*a1157835SDaniel Fojt 		eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
266*a1157835SDaniel Fojt 		eloop_register_timeout(new_sec, 0, wpa_supplicant_timeout,
267*a1157835SDaniel Fojt 				       wpa_s, NULL);
268*a1157835SDaniel Fojt 	}
269*a1157835SDaniel Fojt }
270*a1157835SDaniel Fojt 
271*a1157835SDaniel Fojt 
2726d49e1aeSJan Lentfer /**
2736d49e1aeSJan Lentfer  * wpa_supplicant_cancel_auth_timeout - Cancel authentication timeout
2746d49e1aeSJan Lentfer  * @wpa_s: Pointer to wpa_supplicant data
2756d49e1aeSJan Lentfer  *
2766d49e1aeSJan Lentfer  * This function is used to cancel authentication timeout scheduled with
2776d49e1aeSJan Lentfer  * wpa_supplicant_req_auth_timeout() and it is called when authentication has
2786d49e1aeSJan Lentfer  * been completed.
2796d49e1aeSJan Lentfer  */
wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant * wpa_s)2806d49e1aeSJan Lentfer void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s)
2816d49e1aeSJan Lentfer {
2823ff40c12SJohn Marino 	wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling authentication timeout");
2836d49e1aeSJan Lentfer 	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
2846d49e1aeSJan Lentfer 	wpa_blacklist_del(wpa_s, wpa_s->bssid);
285*a1157835SDaniel Fojt 	os_free(wpa_s->last_con_fail_realm);
286*a1157835SDaniel Fojt 	wpa_s->last_con_fail_realm = NULL;
287*a1157835SDaniel Fojt 	wpa_s->last_con_fail_realm_len = 0;
2886d49e1aeSJan Lentfer }
2896d49e1aeSJan Lentfer 
2906d49e1aeSJan Lentfer 
2916d49e1aeSJan Lentfer /**
2926d49e1aeSJan Lentfer  * wpa_supplicant_initiate_eapol - Configure EAPOL state machine
2936d49e1aeSJan Lentfer  * @wpa_s: Pointer to wpa_supplicant data
2946d49e1aeSJan Lentfer  *
2956d49e1aeSJan Lentfer  * This function is used to configure EAPOL state machine based on the selected
2966d49e1aeSJan Lentfer  * authentication mode.
2976d49e1aeSJan Lentfer  */
wpa_supplicant_initiate_eapol(struct wpa_supplicant * wpa_s)2986d49e1aeSJan Lentfer void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
2996d49e1aeSJan Lentfer {
3006d49e1aeSJan Lentfer #ifdef IEEE8021X_EAPOL
3016d49e1aeSJan Lentfer 	struct eapol_config eapol_conf;
3026d49e1aeSJan Lentfer 	struct wpa_ssid *ssid = wpa_s->current_ssid;
3036d49e1aeSJan Lentfer 
3043ff40c12SJohn Marino #ifdef CONFIG_IBSS_RSN
3053ff40c12SJohn Marino 	if (ssid->mode == WPAS_MODE_IBSS &&
3063ff40c12SJohn Marino 	    wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
3073ff40c12SJohn Marino 	    wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE) {
3083ff40c12SJohn Marino 		/*
3093ff40c12SJohn Marino 		 * RSN IBSS authentication is per-STA and we can disable the
3103ff40c12SJohn Marino 		 * per-BSSID EAPOL authentication.
3113ff40c12SJohn Marino 		 */
3123ff40c12SJohn Marino 		eapol_sm_notify_portControl(wpa_s->eapol, ForceAuthorized);
3133ff40c12SJohn Marino 		eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
3143ff40c12SJohn Marino 		eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE);
3153ff40c12SJohn Marino 		return;
3163ff40c12SJohn Marino 	}
3173ff40c12SJohn Marino #endif /* CONFIG_IBSS_RSN */
3183ff40c12SJohn Marino 
3196d49e1aeSJan Lentfer 	eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
3206d49e1aeSJan Lentfer 	eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE);
3216d49e1aeSJan Lentfer 
3226d49e1aeSJan Lentfer 	if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
3236d49e1aeSJan Lentfer 	    wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE)
3246d49e1aeSJan Lentfer 		eapol_sm_notify_portControl(wpa_s->eapol, ForceAuthorized);
3256d49e1aeSJan Lentfer 	else
3266d49e1aeSJan Lentfer 		eapol_sm_notify_portControl(wpa_s->eapol, Auto);
3276d49e1aeSJan Lentfer 
3286d49e1aeSJan Lentfer 	os_memset(&eapol_conf, 0, sizeof(eapol_conf));
3296d49e1aeSJan Lentfer 	if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
3306d49e1aeSJan Lentfer 		eapol_conf.accept_802_1x_keys = 1;
3316d49e1aeSJan Lentfer 		eapol_conf.required_keys = 0;
3326d49e1aeSJan Lentfer 		if (ssid->eapol_flags & EAPOL_FLAG_REQUIRE_KEY_UNICAST) {
3336d49e1aeSJan Lentfer 			eapol_conf.required_keys |= EAPOL_REQUIRE_KEY_UNICAST;
3346d49e1aeSJan Lentfer 		}
3356d49e1aeSJan Lentfer 		if (ssid->eapol_flags & EAPOL_FLAG_REQUIRE_KEY_BROADCAST) {
3366d49e1aeSJan Lentfer 			eapol_conf.required_keys |=
3376d49e1aeSJan Lentfer 				EAPOL_REQUIRE_KEY_BROADCAST;
3386d49e1aeSJan Lentfer 		}
3396d49e1aeSJan Lentfer 
3403ff40c12SJohn Marino 		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)
3416d49e1aeSJan Lentfer 			eapol_conf.required_keys = 0;
3426d49e1aeSJan Lentfer 	}
3436d49e1aeSJan Lentfer 	eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
3446d49e1aeSJan Lentfer 	eapol_conf.workaround = ssid->eap_workaround;
3456d49e1aeSJan Lentfer 	eapol_conf.eap_disabled =
3466d49e1aeSJan Lentfer 		!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) &&
3476d49e1aeSJan Lentfer 		wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
3486d49e1aeSJan Lentfer 		wpa_s->key_mgmt != WPA_KEY_MGMT_WPS;
3493ff40c12SJohn Marino 	eapol_conf.external_sim = wpa_s->conf->external_sim;
350*a1157835SDaniel Fojt 
351*a1157835SDaniel Fojt #ifdef CONFIG_WPS
352*a1157835SDaniel Fojt 	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
353*a1157835SDaniel Fojt 		eapol_conf.wps |= EAPOL_LOCAL_WPS_IN_USE;
354*a1157835SDaniel Fojt 		if (wpa_s->current_bss) {
355*a1157835SDaniel Fojt 			struct wpabuf *ie;
356*a1157835SDaniel Fojt 			ie = wpa_bss_get_vendor_ie_multi(wpa_s->current_bss,
357*a1157835SDaniel Fojt 							 WPS_IE_VENDOR_TYPE);
358*a1157835SDaniel Fojt 			if (ie) {
359*a1157835SDaniel Fojt 				if (wps_is_20(ie))
360*a1157835SDaniel Fojt 					eapol_conf.wps |=
361*a1157835SDaniel Fojt 						EAPOL_PEER_IS_WPS20_AP;
362*a1157835SDaniel Fojt 				wpabuf_free(ie);
363*a1157835SDaniel Fojt 			}
364*a1157835SDaniel Fojt 		}
365*a1157835SDaniel Fojt 	}
366*a1157835SDaniel Fojt #endif /* CONFIG_WPS */
367*a1157835SDaniel Fojt 
3686d49e1aeSJan Lentfer 	eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
369*a1157835SDaniel Fojt 
370*a1157835SDaniel Fojt #ifdef CONFIG_MACSEC
371*a1157835SDaniel Fojt 	if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE && ssid->mka_psk_set)
372*a1157835SDaniel Fojt 		ieee802_1x_create_preshared_mka(wpa_s, ssid);
373*a1157835SDaniel Fojt 	else
374*a1157835SDaniel Fojt 		ieee802_1x_alloc_kay_sm(wpa_s, ssid);
375*a1157835SDaniel Fojt #endif /* CONFIG_MACSEC */
3766d49e1aeSJan Lentfer #endif /* IEEE8021X_EAPOL */
3776d49e1aeSJan Lentfer }
3786d49e1aeSJan Lentfer 
3796d49e1aeSJan Lentfer 
3806d49e1aeSJan Lentfer /**
3816d49e1aeSJan Lentfer  * wpa_supplicant_set_non_wpa_policy - Set WPA parameters to non-WPA mode
3826d49e1aeSJan Lentfer  * @wpa_s: Pointer to wpa_supplicant data
3836d49e1aeSJan Lentfer  * @ssid: Configuration data for the network
3846d49e1aeSJan Lentfer  *
3856d49e1aeSJan Lentfer  * This function is used to configure WPA state machine and related parameters
3866d49e1aeSJan Lentfer  * to a mode where WPA is not enabled. This is called as part of the
3876d49e1aeSJan Lentfer  * authentication configuration when the selected network does not use WPA.
3886d49e1aeSJan Lentfer  */
wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid)3896d49e1aeSJan Lentfer void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
3906d49e1aeSJan Lentfer 				       struct wpa_ssid *ssid)
3916d49e1aeSJan Lentfer {
3926d49e1aeSJan Lentfer 	int i;
3936d49e1aeSJan Lentfer 
3946d49e1aeSJan Lentfer 	if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
3956d49e1aeSJan Lentfer 		wpa_s->key_mgmt = WPA_KEY_MGMT_WPS;
3966d49e1aeSJan Lentfer 	else if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)
3976d49e1aeSJan Lentfer 		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA;
3986d49e1aeSJan Lentfer 	else
3996d49e1aeSJan Lentfer 		wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
4006d49e1aeSJan Lentfer 	wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
4016d49e1aeSJan Lentfer 	wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
4026d49e1aeSJan Lentfer 	wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
4036d49e1aeSJan Lentfer 	wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
4046d49e1aeSJan Lentfer 	wpa_s->group_cipher = WPA_CIPHER_NONE;
4056d49e1aeSJan Lentfer 	wpa_s->mgmt_group_cipher = 0;
4066d49e1aeSJan Lentfer 
4076d49e1aeSJan Lentfer 	for (i = 0; i < NUM_WEP_KEYS; i++) {
4086d49e1aeSJan Lentfer 		if (ssid->wep_key_len[i] > 5) {
4096d49e1aeSJan Lentfer 			wpa_s->pairwise_cipher = WPA_CIPHER_WEP104;
4106d49e1aeSJan Lentfer 			wpa_s->group_cipher = WPA_CIPHER_WEP104;
4116d49e1aeSJan Lentfer 			break;
4126d49e1aeSJan Lentfer 		} else if (ssid->wep_key_len[i] > 0) {
4136d49e1aeSJan Lentfer 			wpa_s->pairwise_cipher = WPA_CIPHER_WEP40;
4146d49e1aeSJan Lentfer 			wpa_s->group_cipher = WPA_CIPHER_WEP40;
4156d49e1aeSJan Lentfer 			break;
4166d49e1aeSJan Lentfer 		}
4176d49e1aeSJan Lentfer 	}
4186d49e1aeSJan Lentfer 
4196d49e1aeSJan Lentfer 	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED, 0);
4206d49e1aeSJan Lentfer 	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt);
4216d49e1aeSJan Lentfer 	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE,
4226d49e1aeSJan Lentfer 			 wpa_s->pairwise_cipher);
4236d49e1aeSJan Lentfer 	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
4246d49e1aeSJan Lentfer #ifdef CONFIG_IEEE80211W
4256d49e1aeSJan Lentfer 	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
4266d49e1aeSJan Lentfer 			 wpa_s->mgmt_group_cipher);
4276d49e1aeSJan Lentfer #endif /* CONFIG_IEEE80211W */
4286d49e1aeSJan Lentfer 
4296d49e1aeSJan Lentfer 	pmksa_cache_clear_current(wpa_s->wpa);
4306d49e1aeSJan Lentfer }
4316d49e1aeSJan Lentfer 
4326d49e1aeSJan Lentfer 
free_hw_features(struct wpa_supplicant * wpa_s)4333ff40c12SJohn Marino void free_hw_features(struct wpa_supplicant *wpa_s)
4343ff40c12SJohn Marino {
4353ff40c12SJohn Marino 	int i;
4363ff40c12SJohn Marino 	if (wpa_s->hw.modes == NULL)
4373ff40c12SJohn Marino 		return;
4383ff40c12SJohn Marino 
4393ff40c12SJohn Marino 	for (i = 0; i < wpa_s->hw.num_modes; i++) {
4403ff40c12SJohn Marino 		os_free(wpa_s->hw.modes[i].channels);
4413ff40c12SJohn Marino 		os_free(wpa_s->hw.modes[i].rates);
4423ff40c12SJohn Marino 	}
4433ff40c12SJohn Marino 
4443ff40c12SJohn Marino 	os_free(wpa_s->hw.modes);
4453ff40c12SJohn Marino 	wpa_s->hw.modes = NULL;
4463ff40c12SJohn Marino }
4473ff40c12SJohn Marino 
4483ff40c12SJohn Marino 
free_bss_tmp_disallowed(struct wpa_supplicant * wpa_s)449*a1157835SDaniel Fojt void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s)
450*a1157835SDaniel Fojt {
451*a1157835SDaniel Fojt 	struct wpa_bss_tmp_disallowed *bss, *prev;
452*a1157835SDaniel Fojt 
453*a1157835SDaniel Fojt 	dl_list_for_each_safe(bss, prev, &wpa_s->bss_tmp_disallowed,
454*a1157835SDaniel Fojt 			      struct wpa_bss_tmp_disallowed, list) {
455*a1157835SDaniel Fojt 		eloop_cancel_timeout(wpa_bss_tmp_disallow_timeout, wpa_s, bss);
456*a1157835SDaniel Fojt 		dl_list_del(&bss->list);
457*a1157835SDaniel Fojt 		os_free(bss);
458*a1157835SDaniel Fojt 	}
459*a1157835SDaniel Fojt }
460*a1157835SDaniel Fojt 
461*a1157835SDaniel Fojt 
wpas_flush_fils_hlp_req(struct wpa_supplicant * wpa_s)462*a1157835SDaniel Fojt void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s)
463*a1157835SDaniel Fojt {
464*a1157835SDaniel Fojt 	struct fils_hlp_req *req;
465*a1157835SDaniel Fojt 
466*a1157835SDaniel Fojt 	while ((req = dl_list_first(&wpa_s->fils_hlp_req, struct fils_hlp_req,
467*a1157835SDaniel Fojt 				    list)) != NULL) {
468*a1157835SDaniel Fojt 		dl_list_del(&req->list);
469*a1157835SDaniel Fojt 		wpabuf_free(req->pkt);
470*a1157835SDaniel Fojt 		os_free(req);
471*a1157835SDaniel Fojt 	}
472*a1157835SDaniel Fojt }
473*a1157835SDaniel Fojt 
474*a1157835SDaniel Fojt 
wpa_supplicant_cleanup(struct wpa_supplicant * wpa_s)4756d49e1aeSJan Lentfer static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
4766d49e1aeSJan Lentfer {
477*a1157835SDaniel Fojt 	int i;
478*a1157835SDaniel Fojt 
4793ff40c12SJohn Marino 	bgscan_deinit(wpa_s);
4803ff40c12SJohn Marino 	autoscan_deinit(wpa_s);
4816d49e1aeSJan Lentfer 	scard_deinit(wpa_s->scard);
4826d49e1aeSJan Lentfer 	wpa_s->scard = NULL;
4836d49e1aeSJan Lentfer 	wpa_sm_set_scard_ctx(wpa_s->wpa, NULL);
4846d49e1aeSJan Lentfer 	eapol_sm_register_scard_ctx(wpa_s->eapol, NULL);
4856d49e1aeSJan Lentfer 	l2_packet_deinit(wpa_s->l2);
4866d49e1aeSJan Lentfer 	wpa_s->l2 = NULL;
4876d49e1aeSJan Lentfer 	if (wpa_s->l2_br) {
4886d49e1aeSJan Lentfer 		l2_packet_deinit(wpa_s->l2_br);
4896d49e1aeSJan Lentfer 		wpa_s->l2_br = NULL;
4906d49e1aeSJan Lentfer 	}
491*a1157835SDaniel Fojt #ifdef CONFIG_TESTING_OPTIONS
492*a1157835SDaniel Fojt 	l2_packet_deinit(wpa_s->l2_test);
493*a1157835SDaniel Fojt 	wpa_s->l2_test = NULL;
494*a1157835SDaniel Fojt 	os_free(wpa_s->get_pref_freq_list_override);
495*a1157835SDaniel Fojt 	wpa_s->get_pref_freq_list_override = NULL;
496*a1157835SDaniel Fojt 	wpabuf_free(wpa_s->last_assoc_req_wpa_ie);
497*a1157835SDaniel Fojt 	wpa_s->last_assoc_req_wpa_ie = NULL;
498*a1157835SDaniel Fojt #endif /* CONFIG_TESTING_OPTIONS */
4996d49e1aeSJan Lentfer 
5006d49e1aeSJan Lentfer 	if (wpa_s->conf != NULL) {
5013ff40c12SJohn Marino 		struct wpa_ssid *ssid;
5023ff40c12SJohn Marino 		for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
5033ff40c12SJohn Marino 			wpas_notify_network_removed(wpa_s, ssid);
5046d49e1aeSJan Lentfer 	}
5056d49e1aeSJan Lentfer 
5066d49e1aeSJan Lentfer 	os_free(wpa_s->confname);
5076d49e1aeSJan Lentfer 	wpa_s->confname = NULL;
5086d49e1aeSJan Lentfer 
5093ff40c12SJohn Marino 	os_free(wpa_s->confanother);
5103ff40c12SJohn Marino 	wpa_s->confanother = NULL;
5113ff40c12SJohn Marino 
512*a1157835SDaniel Fojt 	os_free(wpa_s->last_con_fail_realm);
513*a1157835SDaniel Fojt 	wpa_s->last_con_fail_realm = NULL;
514*a1157835SDaniel Fojt 	wpa_s->last_con_fail_realm_len = 0;
515*a1157835SDaniel Fojt 
5166d49e1aeSJan Lentfer 	wpa_sm_set_eapol(wpa_s->wpa, NULL);
5176d49e1aeSJan Lentfer 	eapol_sm_deinit(wpa_s->eapol);
5186d49e1aeSJan Lentfer 	wpa_s->eapol = NULL;
5196d49e1aeSJan Lentfer 
5206d49e1aeSJan Lentfer 	rsn_preauth_deinit(wpa_s->wpa);
5216d49e1aeSJan Lentfer 
5223ff40c12SJohn Marino #ifdef CONFIG_TDLS
5233ff40c12SJohn Marino 	wpa_tdls_deinit(wpa_s->wpa);
5243ff40c12SJohn Marino #endif /* CONFIG_TDLS */
5253ff40c12SJohn Marino 
526*a1157835SDaniel Fojt 	wmm_ac_clear_saved_tspecs(wpa_s);
5276d49e1aeSJan Lentfer 	pmksa_candidate_free(wpa_s->wpa);
5286d49e1aeSJan Lentfer 	wpa_sm_deinit(wpa_s->wpa);
5296d49e1aeSJan Lentfer 	wpa_s->wpa = NULL;
5306d49e1aeSJan Lentfer 	wpa_blacklist_clear(wpa_s);
5316d49e1aeSJan Lentfer 
5323ff40c12SJohn Marino 	wpa_bss_deinit(wpa_s);
5336d49e1aeSJan Lentfer 
5343ff40c12SJohn Marino 	wpa_supplicant_cancel_delayed_sched_scan(wpa_s);
5356d49e1aeSJan Lentfer 	wpa_supplicant_cancel_scan(wpa_s);
5366d49e1aeSJan Lentfer 	wpa_supplicant_cancel_auth_timeout(wpa_s);
5373ff40c12SJohn Marino 	eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL);
5383ff40c12SJohn Marino #ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
5393ff40c12SJohn Marino 	eloop_cancel_timeout(wpa_supplicant_delayed_mic_error_report,
5403ff40c12SJohn Marino 			     wpa_s, NULL);
5413ff40c12SJohn Marino #endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
5426d49e1aeSJan Lentfer 
543*a1157835SDaniel Fojt 	eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
544*a1157835SDaniel Fojt 
5456d49e1aeSJan Lentfer 	wpas_wps_deinit(wpa_s);
5466d49e1aeSJan Lentfer 
5476d49e1aeSJan Lentfer 	wpabuf_free(wpa_s->pending_eapol_rx);
5486d49e1aeSJan Lentfer 	wpa_s->pending_eapol_rx = NULL;
5493ff40c12SJohn Marino 
5503ff40c12SJohn Marino #ifdef CONFIG_IBSS_RSN
5513ff40c12SJohn Marino 	ibss_rsn_deinit(wpa_s->ibss_rsn);
5523ff40c12SJohn Marino 	wpa_s->ibss_rsn = NULL;
5533ff40c12SJohn Marino #endif /* CONFIG_IBSS_RSN */
5543ff40c12SJohn Marino 
5553ff40c12SJohn Marino 	sme_deinit(wpa_s);
5563ff40c12SJohn Marino 
5573ff40c12SJohn Marino #ifdef CONFIG_AP
5583ff40c12SJohn Marino 	wpa_supplicant_ap_deinit(wpa_s);
5593ff40c12SJohn Marino #endif /* CONFIG_AP */
5603ff40c12SJohn Marino 
5613ff40c12SJohn Marino 	wpas_p2p_deinit(wpa_s);
5623ff40c12SJohn Marino 
5633ff40c12SJohn Marino #ifdef CONFIG_OFFCHANNEL
5643ff40c12SJohn Marino 	offchannel_deinit(wpa_s);
5653ff40c12SJohn Marino #endif /* CONFIG_OFFCHANNEL */
5663ff40c12SJohn Marino 
5673ff40c12SJohn Marino 	wpa_supplicant_cancel_sched_scan(wpa_s);
5683ff40c12SJohn Marino 
5693ff40c12SJohn Marino 	os_free(wpa_s->next_scan_freqs);
5703ff40c12SJohn Marino 	wpa_s->next_scan_freqs = NULL;
5713ff40c12SJohn Marino 
5723ff40c12SJohn Marino 	os_free(wpa_s->manual_scan_freqs);
5733ff40c12SJohn Marino 	wpa_s->manual_scan_freqs = NULL;
574*a1157835SDaniel Fojt 	os_free(wpa_s->select_network_scan_freqs);
575*a1157835SDaniel Fojt 	wpa_s->select_network_scan_freqs = NULL;
5763ff40c12SJohn Marino 
577*a1157835SDaniel Fojt 	os_free(wpa_s->manual_sched_scan_freqs);
578*a1157835SDaniel Fojt 	wpa_s->manual_sched_scan_freqs = NULL;
579*a1157835SDaniel Fojt 
580*a1157835SDaniel Fojt 	wpas_mac_addr_rand_scan_clear(wpa_s, MAC_ADDR_RAND_ALL);
581*a1157835SDaniel Fojt 
582*a1157835SDaniel Fojt 	/*
583*a1157835SDaniel Fojt 	 * Need to remove any pending gas-query radio work before the
584*a1157835SDaniel Fojt 	 * gas_query_deinit() call because gas_query::work has not yet been set
585*a1157835SDaniel Fojt 	 * for works that have not been started. gas_query_free() will be unable
586*a1157835SDaniel Fojt 	 * to cancel such pending radio works and once the pending gas-query
587*a1157835SDaniel Fojt 	 * radio work eventually gets removed, the deinit notification call to
588*a1157835SDaniel Fojt 	 * gas_query_start_cb() would result in dereferencing freed memory.
589*a1157835SDaniel Fojt 	 */
590*a1157835SDaniel Fojt 	if (wpa_s->radio)
591*a1157835SDaniel Fojt 		radio_remove_works(wpa_s, "gas-query", 0);
5923ff40c12SJohn Marino 	gas_query_deinit(wpa_s->gas);
5933ff40c12SJohn Marino 	wpa_s->gas = NULL;
594*a1157835SDaniel Fojt 	gas_server_deinit(wpa_s->gas_server);
595*a1157835SDaniel Fojt 	wpa_s->gas_server = NULL;
5963ff40c12SJohn Marino 
5973ff40c12SJohn Marino 	free_hw_features(wpa_s);
5983ff40c12SJohn Marino 
599*a1157835SDaniel Fojt 	ieee802_1x_dealloc_kay_sm(wpa_s);
600*a1157835SDaniel Fojt 
6013ff40c12SJohn Marino 	os_free(wpa_s->bssid_filter);
6023ff40c12SJohn Marino 	wpa_s->bssid_filter = NULL;
6033ff40c12SJohn Marino 
6043ff40c12SJohn Marino 	os_free(wpa_s->disallow_aps_bssid);
6053ff40c12SJohn Marino 	wpa_s->disallow_aps_bssid = NULL;
6063ff40c12SJohn Marino 	os_free(wpa_s->disallow_aps_ssid);
6073ff40c12SJohn Marino 	wpa_s->disallow_aps_ssid = NULL;
6083ff40c12SJohn Marino 
6093ff40c12SJohn Marino 	wnm_bss_keep_alive_deinit(wpa_s);
6103ff40c12SJohn Marino #ifdef CONFIG_WNM
6113ff40c12SJohn Marino 	wnm_deallocate_memory(wpa_s);
6123ff40c12SJohn Marino #endif /* CONFIG_WNM */
6133ff40c12SJohn Marino 
6143ff40c12SJohn Marino 	ext_password_deinit(wpa_s->ext_pw);
6153ff40c12SJohn Marino 	wpa_s->ext_pw = NULL;
6163ff40c12SJohn Marino 
6173ff40c12SJohn Marino 	wpabuf_free(wpa_s->last_gas_resp);
6183ff40c12SJohn Marino 	wpa_s->last_gas_resp = NULL;
6193ff40c12SJohn Marino 	wpabuf_free(wpa_s->prev_gas_resp);
6203ff40c12SJohn Marino 	wpa_s->prev_gas_resp = NULL;
6213ff40c12SJohn Marino 
6223ff40c12SJohn Marino 	os_free(wpa_s->last_scan_res);
6233ff40c12SJohn Marino 	wpa_s->last_scan_res = NULL;
624*a1157835SDaniel Fojt 
625*a1157835SDaniel Fojt #ifdef CONFIG_HS20
626*a1157835SDaniel Fojt 	if (wpa_s->drv_priv)
627*a1157835SDaniel Fojt 		wpa_drv_configure_frame_filters(wpa_s, 0);
628*a1157835SDaniel Fojt 	hs20_deinit(wpa_s);
629*a1157835SDaniel Fojt #endif /* CONFIG_HS20 */
630*a1157835SDaniel Fojt 
631*a1157835SDaniel Fojt 	for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) {
632*a1157835SDaniel Fojt 		wpabuf_free(wpa_s->vendor_elem[i]);
633*a1157835SDaniel Fojt 		wpa_s->vendor_elem[i] = NULL;
634*a1157835SDaniel Fojt 	}
635*a1157835SDaniel Fojt 
636*a1157835SDaniel Fojt 	wmm_ac_notify_disassoc(wpa_s);
637*a1157835SDaniel Fojt 
638*a1157835SDaniel Fojt 	wpa_s->sched_scan_plans_num = 0;
639*a1157835SDaniel Fojt 	os_free(wpa_s->sched_scan_plans);
640*a1157835SDaniel Fojt 	wpa_s->sched_scan_plans = NULL;
641*a1157835SDaniel Fojt 
642*a1157835SDaniel Fojt #ifdef CONFIG_MBO
643*a1157835SDaniel Fojt 	wpa_s->non_pref_chan_num = 0;
644*a1157835SDaniel Fojt 	os_free(wpa_s->non_pref_chan);
645*a1157835SDaniel Fojt 	wpa_s->non_pref_chan = NULL;
646*a1157835SDaniel Fojt #endif /* CONFIG_MBO */
647*a1157835SDaniel Fojt 
648*a1157835SDaniel Fojt 	free_bss_tmp_disallowed(wpa_s);
649*a1157835SDaniel Fojt 
650*a1157835SDaniel Fojt 	wpabuf_free(wpa_s->lci);
651*a1157835SDaniel Fojt 	wpa_s->lci = NULL;
652*a1157835SDaniel Fojt 	wpas_clear_beacon_rep_data(wpa_s);
653*a1157835SDaniel Fojt 
654*a1157835SDaniel Fojt #ifdef CONFIG_PMKSA_CACHE_EXTERNAL
655*a1157835SDaniel Fojt #ifdef CONFIG_MESH
656*a1157835SDaniel Fojt 	{
657*a1157835SDaniel Fojt 		struct external_pmksa_cache *entry;
658*a1157835SDaniel Fojt 
659*a1157835SDaniel Fojt 		while ((entry = dl_list_last(&wpa_s->mesh_external_pmksa_cache,
660*a1157835SDaniel Fojt 					     struct external_pmksa_cache,
661*a1157835SDaniel Fojt 					     list)) != NULL) {
662*a1157835SDaniel Fojt 			dl_list_del(&entry->list);
663*a1157835SDaniel Fojt 			os_free(entry->pmksa_cache);
664*a1157835SDaniel Fojt 			os_free(entry);
665*a1157835SDaniel Fojt 		}
666*a1157835SDaniel Fojt 	}
667*a1157835SDaniel Fojt #endif /* CONFIG_MESH */
668*a1157835SDaniel Fojt #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
669*a1157835SDaniel Fojt 
670*a1157835SDaniel Fojt 	wpas_flush_fils_hlp_req(wpa_s);
671*a1157835SDaniel Fojt 
672*a1157835SDaniel Fojt 	wpabuf_free(wpa_s->ric_ies);
673*a1157835SDaniel Fojt 	wpa_s->ric_ies = NULL;
674*a1157835SDaniel Fojt 
675*a1157835SDaniel Fojt #ifdef CONFIG_DPP
676*a1157835SDaniel Fojt 	wpas_dpp_deinit(wpa_s);
677*a1157835SDaniel Fojt 	dpp_global_deinit(wpa_s->dpp);
678*a1157835SDaniel Fojt 	wpa_s->dpp = NULL;
679*a1157835SDaniel Fojt #endif /* CONFIG_DPP */
6806d49e1aeSJan Lentfer }
6816d49e1aeSJan Lentfer 
6826d49e1aeSJan Lentfer 
6836d49e1aeSJan Lentfer /**
6846d49e1aeSJan Lentfer  * wpa_clear_keys - Clear keys configured for the driver
6856d49e1aeSJan Lentfer  * @wpa_s: Pointer to wpa_supplicant data
6866d49e1aeSJan Lentfer  * @addr: Previously used BSSID or %NULL if not available
6876d49e1aeSJan Lentfer  *
6886d49e1aeSJan Lentfer  * This function clears the encryption keys that has been previously configured
6896d49e1aeSJan Lentfer  * for the driver.
6906d49e1aeSJan Lentfer  */
wpa_clear_keys(struct wpa_supplicant * wpa_s,const u8 * addr)6916d49e1aeSJan Lentfer void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
6926d49e1aeSJan Lentfer {
6933ff40c12SJohn Marino 	int i, max;
6946d49e1aeSJan Lentfer 
6953ff40c12SJohn Marino #ifdef CONFIG_IEEE80211W
6963ff40c12SJohn Marino 	max = 6;
6973ff40c12SJohn Marino #else /* CONFIG_IEEE80211W */
6983ff40c12SJohn Marino 	max = 4;
6993ff40c12SJohn Marino #endif /* CONFIG_IEEE80211W */
7006d49e1aeSJan Lentfer 
7016d49e1aeSJan Lentfer 	/* MLME-DELETEKEYS.request */
7023ff40c12SJohn Marino 	for (i = 0; i < max; i++) {
7033ff40c12SJohn Marino 		if (wpa_s->keys_cleared & BIT(i))
7043ff40c12SJohn Marino 			continue;
7053ff40c12SJohn Marino 		wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, i, 0, NULL, 0,
7063ff40c12SJohn Marino 				NULL, 0);
7073ff40c12SJohn Marino 	}
7083ff40c12SJohn Marino 	if (!(wpa_s->keys_cleared & BIT(0)) && addr &&
7093ff40c12SJohn Marino 	    !is_zero_ether_addr(addr)) {
7106d49e1aeSJan Lentfer 		wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL,
7116d49e1aeSJan Lentfer 				0);
7126d49e1aeSJan Lentfer 		/* MLME-SETPROTECTION.request(None) */
7136d49e1aeSJan Lentfer 		wpa_drv_mlme_setprotection(
7146d49e1aeSJan Lentfer 			wpa_s, addr,
7156d49e1aeSJan Lentfer 			MLME_SETPROTECTION_PROTECT_TYPE_NONE,
7166d49e1aeSJan Lentfer 			MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
7176d49e1aeSJan Lentfer 	}
7183ff40c12SJohn Marino 	wpa_s->keys_cleared = (u32) -1;
7196d49e1aeSJan Lentfer }
7206d49e1aeSJan Lentfer 
7216d49e1aeSJan Lentfer 
7226d49e1aeSJan Lentfer /**
7236d49e1aeSJan Lentfer  * wpa_supplicant_state_txt - Get the connection state name as a text string
7246d49e1aeSJan Lentfer  * @state: State (wpa_state; WPA_*)
7256d49e1aeSJan Lentfer  * Returns: The state name as a printable text string
7266d49e1aeSJan Lentfer  */
wpa_supplicant_state_txt(enum wpa_states state)7273ff40c12SJohn Marino const char * wpa_supplicant_state_txt(enum wpa_states state)
7286d49e1aeSJan Lentfer {
7296d49e1aeSJan Lentfer 	switch (state) {
7306d49e1aeSJan Lentfer 	case WPA_DISCONNECTED:
7316d49e1aeSJan Lentfer 		return "DISCONNECTED";
7326d49e1aeSJan Lentfer 	case WPA_INACTIVE:
7336d49e1aeSJan Lentfer 		return "INACTIVE";
7343ff40c12SJohn Marino 	case WPA_INTERFACE_DISABLED:
7353ff40c12SJohn Marino 		return "INTERFACE_DISABLED";
7366d49e1aeSJan Lentfer 	case WPA_SCANNING:
7376d49e1aeSJan Lentfer 		return "SCANNING";
7383ff40c12SJohn Marino 	case WPA_AUTHENTICATING:
7393ff40c12SJohn Marino 		return "AUTHENTICATING";
7406d49e1aeSJan Lentfer 	case WPA_ASSOCIATING:
7416d49e1aeSJan Lentfer 		return "ASSOCIATING";
7426d49e1aeSJan Lentfer 	case WPA_ASSOCIATED:
7436d49e1aeSJan Lentfer 		return "ASSOCIATED";
7446d49e1aeSJan Lentfer 	case WPA_4WAY_HANDSHAKE:
7456d49e1aeSJan Lentfer 		return "4WAY_HANDSHAKE";
7466d49e1aeSJan Lentfer 	case WPA_GROUP_HANDSHAKE:
7476d49e1aeSJan Lentfer 		return "GROUP_HANDSHAKE";
7486d49e1aeSJan Lentfer 	case WPA_COMPLETED:
7496d49e1aeSJan Lentfer 		return "COMPLETED";
7506d49e1aeSJan Lentfer 	default:
7516d49e1aeSJan Lentfer 		return "UNKNOWN";
7526d49e1aeSJan Lentfer 	}
7536d49e1aeSJan Lentfer }
7546d49e1aeSJan Lentfer 
7556d49e1aeSJan Lentfer 
7563ff40c12SJohn Marino #ifdef CONFIG_BGSCAN
7573ff40c12SJohn Marino 
wpa_supplicant_start_bgscan(struct wpa_supplicant * wpa_s)7583ff40c12SJohn Marino static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
7593ff40c12SJohn Marino {
7603ff40c12SJohn Marino 	const char *name;
7613ff40c12SJohn Marino 
7623ff40c12SJohn Marino 	if (wpa_s->current_ssid && wpa_s->current_ssid->bgscan)
7633ff40c12SJohn Marino 		name = wpa_s->current_ssid->bgscan;
7643ff40c12SJohn Marino 	else
7653ff40c12SJohn Marino 		name = wpa_s->conf->bgscan;
766*a1157835SDaniel Fojt 	if (name == NULL || name[0] == '\0')
7673ff40c12SJohn Marino 		return;
7683ff40c12SJohn Marino 	if (wpas_driver_bss_selection(wpa_s))
7693ff40c12SJohn Marino 		return;
7703ff40c12SJohn Marino 	if (wpa_s->current_ssid == wpa_s->bgscan_ssid)
7713ff40c12SJohn Marino 		return;
772*a1157835SDaniel Fojt #ifdef CONFIG_P2P
773*a1157835SDaniel Fojt 	if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)
774*a1157835SDaniel Fojt 		return;
775*a1157835SDaniel Fojt #endif /* CONFIG_P2P */
7763ff40c12SJohn Marino 
7773ff40c12SJohn Marino 	bgscan_deinit(wpa_s);
7783ff40c12SJohn Marino 	if (wpa_s->current_ssid) {
7793ff40c12SJohn Marino 		if (bgscan_init(wpa_s, wpa_s->current_ssid, name)) {
7803ff40c12SJohn Marino 			wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
7813ff40c12SJohn Marino 				"bgscan");
7823ff40c12SJohn Marino 			/*
7833ff40c12SJohn Marino 			 * Live without bgscan; it is only used as a roaming
7843ff40c12SJohn Marino 			 * optimization, so the initial connection is not
7853ff40c12SJohn Marino 			 * affected.
7863ff40c12SJohn Marino 			 */
7873ff40c12SJohn Marino 		} else {
7883ff40c12SJohn Marino 			struct wpa_scan_results *scan_res;
7893ff40c12SJohn Marino 			wpa_s->bgscan_ssid = wpa_s->current_ssid;
7903ff40c12SJohn Marino 			scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL,
7913ff40c12SJohn Marino 								   0);
7923ff40c12SJohn Marino 			if (scan_res) {
7933ff40c12SJohn Marino 				bgscan_notify_scan(wpa_s, scan_res);
7943ff40c12SJohn Marino 				wpa_scan_results_free(scan_res);
7953ff40c12SJohn Marino 			}
7963ff40c12SJohn Marino 		}
7973ff40c12SJohn Marino 	} else
7983ff40c12SJohn Marino 		wpa_s->bgscan_ssid = NULL;
7993ff40c12SJohn Marino }
8003ff40c12SJohn Marino 
8013ff40c12SJohn Marino 
wpa_supplicant_stop_bgscan(struct wpa_supplicant * wpa_s)8023ff40c12SJohn Marino static void wpa_supplicant_stop_bgscan(struct wpa_supplicant *wpa_s)
8033ff40c12SJohn Marino {
8043ff40c12SJohn Marino 	if (wpa_s->bgscan_ssid != NULL) {
8053ff40c12SJohn Marino 		bgscan_deinit(wpa_s);
8063ff40c12SJohn Marino 		wpa_s->bgscan_ssid = NULL;
8073ff40c12SJohn Marino 	}
8083ff40c12SJohn Marino }
8093ff40c12SJohn Marino 
8103ff40c12SJohn Marino #endif /* CONFIG_BGSCAN */
8113ff40c12SJohn Marino 
8123ff40c12SJohn Marino 
wpa_supplicant_start_autoscan(struct wpa_supplicant * wpa_s)8133ff40c12SJohn Marino static void wpa_supplicant_start_autoscan(struct wpa_supplicant *wpa_s)
8143ff40c12SJohn Marino {
8153ff40c12SJohn Marino 	if (autoscan_init(wpa_s, 0))
8163ff40c12SJohn Marino 		wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize autoscan");
8173ff40c12SJohn Marino }
8183ff40c12SJohn Marino 
8193ff40c12SJohn Marino 
wpa_supplicant_stop_autoscan(struct wpa_supplicant * wpa_s)8203ff40c12SJohn Marino static void wpa_supplicant_stop_autoscan(struct wpa_supplicant *wpa_s)
8213ff40c12SJohn Marino {
8223ff40c12SJohn Marino 	autoscan_deinit(wpa_s);
8233ff40c12SJohn Marino }
8243ff40c12SJohn Marino 
8253ff40c12SJohn Marino 
wpa_supplicant_reinit_autoscan(struct wpa_supplicant * wpa_s)8263ff40c12SJohn Marino void wpa_supplicant_reinit_autoscan(struct wpa_supplicant *wpa_s)
8273ff40c12SJohn Marino {
8283ff40c12SJohn Marino 	if (wpa_s->wpa_state == WPA_DISCONNECTED ||
8293ff40c12SJohn Marino 	    wpa_s->wpa_state == WPA_SCANNING) {
8303ff40c12SJohn Marino 		autoscan_deinit(wpa_s);
8313ff40c12SJohn Marino 		wpa_supplicant_start_autoscan(wpa_s);
8323ff40c12SJohn Marino 	}
8333ff40c12SJohn Marino }
8343ff40c12SJohn Marino 
8353ff40c12SJohn Marino 
8366d49e1aeSJan Lentfer /**
8376d49e1aeSJan Lentfer  * wpa_supplicant_set_state - Set current connection state
8386d49e1aeSJan Lentfer  * @wpa_s: Pointer to wpa_supplicant data
8396d49e1aeSJan Lentfer  * @state: The new connection state
8406d49e1aeSJan Lentfer  *
8416d49e1aeSJan Lentfer  * This function is called whenever the connection state changes, e.g.,
8426d49e1aeSJan Lentfer  * association is completed for WPA/WPA2 4-Way Handshake is started.
8436d49e1aeSJan Lentfer  */
wpa_supplicant_set_state(struct wpa_supplicant * wpa_s,enum wpa_states state)8443ff40c12SJohn Marino void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
8453ff40c12SJohn Marino 			      enum wpa_states state)
8466d49e1aeSJan Lentfer {
8473ff40c12SJohn Marino 	enum wpa_states old_state = wpa_s->wpa_state;
8483ff40c12SJohn Marino 
8493ff40c12SJohn Marino 	wpa_dbg(wpa_s, MSG_DEBUG, "State: %s -> %s",
8506d49e1aeSJan Lentfer 		wpa_supplicant_state_txt(wpa_s->wpa_state),
8516d49e1aeSJan Lentfer 		wpa_supplicant_state_txt(state));
8526d49e1aeSJan Lentfer 
853*a1157835SDaniel Fojt 	if (state == WPA_COMPLETED &&
854*a1157835SDaniel Fojt 	    os_reltime_initialized(&wpa_s->roam_start)) {
855*a1157835SDaniel Fojt 		os_reltime_age(&wpa_s->roam_start, &wpa_s->roam_time);
856*a1157835SDaniel Fojt 		wpa_s->roam_start.sec = 0;
857*a1157835SDaniel Fojt 		wpa_s->roam_start.usec = 0;
858*a1157835SDaniel Fojt 		wpas_notify_auth_changed(wpa_s);
859*a1157835SDaniel Fojt 		wpas_notify_roam_time(wpa_s);
860*a1157835SDaniel Fojt 		wpas_notify_roam_complete(wpa_s);
861*a1157835SDaniel Fojt 	} else if (state == WPA_DISCONNECTED &&
862*a1157835SDaniel Fojt 		   os_reltime_initialized(&wpa_s->roam_start)) {
863*a1157835SDaniel Fojt 		wpa_s->roam_start.sec = 0;
864*a1157835SDaniel Fojt 		wpa_s->roam_start.usec = 0;
865*a1157835SDaniel Fojt 		wpa_s->roam_time.sec = 0;
866*a1157835SDaniel Fojt 		wpa_s->roam_time.usec = 0;
867*a1157835SDaniel Fojt 		wpas_notify_roam_complete(wpa_s);
868*a1157835SDaniel Fojt 	}
869*a1157835SDaniel Fojt 
8703ff40c12SJohn Marino 	if (state == WPA_INTERFACE_DISABLED) {
8713ff40c12SJohn Marino 		/* Assure normal scan when interface is restored */
8723ff40c12SJohn Marino 		wpa_s->normal_scans = 0;
8733ff40c12SJohn Marino 	}
8743ff40c12SJohn Marino 
875*a1157835SDaniel Fojt 	if (state == WPA_COMPLETED) {
8763ff40c12SJohn Marino 		wpas_connect_work_done(wpa_s);
877*a1157835SDaniel Fojt 		/* Reinitialize normal_scan counter */
878*a1157835SDaniel Fojt 		wpa_s->normal_scans = 0;
879*a1157835SDaniel Fojt 	}
880*a1157835SDaniel Fojt 
881*a1157835SDaniel Fojt #ifdef CONFIG_P2P
882*a1157835SDaniel Fojt 	/*
883*a1157835SDaniel Fojt 	 * P2PS client has to reply to Probe Request frames received on the
884*a1157835SDaniel Fojt 	 * group operating channel. Enable Probe Request frame reporting for
885*a1157835SDaniel Fojt 	 * P2P connected client in case p2p_cli_probe configuration property is
886*a1157835SDaniel Fojt 	 * set to 1.
887*a1157835SDaniel Fojt 	 */
888*a1157835SDaniel Fojt 	if (wpa_s->conf->p2p_cli_probe && wpa_s->current_ssid &&
889*a1157835SDaniel Fojt 	    wpa_s->current_ssid->mode == WPAS_MODE_INFRA &&
890*a1157835SDaniel Fojt 	    wpa_s->current_ssid->p2p_group) {
891*a1157835SDaniel Fojt 		if (state == WPA_COMPLETED && !wpa_s->p2p_cli_probe) {
892*a1157835SDaniel Fojt 			wpa_dbg(wpa_s, MSG_DEBUG,
893*a1157835SDaniel Fojt 				"P2P: Enable CLI Probe Request RX reporting");
894*a1157835SDaniel Fojt 			wpa_s->p2p_cli_probe =
895*a1157835SDaniel Fojt 				wpa_drv_probe_req_report(wpa_s, 1) >= 0;
896*a1157835SDaniel Fojt 		} else if (state != WPA_COMPLETED && wpa_s->p2p_cli_probe) {
897*a1157835SDaniel Fojt 			wpa_dbg(wpa_s, MSG_DEBUG,
898*a1157835SDaniel Fojt 				"P2P: Disable CLI Probe Request RX reporting");
899*a1157835SDaniel Fojt 			wpa_s->p2p_cli_probe = 0;
900*a1157835SDaniel Fojt 			wpa_drv_probe_req_report(wpa_s, 0);
901*a1157835SDaniel Fojt 		}
902*a1157835SDaniel Fojt 	}
903*a1157835SDaniel Fojt #endif /* CONFIG_P2P */
9043ff40c12SJohn Marino 
9056d49e1aeSJan Lentfer 	if (state != WPA_SCANNING)
9066d49e1aeSJan Lentfer 		wpa_supplicant_notify_scanning(wpa_s, 0);
9076d49e1aeSJan Lentfer 
9086d49e1aeSJan Lentfer 	if (state == WPA_COMPLETED && wpa_s->new_connection) {
9096d49e1aeSJan Lentfer 		struct wpa_ssid *ssid = wpa_s->current_ssid;
910*a1157835SDaniel Fojt 		int fils_hlp_sent = 0;
911*a1157835SDaniel Fojt 
912*a1157835SDaniel Fojt #ifdef CONFIG_SME
913*a1157835SDaniel Fojt 		if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
914*a1157835SDaniel Fojt 		    wpa_auth_alg_fils(wpa_s->sme.auth_alg))
915*a1157835SDaniel Fojt 			fils_hlp_sent = 1;
916*a1157835SDaniel Fojt #endif /* CONFIG_SME */
917*a1157835SDaniel Fojt 		if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
918*a1157835SDaniel Fojt 		    wpa_auth_alg_fils(wpa_s->auth_alg))
919*a1157835SDaniel Fojt 			fils_hlp_sent = 1;
920*a1157835SDaniel Fojt 
9213ff40c12SJohn Marino #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
9226d49e1aeSJan Lentfer 		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- Connection to "
923*a1157835SDaniel Fojt 			MACSTR " completed [id=%d id_str=%s%s]",
9243ff40c12SJohn Marino 			MAC2STR(wpa_s->bssid),
9256d49e1aeSJan Lentfer 			ssid ? ssid->id : -1,
926*a1157835SDaniel Fojt 			ssid && ssid->id_str ? ssid->id_str : "",
927*a1157835SDaniel Fojt 			fils_hlp_sent ? " FILS_HLP_SENT" : "");
9286d49e1aeSJan Lentfer #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
9293ff40c12SJohn Marino 		wpas_clear_temp_disabled(wpa_s, ssid, 1);
930*a1157835SDaniel Fojt 		wpa_blacklist_clear(wpa_s);
9313ff40c12SJohn Marino 		wpa_s->extra_blacklist_count = 0;
9326d49e1aeSJan Lentfer 		wpa_s->new_connection = 0;
9336d49e1aeSJan Lentfer 		wpa_drv_set_operstate(wpa_s, 1);
9343ff40c12SJohn Marino #ifndef IEEE8021X_EAPOL
9353ff40c12SJohn Marino 		wpa_drv_set_supp_port(wpa_s, 1);
9363ff40c12SJohn Marino #endif /* IEEE8021X_EAPOL */
9373ff40c12SJohn Marino 		wpa_s->after_wps = 0;
9383ff40c12SJohn Marino 		wpa_s->known_wps_freq = 0;
9393ff40c12SJohn Marino 		wpas_p2p_completed(wpa_s);
9403ff40c12SJohn Marino 
9413ff40c12SJohn Marino 		sme_sched_obss_scan(wpa_s, 1);
942*a1157835SDaniel Fojt 
943*a1157835SDaniel Fojt #if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
944*a1157835SDaniel Fojt 		if (!fils_hlp_sent && ssid && ssid->eap.erp)
945*a1157835SDaniel Fojt 			wpas_update_fils_connect_params(wpa_s);
946*a1157835SDaniel Fojt #endif /* CONFIG_FILS && IEEE8021X_EAPOL */
9476d49e1aeSJan Lentfer 	} else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
9486d49e1aeSJan Lentfer 		   state == WPA_ASSOCIATED) {
9496d49e1aeSJan Lentfer 		wpa_s->new_connection = 1;
9506d49e1aeSJan Lentfer 		wpa_drv_set_operstate(wpa_s, 0);
9513ff40c12SJohn Marino #ifndef IEEE8021X_EAPOL
9523ff40c12SJohn Marino 		wpa_drv_set_supp_port(wpa_s, 0);
9533ff40c12SJohn Marino #endif /* IEEE8021X_EAPOL */
9543ff40c12SJohn Marino 		sme_sched_obss_scan(wpa_s, 0);
9556d49e1aeSJan Lentfer 	}
9566d49e1aeSJan Lentfer 	wpa_s->wpa_state = state;
9573ff40c12SJohn Marino 
9583ff40c12SJohn Marino #ifdef CONFIG_BGSCAN
9593ff40c12SJohn Marino 	if (state == WPA_COMPLETED)
9603ff40c12SJohn Marino 		wpa_supplicant_start_bgscan(wpa_s);
9613ff40c12SJohn Marino 	else if (state < WPA_ASSOCIATED)
9623ff40c12SJohn Marino 		wpa_supplicant_stop_bgscan(wpa_s);
9633ff40c12SJohn Marino #endif /* CONFIG_BGSCAN */
9643ff40c12SJohn Marino 
965*a1157835SDaniel Fojt 	if (state > WPA_SCANNING)
9663ff40c12SJohn Marino 		wpa_supplicant_stop_autoscan(wpa_s);
9673ff40c12SJohn Marino 
9683ff40c12SJohn Marino 	if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
9693ff40c12SJohn Marino 		wpa_supplicant_start_autoscan(wpa_s);
9703ff40c12SJohn Marino 
971*a1157835SDaniel Fojt 	if (old_state >= WPA_ASSOCIATED && wpa_s->wpa_state < WPA_ASSOCIATED)
972*a1157835SDaniel Fojt 		wmm_ac_notify_disassoc(wpa_s);
973*a1157835SDaniel Fojt 
9743ff40c12SJohn Marino 	if (wpa_s->wpa_state != old_state) {
9753ff40c12SJohn Marino 		wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
9763ff40c12SJohn Marino 
977*a1157835SDaniel Fojt 		/*
978*a1157835SDaniel Fojt 		 * Notify the P2P Device interface about a state change in one
979*a1157835SDaniel Fojt 		 * of the interfaces.
980*a1157835SDaniel Fojt 		 */
981*a1157835SDaniel Fojt 		wpas_p2p_indicate_state_change(wpa_s);
982*a1157835SDaniel Fojt 
9833ff40c12SJohn Marino 		if (wpa_s->wpa_state == WPA_COMPLETED ||
9843ff40c12SJohn Marino 		    old_state == WPA_COMPLETED)
9853ff40c12SJohn Marino 			wpas_notify_auth_changed(wpa_s);
9863ff40c12SJohn Marino 	}
9876d49e1aeSJan Lentfer }
9886d49e1aeSJan Lentfer 
9896d49e1aeSJan Lentfer 
wpa_supplicant_terminate_proc(struct wpa_global * global)9903ff40c12SJohn Marino void wpa_supplicant_terminate_proc(struct wpa_global *global)
9916d49e1aeSJan Lentfer {
9923ff40c12SJohn Marino 	int pending = 0;
9933ff40c12SJohn Marino #ifdef CONFIG_WPS
9943ff40c12SJohn Marino 	struct wpa_supplicant *wpa_s = global->ifaces;
9953ff40c12SJohn Marino 	while (wpa_s) {
9963ff40c12SJohn Marino 		struct wpa_supplicant *next = wpa_s->next;
997*a1157835SDaniel Fojt 		if (wpas_wps_terminate_pending(wpa_s) == 1)
998*a1157835SDaniel Fojt 			pending = 1;
9993ff40c12SJohn Marino #ifdef CONFIG_P2P
10003ff40c12SJohn Marino 		if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE ||
10013ff40c12SJohn Marino 		    (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group))
10023ff40c12SJohn Marino 			wpas_p2p_disconnect(wpa_s);
10033ff40c12SJohn Marino #endif /* CONFIG_P2P */
10043ff40c12SJohn Marino 		wpa_s = next;
10056d49e1aeSJan Lentfer 	}
10063ff40c12SJohn Marino #endif /* CONFIG_WPS */
10073ff40c12SJohn Marino 	if (pending)
10083ff40c12SJohn Marino 		return;
10096d49e1aeSJan Lentfer 	eloop_terminate();
10106d49e1aeSJan Lentfer }
10116d49e1aeSJan Lentfer 
10126d49e1aeSJan Lentfer 
wpa_supplicant_terminate(int sig,void * signal_ctx)10133ff40c12SJohn Marino static void wpa_supplicant_terminate(int sig, void *signal_ctx)
10146d49e1aeSJan Lentfer {
10153ff40c12SJohn Marino 	struct wpa_global *global = signal_ctx;
10163ff40c12SJohn Marino 	wpa_supplicant_terminate_proc(global);
10173ff40c12SJohn Marino }
10183ff40c12SJohn Marino 
10193ff40c12SJohn Marino 
wpa_supplicant_clear_status(struct wpa_supplicant * wpa_s)10203ff40c12SJohn Marino void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
10213ff40c12SJohn Marino {
10223ff40c12SJohn Marino 	enum wpa_states old_state = wpa_s->wpa_state;
10233ff40c12SJohn Marino 
10246d49e1aeSJan Lentfer 	wpa_s->pairwise_cipher = 0;
10256d49e1aeSJan Lentfer 	wpa_s->group_cipher = 0;
10266d49e1aeSJan Lentfer 	wpa_s->mgmt_group_cipher = 0;
10276d49e1aeSJan Lentfer 	wpa_s->key_mgmt = 0;
10283ff40c12SJohn Marino 	if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED)
10293ff40c12SJohn Marino 		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
10303ff40c12SJohn Marino 
10313ff40c12SJohn Marino 	if (wpa_s->wpa_state != old_state)
10323ff40c12SJohn Marino 		wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
10336d49e1aeSJan Lentfer }
10346d49e1aeSJan Lentfer 
10356d49e1aeSJan Lentfer 
10366d49e1aeSJan Lentfer /**
10376d49e1aeSJan Lentfer  * wpa_supplicant_reload_configuration - Reload configuration data
10386d49e1aeSJan Lentfer  * @wpa_s: Pointer to wpa_supplicant data
10396d49e1aeSJan Lentfer  * Returns: 0 on success or -1 if configuration parsing failed
10406d49e1aeSJan Lentfer  *
10416d49e1aeSJan Lentfer  * This function can be used to request that the configuration data is reloaded
10426d49e1aeSJan Lentfer  * (e.g., after configuration file change). This function is reloading
10436d49e1aeSJan Lentfer  * configuration only for one interface, so this may need to be called multiple
10446d49e1aeSJan Lentfer  * times if %wpa_supplicant is controlling multiple interfaces and all
10456d49e1aeSJan Lentfer  * interfaces need reconfiguration.
10466d49e1aeSJan Lentfer  */
wpa_supplicant_reload_configuration(struct wpa_supplicant * wpa_s)10476d49e1aeSJan Lentfer int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
10486d49e1aeSJan Lentfer {
10496d49e1aeSJan Lentfer 	struct wpa_config *conf;
10506d49e1aeSJan Lentfer 	int reconf_ctrl;
10513ff40c12SJohn Marino 	int old_ap_scan;
10523ff40c12SJohn Marino 
10536d49e1aeSJan Lentfer 	if (wpa_s->confname == NULL)
10546d49e1aeSJan Lentfer 		return -1;
10553ff40c12SJohn Marino 	conf = wpa_config_read(wpa_s->confname, NULL);
10566d49e1aeSJan Lentfer 	if (conf == NULL) {
10576d49e1aeSJan Lentfer 		wpa_msg(wpa_s, MSG_ERROR, "Failed to parse the configuration "
10586d49e1aeSJan Lentfer 			"file '%s' - exiting", wpa_s->confname);
10596d49e1aeSJan Lentfer 		return -1;
10606d49e1aeSJan Lentfer 	}
1061*a1157835SDaniel Fojt 	if (wpa_s->confanother &&
1062*a1157835SDaniel Fojt 	    !wpa_config_read(wpa_s->confanother, conf)) {
1063*a1157835SDaniel Fojt 		wpa_msg(wpa_s, MSG_ERROR,
1064*a1157835SDaniel Fojt 			"Failed to parse the configuration file '%s' - exiting",
1065*a1157835SDaniel Fojt 			wpa_s->confanother);
1066*a1157835SDaniel Fojt 		return -1;
1067*a1157835SDaniel Fojt 	}
10683ff40c12SJohn Marino 
10693ff40c12SJohn Marino 	conf->changed_parameters = (unsigned int) -1;
10706d49e1aeSJan Lentfer 
10716d49e1aeSJan Lentfer 	reconf_ctrl = !!conf->ctrl_interface != !!wpa_s->conf->ctrl_interface
10726d49e1aeSJan Lentfer 		|| (conf->ctrl_interface && wpa_s->conf->ctrl_interface &&
10736d49e1aeSJan Lentfer 		    os_strcmp(conf->ctrl_interface,
10746d49e1aeSJan Lentfer 			      wpa_s->conf->ctrl_interface) != 0);
10756d49e1aeSJan Lentfer 
10766d49e1aeSJan Lentfer 	if (reconf_ctrl && wpa_s->ctrl_iface) {
10776d49e1aeSJan Lentfer 		wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
10786d49e1aeSJan Lentfer 		wpa_s->ctrl_iface = NULL;
10796d49e1aeSJan Lentfer 	}
10806d49e1aeSJan Lentfer 
10816d49e1aeSJan Lentfer 	eapol_sm_invalidate_cached_session(wpa_s->eapol);
10823ff40c12SJohn Marino 	if (wpa_s->current_ssid) {
1083*a1157835SDaniel Fojt 		if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
1084*a1157835SDaniel Fojt 			wpa_s->own_disconnect_req = 1;
10853ff40c12SJohn Marino 		wpa_supplicant_deauthenticate(wpa_s,
10863ff40c12SJohn Marino 					      WLAN_REASON_DEAUTH_LEAVING);
10873ff40c12SJohn Marino 	}
10883ff40c12SJohn Marino 
10896d49e1aeSJan Lentfer 	/*
10906d49e1aeSJan Lentfer 	 * TODO: should notify EAPOL SM about changes in opensc_engine_path,
1091*a1157835SDaniel Fojt 	 * pkcs11_engine_path, pkcs11_module_path, openssl_ciphers.
10926d49e1aeSJan Lentfer 	 */
1093*a1157835SDaniel Fojt 	if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
1094*a1157835SDaniel Fojt 	    wpa_s->key_mgmt == WPA_KEY_MGMT_OWE ||
1095*a1157835SDaniel Fojt 	    wpa_s->key_mgmt == WPA_KEY_MGMT_DPP) {
10966d49e1aeSJan Lentfer 		/*
10976d49e1aeSJan Lentfer 		 * Clear forced success to clear EAP state for next
10986d49e1aeSJan Lentfer 		 * authentication.
10996d49e1aeSJan Lentfer 		 */
11006d49e1aeSJan Lentfer 		eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
11016d49e1aeSJan Lentfer 	}
11026d49e1aeSJan Lentfer 	eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
11036d49e1aeSJan Lentfer 	wpa_sm_set_config(wpa_s->wpa, NULL);
11043ff40c12SJohn Marino 	wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
11056d49e1aeSJan Lentfer 	wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
11066d49e1aeSJan Lentfer 	rsn_preauth_deinit(wpa_s->wpa);
11073ff40c12SJohn Marino 
11083ff40c12SJohn Marino 	old_ap_scan = wpa_s->conf->ap_scan;
11096d49e1aeSJan Lentfer 	wpa_config_free(wpa_s->conf);
11106d49e1aeSJan Lentfer 	wpa_s->conf = conf;
11113ff40c12SJohn Marino 	if (old_ap_scan != wpa_s->conf->ap_scan)
11123ff40c12SJohn Marino 		wpas_notify_ap_scan_changed(wpa_s);
11133ff40c12SJohn Marino 
11146d49e1aeSJan Lentfer 	if (reconf_ctrl)
11156d49e1aeSJan Lentfer 		wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
11166d49e1aeSJan Lentfer 
11173ff40c12SJohn Marino 	wpa_supplicant_update_config(wpa_s);
11183ff40c12SJohn Marino 
11196d49e1aeSJan Lentfer 	wpa_supplicant_clear_status(wpa_s);
11203ff40c12SJohn Marino 	if (wpa_supplicant_enabled_networks(wpa_s)) {
11216d49e1aeSJan Lentfer 		wpa_s->reassociate = 1;
11226d49e1aeSJan Lentfer 		wpa_supplicant_req_scan(wpa_s, 0, 0);
11233ff40c12SJohn Marino 	}
11243ff40c12SJohn Marino 	wpa_dbg(wpa_s, MSG_DEBUG, "Reconfiguration completed");
11256d49e1aeSJan Lentfer 	return 0;
11266d49e1aeSJan Lentfer }
11276d49e1aeSJan Lentfer 
11286d49e1aeSJan Lentfer 
wpa_supplicant_reconfig(int sig,void * signal_ctx)11293ff40c12SJohn Marino static void wpa_supplicant_reconfig(int sig, void *signal_ctx)
11306d49e1aeSJan Lentfer {
11313ff40c12SJohn Marino 	struct wpa_global *global = signal_ctx;
11326d49e1aeSJan Lentfer 	struct wpa_supplicant *wpa_s;
11336d49e1aeSJan Lentfer 	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
11343ff40c12SJohn Marino 		wpa_dbg(wpa_s, MSG_DEBUG, "Signal %d received - reconfiguring",
11353ff40c12SJohn Marino 			sig);
11366d49e1aeSJan Lentfer 		if (wpa_supplicant_reload_configuration(wpa_s) < 0) {
11373ff40c12SJohn Marino 			wpa_supplicant_terminate_proc(global);
11386d49e1aeSJan Lentfer 		}
11396d49e1aeSJan Lentfer 	}
1140*a1157835SDaniel Fojt 
1141*a1157835SDaniel Fojt 	if (wpa_debug_reopen_file() < 0) {
1142*a1157835SDaniel Fojt 		/* Ignore errors since we cannot really do much to fix this */
1143*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "Could not reopen debug log file");
1144*a1157835SDaniel Fojt 	}
11456d49e1aeSJan Lentfer }
11466d49e1aeSJan Lentfer 
11476d49e1aeSJan Lentfer 
wpa_supplicant_suites_from_ai(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid,struct wpa_ie_data * ie)11486d49e1aeSJan Lentfer static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
11496d49e1aeSJan Lentfer 					 struct wpa_ssid *ssid,
11506d49e1aeSJan Lentfer 					 struct wpa_ie_data *ie)
11516d49e1aeSJan Lentfer {
11526d49e1aeSJan Lentfer 	int ret = wpa_sm_parse_own_wpa_ie(wpa_s->wpa, ie);
11536d49e1aeSJan Lentfer 	if (ret) {
11546d49e1aeSJan Lentfer 		if (ret == -2) {
11556d49e1aeSJan Lentfer 			wpa_msg(wpa_s, MSG_INFO, "WPA: Failed to parse WPA IE "
11566d49e1aeSJan Lentfer 				"from association info");
11576d49e1aeSJan Lentfer 		}
11586d49e1aeSJan Lentfer 		return -1;
11596d49e1aeSJan Lentfer 	}
11606d49e1aeSJan Lentfer 
11613ff40c12SJohn Marino 	wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Using WPA IE from AssocReq to set "
11623ff40c12SJohn Marino 		"cipher suites");
11636d49e1aeSJan Lentfer 	if (!(ie->group_cipher & ssid->group_cipher)) {
11646d49e1aeSJan Lentfer 		wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled group "
11656d49e1aeSJan Lentfer 			"cipher 0x%x (mask 0x%x) - reject",
11666d49e1aeSJan Lentfer 			ie->group_cipher, ssid->group_cipher);
11676d49e1aeSJan Lentfer 		return -1;
11686d49e1aeSJan Lentfer 	}
11696d49e1aeSJan Lentfer 	if (!(ie->pairwise_cipher & ssid->pairwise_cipher)) {
11706d49e1aeSJan Lentfer 		wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled pairwise "
11716d49e1aeSJan Lentfer 			"cipher 0x%x (mask 0x%x) - reject",
11726d49e1aeSJan Lentfer 			ie->pairwise_cipher, ssid->pairwise_cipher);
11736d49e1aeSJan Lentfer 		return -1;
11746d49e1aeSJan Lentfer 	}
11756d49e1aeSJan Lentfer 	if (!(ie->key_mgmt & ssid->key_mgmt)) {
11766d49e1aeSJan Lentfer 		wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled key "
11776d49e1aeSJan Lentfer 			"management 0x%x (mask 0x%x) - reject",
11786d49e1aeSJan Lentfer 			ie->key_mgmt, ssid->key_mgmt);
11796d49e1aeSJan Lentfer 		return -1;
11806d49e1aeSJan Lentfer 	}
11816d49e1aeSJan Lentfer 
11826d49e1aeSJan Lentfer #ifdef CONFIG_IEEE80211W
11836d49e1aeSJan Lentfer 	if (!(ie->capabilities & WPA_CAPABILITY_MFPC) &&
1184*a1157835SDaniel Fojt 	    wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) {
11856d49e1aeSJan Lentfer 		wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP "
11866d49e1aeSJan Lentfer 			"that does not support management frame protection - "
11876d49e1aeSJan Lentfer 			"reject");
11886d49e1aeSJan Lentfer 		return -1;
11896d49e1aeSJan Lentfer 	}
11906d49e1aeSJan Lentfer #endif /* CONFIG_IEEE80211W */
11916d49e1aeSJan Lentfer 
11926d49e1aeSJan Lentfer 	return 0;
11936d49e1aeSJan Lentfer }
11946d49e1aeSJan Lentfer 
11956d49e1aeSJan Lentfer 
matching_ciphers(struct wpa_ssid * ssid,struct wpa_ie_data * ie,int freq)1196*a1157835SDaniel Fojt static int matching_ciphers(struct wpa_ssid *ssid, struct wpa_ie_data *ie,
1197*a1157835SDaniel Fojt 			    int freq)
1198*a1157835SDaniel Fojt {
1199*a1157835SDaniel Fojt 	if (!ie->has_group)
1200*a1157835SDaniel Fojt 		ie->group_cipher = wpa_default_rsn_cipher(freq);
1201*a1157835SDaniel Fojt 	if (!ie->has_pairwise)
1202*a1157835SDaniel Fojt 		ie->pairwise_cipher = wpa_default_rsn_cipher(freq);
1203*a1157835SDaniel Fojt 	return (ie->group_cipher & ssid->group_cipher) &&
1204*a1157835SDaniel Fojt 		(ie->pairwise_cipher & ssid->pairwise_cipher);
1205*a1157835SDaniel Fojt }
1206*a1157835SDaniel Fojt 
1207*a1157835SDaniel Fojt 
12086d49e1aeSJan Lentfer /**
12096d49e1aeSJan Lentfer  * wpa_supplicant_set_suites - Set authentication and encryption parameters
12106d49e1aeSJan Lentfer  * @wpa_s: Pointer to wpa_supplicant data
12116d49e1aeSJan Lentfer  * @bss: Scan results for the selected BSS, or %NULL if not available
12126d49e1aeSJan Lentfer  * @ssid: Configuration data for the selected network
12136d49e1aeSJan Lentfer  * @wpa_ie: Buffer for the WPA/RSN IE
12146d49e1aeSJan Lentfer  * @wpa_ie_len: Maximum wpa_ie buffer size on input. This is changed to be the
12156d49e1aeSJan Lentfer  * used buffer length in case the functions returns success.
12166d49e1aeSJan Lentfer  * Returns: 0 on success or -1 on failure
12176d49e1aeSJan Lentfer  *
12186d49e1aeSJan Lentfer  * This function is used to configure authentication and encryption parameters
12196d49e1aeSJan Lentfer  * based on the network configuration and scan result for the selected BSS (if
12206d49e1aeSJan Lentfer  * available).
12216d49e1aeSJan Lentfer  */
wpa_supplicant_set_suites(struct wpa_supplicant * wpa_s,struct wpa_bss * bss,struct wpa_ssid * ssid,u8 * wpa_ie,size_t * wpa_ie_len)12226d49e1aeSJan Lentfer int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
12233ff40c12SJohn Marino 			      struct wpa_bss *bss, struct wpa_ssid *ssid,
12246d49e1aeSJan Lentfer 			      u8 *wpa_ie, size_t *wpa_ie_len)
12256d49e1aeSJan Lentfer {
12266d49e1aeSJan Lentfer 	struct wpa_ie_data ie;
12276d49e1aeSJan Lentfer 	int sel, proto;
1228*a1157835SDaniel Fojt 	const u8 *bss_wpa, *bss_rsn, *bss_osen;
12296d49e1aeSJan Lentfer 
12306d49e1aeSJan Lentfer 	if (bss) {
12313ff40c12SJohn Marino 		bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
12323ff40c12SJohn Marino 		bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
1233*a1157835SDaniel Fojt 		bss_osen = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
12346d49e1aeSJan Lentfer 	} else
1235*a1157835SDaniel Fojt 		bss_wpa = bss_rsn = bss_osen = NULL;
12366d49e1aeSJan Lentfer 
12376d49e1aeSJan Lentfer 	if (bss_rsn && (ssid->proto & WPA_PROTO_RSN) &&
12386d49e1aeSJan Lentfer 	    wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 &&
1239*a1157835SDaniel Fojt 	    matching_ciphers(ssid, &ie, bss->freq) &&
12406d49e1aeSJan Lentfer 	    (ie.key_mgmt & ssid->key_mgmt)) {
12413ff40c12SJohn Marino 		wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0");
12426d49e1aeSJan Lentfer 		proto = WPA_PROTO_RSN;
12436d49e1aeSJan Lentfer 	} else if (bss_wpa && (ssid->proto & WPA_PROTO_WPA) &&
12446d49e1aeSJan Lentfer 		   wpa_parse_wpa_ie(bss_wpa, 2 + bss_wpa[1], &ie) == 0 &&
12456d49e1aeSJan Lentfer 		   (ie.group_cipher & ssid->group_cipher) &&
12466d49e1aeSJan Lentfer 		   (ie.pairwise_cipher & ssid->pairwise_cipher) &&
12476d49e1aeSJan Lentfer 		   (ie.key_mgmt & ssid->key_mgmt)) {
12483ff40c12SJohn Marino 		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using IEEE 802.11i/D3.0");
12496d49e1aeSJan Lentfer 		proto = WPA_PROTO_WPA;
1250*a1157835SDaniel Fojt #ifdef CONFIG_HS20
1251*a1157835SDaniel Fojt 	} else if (bss_osen && (ssid->proto & WPA_PROTO_OSEN) &&
1252*a1157835SDaniel Fojt 		   wpa_parse_wpa_ie(bss_osen, 2 + bss_osen[1], &ie) == 0 &&
1253*a1157835SDaniel Fojt 		   (ie.group_cipher & ssid->group_cipher) &&
1254*a1157835SDaniel Fojt 		   (ie.pairwise_cipher & ssid->pairwise_cipher) &&
1255*a1157835SDaniel Fojt 		   (ie.key_mgmt & ssid->key_mgmt)) {
1256*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: using OSEN");
1257*a1157835SDaniel Fojt 		proto = WPA_PROTO_OSEN;
1258*a1157835SDaniel Fojt 	} else if (bss_rsn && (ssid->proto & WPA_PROTO_OSEN) &&
1259*a1157835SDaniel Fojt 	    wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 &&
1260*a1157835SDaniel Fojt 	    (ie.group_cipher & ssid->group_cipher) &&
1261*a1157835SDaniel Fojt 	    (ie.pairwise_cipher & ssid->pairwise_cipher) &&
1262*a1157835SDaniel Fojt 	    (ie.key_mgmt & ssid->key_mgmt)) {
1263*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using OSEN (within RSN)");
1264*a1157835SDaniel Fojt 		proto = WPA_PROTO_RSN;
1265*a1157835SDaniel Fojt #endif /* CONFIG_HS20 */
12666d49e1aeSJan Lentfer 	} else if (bss) {
12676d49e1aeSJan Lentfer 		wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select WPA/RSN");
1268*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG,
1269*a1157835SDaniel Fojt 			"WPA: ssid proto=0x%x pairwise_cipher=0x%x group_cipher=0x%x key_mgmt=0x%x",
1270*a1157835SDaniel Fojt 			ssid->proto, ssid->pairwise_cipher, ssid->group_cipher,
1271*a1157835SDaniel Fojt 			ssid->key_mgmt);
1272*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: BSS " MACSTR " ssid='%s'%s%s%s",
1273*a1157835SDaniel Fojt 			MAC2STR(bss->bssid),
1274*a1157835SDaniel Fojt 			wpa_ssid_txt(bss->ssid, bss->ssid_len),
1275*a1157835SDaniel Fojt 			bss_wpa ? " WPA" : "",
1276*a1157835SDaniel Fojt 			bss_rsn ? " RSN" : "",
1277*a1157835SDaniel Fojt 			bss_osen ? " OSEN" : "");
1278*a1157835SDaniel Fojt 		if (bss_rsn) {
1279*a1157835SDaniel Fojt 			wpa_hexdump(MSG_DEBUG, "RSN", bss_rsn, 2 + bss_rsn[1]);
1280*a1157835SDaniel Fojt 			if (wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie)) {
1281*a1157835SDaniel Fojt 				wpa_dbg(wpa_s, MSG_DEBUG,
1282*a1157835SDaniel Fojt 					"Could not parse RSN element");
1283*a1157835SDaniel Fojt 			} else {
1284*a1157835SDaniel Fojt 				wpa_dbg(wpa_s, MSG_DEBUG,
1285*a1157835SDaniel Fojt 					"RSN: pairwise_cipher=0x%x group_cipher=0x%x key_mgmt=0x%x",
1286*a1157835SDaniel Fojt 					ie.pairwise_cipher, ie.group_cipher,
1287*a1157835SDaniel Fojt 					ie.key_mgmt);
1288*a1157835SDaniel Fojt 			}
1289*a1157835SDaniel Fojt 		}
1290*a1157835SDaniel Fojt 		if (bss_wpa) {
1291*a1157835SDaniel Fojt 			wpa_hexdump(MSG_DEBUG, "WPA", bss_wpa, 2 + bss_wpa[1]);
1292*a1157835SDaniel Fojt 			if (wpa_parse_wpa_ie(bss_wpa, 2 + bss_wpa[1], &ie)) {
1293*a1157835SDaniel Fojt 				wpa_dbg(wpa_s, MSG_DEBUG,
1294*a1157835SDaniel Fojt 					"Could not parse WPA element");
1295*a1157835SDaniel Fojt 			} else {
1296*a1157835SDaniel Fojt 				wpa_dbg(wpa_s, MSG_DEBUG,
1297*a1157835SDaniel Fojt 					"WPA: pairwise_cipher=0x%x group_cipher=0x%x key_mgmt=0x%x",
1298*a1157835SDaniel Fojt 					ie.pairwise_cipher, ie.group_cipher,
1299*a1157835SDaniel Fojt 					ie.key_mgmt);
1300*a1157835SDaniel Fojt 			}
1301*a1157835SDaniel Fojt 		}
13026d49e1aeSJan Lentfer 		return -1;
13036d49e1aeSJan Lentfer 	} else {
1304*a1157835SDaniel Fojt 		if (ssid->proto & WPA_PROTO_OSEN)
1305*a1157835SDaniel Fojt 			proto = WPA_PROTO_OSEN;
1306*a1157835SDaniel Fojt 		else if (ssid->proto & WPA_PROTO_RSN)
13076d49e1aeSJan Lentfer 			proto = WPA_PROTO_RSN;
13086d49e1aeSJan Lentfer 		else
13096d49e1aeSJan Lentfer 			proto = WPA_PROTO_WPA;
13106d49e1aeSJan Lentfer 		if (wpa_supplicant_suites_from_ai(wpa_s, ssid, &ie) < 0) {
13116d49e1aeSJan Lentfer 			os_memset(&ie, 0, sizeof(ie));
13126d49e1aeSJan Lentfer 			ie.group_cipher = ssid->group_cipher;
13136d49e1aeSJan Lentfer 			ie.pairwise_cipher = ssid->pairwise_cipher;
13146d49e1aeSJan Lentfer 			ie.key_mgmt = ssid->key_mgmt;
13156d49e1aeSJan Lentfer #ifdef CONFIG_IEEE80211W
1316*a1157835SDaniel Fojt 			ie.mgmt_group_cipher = 0;
1317*a1157835SDaniel Fojt 			if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
1318*a1157835SDaniel Fojt 				if (ssid->group_mgmt_cipher &
1319*a1157835SDaniel Fojt 				    WPA_CIPHER_BIP_GMAC_256)
13206d49e1aeSJan Lentfer 					ie.mgmt_group_cipher =
1321*a1157835SDaniel Fojt 						WPA_CIPHER_BIP_GMAC_256;
1322*a1157835SDaniel Fojt 				else if (ssid->group_mgmt_cipher &
1323*a1157835SDaniel Fojt 					 WPA_CIPHER_BIP_CMAC_256)
1324*a1157835SDaniel Fojt 					ie.mgmt_group_cipher =
1325*a1157835SDaniel Fojt 						WPA_CIPHER_BIP_CMAC_256;
1326*a1157835SDaniel Fojt 				else if (ssid->group_mgmt_cipher &
1327*a1157835SDaniel Fojt 					 WPA_CIPHER_BIP_GMAC_128)
1328*a1157835SDaniel Fojt 					ie.mgmt_group_cipher =
1329*a1157835SDaniel Fojt 						WPA_CIPHER_BIP_GMAC_128;
1330*a1157835SDaniel Fojt 				else
1331*a1157835SDaniel Fojt 					ie.mgmt_group_cipher =
1332*a1157835SDaniel Fojt 						WPA_CIPHER_AES_128_CMAC;
1333*a1157835SDaniel Fojt 			}
13346d49e1aeSJan Lentfer #endif /* CONFIG_IEEE80211W */
1335*a1157835SDaniel Fojt #ifdef CONFIG_OWE
1336*a1157835SDaniel Fojt 			if ((ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
1337*a1157835SDaniel Fojt 			    !ssid->owe_only &&
1338*a1157835SDaniel Fojt 			    !bss_wpa && !bss_rsn && !bss_osen) {
1339*a1157835SDaniel Fojt 				wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
1340*a1157835SDaniel Fojt 				wpa_s->wpa_proto = 0;
1341*a1157835SDaniel Fojt 				*wpa_ie_len = 0;
1342*a1157835SDaniel Fojt 				return 0;
1343*a1157835SDaniel Fojt 			}
1344*a1157835SDaniel Fojt #endif /* CONFIG_OWE */
13453ff40c12SJohn Marino 			wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Set cipher suites "
13463ff40c12SJohn Marino 				"based on configuration");
13476d49e1aeSJan Lentfer 		} else
13486d49e1aeSJan Lentfer 			proto = ie.proto;
13496d49e1aeSJan Lentfer 	}
13506d49e1aeSJan Lentfer 
13513ff40c12SJohn Marino 	wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected cipher suites: group %d "
13526d49e1aeSJan Lentfer 		"pairwise %d key_mgmt %d proto %d",
13536d49e1aeSJan Lentfer 		ie.group_cipher, ie.pairwise_cipher, ie.key_mgmt, proto);
13546d49e1aeSJan Lentfer #ifdef CONFIG_IEEE80211W
13556d49e1aeSJan Lentfer 	if (ssid->ieee80211w) {
13563ff40c12SJohn Marino 		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected mgmt group cipher %d",
13576d49e1aeSJan Lentfer 			ie.mgmt_group_cipher);
13586d49e1aeSJan Lentfer 	}
13596d49e1aeSJan Lentfer #endif /* CONFIG_IEEE80211W */
13606d49e1aeSJan Lentfer 
13613ff40c12SJohn Marino 	wpa_s->wpa_proto = proto;
13626d49e1aeSJan Lentfer 	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto);
13636d49e1aeSJan Lentfer 	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED,
1364*a1157835SDaniel Fojt 			 !!(ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_OSEN)));
13656d49e1aeSJan Lentfer 
13666d49e1aeSJan Lentfer 	if (bss || !wpa_s->ap_ies_from_associnfo) {
13676d49e1aeSJan Lentfer 		if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
13686d49e1aeSJan Lentfer 					 bss_wpa ? 2 + bss_wpa[1] : 0) ||
13696d49e1aeSJan Lentfer 		    wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
13706d49e1aeSJan Lentfer 					 bss_rsn ? 2 + bss_rsn[1] : 0))
13716d49e1aeSJan Lentfer 			return -1;
13726d49e1aeSJan Lentfer 	}
13736d49e1aeSJan Lentfer 
1374*a1157835SDaniel Fojt #ifdef CONFIG_NO_WPA
1375*a1157835SDaniel Fojt 	wpa_s->group_cipher = WPA_CIPHER_NONE;
1376*a1157835SDaniel Fojt 	wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
1377*a1157835SDaniel Fojt #else /* CONFIG_NO_WPA */
13786d49e1aeSJan Lentfer 	sel = ie.group_cipher & ssid->group_cipher;
1379*a1157835SDaniel Fojt 	wpa_dbg(wpa_s, MSG_DEBUG,
1380*a1157835SDaniel Fojt 		"WPA: AP group 0x%x network profile group 0x%x; available group 0x%x",
1381*a1157835SDaniel Fojt 		ie.group_cipher, ssid->group_cipher, sel);
13823ff40c12SJohn Marino 	wpa_s->group_cipher = wpa_pick_group_cipher(sel);
13833ff40c12SJohn Marino 	if (wpa_s->group_cipher < 0) {
13843ff40c12SJohn Marino 		wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select group "
13853ff40c12SJohn Marino 			"cipher");
13866d49e1aeSJan Lentfer 		return -1;
13876d49e1aeSJan Lentfer 	}
13883ff40c12SJohn Marino 	wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK %s",
13893ff40c12SJohn Marino 		wpa_cipher_txt(wpa_s->group_cipher));
13906d49e1aeSJan Lentfer 
13916d49e1aeSJan Lentfer 	sel = ie.pairwise_cipher & ssid->pairwise_cipher;
1392*a1157835SDaniel Fojt 	wpa_dbg(wpa_s, MSG_DEBUG,
1393*a1157835SDaniel Fojt 		"WPA: AP pairwise 0x%x network profile pairwise 0x%x; available pairwise 0x%x",
1394*a1157835SDaniel Fojt 		ie.pairwise_cipher, ssid->pairwise_cipher, sel);
13953ff40c12SJohn Marino 	wpa_s->pairwise_cipher = wpa_pick_pairwise_cipher(sel, 1);
13963ff40c12SJohn Marino 	if (wpa_s->pairwise_cipher < 0) {
13973ff40c12SJohn Marino 		wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select pairwise "
13983ff40c12SJohn Marino 			"cipher");
13996d49e1aeSJan Lentfer 		return -1;
14006d49e1aeSJan Lentfer 	}
14013ff40c12SJohn Marino 	wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK %s",
14023ff40c12SJohn Marino 		wpa_cipher_txt(wpa_s->pairwise_cipher));
1403*a1157835SDaniel Fojt #endif /* CONFIG_NO_WPA */
14046d49e1aeSJan Lentfer 
14056d49e1aeSJan Lentfer 	sel = ie.key_mgmt & ssid->key_mgmt;
1406*a1157835SDaniel Fojt 	wpa_dbg(wpa_s, MSG_DEBUG,
1407*a1157835SDaniel Fojt 		"WPA: AP key_mgmt 0x%x network profile key_mgmt 0x%x; available key_mgmt 0x%x",
1408*a1157835SDaniel Fojt 		ie.key_mgmt, ssid->key_mgmt, sel);
14093ff40c12SJohn Marino #ifdef CONFIG_SAE
14103ff40c12SJohn Marino 	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE))
14113ff40c12SJohn Marino 		sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE);
14123ff40c12SJohn Marino #endif /* CONFIG_SAE */
14136d49e1aeSJan Lentfer 	if (0) {
14146d49e1aeSJan Lentfer #ifdef CONFIG_IEEE80211R
1415*a1157835SDaniel Fojt #ifdef CONFIG_SHA384
1416*a1157835SDaniel Fojt 	} else if (sel & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) {
1417*a1157835SDaniel Fojt 		wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X_SHA384;
1418*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG,
1419*a1157835SDaniel Fojt 			"WPA: using KEY_MGMT FT/802.1X-SHA384");
1420*a1157835SDaniel Fojt 		if (!ssid->ft_eap_pmksa_caching &&
1421*a1157835SDaniel Fojt 		    pmksa_cache_get_current(wpa_s->wpa)) {
1422*a1157835SDaniel Fojt 			/* PMKSA caching with FT may have interoperability
1423*a1157835SDaniel Fojt 			 * issues, so disable that case by default for now. */
1424*a1157835SDaniel Fojt 			wpa_dbg(wpa_s, MSG_DEBUG,
1425*a1157835SDaniel Fojt 				"WPA: Disable PMKSA caching for FT/802.1X connection");
1426*a1157835SDaniel Fojt 			pmksa_cache_clear_current(wpa_s->wpa);
1427*a1157835SDaniel Fojt 		}
1428*a1157835SDaniel Fojt #endif /* CONFIG_SHA384 */
1429*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R */
1430*a1157835SDaniel Fojt #ifdef CONFIG_SUITEB192
1431*a1157835SDaniel Fojt 	} else if (sel & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
1432*a1157835SDaniel Fojt 		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
1433*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG,
1434*a1157835SDaniel Fojt 			"WPA: using KEY_MGMT 802.1X with Suite B (192-bit)");
1435*a1157835SDaniel Fojt #endif /* CONFIG_SUITEB192 */
1436*a1157835SDaniel Fojt #ifdef CONFIG_SUITEB
1437*a1157835SDaniel Fojt 	} else if (sel & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
1438*a1157835SDaniel Fojt 		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B;
1439*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG,
1440*a1157835SDaniel Fojt 			"WPA: using KEY_MGMT 802.1X with Suite B");
1441*a1157835SDaniel Fojt #endif /* CONFIG_SUITEB */
1442*a1157835SDaniel Fojt #ifdef CONFIG_FILS
1443*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R
1444*a1157835SDaniel Fojt 	} else if (sel & WPA_KEY_MGMT_FT_FILS_SHA384) {
1445*a1157835SDaniel Fojt 		wpa_s->key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA384;
1446*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT-FILS-SHA384");
1447*a1157835SDaniel Fojt 	} else if (sel & WPA_KEY_MGMT_FT_FILS_SHA256) {
1448*a1157835SDaniel Fojt 		wpa_s->key_mgmt = WPA_KEY_MGMT_FT_FILS_SHA256;
1449*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT-FILS-SHA256");
1450*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R */
1451*a1157835SDaniel Fojt 	} else if (sel & WPA_KEY_MGMT_FILS_SHA384) {
1452*a1157835SDaniel Fojt 		wpa_s->key_mgmt = WPA_KEY_MGMT_FILS_SHA384;
1453*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA384");
1454*a1157835SDaniel Fojt 	} else if (sel & WPA_KEY_MGMT_FILS_SHA256) {
1455*a1157835SDaniel Fojt 		wpa_s->key_mgmt = WPA_KEY_MGMT_FILS_SHA256;
1456*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FILS-SHA256");
1457*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
1458*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R
14596d49e1aeSJan Lentfer 	} else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
14606d49e1aeSJan Lentfer 		wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
14613ff40c12SJohn Marino 		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/802.1X");
1462*a1157835SDaniel Fojt 		if (!ssid->ft_eap_pmksa_caching &&
1463*a1157835SDaniel Fojt 		    pmksa_cache_get_current(wpa_s->wpa)) {
1464*a1157835SDaniel Fojt 			/* PMKSA caching with FT may have interoperability
1465*a1157835SDaniel Fojt 			 * issues, so disable that case by default for now. */
1466*a1157835SDaniel Fojt 			wpa_dbg(wpa_s, MSG_DEBUG,
1467*a1157835SDaniel Fojt 				"WPA: Disable PMKSA caching for FT/802.1X connection");
1468*a1157835SDaniel Fojt 			pmksa_cache_clear_current(wpa_s->wpa);
1469*a1157835SDaniel Fojt 		}
1470*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R */
1471*a1157835SDaniel Fojt #ifdef CONFIG_DPP
1472*a1157835SDaniel Fojt 	} else if (sel & WPA_KEY_MGMT_DPP) {
1473*a1157835SDaniel Fojt 		wpa_s->key_mgmt = WPA_KEY_MGMT_DPP;
1474*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT DPP");
1475*a1157835SDaniel Fojt #endif /* CONFIG_DPP */
1476*a1157835SDaniel Fojt #ifdef CONFIG_SAE
1477*a1157835SDaniel Fojt 	} else if (sel & WPA_KEY_MGMT_FT_SAE) {
1478*a1157835SDaniel Fojt 		wpa_s->key_mgmt = WPA_KEY_MGMT_FT_SAE;
1479*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT FT/SAE");
1480*a1157835SDaniel Fojt 	} else if (sel & WPA_KEY_MGMT_SAE) {
1481*a1157835SDaniel Fojt 		wpa_s->key_mgmt = WPA_KEY_MGMT_SAE;
1482*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT SAE");
1483*a1157835SDaniel Fojt #endif /* CONFIG_SAE */
1484*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R
14856d49e1aeSJan Lentfer 	} else if (sel & WPA_KEY_MGMT_FT_PSK) {
14866d49e1aeSJan Lentfer 		wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
14873ff40c12SJohn Marino 		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
14886d49e1aeSJan Lentfer #endif /* CONFIG_IEEE80211R */
14896d49e1aeSJan Lentfer #ifdef CONFIG_IEEE80211W
14906d49e1aeSJan Lentfer 	} else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) {
14916d49e1aeSJan Lentfer 		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
14923ff40c12SJohn Marino 		wpa_dbg(wpa_s, MSG_DEBUG,
14936d49e1aeSJan Lentfer 			"WPA: using KEY_MGMT 802.1X with SHA256");
14946d49e1aeSJan Lentfer 	} else if (sel & WPA_KEY_MGMT_PSK_SHA256) {
14956d49e1aeSJan Lentfer 		wpa_s->key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
14963ff40c12SJohn Marino 		wpa_dbg(wpa_s, MSG_DEBUG,
14976d49e1aeSJan Lentfer 			"WPA: using KEY_MGMT PSK with SHA256");
14986d49e1aeSJan Lentfer #endif /* CONFIG_IEEE80211W */
14996d49e1aeSJan Lentfer 	} else if (sel & WPA_KEY_MGMT_IEEE8021X) {
15006d49e1aeSJan Lentfer 		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
15013ff40c12SJohn Marino 		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X");
15026d49e1aeSJan Lentfer 	} else if (sel & WPA_KEY_MGMT_PSK) {
15036d49e1aeSJan Lentfer 		wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
15043ff40c12SJohn Marino 		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-PSK");
15056d49e1aeSJan Lentfer 	} else if (sel & WPA_KEY_MGMT_WPA_NONE) {
15066d49e1aeSJan Lentfer 		wpa_s->key_mgmt = WPA_KEY_MGMT_WPA_NONE;
15073ff40c12SJohn Marino 		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-NONE");
1508*a1157835SDaniel Fojt #ifdef CONFIG_HS20
1509*a1157835SDaniel Fojt 	} else if (sel & WPA_KEY_MGMT_OSEN) {
1510*a1157835SDaniel Fojt 		wpa_s->key_mgmt = WPA_KEY_MGMT_OSEN;
1511*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: using KEY_MGMT OSEN");
1512*a1157835SDaniel Fojt #endif /* CONFIG_HS20 */
1513*a1157835SDaniel Fojt #ifdef CONFIG_OWE
1514*a1157835SDaniel Fojt 	} else if (sel & WPA_KEY_MGMT_OWE) {
1515*a1157835SDaniel Fojt 		wpa_s->key_mgmt = WPA_KEY_MGMT_OWE;
1516*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT OWE");
1517*a1157835SDaniel Fojt #endif /* CONFIG_OWE */
15186d49e1aeSJan Lentfer 	} else {
15193ff40c12SJohn Marino 		wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select "
15203ff40c12SJohn Marino 			"authenticated key management type");
15216d49e1aeSJan Lentfer 		return -1;
15226d49e1aeSJan Lentfer 	}
15236d49e1aeSJan Lentfer 
15246d49e1aeSJan Lentfer 	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt);
15256d49e1aeSJan Lentfer 	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE,
15266d49e1aeSJan Lentfer 			 wpa_s->pairwise_cipher);
15276d49e1aeSJan Lentfer 	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
15286d49e1aeSJan Lentfer 
15296d49e1aeSJan Lentfer #ifdef CONFIG_IEEE80211W
15306d49e1aeSJan Lentfer 	sel = ie.mgmt_group_cipher;
1531*a1157835SDaniel Fojt 	if (ssid->group_mgmt_cipher)
1532*a1157835SDaniel Fojt 		sel &= ssid->group_mgmt_cipher;
1533*a1157835SDaniel Fojt 	if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION ||
15346d49e1aeSJan Lentfer 	    !(ie.capabilities & WPA_CAPABILITY_MFPC))
15356d49e1aeSJan Lentfer 		sel = 0;
1536*a1157835SDaniel Fojt 	wpa_dbg(wpa_s, MSG_DEBUG,
1537*a1157835SDaniel Fojt 		"WPA: AP mgmt_group_cipher 0x%x network profile mgmt_group_cipher 0x%x; available mgmt_group_cipher 0x%x",
1538*a1157835SDaniel Fojt 		ie.mgmt_group_cipher, ssid->group_mgmt_cipher, sel);
15396d49e1aeSJan Lentfer 	if (sel & WPA_CIPHER_AES_128_CMAC) {
15406d49e1aeSJan Lentfer 		wpa_s->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
15413ff40c12SJohn Marino 		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
15426d49e1aeSJan Lentfer 			"AES-128-CMAC");
1543*a1157835SDaniel Fojt 	} else if (sel & WPA_CIPHER_BIP_GMAC_128) {
1544*a1157835SDaniel Fojt 		wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_GMAC_128;
1545*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
1546*a1157835SDaniel Fojt 			"BIP-GMAC-128");
1547*a1157835SDaniel Fojt 	} else if (sel & WPA_CIPHER_BIP_GMAC_256) {
1548*a1157835SDaniel Fojt 		wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_GMAC_256;
1549*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
1550*a1157835SDaniel Fojt 			"BIP-GMAC-256");
1551*a1157835SDaniel Fojt 	} else if (sel & WPA_CIPHER_BIP_CMAC_256) {
1552*a1157835SDaniel Fojt 		wpa_s->mgmt_group_cipher = WPA_CIPHER_BIP_CMAC_256;
1553*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
1554*a1157835SDaniel Fojt 			"BIP-CMAC-256");
15556d49e1aeSJan Lentfer 	} else {
15566d49e1aeSJan Lentfer 		wpa_s->mgmt_group_cipher = 0;
15573ff40c12SJohn Marino 		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: not using MGMT group cipher");
15586d49e1aeSJan Lentfer 	}
15596d49e1aeSJan Lentfer 	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
15606d49e1aeSJan Lentfer 			 wpa_s->mgmt_group_cipher);
15613ff40c12SJohn Marino 	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
1562*a1157835SDaniel Fojt 			 wpas_get_ssid_pmf(wpa_s, ssid));
15636d49e1aeSJan Lentfer #endif /* CONFIG_IEEE80211W */
1564*a1157835SDaniel Fojt #ifdef CONFIG_OCV
1565*a1157835SDaniel Fojt 	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCV, ssid->ocv);
1566*a1157835SDaniel Fojt #endif /* CONFIG_OCV */
15676d49e1aeSJan Lentfer 
15686d49e1aeSJan Lentfer 	if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
15693ff40c12SJohn Marino 		wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to generate WPA IE");
15706d49e1aeSJan Lentfer 		return -1;
15716d49e1aeSJan Lentfer 	}
15726d49e1aeSJan Lentfer 
1573*a1157835SDaniel Fojt 	if (0) {
1574*a1157835SDaniel Fojt #ifdef CONFIG_DPP
1575*a1157835SDaniel Fojt 	} else if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP) {
1576*a1157835SDaniel Fojt 		/* Use PMK from DPP network introduction (PMKSA entry) */
1577*a1157835SDaniel Fojt 		wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
1578*a1157835SDaniel Fojt #endif /* CONFIG_DPP */
1579*a1157835SDaniel Fojt 	} else if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
1580*a1157835SDaniel Fojt 		int psk_set = 0;
1581*a1157835SDaniel Fojt 		int sae_only;
1582*a1157835SDaniel Fojt 
1583*a1157835SDaniel Fojt 		sae_only = (ssid->key_mgmt & (WPA_KEY_MGMT_PSK |
1584*a1157835SDaniel Fojt 					      WPA_KEY_MGMT_FT_PSK |
1585*a1157835SDaniel Fojt 					      WPA_KEY_MGMT_PSK_SHA256)) == 0;
1586*a1157835SDaniel Fojt 
1587*a1157835SDaniel Fojt 		if (ssid->psk_set && !sae_only) {
1588*a1157835SDaniel Fojt 			wpa_hexdump_key(MSG_MSGDUMP, "PSK (set in config)",
1589*a1157835SDaniel Fojt 					ssid->psk, PMK_LEN);
1590*a1157835SDaniel Fojt 			wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL,
1591*a1157835SDaniel Fojt 				       NULL);
1592*a1157835SDaniel Fojt 			psk_set = 1;
1593*a1157835SDaniel Fojt 		}
1594*a1157835SDaniel Fojt 
1595*a1157835SDaniel Fojt 		if (wpa_key_mgmt_sae(ssid->key_mgmt) &&
1596*a1157835SDaniel Fojt 		    (ssid->sae_password || ssid->passphrase))
1597*a1157835SDaniel Fojt 			psk_set = 1;
1598*a1157835SDaniel Fojt 
15993ff40c12SJohn Marino #ifndef CONFIG_NO_PBKDF2
16003ff40c12SJohn Marino 		if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
1601*a1157835SDaniel Fojt 		    ssid->passphrase && !sae_only) {
16023ff40c12SJohn Marino 			u8 psk[PMK_LEN];
16033ff40c12SJohn Marino 		        pbkdf2_sha1(ssid->passphrase, bss->ssid, bss->ssid_len,
16043ff40c12SJohn Marino 				    4096, psk, PMK_LEN);
16053ff40c12SJohn Marino 		        wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
16063ff40c12SJohn Marino 					psk, PMK_LEN);
1607*a1157835SDaniel Fojt 			wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL, NULL);
1608*a1157835SDaniel Fojt 			psk_set = 1;
1609*a1157835SDaniel Fojt 			os_memset(psk, 0, sizeof(psk));
16103ff40c12SJohn Marino 		}
16113ff40c12SJohn Marino #endif /* CONFIG_NO_PBKDF2 */
16123ff40c12SJohn Marino #ifdef CONFIG_EXT_PASSWORD
1613*a1157835SDaniel Fojt 		if (ssid->ext_psk && !sae_only) {
16143ff40c12SJohn Marino 			struct wpabuf *pw = ext_password_get(wpa_s->ext_pw,
16153ff40c12SJohn Marino 							     ssid->ext_psk);
16163ff40c12SJohn Marino 			char pw_str[64 + 1];
16173ff40c12SJohn Marino 			u8 psk[PMK_LEN];
16183ff40c12SJohn Marino 
16193ff40c12SJohn Marino 			if (pw == NULL) {
16203ff40c12SJohn Marino 				wpa_msg(wpa_s, MSG_INFO, "EXT PW: No PSK "
16213ff40c12SJohn Marino 					"found from external storage");
16223ff40c12SJohn Marino 				return -1;
16233ff40c12SJohn Marino 			}
16243ff40c12SJohn Marino 
16253ff40c12SJohn Marino 			if (wpabuf_len(pw) < 8 || wpabuf_len(pw) > 64) {
16263ff40c12SJohn Marino 				wpa_msg(wpa_s, MSG_INFO, "EXT PW: Unexpected "
16273ff40c12SJohn Marino 					"PSK length %d in external storage",
16283ff40c12SJohn Marino 					(int) wpabuf_len(pw));
16293ff40c12SJohn Marino 				ext_password_free(pw);
16303ff40c12SJohn Marino 				return -1;
16313ff40c12SJohn Marino 			}
16323ff40c12SJohn Marino 
16333ff40c12SJohn Marino 			os_memcpy(pw_str, wpabuf_head(pw), wpabuf_len(pw));
16343ff40c12SJohn Marino 			pw_str[wpabuf_len(pw)] = '\0';
16353ff40c12SJohn Marino 
16363ff40c12SJohn Marino #ifndef CONFIG_NO_PBKDF2
16373ff40c12SJohn Marino 			if (wpabuf_len(pw) >= 8 && wpabuf_len(pw) < 64 && bss)
16383ff40c12SJohn Marino 			{
16393ff40c12SJohn Marino 				pbkdf2_sha1(pw_str, bss->ssid, bss->ssid_len,
16403ff40c12SJohn Marino 					    4096, psk, PMK_LEN);
16413ff40c12SJohn Marino 				os_memset(pw_str, 0, sizeof(pw_str));
16423ff40c12SJohn Marino 				wpa_hexdump_key(MSG_MSGDUMP, "PSK (from "
16433ff40c12SJohn Marino 						"external passphrase)",
16443ff40c12SJohn Marino 						psk, PMK_LEN);
1645*a1157835SDaniel Fojt 				wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL,
1646*a1157835SDaniel Fojt 					       NULL);
1647*a1157835SDaniel Fojt 				psk_set = 1;
1648*a1157835SDaniel Fojt 				os_memset(psk, 0, sizeof(psk));
16493ff40c12SJohn Marino 			} else
16503ff40c12SJohn Marino #endif /* CONFIG_NO_PBKDF2 */
16513ff40c12SJohn Marino 			if (wpabuf_len(pw) == 2 * PMK_LEN) {
16523ff40c12SJohn Marino 				if (hexstr2bin(pw_str, psk, PMK_LEN) < 0) {
16533ff40c12SJohn Marino 					wpa_msg(wpa_s, MSG_INFO, "EXT PW: "
16543ff40c12SJohn Marino 						"Invalid PSK hex string");
16553ff40c12SJohn Marino 					os_memset(pw_str, 0, sizeof(pw_str));
16563ff40c12SJohn Marino 					ext_password_free(pw);
16573ff40c12SJohn Marino 					return -1;
16583ff40c12SJohn Marino 				}
1659*a1157835SDaniel Fojt 				wpa_hexdump_key(MSG_MSGDUMP,
1660*a1157835SDaniel Fojt 						"PSK (from external PSK)",
1661*a1157835SDaniel Fojt 						psk, PMK_LEN);
1662*a1157835SDaniel Fojt 				wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL,
1663*a1157835SDaniel Fojt 					       NULL);
1664*a1157835SDaniel Fojt 				psk_set = 1;
1665*a1157835SDaniel Fojt 				os_memset(psk, 0, sizeof(psk));
16663ff40c12SJohn Marino 			} else {
16673ff40c12SJohn Marino 				wpa_msg(wpa_s, MSG_INFO, "EXT PW: No suitable "
16683ff40c12SJohn Marino 					"PSK available");
16693ff40c12SJohn Marino 				os_memset(pw_str, 0, sizeof(pw_str));
16703ff40c12SJohn Marino 				ext_password_free(pw);
16713ff40c12SJohn Marino 				return -1;
16723ff40c12SJohn Marino 			}
16733ff40c12SJohn Marino 
16743ff40c12SJohn Marino 			os_memset(pw_str, 0, sizeof(pw_str));
16753ff40c12SJohn Marino 			ext_password_free(pw);
16763ff40c12SJohn Marino 		}
16773ff40c12SJohn Marino #endif /* CONFIG_EXT_PASSWORD */
1678*a1157835SDaniel Fojt 
1679*a1157835SDaniel Fojt 		if (!psk_set) {
1680*a1157835SDaniel Fojt 			wpa_msg(wpa_s, MSG_INFO,
1681*a1157835SDaniel Fojt 				"No PSK available for association");
1682*a1157835SDaniel Fojt 			wpas_auth_failed(wpa_s, "NO_PSK_AVAILABLE");
1683*a1157835SDaniel Fojt 			return -1;
1684*a1157835SDaniel Fojt 		}
1685*a1157835SDaniel Fojt #ifdef CONFIG_OWE
1686*a1157835SDaniel Fojt 	} else if (wpa_s->key_mgmt == WPA_KEY_MGMT_OWE) {
1687*a1157835SDaniel Fojt 		/* OWE Diffie-Hellman exchange in (Re)Association
1688*a1157835SDaniel Fojt 		 * Request/Response frames set the PMK, so do not override it
1689*a1157835SDaniel Fojt 		 * here. */
1690*a1157835SDaniel Fojt #endif /* CONFIG_OWE */
16913ff40c12SJohn Marino 	} else
16926d49e1aeSJan Lentfer 		wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
16936d49e1aeSJan Lentfer 
16946d49e1aeSJan Lentfer 	return 0;
16956d49e1aeSJan Lentfer }
16966d49e1aeSJan Lentfer 
16976d49e1aeSJan Lentfer 
wpas_ext_capab_byte(struct wpa_supplicant * wpa_s,u8 * pos,int idx)16983ff40c12SJohn Marino static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
16993ff40c12SJohn Marino {
17003ff40c12SJohn Marino 	*pos = 0x00;
17013ff40c12SJohn Marino 
17023ff40c12SJohn Marino 	switch (idx) {
17033ff40c12SJohn Marino 	case 0: /* Bits 0-7 */
17043ff40c12SJohn Marino 		break;
17053ff40c12SJohn Marino 	case 1: /* Bits 8-15 */
1706*a1157835SDaniel Fojt 		if (wpa_s->conf->coloc_intf_reporting) {
1707*a1157835SDaniel Fojt 			/* Bit 13 - Collocated Interference Reporting */
1708*a1157835SDaniel Fojt 			*pos |= 0x20;
1709*a1157835SDaniel Fojt 		}
17103ff40c12SJohn Marino 		break;
17113ff40c12SJohn Marino 	case 2: /* Bits 16-23 */
17123ff40c12SJohn Marino #ifdef CONFIG_WNM
17133ff40c12SJohn Marino 		*pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
1714*a1157835SDaniel Fojt 		if (!wpa_s->conf->disable_btm)
17153ff40c12SJohn Marino 			*pos |= 0x08; /* Bit 19 - BSS Transition */
17163ff40c12SJohn Marino #endif /* CONFIG_WNM */
17173ff40c12SJohn Marino 		break;
17183ff40c12SJohn Marino 	case 3: /* Bits 24-31 */
17193ff40c12SJohn Marino #ifdef CONFIG_WNM
17203ff40c12SJohn Marino 		*pos |= 0x02; /* Bit 25 - SSID List */
17213ff40c12SJohn Marino #endif /* CONFIG_WNM */
17223ff40c12SJohn Marino #ifdef CONFIG_INTERWORKING
17233ff40c12SJohn Marino 		if (wpa_s->conf->interworking)
17243ff40c12SJohn Marino 			*pos |= 0x80; /* Bit 31 - Interworking */
17253ff40c12SJohn Marino #endif /* CONFIG_INTERWORKING */
17263ff40c12SJohn Marino 		break;
17273ff40c12SJohn Marino 	case 4: /* Bits 32-39 */
17283ff40c12SJohn Marino #ifdef CONFIG_INTERWORKING
1729*a1157835SDaniel Fojt 		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_QOS_MAPPING)
17303ff40c12SJohn Marino 			*pos |= 0x01; /* Bit 32 - QoS Map */
17313ff40c12SJohn Marino #endif /* CONFIG_INTERWORKING */
17323ff40c12SJohn Marino 		break;
17333ff40c12SJohn Marino 	case 5: /* Bits 40-47 */
1734*a1157835SDaniel Fojt #ifdef CONFIG_HS20
1735*a1157835SDaniel Fojt 		if (wpa_s->conf->hs20)
1736*a1157835SDaniel Fojt 			*pos |= 0x40; /* Bit 46 - WNM-Notification */
1737*a1157835SDaniel Fojt #endif /* CONFIG_HS20 */
1738*a1157835SDaniel Fojt #ifdef CONFIG_MBO
1739*a1157835SDaniel Fojt 		*pos |= 0x40; /* Bit 46 - WNM-Notification */
1740*a1157835SDaniel Fojt #endif /* CONFIG_MBO */
17413ff40c12SJohn Marino 		break;
17423ff40c12SJohn Marino 	case 6: /* Bits 48-55 */
17433ff40c12SJohn Marino 		break;
1744*a1157835SDaniel Fojt 	case 7: /* Bits 56-63 */
1745*a1157835SDaniel Fojt 		break;
1746*a1157835SDaniel Fojt 	case 8: /* Bits 64-71 */
1747*a1157835SDaniel Fojt 		if (wpa_s->conf->ftm_responder)
1748*a1157835SDaniel Fojt 			*pos |= 0x40; /* Bit 70 - FTM responder */
1749*a1157835SDaniel Fojt 		if (wpa_s->conf->ftm_initiator)
1750*a1157835SDaniel Fojt 			*pos |= 0x80; /* Bit 71 - FTM initiator */
1751*a1157835SDaniel Fojt 		break;
1752*a1157835SDaniel Fojt 	case 9: /* Bits 72-79 */
1753*a1157835SDaniel Fojt #ifdef CONFIG_FILS
1754*a1157835SDaniel Fojt 		if (!wpa_s->disable_fils)
1755*a1157835SDaniel Fojt 			*pos |= 0x01;
1756*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
1757*a1157835SDaniel Fojt 		break;
17583ff40c12SJohn Marino 	}
17593ff40c12SJohn Marino }
17603ff40c12SJohn Marino 
17613ff40c12SJohn Marino 
wpas_build_ext_capab(struct wpa_supplicant * wpa_s,u8 * buf,size_t buflen)1762*a1157835SDaniel Fojt int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen)
17633ff40c12SJohn Marino {
17643ff40c12SJohn Marino 	u8 *pos = buf;
1765*a1157835SDaniel Fojt 	u8 len = 10, i;
17663ff40c12SJohn Marino 
17673ff40c12SJohn Marino 	if (len < wpa_s->extended_capa_len)
17683ff40c12SJohn Marino 		len = wpa_s->extended_capa_len;
1769*a1157835SDaniel Fojt 	if (buflen < (size_t) len + 2) {
1770*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
1771*a1157835SDaniel Fojt 			   "Not enough room for building extended capabilities element");
1772*a1157835SDaniel Fojt 		return -1;
1773*a1157835SDaniel Fojt 	}
17743ff40c12SJohn Marino 
17753ff40c12SJohn Marino 	*pos++ = WLAN_EID_EXT_CAPAB;
17763ff40c12SJohn Marino 	*pos++ = len;
17773ff40c12SJohn Marino 	for (i = 0; i < len; i++, pos++) {
17783ff40c12SJohn Marino 		wpas_ext_capab_byte(wpa_s, pos, i);
17793ff40c12SJohn Marino 
17803ff40c12SJohn Marino 		if (i < wpa_s->extended_capa_len) {
17813ff40c12SJohn Marino 			*pos &= ~wpa_s->extended_capa_mask[i];
17823ff40c12SJohn Marino 			*pos |= wpa_s->extended_capa[i];
17833ff40c12SJohn Marino 		}
17843ff40c12SJohn Marino 	}
17853ff40c12SJohn Marino 
17863ff40c12SJohn Marino 	while (len > 0 && buf[1 + len] == 0) {
17873ff40c12SJohn Marino 		len--;
17883ff40c12SJohn Marino 		buf[1] = len;
17893ff40c12SJohn Marino 	}
17903ff40c12SJohn Marino 	if (len == 0)
17913ff40c12SJohn Marino 		return 0;
17923ff40c12SJohn Marino 
17933ff40c12SJohn Marino 	return 2 + len;
17943ff40c12SJohn Marino }
17953ff40c12SJohn Marino 
17963ff40c12SJohn Marino 
wpas_valid_bss(struct wpa_supplicant * wpa_s,struct wpa_bss * test_bss)17973ff40c12SJohn Marino static int wpas_valid_bss(struct wpa_supplicant *wpa_s,
17983ff40c12SJohn Marino 			  struct wpa_bss *test_bss)
17993ff40c12SJohn Marino {
18003ff40c12SJohn Marino 	struct wpa_bss *bss;
18013ff40c12SJohn Marino 
18023ff40c12SJohn Marino 	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
18033ff40c12SJohn Marino 		if (bss == test_bss)
18043ff40c12SJohn Marino 			return 1;
18053ff40c12SJohn Marino 	}
18063ff40c12SJohn Marino 
18073ff40c12SJohn Marino 	return 0;
18083ff40c12SJohn Marino }
18093ff40c12SJohn Marino 
18103ff40c12SJohn Marino 
wpas_valid_ssid(struct wpa_supplicant * wpa_s,struct wpa_ssid * test_ssid)18113ff40c12SJohn Marino static int wpas_valid_ssid(struct wpa_supplicant *wpa_s,
18123ff40c12SJohn Marino 			   struct wpa_ssid *test_ssid)
18133ff40c12SJohn Marino {
18143ff40c12SJohn Marino 	struct wpa_ssid *ssid;
18153ff40c12SJohn Marino 
18163ff40c12SJohn Marino 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
18173ff40c12SJohn Marino 		if (ssid == test_ssid)
18183ff40c12SJohn Marino 			return 1;
18193ff40c12SJohn Marino 	}
18203ff40c12SJohn Marino 
18213ff40c12SJohn Marino 	return 0;
18223ff40c12SJohn Marino }
18233ff40c12SJohn Marino 
18243ff40c12SJohn Marino 
wpas_valid_bss_ssid(struct wpa_supplicant * wpa_s,struct wpa_bss * test_bss,struct wpa_ssid * test_ssid)18253ff40c12SJohn Marino int wpas_valid_bss_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *test_bss,
18263ff40c12SJohn Marino 			struct wpa_ssid *test_ssid)
18273ff40c12SJohn Marino {
18283ff40c12SJohn Marino 	if (test_bss && !wpas_valid_bss(wpa_s, test_bss))
18293ff40c12SJohn Marino 		return 0;
18303ff40c12SJohn Marino 
18313ff40c12SJohn Marino 	return test_ssid == NULL || wpas_valid_ssid(wpa_s, test_ssid);
18323ff40c12SJohn Marino }
18333ff40c12SJohn Marino 
18343ff40c12SJohn Marino 
wpas_connect_work_free(struct wpa_connect_work * cwork)18353ff40c12SJohn Marino void wpas_connect_work_free(struct wpa_connect_work *cwork)
18363ff40c12SJohn Marino {
18373ff40c12SJohn Marino 	if (cwork == NULL)
18383ff40c12SJohn Marino 		return;
18393ff40c12SJohn Marino 	os_free(cwork);
18403ff40c12SJohn Marino }
18413ff40c12SJohn Marino 
18423ff40c12SJohn Marino 
wpas_connect_work_done(struct wpa_supplicant * wpa_s)18433ff40c12SJohn Marino void wpas_connect_work_done(struct wpa_supplicant *wpa_s)
18443ff40c12SJohn Marino {
18453ff40c12SJohn Marino 	struct wpa_connect_work *cwork;
18463ff40c12SJohn Marino 	struct wpa_radio_work *work = wpa_s->connect_work;
18473ff40c12SJohn Marino 
18483ff40c12SJohn Marino 	if (!work)
18493ff40c12SJohn Marino 		return;
18503ff40c12SJohn Marino 
18513ff40c12SJohn Marino 	wpa_s->connect_work = NULL;
18523ff40c12SJohn Marino 	cwork = work->ctx;
18533ff40c12SJohn Marino 	work->ctx = NULL;
18543ff40c12SJohn Marino 	wpas_connect_work_free(cwork);
18553ff40c12SJohn Marino 	radio_work_done(work);
18563ff40c12SJohn Marino }
18573ff40c12SJohn Marino 
18583ff40c12SJohn Marino 
wpas_update_random_addr(struct wpa_supplicant * wpa_s,int style)1859*a1157835SDaniel Fojt int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style)
1860*a1157835SDaniel Fojt {
1861*a1157835SDaniel Fojt 	struct os_reltime now;
1862*a1157835SDaniel Fojt 	u8 addr[ETH_ALEN];
1863*a1157835SDaniel Fojt 
1864*a1157835SDaniel Fojt 	os_get_reltime(&now);
1865*a1157835SDaniel Fojt 	if (wpa_s->last_mac_addr_style == style &&
1866*a1157835SDaniel Fojt 	    wpa_s->last_mac_addr_change.sec != 0 &&
1867*a1157835SDaniel Fojt 	    !os_reltime_expired(&now, &wpa_s->last_mac_addr_change,
1868*a1157835SDaniel Fojt 				wpa_s->conf->rand_addr_lifetime)) {
1869*a1157835SDaniel Fojt 		wpa_msg(wpa_s, MSG_DEBUG,
1870*a1157835SDaniel Fojt 			"Previously selected random MAC address has not yet expired");
1871*a1157835SDaniel Fojt 		return 0;
1872*a1157835SDaniel Fojt 	}
1873*a1157835SDaniel Fojt 
1874*a1157835SDaniel Fojt 	switch (style) {
1875*a1157835SDaniel Fojt 	case 1:
1876*a1157835SDaniel Fojt 		if (random_mac_addr(addr) < 0)
1877*a1157835SDaniel Fojt 			return -1;
1878*a1157835SDaniel Fojt 		break;
1879*a1157835SDaniel Fojt 	case 2:
1880*a1157835SDaniel Fojt 		os_memcpy(addr, wpa_s->perm_addr, ETH_ALEN);
1881*a1157835SDaniel Fojt 		if (random_mac_addr_keep_oui(addr) < 0)
1882*a1157835SDaniel Fojt 			return -1;
1883*a1157835SDaniel Fojt 		break;
1884*a1157835SDaniel Fojt 	default:
1885*a1157835SDaniel Fojt 		return -1;
1886*a1157835SDaniel Fojt 	}
1887*a1157835SDaniel Fojt 
1888*a1157835SDaniel Fojt 	if (wpa_drv_set_mac_addr(wpa_s, addr) < 0) {
1889*a1157835SDaniel Fojt 		wpa_msg(wpa_s, MSG_INFO,
1890*a1157835SDaniel Fojt 			"Failed to set random MAC address");
1891*a1157835SDaniel Fojt 		return -1;
1892*a1157835SDaniel Fojt 	}
1893*a1157835SDaniel Fojt 
1894*a1157835SDaniel Fojt 	os_get_reltime(&wpa_s->last_mac_addr_change);
1895*a1157835SDaniel Fojt 	wpa_s->mac_addr_changed = 1;
1896*a1157835SDaniel Fojt 	wpa_s->last_mac_addr_style = style;
1897*a1157835SDaniel Fojt 
1898*a1157835SDaniel Fojt 	if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
1899*a1157835SDaniel Fojt 		wpa_msg(wpa_s, MSG_INFO,
1900*a1157835SDaniel Fojt 			"Could not update MAC address information");
1901*a1157835SDaniel Fojt 		return -1;
1902*a1157835SDaniel Fojt 	}
1903*a1157835SDaniel Fojt 
1904*a1157835SDaniel Fojt 	wpa_msg(wpa_s, MSG_DEBUG, "Using random MAC address " MACSTR,
1905*a1157835SDaniel Fojt 		MAC2STR(addr));
1906*a1157835SDaniel Fojt 
1907*a1157835SDaniel Fojt 	return 0;
1908*a1157835SDaniel Fojt }
1909*a1157835SDaniel Fojt 
1910*a1157835SDaniel Fojt 
wpas_update_random_addr_disassoc(struct wpa_supplicant * wpa_s)1911*a1157835SDaniel Fojt int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s)
1912*a1157835SDaniel Fojt {
1913*a1157835SDaniel Fojt 	if (wpa_s->wpa_state >= WPA_AUTHENTICATING ||
1914*a1157835SDaniel Fojt 	    !wpa_s->conf->preassoc_mac_addr)
1915*a1157835SDaniel Fojt 		return 0;
1916*a1157835SDaniel Fojt 
1917*a1157835SDaniel Fojt 	return wpas_update_random_addr(wpa_s, wpa_s->conf->preassoc_mac_addr);
1918*a1157835SDaniel Fojt }
1919*a1157835SDaniel Fojt 
1920*a1157835SDaniel Fojt 
19213ff40c12SJohn Marino static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit);
19223ff40c12SJohn Marino 
19236d49e1aeSJan Lentfer /**
19246d49e1aeSJan Lentfer  * wpa_supplicant_associate - Request association
19256d49e1aeSJan Lentfer  * @wpa_s: Pointer to wpa_supplicant data
19266d49e1aeSJan Lentfer  * @bss: Scan results for the selected BSS, or %NULL if not available
19276d49e1aeSJan Lentfer  * @ssid: Configuration data for the selected network
19286d49e1aeSJan Lentfer  *
19296d49e1aeSJan Lentfer  * This function is used to request %wpa_supplicant to associate with a BSS.
19306d49e1aeSJan Lentfer  */
wpa_supplicant_associate(struct wpa_supplicant * wpa_s,struct wpa_bss * bss,struct wpa_ssid * ssid)19316d49e1aeSJan Lentfer void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
19323ff40c12SJohn Marino 			      struct wpa_bss *bss, struct wpa_ssid *ssid)
19336d49e1aeSJan Lentfer {
19343ff40c12SJohn Marino 	struct wpa_connect_work *cwork;
1935*a1157835SDaniel Fojt 	int rand_style;
1936*a1157835SDaniel Fojt 
1937*a1157835SDaniel Fojt 	wpa_s->own_disconnect_req = 0;
1938*a1157835SDaniel Fojt 
1939*a1157835SDaniel Fojt 	/*
1940*a1157835SDaniel Fojt 	 * If we are starting a new connection, any previously pending EAPOL
1941*a1157835SDaniel Fojt 	 * RX cannot be valid anymore.
1942*a1157835SDaniel Fojt 	 */
1943*a1157835SDaniel Fojt 	wpabuf_free(wpa_s->pending_eapol_rx);
1944*a1157835SDaniel Fojt 	wpa_s->pending_eapol_rx = NULL;
1945*a1157835SDaniel Fojt 
1946*a1157835SDaniel Fojt 	if (ssid->mac_addr == -1)
1947*a1157835SDaniel Fojt 		rand_style = wpa_s->conf->mac_addr;
1948*a1157835SDaniel Fojt 	else
1949*a1157835SDaniel Fojt 		rand_style = ssid->mac_addr;
1950*a1157835SDaniel Fojt 
1951*a1157835SDaniel Fojt 	wmm_ac_clear_saved_tspecs(wpa_s);
1952*a1157835SDaniel Fojt 	wpa_s->reassoc_same_bss = 0;
1953*a1157835SDaniel Fojt 	wpa_s->reassoc_same_ess = 0;
1954*a1157835SDaniel Fojt #ifdef CONFIG_TESTING_OPTIONS
1955*a1157835SDaniel Fojt 	wpa_s->testing_resend_assoc = 0;
1956*a1157835SDaniel Fojt #endif /* CONFIG_TESTING_OPTIONS */
1957*a1157835SDaniel Fojt 
1958*a1157835SDaniel Fojt 	if (wpa_s->last_ssid == ssid) {
1959*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG, "Re-association to the same ESS");
1960*a1157835SDaniel Fojt 		wpa_s->reassoc_same_ess = 1;
1961*a1157835SDaniel Fojt 		if (wpa_s->current_bss && wpa_s->current_bss == bss) {
1962*a1157835SDaniel Fojt 			wmm_ac_save_tspecs(wpa_s);
1963*a1157835SDaniel Fojt 			wpa_s->reassoc_same_bss = 1;
1964*a1157835SDaniel Fojt 		} else if (wpa_s->current_bss && wpa_s->current_bss != bss) {
1965*a1157835SDaniel Fojt 			os_get_reltime(&wpa_s->roam_start);
1966*a1157835SDaniel Fojt 		}
1967*a1157835SDaniel Fojt 	}
1968*a1157835SDaniel Fojt 
1969*a1157835SDaniel Fojt 	if (rand_style > 0 && !wpa_s->reassoc_same_ess) {
1970*a1157835SDaniel Fojt 		if (wpas_update_random_addr(wpa_s, rand_style) < 0)
1971*a1157835SDaniel Fojt 			return;
1972*a1157835SDaniel Fojt 		wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
1973*a1157835SDaniel Fojt 	} else if (rand_style == 0 && wpa_s->mac_addr_changed) {
1974*a1157835SDaniel Fojt 		if (wpa_drv_set_mac_addr(wpa_s, NULL) < 0) {
1975*a1157835SDaniel Fojt 			wpa_msg(wpa_s, MSG_INFO,
1976*a1157835SDaniel Fojt 				"Could not restore permanent MAC address");
1977*a1157835SDaniel Fojt 			return;
1978*a1157835SDaniel Fojt 		}
1979*a1157835SDaniel Fojt 		wpa_s->mac_addr_changed = 0;
1980*a1157835SDaniel Fojt 		if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
1981*a1157835SDaniel Fojt 			wpa_msg(wpa_s, MSG_INFO,
1982*a1157835SDaniel Fojt 				"Could not update MAC address information");
1983*a1157835SDaniel Fojt 			return;
1984*a1157835SDaniel Fojt 		}
1985*a1157835SDaniel Fojt 		wpa_msg(wpa_s, MSG_DEBUG, "Using permanent MAC address");
1986*a1157835SDaniel Fojt 	}
1987*a1157835SDaniel Fojt 	wpa_s->last_ssid = ssid;
19883ff40c12SJohn Marino 
19893ff40c12SJohn Marino #ifdef CONFIG_IBSS_RSN
19903ff40c12SJohn Marino 	ibss_rsn_deinit(wpa_s->ibss_rsn);
19913ff40c12SJohn Marino 	wpa_s->ibss_rsn = NULL;
1992*a1157835SDaniel Fojt #else /* CONFIG_IBSS_RSN */
1993*a1157835SDaniel Fojt 	if (ssid->mode == WPAS_MODE_IBSS &&
1994*a1157835SDaniel Fojt 	    !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE | WPA_KEY_MGMT_WPA_NONE))) {
1995*a1157835SDaniel Fojt 		wpa_msg(wpa_s, MSG_INFO,
1996*a1157835SDaniel Fojt 			"IBSS RSN not supported in the build");
1997*a1157835SDaniel Fojt 		return;
1998*a1157835SDaniel Fojt 	}
19993ff40c12SJohn Marino #endif /* CONFIG_IBSS_RSN */
20003ff40c12SJohn Marino 
20013ff40c12SJohn Marino 	if (ssid->mode == WPAS_MODE_AP || ssid->mode == WPAS_MODE_P2P_GO ||
20023ff40c12SJohn Marino 	    ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) {
20033ff40c12SJohn Marino #ifdef CONFIG_AP
20043ff40c12SJohn Marino 		if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP)) {
20053ff40c12SJohn Marino 			wpa_msg(wpa_s, MSG_INFO, "Driver does not support AP "
20063ff40c12SJohn Marino 				"mode");
20073ff40c12SJohn Marino 			return;
20083ff40c12SJohn Marino 		}
20093ff40c12SJohn Marino 		if (wpa_supplicant_create_ap(wpa_s, ssid) < 0) {
20103ff40c12SJohn Marino 			wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
20113ff40c12SJohn Marino 			if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
20123ff40c12SJohn Marino 				wpas_p2p_ap_setup_failed(wpa_s);
20133ff40c12SJohn Marino 			return;
20143ff40c12SJohn Marino 		}
20153ff40c12SJohn Marino 		wpa_s->current_bss = bss;
20163ff40c12SJohn Marino #else /* CONFIG_AP */
20173ff40c12SJohn Marino 		wpa_msg(wpa_s, MSG_ERROR, "AP mode support not included in "
20183ff40c12SJohn Marino 			"the build");
20193ff40c12SJohn Marino #endif /* CONFIG_AP */
20203ff40c12SJohn Marino 		return;
20213ff40c12SJohn Marino 	}
20223ff40c12SJohn Marino 
2023*a1157835SDaniel Fojt 	if (ssid->mode == WPAS_MODE_MESH) {
2024*a1157835SDaniel Fojt #ifdef CONFIG_MESH
2025*a1157835SDaniel Fojt 		if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MESH)) {
2026*a1157835SDaniel Fojt 			wpa_msg(wpa_s, MSG_INFO,
2027*a1157835SDaniel Fojt 				"Driver does not support mesh mode");
2028*a1157835SDaniel Fojt 			return;
2029*a1157835SDaniel Fojt 		}
2030*a1157835SDaniel Fojt 		if (bss)
2031*a1157835SDaniel Fojt 			ssid->frequency = bss->freq;
2032*a1157835SDaniel Fojt 		if (wpa_supplicant_join_mesh(wpa_s, ssid) < 0) {
2033*a1157835SDaniel Fojt 			wpa_msg(wpa_s, MSG_ERROR, "Could not join mesh");
2034*a1157835SDaniel Fojt 			return;
2035*a1157835SDaniel Fojt 		}
2036*a1157835SDaniel Fojt 		wpa_s->current_bss = bss;
2037*a1157835SDaniel Fojt 		wpa_msg(wpa_s, MSG_INFO, MESH_GROUP_STARTED "ssid=\"%s\" id=%d",
2038*a1157835SDaniel Fojt 			wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
2039*a1157835SDaniel Fojt 			ssid->id);
2040*a1157835SDaniel Fojt 		wpas_notify_mesh_group_started(wpa_s, ssid);
2041*a1157835SDaniel Fojt #else /* CONFIG_MESH */
2042*a1157835SDaniel Fojt 		wpa_msg(wpa_s, MSG_ERROR,
2043*a1157835SDaniel Fojt 			"mesh mode support not included in the build");
2044*a1157835SDaniel Fojt #endif /* CONFIG_MESH */
2045*a1157835SDaniel Fojt 		return;
2046*a1157835SDaniel Fojt 	}
2047*a1157835SDaniel Fojt 
2048*a1157835SDaniel Fojt 	/*
2049*a1157835SDaniel Fojt 	 * Set WPA state machine configuration to match the selected network now
2050*a1157835SDaniel Fojt 	 * so that the information is available before wpas_start_assoc_cb()
2051*a1157835SDaniel Fojt 	 * gets called. This is needed at least for RSN pre-authentication where
2052*a1157835SDaniel Fojt 	 * candidate APs are added to a list based on scan result processing
2053*a1157835SDaniel Fojt 	 * before completion of the first association.
2054*a1157835SDaniel Fojt 	 */
2055*a1157835SDaniel Fojt 	wpa_supplicant_rsn_supp_set_config(wpa_s, ssid);
2056*a1157835SDaniel Fojt 
2057*a1157835SDaniel Fojt #ifdef CONFIG_DPP
2058*a1157835SDaniel Fojt 	if (wpas_dpp_check_connect(wpa_s, ssid, bss) != 0)
2059*a1157835SDaniel Fojt 		return;
2060*a1157835SDaniel Fojt #endif /* CONFIG_DPP */
2061*a1157835SDaniel Fojt 
20623ff40c12SJohn Marino #ifdef CONFIG_TDLS
20633ff40c12SJohn Marino 	if (bss)
20643ff40c12SJohn Marino 		wpa_tdls_ap_ies(wpa_s->wpa, (const u8 *) (bss + 1),
20653ff40c12SJohn Marino 				bss->ie_len);
20663ff40c12SJohn Marino #endif /* CONFIG_TDLS */
20673ff40c12SJohn Marino 
20683ff40c12SJohn Marino 	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
2069*a1157835SDaniel Fojt 	    ssid->mode == WPAS_MODE_INFRA) {
20703ff40c12SJohn Marino 		sme_authenticate(wpa_s, bss, ssid);
20713ff40c12SJohn Marino 		return;
20723ff40c12SJohn Marino 	}
20733ff40c12SJohn Marino 
20743ff40c12SJohn Marino 	if (wpa_s->connect_work) {
20753ff40c12SJohn Marino 		wpa_dbg(wpa_s, MSG_DEBUG, "Reject wpa_supplicant_associate() call since connect_work exist");
20763ff40c12SJohn Marino 		return;
20773ff40c12SJohn Marino 	}
20783ff40c12SJohn Marino 
2079*a1157835SDaniel Fojt 	if (radio_work_pending(wpa_s, "connect")) {
2080*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG, "Reject wpa_supplicant_associate() call since pending work exist");
2081*a1157835SDaniel Fojt 		return;
2082*a1157835SDaniel Fojt 	}
2083*a1157835SDaniel Fojt 
2084*a1157835SDaniel Fojt #ifdef CONFIG_SME
2085*a1157835SDaniel Fojt 	if (ssid->mode == WPAS_MODE_IBSS || ssid->mode == WPAS_MODE_MESH) {
2086*a1157835SDaniel Fojt 		/* Clear possibly set auth_alg, if any, from last attempt. */
2087*a1157835SDaniel Fojt 		wpa_s->sme.auth_alg = WPA_AUTH_ALG_OPEN;
2088*a1157835SDaniel Fojt 	}
2089*a1157835SDaniel Fojt #endif /* CONFIG_SME */
2090*a1157835SDaniel Fojt 
2091*a1157835SDaniel Fojt 	wpas_abort_ongoing_scan(wpa_s);
2092*a1157835SDaniel Fojt 
20933ff40c12SJohn Marino 	cwork = os_zalloc(sizeof(*cwork));
20943ff40c12SJohn Marino 	if (cwork == NULL)
20953ff40c12SJohn Marino 		return;
20963ff40c12SJohn Marino 
20973ff40c12SJohn Marino 	cwork->bss = bss;
20983ff40c12SJohn Marino 	cwork->ssid = ssid;
20993ff40c12SJohn Marino 
21003ff40c12SJohn Marino 	if (radio_add_work(wpa_s, bss ? bss->freq : 0, "connect", 1,
21013ff40c12SJohn Marino 			   wpas_start_assoc_cb, cwork) < 0) {
21023ff40c12SJohn Marino 		os_free(cwork);
21033ff40c12SJohn Marino 	}
21043ff40c12SJohn Marino }
21053ff40c12SJohn Marino 
21063ff40c12SJohn Marino 
bss_is_ibss(struct wpa_bss * bss)2107*a1157835SDaniel Fojt static int bss_is_ibss(struct wpa_bss *bss)
2108*a1157835SDaniel Fojt {
2109*a1157835SDaniel Fojt 	return (bss->caps & (IEEE80211_CAP_ESS | IEEE80211_CAP_IBSS)) ==
2110*a1157835SDaniel Fojt 		IEEE80211_CAP_IBSS;
2111*a1157835SDaniel Fojt }
2112*a1157835SDaniel Fojt 
2113*a1157835SDaniel Fojt 
drv_supports_vht(struct wpa_supplicant * wpa_s,const struct wpa_ssid * ssid)2114*a1157835SDaniel Fojt static int drv_supports_vht(struct wpa_supplicant *wpa_s,
2115*a1157835SDaniel Fojt 			    const struct wpa_ssid *ssid)
2116*a1157835SDaniel Fojt {
2117*a1157835SDaniel Fojt 	enum hostapd_hw_mode hw_mode;
2118*a1157835SDaniel Fojt 	struct hostapd_hw_modes *mode = NULL;
2119*a1157835SDaniel Fojt 	u8 channel;
2120*a1157835SDaniel Fojt 	int i;
2121*a1157835SDaniel Fojt 
2122*a1157835SDaniel Fojt 	hw_mode = ieee80211_freq_to_chan(ssid->frequency, &channel);
2123*a1157835SDaniel Fojt 	if (hw_mode == NUM_HOSTAPD_MODES)
2124*a1157835SDaniel Fojt 		return 0;
2125*a1157835SDaniel Fojt 	for (i = 0; wpa_s->hw.modes && i < wpa_s->hw.num_modes; i++) {
2126*a1157835SDaniel Fojt 		if (wpa_s->hw.modes[i].mode == hw_mode) {
2127*a1157835SDaniel Fojt 			mode = &wpa_s->hw.modes[i];
2128*a1157835SDaniel Fojt 			break;
2129*a1157835SDaniel Fojt 		}
2130*a1157835SDaniel Fojt 	}
2131*a1157835SDaniel Fojt 
2132*a1157835SDaniel Fojt 	if (!mode)
2133*a1157835SDaniel Fojt 		return 0;
2134*a1157835SDaniel Fojt 
2135*a1157835SDaniel Fojt 	return mode->vht_capab != 0;
2136*a1157835SDaniel Fojt }
2137*a1157835SDaniel Fojt 
2138*a1157835SDaniel Fojt 
ibss_mesh_setup_freq(struct wpa_supplicant * wpa_s,const struct wpa_ssid * ssid,struct hostapd_freq_params * freq)2139*a1157835SDaniel Fojt void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s,
2140*a1157835SDaniel Fojt 			  const struct wpa_ssid *ssid,
2141*a1157835SDaniel Fojt 			  struct hostapd_freq_params *freq)
2142*a1157835SDaniel Fojt {
2143*a1157835SDaniel Fojt 	int ieee80211_mode = wpas_mode_to_ieee80211_mode(ssid->mode);
2144*a1157835SDaniel Fojt 	enum hostapd_hw_mode hw_mode;
2145*a1157835SDaniel Fojt 	struct hostapd_hw_modes *mode = NULL;
2146*a1157835SDaniel Fojt 	int ht40plus[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
2147*a1157835SDaniel Fojt 			   184, 192 };
2148*a1157835SDaniel Fojt 	int vht80[] = { 36, 52, 100, 116, 132, 149 };
2149*a1157835SDaniel Fojt 	struct hostapd_channel_data *pri_chan = NULL, *sec_chan = NULL;
2150*a1157835SDaniel Fojt 	u8 channel;
2151*a1157835SDaniel Fojt 	int i, chan_idx, ht40 = -1, res, obss_scan = 1;
2152*a1157835SDaniel Fojt 	unsigned int j, k;
2153*a1157835SDaniel Fojt 	struct hostapd_freq_params vht_freq;
2154*a1157835SDaniel Fojt 	int chwidth, seg0, seg1;
2155*a1157835SDaniel Fojt 	u32 vht_caps = 0;
2156*a1157835SDaniel Fojt 
2157*a1157835SDaniel Fojt 	freq->freq = ssid->frequency;
2158*a1157835SDaniel Fojt 
2159*a1157835SDaniel Fojt 	for (j = 0; j < wpa_s->last_scan_res_used; j++) {
2160*a1157835SDaniel Fojt 		struct wpa_bss *bss = wpa_s->last_scan_res[j];
2161*a1157835SDaniel Fojt 
2162*a1157835SDaniel Fojt 		if (ssid->mode != WPAS_MODE_IBSS)
2163*a1157835SDaniel Fojt 			break;
2164*a1157835SDaniel Fojt 
2165*a1157835SDaniel Fojt 		/* Don't adjust control freq in case of fixed_freq */
2166*a1157835SDaniel Fojt 		if (ssid->fixed_freq)
2167*a1157835SDaniel Fojt 			break;
2168*a1157835SDaniel Fojt 
2169*a1157835SDaniel Fojt 		if (!bss_is_ibss(bss))
2170*a1157835SDaniel Fojt 			continue;
2171*a1157835SDaniel Fojt 
2172*a1157835SDaniel Fojt 		if (ssid->ssid_len == bss->ssid_len &&
2173*a1157835SDaniel Fojt 		    os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) == 0) {
2174*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
2175*a1157835SDaniel Fojt 				   "IBSS already found in scan results, adjust control freq: %d",
2176*a1157835SDaniel Fojt 				   bss->freq);
2177*a1157835SDaniel Fojt 			freq->freq = bss->freq;
2178*a1157835SDaniel Fojt 			obss_scan = 0;
2179*a1157835SDaniel Fojt 			break;
2180*a1157835SDaniel Fojt 		}
2181*a1157835SDaniel Fojt 	}
2182*a1157835SDaniel Fojt 
2183*a1157835SDaniel Fojt 	/* For IBSS check HT_IBSS flag */
2184*a1157835SDaniel Fojt 	if (ssid->mode == WPAS_MODE_IBSS &&
2185*a1157835SDaniel Fojt 	    !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_HT_IBSS))
2186*a1157835SDaniel Fojt 		return;
2187*a1157835SDaniel Fojt 
2188*a1157835SDaniel Fojt 	if (wpa_s->group_cipher == WPA_CIPHER_WEP40 ||
2189*a1157835SDaniel Fojt 	    wpa_s->group_cipher == WPA_CIPHER_WEP104 ||
2190*a1157835SDaniel Fojt 	    wpa_s->pairwise_cipher == WPA_CIPHER_TKIP) {
2191*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
2192*a1157835SDaniel Fojt 			   "IBSS: WEP/TKIP detected, do not try to enable HT");
2193*a1157835SDaniel Fojt 		return;
2194*a1157835SDaniel Fojt 	}
2195*a1157835SDaniel Fojt 
2196*a1157835SDaniel Fojt 	hw_mode = ieee80211_freq_to_chan(freq->freq, &channel);
2197*a1157835SDaniel Fojt 	for (i = 0; wpa_s->hw.modes && i < wpa_s->hw.num_modes; i++) {
2198*a1157835SDaniel Fojt 		if (wpa_s->hw.modes[i].mode == hw_mode) {
2199*a1157835SDaniel Fojt 			mode = &wpa_s->hw.modes[i];
2200*a1157835SDaniel Fojt 			break;
2201*a1157835SDaniel Fojt 		}
2202*a1157835SDaniel Fojt 	}
2203*a1157835SDaniel Fojt 
2204*a1157835SDaniel Fojt 	if (!mode)
2205*a1157835SDaniel Fojt 		return;
2206*a1157835SDaniel Fojt 
2207*a1157835SDaniel Fojt 	/* HE can work without HT + VHT */
2208*a1157835SDaniel Fojt 	freq->he_enabled = mode->he_capab[ieee80211_mode].he_supported;
2209*a1157835SDaniel Fojt 
2210*a1157835SDaniel Fojt #ifdef CONFIG_HT_OVERRIDES
2211*a1157835SDaniel Fojt 	if (ssid->disable_ht) {
2212*a1157835SDaniel Fojt 		freq->ht_enabled = 0;
2213*a1157835SDaniel Fojt 		return;
2214*a1157835SDaniel Fojt 	}
2215*a1157835SDaniel Fojt #endif /* CONFIG_HT_OVERRIDES */
2216*a1157835SDaniel Fojt 
2217*a1157835SDaniel Fojt 	freq->ht_enabled = ht_supported(mode);
2218*a1157835SDaniel Fojt 	if (!freq->ht_enabled)
2219*a1157835SDaniel Fojt 		return;
2220*a1157835SDaniel Fojt 
2221*a1157835SDaniel Fojt 	/* Setup higher BW only for 5 GHz */
2222*a1157835SDaniel Fojt 	if (mode->mode != HOSTAPD_MODE_IEEE80211A)
2223*a1157835SDaniel Fojt 		return;
2224*a1157835SDaniel Fojt 
2225*a1157835SDaniel Fojt 	for (chan_idx = 0; chan_idx < mode->num_channels; chan_idx++) {
2226*a1157835SDaniel Fojt 		pri_chan = &mode->channels[chan_idx];
2227*a1157835SDaniel Fojt 		if (pri_chan->chan == channel)
2228*a1157835SDaniel Fojt 			break;
2229*a1157835SDaniel Fojt 		pri_chan = NULL;
2230*a1157835SDaniel Fojt 	}
2231*a1157835SDaniel Fojt 	if (!pri_chan)
2232*a1157835SDaniel Fojt 		return;
2233*a1157835SDaniel Fojt 
2234*a1157835SDaniel Fojt 	/* Check primary channel flags */
2235*a1157835SDaniel Fojt 	if (pri_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
2236*a1157835SDaniel Fojt 		return;
2237*a1157835SDaniel Fojt 
2238*a1157835SDaniel Fojt 	freq->channel = pri_chan->chan;
2239*a1157835SDaniel Fojt 
2240*a1157835SDaniel Fojt #ifdef CONFIG_HT_OVERRIDES
2241*a1157835SDaniel Fojt 	if (ssid->disable_ht40) {
2242*a1157835SDaniel Fojt 		if (ssid->disable_vht)
2243*a1157835SDaniel Fojt 			return;
2244*a1157835SDaniel Fojt 		goto skip_ht40;
2245*a1157835SDaniel Fojt 	}
2246*a1157835SDaniel Fojt #endif /* CONFIG_HT_OVERRIDES */
2247*a1157835SDaniel Fojt 
2248*a1157835SDaniel Fojt 	/* Check/setup HT40+/HT40- */
2249*a1157835SDaniel Fojt 	for (j = 0; j < ARRAY_SIZE(ht40plus); j++) {
2250*a1157835SDaniel Fojt 		if (ht40plus[j] == channel) {
2251*a1157835SDaniel Fojt 			ht40 = 1;
2252*a1157835SDaniel Fojt 			break;
2253*a1157835SDaniel Fojt 		}
2254*a1157835SDaniel Fojt 	}
2255*a1157835SDaniel Fojt 
2256*a1157835SDaniel Fojt 	/* Find secondary channel */
2257*a1157835SDaniel Fojt 	for (i = 0; i < mode->num_channels; i++) {
2258*a1157835SDaniel Fojt 		sec_chan = &mode->channels[i];
2259*a1157835SDaniel Fojt 		if (sec_chan->chan == channel + ht40 * 4)
2260*a1157835SDaniel Fojt 			break;
2261*a1157835SDaniel Fojt 		sec_chan = NULL;
2262*a1157835SDaniel Fojt 	}
2263*a1157835SDaniel Fojt 	if (!sec_chan)
2264*a1157835SDaniel Fojt 		return;
2265*a1157835SDaniel Fojt 
2266*a1157835SDaniel Fojt 	/* Check secondary channel flags */
2267*a1157835SDaniel Fojt 	if (sec_chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
2268*a1157835SDaniel Fojt 		return;
2269*a1157835SDaniel Fojt 
2270*a1157835SDaniel Fojt 	if (ht40 == -1) {
2271*a1157835SDaniel Fojt 		if (!(pri_chan->flag & HOSTAPD_CHAN_HT40MINUS))
2272*a1157835SDaniel Fojt 			return;
2273*a1157835SDaniel Fojt 	} else {
2274*a1157835SDaniel Fojt 		if (!(pri_chan->flag & HOSTAPD_CHAN_HT40PLUS))
2275*a1157835SDaniel Fojt 			return;
2276*a1157835SDaniel Fojt 	}
2277*a1157835SDaniel Fojt 	freq->sec_channel_offset = ht40;
2278*a1157835SDaniel Fojt 
2279*a1157835SDaniel Fojt 	if (obss_scan) {
2280*a1157835SDaniel Fojt 		struct wpa_scan_results *scan_res;
2281*a1157835SDaniel Fojt 
2282*a1157835SDaniel Fojt 		scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0);
2283*a1157835SDaniel Fojt 		if (scan_res == NULL) {
2284*a1157835SDaniel Fojt 			/* Back to HT20 */
2285*a1157835SDaniel Fojt 			freq->sec_channel_offset = 0;
2286*a1157835SDaniel Fojt 			return;
2287*a1157835SDaniel Fojt 		}
2288*a1157835SDaniel Fojt 
2289*a1157835SDaniel Fojt 		res = check_40mhz_5g(mode, scan_res, pri_chan->chan,
2290*a1157835SDaniel Fojt 				     sec_chan->chan);
2291*a1157835SDaniel Fojt 		switch (res) {
2292*a1157835SDaniel Fojt 		case 0:
2293*a1157835SDaniel Fojt 			/* Back to HT20 */
2294*a1157835SDaniel Fojt 			freq->sec_channel_offset = 0;
2295*a1157835SDaniel Fojt 			break;
2296*a1157835SDaniel Fojt 		case 1:
2297*a1157835SDaniel Fojt 			/* Configuration allowed */
2298*a1157835SDaniel Fojt 			break;
2299*a1157835SDaniel Fojt 		case 2:
2300*a1157835SDaniel Fojt 			/* Switch pri/sec channels */
2301*a1157835SDaniel Fojt 			freq->freq = hw_get_freq(mode, sec_chan->chan);
2302*a1157835SDaniel Fojt 			freq->sec_channel_offset = -freq->sec_channel_offset;
2303*a1157835SDaniel Fojt 			freq->channel = sec_chan->chan;
2304*a1157835SDaniel Fojt 			break;
2305*a1157835SDaniel Fojt 		default:
2306*a1157835SDaniel Fojt 			freq->sec_channel_offset = 0;
2307*a1157835SDaniel Fojt 			break;
2308*a1157835SDaniel Fojt 		}
2309*a1157835SDaniel Fojt 
2310*a1157835SDaniel Fojt 		wpa_scan_results_free(scan_res);
2311*a1157835SDaniel Fojt 	}
2312*a1157835SDaniel Fojt 
2313*a1157835SDaniel Fojt #ifdef CONFIG_HT_OVERRIDES
2314*a1157835SDaniel Fojt skip_ht40:
2315*a1157835SDaniel Fojt #endif /* CONFIG_HT_OVERRIDES */
2316*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG,
2317*a1157835SDaniel Fojt 		   "IBSS/mesh: setup freq channel %d, sec_channel_offset %d",
2318*a1157835SDaniel Fojt 		   freq->channel, freq->sec_channel_offset);
2319*a1157835SDaniel Fojt 
2320*a1157835SDaniel Fojt 	if (!drv_supports_vht(wpa_s, ssid))
2321*a1157835SDaniel Fojt 		return;
2322*a1157835SDaniel Fojt 
2323*a1157835SDaniel Fojt 	/* For IBSS check VHT_IBSS flag */
2324*a1157835SDaniel Fojt 	if (ssid->mode == WPAS_MODE_IBSS &&
2325*a1157835SDaniel Fojt 	    !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_VHT_IBSS))
2326*a1157835SDaniel Fojt 		return;
2327*a1157835SDaniel Fojt 
2328*a1157835SDaniel Fojt 	vht_freq = *freq;
2329*a1157835SDaniel Fojt 
2330*a1157835SDaniel Fojt #ifdef CONFIG_VHT_OVERRIDES
2331*a1157835SDaniel Fojt 	if (ssid->disable_vht) {
2332*a1157835SDaniel Fojt 		freq->vht_enabled = 0;
2333*a1157835SDaniel Fojt 		return;
2334*a1157835SDaniel Fojt 	}
2335*a1157835SDaniel Fojt #endif /* CONFIG_VHT_OVERRIDES */
2336*a1157835SDaniel Fojt 
2337*a1157835SDaniel Fojt 	vht_freq.vht_enabled = vht_supported(mode);
2338*a1157835SDaniel Fojt 	if (!vht_freq.vht_enabled)
2339*a1157835SDaniel Fojt 		return;
2340*a1157835SDaniel Fojt 
2341*a1157835SDaniel Fojt 	/* setup center_freq1, bandwidth */
2342*a1157835SDaniel Fojt 	for (j = 0; j < ARRAY_SIZE(vht80); j++) {
2343*a1157835SDaniel Fojt 		if (freq->channel >= vht80[j] &&
2344*a1157835SDaniel Fojt 		    freq->channel < vht80[j] + 16)
2345*a1157835SDaniel Fojt 			break;
2346*a1157835SDaniel Fojt 	}
2347*a1157835SDaniel Fojt 
2348*a1157835SDaniel Fojt 	if (j == ARRAY_SIZE(vht80))
2349*a1157835SDaniel Fojt 		return;
2350*a1157835SDaniel Fojt 
2351*a1157835SDaniel Fojt 	for (i = vht80[j]; i < vht80[j] + 16; i += 4) {
2352*a1157835SDaniel Fojt 		struct hostapd_channel_data *chan;
2353*a1157835SDaniel Fojt 
2354*a1157835SDaniel Fojt 		chan = hw_get_channel_chan(mode, i, NULL);
2355*a1157835SDaniel Fojt 		if (!chan)
2356*a1157835SDaniel Fojt 			return;
2357*a1157835SDaniel Fojt 
2358*a1157835SDaniel Fojt 		/* Back to HT configuration if channel not usable */
2359*a1157835SDaniel Fojt 		if (chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_NO_IR))
2360*a1157835SDaniel Fojt 			return;
2361*a1157835SDaniel Fojt 	}
2362*a1157835SDaniel Fojt 
2363*a1157835SDaniel Fojt 	chwidth = CHANWIDTH_80MHZ;
2364*a1157835SDaniel Fojt 	seg0 = vht80[j] + 6;
2365*a1157835SDaniel Fojt 	seg1 = 0;
2366*a1157835SDaniel Fojt 
2367*a1157835SDaniel Fojt 	if (ssid->max_oper_chwidth == CHANWIDTH_80P80MHZ) {
2368*a1157835SDaniel Fojt 		/* setup center_freq2, bandwidth */
2369*a1157835SDaniel Fojt 		for (k = 0; k < ARRAY_SIZE(vht80); k++) {
2370*a1157835SDaniel Fojt 			/* Only accept 80 MHz segments separated by a gap */
2371*a1157835SDaniel Fojt 			if (j == k || abs(vht80[j] - vht80[k]) == 16)
2372*a1157835SDaniel Fojt 				continue;
2373*a1157835SDaniel Fojt 			for (i = vht80[k]; i < vht80[k] + 16; i += 4) {
2374*a1157835SDaniel Fojt 				struct hostapd_channel_data *chan;
2375*a1157835SDaniel Fojt 
2376*a1157835SDaniel Fojt 				chan = hw_get_channel_chan(mode, i, NULL);
2377*a1157835SDaniel Fojt 				if (!chan)
2378*a1157835SDaniel Fojt 					continue;
2379*a1157835SDaniel Fojt 
2380*a1157835SDaniel Fojt 				if (chan->flag & (HOSTAPD_CHAN_DISABLED |
2381*a1157835SDaniel Fojt 						  HOSTAPD_CHAN_NO_IR |
2382*a1157835SDaniel Fojt 						  HOSTAPD_CHAN_RADAR))
2383*a1157835SDaniel Fojt 					continue;
2384*a1157835SDaniel Fojt 
2385*a1157835SDaniel Fojt 				/* Found a suitable second segment for 80+80 */
2386*a1157835SDaniel Fojt 				chwidth = CHANWIDTH_80P80MHZ;
2387*a1157835SDaniel Fojt 				vht_caps |=
2388*a1157835SDaniel Fojt 					VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
2389*a1157835SDaniel Fojt 				seg1 = vht80[k] + 6;
2390*a1157835SDaniel Fojt 			}
2391*a1157835SDaniel Fojt 
2392*a1157835SDaniel Fojt 			if (chwidth == CHANWIDTH_80P80MHZ)
2393*a1157835SDaniel Fojt 				break;
2394*a1157835SDaniel Fojt 		}
2395*a1157835SDaniel Fojt 	} else if (ssid->max_oper_chwidth == CHANWIDTH_160MHZ) {
2396*a1157835SDaniel Fojt 		if (freq->freq == 5180) {
2397*a1157835SDaniel Fojt 			chwidth = CHANWIDTH_160MHZ;
2398*a1157835SDaniel Fojt 			vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
2399*a1157835SDaniel Fojt 			seg0 = 50;
2400*a1157835SDaniel Fojt 		} else if (freq->freq == 5520) {
2401*a1157835SDaniel Fojt 			chwidth = CHANWIDTH_160MHZ;
2402*a1157835SDaniel Fojt 			vht_caps |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
2403*a1157835SDaniel Fojt 			seg0 = 114;
2404*a1157835SDaniel Fojt 		}
2405*a1157835SDaniel Fojt 	} else if (ssid->max_oper_chwidth == CHANWIDTH_USE_HT) {
2406*a1157835SDaniel Fojt 		chwidth = CHANWIDTH_USE_HT;
2407*a1157835SDaniel Fojt 		seg0 = vht80[j] + 2;
2408*a1157835SDaniel Fojt #ifdef CONFIG_HT_OVERRIDES
2409*a1157835SDaniel Fojt 		if (ssid->disable_ht40)
2410*a1157835SDaniel Fojt 			seg0 = 0;
2411*a1157835SDaniel Fojt #endif /* CONFIG_HT_OVERRIDES */
2412*a1157835SDaniel Fojt 	}
2413*a1157835SDaniel Fojt 
2414*a1157835SDaniel Fojt 	if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq,
2415*a1157835SDaniel Fojt 				    freq->channel, freq->ht_enabled,
2416*a1157835SDaniel Fojt 				    vht_freq.vht_enabled, freq->he_enabled,
2417*a1157835SDaniel Fojt 				    freq->sec_channel_offset,
2418*a1157835SDaniel Fojt 				    chwidth, seg0, seg1, vht_caps,
2419*a1157835SDaniel Fojt 				    &mode->he_capab[ieee80211_mode]) != 0)
2420*a1157835SDaniel Fojt 		return;
2421*a1157835SDaniel Fojt 
2422*a1157835SDaniel Fojt 	*freq = vht_freq;
2423*a1157835SDaniel Fojt 
2424*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "IBSS: VHT setup freq cf1 %d, cf2 %d, bw %d",
2425*a1157835SDaniel Fojt 		   freq->center_freq1, freq->center_freq2, freq->bandwidth);
2426*a1157835SDaniel Fojt }
2427*a1157835SDaniel Fojt 
2428*a1157835SDaniel Fojt 
2429*a1157835SDaniel Fojt #ifdef CONFIG_FILS
wpas_add_fils_hlp_req(struct wpa_supplicant * wpa_s,u8 * ie_buf,size_t ie_buf_len)2430*a1157835SDaniel Fojt static size_t wpas_add_fils_hlp_req(struct wpa_supplicant *wpa_s, u8 *ie_buf,
2431*a1157835SDaniel Fojt 				    size_t ie_buf_len)
2432*a1157835SDaniel Fojt {
2433*a1157835SDaniel Fojt 	struct fils_hlp_req *req;
2434*a1157835SDaniel Fojt 	size_t rem_len, hdr_len, hlp_len, len, ie_len = 0;
2435*a1157835SDaniel Fojt 	const u8 *pos;
2436*a1157835SDaniel Fojt 	u8 *buf = ie_buf;
2437*a1157835SDaniel Fojt 
2438*a1157835SDaniel Fojt 	dl_list_for_each(req, &wpa_s->fils_hlp_req, struct fils_hlp_req,
2439*a1157835SDaniel Fojt 			 list) {
2440*a1157835SDaniel Fojt 		rem_len = ie_buf_len - ie_len;
2441*a1157835SDaniel Fojt 		pos = wpabuf_head(req->pkt);
2442*a1157835SDaniel Fojt 		hdr_len = 1 + 2 * ETH_ALEN + 6;
2443*a1157835SDaniel Fojt 		hlp_len = wpabuf_len(req->pkt);
2444*a1157835SDaniel Fojt 
2445*a1157835SDaniel Fojt 		if (rem_len < 2 + hdr_len + hlp_len) {
2446*a1157835SDaniel Fojt 			wpa_printf(MSG_ERROR,
2447*a1157835SDaniel Fojt 				   "FILS: Cannot fit HLP - rem_len=%lu to_fill=%lu",
2448*a1157835SDaniel Fojt 				   (unsigned long) rem_len,
2449*a1157835SDaniel Fojt 				   (unsigned long) (2 + hdr_len + hlp_len));
2450*a1157835SDaniel Fojt 			break;
2451*a1157835SDaniel Fojt 		}
2452*a1157835SDaniel Fojt 
2453*a1157835SDaniel Fojt 		len = (hdr_len + hlp_len) > 255 ? 255 : hdr_len + hlp_len;
2454*a1157835SDaniel Fojt 		/* Element ID */
2455*a1157835SDaniel Fojt 		*buf++ = WLAN_EID_EXTENSION;
2456*a1157835SDaniel Fojt 		/* Length */
2457*a1157835SDaniel Fojt 		*buf++ = len;
2458*a1157835SDaniel Fojt 		/* Element ID Extension */
2459*a1157835SDaniel Fojt 		*buf++ = WLAN_EID_EXT_FILS_HLP_CONTAINER;
2460*a1157835SDaniel Fojt 		/* Destination MAC address */
2461*a1157835SDaniel Fojt 		os_memcpy(buf, req->dst, ETH_ALEN);
2462*a1157835SDaniel Fojt 		buf += ETH_ALEN;
2463*a1157835SDaniel Fojt 		/* Source MAC address */
2464*a1157835SDaniel Fojt 		os_memcpy(buf, wpa_s->own_addr, ETH_ALEN);
2465*a1157835SDaniel Fojt 		buf += ETH_ALEN;
2466*a1157835SDaniel Fojt 		/* LLC/SNAP Header */
2467*a1157835SDaniel Fojt 		os_memcpy(buf, "\xaa\xaa\x03\x00\x00\x00", 6);
2468*a1157835SDaniel Fojt 		buf += 6;
2469*a1157835SDaniel Fojt 		/* HLP Packet */
2470*a1157835SDaniel Fojt 		os_memcpy(buf, pos, len - hdr_len);
2471*a1157835SDaniel Fojt 		buf += len - hdr_len;
2472*a1157835SDaniel Fojt 		pos += len - hdr_len;
2473*a1157835SDaniel Fojt 
2474*a1157835SDaniel Fojt 		hlp_len -= len - hdr_len;
2475*a1157835SDaniel Fojt 		ie_len += 2 + len;
2476*a1157835SDaniel Fojt 		rem_len -= 2 + len;
2477*a1157835SDaniel Fojt 
2478*a1157835SDaniel Fojt 		while (hlp_len) {
2479*a1157835SDaniel Fojt 			len = (hlp_len > 255) ? 255 : hlp_len;
2480*a1157835SDaniel Fojt 			if (rem_len < 2 + len)
2481*a1157835SDaniel Fojt 				break;
2482*a1157835SDaniel Fojt 			*buf++ = WLAN_EID_FRAGMENT;
2483*a1157835SDaniel Fojt 			*buf++ = len;
2484*a1157835SDaniel Fojt 			os_memcpy(buf, pos, len);
2485*a1157835SDaniel Fojt 			buf += len;
2486*a1157835SDaniel Fojt 			pos += len;
2487*a1157835SDaniel Fojt 
2488*a1157835SDaniel Fojt 			hlp_len -= len;
2489*a1157835SDaniel Fojt 			ie_len += 2 + len;
2490*a1157835SDaniel Fojt 			rem_len -= 2 + len;
2491*a1157835SDaniel Fojt 		}
2492*a1157835SDaniel Fojt 	}
2493*a1157835SDaniel Fojt 
2494*a1157835SDaniel Fojt 	return ie_len;
2495*a1157835SDaniel Fojt }
2496*a1157835SDaniel Fojt 
2497*a1157835SDaniel Fojt 
wpa_is_fils_supported(struct wpa_supplicant * wpa_s)2498*a1157835SDaniel Fojt int wpa_is_fils_supported(struct wpa_supplicant *wpa_s)
2499*a1157835SDaniel Fojt {
2500*a1157835SDaniel Fojt 	return (((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
2501*a1157835SDaniel Fojt 		 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_FILS)) ||
2502*a1157835SDaniel Fojt 		(!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
2503*a1157835SDaniel Fojt 		 (wpa_s->drv_flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD)));
2504*a1157835SDaniel Fojt }
2505*a1157835SDaniel Fojt 
2506*a1157835SDaniel Fojt 
wpa_is_fils_sk_pfs_supported(struct wpa_supplicant * wpa_s)2507*a1157835SDaniel Fojt int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s)
2508*a1157835SDaniel Fojt {
2509*a1157835SDaniel Fojt #ifdef CONFIG_FILS_SK_PFS
2510*a1157835SDaniel Fojt 	return (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
2511*a1157835SDaniel Fojt 		(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_FILS);
2512*a1157835SDaniel Fojt #else /* CONFIG_FILS_SK_PFS */
2513*a1157835SDaniel Fojt 	return 0;
2514*a1157835SDaniel Fojt #endif /* CONFIG_FILS_SK_PFS */
2515*a1157835SDaniel Fojt }
2516*a1157835SDaniel Fojt 
2517*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
2518*a1157835SDaniel Fojt 
2519*a1157835SDaniel Fojt 
wpas_populate_assoc_ies(struct wpa_supplicant * wpa_s,struct wpa_bss * bss,struct wpa_ssid * ssid,struct wpa_driver_associate_params * params,enum wpa_drv_update_connect_params_mask * mask)2520*a1157835SDaniel Fojt static u8 * wpas_populate_assoc_ies(
2521*a1157835SDaniel Fojt 	struct wpa_supplicant *wpa_s,
2522*a1157835SDaniel Fojt 	struct wpa_bss *bss, struct wpa_ssid *ssid,
2523*a1157835SDaniel Fojt 	struct wpa_driver_associate_params *params,
2524*a1157835SDaniel Fojt 	enum wpa_drv_update_connect_params_mask *mask)
2525*a1157835SDaniel Fojt {
2526*a1157835SDaniel Fojt 	u8 *wpa_ie;
2527*a1157835SDaniel Fojt 	size_t max_wpa_ie_len = 500;
2528*a1157835SDaniel Fojt 	size_t wpa_ie_len;
2529*a1157835SDaniel Fojt 	int algs = WPA_AUTH_ALG_OPEN;
2530*a1157835SDaniel Fojt #ifdef CONFIG_MBO
2531*a1157835SDaniel Fojt 	const u8 *mbo_ie;
2532*a1157835SDaniel Fojt #endif
2533*a1157835SDaniel Fojt #ifdef CONFIG_SAE
2534*a1157835SDaniel Fojt 	int sae_pmksa_cached = 0;
2535*a1157835SDaniel Fojt #endif /* CONFIG_SAE */
2536*a1157835SDaniel Fojt #ifdef CONFIG_FILS
2537*a1157835SDaniel Fojt 	const u8 *realm, *username, *rrk;
2538*a1157835SDaniel Fojt 	size_t realm_len, username_len, rrk_len;
2539*a1157835SDaniel Fojt 	u16 next_seq_num;
2540*a1157835SDaniel Fojt 	struct fils_hlp_req *req;
2541*a1157835SDaniel Fojt 
2542*a1157835SDaniel Fojt 	dl_list_for_each(req, &wpa_s->fils_hlp_req, struct fils_hlp_req,
2543*a1157835SDaniel Fojt 			 list) {
2544*a1157835SDaniel Fojt 		max_wpa_ie_len += 3 + 2 * ETH_ALEN + 6 + wpabuf_len(req->pkt) +
2545*a1157835SDaniel Fojt 				  2 + 2 * wpabuf_len(req->pkt) / 255;
2546*a1157835SDaniel Fojt 	}
2547*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
2548*a1157835SDaniel Fojt 
2549*a1157835SDaniel Fojt 	wpa_ie = os_malloc(max_wpa_ie_len);
2550*a1157835SDaniel Fojt 	if (!wpa_ie) {
2551*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR,
2552*a1157835SDaniel Fojt 			   "Failed to allocate connect IE buffer for %lu bytes",
2553*a1157835SDaniel Fojt 			   (unsigned long) max_wpa_ie_len);
2554*a1157835SDaniel Fojt 		return NULL;
2555*a1157835SDaniel Fojt 	}
2556*a1157835SDaniel Fojt 
2557*a1157835SDaniel Fojt 	if (bss && (wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
2558*a1157835SDaniel Fojt 		    wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
2559*a1157835SDaniel Fojt 	    wpa_key_mgmt_wpa(ssid->key_mgmt)) {
2560*a1157835SDaniel Fojt 		int try_opportunistic;
2561*a1157835SDaniel Fojt 		const u8 *cache_id = NULL;
2562*a1157835SDaniel Fojt 
2563*a1157835SDaniel Fojt 		try_opportunistic = (ssid->proactive_key_caching < 0 ?
2564*a1157835SDaniel Fojt 				     wpa_s->conf->okc :
2565*a1157835SDaniel Fojt 				     ssid->proactive_key_caching) &&
2566*a1157835SDaniel Fojt 			(ssid->proto & WPA_PROTO_RSN);
2567*a1157835SDaniel Fojt #ifdef CONFIG_FILS
2568*a1157835SDaniel Fojt 		if (wpa_key_mgmt_fils(ssid->key_mgmt))
2569*a1157835SDaniel Fojt 			cache_id = wpa_bss_get_fils_cache_id(bss);
2570*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
2571*a1157835SDaniel Fojt 		if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
2572*a1157835SDaniel Fojt 					    ssid, try_opportunistic,
2573*a1157835SDaniel Fojt 					    cache_id, 0) == 0) {
2574*a1157835SDaniel Fojt 			eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
2575*a1157835SDaniel Fojt #ifdef CONFIG_SAE
2576*a1157835SDaniel Fojt 			sae_pmksa_cached = 1;
2577*a1157835SDaniel Fojt #endif /* CONFIG_SAE */
2578*a1157835SDaniel Fojt 		}
2579*a1157835SDaniel Fojt 		wpa_ie_len = max_wpa_ie_len;
2580*a1157835SDaniel Fojt 		if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
2581*a1157835SDaniel Fojt 					      wpa_ie, &wpa_ie_len)) {
2582*a1157835SDaniel Fojt 			wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
2583*a1157835SDaniel Fojt 				"key management and encryption suites");
2584*a1157835SDaniel Fojt 			os_free(wpa_ie);
2585*a1157835SDaniel Fojt 			return NULL;
2586*a1157835SDaniel Fojt 		}
2587*a1157835SDaniel Fojt #ifdef CONFIG_HS20
2588*a1157835SDaniel Fojt 	} else if (bss && wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE) &&
2589*a1157835SDaniel Fojt 		   (ssid->key_mgmt & WPA_KEY_MGMT_OSEN)) {
2590*a1157835SDaniel Fojt 		/* No PMKSA caching, but otherwise similar to RSN/WPA */
2591*a1157835SDaniel Fojt 		wpa_ie_len = max_wpa_ie_len;
2592*a1157835SDaniel Fojt 		if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
2593*a1157835SDaniel Fojt 					      wpa_ie, &wpa_ie_len)) {
2594*a1157835SDaniel Fojt 			wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
2595*a1157835SDaniel Fojt 				"key management and encryption suites");
2596*a1157835SDaniel Fojt 			os_free(wpa_ie);
2597*a1157835SDaniel Fojt 			return NULL;
2598*a1157835SDaniel Fojt 		}
2599*a1157835SDaniel Fojt #endif /* CONFIG_HS20 */
2600*a1157835SDaniel Fojt 	} else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && bss &&
2601*a1157835SDaniel Fojt 		   wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) {
2602*a1157835SDaniel Fojt 		/*
2603*a1157835SDaniel Fojt 		 * Both WPA and non-WPA IEEE 802.1X enabled in configuration -
2604*a1157835SDaniel Fojt 		 * use non-WPA since the scan results did not indicate that the
2605*a1157835SDaniel Fojt 		 * AP is using WPA or WPA2.
2606*a1157835SDaniel Fojt 		 */
2607*a1157835SDaniel Fojt 		wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
2608*a1157835SDaniel Fojt 		wpa_ie_len = 0;
2609*a1157835SDaniel Fojt 		wpa_s->wpa_proto = 0;
2610*a1157835SDaniel Fojt 	} else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
2611*a1157835SDaniel Fojt 		wpa_ie_len = max_wpa_ie_len;
2612*a1157835SDaniel Fojt 		if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
2613*a1157835SDaniel Fojt 					      wpa_ie, &wpa_ie_len)) {
2614*a1157835SDaniel Fojt 			wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
2615*a1157835SDaniel Fojt 				"key management and encryption suites (no "
2616*a1157835SDaniel Fojt 				"scan results)");
2617*a1157835SDaniel Fojt 			os_free(wpa_ie);
2618*a1157835SDaniel Fojt 			return NULL;
2619*a1157835SDaniel Fojt 		}
2620*a1157835SDaniel Fojt #ifdef CONFIG_WPS
2621*a1157835SDaniel Fojt 	} else if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
2622*a1157835SDaniel Fojt 		struct wpabuf *wps_ie;
2623*a1157835SDaniel Fojt 		wps_ie = wps_build_assoc_req_ie(wpas_wps_get_req_type(ssid));
2624*a1157835SDaniel Fojt 		if (wps_ie && wpabuf_len(wps_ie) <= max_wpa_ie_len) {
2625*a1157835SDaniel Fojt 			wpa_ie_len = wpabuf_len(wps_ie);
2626*a1157835SDaniel Fojt 			os_memcpy(wpa_ie, wpabuf_head(wps_ie), wpa_ie_len);
2627*a1157835SDaniel Fojt 		} else
2628*a1157835SDaniel Fojt 			wpa_ie_len = 0;
2629*a1157835SDaniel Fojt 		wpabuf_free(wps_ie);
2630*a1157835SDaniel Fojt 		wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
2631*a1157835SDaniel Fojt 		if (!bss || (bss->caps & IEEE80211_CAP_PRIVACY))
2632*a1157835SDaniel Fojt 			params->wps = WPS_MODE_PRIVACY;
2633*a1157835SDaniel Fojt 		else
2634*a1157835SDaniel Fojt 			params->wps = WPS_MODE_OPEN;
2635*a1157835SDaniel Fojt 		wpa_s->wpa_proto = 0;
2636*a1157835SDaniel Fojt #endif /* CONFIG_WPS */
2637*a1157835SDaniel Fojt 	} else {
2638*a1157835SDaniel Fojt 		wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
2639*a1157835SDaniel Fojt 		wpa_ie_len = 0;
2640*a1157835SDaniel Fojt 		wpa_s->wpa_proto = 0;
2641*a1157835SDaniel Fojt 	}
2642*a1157835SDaniel Fojt 
2643*a1157835SDaniel Fojt #ifdef IEEE8021X_EAPOL
2644*a1157835SDaniel Fojt 	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
2645*a1157835SDaniel Fojt 		if (ssid->leap) {
2646*a1157835SDaniel Fojt 			if (ssid->non_leap == 0)
2647*a1157835SDaniel Fojt 				algs = WPA_AUTH_ALG_LEAP;
2648*a1157835SDaniel Fojt 			else
2649*a1157835SDaniel Fojt 				algs |= WPA_AUTH_ALG_LEAP;
2650*a1157835SDaniel Fojt 		}
2651*a1157835SDaniel Fojt 	}
2652*a1157835SDaniel Fojt 
2653*a1157835SDaniel Fojt #ifdef CONFIG_FILS
2654*a1157835SDaniel Fojt 	/* Clear FILS association */
2655*a1157835SDaniel Fojt 	wpa_sm_set_reset_fils_completed(wpa_s->wpa, 0);
2656*a1157835SDaniel Fojt 
2657*a1157835SDaniel Fojt 	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_FILS_SK_OFFLOAD) &&
2658*a1157835SDaniel Fojt 	    ssid->eap.erp && wpa_key_mgmt_fils(wpa_s->key_mgmt) &&
2659*a1157835SDaniel Fojt 	    eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap, &username,
2660*a1157835SDaniel Fojt 				  &username_len, &realm, &realm_len,
2661*a1157835SDaniel Fojt 				  &next_seq_num, &rrk, &rrk_len) == 0 &&
2662*a1157835SDaniel Fojt 	    (!wpa_s->last_con_fail_realm ||
2663*a1157835SDaniel Fojt 	     wpa_s->last_con_fail_realm_len != realm_len ||
2664*a1157835SDaniel Fojt 	     os_memcmp(wpa_s->last_con_fail_realm, realm, realm_len) != 0)) {
2665*a1157835SDaniel Fojt 		algs = WPA_AUTH_ALG_FILS;
2666*a1157835SDaniel Fojt 		params->fils_erp_username = username;
2667*a1157835SDaniel Fojt 		params->fils_erp_username_len = username_len;
2668*a1157835SDaniel Fojt 		params->fils_erp_realm = realm;
2669*a1157835SDaniel Fojt 		params->fils_erp_realm_len = realm_len;
2670*a1157835SDaniel Fojt 		params->fils_erp_next_seq_num = next_seq_num;
2671*a1157835SDaniel Fojt 		params->fils_erp_rrk = rrk;
2672*a1157835SDaniel Fojt 		params->fils_erp_rrk_len = rrk_len;
2673*a1157835SDaniel Fojt 
2674*a1157835SDaniel Fojt 		if (mask)
2675*a1157835SDaniel Fojt 			*mask |= WPA_DRV_UPDATE_FILS_ERP_INFO;
2676*a1157835SDaniel Fojt 	}
2677*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
2678*a1157835SDaniel Fojt #endif /* IEEE8021X_EAPOL */
2679*a1157835SDaniel Fojt #ifdef CONFIG_SAE
2680*a1157835SDaniel Fojt 	if (wpa_s->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE))
2681*a1157835SDaniel Fojt 		algs = WPA_AUTH_ALG_SAE;
2682*a1157835SDaniel Fojt #endif /* CONFIG_SAE */
2683*a1157835SDaniel Fojt 
2684*a1157835SDaniel Fojt 	wpa_dbg(wpa_s, MSG_DEBUG, "Automatic auth_alg selection: 0x%x", algs);
2685*a1157835SDaniel Fojt 	if (ssid->auth_alg) {
2686*a1157835SDaniel Fojt 		algs = ssid->auth_alg;
2687*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG,
2688*a1157835SDaniel Fojt 			"Overriding auth_alg selection: 0x%x", algs);
2689*a1157835SDaniel Fojt 	}
2690*a1157835SDaniel Fojt 
2691*a1157835SDaniel Fojt #ifdef CONFIG_SAE
2692*a1157835SDaniel Fojt 	if (sae_pmksa_cached && algs == WPA_AUTH_ALG_SAE) {
2693*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG,
2694*a1157835SDaniel Fojt 			"SAE: Use WPA_AUTH_ALG_OPEN for PMKSA caching attempt");
2695*a1157835SDaniel Fojt 		algs = WPA_AUTH_ALG_OPEN;
2696*a1157835SDaniel Fojt 	}
2697*a1157835SDaniel Fojt #endif /* CONFIG_SAE */
2698*a1157835SDaniel Fojt 
2699*a1157835SDaniel Fojt #ifdef CONFIG_P2P
2700*a1157835SDaniel Fojt 	if (wpa_s->global->p2p) {
2701*a1157835SDaniel Fojt 		u8 *pos;
2702*a1157835SDaniel Fojt 		size_t len;
2703*a1157835SDaniel Fojt 		int res;
2704*a1157835SDaniel Fojt 		pos = wpa_ie + wpa_ie_len;
2705*a1157835SDaniel Fojt 		len = max_wpa_ie_len - wpa_ie_len;
2706*a1157835SDaniel Fojt 		res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len,
2707*a1157835SDaniel Fojt 					    ssid->p2p_group);
2708*a1157835SDaniel Fojt 		if (res >= 0)
2709*a1157835SDaniel Fojt 			wpa_ie_len += res;
2710*a1157835SDaniel Fojt 	}
2711*a1157835SDaniel Fojt 
2712*a1157835SDaniel Fojt 	wpa_s->cross_connect_disallowed = 0;
2713*a1157835SDaniel Fojt 	if (bss) {
2714*a1157835SDaniel Fojt 		struct wpabuf *p2p;
2715*a1157835SDaniel Fojt 		p2p = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE);
2716*a1157835SDaniel Fojt 		if (p2p) {
2717*a1157835SDaniel Fojt 			wpa_s->cross_connect_disallowed =
2718*a1157835SDaniel Fojt 				p2p_get_cross_connect_disallowed(p2p);
2719*a1157835SDaniel Fojt 			wpabuf_free(p2p);
2720*a1157835SDaniel Fojt 			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: WLAN AP %s cross "
2721*a1157835SDaniel Fojt 				"connection",
2722*a1157835SDaniel Fojt 				wpa_s->cross_connect_disallowed ?
2723*a1157835SDaniel Fojt 				"disallows" : "allows");
2724*a1157835SDaniel Fojt 		}
2725*a1157835SDaniel Fojt 	}
2726*a1157835SDaniel Fojt 
2727*a1157835SDaniel Fojt 	os_memset(wpa_s->p2p_ip_addr_info, 0, sizeof(wpa_s->p2p_ip_addr_info));
2728*a1157835SDaniel Fojt #endif /* CONFIG_P2P */
2729*a1157835SDaniel Fojt 
2730*a1157835SDaniel Fojt 	if (bss) {
2731*a1157835SDaniel Fojt 		wpa_ie_len += wpas_supp_op_class_ie(wpa_s, ssid, bss->freq,
2732*a1157835SDaniel Fojt 						    wpa_ie + wpa_ie_len,
2733*a1157835SDaniel Fojt 						    max_wpa_ie_len -
2734*a1157835SDaniel Fojt 						    wpa_ie_len);
2735*a1157835SDaniel Fojt 	}
2736*a1157835SDaniel Fojt 
2737*a1157835SDaniel Fojt 	/*
2738*a1157835SDaniel Fojt 	 * Workaround: Add Extended Capabilities element only if the AP
2739*a1157835SDaniel Fojt 	 * included this element in Beacon/Probe Response frames. Some older
2740*a1157835SDaniel Fojt 	 * APs seem to have interoperability issues if this element is
2741*a1157835SDaniel Fojt 	 * included, so while the standard may require us to include the
2742*a1157835SDaniel Fojt 	 * element in all cases, it is justifiable to skip it to avoid
2743*a1157835SDaniel Fojt 	 * interoperability issues.
2744*a1157835SDaniel Fojt 	 */
2745*a1157835SDaniel Fojt 	if (ssid->p2p_group)
2746*a1157835SDaniel Fojt 		wpa_drv_get_ext_capa(wpa_s, WPA_IF_P2P_CLIENT);
2747*a1157835SDaniel Fojt 	else
2748*a1157835SDaniel Fojt 		wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
2749*a1157835SDaniel Fojt 
2750*a1157835SDaniel Fojt 	if (!bss || wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB)) {
2751*a1157835SDaniel Fojt 		u8 ext_capab[18];
2752*a1157835SDaniel Fojt 		int ext_capab_len;
2753*a1157835SDaniel Fojt 		ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab,
2754*a1157835SDaniel Fojt 						     sizeof(ext_capab));
2755*a1157835SDaniel Fojt 		if (ext_capab_len > 0 &&
2756*a1157835SDaniel Fojt 		    wpa_ie_len + ext_capab_len <= max_wpa_ie_len) {
2757*a1157835SDaniel Fojt 			u8 *pos = wpa_ie;
2758*a1157835SDaniel Fojt 			if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN)
2759*a1157835SDaniel Fojt 				pos += 2 + pos[1];
2760*a1157835SDaniel Fojt 			os_memmove(pos + ext_capab_len, pos,
2761*a1157835SDaniel Fojt 				   wpa_ie_len - (pos - wpa_ie));
2762*a1157835SDaniel Fojt 			wpa_ie_len += ext_capab_len;
2763*a1157835SDaniel Fojt 			os_memcpy(pos, ext_capab, ext_capab_len);
2764*a1157835SDaniel Fojt 		}
2765*a1157835SDaniel Fojt 	}
2766*a1157835SDaniel Fojt 
2767*a1157835SDaniel Fojt #ifdef CONFIG_HS20
2768*a1157835SDaniel Fojt 	if (is_hs20_network(wpa_s, ssid, bss)) {
2769*a1157835SDaniel Fojt 		struct wpabuf *hs20;
2770*a1157835SDaniel Fojt 
2771*a1157835SDaniel Fojt 		hs20 = wpabuf_alloc(20 + MAX_ROAMING_CONS_OI_LEN);
2772*a1157835SDaniel Fojt 		if (hs20) {
2773*a1157835SDaniel Fojt 			int pps_mo_id = hs20_get_pps_mo_id(wpa_s, ssid);
2774*a1157835SDaniel Fojt 			size_t len;
2775*a1157835SDaniel Fojt 
2776*a1157835SDaniel Fojt 			wpas_hs20_add_indication(hs20, pps_mo_id,
2777*a1157835SDaniel Fojt 						 get_hs20_version(bss));
2778*a1157835SDaniel Fojt 			wpas_hs20_add_roam_cons_sel(hs20, ssid);
2779*a1157835SDaniel Fojt 			len = max_wpa_ie_len - wpa_ie_len;
2780*a1157835SDaniel Fojt 			if (wpabuf_len(hs20) <= len) {
2781*a1157835SDaniel Fojt 				os_memcpy(wpa_ie + wpa_ie_len,
2782*a1157835SDaniel Fojt 					  wpabuf_head(hs20), wpabuf_len(hs20));
2783*a1157835SDaniel Fojt 				wpa_ie_len += wpabuf_len(hs20);
2784*a1157835SDaniel Fojt 			}
2785*a1157835SDaniel Fojt 			wpabuf_free(hs20);
2786*a1157835SDaniel Fojt 
2787*a1157835SDaniel Fojt 			hs20_configure_frame_filters(wpa_s);
2788*a1157835SDaniel Fojt 		}
2789*a1157835SDaniel Fojt 	}
2790*a1157835SDaniel Fojt #endif /* CONFIG_HS20 */
2791*a1157835SDaniel Fojt 
2792*a1157835SDaniel Fojt 	if (wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ]) {
2793*a1157835SDaniel Fojt 		struct wpabuf *buf = wpa_s->vendor_elem[VENDOR_ELEM_ASSOC_REQ];
2794*a1157835SDaniel Fojt 		size_t len;
2795*a1157835SDaniel Fojt 
2796*a1157835SDaniel Fojt 		len = max_wpa_ie_len - wpa_ie_len;
2797*a1157835SDaniel Fojt 		if (wpabuf_len(buf) <= len) {
2798*a1157835SDaniel Fojt 			os_memcpy(wpa_ie + wpa_ie_len,
2799*a1157835SDaniel Fojt 				  wpabuf_head(buf), wpabuf_len(buf));
2800*a1157835SDaniel Fojt 			wpa_ie_len += wpabuf_len(buf);
2801*a1157835SDaniel Fojt 		}
2802*a1157835SDaniel Fojt 	}
2803*a1157835SDaniel Fojt 
2804*a1157835SDaniel Fojt #ifdef CONFIG_FST
2805*a1157835SDaniel Fojt 	if (wpa_s->fst_ies) {
2806*a1157835SDaniel Fojt 		int fst_ies_len = wpabuf_len(wpa_s->fst_ies);
2807*a1157835SDaniel Fojt 
2808*a1157835SDaniel Fojt 		if (wpa_ie_len + fst_ies_len <= max_wpa_ie_len) {
2809*a1157835SDaniel Fojt 			os_memcpy(wpa_ie + wpa_ie_len,
2810*a1157835SDaniel Fojt 				  wpabuf_head(wpa_s->fst_ies), fst_ies_len);
2811*a1157835SDaniel Fojt 			wpa_ie_len += fst_ies_len;
2812*a1157835SDaniel Fojt 		}
2813*a1157835SDaniel Fojt 	}
2814*a1157835SDaniel Fojt #endif /* CONFIG_FST */
2815*a1157835SDaniel Fojt 
2816*a1157835SDaniel Fojt #ifdef CONFIG_MBO
2817*a1157835SDaniel Fojt 	mbo_ie = bss ? wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE) : NULL;
2818*a1157835SDaniel Fojt 	if (mbo_ie) {
2819*a1157835SDaniel Fojt 		int len;
2820*a1157835SDaniel Fojt 
2821*a1157835SDaniel Fojt 		len = wpas_mbo_ie(wpa_s, wpa_ie + wpa_ie_len,
2822*a1157835SDaniel Fojt 				  max_wpa_ie_len - wpa_ie_len,
2823*a1157835SDaniel Fojt 				  !!mbo_attr_from_mbo_ie(mbo_ie,
2824*a1157835SDaniel Fojt 							 OCE_ATTR_ID_CAPA_IND));
2825*a1157835SDaniel Fojt 		if (len >= 0)
2826*a1157835SDaniel Fojt 			wpa_ie_len += len;
2827*a1157835SDaniel Fojt 	}
2828*a1157835SDaniel Fojt #endif /* CONFIG_MBO */
2829*a1157835SDaniel Fojt 
2830*a1157835SDaniel Fojt #ifdef CONFIG_FILS
2831*a1157835SDaniel Fojt 	if (algs == WPA_AUTH_ALG_FILS) {
2832*a1157835SDaniel Fojt 		size_t len;
2833*a1157835SDaniel Fojt 
2834*a1157835SDaniel Fojt 		len = wpas_add_fils_hlp_req(wpa_s, wpa_ie + wpa_ie_len,
2835*a1157835SDaniel Fojt 					    max_wpa_ie_len - wpa_ie_len);
2836*a1157835SDaniel Fojt 		wpa_ie_len += len;
2837*a1157835SDaniel Fojt 	}
2838*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
2839*a1157835SDaniel Fojt 
2840*a1157835SDaniel Fojt #ifdef CONFIG_OWE
2841*a1157835SDaniel Fojt #ifdef CONFIG_TESTING_OPTIONS
2842*a1157835SDaniel Fojt 	if (get_ie_ext(wpa_ie, wpa_ie_len, WLAN_EID_EXT_OWE_DH_PARAM)) {
2843*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO, "TESTING: Override OWE DH element");
2844*a1157835SDaniel Fojt 	} else
2845*a1157835SDaniel Fojt #endif /* CONFIG_TESTING_OPTIONS */
2846*a1157835SDaniel Fojt 	if (algs == WPA_AUTH_ALG_OPEN &&
2847*a1157835SDaniel Fojt 	    ssid->key_mgmt == WPA_KEY_MGMT_OWE) {
2848*a1157835SDaniel Fojt 		struct wpabuf *owe_ie;
2849*a1157835SDaniel Fojt 		u16 group;
2850*a1157835SDaniel Fojt 
2851*a1157835SDaniel Fojt 		if (ssid->owe_group) {
2852*a1157835SDaniel Fojt 			group = ssid->owe_group;
2853*a1157835SDaniel Fojt 		} else if (wpa_s->assoc_status_code ==
2854*a1157835SDaniel Fojt 			   WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) {
2855*a1157835SDaniel Fojt 			if (wpa_s->last_owe_group == 19)
2856*a1157835SDaniel Fojt 				group = 20;
2857*a1157835SDaniel Fojt 			else if (wpa_s->last_owe_group == 20)
2858*a1157835SDaniel Fojt 				group = 21;
2859*a1157835SDaniel Fojt 			else
2860*a1157835SDaniel Fojt 				group = OWE_DH_GROUP;
2861*a1157835SDaniel Fojt 		} else {
2862*a1157835SDaniel Fojt 			group = OWE_DH_GROUP;
2863*a1157835SDaniel Fojt 		}
2864*a1157835SDaniel Fojt 
2865*a1157835SDaniel Fojt 		wpa_s->last_owe_group = group;
2866*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "OWE: Try to use group %u", group);
2867*a1157835SDaniel Fojt 		owe_ie = owe_build_assoc_req(wpa_s->wpa, group);
2868*a1157835SDaniel Fojt 		if (owe_ie &&
2869*a1157835SDaniel Fojt 		    wpabuf_len(owe_ie) <= max_wpa_ie_len - wpa_ie_len) {
2870*a1157835SDaniel Fojt 			os_memcpy(wpa_ie + wpa_ie_len,
2871*a1157835SDaniel Fojt 				  wpabuf_head(owe_ie), wpabuf_len(owe_ie));
2872*a1157835SDaniel Fojt 			wpa_ie_len += wpabuf_len(owe_ie);
2873*a1157835SDaniel Fojt 		}
2874*a1157835SDaniel Fojt 		wpabuf_free(owe_ie);
2875*a1157835SDaniel Fojt 	}
2876*a1157835SDaniel Fojt #endif /* CONFIG_OWE */
2877*a1157835SDaniel Fojt 
2878*a1157835SDaniel Fojt #ifdef CONFIG_DPP2
2879*a1157835SDaniel Fojt 	if (wpa_sm_get_key_mgmt(wpa_s->wpa) == WPA_KEY_MGMT_DPP &&
2880*a1157835SDaniel Fojt 	    ssid->dpp_netaccesskey) {
2881*a1157835SDaniel Fojt 		dpp_pfs_free(wpa_s->dpp_pfs);
2882*a1157835SDaniel Fojt 		wpa_s->dpp_pfs = dpp_pfs_init(ssid->dpp_netaccesskey,
2883*a1157835SDaniel Fojt 					      ssid->dpp_netaccesskey_len);
2884*a1157835SDaniel Fojt 		if (!wpa_s->dpp_pfs) {
2885*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG, "DPP: Could not initialize PFS");
2886*a1157835SDaniel Fojt 			/* Try to continue without PFS */
2887*a1157835SDaniel Fojt 			goto pfs_fail;
2888*a1157835SDaniel Fojt 		}
2889*a1157835SDaniel Fojt 		if (wpabuf_len(wpa_s->dpp_pfs->ie) <=
2890*a1157835SDaniel Fojt 		    max_wpa_ie_len - wpa_ie_len) {
2891*a1157835SDaniel Fojt 			os_memcpy(wpa_ie + wpa_ie_len,
2892*a1157835SDaniel Fojt 				  wpabuf_head(wpa_s->dpp_pfs->ie),
2893*a1157835SDaniel Fojt 				  wpabuf_len(wpa_s->dpp_pfs->ie));
2894*a1157835SDaniel Fojt 			wpa_ie_len += wpabuf_len(wpa_s->dpp_pfs->ie);
2895*a1157835SDaniel Fojt 		}
2896*a1157835SDaniel Fojt 	}
2897*a1157835SDaniel Fojt pfs_fail:
2898*a1157835SDaniel Fojt #endif /* CONFIG_DPP2 */
2899*a1157835SDaniel Fojt 
2900*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211R
2901*a1157835SDaniel Fojt 	/*
2902*a1157835SDaniel Fojt 	 * Add MDIE under these conditions: the network profile allows FT,
2903*a1157835SDaniel Fojt 	 * the AP supports FT, and the mobility domain ID matches.
2904*a1157835SDaniel Fojt 	 */
2905*a1157835SDaniel Fojt 	if (bss && wpa_key_mgmt_ft(wpa_sm_get_key_mgmt(wpa_s->wpa))) {
2906*a1157835SDaniel Fojt 		const u8 *mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
2907*a1157835SDaniel Fojt 
2908*a1157835SDaniel Fojt 		if (mdie && mdie[1] >= MOBILITY_DOMAIN_ID_LEN) {
2909*a1157835SDaniel Fojt 			size_t len = 0;
2910*a1157835SDaniel Fojt 			const u8 *md = mdie + 2;
2911*a1157835SDaniel Fojt 			const u8 *wpa_md = wpa_sm_get_ft_md(wpa_s->wpa);
2912*a1157835SDaniel Fojt 
2913*a1157835SDaniel Fojt 			if (os_memcmp(md, wpa_md,
2914*a1157835SDaniel Fojt 				      MOBILITY_DOMAIN_ID_LEN) == 0) {
2915*a1157835SDaniel Fojt 				/* Add mobility domain IE */
2916*a1157835SDaniel Fojt 				len = wpa_ft_add_mdie(
2917*a1157835SDaniel Fojt 					wpa_s->wpa, wpa_ie + wpa_ie_len,
2918*a1157835SDaniel Fojt 					max_wpa_ie_len - wpa_ie_len, mdie);
2919*a1157835SDaniel Fojt 				wpa_ie_len += len;
2920*a1157835SDaniel Fojt 			}
2921*a1157835SDaniel Fojt #ifdef CONFIG_SME
2922*a1157835SDaniel Fojt 			if (len > 0 && wpa_s->sme.ft_used &&
2923*a1157835SDaniel Fojt 			    wpa_sm_has_ptk(wpa_s->wpa)) {
2924*a1157835SDaniel Fojt 				wpa_dbg(wpa_s, MSG_DEBUG,
2925*a1157835SDaniel Fojt 					"SME: Trying to use FT over-the-air");
2926*a1157835SDaniel Fojt 				algs |= WPA_AUTH_ALG_FT;
2927*a1157835SDaniel Fojt 			}
2928*a1157835SDaniel Fojt #endif /* CONFIG_SME */
2929*a1157835SDaniel Fojt 		}
2930*a1157835SDaniel Fojt 	}
2931*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211R */
2932*a1157835SDaniel Fojt 
2933*a1157835SDaniel Fojt 	if (ssid->multi_ap_backhaul_sta) {
2934*a1157835SDaniel Fojt 		size_t multi_ap_ie_len;
2935*a1157835SDaniel Fojt 
2936*a1157835SDaniel Fojt 		multi_ap_ie_len = add_multi_ap_ie(wpa_ie + wpa_ie_len,
2937*a1157835SDaniel Fojt 						  max_wpa_ie_len - wpa_ie_len,
2938*a1157835SDaniel Fojt 						  MULTI_AP_BACKHAUL_STA);
2939*a1157835SDaniel Fojt 		if (multi_ap_ie_len == 0) {
2940*a1157835SDaniel Fojt 			wpa_printf(MSG_ERROR,
2941*a1157835SDaniel Fojt 				   "Multi-AP: Failed to build Multi-AP IE");
2942*a1157835SDaniel Fojt 			os_free(wpa_ie);
2943*a1157835SDaniel Fojt 			return NULL;
2944*a1157835SDaniel Fojt 		}
2945*a1157835SDaniel Fojt 		wpa_ie_len += multi_ap_ie_len;
2946*a1157835SDaniel Fojt 	}
2947*a1157835SDaniel Fojt 
2948*a1157835SDaniel Fojt 	params->wpa_ie = wpa_ie;
2949*a1157835SDaniel Fojt 	params->wpa_ie_len = wpa_ie_len;
2950*a1157835SDaniel Fojt 	params->auth_alg = algs;
2951*a1157835SDaniel Fojt 	if (mask)
2952*a1157835SDaniel Fojt 		*mask |= WPA_DRV_UPDATE_ASSOC_IES | WPA_DRV_UPDATE_AUTH_TYPE;
2953*a1157835SDaniel Fojt 
2954*a1157835SDaniel Fojt 	return wpa_ie;
2955*a1157835SDaniel Fojt }
2956*a1157835SDaniel Fojt 
2957*a1157835SDaniel Fojt 
2958*a1157835SDaniel Fojt #if defined(CONFIG_FILS) && defined(IEEE8021X_EAPOL)
wpas_update_fils_connect_params(struct wpa_supplicant * wpa_s)2959*a1157835SDaniel Fojt static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s)
2960*a1157835SDaniel Fojt {
2961*a1157835SDaniel Fojt 	struct wpa_driver_associate_params params;
2962*a1157835SDaniel Fojt 	enum wpa_drv_update_connect_params_mask mask = 0;
2963*a1157835SDaniel Fojt 	u8 *wpa_ie;
2964*a1157835SDaniel Fojt 
2965*a1157835SDaniel Fojt 	if (wpa_s->auth_alg != WPA_AUTH_ALG_OPEN)
2966*a1157835SDaniel Fojt 		return; /* nothing to do */
2967*a1157835SDaniel Fojt 
2968*a1157835SDaniel Fojt 	os_memset(&params, 0, sizeof(params));
2969*a1157835SDaniel Fojt 	wpa_ie = wpas_populate_assoc_ies(wpa_s, wpa_s->current_bss,
2970*a1157835SDaniel Fojt 					 wpa_s->current_ssid, &params, &mask);
2971*a1157835SDaniel Fojt 	if (!wpa_ie)
2972*a1157835SDaniel Fojt 		return;
2973*a1157835SDaniel Fojt 
2974*a1157835SDaniel Fojt 	if (params.auth_alg != WPA_AUTH_ALG_FILS) {
2975*a1157835SDaniel Fojt 		os_free(wpa_ie);
2976*a1157835SDaniel Fojt 		return;
2977*a1157835SDaniel Fojt 	}
2978*a1157835SDaniel Fojt 
2979*a1157835SDaniel Fojt 	wpa_s->auth_alg = params.auth_alg;
2980*a1157835SDaniel Fojt 	wpa_drv_update_connect_params(wpa_s, &params, mask);
2981*a1157835SDaniel Fojt 	os_free(wpa_ie);
2982*a1157835SDaniel Fojt }
2983*a1157835SDaniel Fojt #endif /* CONFIG_FILS && IEEE8021X_EAPOL */
2984*a1157835SDaniel Fojt 
2985*a1157835SDaniel Fojt 
2986*a1157835SDaniel Fojt #ifdef CONFIG_MBO
wpas_update_mbo_connect_params(struct wpa_supplicant * wpa_s)2987*a1157835SDaniel Fojt void wpas_update_mbo_connect_params(struct wpa_supplicant *wpa_s)
2988*a1157835SDaniel Fojt {
2989*a1157835SDaniel Fojt 	struct wpa_driver_associate_params params;
2990*a1157835SDaniel Fojt 	u8 *wpa_ie;
2991*a1157835SDaniel Fojt 
2992*a1157835SDaniel Fojt 	/*
2993*a1157835SDaniel Fojt 	 * Update MBO connect params only in case of change of MBO attributes
2994*a1157835SDaniel Fojt 	 * when connected, if the AP support MBO.
2995*a1157835SDaniel Fojt 	 */
2996*a1157835SDaniel Fojt 
2997*a1157835SDaniel Fojt 	if (wpa_s->wpa_state != WPA_COMPLETED || !wpa_s->current_ssid ||
2998*a1157835SDaniel Fojt 	    !wpa_s->current_bss ||
2999*a1157835SDaniel Fojt 	    !wpa_bss_get_vendor_ie(wpa_s->current_bss, MBO_IE_VENDOR_TYPE))
3000*a1157835SDaniel Fojt 		return;
3001*a1157835SDaniel Fojt 
3002*a1157835SDaniel Fojt 	os_memset(&params, 0, sizeof(params));
3003*a1157835SDaniel Fojt 	wpa_ie = wpas_populate_assoc_ies(wpa_s, wpa_s->current_bss,
3004*a1157835SDaniel Fojt 					 wpa_s->current_ssid, &params, NULL);
3005*a1157835SDaniel Fojt 	if (!wpa_ie)
3006*a1157835SDaniel Fojt 		return;
3007*a1157835SDaniel Fojt 
3008*a1157835SDaniel Fojt 	wpa_drv_update_connect_params(wpa_s, &params, WPA_DRV_UPDATE_ASSOC_IES);
3009*a1157835SDaniel Fojt 	os_free(wpa_ie);
3010*a1157835SDaniel Fojt }
3011*a1157835SDaniel Fojt #endif /* CONFIG_MBO */
3012*a1157835SDaniel Fojt 
3013*a1157835SDaniel Fojt 
wpas_start_assoc_cb(struct wpa_radio_work * work,int deinit)30143ff40c12SJohn Marino static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
30153ff40c12SJohn Marino {
30163ff40c12SJohn Marino 	struct wpa_connect_work *cwork = work->ctx;
30173ff40c12SJohn Marino 	struct wpa_bss *bss = cwork->bss;
30183ff40c12SJohn Marino 	struct wpa_ssid *ssid = cwork->ssid;
30193ff40c12SJohn Marino 	struct wpa_supplicant *wpa_s = work->wpa_s;
3020*a1157835SDaniel Fojt 	u8 *wpa_ie;
30213ff40c12SJohn Marino 	int use_crypt, ret, i, bssid_changed;
3022*a1157835SDaniel Fojt 	unsigned int cipher_pairwise, cipher_group, cipher_group_mgmt;
30236d49e1aeSJan Lentfer 	struct wpa_driver_associate_params params;
30246d49e1aeSJan Lentfer 	int wep_keys_set = 0;
30256d49e1aeSJan Lentfer 	int assoc_failed = 0;
30263ff40c12SJohn Marino 	struct wpa_ssid *old_ssid;
3027*a1157835SDaniel Fojt 	u8 prev_bssid[ETH_ALEN];
30283ff40c12SJohn Marino #ifdef CONFIG_HT_OVERRIDES
30293ff40c12SJohn Marino 	struct ieee80211_ht_capabilities htcaps;
30303ff40c12SJohn Marino 	struct ieee80211_ht_capabilities htcaps_mask;
30313ff40c12SJohn Marino #endif /* CONFIG_HT_OVERRIDES */
3032*a1157835SDaniel Fojt #ifdef CONFIG_VHT_OVERRIDES
3033*a1157835SDaniel Fojt        struct ieee80211_vht_capabilities vhtcaps;
3034*a1157835SDaniel Fojt        struct ieee80211_vht_capabilities vhtcaps_mask;
3035*a1157835SDaniel Fojt #endif /* CONFIG_VHT_OVERRIDES */
30366d49e1aeSJan Lentfer 
30373ff40c12SJohn Marino 	if (deinit) {
3038*a1157835SDaniel Fojt 		if (work->started) {
3039*a1157835SDaniel Fojt 			wpa_s->connect_work = NULL;
3040*a1157835SDaniel Fojt 
3041*a1157835SDaniel Fojt 			/* cancel possible auth. timeout */
3042*a1157835SDaniel Fojt 			eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s,
3043*a1157835SDaniel Fojt 					     NULL);
3044*a1157835SDaniel Fojt 		}
30453ff40c12SJohn Marino 		wpas_connect_work_free(cwork);
30463ff40c12SJohn Marino 		return;
30473ff40c12SJohn Marino 	}
30483ff40c12SJohn Marino 
30493ff40c12SJohn Marino 	wpa_s->connect_work = work;
30503ff40c12SJohn Marino 
3051*a1157835SDaniel Fojt 	if (cwork->bss_removed || !wpas_valid_bss_ssid(wpa_s, bss, ssid) ||
3052*a1157835SDaniel Fojt 	    wpas_network_disabled(wpa_s, ssid)) {
30533ff40c12SJohn Marino 		wpa_dbg(wpa_s, MSG_DEBUG, "BSS/SSID entry for association not valid anymore - drop connection attempt");
30543ff40c12SJohn Marino 		wpas_connect_work_done(wpa_s);
30553ff40c12SJohn Marino 		return;
30563ff40c12SJohn Marino 	}
30573ff40c12SJohn Marino 
3058*a1157835SDaniel Fojt 	os_memcpy(prev_bssid, wpa_s->bssid, ETH_ALEN);
30593ff40c12SJohn Marino 	os_memset(&params, 0, sizeof(params));
30606d49e1aeSJan Lentfer 	wpa_s->reassociate = 0;
30613ff40c12SJohn Marino 	wpa_s->eap_expected_failure = 0;
3062*a1157835SDaniel Fojt 	if (bss &&
3063*a1157835SDaniel Fojt 	    (!wpas_driver_bss_selection(wpa_s) || wpas_wps_searching(wpa_s))) {
30646d49e1aeSJan Lentfer #ifdef CONFIG_IEEE80211R
30653ff40c12SJohn Marino 		const u8 *ie, *md = NULL;
30666d49e1aeSJan Lentfer #endif /* CONFIG_IEEE80211R */
30676d49e1aeSJan Lentfer 		wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR
30686d49e1aeSJan Lentfer 			" (SSID='%s' freq=%d MHz)", MAC2STR(bss->bssid),
30693ff40c12SJohn Marino 			wpa_ssid_txt(bss->ssid, bss->ssid_len), bss->freq);
30703ff40c12SJohn Marino 		bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
30716d49e1aeSJan Lentfer 		os_memset(wpa_s->bssid, 0, ETH_ALEN);
30726d49e1aeSJan Lentfer 		os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
30733ff40c12SJohn Marino 		if (bssid_changed)
30743ff40c12SJohn Marino 			wpas_notify_bssid_changed(wpa_s);
30756d49e1aeSJan Lentfer #ifdef CONFIG_IEEE80211R
30763ff40c12SJohn Marino 		ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
30776d49e1aeSJan Lentfer 		if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN)
30786d49e1aeSJan Lentfer 			md = ie + 2;
30793ff40c12SJohn Marino 		wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0);
30806d49e1aeSJan Lentfer 		if (md) {
30816d49e1aeSJan Lentfer 			/* Prepare for the next transition */
30823ff40c12SJohn Marino 			wpa_ft_prepare_auth_request(wpa_s->wpa, ie);
30836d49e1aeSJan Lentfer 		}
30846d49e1aeSJan Lentfer #endif /* CONFIG_IEEE80211R */
30856d49e1aeSJan Lentfer #ifdef CONFIG_WPS
30866d49e1aeSJan Lentfer 	} else if ((ssid->ssid == NULL || ssid->ssid_len == 0) &&
30876d49e1aeSJan Lentfer 		   wpa_s->conf->ap_scan == 2 &&
30886d49e1aeSJan Lentfer 		   (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
30896d49e1aeSJan Lentfer 		/* Use ap_scan==1 style network selection to find the network
30906d49e1aeSJan Lentfer 		 */
3091*a1157835SDaniel Fojt 		wpas_connect_work_done(wpa_s);
30923ff40c12SJohn Marino 		wpa_s->scan_req = MANUAL_SCAN_REQ;
30936d49e1aeSJan Lentfer 		wpa_s->reassociate = 1;
30946d49e1aeSJan Lentfer 		wpa_supplicant_req_scan(wpa_s, 0, 0);
30956d49e1aeSJan Lentfer 		return;
30966d49e1aeSJan Lentfer #endif /* CONFIG_WPS */
30976d49e1aeSJan Lentfer 	} else {
30986d49e1aeSJan Lentfer 		wpa_msg(wpa_s, MSG_INFO, "Trying to associate with SSID '%s'",
30996d49e1aeSJan Lentfer 			wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
3100*a1157835SDaniel Fojt 		if (bss)
3101*a1157835SDaniel Fojt 			os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
3102*a1157835SDaniel Fojt 		else
31036d49e1aeSJan Lentfer 			os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
31046d49e1aeSJan Lentfer 	}
3105*a1157835SDaniel Fojt 	if (!wpa_s->pno)
31063ff40c12SJohn Marino 		wpa_supplicant_cancel_sched_scan(wpa_s);
3107*a1157835SDaniel Fojt 
31086d49e1aeSJan Lentfer 	wpa_supplicant_cancel_scan(wpa_s);
31096d49e1aeSJan Lentfer 
31106d49e1aeSJan Lentfer 	/* Starting new association, so clear the possibly used WPA IE from the
31116d49e1aeSJan Lentfer 	 * previous association. */
31126d49e1aeSJan Lentfer 	wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
31136d49e1aeSJan Lentfer 
3114*a1157835SDaniel Fojt 	wpa_ie = wpas_populate_assoc_ies(wpa_s, bss, ssid, &params, NULL);
3115*a1157835SDaniel Fojt 	if (!wpa_ie) {
3116*a1157835SDaniel Fojt 		wpas_connect_work_done(wpa_s);
31176d49e1aeSJan Lentfer 		return;
31186d49e1aeSJan Lentfer 	}
31196d49e1aeSJan Lentfer 
31206d49e1aeSJan Lentfer 	wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
31216d49e1aeSJan Lentfer 	use_crypt = 1;
31223ff40c12SJohn Marino 	cipher_pairwise = wpa_s->pairwise_cipher;
31233ff40c12SJohn Marino 	cipher_group = wpa_s->group_cipher;
3124*a1157835SDaniel Fojt 	cipher_group_mgmt = wpa_s->mgmt_group_cipher;
31256d49e1aeSJan Lentfer 	if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
31266d49e1aeSJan Lentfer 	    wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
31276d49e1aeSJan Lentfer 		if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE)
31286d49e1aeSJan Lentfer 			use_crypt = 0;
31296d49e1aeSJan Lentfer 		if (wpa_set_wep_keys(wpa_s, ssid)) {
31306d49e1aeSJan Lentfer 			use_crypt = 1;
31316d49e1aeSJan Lentfer 			wep_keys_set = 1;
31326d49e1aeSJan Lentfer 		}
31336d49e1aeSJan Lentfer 	}
31346d49e1aeSJan Lentfer 	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS)
31356d49e1aeSJan Lentfer 		use_crypt = 0;
31366d49e1aeSJan Lentfer 
31376d49e1aeSJan Lentfer #ifdef IEEE8021X_EAPOL
31386d49e1aeSJan Lentfer 	if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
31396d49e1aeSJan Lentfer 		if ((ssid->eapol_flags &
31406d49e1aeSJan Lentfer 		     (EAPOL_FLAG_REQUIRE_KEY_UNICAST |
31416d49e1aeSJan Lentfer 		      EAPOL_FLAG_REQUIRE_KEY_BROADCAST)) == 0 &&
31426d49e1aeSJan Lentfer 		    !wep_keys_set) {
31436d49e1aeSJan Lentfer 			use_crypt = 0;
31446d49e1aeSJan Lentfer 		} else {
31456d49e1aeSJan Lentfer 			/* Assume that dynamic WEP-104 keys will be used and
31466d49e1aeSJan Lentfer 			 * set cipher suites in order for drivers to expect
31476d49e1aeSJan Lentfer 			 * encryption. */
31483ff40c12SJohn Marino 			cipher_pairwise = cipher_group = WPA_CIPHER_WEP104;
31496d49e1aeSJan Lentfer 		}
31506d49e1aeSJan Lentfer 	}
31516d49e1aeSJan Lentfer #endif /* IEEE8021X_EAPOL */
31526d49e1aeSJan Lentfer 
31536d49e1aeSJan Lentfer 	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
31546d49e1aeSJan Lentfer 		/* Set the key before (and later after) association */
31556d49e1aeSJan Lentfer 		wpa_supplicant_set_wpa_none_key(wpa_s, ssid);
31566d49e1aeSJan Lentfer 	}
31576d49e1aeSJan Lentfer 
31586d49e1aeSJan Lentfer 	wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
31596d49e1aeSJan Lentfer 	if (bss) {
31603ff40c12SJohn Marino 		params.ssid = bss->ssid;
31613ff40c12SJohn Marino 		params.ssid_len = bss->ssid_len;
3162*a1157835SDaniel Fojt 		if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set ||
3163*a1157835SDaniel Fojt 		    wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
31643ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "Limit connection to BSSID "
31653ff40c12SJohn Marino 				   MACSTR " freq=%u MHz based on scan results "
3166*a1157835SDaniel Fojt 				   "(bssid_set=%d wps=%d)",
31673ff40c12SJohn Marino 				   MAC2STR(bss->bssid), bss->freq,
3168*a1157835SDaniel Fojt 				   ssid->bssid_set,
3169*a1157835SDaniel Fojt 				   wpa_s->key_mgmt == WPA_KEY_MGMT_WPS);
31706d49e1aeSJan Lentfer 			params.bssid = bss->bssid;
3171*a1157835SDaniel Fojt 			params.freq.freq = bss->freq;
31723ff40c12SJohn Marino 		}
3173*a1157835SDaniel Fojt 		params.bssid_hint = bss->bssid;
3174*a1157835SDaniel Fojt 		params.freq_hint = bss->freq;
3175*a1157835SDaniel Fojt 		params.pbss = bss_is_pbss(bss);
31766d49e1aeSJan Lentfer 	} else {
3177*a1157835SDaniel Fojt 		if (ssid->bssid_hint_set)
3178*a1157835SDaniel Fojt 			params.bssid_hint = ssid->bssid_hint;
3179*a1157835SDaniel Fojt 
31806d49e1aeSJan Lentfer 		params.ssid = ssid->ssid;
31816d49e1aeSJan Lentfer 		params.ssid_len = ssid->ssid_len;
3182*a1157835SDaniel Fojt 		params.pbss = (ssid->pbss != 2) ? ssid->pbss : 0;
31836d49e1aeSJan Lentfer 	}
31843ff40c12SJohn Marino 
31853ff40c12SJohn Marino 	if (ssid->mode == WPAS_MODE_IBSS && ssid->bssid_set &&
31863ff40c12SJohn Marino 	    wpa_s->conf->ap_scan == 2) {
31873ff40c12SJohn Marino 		params.bssid = ssid->bssid;
31883ff40c12SJohn Marino 		params.fixed_bssid = 1;
31893ff40c12SJohn Marino 	}
31903ff40c12SJohn Marino 
3191*a1157835SDaniel Fojt 	/* Initial frequency for IBSS/mesh */
3192*a1157835SDaniel Fojt 	if ((ssid->mode == WPAS_MODE_IBSS || ssid->mode == WPAS_MODE_MESH) &&
3193*a1157835SDaniel Fojt 	    ssid->frequency > 0 && params.freq.freq == 0)
3194*a1157835SDaniel Fojt 		ibss_mesh_setup_freq(wpa_s, ssid, &params.freq);
3195*a1157835SDaniel Fojt 
3196*a1157835SDaniel Fojt 	if (ssid->mode == WPAS_MODE_IBSS) {
3197*a1157835SDaniel Fojt 		params.fixed_freq = ssid->fixed_freq;
3198*a1157835SDaniel Fojt 		if (ssid->beacon_int)
3199*a1157835SDaniel Fojt 			params.beacon_int = ssid->beacon_int;
3200*a1157835SDaniel Fojt 		else
3201*a1157835SDaniel Fojt 			params.beacon_int = wpa_s->conf->beacon_int;
3202*a1157835SDaniel Fojt 	}
3203*a1157835SDaniel Fojt 
32046d49e1aeSJan Lentfer 	params.pairwise_suite = cipher_pairwise;
32056d49e1aeSJan Lentfer 	params.group_suite = cipher_group;
3206*a1157835SDaniel Fojt 	params.mgmt_group_suite = cipher_group_mgmt;
32073ff40c12SJohn Marino 	params.key_mgmt_suite = wpa_s->key_mgmt;
32083ff40c12SJohn Marino 	params.wpa_proto = wpa_s->wpa_proto;
3209*a1157835SDaniel Fojt 	wpa_s->auth_alg = params.auth_alg;
32106d49e1aeSJan Lentfer 	params.mode = ssid->mode;
32113ff40c12SJohn Marino 	params.bg_scan_period = ssid->bg_scan_period;
32126d49e1aeSJan Lentfer 	for (i = 0; i < NUM_WEP_KEYS; i++) {
32136d49e1aeSJan Lentfer 		if (ssid->wep_key_len[i])
32146d49e1aeSJan Lentfer 			params.wep_key[i] = ssid->wep_key[i];
32156d49e1aeSJan Lentfer 		params.wep_key_len[i] = ssid->wep_key_len[i];
32166d49e1aeSJan Lentfer 	}
32176d49e1aeSJan Lentfer 	params.wep_tx_keyidx = ssid->wep_tx_keyidx;
32186d49e1aeSJan Lentfer 
3219*a1157835SDaniel Fojt 	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) &&
32203ff40c12SJohn Marino 	    (params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
32213ff40c12SJohn Marino 	     params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) {
32226d49e1aeSJan Lentfer 		params.passphrase = ssid->passphrase;
32236d49e1aeSJan Lentfer 		if (ssid->psk_set)
32246d49e1aeSJan Lentfer 			params.psk = ssid->psk;
32256d49e1aeSJan Lentfer 	}
32266d49e1aeSJan Lentfer 
3227*a1157835SDaniel Fojt 	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X) &&
3228*a1157835SDaniel Fojt 	    (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
3229*a1157835SDaniel Fojt 	     params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
3230*a1157835SDaniel Fojt 	     params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
3231*a1157835SDaniel Fojt 	     params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192))
3232*a1157835SDaniel Fojt 		params.req_handshake_offload = 1;
3233*a1157835SDaniel Fojt 
3234*a1157835SDaniel Fojt 	if (wpa_s->conf->key_mgmt_offload) {
3235*a1157835SDaniel Fojt 		if (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
3236*a1157835SDaniel Fojt 		    params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
3237*a1157835SDaniel Fojt 		    params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
3238*a1157835SDaniel Fojt 		    params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
3239*a1157835SDaniel Fojt 			params.req_key_mgmt_offload =
3240*a1157835SDaniel Fojt 				ssid->proactive_key_caching < 0 ?
3241*a1157835SDaniel Fojt 				wpa_s->conf->okc : ssid->proactive_key_caching;
3242*a1157835SDaniel Fojt 		else
3243*a1157835SDaniel Fojt 			params.req_key_mgmt_offload = 1;
3244*a1157835SDaniel Fojt 
3245*a1157835SDaniel Fojt 		if ((params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
3246*a1157835SDaniel Fojt 		     params.key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
3247*a1157835SDaniel Fojt 		     params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK) &&
3248*a1157835SDaniel Fojt 		    ssid->psk_set)
3249*a1157835SDaniel Fojt 			params.psk = ssid->psk;
3250*a1157835SDaniel Fojt 	}
3251*a1157835SDaniel Fojt 
32523ff40c12SJohn Marino 	params.drop_unencrypted = use_crypt;
32533ff40c12SJohn Marino 
32546d49e1aeSJan Lentfer #ifdef CONFIG_IEEE80211W
3255*a1157835SDaniel Fojt 	params.mgmt_frame_protection = wpas_get_ssid_pmf(wpa_s, ssid);
32563ff40c12SJohn Marino 	if (params.mgmt_frame_protection != NO_MGMT_FRAME_PROTECTION && bss) {
32573ff40c12SJohn Marino 		const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
32586d49e1aeSJan Lentfer 		struct wpa_ie_data ie;
32596d49e1aeSJan Lentfer 		if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie) == 0 &&
32606d49e1aeSJan Lentfer 		    ie.capabilities &
32616d49e1aeSJan Lentfer 		    (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) {
32623ff40c12SJohn Marino 			wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected AP supports "
32633ff40c12SJohn Marino 				"MFP: require MFP");
32646d49e1aeSJan Lentfer 			params.mgmt_frame_protection =
32656d49e1aeSJan Lentfer 				MGMT_FRAME_PROTECTION_REQUIRED;
3266*a1157835SDaniel Fojt #ifdef CONFIG_OWE
3267*a1157835SDaniel Fojt 		} else if (!rsn && (ssid->key_mgmt & WPA_KEY_MGMT_OWE) &&
3268*a1157835SDaniel Fojt 			   !ssid->owe_only) {
3269*a1157835SDaniel Fojt 			params.mgmt_frame_protection = NO_MGMT_FRAME_PROTECTION;
3270*a1157835SDaniel Fojt #endif /* CONFIG_OWE */
32716d49e1aeSJan Lentfer 		}
32726d49e1aeSJan Lentfer 	}
32736d49e1aeSJan Lentfer #endif /* CONFIG_IEEE80211W */
32746d49e1aeSJan Lentfer 
32753ff40c12SJohn Marino 	params.p2p = ssid->p2p_group;
32763ff40c12SJohn Marino 
3277*a1157835SDaniel Fojt 	if (wpa_s->p2pdev->set_sta_uapsd)
3278*a1157835SDaniel Fojt 		params.uapsd = wpa_s->p2pdev->sta_uapsd;
32796d49e1aeSJan Lentfer 	else
32803ff40c12SJohn Marino 		params.uapsd = -1;
32813ff40c12SJohn Marino 
32823ff40c12SJohn Marino #ifdef CONFIG_HT_OVERRIDES
32833ff40c12SJohn Marino 	os_memset(&htcaps, 0, sizeof(htcaps));
32843ff40c12SJohn Marino 	os_memset(&htcaps_mask, 0, sizeof(htcaps_mask));
32853ff40c12SJohn Marino 	params.htcaps = (u8 *) &htcaps;
32863ff40c12SJohn Marino 	params.htcaps_mask = (u8 *) &htcaps_mask;
32873ff40c12SJohn Marino 	wpa_supplicant_apply_ht_overrides(wpa_s, ssid, &params);
32883ff40c12SJohn Marino #endif /* CONFIG_HT_OVERRIDES */
3289*a1157835SDaniel Fojt #ifdef CONFIG_VHT_OVERRIDES
3290*a1157835SDaniel Fojt 	os_memset(&vhtcaps, 0, sizeof(vhtcaps));
3291*a1157835SDaniel Fojt 	os_memset(&vhtcaps_mask, 0, sizeof(vhtcaps_mask));
3292*a1157835SDaniel Fojt 	params.vhtcaps = &vhtcaps;
3293*a1157835SDaniel Fojt 	params.vhtcaps_mask = &vhtcaps_mask;
3294*a1157835SDaniel Fojt 	wpa_supplicant_apply_vht_overrides(wpa_s, ssid, &params);
3295*a1157835SDaniel Fojt #endif /* CONFIG_VHT_OVERRIDES */
32963ff40c12SJohn Marino 
32973ff40c12SJohn Marino #ifdef CONFIG_P2P
32983ff40c12SJohn Marino 	/*
32993ff40c12SJohn Marino 	 * If multi-channel concurrency is not supported, check for any
33003ff40c12SJohn Marino 	 * frequency conflict. In case of any frequency conflict, remove the
33013ff40c12SJohn Marino 	 * least prioritized connection.
33023ff40c12SJohn Marino 	 */
33033ff40c12SJohn Marino 	if (wpa_s->num_multichan_concurrent < 2) {
3304*a1157835SDaniel Fojt 		int freq, num;
3305*a1157835SDaniel Fojt 		num = get_shared_radio_freqs(wpa_s, &freq, 1);
3306*a1157835SDaniel Fojt 		if (num > 0 && freq > 0 && freq != params.freq.freq) {
3307*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
3308*a1157835SDaniel Fojt 				   "Assoc conflicting freq found (%d != %d)",
3309*a1157835SDaniel Fojt 				   freq, params.freq.freq);
3310*a1157835SDaniel Fojt 			if (wpas_p2p_handle_frequency_conflicts(
3311*a1157835SDaniel Fojt 				    wpa_s, params.freq.freq, ssid) < 0) {
3312*a1157835SDaniel Fojt 				wpas_connect_work_done(wpa_s);
3313*a1157835SDaniel Fojt 				os_free(wpa_ie);
33143ff40c12SJohn Marino 				return;
33153ff40c12SJohn Marino 			}
33163ff40c12SJohn Marino 		}
3317*a1157835SDaniel Fojt 	}
33183ff40c12SJohn Marino #endif /* CONFIG_P2P */
33193ff40c12SJohn Marino 
3320*a1157835SDaniel Fojt 	if (wpa_s->reassoc_same_ess && !is_zero_ether_addr(prev_bssid) &&
3321*a1157835SDaniel Fojt 	    wpa_s->current_ssid)
3322*a1157835SDaniel Fojt 		params.prev_bssid = prev_bssid;
3323*a1157835SDaniel Fojt 
33246d49e1aeSJan Lentfer 	ret = wpa_drv_associate(wpa_s, &params);
3325*a1157835SDaniel Fojt 	os_free(wpa_ie);
33266d49e1aeSJan Lentfer 	if (ret < 0) {
33276d49e1aeSJan Lentfer 		wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
33286d49e1aeSJan Lentfer 			"failed");
33293ff40c12SJohn Marino 		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SANE_ERROR_CODES) {
33303ff40c12SJohn Marino 			/*
33313ff40c12SJohn Marino 			 * The driver is known to mean what is saying, so we
33323ff40c12SJohn Marino 			 * can stop right here; the association will not
33333ff40c12SJohn Marino 			 * succeed.
33343ff40c12SJohn Marino 			 */
33353ff40c12SJohn Marino 			wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
33363ff40c12SJohn Marino 			wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
33373ff40c12SJohn Marino 			os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
33383ff40c12SJohn Marino 			return;
33393ff40c12SJohn Marino 		}
33406d49e1aeSJan Lentfer 		/* try to continue anyway; new association will be tried again
33416d49e1aeSJan Lentfer 		 * after timeout */
33426d49e1aeSJan Lentfer 		assoc_failed = 1;
33436d49e1aeSJan Lentfer 	}
33446d49e1aeSJan Lentfer 
33456d49e1aeSJan Lentfer 	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
33466d49e1aeSJan Lentfer 		/* Set the key after the association just in case association
33476d49e1aeSJan Lentfer 		 * cleared the previously configured key. */
33486d49e1aeSJan Lentfer 		wpa_supplicant_set_wpa_none_key(wpa_s, ssid);
33496d49e1aeSJan Lentfer 		/* No need to timeout authentication since there is no key
33506d49e1aeSJan Lentfer 		 * management. */
33516d49e1aeSJan Lentfer 		wpa_supplicant_cancel_auth_timeout(wpa_s);
33526d49e1aeSJan Lentfer 		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
33533ff40c12SJohn Marino #ifdef CONFIG_IBSS_RSN
33543ff40c12SJohn Marino 	} else if (ssid->mode == WPAS_MODE_IBSS &&
33553ff40c12SJohn Marino 		   wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
33563ff40c12SJohn Marino 		   wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE) {
33573ff40c12SJohn Marino 		/*
33583ff40c12SJohn Marino 		 * RSN IBSS authentication is per-STA and we can disable the
33593ff40c12SJohn Marino 		 * per-BSSID authentication.
33603ff40c12SJohn Marino 		 */
33613ff40c12SJohn Marino 		wpa_supplicant_cancel_auth_timeout(wpa_s);
33623ff40c12SJohn Marino #endif /* CONFIG_IBSS_RSN */
33636d49e1aeSJan Lentfer 	} else {
33646d49e1aeSJan Lentfer 		/* Timeout for IEEE 802.11 authentication and association */
33656d49e1aeSJan Lentfer 		int timeout = 60;
33666d49e1aeSJan Lentfer 
33676d49e1aeSJan Lentfer 		if (assoc_failed) {
33686d49e1aeSJan Lentfer 			/* give IBSS a bit more time */
33693ff40c12SJohn Marino 			timeout = ssid->mode == WPAS_MODE_IBSS ? 10 : 5;
33706d49e1aeSJan Lentfer 		} else if (wpa_s->conf->ap_scan == 1) {
33716d49e1aeSJan Lentfer 			/* give IBSS a bit more time */
33723ff40c12SJohn Marino 			timeout = ssid->mode == WPAS_MODE_IBSS ? 20 : 10;
33736d49e1aeSJan Lentfer 		}
33746d49e1aeSJan Lentfer 		wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
33756d49e1aeSJan Lentfer 	}
33766d49e1aeSJan Lentfer 
33773ff40c12SJohn Marino 	if (wep_keys_set &&
33783ff40c12SJohn Marino 	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC)) {
33796d49e1aeSJan Lentfer 		/* Set static WEP keys again */
33806d49e1aeSJan Lentfer 		wpa_set_wep_keys(wpa_s, ssid);
33816d49e1aeSJan Lentfer 	}
33826d49e1aeSJan Lentfer 
33836d49e1aeSJan Lentfer 	if (wpa_s->current_ssid && wpa_s->current_ssid != ssid) {
33846d49e1aeSJan Lentfer 		/*
33856d49e1aeSJan Lentfer 		 * Do not allow EAP session resumption between different
33866d49e1aeSJan Lentfer 		 * network configurations.
33876d49e1aeSJan Lentfer 		 */
33886d49e1aeSJan Lentfer 		eapol_sm_invalidate_cached_session(wpa_s->eapol);
33896d49e1aeSJan Lentfer 	}
33903ff40c12SJohn Marino 	old_ssid = wpa_s->current_ssid;
33916d49e1aeSJan Lentfer 	wpa_s->current_ssid = ssid;
3392*a1157835SDaniel Fojt 
3393*a1157835SDaniel Fojt 	if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) {
33943ff40c12SJohn Marino 		wpa_s->current_bss = bss;
3395*a1157835SDaniel Fojt #ifdef CONFIG_HS20
3396*a1157835SDaniel Fojt 		hs20_configure_frame_filters(wpa_s);
3397*a1157835SDaniel Fojt #endif /* CONFIG_HS20 */
3398*a1157835SDaniel Fojt 	}
3399*a1157835SDaniel Fojt 
34006d49e1aeSJan Lentfer 	wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
34016d49e1aeSJan Lentfer 	wpa_supplicant_initiate_eapol(wpa_s);
34023ff40c12SJohn Marino 	if (old_ssid != wpa_s->current_ssid)
34033ff40c12SJohn Marino 		wpas_notify_network_changed(wpa_s);
34046d49e1aeSJan Lentfer }
34056d49e1aeSJan Lentfer 
34066d49e1aeSJan Lentfer 
wpa_supplicant_clear_connection(struct wpa_supplicant * wpa_s,const u8 * addr)34073ff40c12SJohn Marino static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s,
34083ff40c12SJohn Marino 					    const u8 *addr)
34096d49e1aeSJan Lentfer {
34103ff40c12SJohn Marino 	struct wpa_ssid *old_ssid;
34113ff40c12SJohn Marino 
3412*a1157835SDaniel Fojt 	wpas_connect_work_done(wpa_s);
34136d49e1aeSJan Lentfer 	wpa_clear_keys(wpa_s, addr);
34143ff40c12SJohn Marino 	old_ssid = wpa_s->current_ssid;
34156d49e1aeSJan Lentfer 	wpa_supplicant_mark_disassoc(wpa_s);
34166d49e1aeSJan Lentfer 	wpa_sm_set_config(wpa_s->wpa, NULL);
34176d49e1aeSJan Lentfer 	eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
34183ff40c12SJohn Marino 	if (old_ssid != wpa_s->current_ssid)
34193ff40c12SJohn Marino 		wpas_notify_network_changed(wpa_s);
34203ff40c12SJohn Marino 	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
34216d49e1aeSJan Lentfer }
34226d49e1aeSJan Lentfer 
34236d49e1aeSJan Lentfer 
34246d49e1aeSJan Lentfer /**
34256d49e1aeSJan Lentfer  * wpa_supplicant_deauthenticate - Deauthenticate the current connection
34266d49e1aeSJan Lentfer  * @wpa_s: Pointer to wpa_supplicant data
34276d49e1aeSJan Lentfer  * @reason_code: IEEE 802.11 reason code for the deauthenticate frame
34286d49e1aeSJan Lentfer  *
34296d49e1aeSJan Lentfer  * This function is used to request %wpa_supplicant to deauthenticate from the
34306d49e1aeSJan Lentfer  * current AP.
34316d49e1aeSJan Lentfer  */
wpa_supplicant_deauthenticate(struct wpa_supplicant * wpa_s,u16 reason_code)34326d49e1aeSJan Lentfer void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
3433*a1157835SDaniel Fojt 				   u16 reason_code)
34346d49e1aeSJan Lentfer {
34356d49e1aeSJan Lentfer 	u8 *addr = NULL;
34363ff40c12SJohn Marino 	union wpa_event_data event;
34373ff40c12SJohn Marino 	int zero_addr = 0;
34383ff40c12SJohn Marino 
34393ff40c12SJohn Marino 	wpa_dbg(wpa_s, MSG_DEBUG, "Request to deauthenticate - bssid=" MACSTR
3440*a1157835SDaniel Fojt 		" pending_bssid=" MACSTR " reason=%d (%s) state=%s",
34413ff40c12SJohn Marino 		MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
3442*a1157835SDaniel Fojt 		reason_code, reason2str(reason_code),
3443*a1157835SDaniel Fojt 		wpa_supplicant_state_txt(wpa_s->wpa_state));
34443ff40c12SJohn Marino 
3445*a1157835SDaniel Fojt 	if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
34463ff40c12SJohn Marino 	    (wpa_s->wpa_state == WPA_AUTHENTICATING ||
34473ff40c12SJohn Marino 	     wpa_s->wpa_state == WPA_ASSOCIATING))
34483ff40c12SJohn Marino 		addr = wpa_s->pending_bssid;
3449*a1157835SDaniel Fojt 	else if (!is_zero_ether_addr(wpa_s->bssid))
3450*a1157835SDaniel Fojt 		addr = wpa_s->bssid;
34513ff40c12SJohn Marino 	else if (wpa_s->wpa_state == WPA_ASSOCIATING) {
34523ff40c12SJohn Marino 		/*
34533ff40c12SJohn Marino 		 * When using driver-based BSS selection, we may not know the
34543ff40c12SJohn Marino 		 * BSSID with which we are currently trying to associate. We
34553ff40c12SJohn Marino 		 * need to notify the driver of this disconnection even in such
34563ff40c12SJohn Marino 		 * a case, so use the all zeros address here.
34573ff40c12SJohn Marino 		 */
34583ff40c12SJohn Marino 		addr = wpa_s->bssid;
34593ff40c12SJohn Marino 		zero_addr = 1;
34606d49e1aeSJan Lentfer 	}
34613ff40c12SJohn Marino 
3462*a1157835SDaniel Fojt 	if (wpa_s->enabled_4addr_mode && wpa_drv_set_4addr_mode(wpa_s, 0) == 0)
3463*a1157835SDaniel Fojt 		wpa_s->enabled_4addr_mode = 0;
3464*a1157835SDaniel Fojt 
34653ff40c12SJohn Marino #ifdef CONFIG_TDLS
34663ff40c12SJohn Marino 	wpa_tdls_teardown_peers(wpa_s->wpa);
34673ff40c12SJohn Marino #endif /* CONFIG_TDLS */
34683ff40c12SJohn Marino 
3469*a1157835SDaniel Fojt #ifdef CONFIG_MESH
3470*a1157835SDaniel Fojt 	if (wpa_s->ifmsh) {
3471*a1157835SDaniel Fojt 		struct mesh_conf *mconf;
3472*a1157835SDaniel Fojt 
3473*a1157835SDaniel Fojt 		mconf = wpa_s->ifmsh->mconf;
3474*a1157835SDaniel Fojt 		wpa_msg(wpa_s, MSG_INFO, MESH_GROUP_REMOVED "%s",
3475*a1157835SDaniel Fojt 			wpa_s->ifname);
3476*a1157835SDaniel Fojt 		wpas_notify_mesh_group_removed(wpa_s, mconf->meshid,
3477*a1157835SDaniel Fojt 					       mconf->meshid_len, reason_code);
3478*a1157835SDaniel Fojt 		wpa_supplicant_leave_mesh(wpa_s);
3479*a1157835SDaniel Fojt 	}
3480*a1157835SDaniel Fojt #endif /* CONFIG_MESH */
3481*a1157835SDaniel Fojt 
34823ff40c12SJohn Marino 	if (addr) {
34833ff40c12SJohn Marino 		wpa_drv_deauthenticate(wpa_s, addr, reason_code);
34843ff40c12SJohn Marino 		os_memset(&event, 0, sizeof(event));
3485*a1157835SDaniel Fojt 		event.deauth_info.reason_code = reason_code;
34863ff40c12SJohn Marino 		event.deauth_info.locally_generated = 1;
34873ff40c12SJohn Marino 		wpa_supplicant_event(wpa_s, EVENT_DEAUTH, &event);
34883ff40c12SJohn Marino 		if (zero_addr)
34893ff40c12SJohn Marino 			addr = NULL;
34903ff40c12SJohn Marino 	}
34913ff40c12SJohn Marino 
34923ff40c12SJohn Marino 	wpa_supplicant_clear_connection(wpa_s, addr);
34933ff40c12SJohn Marino }
34943ff40c12SJohn Marino 
wpa_supplicant_enable_one_network(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid)34953ff40c12SJohn Marino static void wpa_supplicant_enable_one_network(struct wpa_supplicant *wpa_s,
34963ff40c12SJohn Marino 					      struct wpa_ssid *ssid)
34973ff40c12SJohn Marino {
34983ff40c12SJohn Marino 	if (!ssid || !ssid->disabled || ssid->disabled == 2)
34993ff40c12SJohn Marino 		return;
35003ff40c12SJohn Marino 
35013ff40c12SJohn Marino 	ssid->disabled = 0;
3502*a1157835SDaniel Fojt 	ssid->owe_transition_bss_select_count = 0;
35033ff40c12SJohn Marino 	wpas_clear_temp_disabled(wpa_s, ssid, 1);
35043ff40c12SJohn Marino 	wpas_notify_network_enabled_changed(wpa_s, ssid);
35053ff40c12SJohn Marino 
35063ff40c12SJohn Marino 	/*
35073ff40c12SJohn Marino 	 * Try to reassociate since there is no current configuration and a new
35083ff40c12SJohn Marino 	 * network was made available.
35093ff40c12SJohn Marino 	 */
35103ff40c12SJohn Marino 	if (!wpa_s->current_ssid && !wpa_s->disconnected)
35113ff40c12SJohn Marino 		wpa_s->reassociate = 1;
35123ff40c12SJohn Marino }
35133ff40c12SJohn Marino 
35143ff40c12SJohn Marino 
35153ff40c12SJohn Marino /**
3516*a1157835SDaniel Fojt  * wpa_supplicant_add_network - Add a new network
3517*a1157835SDaniel Fojt  * @wpa_s: wpa_supplicant structure for a network interface
3518*a1157835SDaniel Fojt  * Returns: The new network configuration or %NULL if operation failed
3519*a1157835SDaniel Fojt  *
3520*a1157835SDaniel Fojt  * This function performs the following operations:
3521*a1157835SDaniel Fojt  * 1. Adds a new network.
3522*a1157835SDaniel Fojt  * 2. Send network addition notification.
3523*a1157835SDaniel Fojt  * 3. Marks the network disabled.
3524*a1157835SDaniel Fojt  * 4. Set network default parameters.
3525*a1157835SDaniel Fojt  */
wpa_supplicant_add_network(struct wpa_supplicant * wpa_s)3526*a1157835SDaniel Fojt struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s)
3527*a1157835SDaniel Fojt {
3528*a1157835SDaniel Fojt 	struct wpa_ssid *ssid;
3529*a1157835SDaniel Fojt 
3530*a1157835SDaniel Fojt 	ssid = wpa_config_add_network(wpa_s->conf);
3531*a1157835SDaniel Fojt 	if (!ssid)
3532*a1157835SDaniel Fojt 		return NULL;
3533*a1157835SDaniel Fojt 	wpas_notify_network_added(wpa_s, ssid);
3534*a1157835SDaniel Fojt 	ssid->disabled = 1;
3535*a1157835SDaniel Fojt 	wpa_config_set_network_defaults(ssid);
3536*a1157835SDaniel Fojt 
3537*a1157835SDaniel Fojt 	return ssid;
3538*a1157835SDaniel Fojt }
3539*a1157835SDaniel Fojt 
3540*a1157835SDaniel Fojt 
3541*a1157835SDaniel Fojt /**
3542*a1157835SDaniel Fojt  * wpa_supplicant_remove_network - Remove a configured network based on id
3543*a1157835SDaniel Fojt  * @wpa_s: wpa_supplicant structure for a network interface
3544*a1157835SDaniel Fojt  * @id: Unique network id to search for
3545*a1157835SDaniel Fojt  * Returns: 0 on success, or -1 if the network was not found, -2 if the network
3546*a1157835SDaniel Fojt  * could not be removed
3547*a1157835SDaniel Fojt  *
3548*a1157835SDaniel Fojt  * This function performs the following operations:
3549*a1157835SDaniel Fojt  * 1. Removes the network.
3550*a1157835SDaniel Fojt  * 2. Send network removal notification.
3551*a1157835SDaniel Fojt  * 3. Update internal state machines.
3552*a1157835SDaniel Fojt  * 4. Stop any running sched scans.
3553*a1157835SDaniel Fojt  */
wpa_supplicant_remove_network(struct wpa_supplicant * wpa_s,int id)3554*a1157835SDaniel Fojt int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id)
3555*a1157835SDaniel Fojt {
3556*a1157835SDaniel Fojt 	struct wpa_ssid *ssid;
3557*a1157835SDaniel Fojt 	int was_disabled;
3558*a1157835SDaniel Fojt 
3559*a1157835SDaniel Fojt 	ssid = wpa_config_get_network(wpa_s->conf, id);
3560*a1157835SDaniel Fojt 	if (!ssid)
3561*a1157835SDaniel Fojt 		return -1;
3562*a1157835SDaniel Fojt 	wpas_notify_network_removed(wpa_s, ssid);
3563*a1157835SDaniel Fojt 
3564*a1157835SDaniel Fojt 	if (wpa_s->last_ssid == ssid)
3565*a1157835SDaniel Fojt 		wpa_s->last_ssid = NULL;
3566*a1157835SDaniel Fojt 
3567*a1157835SDaniel Fojt 	if (ssid == wpa_s->current_ssid || !wpa_s->current_ssid) {
3568*a1157835SDaniel Fojt #ifdef CONFIG_SME
3569*a1157835SDaniel Fojt 		wpa_s->sme.prev_bssid_set = 0;
3570*a1157835SDaniel Fojt #endif /* CONFIG_SME */
3571*a1157835SDaniel Fojt 		/*
3572*a1157835SDaniel Fojt 		 * Invalidate the EAP session cache if the current or
3573*a1157835SDaniel Fojt 		 * previously used network is removed.
3574*a1157835SDaniel Fojt 		 */
3575*a1157835SDaniel Fojt 		eapol_sm_invalidate_cached_session(wpa_s->eapol);
3576*a1157835SDaniel Fojt 	}
3577*a1157835SDaniel Fojt 
3578*a1157835SDaniel Fojt 	if (ssid == wpa_s->current_ssid) {
3579*a1157835SDaniel Fojt 		wpa_sm_set_config(wpa_s->wpa, NULL);
3580*a1157835SDaniel Fojt 		eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
3581*a1157835SDaniel Fojt 
3582*a1157835SDaniel Fojt 		if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
3583*a1157835SDaniel Fojt 			wpa_s->own_disconnect_req = 1;
3584*a1157835SDaniel Fojt 		wpa_supplicant_deauthenticate(wpa_s,
3585*a1157835SDaniel Fojt 					      WLAN_REASON_DEAUTH_LEAVING);
3586*a1157835SDaniel Fojt 	}
3587*a1157835SDaniel Fojt 
3588*a1157835SDaniel Fojt 	was_disabled = ssid->disabled;
3589*a1157835SDaniel Fojt 
3590*a1157835SDaniel Fojt 	if (wpa_config_remove_network(wpa_s->conf, id) < 0)
3591*a1157835SDaniel Fojt 		return -2;
3592*a1157835SDaniel Fojt 
3593*a1157835SDaniel Fojt 	if (!was_disabled && wpa_s->sched_scanning) {
3594*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
3595*a1157835SDaniel Fojt 			   "Stop ongoing sched_scan to remove network from filters");
3596*a1157835SDaniel Fojt 		wpa_supplicant_cancel_sched_scan(wpa_s);
3597*a1157835SDaniel Fojt 		wpa_supplicant_req_scan(wpa_s, 0, 0);
3598*a1157835SDaniel Fojt 	}
3599*a1157835SDaniel Fojt 
3600*a1157835SDaniel Fojt 	return 0;
3601*a1157835SDaniel Fojt }
3602*a1157835SDaniel Fojt 
3603*a1157835SDaniel Fojt 
3604*a1157835SDaniel Fojt /**
36053ff40c12SJohn Marino  * wpa_supplicant_enable_network - Mark a configured network as enabled
36063ff40c12SJohn Marino  * @wpa_s: wpa_supplicant structure for a network interface
36073ff40c12SJohn Marino  * @ssid: wpa_ssid structure for a configured network or %NULL
36083ff40c12SJohn Marino  *
36093ff40c12SJohn Marino  * Enables the specified network or all networks if no network specified.
36103ff40c12SJohn Marino  */
wpa_supplicant_enable_network(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid)36113ff40c12SJohn Marino void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
36123ff40c12SJohn Marino 				   struct wpa_ssid *ssid)
36133ff40c12SJohn Marino {
36143ff40c12SJohn Marino 	if (ssid == NULL) {
36153ff40c12SJohn Marino 		for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
36163ff40c12SJohn Marino 			wpa_supplicant_enable_one_network(wpa_s, ssid);
36173ff40c12SJohn Marino 	} else
36183ff40c12SJohn Marino 		wpa_supplicant_enable_one_network(wpa_s, ssid);
36193ff40c12SJohn Marino 
3620*a1157835SDaniel Fojt 	if (wpa_s->reassociate && !wpa_s->disconnected &&
3621*a1157835SDaniel Fojt 	    (!wpa_s->current_ssid ||
3622*a1157835SDaniel Fojt 	     wpa_s->wpa_state == WPA_DISCONNECTED ||
3623*a1157835SDaniel Fojt 	     wpa_s->wpa_state == WPA_SCANNING)) {
36243ff40c12SJohn Marino 		if (wpa_s->sched_scanning) {
36253ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to add "
36263ff40c12SJohn Marino 				   "new network to scan filters");
36273ff40c12SJohn Marino 			wpa_supplicant_cancel_sched_scan(wpa_s);
36283ff40c12SJohn Marino 		}
36293ff40c12SJohn Marino 
3630*a1157835SDaniel Fojt 		if (wpa_supplicant_fast_associate(wpa_s) != 1) {
3631*a1157835SDaniel Fojt 			wpa_s->scan_req = NORMAL_SCAN_REQ;
36323ff40c12SJohn Marino 			wpa_supplicant_req_scan(wpa_s, 0, 0);
36333ff40c12SJohn Marino 		}
36343ff40c12SJohn Marino 	}
3635*a1157835SDaniel Fojt }
36363ff40c12SJohn Marino 
36373ff40c12SJohn Marino 
36383ff40c12SJohn Marino /**
36393ff40c12SJohn Marino  * wpa_supplicant_disable_network - Mark a configured network as disabled
36403ff40c12SJohn Marino  * @wpa_s: wpa_supplicant structure for a network interface
36413ff40c12SJohn Marino  * @ssid: wpa_ssid structure for a configured network or %NULL
36423ff40c12SJohn Marino  *
36433ff40c12SJohn Marino  * Disables the specified network or all networks if no network specified.
36443ff40c12SJohn Marino  */
wpa_supplicant_disable_network(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid)36453ff40c12SJohn Marino void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
36463ff40c12SJohn Marino 				    struct wpa_ssid *ssid)
36473ff40c12SJohn Marino {
36483ff40c12SJohn Marino 	struct wpa_ssid *other_ssid;
36493ff40c12SJohn Marino 	int was_disabled;
36503ff40c12SJohn Marino 
36513ff40c12SJohn Marino 	if (ssid == NULL) {
36523ff40c12SJohn Marino 		if (wpa_s->sched_scanning)
36533ff40c12SJohn Marino 			wpa_supplicant_cancel_sched_scan(wpa_s);
36543ff40c12SJohn Marino 
36553ff40c12SJohn Marino 		for (other_ssid = wpa_s->conf->ssid; other_ssid;
36563ff40c12SJohn Marino 		     other_ssid = other_ssid->next) {
36573ff40c12SJohn Marino 			was_disabled = other_ssid->disabled;
36583ff40c12SJohn Marino 			if (was_disabled == 2)
36593ff40c12SJohn Marino 				continue; /* do not change persistent P2P group
36603ff40c12SJohn Marino 					   * data */
36613ff40c12SJohn Marino 
36623ff40c12SJohn Marino 			other_ssid->disabled = 1;
36633ff40c12SJohn Marino 
36643ff40c12SJohn Marino 			if (was_disabled != other_ssid->disabled)
36653ff40c12SJohn Marino 				wpas_notify_network_enabled_changed(
36663ff40c12SJohn Marino 					wpa_s, other_ssid);
36673ff40c12SJohn Marino 		}
3668*a1157835SDaniel Fojt 		if (wpa_s->current_ssid) {
3669*a1157835SDaniel Fojt 			if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
3670*a1157835SDaniel Fojt 				wpa_s->own_disconnect_req = 1;
36713ff40c12SJohn Marino 			wpa_supplicant_deauthenticate(
36723ff40c12SJohn Marino 				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
3673*a1157835SDaniel Fojt 		}
36743ff40c12SJohn Marino 	} else if (ssid->disabled != 2) {
3675*a1157835SDaniel Fojt 		if (ssid == wpa_s->current_ssid) {
3676*a1157835SDaniel Fojt 			if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
3677*a1157835SDaniel Fojt 				wpa_s->own_disconnect_req = 1;
36783ff40c12SJohn Marino 			wpa_supplicant_deauthenticate(
36793ff40c12SJohn Marino 				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
3680*a1157835SDaniel Fojt 		}
36813ff40c12SJohn Marino 
36823ff40c12SJohn Marino 		was_disabled = ssid->disabled;
36833ff40c12SJohn Marino 
36843ff40c12SJohn Marino 		ssid->disabled = 1;
36853ff40c12SJohn Marino 
36863ff40c12SJohn Marino 		if (was_disabled != ssid->disabled) {
36873ff40c12SJohn Marino 			wpas_notify_network_enabled_changed(wpa_s, ssid);
36883ff40c12SJohn Marino 			if (wpa_s->sched_scanning) {
36893ff40c12SJohn Marino 				wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan "
36903ff40c12SJohn Marino 					   "to remove network from filters");
36913ff40c12SJohn Marino 				wpa_supplicant_cancel_sched_scan(wpa_s);
36923ff40c12SJohn Marino 				wpa_supplicant_req_scan(wpa_s, 0, 0);
36933ff40c12SJohn Marino 			}
36943ff40c12SJohn Marino 		}
36953ff40c12SJohn Marino 	}
36963ff40c12SJohn Marino }
36973ff40c12SJohn Marino 
36983ff40c12SJohn Marino 
36993ff40c12SJohn Marino /**
37003ff40c12SJohn Marino  * wpa_supplicant_select_network - Attempt association with a network
37013ff40c12SJohn Marino  * @wpa_s: wpa_supplicant structure for a network interface
37023ff40c12SJohn Marino  * @ssid: wpa_ssid structure for a configured network or %NULL for any network
37033ff40c12SJohn Marino  */
wpa_supplicant_select_network(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid)37043ff40c12SJohn Marino void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
37053ff40c12SJohn Marino 				   struct wpa_ssid *ssid)
37063ff40c12SJohn Marino {
37073ff40c12SJohn Marino 
37083ff40c12SJohn Marino 	struct wpa_ssid *other_ssid;
37093ff40c12SJohn Marino 	int disconnected = 0;
37103ff40c12SJohn Marino 
37113ff40c12SJohn Marino 	if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid) {
3712*a1157835SDaniel Fojt 		if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
3713*a1157835SDaniel Fojt 			wpa_s->own_disconnect_req = 1;
37143ff40c12SJohn Marino 		wpa_supplicant_deauthenticate(
37153ff40c12SJohn Marino 			wpa_s, WLAN_REASON_DEAUTH_LEAVING);
37163ff40c12SJohn Marino 		disconnected = 1;
37173ff40c12SJohn Marino 	}
37183ff40c12SJohn Marino 
37193ff40c12SJohn Marino 	if (ssid)
37203ff40c12SJohn Marino 		wpas_clear_temp_disabled(wpa_s, ssid, 1);
37213ff40c12SJohn Marino 
37223ff40c12SJohn Marino 	/*
37233ff40c12SJohn Marino 	 * Mark all other networks disabled or mark all networks enabled if no
37243ff40c12SJohn Marino 	 * network specified.
37253ff40c12SJohn Marino 	 */
37263ff40c12SJohn Marino 	for (other_ssid = wpa_s->conf->ssid; other_ssid;
37273ff40c12SJohn Marino 	     other_ssid = other_ssid->next) {
37283ff40c12SJohn Marino 		int was_disabled = other_ssid->disabled;
37293ff40c12SJohn Marino 		if (was_disabled == 2)
37303ff40c12SJohn Marino 			continue; /* do not change persistent P2P group data */
37313ff40c12SJohn Marino 
37323ff40c12SJohn Marino 		other_ssid->disabled = ssid ? (ssid->id != other_ssid->id) : 0;
37333ff40c12SJohn Marino 		if (was_disabled && !other_ssid->disabled)
37343ff40c12SJohn Marino 			wpas_clear_temp_disabled(wpa_s, other_ssid, 0);
37353ff40c12SJohn Marino 
37363ff40c12SJohn Marino 		if (was_disabled != other_ssid->disabled)
37373ff40c12SJohn Marino 			wpas_notify_network_enabled_changed(wpa_s, other_ssid);
37383ff40c12SJohn Marino 	}
37393ff40c12SJohn Marino 
3740*a1157835SDaniel Fojt 	if (ssid && ssid == wpa_s->current_ssid && wpa_s->current_ssid &&
3741*a1157835SDaniel Fojt 	    wpa_s->wpa_state >= WPA_AUTHENTICATING) {
37423ff40c12SJohn Marino 		/* We are already associated with the selected network */
37433ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "Already associated with the "
37443ff40c12SJohn Marino 			   "selected network - do nothing");
37453ff40c12SJohn Marino 		return;
37463ff40c12SJohn Marino 	}
37473ff40c12SJohn Marino 
37483ff40c12SJohn Marino 	if (ssid) {
37493ff40c12SJohn Marino 		wpa_s->current_ssid = ssid;
37506d49e1aeSJan Lentfer 		eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
3751*a1157835SDaniel Fojt 		wpa_s->connect_without_scan =
3752*a1157835SDaniel Fojt 			(ssid->mode == WPAS_MODE_MESH) ? ssid : NULL;
3753*a1157835SDaniel Fojt 
3754*a1157835SDaniel Fojt 		/*
3755*a1157835SDaniel Fojt 		 * Don't optimize next scan freqs since a new ESS has been
3756*a1157835SDaniel Fojt 		 * selected.
3757*a1157835SDaniel Fojt 		 */
3758*a1157835SDaniel Fojt 		os_free(wpa_s->next_scan_freqs);
3759*a1157835SDaniel Fojt 		wpa_s->next_scan_freqs = NULL;
3760*a1157835SDaniel Fojt 	} else {
37613ff40c12SJohn Marino 		wpa_s->connect_without_scan = NULL;
3762*a1157835SDaniel Fojt 	}
3763*a1157835SDaniel Fojt 
37643ff40c12SJohn Marino 	wpa_s->disconnected = 0;
37653ff40c12SJohn Marino 	wpa_s->reassociate = 1;
3766*a1157835SDaniel Fojt 	wpa_s->last_owe_group = 0;
3767*a1157835SDaniel Fojt 	if (ssid)
3768*a1157835SDaniel Fojt 		ssid->owe_transition_bss_select_count = 0;
37693ff40c12SJohn Marino 
3770*a1157835SDaniel Fojt 	if (wpa_s->connect_without_scan ||
3771*a1157835SDaniel Fojt 	    wpa_supplicant_fast_associate(wpa_s) != 1) {
3772*a1157835SDaniel Fojt 		wpa_s->scan_req = NORMAL_SCAN_REQ;
3773*a1157835SDaniel Fojt 		wpas_scan_reset_sched_scan(wpa_s);
37743ff40c12SJohn Marino 		wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
3775*a1157835SDaniel Fojt 	}
37763ff40c12SJohn Marino 
37773ff40c12SJohn Marino 	if (ssid)
37783ff40c12SJohn Marino 		wpas_notify_network_selected(wpa_s, ssid);
37793ff40c12SJohn Marino }
37806d49e1aeSJan Lentfer 
37816d49e1aeSJan Lentfer 
37823ff40c12SJohn Marino /**
37833ff40c12SJohn Marino  * wpas_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path
37843ff40c12SJohn Marino  * @wpa_s: wpa_supplicant structure for a network interface
37853ff40c12SJohn Marino  * @pkcs11_engine_path: PKCS #11 engine path or NULL
37863ff40c12SJohn Marino  * @pkcs11_module_path: PKCS #11 module path or NULL
37873ff40c12SJohn Marino  * Returns: 0 on success; -1 on failure
37883ff40c12SJohn Marino  *
37893ff40c12SJohn Marino  * Sets the PKCS #11 engine and module path. Both have to be NULL or a valid
37903ff40c12SJohn Marino  * path. If resetting the EAPOL state machine with the new PKCS #11 engine and
37913ff40c12SJohn Marino  * module path fails the paths will be reset to the default value (NULL).
37923ff40c12SJohn Marino  */
wpas_set_pkcs11_engine_and_module_path(struct wpa_supplicant * wpa_s,const char * pkcs11_engine_path,const char * pkcs11_module_path)37933ff40c12SJohn Marino int wpas_set_pkcs11_engine_and_module_path(struct wpa_supplicant *wpa_s,
37943ff40c12SJohn Marino 					   const char *pkcs11_engine_path,
37953ff40c12SJohn Marino 					   const char *pkcs11_module_path)
37966d49e1aeSJan Lentfer {
37973ff40c12SJohn Marino 	char *pkcs11_engine_path_copy = NULL;
37983ff40c12SJohn Marino 	char *pkcs11_module_path_copy = NULL;
37996d49e1aeSJan Lentfer 
38003ff40c12SJohn Marino 	if (pkcs11_engine_path != NULL) {
38013ff40c12SJohn Marino 		pkcs11_engine_path_copy = os_strdup(pkcs11_engine_path);
38023ff40c12SJohn Marino 		if (pkcs11_engine_path_copy == NULL)
38036d49e1aeSJan Lentfer 			return -1;
38046d49e1aeSJan Lentfer 	}
38053ff40c12SJohn Marino 	if (pkcs11_module_path != NULL) {
38063ff40c12SJohn Marino 		pkcs11_module_path_copy = os_strdup(pkcs11_module_path);
38073ff40c12SJohn Marino 		if (pkcs11_module_path_copy == NULL) {
38083ff40c12SJohn Marino 			os_free(pkcs11_engine_path_copy);
38096d49e1aeSJan Lentfer 			return -1;
38106d49e1aeSJan Lentfer 		}
38116d49e1aeSJan Lentfer 	}
38126d49e1aeSJan Lentfer 
38133ff40c12SJohn Marino 	os_free(wpa_s->conf->pkcs11_engine_path);
38143ff40c12SJohn Marino 	os_free(wpa_s->conf->pkcs11_module_path);
38153ff40c12SJohn Marino 	wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path_copy;
38163ff40c12SJohn Marino 	wpa_s->conf->pkcs11_module_path = pkcs11_module_path_copy;
38176d49e1aeSJan Lentfer 
38183ff40c12SJohn Marino 	wpa_sm_set_eapol(wpa_s->wpa, NULL);
38193ff40c12SJohn Marino 	eapol_sm_deinit(wpa_s->eapol);
38203ff40c12SJohn Marino 	wpa_s->eapol = NULL;
38213ff40c12SJohn Marino 	if (wpa_supplicant_init_eapol(wpa_s)) {
38223ff40c12SJohn Marino 		/* Error -> Reset paths to the default value (NULL) once. */
38233ff40c12SJohn Marino 		if (pkcs11_engine_path != NULL && pkcs11_module_path != NULL)
38243ff40c12SJohn Marino 			wpas_set_pkcs11_engine_and_module_path(wpa_s, NULL,
38253ff40c12SJohn Marino 							       NULL);
38263ff40c12SJohn Marino 
38276d49e1aeSJan Lentfer 		return -1;
38286d49e1aeSJan Lentfer 	}
38293ff40c12SJohn Marino 	wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
38306d49e1aeSJan Lentfer 
38316d49e1aeSJan Lentfer 	return 0;
38326d49e1aeSJan Lentfer }
38336d49e1aeSJan Lentfer 
38346d49e1aeSJan Lentfer 
38356d49e1aeSJan Lentfer /**
38363ff40c12SJohn Marino  * wpa_supplicant_set_ap_scan - Set AP scan mode for interface
38373ff40c12SJohn Marino  * @wpa_s: wpa_supplicant structure for a network interface
38383ff40c12SJohn Marino  * @ap_scan: AP scan mode
38393ff40c12SJohn Marino  * Returns: 0 if succeed or -1 if ap_scan has an invalid value
38406d49e1aeSJan Lentfer  *
38416d49e1aeSJan Lentfer  */
wpa_supplicant_set_ap_scan(struct wpa_supplicant * wpa_s,int ap_scan)38423ff40c12SJohn Marino int wpa_supplicant_set_ap_scan(struct wpa_supplicant *wpa_s, int ap_scan)
38436d49e1aeSJan Lentfer {
38446d49e1aeSJan Lentfer 
38453ff40c12SJohn Marino 	int old_ap_scan;
38463ff40c12SJohn Marino 
38473ff40c12SJohn Marino 	if (ap_scan < 0 || ap_scan > 2)
38483ff40c12SJohn Marino 		return -1;
38493ff40c12SJohn Marino 
3850*a1157835SDaniel Fojt 	if (ap_scan == 2 && os_strcmp(wpa_s->driver->name, "nl80211") == 0) {
3851*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
3852*a1157835SDaniel Fojt 			   "Note: nl80211 driver interface is not designed to be used with ap_scan=2; this can result in connection failures");
3853*a1157835SDaniel Fojt 	}
3854*a1157835SDaniel Fojt 
38553ff40c12SJohn Marino #ifdef ANDROID
38563ff40c12SJohn Marino 	if (ap_scan == 2 && ap_scan != wpa_s->conf->ap_scan &&
38573ff40c12SJohn Marino 	    wpa_s->wpa_state >= WPA_ASSOCIATING &&
38583ff40c12SJohn Marino 	    wpa_s->wpa_state < WPA_COMPLETED) {
38593ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "ap_scan = %d (%d) rejected while "
38603ff40c12SJohn Marino 			   "associating", wpa_s->conf->ap_scan, ap_scan);
38613ff40c12SJohn Marino 		return 0;
38623ff40c12SJohn Marino 	}
38633ff40c12SJohn Marino #endif /* ANDROID */
38643ff40c12SJohn Marino 
38653ff40c12SJohn Marino 	old_ap_scan = wpa_s->conf->ap_scan;
38663ff40c12SJohn Marino 	wpa_s->conf->ap_scan = ap_scan;
38673ff40c12SJohn Marino 
38683ff40c12SJohn Marino 	if (old_ap_scan != wpa_s->conf->ap_scan)
38693ff40c12SJohn Marino 		wpas_notify_ap_scan_changed(wpa_s);
38703ff40c12SJohn Marino 
38713ff40c12SJohn Marino 	return 0;
38726d49e1aeSJan Lentfer }
38736d49e1aeSJan Lentfer 
38746d49e1aeSJan Lentfer 
38753ff40c12SJohn Marino /**
38763ff40c12SJohn Marino  * wpa_supplicant_set_bss_expiration_age - Set BSS entry expiration age
38773ff40c12SJohn Marino  * @wpa_s: wpa_supplicant structure for a network interface
38783ff40c12SJohn Marino  * @expire_age: Expiration age in seconds
38793ff40c12SJohn Marino  * Returns: 0 if succeed or -1 if expire_age has an invalid value
38803ff40c12SJohn Marino  *
38813ff40c12SJohn Marino  */
wpa_supplicant_set_bss_expiration_age(struct wpa_supplicant * wpa_s,unsigned int bss_expire_age)38823ff40c12SJohn Marino int wpa_supplicant_set_bss_expiration_age(struct wpa_supplicant *wpa_s,
38833ff40c12SJohn Marino 					  unsigned int bss_expire_age)
38843ff40c12SJohn Marino {
38853ff40c12SJohn Marino 	if (bss_expire_age < 10) {
38863ff40c12SJohn Marino 		wpa_msg(wpa_s, MSG_ERROR, "Invalid bss expiration age %u",
38873ff40c12SJohn Marino 			bss_expire_age);
38883ff40c12SJohn Marino 		return -1;
38893ff40c12SJohn Marino 	}
38903ff40c12SJohn Marino 	wpa_msg(wpa_s, MSG_DEBUG, "Setting bss expiration age: %d sec",
38913ff40c12SJohn Marino 		bss_expire_age);
38923ff40c12SJohn Marino 	wpa_s->conf->bss_expiration_age = bss_expire_age;
38933ff40c12SJohn Marino 
38943ff40c12SJohn Marino 	return 0;
38953ff40c12SJohn Marino }
38963ff40c12SJohn Marino 
38973ff40c12SJohn Marino 
38983ff40c12SJohn Marino /**
38993ff40c12SJohn Marino  * wpa_supplicant_set_bss_expiration_count - Set BSS entry expiration scan count
39003ff40c12SJohn Marino  * @wpa_s: wpa_supplicant structure for a network interface
39013ff40c12SJohn Marino  * @expire_count: number of scans after which an unseen BSS is reclaimed
39023ff40c12SJohn Marino  * Returns: 0 if succeed or -1 if expire_count has an invalid value
39033ff40c12SJohn Marino  *
39043ff40c12SJohn Marino  */
wpa_supplicant_set_bss_expiration_count(struct wpa_supplicant * wpa_s,unsigned int bss_expire_count)39053ff40c12SJohn Marino int wpa_supplicant_set_bss_expiration_count(struct wpa_supplicant *wpa_s,
39063ff40c12SJohn Marino 					    unsigned int bss_expire_count)
39073ff40c12SJohn Marino {
39083ff40c12SJohn Marino 	if (bss_expire_count < 1) {
39093ff40c12SJohn Marino 		wpa_msg(wpa_s, MSG_ERROR, "Invalid bss expiration count %u",
39103ff40c12SJohn Marino 			bss_expire_count);
39113ff40c12SJohn Marino 		return -1;
39123ff40c12SJohn Marino 	}
39133ff40c12SJohn Marino 	wpa_msg(wpa_s, MSG_DEBUG, "Setting bss expiration scan count: %u",
39143ff40c12SJohn Marino 		bss_expire_count);
39153ff40c12SJohn Marino 	wpa_s->conf->bss_expiration_scan_count = bss_expire_count;
39163ff40c12SJohn Marino 
39173ff40c12SJohn Marino 	return 0;
39183ff40c12SJohn Marino }
39193ff40c12SJohn Marino 
39203ff40c12SJohn Marino 
39213ff40c12SJohn Marino /**
39223ff40c12SJohn Marino  * wpa_supplicant_set_scan_interval - Set scan interval
39233ff40c12SJohn Marino  * @wpa_s: wpa_supplicant structure for a network interface
39243ff40c12SJohn Marino  * @scan_interval: scan interval in seconds
39253ff40c12SJohn Marino  * Returns: 0 if succeed or -1 if scan_interval has an invalid value
39263ff40c12SJohn Marino  *
39273ff40c12SJohn Marino  */
wpa_supplicant_set_scan_interval(struct wpa_supplicant * wpa_s,int scan_interval)39283ff40c12SJohn Marino int wpa_supplicant_set_scan_interval(struct wpa_supplicant *wpa_s,
39293ff40c12SJohn Marino 				     int scan_interval)
39303ff40c12SJohn Marino {
39313ff40c12SJohn Marino 	if (scan_interval < 0) {
39323ff40c12SJohn Marino 		wpa_msg(wpa_s, MSG_ERROR, "Invalid scan interval %d",
39333ff40c12SJohn Marino 			scan_interval);
39343ff40c12SJohn Marino 		return -1;
39353ff40c12SJohn Marino 	}
39363ff40c12SJohn Marino 	wpa_msg(wpa_s, MSG_DEBUG, "Setting scan interval: %d sec",
39373ff40c12SJohn Marino 		scan_interval);
39383ff40c12SJohn Marino 	wpa_supplicant_update_scan_int(wpa_s, scan_interval);
39393ff40c12SJohn Marino 
39403ff40c12SJohn Marino 	return 0;
39413ff40c12SJohn Marino }
39423ff40c12SJohn Marino 
39433ff40c12SJohn Marino 
39443ff40c12SJohn Marino /**
39453ff40c12SJohn Marino  * wpa_supplicant_set_debug_params - Set global debug params
39463ff40c12SJohn Marino  * @global: wpa_global structure
39473ff40c12SJohn Marino  * @debug_level: debug level
39483ff40c12SJohn Marino  * @debug_timestamp: determines if show timestamp in debug data
39493ff40c12SJohn Marino  * @debug_show_keys: determines if show keys in debug data
39503ff40c12SJohn Marino  * Returns: 0 if succeed or -1 if debug_level has wrong value
39513ff40c12SJohn Marino  */
wpa_supplicant_set_debug_params(struct wpa_global * global,int debug_level,int debug_timestamp,int debug_show_keys)39523ff40c12SJohn Marino int wpa_supplicant_set_debug_params(struct wpa_global *global, int debug_level,
39533ff40c12SJohn Marino 				    int debug_timestamp, int debug_show_keys)
39543ff40c12SJohn Marino {
39553ff40c12SJohn Marino 
39563ff40c12SJohn Marino 	int old_level, old_timestamp, old_show_keys;
39573ff40c12SJohn Marino 
39583ff40c12SJohn Marino 	/* check for allowed debuglevels */
39593ff40c12SJohn Marino 	if (debug_level != MSG_EXCESSIVE &&
39603ff40c12SJohn Marino 	    debug_level != MSG_MSGDUMP &&
39613ff40c12SJohn Marino 	    debug_level != MSG_DEBUG &&
39623ff40c12SJohn Marino 	    debug_level != MSG_INFO &&
39633ff40c12SJohn Marino 	    debug_level != MSG_WARNING &&
39643ff40c12SJohn Marino 	    debug_level != MSG_ERROR)
39653ff40c12SJohn Marino 		return -1;
39663ff40c12SJohn Marino 
39673ff40c12SJohn Marino 	old_level = wpa_debug_level;
39683ff40c12SJohn Marino 	old_timestamp = wpa_debug_timestamp;
39693ff40c12SJohn Marino 	old_show_keys = wpa_debug_show_keys;
39703ff40c12SJohn Marino 
39713ff40c12SJohn Marino 	wpa_debug_level = debug_level;
39723ff40c12SJohn Marino 	wpa_debug_timestamp = debug_timestamp ? 1 : 0;
39733ff40c12SJohn Marino 	wpa_debug_show_keys = debug_show_keys ? 1 : 0;
39743ff40c12SJohn Marino 
39753ff40c12SJohn Marino 	if (wpa_debug_level != old_level)
39763ff40c12SJohn Marino 		wpas_notify_debug_level_changed(global);
39773ff40c12SJohn Marino 	if (wpa_debug_timestamp != old_timestamp)
39783ff40c12SJohn Marino 		wpas_notify_debug_timestamp_changed(global);
39793ff40c12SJohn Marino 	if (wpa_debug_show_keys != old_show_keys)
39803ff40c12SJohn Marino 		wpas_notify_debug_show_keys_changed(global);
39813ff40c12SJohn Marino 
39823ff40c12SJohn Marino 	return 0;
39836d49e1aeSJan Lentfer }
39846d49e1aeSJan Lentfer 
39856d49e1aeSJan Lentfer 
3986*a1157835SDaniel Fojt #ifdef CONFIG_OWE
owe_trans_ssid_match(struct wpa_supplicant * wpa_s,const u8 * bssid,const u8 * entry_ssid,size_t entry_ssid_len)3987*a1157835SDaniel Fojt static int owe_trans_ssid_match(struct wpa_supplicant *wpa_s, const u8 *bssid,
3988*a1157835SDaniel Fojt 				const u8 *entry_ssid, size_t entry_ssid_len)
3989*a1157835SDaniel Fojt {
3990*a1157835SDaniel Fojt 	const u8 *owe, *pos, *end;
3991*a1157835SDaniel Fojt 	u8 ssid_len;
3992*a1157835SDaniel Fojt 	struct wpa_bss *bss;
3993*a1157835SDaniel Fojt 
3994*a1157835SDaniel Fojt 	/* Check network profile SSID aganst the SSID in the
3995*a1157835SDaniel Fojt 	 * OWE Transition Mode element. */
3996*a1157835SDaniel Fojt 
3997*a1157835SDaniel Fojt 	bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
3998*a1157835SDaniel Fojt 	if (!bss)
3999*a1157835SDaniel Fojt 		return 0;
4000*a1157835SDaniel Fojt 
4001*a1157835SDaniel Fojt 	owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE);
4002*a1157835SDaniel Fojt 	if (!owe)
4003*a1157835SDaniel Fojt 		return 0;
4004*a1157835SDaniel Fojt 
4005*a1157835SDaniel Fojt 	pos = owe + 6;
4006*a1157835SDaniel Fojt 	end = owe + 2 + owe[1];
4007*a1157835SDaniel Fojt 
4008*a1157835SDaniel Fojt 	if (end - pos < ETH_ALEN + 1)
4009*a1157835SDaniel Fojt 		return 0;
4010*a1157835SDaniel Fojt 	pos += ETH_ALEN;
4011*a1157835SDaniel Fojt 	ssid_len = *pos++;
4012*a1157835SDaniel Fojt 	if (end - pos < ssid_len || ssid_len > SSID_MAX_LEN)
4013*a1157835SDaniel Fojt 		return 0;
4014*a1157835SDaniel Fojt 
4015*a1157835SDaniel Fojt 	return entry_ssid_len == ssid_len &&
4016*a1157835SDaniel Fojt 		os_memcmp(pos, entry_ssid, ssid_len) == 0;
4017*a1157835SDaniel Fojt }
4018*a1157835SDaniel Fojt #endif /* CONFIG_OWE */
4019*a1157835SDaniel Fojt 
4020*a1157835SDaniel Fojt 
40216d49e1aeSJan Lentfer /**
40226d49e1aeSJan Lentfer  * wpa_supplicant_get_ssid - Get a pointer to the current network structure
40236d49e1aeSJan Lentfer  * @wpa_s: Pointer to wpa_supplicant data
40246d49e1aeSJan Lentfer  * Returns: A pointer to the current network structure or %NULL on failure
40256d49e1aeSJan Lentfer  */
wpa_supplicant_get_ssid(struct wpa_supplicant * wpa_s)40266d49e1aeSJan Lentfer struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
40276d49e1aeSJan Lentfer {
40286d49e1aeSJan Lentfer 	struct wpa_ssid *entry;
4029*a1157835SDaniel Fojt 	u8 ssid[SSID_MAX_LEN];
40306d49e1aeSJan Lentfer 	int res;
40316d49e1aeSJan Lentfer 	size_t ssid_len;
40326d49e1aeSJan Lentfer 	u8 bssid[ETH_ALEN];
40336d49e1aeSJan Lentfer 	int wired;
40346d49e1aeSJan Lentfer 
40356d49e1aeSJan Lentfer 	res = wpa_drv_get_ssid(wpa_s, ssid);
40366d49e1aeSJan Lentfer 	if (res < 0) {
40373ff40c12SJohn Marino 		wpa_msg(wpa_s, MSG_WARNING, "Could not read SSID from "
40383ff40c12SJohn Marino 			"driver");
40396d49e1aeSJan Lentfer 		return NULL;
40406d49e1aeSJan Lentfer 	}
40416d49e1aeSJan Lentfer 	ssid_len = res;
40426d49e1aeSJan Lentfer 
40433ff40c12SJohn Marino 	if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
40443ff40c12SJohn Marino 		wpa_msg(wpa_s, MSG_WARNING, "Could not read BSSID from "
40453ff40c12SJohn Marino 			"driver");
40466d49e1aeSJan Lentfer 		return NULL;
40476d49e1aeSJan Lentfer 	}
40486d49e1aeSJan Lentfer 
40493ff40c12SJohn Marino 	wired = wpa_s->conf->ap_scan == 0 &&
40503ff40c12SJohn Marino 		(wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED);
40516d49e1aeSJan Lentfer 
40526d49e1aeSJan Lentfer 	entry = wpa_s->conf->ssid;
40536d49e1aeSJan Lentfer 	while (entry) {
40543ff40c12SJohn Marino 		if (!wpas_network_disabled(wpa_s, entry) &&
40556d49e1aeSJan Lentfer 		    ((ssid_len == entry->ssid_len &&
4056*a1157835SDaniel Fojt 		      (!entry->ssid ||
4057*a1157835SDaniel Fojt 		       os_memcmp(ssid, entry->ssid, ssid_len) == 0)) ||
4058*a1157835SDaniel Fojt 		     wired) &&
40596d49e1aeSJan Lentfer 		    (!entry->bssid_set ||
40606d49e1aeSJan Lentfer 		     os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
40616d49e1aeSJan Lentfer 			return entry;
40626d49e1aeSJan Lentfer #ifdef CONFIG_WPS
40633ff40c12SJohn Marino 		if (!wpas_network_disabled(wpa_s, entry) &&
40646d49e1aeSJan Lentfer 		    (entry->key_mgmt & WPA_KEY_MGMT_WPS) &&
40656d49e1aeSJan Lentfer 		    (entry->ssid == NULL || entry->ssid_len == 0) &&
40666d49e1aeSJan Lentfer 		    (!entry->bssid_set ||
40676d49e1aeSJan Lentfer 		     os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
40686d49e1aeSJan Lentfer 			return entry;
40696d49e1aeSJan Lentfer #endif /* CONFIG_WPS */
40703ff40c12SJohn Marino 
4071*a1157835SDaniel Fojt #ifdef CONFIG_OWE
4072*a1157835SDaniel Fojt 		if (!wpas_network_disabled(wpa_s, entry) &&
4073*a1157835SDaniel Fojt 		    owe_trans_ssid_match(wpa_s, bssid, entry->ssid,
4074*a1157835SDaniel Fojt 		    entry->ssid_len) &&
4075*a1157835SDaniel Fojt 		    (!entry->bssid_set ||
4076*a1157835SDaniel Fojt 		     os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
4077*a1157835SDaniel Fojt 			return entry;
4078*a1157835SDaniel Fojt #endif /* CONFIG_OWE */
4079*a1157835SDaniel Fojt 
40803ff40c12SJohn Marino 		if (!wpas_network_disabled(wpa_s, entry) && entry->bssid_set &&
40813ff40c12SJohn Marino 		    entry->ssid_len == 0 &&
40823ff40c12SJohn Marino 		    os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)
40833ff40c12SJohn Marino 			return entry;
40843ff40c12SJohn Marino 
40856d49e1aeSJan Lentfer 		entry = entry->next;
40866d49e1aeSJan Lentfer 	}
40876d49e1aeSJan Lentfer 
40886d49e1aeSJan Lentfer 	return NULL;
40896d49e1aeSJan Lentfer }
40906d49e1aeSJan Lentfer 
40916d49e1aeSJan Lentfer 
select_driver(struct wpa_supplicant * wpa_s,int i)40923ff40c12SJohn Marino static int select_driver(struct wpa_supplicant *wpa_s, int i)
40933ff40c12SJohn Marino {
40943ff40c12SJohn Marino 	struct wpa_global *global = wpa_s->global;
40953ff40c12SJohn Marino 
40963ff40c12SJohn Marino 	if (wpa_drivers[i]->global_init && global->drv_priv[i] == NULL) {
4097*a1157835SDaniel Fojt 		global->drv_priv[i] = wpa_drivers[i]->global_init(global);
40983ff40c12SJohn Marino 		if (global->drv_priv[i] == NULL) {
40993ff40c12SJohn Marino 			wpa_printf(MSG_ERROR, "Failed to initialize driver "
41003ff40c12SJohn Marino 				   "'%s'", wpa_drivers[i]->name);
41013ff40c12SJohn Marino 			return -1;
41023ff40c12SJohn Marino 		}
41033ff40c12SJohn Marino 	}
41043ff40c12SJohn Marino 
41053ff40c12SJohn Marino 	wpa_s->driver = wpa_drivers[i];
41063ff40c12SJohn Marino 	wpa_s->global_drv_priv = global->drv_priv[i];
41073ff40c12SJohn Marino 
41083ff40c12SJohn Marino 	return 0;
41093ff40c12SJohn Marino }
41103ff40c12SJohn Marino 
41113ff40c12SJohn Marino 
wpa_supplicant_set_driver(struct wpa_supplicant * wpa_s,const char * name)41126d49e1aeSJan Lentfer static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
41136d49e1aeSJan Lentfer 				     const char *name)
41146d49e1aeSJan Lentfer {
41156d49e1aeSJan Lentfer 	int i;
41163ff40c12SJohn Marino 	size_t len;
41173ff40c12SJohn Marino 	const char *pos, *driver = name;
41186d49e1aeSJan Lentfer 
41196d49e1aeSJan Lentfer 	if (wpa_s == NULL)
41206d49e1aeSJan Lentfer 		return -1;
41216d49e1aeSJan Lentfer 
41223ff40c12SJohn Marino 	if (wpa_drivers[0] == NULL) {
41233ff40c12SJohn Marino 		wpa_msg(wpa_s, MSG_ERROR, "No driver interfaces build into "
41243ff40c12SJohn Marino 			"wpa_supplicant");
41256d49e1aeSJan Lentfer 		return -1;
41266d49e1aeSJan Lentfer 	}
41276d49e1aeSJan Lentfer 
41286d49e1aeSJan Lentfer 	if (name == NULL) {
41296d49e1aeSJan Lentfer 		/* default to first driver in the list */
41303ff40c12SJohn Marino 		return select_driver(wpa_s, 0);
41316d49e1aeSJan Lentfer 	}
41326d49e1aeSJan Lentfer 
41333ff40c12SJohn Marino 	do {
41343ff40c12SJohn Marino 		pos = os_strchr(driver, ',');
41353ff40c12SJohn Marino 		if (pos)
41363ff40c12SJohn Marino 			len = pos - driver;
41373ff40c12SJohn Marino 		else
41383ff40c12SJohn Marino 			len = os_strlen(driver);
41393ff40c12SJohn Marino 
41403ff40c12SJohn Marino 		for (i = 0; wpa_drivers[i]; i++) {
41413ff40c12SJohn Marino 			if (os_strlen(wpa_drivers[i]->name) == len &&
41423ff40c12SJohn Marino 			    os_strncmp(driver, wpa_drivers[i]->name, len) ==
41433ff40c12SJohn Marino 			    0) {
41443ff40c12SJohn Marino 				/* First driver that succeeds wins */
41453ff40c12SJohn Marino 				if (select_driver(wpa_s, i) == 0)
41466d49e1aeSJan Lentfer 					return 0;
41476d49e1aeSJan Lentfer 			}
41486d49e1aeSJan Lentfer 		}
41496d49e1aeSJan Lentfer 
41503ff40c12SJohn Marino 		driver = pos + 1;
41513ff40c12SJohn Marino 	} while (pos);
41523ff40c12SJohn Marino 
41533ff40c12SJohn Marino 	wpa_msg(wpa_s, MSG_ERROR, "Unsupported driver '%s'", name);
41546d49e1aeSJan Lentfer 	return -1;
41556d49e1aeSJan Lentfer }
41566d49e1aeSJan Lentfer 
41576d49e1aeSJan Lentfer 
41583ff40c12SJohn Marino /**
41593ff40c12SJohn Marino  * wpa_supplicant_rx_eapol - Deliver a received EAPOL frame to wpa_supplicant
41603ff40c12SJohn Marino  * @ctx: Context pointer (wpa_s); this is the ctx variable registered
41613ff40c12SJohn Marino  *	with struct wpa_driver_ops::init()
41623ff40c12SJohn Marino  * @src_addr: Source address of the EAPOL frame
41633ff40c12SJohn Marino  * @buf: EAPOL data starting from the EAPOL header (i.e., no Ethernet header)
41643ff40c12SJohn Marino  * @len: Length of the EAPOL data
41653ff40c12SJohn Marino  *
41663ff40c12SJohn Marino  * This function is called for each received EAPOL frame. Most driver
41673ff40c12SJohn Marino  * interfaces rely on more generic OS mechanism for receiving frames through
41683ff40c12SJohn Marino  * l2_packet, but if such a mechanism is not available, the driver wrapper may
41693ff40c12SJohn Marino  * take care of received EAPOL frames and deliver them to the core supplicant
41703ff40c12SJohn Marino  * code by calling this function.
41713ff40c12SJohn Marino  */
wpa_supplicant_rx_eapol(void * ctx,const u8 * src_addr,const u8 * buf,size_t len)41726d49e1aeSJan Lentfer void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
41736d49e1aeSJan Lentfer 			     const u8 *buf, size_t len)
41746d49e1aeSJan Lentfer {
41756d49e1aeSJan Lentfer 	struct wpa_supplicant *wpa_s = ctx;
41766d49e1aeSJan Lentfer 
41773ff40c12SJohn Marino 	wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
41786d49e1aeSJan Lentfer 	wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
41796d49e1aeSJan Lentfer 
4180*a1157835SDaniel Fojt #ifdef CONFIG_TESTING_OPTIONS
4181*a1157835SDaniel Fojt 	if (wpa_s->ignore_auth_resp) {
4182*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO, "RX EAPOL - ignore_auth_resp active!");
41833ff40c12SJohn Marino 		return;
41843ff40c12SJohn Marino 	}
4185*a1157835SDaniel Fojt #endif /* CONFIG_TESTING_OPTIONS */
41863ff40c12SJohn Marino 
41873ff40c12SJohn Marino 	if (wpa_s->wpa_state < WPA_ASSOCIATED ||
41883ff40c12SJohn Marino 	    (wpa_s->last_eapol_matches_bssid &&
41893ff40c12SJohn Marino #ifdef CONFIG_AP
41903ff40c12SJohn Marino 	     !wpa_s->ap_iface &&
41913ff40c12SJohn Marino #endif /* CONFIG_AP */
41923ff40c12SJohn Marino 	     os_memcmp(src_addr, wpa_s->bssid, ETH_ALEN) != 0)) {
41936d49e1aeSJan Lentfer 		/*
41946d49e1aeSJan Lentfer 		 * There is possible race condition between receiving the
41956d49e1aeSJan Lentfer 		 * association event and the EAPOL frame since they are coming
41966d49e1aeSJan Lentfer 		 * through different paths from the driver. In order to avoid
41976d49e1aeSJan Lentfer 		 * issues in trying to process the EAPOL frame before receiving
41986d49e1aeSJan Lentfer 		 * association information, lets queue it for processing until
41993ff40c12SJohn Marino 		 * the association event is received. This may also be needed in
42003ff40c12SJohn Marino 		 * driver-based roaming case, so also use src_addr != BSSID as a
42013ff40c12SJohn Marino 		 * trigger if we have previously confirmed that the
42023ff40c12SJohn Marino 		 * Authenticator uses BSSID as the src_addr (which is not the
42033ff40c12SJohn Marino 		 * case with wired IEEE 802.1X).
42046d49e1aeSJan Lentfer 		 */
42053ff40c12SJohn Marino 		wpa_dbg(wpa_s, MSG_DEBUG, "Not associated - Delay processing "
42063ff40c12SJohn Marino 			"of received EAPOL frame (state=%s bssid=" MACSTR ")",
42073ff40c12SJohn Marino 			wpa_supplicant_state_txt(wpa_s->wpa_state),
42083ff40c12SJohn Marino 			MAC2STR(wpa_s->bssid));
42096d49e1aeSJan Lentfer 		wpabuf_free(wpa_s->pending_eapol_rx);
42106d49e1aeSJan Lentfer 		wpa_s->pending_eapol_rx = wpabuf_alloc_copy(buf, len);
42116d49e1aeSJan Lentfer 		if (wpa_s->pending_eapol_rx) {
42123ff40c12SJohn Marino 			os_get_reltime(&wpa_s->pending_eapol_rx_time);
42136d49e1aeSJan Lentfer 			os_memcpy(wpa_s->pending_eapol_rx_src, src_addr,
42146d49e1aeSJan Lentfer 				  ETH_ALEN);
42156d49e1aeSJan Lentfer 		}
42166d49e1aeSJan Lentfer 		return;
42176d49e1aeSJan Lentfer 	}
42186d49e1aeSJan Lentfer 
42193ff40c12SJohn Marino 	wpa_s->last_eapol_matches_bssid =
42203ff40c12SJohn Marino 		os_memcmp(src_addr, wpa_s->bssid, ETH_ALEN) == 0;
42213ff40c12SJohn Marino 
42223ff40c12SJohn Marino #ifdef CONFIG_AP
42233ff40c12SJohn Marino 	if (wpa_s->ap_iface) {
42243ff40c12SJohn Marino 		wpa_supplicant_ap_rx_eapol(wpa_s, src_addr, buf, len);
42253ff40c12SJohn Marino 		return;
42263ff40c12SJohn Marino 	}
42273ff40c12SJohn Marino #endif /* CONFIG_AP */
42283ff40c12SJohn Marino 
42296d49e1aeSJan Lentfer 	if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
42303ff40c12SJohn Marino 		wpa_dbg(wpa_s, MSG_DEBUG, "Ignored received EAPOL frame since "
42316d49e1aeSJan Lentfer 			"no key management is configured");
42326d49e1aeSJan Lentfer 		return;
42336d49e1aeSJan Lentfer 	}
42346d49e1aeSJan Lentfer 
42356d49e1aeSJan Lentfer 	if (wpa_s->eapol_received == 0 &&
4236*a1157835SDaniel Fojt 	    (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) ||
42376d49e1aeSJan Lentfer 	     !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
42383ff40c12SJohn Marino 	     wpa_s->wpa_state != WPA_COMPLETED) &&
42393ff40c12SJohn Marino 	    (wpa_s->current_ssid == NULL ||
4240*a1157835SDaniel Fojt 	     wpa_s->current_ssid->mode != WPAS_MODE_IBSS)) {
42416d49e1aeSJan Lentfer 		/* Timeout for completing IEEE 802.1X and WPA authentication */
4242*a1157835SDaniel Fojt 		int timeout = 10;
4243*a1157835SDaniel Fojt 
4244*a1157835SDaniel Fojt 		if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
42456d49e1aeSJan Lentfer 		    wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA ||
4246*a1157835SDaniel Fojt 		    wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
4247*a1157835SDaniel Fojt 			/* Use longer timeout for IEEE 802.1X/EAP */
4248*a1157835SDaniel Fojt 			timeout = 70;
4249*a1157835SDaniel Fojt 		}
4250*a1157835SDaniel Fojt 
4251*a1157835SDaniel Fojt #ifdef CONFIG_WPS
4252*a1157835SDaniel Fojt 		if (wpa_s->current_ssid && wpa_s->current_bss &&
4253*a1157835SDaniel Fojt 		    (wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
4254*a1157835SDaniel Fojt 		    eap_is_wps_pin_enrollee(&wpa_s->current_ssid->eap)) {
4255*a1157835SDaniel Fojt 			/*
4256*a1157835SDaniel Fojt 			 * Use shorter timeout if going through WPS AP iteration
4257*a1157835SDaniel Fojt 			 * for PIN config method with an AP that does not
4258*a1157835SDaniel Fojt 			 * advertise Selected Registrar.
4259*a1157835SDaniel Fojt 			 */
4260*a1157835SDaniel Fojt 			struct wpabuf *wps_ie;
4261*a1157835SDaniel Fojt 
4262*a1157835SDaniel Fojt 			wps_ie = wpa_bss_get_vendor_ie_multi(
4263*a1157835SDaniel Fojt 				wpa_s->current_bss, WPS_IE_VENDOR_TYPE);
4264*a1157835SDaniel Fojt 			if (wps_ie &&
4265*a1157835SDaniel Fojt 			    !wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1))
4266*a1157835SDaniel Fojt 				timeout = 10;
4267*a1157835SDaniel Fojt 			wpabuf_free(wps_ie);
4268*a1157835SDaniel Fojt 		}
4269*a1157835SDaniel Fojt #endif /* CONFIG_WPS */
4270*a1157835SDaniel Fojt 
4271*a1157835SDaniel Fojt 		wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
42726d49e1aeSJan Lentfer 	}
42736d49e1aeSJan Lentfer 	wpa_s->eapol_received++;
42746d49e1aeSJan Lentfer 
42756d49e1aeSJan Lentfer 	if (wpa_s->countermeasures) {
42763ff40c12SJohn Marino 		wpa_msg(wpa_s, MSG_INFO, "WPA: Countermeasures - dropped "
42773ff40c12SJohn Marino 			"EAPOL packet");
42786d49e1aeSJan Lentfer 		return;
42796d49e1aeSJan Lentfer 	}
42806d49e1aeSJan Lentfer 
42813ff40c12SJohn Marino #ifdef CONFIG_IBSS_RSN
42823ff40c12SJohn Marino 	if (wpa_s->current_ssid &&
42833ff40c12SJohn Marino 	    wpa_s->current_ssid->mode == WPAS_MODE_IBSS) {
42843ff40c12SJohn Marino 		ibss_rsn_rx_eapol(wpa_s->ibss_rsn, src_addr, buf, len);
42853ff40c12SJohn Marino 		return;
42863ff40c12SJohn Marino 	}
42873ff40c12SJohn Marino #endif /* CONFIG_IBSS_RSN */
42883ff40c12SJohn Marino 
42896d49e1aeSJan Lentfer 	/* Source address of the incoming EAPOL frame could be compared to the
42906d49e1aeSJan Lentfer 	 * current BSSID. However, it is possible that a centralized
42916d49e1aeSJan Lentfer 	 * Authenticator could be using another MAC address than the BSSID of
42926d49e1aeSJan Lentfer 	 * an AP, so just allow any address to be used for now. The replies are
42936d49e1aeSJan Lentfer 	 * still sent to the current BSSID (if available), though. */
42946d49e1aeSJan Lentfer 
42956d49e1aeSJan Lentfer 	os_memcpy(wpa_s->last_eapol_src, src_addr, ETH_ALEN);
42966d49e1aeSJan Lentfer 	if (!wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) &&
4297*a1157835SDaniel Fojt 	    wpa_s->key_mgmt != WPA_KEY_MGMT_OWE &&
4298*a1157835SDaniel Fojt 	    wpa_s->key_mgmt != WPA_KEY_MGMT_DPP &&
42996d49e1aeSJan Lentfer 	    eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0)
43006d49e1aeSJan Lentfer 		return;
43016d49e1aeSJan Lentfer 	wpa_drv_poll(wpa_s);
4302*a1157835SDaniel Fojt 	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK))
43036d49e1aeSJan Lentfer 		wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
43046d49e1aeSJan Lentfer 	else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
43056d49e1aeSJan Lentfer 		/*
43066d49e1aeSJan Lentfer 		 * Set portValid = TRUE here since we are going to skip 4-way
43076d49e1aeSJan Lentfer 		 * handshake processing which would normally set portValid. We
43086d49e1aeSJan Lentfer 		 * need this to allow the EAPOL state machines to be completed
43096d49e1aeSJan Lentfer 		 * without going through EAPOL-Key handshake.
43106d49e1aeSJan Lentfer 		 */
43116d49e1aeSJan Lentfer 		eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
43126d49e1aeSJan Lentfer 	}
43136d49e1aeSJan Lentfer }
43146d49e1aeSJan Lentfer 
43156d49e1aeSJan Lentfer 
wpa_supplicant_update_mac_addr(struct wpa_supplicant * wpa_s)43163ff40c12SJohn Marino int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
43176d49e1aeSJan Lentfer {
4318*a1157835SDaniel Fojt 	if ((!wpa_s->p2p_mgmt ||
4319*a1157835SDaniel Fojt 	     !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) &&
4320*a1157835SDaniel Fojt 	    !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)) {
43213ff40c12SJohn Marino 		l2_packet_deinit(wpa_s->l2);
43223ff40c12SJohn Marino 		wpa_s->l2 = l2_packet_init(wpa_s->ifname,
43233ff40c12SJohn Marino 					   wpa_drv_get_mac_addr(wpa_s),
43243ff40c12SJohn Marino 					   ETH_P_EAPOL,
43253ff40c12SJohn Marino 					   wpa_supplicant_rx_eapol, wpa_s, 0);
43263ff40c12SJohn Marino 		if (wpa_s->l2 == NULL)
43273ff40c12SJohn Marino 			return -1;
4328*a1157835SDaniel Fojt 
4329*a1157835SDaniel Fojt 		if (l2_packet_set_packet_filter(wpa_s->l2,
4330*a1157835SDaniel Fojt 						L2_PACKET_FILTER_PKTTYPE))
4331*a1157835SDaniel Fojt 			wpa_dbg(wpa_s, MSG_DEBUG,
4332*a1157835SDaniel Fojt 				"Failed to attach pkt_type filter");
43333ff40c12SJohn Marino 	} else {
43343ff40c12SJohn Marino 		const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
43353ff40c12SJohn Marino 		if (addr)
43363ff40c12SJohn Marino 			os_memcpy(wpa_s->own_addr, addr, ETH_ALEN);
43373ff40c12SJohn Marino 	}
43383ff40c12SJohn Marino 
43393ff40c12SJohn Marino 	if (wpa_s->l2 && l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) {
43403ff40c12SJohn Marino 		wpa_msg(wpa_s, MSG_ERROR, "Failed to get own L2 address");
43413ff40c12SJohn Marino 		return -1;
43423ff40c12SJohn Marino 	}
43433ff40c12SJohn Marino 
4344*a1157835SDaniel Fojt 	wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
4345*a1157835SDaniel Fojt 
43463ff40c12SJohn Marino 	return 0;
43476d49e1aeSJan Lentfer }
43486d49e1aeSJan Lentfer 
43496d49e1aeSJan Lentfer 
wpa_supplicant_rx_eapol_bridge(void * ctx,const u8 * src_addr,const u8 * buf,size_t len)43503ff40c12SJohn Marino static void wpa_supplicant_rx_eapol_bridge(void *ctx, const u8 *src_addr,
43513ff40c12SJohn Marino 					   const u8 *buf, size_t len)
43526d49e1aeSJan Lentfer {
43536d49e1aeSJan Lentfer 	struct wpa_supplicant *wpa_s = ctx;
43543ff40c12SJohn Marino 	const struct l2_ethhdr *eth;
43553ff40c12SJohn Marino 
43563ff40c12SJohn Marino 	if (len < sizeof(*eth))
43573ff40c12SJohn Marino 		return;
43583ff40c12SJohn Marino 	eth = (const struct l2_ethhdr *) buf;
43593ff40c12SJohn Marino 
43603ff40c12SJohn Marino 	if (os_memcmp(eth->h_dest, wpa_s->own_addr, ETH_ALEN) != 0 &&
43613ff40c12SJohn Marino 	    !(eth->h_dest[0] & 0x01)) {
43623ff40c12SJohn Marino 		wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " to " MACSTR
43633ff40c12SJohn Marino 			" (bridge - not for this interface - ignore)",
43643ff40c12SJohn Marino 			MAC2STR(src_addr), MAC2STR(eth->h_dest));
43653ff40c12SJohn Marino 		return;
43663ff40c12SJohn Marino 	}
43673ff40c12SJohn Marino 
43683ff40c12SJohn Marino 	wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " to " MACSTR
43693ff40c12SJohn Marino 		" (bridge)", MAC2STR(src_addr), MAC2STR(eth->h_dest));
43703ff40c12SJohn Marino 	wpa_supplicant_rx_eapol(wpa_s, src_addr, buf + sizeof(*eth),
43713ff40c12SJohn Marino 				len - sizeof(*eth));
43726d49e1aeSJan Lentfer }
43736d49e1aeSJan Lentfer 
43746d49e1aeSJan Lentfer 
43756d49e1aeSJan Lentfer /**
43766d49e1aeSJan Lentfer  * wpa_supplicant_driver_init - Initialize driver interface parameters
43776d49e1aeSJan Lentfer  * @wpa_s: Pointer to wpa_supplicant data
43786d49e1aeSJan Lentfer  * Returns: 0 on success, -1 on failure
43796d49e1aeSJan Lentfer  *
43806d49e1aeSJan Lentfer  * This function is called to initialize driver interface parameters.
43816d49e1aeSJan Lentfer  * wpa_drv_init() must have been called before this function to initialize the
43826d49e1aeSJan Lentfer  * driver interface.
43836d49e1aeSJan Lentfer  */
wpa_supplicant_driver_init(struct wpa_supplicant * wpa_s)43846d49e1aeSJan Lentfer int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
43856d49e1aeSJan Lentfer {
43866d49e1aeSJan Lentfer 	static int interface_count = 0;
43876d49e1aeSJan Lentfer 
43883ff40c12SJohn Marino 	if (wpa_supplicant_update_mac_addr(wpa_s) < 0)
43896d49e1aeSJan Lentfer 		return -1;
43906d49e1aeSJan Lentfer 
43913ff40c12SJohn Marino 	wpa_dbg(wpa_s, MSG_DEBUG, "Own MAC address: " MACSTR,
43926d49e1aeSJan Lentfer 		MAC2STR(wpa_s->own_addr));
4393*a1157835SDaniel Fojt 	os_memcpy(wpa_s->perm_addr, wpa_s->own_addr, ETH_ALEN);
43943ff40c12SJohn Marino 	wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
43956d49e1aeSJan Lentfer 
43966d49e1aeSJan Lentfer 	if (wpa_s->bridge_ifname[0]) {
43973ff40c12SJohn Marino 		wpa_dbg(wpa_s, MSG_DEBUG, "Receiving packets from bridge "
43983ff40c12SJohn Marino 			"interface '%s'", wpa_s->bridge_ifname);
4399*a1157835SDaniel Fojt 		wpa_s->l2_br = l2_packet_init_bridge(
4400*a1157835SDaniel Fojt 			wpa_s->bridge_ifname, wpa_s->ifname, wpa_s->own_addr,
4401*a1157835SDaniel Fojt 			ETH_P_EAPOL, wpa_supplicant_rx_eapol_bridge, wpa_s, 1);
44026d49e1aeSJan Lentfer 		if (wpa_s->l2_br == NULL) {
44033ff40c12SJohn Marino 			wpa_msg(wpa_s, MSG_ERROR, "Failed to open l2_packet "
44046d49e1aeSJan Lentfer 				"connection for the bridge interface '%s'",
44056d49e1aeSJan Lentfer 				wpa_s->bridge_ifname);
44066d49e1aeSJan Lentfer 			return -1;
44076d49e1aeSJan Lentfer 		}
44086d49e1aeSJan Lentfer 	}
44096d49e1aeSJan Lentfer 
4410*a1157835SDaniel Fojt 	if (wpa_s->conf->ap_scan == 2 &&
4411*a1157835SDaniel Fojt 	    os_strcmp(wpa_s->driver->name, "nl80211") == 0) {
4412*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
4413*a1157835SDaniel Fojt 			   "Note: nl80211 driver interface is not designed to be used with ap_scan=2; this can result in connection failures");
4414*a1157835SDaniel Fojt 	}
4415*a1157835SDaniel Fojt 
44166d49e1aeSJan Lentfer 	wpa_clear_keys(wpa_s, NULL);
44176d49e1aeSJan Lentfer 
44186d49e1aeSJan Lentfer 	/* Make sure that TKIP countermeasures are not left enabled (could
44196d49e1aeSJan Lentfer 	 * happen if wpa_supplicant is killed during countermeasures. */
44206d49e1aeSJan Lentfer 	wpa_drv_set_countermeasures(wpa_s, 0);
44216d49e1aeSJan Lentfer 
44223ff40c12SJohn Marino 	wpa_dbg(wpa_s, MSG_DEBUG, "RSN: flushing PMKID list in the driver");
44236d49e1aeSJan Lentfer 	wpa_drv_flush_pmkid(wpa_s);
44246d49e1aeSJan Lentfer 
44253ff40c12SJohn Marino 	wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
44263ff40c12SJohn Marino 	wpa_s->prev_scan_wildcard = 0;
44273ff40c12SJohn Marino 
44283ff40c12SJohn Marino 	if (wpa_supplicant_enabled_networks(wpa_s)) {
44293ff40c12SJohn Marino 		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
44303ff40c12SJohn Marino 			wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
44313ff40c12SJohn Marino 			interface_count = 0;
44323ff40c12SJohn Marino 		}
4433*a1157835SDaniel Fojt #ifndef ANDROID
4434*a1157835SDaniel Fojt 		if (!wpa_s->p2p_mgmt &&
4435*a1157835SDaniel Fojt 		    wpa_supplicant_delayed_sched_scan(wpa_s,
4436*a1157835SDaniel Fojt 						      interface_count % 3,
44373ff40c12SJohn Marino 						      100000))
4438*a1157835SDaniel Fojt 			wpa_supplicant_req_scan(wpa_s, interface_count % 3,
44393ff40c12SJohn Marino 						100000);
4440*a1157835SDaniel Fojt #endif /* ANDROID */
44416d49e1aeSJan Lentfer 		interface_count++;
44423ff40c12SJohn Marino 	} else
44433ff40c12SJohn Marino 		wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
44446d49e1aeSJan Lentfer 
44456d49e1aeSJan Lentfer 	return 0;
44466d49e1aeSJan Lentfer }
44476d49e1aeSJan Lentfer 
44486d49e1aeSJan Lentfer 
wpa_supplicant_daemon(const char * pid_file)44496d49e1aeSJan Lentfer static int wpa_supplicant_daemon(const char *pid_file)
44506d49e1aeSJan Lentfer {
44516d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "Daemonize..");
44526d49e1aeSJan Lentfer 	return os_daemonize(pid_file);
44536d49e1aeSJan Lentfer }
44546d49e1aeSJan Lentfer 
44556d49e1aeSJan Lentfer 
4456*a1157835SDaniel Fojt static struct wpa_supplicant *
wpa_supplicant_alloc(struct wpa_supplicant * parent)4457*a1157835SDaniel Fojt wpa_supplicant_alloc(struct wpa_supplicant *parent)
44586d49e1aeSJan Lentfer {
44596d49e1aeSJan Lentfer 	struct wpa_supplicant *wpa_s;
44606d49e1aeSJan Lentfer 
44616d49e1aeSJan Lentfer 	wpa_s = os_zalloc(sizeof(*wpa_s));
44626d49e1aeSJan Lentfer 	if (wpa_s == NULL)
44636d49e1aeSJan Lentfer 		return NULL;
44643ff40c12SJohn Marino 	wpa_s->scan_req = INITIAL_SCAN_REQ;
44653ff40c12SJohn Marino 	wpa_s->scan_interval = 5;
44663ff40c12SJohn Marino 	wpa_s->new_connection = 1;
4467*a1157835SDaniel Fojt 	wpa_s->parent = parent ? parent : wpa_s;
4468*a1157835SDaniel Fojt 	wpa_s->p2pdev = wpa_s->parent;
44693ff40c12SJohn Marino 	wpa_s->sched_scanning = 0;
44706d49e1aeSJan Lentfer 
4471*a1157835SDaniel Fojt 	dl_list_init(&wpa_s->bss_tmp_disallowed);
4472*a1157835SDaniel Fojt 	dl_list_init(&wpa_s->fils_hlp_req);
4473*a1157835SDaniel Fojt 
44746d49e1aeSJan Lentfer 	return wpa_s;
44756d49e1aeSJan Lentfer }
44766d49e1aeSJan Lentfer 
44776d49e1aeSJan Lentfer 
44783ff40c12SJohn Marino #ifdef CONFIG_HT_OVERRIDES
44793ff40c12SJohn Marino 
wpa_set_htcap_mcs(struct wpa_supplicant * wpa_s,struct ieee80211_ht_capabilities * htcaps,struct ieee80211_ht_capabilities * htcaps_mask,const char * ht_mcs)44803ff40c12SJohn Marino static int wpa_set_htcap_mcs(struct wpa_supplicant *wpa_s,
44813ff40c12SJohn Marino 			     struct ieee80211_ht_capabilities *htcaps,
44823ff40c12SJohn Marino 			     struct ieee80211_ht_capabilities *htcaps_mask,
44833ff40c12SJohn Marino 			     const char *ht_mcs)
44843ff40c12SJohn Marino {
44853ff40c12SJohn Marino 	/* parse ht_mcs into hex array */
44863ff40c12SJohn Marino 	int i;
44873ff40c12SJohn Marino 	const char *tmp = ht_mcs;
44883ff40c12SJohn Marino 	char *end = NULL;
44893ff40c12SJohn Marino 
44903ff40c12SJohn Marino 	/* If ht_mcs is null, do not set anything */
44913ff40c12SJohn Marino 	if (!ht_mcs)
44923ff40c12SJohn Marino 		return 0;
44933ff40c12SJohn Marino 
44943ff40c12SJohn Marino 	/* This is what we are setting in the kernel */
44953ff40c12SJohn Marino 	os_memset(&htcaps->supported_mcs_set, 0, IEEE80211_HT_MCS_MASK_LEN);
44963ff40c12SJohn Marino 
44973ff40c12SJohn Marino 	wpa_msg(wpa_s, MSG_DEBUG, "set_htcap, ht_mcs -:%s:-", ht_mcs);
44983ff40c12SJohn Marino 
44993ff40c12SJohn Marino 	for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
4500*a1157835SDaniel Fojt 		long v;
4501*a1157835SDaniel Fojt 
45023ff40c12SJohn Marino 		errno = 0;
4503*a1157835SDaniel Fojt 		v = strtol(tmp, &end, 16);
4504*a1157835SDaniel Fojt 
45053ff40c12SJohn Marino 		if (errno == 0) {
45063ff40c12SJohn Marino 			wpa_msg(wpa_s, MSG_DEBUG,
45073ff40c12SJohn Marino 				"htcap value[%i]: %ld end: %p  tmp: %p",
45083ff40c12SJohn Marino 				i, v, end, tmp);
45093ff40c12SJohn Marino 			if (end == tmp)
45103ff40c12SJohn Marino 				break;
45113ff40c12SJohn Marino 
45123ff40c12SJohn Marino 			htcaps->supported_mcs_set[i] = v;
45133ff40c12SJohn Marino 			tmp = end;
45143ff40c12SJohn Marino 		} else {
45153ff40c12SJohn Marino 			wpa_msg(wpa_s, MSG_ERROR,
45163ff40c12SJohn Marino 				"Failed to parse ht-mcs: %s, error: %s\n",
45173ff40c12SJohn Marino 				ht_mcs, strerror(errno));
45183ff40c12SJohn Marino 			return -1;
45193ff40c12SJohn Marino 		}
45203ff40c12SJohn Marino 	}
45213ff40c12SJohn Marino 
45223ff40c12SJohn Marino 	/*
45233ff40c12SJohn Marino 	 * If we were able to parse any values, then set mask for the MCS set.
45243ff40c12SJohn Marino 	 */
45253ff40c12SJohn Marino 	if (i) {
45263ff40c12SJohn Marino 		os_memset(&htcaps_mask->supported_mcs_set, 0xff,
45273ff40c12SJohn Marino 			  IEEE80211_HT_MCS_MASK_LEN - 1);
45283ff40c12SJohn Marino 		/* skip the 3 reserved bits */
45293ff40c12SJohn Marino 		htcaps_mask->supported_mcs_set[IEEE80211_HT_MCS_MASK_LEN - 1] =
45303ff40c12SJohn Marino 			0x1f;
45313ff40c12SJohn Marino 	}
45323ff40c12SJohn Marino 
45333ff40c12SJohn Marino 	return 0;
45343ff40c12SJohn Marino }
45353ff40c12SJohn Marino 
45363ff40c12SJohn Marino 
wpa_disable_max_amsdu(struct wpa_supplicant * wpa_s,struct ieee80211_ht_capabilities * htcaps,struct ieee80211_ht_capabilities * htcaps_mask,int disabled)45373ff40c12SJohn Marino static int wpa_disable_max_amsdu(struct wpa_supplicant *wpa_s,
45383ff40c12SJohn Marino 				 struct ieee80211_ht_capabilities *htcaps,
45393ff40c12SJohn Marino 				 struct ieee80211_ht_capabilities *htcaps_mask,
45403ff40c12SJohn Marino 				 int disabled)
45413ff40c12SJohn Marino {
4542*a1157835SDaniel Fojt 	le16 msk;
45433ff40c12SJohn Marino 
45443ff40c12SJohn Marino 	if (disabled == -1)
45453ff40c12SJohn Marino 		return 0;
45463ff40c12SJohn Marino 
4547*a1157835SDaniel Fojt 	wpa_msg(wpa_s, MSG_DEBUG, "set_disable_max_amsdu: %d", disabled);
4548*a1157835SDaniel Fojt 
45493ff40c12SJohn Marino 	msk = host_to_le16(HT_CAP_INFO_MAX_AMSDU_SIZE);
45503ff40c12SJohn Marino 	htcaps_mask->ht_capabilities_info |= msk;
45513ff40c12SJohn Marino 	if (disabled)
45523ff40c12SJohn Marino 		htcaps->ht_capabilities_info &= msk;
45533ff40c12SJohn Marino 	else
45543ff40c12SJohn Marino 		htcaps->ht_capabilities_info |= msk;
45553ff40c12SJohn Marino 
45563ff40c12SJohn Marino 	return 0;
45573ff40c12SJohn Marino }
45583ff40c12SJohn Marino 
45593ff40c12SJohn Marino 
wpa_set_ampdu_factor(struct wpa_supplicant * wpa_s,struct ieee80211_ht_capabilities * htcaps,struct ieee80211_ht_capabilities * htcaps_mask,int factor)45603ff40c12SJohn Marino static int wpa_set_ampdu_factor(struct wpa_supplicant *wpa_s,
45613ff40c12SJohn Marino 				struct ieee80211_ht_capabilities *htcaps,
45623ff40c12SJohn Marino 				struct ieee80211_ht_capabilities *htcaps_mask,
45633ff40c12SJohn Marino 				int factor)
45643ff40c12SJohn Marino {
45653ff40c12SJohn Marino 	if (factor == -1)
45663ff40c12SJohn Marino 		return 0;
45673ff40c12SJohn Marino 
4568*a1157835SDaniel Fojt 	wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_factor: %d", factor);
4569*a1157835SDaniel Fojt 
45703ff40c12SJohn Marino 	if (factor < 0 || factor > 3) {
45713ff40c12SJohn Marino 		wpa_msg(wpa_s, MSG_ERROR, "ampdu_factor: %d out of range. "
45723ff40c12SJohn Marino 			"Must be 0-3 or -1", factor);
45733ff40c12SJohn Marino 		return -EINVAL;
45743ff40c12SJohn Marino 	}
45753ff40c12SJohn Marino 
45763ff40c12SJohn Marino 	htcaps_mask->a_mpdu_params |= 0x3; /* 2 bits for factor */
45773ff40c12SJohn Marino 	htcaps->a_mpdu_params &= ~0x3;
45783ff40c12SJohn Marino 	htcaps->a_mpdu_params |= factor & 0x3;
45793ff40c12SJohn Marino 
45803ff40c12SJohn Marino 	return 0;
45813ff40c12SJohn Marino }
45823ff40c12SJohn Marino 
45833ff40c12SJohn Marino 
wpa_set_ampdu_density(struct wpa_supplicant * wpa_s,struct ieee80211_ht_capabilities * htcaps,struct ieee80211_ht_capabilities * htcaps_mask,int density)45843ff40c12SJohn Marino static int wpa_set_ampdu_density(struct wpa_supplicant *wpa_s,
45853ff40c12SJohn Marino 				 struct ieee80211_ht_capabilities *htcaps,
45863ff40c12SJohn Marino 				 struct ieee80211_ht_capabilities *htcaps_mask,
45873ff40c12SJohn Marino 				 int density)
45883ff40c12SJohn Marino {
45893ff40c12SJohn Marino 	if (density == -1)
45903ff40c12SJohn Marino 		return 0;
45913ff40c12SJohn Marino 
4592*a1157835SDaniel Fojt 	wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_density: %d", density);
4593*a1157835SDaniel Fojt 
45943ff40c12SJohn Marino 	if (density < 0 || density > 7) {
45953ff40c12SJohn Marino 		wpa_msg(wpa_s, MSG_ERROR,
45963ff40c12SJohn Marino 			"ampdu_density: %d out of range. Must be 0-7 or -1.",
45973ff40c12SJohn Marino 			density);
45983ff40c12SJohn Marino 		return -EINVAL;
45993ff40c12SJohn Marino 	}
46003ff40c12SJohn Marino 
46013ff40c12SJohn Marino 	htcaps_mask->a_mpdu_params |= 0x1C;
46023ff40c12SJohn Marino 	htcaps->a_mpdu_params &= ~(0x1C);
46033ff40c12SJohn Marino 	htcaps->a_mpdu_params |= (density << 2) & 0x1C;
46043ff40c12SJohn Marino 
46053ff40c12SJohn Marino 	return 0;
46063ff40c12SJohn Marino }
46073ff40c12SJohn Marino 
46083ff40c12SJohn Marino 
wpa_set_disable_ht40(struct wpa_supplicant * wpa_s,struct ieee80211_ht_capabilities * htcaps,struct ieee80211_ht_capabilities * htcaps_mask,int disabled)46093ff40c12SJohn Marino static int wpa_set_disable_ht40(struct wpa_supplicant *wpa_s,
46103ff40c12SJohn Marino 				struct ieee80211_ht_capabilities *htcaps,
46113ff40c12SJohn Marino 				struct ieee80211_ht_capabilities *htcaps_mask,
46123ff40c12SJohn Marino 				int disabled)
46133ff40c12SJohn Marino {
4614*a1157835SDaniel Fojt 	if (disabled)
4615*a1157835SDaniel Fojt 		wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ht40: %d", disabled);
4616*a1157835SDaniel Fojt 
4617*a1157835SDaniel Fojt 	set_disable_ht40(htcaps, disabled);
4618*a1157835SDaniel Fojt 	set_disable_ht40(htcaps_mask, 0);
4619*a1157835SDaniel Fojt 
4620*a1157835SDaniel Fojt 	return 0;
4621*a1157835SDaniel Fojt }
4622*a1157835SDaniel Fojt 
4623*a1157835SDaniel Fojt 
wpa_set_disable_sgi(struct wpa_supplicant * wpa_s,struct ieee80211_ht_capabilities * htcaps,struct ieee80211_ht_capabilities * htcaps_mask,int disabled)4624*a1157835SDaniel Fojt static int wpa_set_disable_sgi(struct wpa_supplicant *wpa_s,
4625*a1157835SDaniel Fojt 			       struct ieee80211_ht_capabilities *htcaps,
4626*a1157835SDaniel Fojt 			       struct ieee80211_ht_capabilities *htcaps_mask,
4627*a1157835SDaniel Fojt 			       int disabled)
4628*a1157835SDaniel Fojt {
4629*a1157835SDaniel Fojt 	/* Masking these out disables SGI */
4630*a1157835SDaniel Fojt 	le16 msk = host_to_le16(HT_CAP_INFO_SHORT_GI20MHZ |
46313ff40c12SJohn Marino 				HT_CAP_INFO_SHORT_GI40MHZ);
46323ff40c12SJohn Marino 
4633*a1157835SDaniel Fojt 	if (disabled)
4634*a1157835SDaniel Fojt 		wpa_msg(wpa_s, MSG_DEBUG, "set_disable_sgi: %d", disabled);
46353ff40c12SJohn Marino 
46363ff40c12SJohn Marino 	if (disabled)
46373ff40c12SJohn Marino 		htcaps->ht_capabilities_info &= ~msk;
46383ff40c12SJohn Marino 	else
46393ff40c12SJohn Marino 		htcaps->ht_capabilities_info |= msk;
46403ff40c12SJohn Marino 
46413ff40c12SJohn Marino 	htcaps_mask->ht_capabilities_info |= msk;
46423ff40c12SJohn Marino 
46433ff40c12SJohn Marino 	return 0;
46443ff40c12SJohn Marino }
46453ff40c12SJohn Marino 
46463ff40c12SJohn Marino 
wpa_set_disable_ldpc(struct wpa_supplicant * wpa_s,struct ieee80211_ht_capabilities * htcaps,struct ieee80211_ht_capabilities * htcaps_mask,int disabled)4647*a1157835SDaniel Fojt static int wpa_set_disable_ldpc(struct wpa_supplicant *wpa_s,
46483ff40c12SJohn Marino 			       struct ieee80211_ht_capabilities *htcaps,
46493ff40c12SJohn Marino 			       struct ieee80211_ht_capabilities *htcaps_mask,
46503ff40c12SJohn Marino 			       int disabled)
46513ff40c12SJohn Marino {
4652*a1157835SDaniel Fojt 	/* Masking these out disables LDPC */
4653*a1157835SDaniel Fojt 	le16 msk = host_to_le16(HT_CAP_INFO_LDPC_CODING_CAP);
46543ff40c12SJohn Marino 
4655*a1157835SDaniel Fojt 	if (disabled)
4656*a1157835SDaniel Fojt 		wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ldpc: %d", disabled);
46573ff40c12SJohn Marino 
46583ff40c12SJohn Marino 	if (disabled)
46593ff40c12SJohn Marino 		htcaps->ht_capabilities_info &= ~msk;
46603ff40c12SJohn Marino 	else
46613ff40c12SJohn Marino 		htcaps->ht_capabilities_info |= msk;
46623ff40c12SJohn Marino 
46633ff40c12SJohn Marino 	htcaps_mask->ht_capabilities_info |= msk;
46643ff40c12SJohn Marino 
46653ff40c12SJohn Marino 	return 0;
46663ff40c12SJohn Marino }
46673ff40c12SJohn Marino 
46683ff40c12SJohn Marino 
wpa_set_tx_stbc(struct wpa_supplicant * wpa_s,struct ieee80211_ht_capabilities * htcaps,struct ieee80211_ht_capabilities * htcaps_mask,int tx_stbc)4669*a1157835SDaniel Fojt static int wpa_set_tx_stbc(struct wpa_supplicant *wpa_s,
4670*a1157835SDaniel Fojt 			   struct ieee80211_ht_capabilities *htcaps,
4671*a1157835SDaniel Fojt 			   struct ieee80211_ht_capabilities *htcaps_mask,
4672*a1157835SDaniel Fojt 			   int tx_stbc)
4673*a1157835SDaniel Fojt {
4674*a1157835SDaniel Fojt 	le16 msk = host_to_le16(HT_CAP_INFO_TX_STBC);
4675*a1157835SDaniel Fojt 
4676*a1157835SDaniel Fojt 	if (tx_stbc == -1)
4677*a1157835SDaniel Fojt 		return 0;
4678*a1157835SDaniel Fojt 
4679*a1157835SDaniel Fojt 	wpa_msg(wpa_s, MSG_DEBUG, "set_tx_stbc: %d", tx_stbc);
4680*a1157835SDaniel Fojt 
4681*a1157835SDaniel Fojt 	if (tx_stbc < 0 || tx_stbc > 1) {
4682*a1157835SDaniel Fojt 		wpa_msg(wpa_s, MSG_ERROR,
4683*a1157835SDaniel Fojt 			"tx_stbc: %d out of range. Must be 0-1 or -1", tx_stbc);
4684*a1157835SDaniel Fojt 		return -EINVAL;
4685*a1157835SDaniel Fojt 	}
4686*a1157835SDaniel Fojt 
4687*a1157835SDaniel Fojt 	htcaps_mask->ht_capabilities_info |= msk;
4688*a1157835SDaniel Fojt 	htcaps->ht_capabilities_info &= ~msk;
4689*a1157835SDaniel Fojt 	htcaps->ht_capabilities_info |= (tx_stbc << 7) & msk;
4690*a1157835SDaniel Fojt 
4691*a1157835SDaniel Fojt 	return 0;
4692*a1157835SDaniel Fojt }
4693*a1157835SDaniel Fojt 
4694*a1157835SDaniel Fojt 
wpa_set_rx_stbc(struct wpa_supplicant * wpa_s,struct ieee80211_ht_capabilities * htcaps,struct ieee80211_ht_capabilities * htcaps_mask,int rx_stbc)4695*a1157835SDaniel Fojt static int wpa_set_rx_stbc(struct wpa_supplicant *wpa_s,
4696*a1157835SDaniel Fojt 			   struct ieee80211_ht_capabilities *htcaps,
4697*a1157835SDaniel Fojt 			   struct ieee80211_ht_capabilities *htcaps_mask,
4698*a1157835SDaniel Fojt 			   int rx_stbc)
4699*a1157835SDaniel Fojt {
4700*a1157835SDaniel Fojt 	le16 msk = host_to_le16(HT_CAP_INFO_RX_STBC_MASK);
4701*a1157835SDaniel Fojt 
4702*a1157835SDaniel Fojt 	if (rx_stbc == -1)
4703*a1157835SDaniel Fojt 		return 0;
4704*a1157835SDaniel Fojt 
4705*a1157835SDaniel Fojt 	wpa_msg(wpa_s, MSG_DEBUG, "set_rx_stbc: %d", rx_stbc);
4706*a1157835SDaniel Fojt 
4707*a1157835SDaniel Fojt 	if (rx_stbc < 0 || rx_stbc > 3) {
4708*a1157835SDaniel Fojt 		wpa_msg(wpa_s, MSG_ERROR,
4709*a1157835SDaniel Fojt 			"rx_stbc: %d out of range. Must be 0-3 or -1", rx_stbc);
4710*a1157835SDaniel Fojt 		return -EINVAL;
4711*a1157835SDaniel Fojt 	}
4712*a1157835SDaniel Fojt 
4713*a1157835SDaniel Fojt 	htcaps_mask->ht_capabilities_info |= msk;
4714*a1157835SDaniel Fojt 	htcaps->ht_capabilities_info &= ~msk;
4715*a1157835SDaniel Fojt 	htcaps->ht_capabilities_info |= (rx_stbc << 8) & msk;
4716*a1157835SDaniel Fojt 
4717*a1157835SDaniel Fojt 	return 0;
4718*a1157835SDaniel Fojt }
4719*a1157835SDaniel Fojt 
4720*a1157835SDaniel Fojt 
wpa_supplicant_apply_ht_overrides(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid,struct wpa_driver_associate_params * params)47213ff40c12SJohn Marino void wpa_supplicant_apply_ht_overrides(
47223ff40c12SJohn Marino 	struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
47233ff40c12SJohn Marino 	struct wpa_driver_associate_params *params)
47243ff40c12SJohn Marino {
47253ff40c12SJohn Marino 	struct ieee80211_ht_capabilities *htcaps;
47263ff40c12SJohn Marino 	struct ieee80211_ht_capabilities *htcaps_mask;
47273ff40c12SJohn Marino 
47283ff40c12SJohn Marino 	if (!ssid)
47293ff40c12SJohn Marino 		return;
47303ff40c12SJohn Marino 
47313ff40c12SJohn Marino 	params->disable_ht = ssid->disable_ht;
47323ff40c12SJohn Marino 	if (!params->htcaps || !params->htcaps_mask)
47333ff40c12SJohn Marino 		return;
47343ff40c12SJohn Marino 
47353ff40c12SJohn Marino 	htcaps = (struct ieee80211_ht_capabilities *) params->htcaps;
47363ff40c12SJohn Marino 	htcaps_mask = (struct ieee80211_ht_capabilities *) params->htcaps_mask;
47373ff40c12SJohn Marino 	wpa_set_htcap_mcs(wpa_s, htcaps, htcaps_mask, ssid->ht_mcs);
47383ff40c12SJohn Marino 	wpa_disable_max_amsdu(wpa_s, htcaps, htcaps_mask,
47393ff40c12SJohn Marino 			      ssid->disable_max_amsdu);
47403ff40c12SJohn Marino 	wpa_set_ampdu_factor(wpa_s, htcaps, htcaps_mask, ssid->ampdu_factor);
47413ff40c12SJohn Marino 	wpa_set_ampdu_density(wpa_s, htcaps, htcaps_mask, ssid->ampdu_density);
47423ff40c12SJohn Marino 	wpa_set_disable_ht40(wpa_s, htcaps, htcaps_mask, ssid->disable_ht40);
47433ff40c12SJohn Marino 	wpa_set_disable_sgi(wpa_s, htcaps, htcaps_mask, ssid->disable_sgi);
4744*a1157835SDaniel Fojt 	wpa_set_disable_ldpc(wpa_s, htcaps, htcaps_mask, ssid->disable_ldpc);
4745*a1157835SDaniel Fojt 	wpa_set_rx_stbc(wpa_s, htcaps, htcaps_mask, ssid->rx_stbc);
4746*a1157835SDaniel Fojt 	wpa_set_tx_stbc(wpa_s, htcaps, htcaps_mask, ssid->tx_stbc);
4747*a1157835SDaniel Fojt 
4748*a1157835SDaniel Fojt 	if (ssid->ht40_intolerant) {
4749*a1157835SDaniel Fojt 		le16 bit = host_to_le16(HT_CAP_INFO_40MHZ_INTOLERANT);
4750*a1157835SDaniel Fojt 		htcaps->ht_capabilities_info |= bit;
4751*a1157835SDaniel Fojt 		htcaps_mask->ht_capabilities_info |= bit;
4752*a1157835SDaniel Fojt 	}
47533ff40c12SJohn Marino }
47543ff40c12SJohn Marino 
47553ff40c12SJohn Marino #endif /* CONFIG_HT_OVERRIDES */
47563ff40c12SJohn Marino 
47573ff40c12SJohn Marino 
47583ff40c12SJohn Marino #ifdef CONFIG_VHT_OVERRIDES
wpa_supplicant_apply_vht_overrides(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid,struct wpa_driver_associate_params * params)47593ff40c12SJohn Marino void wpa_supplicant_apply_vht_overrides(
47603ff40c12SJohn Marino 	struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
47613ff40c12SJohn Marino 	struct wpa_driver_associate_params *params)
47623ff40c12SJohn Marino {
47633ff40c12SJohn Marino 	struct ieee80211_vht_capabilities *vhtcaps;
47643ff40c12SJohn Marino 	struct ieee80211_vht_capabilities *vhtcaps_mask;
47653ff40c12SJohn Marino 
47663ff40c12SJohn Marino 	if (!ssid)
47673ff40c12SJohn Marino 		return;
47683ff40c12SJohn Marino 
47693ff40c12SJohn Marino 	params->disable_vht = ssid->disable_vht;
47703ff40c12SJohn Marino 
47713ff40c12SJohn Marino 	vhtcaps = (void *) params->vhtcaps;
47723ff40c12SJohn Marino 	vhtcaps_mask = (void *) params->vhtcaps_mask;
47733ff40c12SJohn Marino 
47743ff40c12SJohn Marino 	if (!vhtcaps || !vhtcaps_mask)
47753ff40c12SJohn Marino 		return;
47763ff40c12SJohn Marino 
4777*a1157835SDaniel Fojt 	vhtcaps->vht_capabilities_info = host_to_le32(ssid->vht_capa);
4778*a1157835SDaniel Fojt 	vhtcaps_mask->vht_capabilities_info = host_to_le32(ssid->vht_capa_mask);
4779*a1157835SDaniel Fojt 
4780*a1157835SDaniel Fojt #ifdef CONFIG_HT_OVERRIDES
4781*a1157835SDaniel Fojt 	if (ssid->disable_sgi) {
4782*a1157835SDaniel Fojt 		vhtcaps_mask->vht_capabilities_info |= (VHT_CAP_SHORT_GI_80 |
4783*a1157835SDaniel Fojt 							VHT_CAP_SHORT_GI_160);
4784*a1157835SDaniel Fojt 		vhtcaps->vht_capabilities_info &= ~(VHT_CAP_SHORT_GI_80 |
4785*a1157835SDaniel Fojt 						    VHT_CAP_SHORT_GI_160);
4786*a1157835SDaniel Fojt 		wpa_msg(wpa_s, MSG_DEBUG,
4787*a1157835SDaniel Fojt 			"disable-sgi override specified, vht-caps: 0x%x",
4788*a1157835SDaniel Fojt 			vhtcaps->vht_capabilities_info);
4789*a1157835SDaniel Fojt 	}
4790*a1157835SDaniel Fojt 
4791*a1157835SDaniel Fojt 	/* if max ampdu is <= 3, we have to make the HT cap the same */
4792*a1157835SDaniel Fojt 	if (ssid->vht_capa_mask & VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX) {
4793*a1157835SDaniel Fojt 		int max_ampdu;
4794*a1157835SDaniel Fojt 
4795*a1157835SDaniel Fojt 		max_ampdu = (ssid->vht_capa &
4796*a1157835SDaniel Fojt 			     VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX) >>
4797*a1157835SDaniel Fojt 			VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX_SHIFT;
4798*a1157835SDaniel Fojt 
4799*a1157835SDaniel Fojt 		max_ampdu = max_ampdu < 3 ? max_ampdu : 3;
4800*a1157835SDaniel Fojt 		wpa_set_ampdu_factor(wpa_s,
4801*a1157835SDaniel Fojt 				     (void *) params->htcaps,
4802*a1157835SDaniel Fojt 				     (void *) params->htcaps_mask,
4803*a1157835SDaniel Fojt 				     max_ampdu);
4804*a1157835SDaniel Fojt 	}
4805*a1157835SDaniel Fojt #endif /* CONFIG_HT_OVERRIDES */
48063ff40c12SJohn Marino 
48073ff40c12SJohn Marino #define OVERRIDE_MCS(i)							\
48083ff40c12SJohn Marino 	if (ssid->vht_tx_mcs_nss_ ##i >= 0) {				\
48093ff40c12SJohn Marino 		vhtcaps_mask->vht_supported_mcs_set.tx_map |=		\
4810*a1157835SDaniel Fojt 			host_to_le16(3 << 2 * (i - 1));			\
48113ff40c12SJohn Marino 		vhtcaps->vht_supported_mcs_set.tx_map |=		\
4812*a1157835SDaniel Fojt 			host_to_le16(ssid->vht_tx_mcs_nss_ ##i <<	\
4813*a1157835SDaniel Fojt 				     2 * (i - 1));			\
48143ff40c12SJohn Marino 	}								\
48153ff40c12SJohn Marino 	if (ssid->vht_rx_mcs_nss_ ##i >= 0) {				\
48163ff40c12SJohn Marino 		vhtcaps_mask->vht_supported_mcs_set.rx_map |=		\
4817*a1157835SDaniel Fojt 			host_to_le16(3 << 2 * (i - 1));			\
48183ff40c12SJohn Marino 		vhtcaps->vht_supported_mcs_set.rx_map |=		\
4819*a1157835SDaniel Fojt 			host_to_le16(ssid->vht_rx_mcs_nss_ ##i <<	\
4820*a1157835SDaniel Fojt 				     2 * (i - 1));			\
48213ff40c12SJohn Marino 	}
48223ff40c12SJohn Marino 
48233ff40c12SJohn Marino 	OVERRIDE_MCS(1);
48243ff40c12SJohn Marino 	OVERRIDE_MCS(2);
48253ff40c12SJohn Marino 	OVERRIDE_MCS(3);
48263ff40c12SJohn Marino 	OVERRIDE_MCS(4);
48273ff40c12SJohn Marino 	OVERRIDE_MCS(5);
48283ff40c12SJohn Marino 	OVERRIDE_MCS(6);
48293ff40c12SJohn Marino 	OVERRIDE_MCS(7);
48303ff40c12SJohn Marino 	OVERRIDE_MCS(8);
48313ff40c12SJohn Marino }
48323ff40c12SJohn Marino #endif /* CONFIG_VHT_OVERRIDES */
48333ff40c12SJohn Marino 
48343ff40c12SJohn Marino 
pcsc_reader_init(struct wpa_supplicant * wpa_s)48353ff40c12SJohn Marino static int pcsc_reader_init(struct wpa_supplicant *wpa_s)
48363ff40c12SJohn Marino {
48373ff40c12SJohn Marino #ifdef PCSC_FUNCS
48383ff40c12SJohn Marino 	size_t len;
48393ff40c12SJohn Marino 
48403ff40c12SJohn Marino 	if (!wpa_s->conf->pcsc_reader)
48413ff40c12SJohn Marino 		return 0;
48423ff40c12SJohn Marino 
48433ff40c12SJohn Marino 	wpa_s->scard = scard_init(wpa_s->conf->pcsc_reader);
48443ff40c12SJohn Marino 	if (!wpa_s->scard)
48453ff40c12SJohn Marino 		return 1;
48463ff40c12SJohn Marino 
48473ff40c12SJohn Marino 	if (wpa_s->conf->pcsc_pin &&
48483ff40c12SJohn Marino 	    scard_set_pin(wpa_s->scard, wpa_s->conf->pcsc_pin) < 0) {
48493ff40c12SJohn Marino 		scard_deinit(wpa_s->scard);
48503ff40c12SJohn Marino 		wpa_s->scard = NULL;
48513ff40c12SJohn Marino 		wpa_msg(wpa_s, MSG_ERROR, "PC/SC PIN validation failed");
48523ff40c12SJohn Marino 		return -1;
48533ff40c12SJohn Marino 	}
48543ff40c12SJohn Marino 
48553ff40c12SJohn Marino 	len = sizeof(wpa_s->imsi) - 1;
48563ff40c12SJohn Marino 	if (scard_get_imsi(wpa_s->scard, wpa_s->imsi, &len)) {
48573ff40c12SJohn Marino 		scard_deinit(wpa_s->scard);
48583ff40c12SJohn Marino 		wpa_s->scard = NULL;
48593ff40c12SJohn Marino 		wpa_msg(wpa_s, MSG_ERROR, "Could not read IMSI");
48603ff40c12SJohn Marino 		return -1;
48613ff40c12SJohn Marino 	}
48623ff40c12SJohn Marino 	wpa_s->imsi[len] = '\0';
48633ff40c12SJohn Marino 
48643ff40c12SJohn Marino 	wpa_s->mnc_len = scard_get_mnc_len(wpa_s->scard);
48653ff40c12SJohn Marino 
48663ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "SCARD: IMSI %s (MNC length %d)",
48673ff40c12SJohn Marino 		   wpa_s->imsi, wpa_s->mnc_len);
48683ff40c12SJohn Marino 
48693ff40c12SJohn Marino 	wpa_sm_set_scard_ctx(wpa_s->wpa, wpa_s->scard);
48703ff40c12SJohn Marino 	eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
48713ff40c12SJohn Marino #endif /* PCSC_FUNCS */
48723ff40c12SJohn Marino 
48733ff40c12SJohn Marino 	return 0;
48743ff40c12SJohn Marino }
48753ff40c12SJohn Marino 
48763ff40c12SJohn Marino 
wpas_init_ext_pw(struct wpa_supplicant * wpa_s)48773ff40c12SJohn Marino int wpas_init_ext_pw(struct wpa_supplicant *wpa_s)
48783ff40c12SJohn Marino {
48793ff40c12SJohn Marino 	char *val, *pos;
48803ff40c12SJohn Marino 
48813ff40c12SJohn Marino 	ext_password_deinit(wpa_s->ext_pw);
48823ff40c12SJohn Marino 	wpa_s->ext_pw = NULL;
48833ff40c12SJohn Marino 	eapol_sm_set_ext_pw_ctx(wpa_s->eapol, NULL);
48843ff40c12SJohn Marino 
48853ff40c12SJohn Marino 	if (!wpa_s->conf->ext_password_backend)
48863ff40c12SJohn Marino 		return 0;
48873ff40c12SJohn Marino 
48883ff40c12SJohn Marino 	val = os_strdup(wpa_s->conf->ext_password_backend);
48893ff40c12SJohn Marino 	if (val == NULL)
48903ff40c12SJohn Marino 		return -1;
48913ff40c12SJohn Marino 	pos = os_strchr(val, ':');
48923ff40c12SJohn Marino 	if (pos)
48933ff40c12SJohn Marino 		*pos++ = '\0';
48943ff40c12SJohn Marino 
48953ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "EXT PW: Initialize backend '%s'", val);
48963ff40c12SJohn Marino 
48973ff40c12SJohn Marino 	wpa_s->ext_pw = ext_password_init(val, pos);
48983ff40c12SJohn Marino 	os_free(val);
48993ff40c12SJohn Marino 	if (wpa_s->ext_pw == NULL) {
49003ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EXT PW: Failed to initialize backend");
49013ff40c12SJohn Marino 		return -1;
49023ff40c12SJohn Marino 	}
49033ff40c12SJohn Marino 	eapol_sm_set_ext_pw_ctx(wpa_s->eapol, wpa_s->ext_pw);
49043ff40c12SJohn Marino 
49053ff40c12SJohn Marino 	return 0;
49063ff40c12SJohn Marino }
49073ff40c12SJohn Marino 
49083ff40c12SJohn Marino 
4909*a1157835SDaniel Fojt #ifdef CONFIG_FST
4910*a1157835SDaniel Fojt 
wpas_fst_get_bssid_cb(void * ctx)4911*a1157835SDaniel Fojt static const u8 * wpas_fst_get_bssid_cb(void *ctx)
4912*a1157835SDaniel Fojt {
4913*a1157835SDaniel Fojt 	struct wpa_supplicant *wpa_s = ctx;
4914*a1157835SDaniel Fojt 
4915*a1157835SDaniel Fojt 	return (is_zero_ether_addr(wpa_s->bssid) ||
4916*a1157835SDaniel Fojt 		wpa_s->wpa_state != WPA_COMPLETED) ? NULL : wpa_s->bssid;
4917*a1157835SDaniel Fojt }
4918*a1157835SDaniel Fojt 
4919*a1157835SDaniel Fojt 
wpas_fst_get_channel_info_cb(void * ctx,enum hostapd_hw_mode * hw_mode,u8 * channel)4920*a1157835SDaniel Fojt static void wpas_fst_get_channel_info_cb(void *ctx,
4921*a1157835SDaniel Fojt 					 enum hostapd_hw_mode *hw_mode,
4922*a1157835SDaniel Fojt 					 u8 *channel)
4923*a1157835SDaniel Fojt {
4924*a1157835SDaniel Fojt 	struct wpa_supplicant *wpa_s = ctx;
4925*a1157835SDaniel Fojt 
4926*a1157835SDaniel Fojt 	if (wpa_s->current_bss) {
4927*a1157835SDaniel Fojt 		*hw_mode = ieee80211_freq_to_chan(wpa_s->current_bss->freq,
4928*a1157835SDaniel Fojt 						  channel);
4929*a1157835SDaniel Fojt 	} else if (wpa_s->hw.num_modes) {
4930*a1157835SDaniel Fojt 		*hw_mode = wpa_s->hw.modes[0].mode;
4931*a1157835SDaniel Fojt 	} else {
4932*a1157835SDaniel Fojt 		WPA_ASSERT(0);
4933*a1157835SDaniel Fojt 		*hw_mode = 0;
4934*a1157835SDaniel Fojt 	}
4935*a1157835SDaniel Fojt }
4936*a1157835SDaniel Fojt 
4937*a1157835SDaniel Fojt 
wpas_fst_get_hw_modes(void * ctx,struct hostapd_hw_modes ** modes)4938*a1157835SDaniel Fojt static int wpas_fst_get_hw_modes(void *ctx, struct hostapd_hw_modes **modes)
4939*a1157835SDaniel Fojt {
4940*a1157835SDaniel Fojt 	struct wpa_supplicant *wpa_s = ctx;
4941*a1157835SDaniel Fojt 
4942*a1157835SDaniel Fojt 	*modes = wpa_s->hw.modes;
4943*a1157835SDaniel Fojt 	return wpa_s->hw.num_modes;
4944*a1157835SDaniel Fojt }
4945*a1157835SDaniel Fojt 
4946*a1157835SDaniel Fojt 
wpas_fst_set_ies_cb(void * ctx,const struct wpabuf * fst_ies)4947*a1157835SDaniel Fojt static void wpas_fst_set_ies_cb(void *ctx, const struct wpabuf *fst_ies)
4948*a1157835SDaniel Fojt {
4949*a1157835SDaniel Fojt 	struct wpa_supplicant *wpa_s = ctx;
4950*a1157835SDaniel Fojt 
4951*a1157835SDaniel Fojt 	wpa_hexdump_buf(MSG_DEBUG, "FST: Set IEs", fst_ies);
4952*a1157835SDaniel Fojt 	wpa_s->fst_ies = fst_ies;
4953*a1157835SDaniel Fojt }
4954*a1157835SDaniel Fojt 
4955*a1157835SDaniel Fojt 
wpas_fst_send_action_cb(void * ctx,const u8 * da,struct wpabuf * data)4956*a1157835SDaniel Fojt static int wpas_fst_send_action_cb(void *ctx, const u8 *da, struct wpabuf *data)
4957*a1157835SDaniel Fojt {
4958*a1157835SDaniel Fojt 	struct wpa_supplicant *wpa_s = ctx;
4959*a1157835SDaniel Fojt 
4960*a1157835SDaniel Fojt 	if (os_memcmp(wpa_s->bssid, da, ETH_ALEN) != 0) {
4961*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO, "FST:%s:bssid=" MACSTR " != da=" MACSTR,
4962*a1157835SDaniel Fojt 			   __func__, MAC2STR(wpa_s->bssid), MAC2STR(da));
4963*a1157835SDaniel Fojt 		return -1;
4964*a1157835SDaniel Fojt 	}
4965*a1157835SDaniel Fojt 	return wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
4966*a1157835SDaniel Fojt 				   wpa_s->own_addr, wpa_s->bssid,
4967*a1157835SDaniel Fojt 				   wpabuf_head(data), wpabuf_len(data),
4968*a1157835SDaniel Fojt 				   0);
4969*a1157835SDaniel Fojt }
4970*a1157835SDaniel Fojt 
4971*a1157835SDaniel Fojt 
wpas_fst_get_mb_ie_cb(void * ctx,const u8 * addr)4972*a1157835SDaniel Fojt static const struct wpabuf * wpas_fst_get_mb_ie_cb(void *ctx, const u8 *addr)
4973*a1157835SDaniel Fojt {
4974*a1157835SDaniel Fojt 	struct wpa_supplicant *wpa_s = ctx;
4975*a1157835SDaniel Fojt 
4976*a1157835SDaniel Fojt 	WPA_ASSERT(os_memcmp(wpa_s->bssid, addr, ETH_ALEN) == 0);
4977*a1157835SDaniel Fojt 	return wpa_s->received_mb_ies;
4978*a1157835SDaniel Fojt }
4979*a1157835SDaniel Fojt 
4980*a1157835SDaniel Fojt 
wpas_fst_update_mb_ie_cb(void * ctx,const u8 * addr,const u8 * buf,size_t size)4981*a1157835SDaniel Fojt static void wpas_fst_update_mb_ie_cb(void *ctx, const u8 *addr,
4982*a1157835SDaniel Fojt 				     const u8 *buf, size_t size)
4983*a1157835SDaniel Fojt {
4984*a1157835SDaniel Fojt 	struct wpa_supplicant *wpa_s = ctx;
4985*a1157835SDaniel Fojt 	struct mb_ies_info info;
4986*a1157835SDaniel Fojt 
4987*a1157835SDaniel Fojt 	WPA_ASSERT(os_memcmp(wpa_s->bssid, addr, ETH_ALEN) == 0);
4988*a1157835SDaniel Fojt 
4989*a1157835SDaniel Fojt 	if (!mb_ies_info_by_ies(&info, buf, size)) {
4990*a1157835SDaniel Fojt 		wpabuf_free(wpa_s->received_mb_ies);
4991*a1157835SDaniel Fojt 		wpa_s->received_mb_ies = mb_ies_by_info(&info);
4992*a1157835SDaniel Fojt 	}
4993*a1157835SDaniel Fojt }
4994*a1157835SDaniel Fojt 
4995*a1157835SDaniel Fojt 
wpas_fst_get_peer_first(void * ctx,struct fst_get_peer_ctx ** get_ctx,Boolean mb_only)4996*a1157835SDaniel Fojt static const u8 * wpas_fst_get_peer_first(void *ctx,
4997*a1157835SDaniel Fojt 					  struct fst_get_peer_ctx **get_ctx,
4998*a1157835SDaniel Fojt 					  Boolean mb_only)
4999*a1157835SDaniel Fojt {
5000*a1157835SDaniel Fojt 	struct wpa_supplicant *wpa_s = ctx;
5001*a1157835SDaniel Fojt 
5002*a1157835SDaniel Fojt 	*get_ctx = NULL;
5003*a1157835SDaniel Fojt 	if (!is_zero_ether_addr(wpa_s->bssid))
5004*a1157835SDaniel Fojt 		return (wpa_s->received_mb_ies || !mb_only) ?
5005*a1157835SDaniel Fojt 			wpa_s->bssid : NULL;
5006*a1157835SDaniel Fojt 	return NULL;
5007*a1157835SDaniel Fojt }
5008*a1157835SDaniel Fojt 
5009*a1157835SDaniel Fojt 
wpas_fst_get_peer_next(void * ctx,struct fst_get_peer_ctx ** get_ctx,Boolean mb_only)5010*a1157835SDaniel Fojt static const u8 * wpas_fst_get_peer_next(void *ctx,
5011*a1157835SDaniel Fojt 					 struct fst_get_peer_ctx **get_ctx,
5012*a1157835SDaniel Fojt 					 Boolean mb_only)
5013*a1157835SDaniel Fojt {
5014*a1157835SDaniel Fojt 	return NULL;
5015*a1157835SDaniel Fojt }
5016*a1157835SDaniel Fojt 
fst_wpa_supplicant_fill_iface_obj(struct wpa_supplicant * wpa_s,struct fst_wpa_obj * iface_obj)5017*a1157835SDaniel Fojt void fst_wpa_supplicant_fill_iface_obj(struct wpa_supplicant *wpa_s,
5018*a1157835SDaniel Fojt 				       struct fst_wpa_obj *iface_obj)
5019*a1157835SDaniel Fojt {
5020*a1157835SDaniel Fojt 	iface_obj->ctx              = wpa_s;
5021*a1157835SDaniel Fojt 	iface_obj->get_bssid        = wpas_fst_get_bssid_cb;
5022*a1157835SDaniel Fojt 	iface_obj->get_channel_info = wpas_fst_get_channel_info_cb;
5023*a1157835SDaniel Fojt 	iface_obj->get_hw_modes     = wpas_fst_get_hw_modes;
5024*a1157835SDaniel Fojt 	iface_obj->set_ies          = wpas_fst_set_ies_cb;
5025*a1157835SDaniel Fojt 	iface_obj->send_action      = wpas_fst_send_action_cb;
5026*a1157835SDaniel Fojt 	iface_obj->get_mb_ie        = wpas_fst_get_mb_ie_cb;
5027*a1157835SDaniel Fojt 	iface_obj->update_mb_ie     = wpas_fst_update_mb_ie_cb;
5028*a1157835SDaniel Fojt 	iface_obj->get_peer_first   = wpas_fst_get_peer_first;
5029*a1157835SDaniel Fojt 	iface_obj->get_peer_next    = wpas_fst_get_peer_next;
5030*a1157835SDaniel Fojt }
5031*a1157835SDaniel Fojt #endif /* CONFIG_FST */
5032*a1157835SDaniel Fojt 
wpas_set_wowlan_triggers(struct wpa_supplicant * wpa_s,const struct wpa_driver_capa * capa)5033*a1157835SDaniel Fojt static int wpas_set_wowlan_triggers(struct wpa_supplicant *wpa_s,
5034*a1157835SDaniel Fojt 				    const struct wpa_driver_capa *capa)
5035*a1157835SDaniel Fojt {
5036*a1157835SDaniel Fojt 	struct wowlan_triggers *triggers;
5037*a1157835SDaniel Fojt 	int ret = 0;
5038*a1157835SDaniel Fojt 
5039*a1157835SDaniel Fojt 	if (!wpa_s->conf->wowlan_triggers)
5040*a1157835SDaniel Fojt 		return 0;
5041*a1157835SDaniel Fojt 
5042*a1157835SDaniel Fojt 	triggers = wpa_get_wowlan_triggers(wpa_s->conf->wowlan_triggers, capa);
5043*a1157835SDaniel Fojt 	if (triggers) {
5044*a1157835SDaniel Fojt 		ret = wpa_drv_wowlan(wpa_s, triggers);
5045*a1157835SDaniel Fojt 		os_free(triggers);
5046*a1157835SDaniel Fojt 	}
5047*a1157835SDaniel Fojt 	return ret;
5048*a1157835SDaniel Fojt }
5049*a1157835SDaniel Fojt 
5050*a1157835SDaniel Fojt 
wpas_freq_to_band(int freq)5051*a1157835SDaniel Fojt enum wpa_radio_work_band wpas_freq_to_band(int freq)
5052*a1157835SDaniel Fojt {
5053*a1157835SDaniel Fojt 	if (freq < 3000)
5054*a1157835SDaniel Fojt 		return BAND_2_4_GHZ;
5055*a1157835SDaniel Fojt 	if (freq > 50000)
5056*a1157835SDaniel Fojt 		return BAND_60_GHZ;
5057*a1157835SDaniel Fojt 	return BAND_5_GHZ;
5058*a1157835SDaniel Fojt }
5059*a1157835SDaniel Fojt 
5060*a1157835SDaniel Fojt 
wpas_get_bands(struct wpa_supplicant * wpa_s,const int * freqs)5061*a1157835SDaniel Fojt unsigned int wpas_get_bands(struct wpa_supplicant *wpa_s, const int *freqs)
5062*a1157835SDaniel Fojt {
5063*a1157835SDaniel Fojt 	int i;
5064*a1157835SDaniel Fojt 	unsigned int band = 0;
5065*a1157835SDaniel Fojt 
5066*a1157835SDaniel Fojt 	if (freqs) {
5067*a1157835SDaniel Fojt 		/* freqs are specified for the radio work */
5068*a1157835SDaniel Fojt 		for (i = 0; freqs[i]; i++)
5069*a1157835SDaniel Fojt 			band |= wpas_freq_to_band(freqs[i]);
5070*a1157835SDaniel Fojt 	} else {
5071*a1157835SDaniel Fojt 		/*
5072*a1157835SDaniel Fojt 		 * freqs are not specified, implies all
5073*a1157835SDaniel Fojt 		 * the supported freqs by HW
5074*a1157835SDaniel Fojt 		 */
5075*a1157835SDaniel Fojt 		for (i = 0; i < wpa_s->hw.num_modes; i++) {
5076*a1157835SDaniel Fojt 			if (wpa_s->hw.modes[i].num_channels != 0) {
5077*a1157835SDaniel Fojt 				if (wpa_s->hw.modes[i].mode ==
5078*a1157835SDaniel Fojt 				    HOSTAPD_MODE_IEEE80211B ||
5079*a1157835SDaniel Fojt 				    wpa_s->hw.modes[i].mode ==
5080*a1157835SDaniel Fojt 				    HOSTAPD_MODE_IEEE80211G)
5081*a1157835SDaniel Fojt 					band |= BAND_2_4_GHZ;
5082*a1157835SDaniel Fojt 				else if (wpa_s->hw.modes[i].mode ==
5083*a1157835SDaniel Fojt 					 HOSTAPD_MODE_IEEE80211A)
5084*a1157835SDaniel Fojt 					band |= BAND_5_GHZ;
5085*a1157835SDaniel Fojt 				else if (wpa_s->hw.modes[i].mode ==
5086*a1157835SDaniel Fojt 					 HOSTAPD_MODE_IEEE80211AD)
5087*a1157835SDaniel Fojt 					band |= BAND_60_GHZ;
5088*a1157835SDaniel Fojt 				else if (wpa_s->hw.modes[i].mode ==
5089*a1157835SDaniel Fojt 					 HOSTAPD_MODE_IEEE80211ANY)
5090*a1157835SDaniel Fojt 					band = BAND_2_4_GHZ | BAND_5_GHZ |
5091*a1157835SDaniel Fojt 						BAND_60_GHZ;
5092*a1157835SDaniel Fojt 			}
5093*a1157835SDaniel Fojt 		}
5094*a1157835SDaniel Fojt 	}
5095*a1157835SDaniel Fojt 
5096*a1157835SDaniel Fojt 	return band;
5097*a1157835SDaniel Fojt }
5098*a1157835SDaniel Fojt 
5099*a1157835SDaniel Fojt 
radio_add_interface(struct wpa_supplicant * wpa_s,const char * rn)51003ff40c12SJohn Marino static struct wpa_radio * radio_add_interface(struct wpa_supplicant *wpa_s,
51013ff40c12SJohn Marino 					      const char *rn)
51023ff40c12SJohn Marino {
51033ff40c12SJohn Marino 	struct wpa_supplicant *iface = wpa_s->global->ifaces;
51043ff40c12SJohn Marino 	struct wpa_radio *radio;
51053ff40c12SJohn Marino 
51063ff40c12SJohn Marino 	while (rn && iface) {
51073ff40c12SJohn Marino 		radio = iface->radio;
51083ff40c12SJohn Marino 		if (radio && os_strcmp(rn, radio->name) == 0) {
51093ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "Add interface %s to existing radio %s",
51103ff40c12SJohn Marino 				   wpa_s->ifname, rn);
51113ff40c12SJohn Marino 			dl_list_add(&radio->ifaces, &wpa_s->radio_list);
51123ff40c12SJohn Marino 			return radio;
51133ff40c12SJohn Marino 		}
51143ff40c12SJohn Marino 
51153ff40c12SJohn Marino 		iface = iface->next;
51163ff40c12SJohn Marino 	}
51173ff40c12SJohn Marino 
51183ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "Add interface %s to a new radio %s",
51193ff40c12SJohn Marino 		   wpa_s->ifname, rn ? rn : "N/A");
51203ff40c12SJohn Marino 	radio = os_zalloc(sizeof(*radio));
51213ff40c12SJohn Marino 	if (radio == NULL)
51223ff40c12SJohn Marino 		return NULL;
51233ff40c12SJohn Marino 
51243ff40c12SJohn Marino 	if (rn)
51253ff40c12SJohn Marino 		os_strlcpy(radio->name, rn, sizeof(radio->name));
51263ff40c12SJohn Marino 	dl_list_init(&radio->ifaces);
51273ff40c12SJohn Marino 	dl_list_init(&radio->work);
51283ff40c12SJohn Marino 	dl_list_add(&radio->ifaces, &wpa_s->radio_list);
51293ff40c12SJohn Marino 
51303ff40c12SJohn Marino 	return radio;
51313ff40c12SJohn Marino }
51323ff40c12SJohn Marino 
51333ff40c12SJohn Marino 
radio_work_free(struct wpa_radio_work * work)51343ff40c12SJohn Marino static void radio_work_free(struct wpa_radio_work *work)
51353ff40c12SJohn Marino {
51363ff40c12SJohn Marino 	if (work->wpa_s->scan_work == work) {
51373ff40c12SJohn Marino 		/* This should not really happen. */
51383ff40c12SJohn Marino 		wpa_dbg(work->wpa_s, MSG_INFO, "Freeing radio work '%s'@%p (started=%d) that is marked as scan_work",
51393ff40c12SJohn Marino 			work->type, work, work->started);
51403ff40c12SJohn Marino 		work->wpa_s->scan_work = NULL;
51413ff40c12SJohn Marino 	}
51423ff40c12SJohn Marino 
51433ff40c12SJohn Marino #ifdef CONFIG_P2P
51443ff40c12SJohn Marino 	if (work->wpa_s->p2p_scan_work == work) {
51453ff40c12SJohn Marino 		/* This should not really happen. */
51463ff40c12SJohn Marino 		wpa_dbg(work->wpa_s, MSG_INFO, "Freeing radio work '%s'@%p (started=%d) that is marked as p2p_scan_work",
51473ff40c12SJohn Marino 			work->type, work, work->started);
51483ff40c12SJohn Marino 		work->wpa_s->p2p_scan_work = NULL;
51493ff40c12SJohn Marino 	}
51503ff40c12SJohn Marino #endif /* CONFIG_P2P */
51513ff40c12SJohn Marino 
5152*a1157835SDaniel Fojt 	if (work->started) {
5153*a1157835SDaniel Fojt 		work->wpa_s->radio->num_active_works--;
5154*a1157835SDaniel Fojt 		wpa_dbg(work->wpa_s, MSG_DEBUG,
5155*a1157835SDaniel Fojt 			"radio_work_free('%s'@%p): num_active_works --> %u",
5156*a1157835SDaniel Fojt 			work->type, work,
5157*a1157835SDaniel Fojt 			work->wpa_s->radio->num_active_works);
5158*a1157835SDaniel Fojt 	}
5159*a1157835SDaniel Fojt 
51603ff40c12SJohn Marino 	dl_list_del(&work->list);
51613ff40c12SJohn Marino 	os_free(work);
51623ff40c12SJohn Marino }
51633ff40c12SJohn Marino 
51643ff40c12SJohn Marino 
radio_work_is_connect(struct wpa_radio_work * work)5165*a1157835SDaniel Fojt static int radio_work_is_connect(struct wpa_radio_work *work)
5166*a1157835SDaniel Fojt {
5167*a1157835SDaniel Fojt 	return os_strcmp(work->type, "sme-connect") == 0 ||
5168*a1157835SDaniel Fojt 		os_strcmp(work->type, "connect") == 0;
5169*a1157835SDaniel Fojt }
5170*a1157835SDaniel Fojt 
5171*a1157835SDaniel Fojt 
radio_work_is_scan(struct wpa_radio_work * work)5172*a1157835SDaniel Fojt static int radio_work_is_scan(struct wpa_radio_work *work)
5173*a1157835SDaniel Fojt {
5174*a1157835SDaniel Fojt 	return os_strcmp(work->type, "scan") == 0 ||
5175*a1157835SDaniel Fojt 		os_strcmp(work->type, "p2p-scan") == 0;
5176*a1157835SDaniel Fojt }
5177*a1157835SDaniel Fojt 
5178*a1157835SDaniel Fojt 
radio_work_get_next_work(struct wpa_radio * radio)5179*a1157835SDaniel Fojt static struct wpa_radio_work * radio_work_get_next_work(struct wpa_radio *radio)
5180*a1157835SDaniel Fojt {
5181*a1157835SDaniel Fojt 	struct wpa_radio_work *active_work = NULL;
5182*a1157835SDaniel Fojt 	struct wpa_radio_work *tmp;
5183*a1157835SDaniel Fojt 
5184*a1157835SDaniel Fojt 	/* Get the active work to know the type and band. */
5185*a1157835SDaniel Fojt 	dl_list_for_each(tmp, &radio->work, struct wpa_radio_work, list) {
5186*a1157835SDaniel Fojt 		if (tmp->started) {
5187*a1157835SDaniel Fojt 			active_work = tmp;
5188*a1157835SDaniel Fojt 			break;
5189*a1157835SDaniel Fojt 		}
5190*a1157835SDaniel Fojt 	}
5191*a1157835SDaniel Fojt 
5192*a1157835SDaniel Fojt 	if (!active_work) {
5193*a1157835SDaniel Fojt 		/* No active work, start one */
5194*a1157835SDaniel Fojt 		radio->num_active_works = 0;
5195*a1157835SDaniel Fojt 		dl_list_for_each(tmp, &radio->work, struct wpa_radio_work,
5196*a1157835SDaniel Fojt 				 list) {
5197*a1157835SDaniel Fojt 			if (os_strcmp(tmp->type, "scan") == 0 &&
5198*a1157835SDaniel Fojt 			    radio->external_scan_running &&
5199*a1157835SDaniel Fojt 			    (((struct wpa_driver_scan_params *)
5200*a1157835SDaniel Fojt 			      tmp->ctx)->only_new_results ||
5201*a1157835SDaniel Fojt 			     tmp->wpa_s->clear_driver_scan_cache))
5202*a1157835SDaniel Fojt 				continue;
5203*a1157835SDaniel Fojt 			return tmp;
5204*a1157835SDaniel Fojt 		}
5205*a1157835SDaniel Fojt 		return NULL;
5206*a1157835SDaniel Fojt 	}
5207*a1157835SDaniel Fojt 
5208*a1157835SDaniel Fojt 	if (radio_work_is_connect(active_work)) {
5209*a1157835SDaniel Fojt 		/*
5210*a1157835SDaniel Fojt 		 * If the active work is either connect or sme-connect,
5211*a1157835SDaniel Fojt 		 * do not parallelize them with other radio works.
5212*a1157835SDaniel Fojt 		 */
5213*a1157835SDaniel Fojt 		wpa_dbg(active_work->wpa_s, MSG_DEBUG,
5214*a1157835SDaniel Fojt 			"Do not parallelize radio work with %s",
5215*a1157835SDaniel Fojt 			active_work->type);
5216*a1157835SDaniel Fojt 		return NULL;
5217*a1157835SDaniel Fojt 	}
5218*a1157835SDaniel Fojt 
5219*a1157835SDaniel Fojt 	dl_list_for_each(tmp, &radio->work, struct wpa_radio_work, list) {
5220*a1157835SDaniel Fojt 		if (tmp->started)
5221*a1157835SDaniel Fojt 			continue;
5222*a1157835SDaniel Fojt 
5223*a1157835SDaniel Fojt 		/*
5224*a1157835SDaniel Fojt 		 * If connect or sme-connect are enqueued, parallelize only
5225*a1157835SDaniel Fojt 		 * those operations ahead of them in the queue.
5226*a1157835SDaniel Fojt 		 */
5227*a1157835SDaniel Fojt 		if (radio_work_is_connect(tmp))
5228*a1157835SDaniel Fojt 			break;
5229*a1157835SDaniel Fojt 
5230*a1157835SDaniel Fojt 		/* Serialize parallel scan and p2p_scan operations on the same
5231*a1157835SDaniel Fojt 		 * interface since the driver_nl80211 mechanism for tracking
5232*a1157835SDaniel Fojt 		 * scan cookies does not yet have support for this. */
5233*a1157835SDaniel Fojt 		if (active_work->wpa_s == tmp->wpa_s &&
5234*a1157835SDaniel Fojt 		    radio_work_is_scan(active_work) &&
5235*a1157835SDaniel Fojt 		    radio_work_is_scan(tmp)) {
5236*a1157835SDaniel Fojt 			wpa_dbg(active_work->wpa_s, MSG_DEBUG,
5237*a1157835SDaniel Fojt 				"Do not start work '%s' when another work '%s' is already scheduled",
5238*a1157835SDaniel Fojt 				tmp->type, active_work->type);
5239*a1157835SDaniel Fojt 			continue;
5240*a1157835SDaniel Fojt 		}
5241*a1157835SDaniel Fojt 		/*
5242*a1157835SDaniel Fojt 		 * Check that the radio works are distinct and
5243*a1157835SDaniel Fojt 		 * on different bands.
5244*a1157835SDaniel Fojt 		 */
5245*a1157835SDaniel Fojt 		if (os_strcmp(active_work->type, tmp->type) != 0 &&
5246*a1157835SDaniel Fojt 		    (active_work->bands != tmp->bands)) {
5247*a1157835SDaniel Fojt 			/*
5248*a1157835SDaniel Fojt 			 * If a scan has to be scheduled through nl80211 scan
5249*a1157835SDaniel Fojt 			 * interface and if an external scan is already running,
5250*a1157835SDaniel Fojt 			 * do not schedule the scan since it is likely to get
5251*a1157835SDaniel Fojt 			 * rejected by kernel.
5252*a1157835SDaniel Fojt 			 */
5253*a1157835SDaniel Fojt 			if (os_strcmp(tmp->type, "scan") == 0 &&
5254*a1157835SDaniel Fojt 			    radio->external_scan_running &&
5255*a1157835SDaniel Fojt 			    (((struct wpa_driver_scan_params *)
5256*a1157835SDaniel Fojt 			      tmp->ctx)->only_new_results ||
5257*a1157835SDaniel Fojt 			     tmp->wpa_s->clear_driver_scan_cache))
5258*a1157835SDaniel Fojt 				continue;
5259*a1157835SDaniel Fojt 
5260*a1157835SDaniel Fojt 			wpa_dbg(active_work->wpa_s, MSG_DEBUG,
5261*a1157835SDaniel Fojt 				"active_work:%s new_work:%s",
5262*a1157835SDaniel Fojt 				active_work->type, tmp->type);
5263*a1157835SDaniel Fojt 			return tmp;
5264*a1157835SDaniel Fojt 		}
5265*a1157835SDaniel Fojt 	}
5266*a1157835SDaniel Fojt 
5267*a1157835SDaniel Fojt 	/* Did not find a radio work to schedule in parallel. */
5268*a1157835SDaniel Fojt 	return NULL;
5269*a1157835SDaniel Fojt }
5270*a1157835SDaniel Fojt 
5271*a1157835SDaniel Fojt 
radio_start_next_work(void * eloop_ctx,void * timeout_ctx)52723ff40c12SJohn Marino static void radio_start_next_work(void *eloop_ctx, void *timeout_ctx)
52733ff40c12SJohn Marino {
52743ff40c12SJohn Marino 	struct wpa_radio *radio = eloop_ctx;
52753ff40c12SJohn Marino 	struct wpa_radio_work *work;
52763ff40c12SJohn Marino 	struct os_reltime now, diff;
52773ff40c12SJohn Marino 	struct wpa_supplicant *wpa_s;
52783ff40c12SJohn Marino 
52793ff40c12SJohn Marino 	work = dl_list_first(&radio->work, struct wpa_radio_work, list);
5280*a1157835SDaniel Fojt 	if (work == NULL) {
5281*a1157835SDaniel Fojt 		radio->num_active_works = 0;
52823ff40c12SJohn Marino 		return;
5283*a1157835SDaniel Fojt 	}
52843ff40c12SJohn Marino 
52853ff40c12SJohn Marino 	wpa_s = dl_list_first(&radio->ifaces, struct wpa_supplicant,
52863ff40c12SJohn Marino 			      radio_list);
5287*a1157835SDaniel Fojt 
5288*a1157835SDaniel Fojt 	if (!(wpa_s &&
5289*a1157835SDaniel Fojt 	      wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS)) {
5290*a1157835SDaniel Fojt 		if (work->started)
5291*a1157835SDaniel Fojt 			return; /* already started and still in progress */
5292*a1157835SDaniel Fojt 
5293*a1157835SDaniel Fojt 		if (wpa_s && wpa_s->radio->external_scan_running) {
52943ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "Delay radio work start until externally triggered scan completes");
52953ff40c12SJohn Marino 			return;
52963ff40c12SJohn Marino 		}
5297*a1157835SDaniel Fojt 	} else {
5298*a1157835SDaniel Fojt 		work = NULL;
5299*a1157835SDaniel Fojt 		if (radio->num_active_works < MAX_ACTIVE_WORKS) {
5300*a1157835SDaniel Fojt 			/* get the work to schedule next */
5301*a1157835SDaniel Fojt 			work = radio_work_get_next_work(radio);
5302*a1157835SDaniel Fojt 		}
5303*a1157835SDaniel Fojt 		if (!work)
5304*a1157835SDaniel Fojt 			return;
5305*a1157835SDaniel Fojt 	}
53063ff40c12SJohn Marino 
5307*a1157835SDaniel Fojt 	wpa_s = work->wpa_s;
53083ff40c12SJohn Marino 	os_get_reltime(&now);
53093ff40c12SJohn Marino 	os_reltime_sub(&now, &work->time, &diff);
5310*a1157835SDaniel Fojt 	wpa_dbg(wpa_s, MSG_DEBUG,
5311*a1157835SDaniel Fojt 		"Starting radio work '%s'@%p after %ld.%06ld second wait",
53123ff40c12SJohn Marino 		work->type, work, diff.sec, diff.usec);
53133ff40c12SJohn Marino 	work->started = 1;
53143ff40c12SJohn Marino 	work->time = now;
5315*a1157835SDaniel Fojt 	radio->num_active_works++;
5316*a1157835SDaniel Fojt 
53173ff40c12SJohn Marino 	work->cb(work, 0);
5318*a1157835SDaniel Fojt 
5319*a1157835SDaniel Fojt 	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS) &&
5320*a1157835SDaniel Fojt 	    radio->num_active_works < MAX_ACTIVE_WORKS)
5321*a1157835SDaniel Fojt 		radio_work_check_next(wpa_s);
53223ff40c12SJohn Marino }
53233ff40c12SJohn Marino 
53243ff40c12SJohn Marino 
5325*a1157835SDaniel Fojt /*
5326*a1157835SDaniel Fojt  * This function removes both started and pending radio works running on
5327*a1157835SDaniel Fojt  * the provided interface's radio.
5328*a1157835SDaniel Fojt  * Prior to the removal of the radio work, its callback (cb) is called with
5329*a1157835SDaniel Fojt  * deinit set to be 1. Each work's callback is responsible for clearing its
5330*a1157835SDaniel Fojt  * internal data and restoring to a correct state.
5331*a1157835SDaniel Fojt  * @wpa_s: wpa_supplicant data
5332*a1157835SDaniel Fojt  * @type: type of works to be removed
5333*a1157835SDaniel Fojt  * @remove_all: 1 to remove all the works on this radio, 0 to remove only
5334*a1157835SDaniel Fojt  * this interface's works.
5335*a1157835SDaniel Fojt  */
radio_remove_works(struct wpa_supplicant * wpa_s,const char * type,int remove_all)5336*a1157835SDaniel Fojt void radio_remove_works(struct wpa_supplicant *wpa_s,
5337*a1157835SDaniel Fojt 			const char *type, int remove_all)
53383ff40c12SJohn Marino {
53393ff40c12SJohn Marino 	struct wpa_radio_work *work, *tmp;
53403ff40c12SJohn Marino 	struct wpa_radio *radio = wpa_s->radio;
53413ff40c12SJohn Marino 
53423ff40c12SJohn Marino 	dl_list_for_each_safe(work, tmp, &radio->work, struct wpa_radio_work,
53433ff40c12SJohn Marino 			      list) {
5344*a1157835SDaniel Fojt 		if (type && os_strcmp(type, work->type) != 0)
53453ff40c12SJohn Marino 			continue;
5346*a1157835SDaniel Fojt 
5347*a1157835SDaniel Fojt 		/* skip other ifaces' works */
5348*a1157835SDaniel Fojt 		if (!remove_all && work->wpa_s != wpa_s)
53493ff40c12SJohn Marino 			continue;
5350*a1157835SDaniel Fojt 
5351*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG, "Remove radio work '%s'@%p%s",
5352*a1157835SDaniel Fojt 			work->type, work, work->started ? " (started)" : "");
53533ff40c12SJohn Marino 		work->cb(work, 1);
53543ff40c12SJohn Marino 		radio_work_free(work);
53553ff40c12SJohn Marino 	}
5356*a1157835SDaniel Fojt 
5357*a1157835SDaniel Fojt 	/* in case we removed the started work */
5358*a1157835SDaniel Fojt 	radio_work_check_next(wpa_s);
5359*a1157835SDaniel Fojt }
5360*a1157835SDaniel Fojt 
5361*a1157835SDaniel Fojt 
radio_remove_pending_work(struct wpa_supplicant * wpa_s,void * ctx)5362*a1157835SDaniel Fojt void radio_remove_pending_work(struct wpa_supplicant *wpa_s, void *ctx)
5363*a1157835SDaniel Fojt {
5364*a1157835SDaniel Fojt 	struct wpa_radio_work *work;
5365*a1157835SDaniel Fojt 	struct wpa_radio *radio = wpa_s->radio;
5366*a1157835SDaniel Fojt 
5367*a1157835SDaniel Fojt 	dl_list_for_each(work, &radio->work, struct wpa_radio_work, list) {
5368*a1157835SDaniel Fojt 		if (work->ctx != ctx)
5369*a1157835SDaniel Fojt 			continue;
5370*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG, "Free pending radio work '%s'@%p%s",
5371*a1157835SDaniel Fojt 			work->type, work, work->started ? " (started)" : "");
5372*a1157835SDaniel Fojt 		radio_work_free(work);
5373*a1157835SDaniel Fojt 		break;
5374*a1157835SDaniel Fojt 	}
53753ff40c12SJohn Marino }
53763ff40c12SJohn Marino 
53773ff40c12SJohn Marino 
radio_remove_interface(struct wpa_supplicant * wpa_s)53783ff40c12SJohn Marino static void radio_remove_interface(struct wpa_supplicant *wpa_s)
53793ff40c12SJohn Marino {
53803ff40c12SJohn Marino 	struct wpa_radio *radio = wpa_s->radio;
53813ff40c12SJohn Marino 
53823ff40c12SJohn Marino 	if (!radio)
53833ff40c12SJohn Marino 		return;
53843ff40c12SJohn Marino 
53853ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "Remove interface %s from radio %s",
53863ff40c12SJohn Marino 		   wpa_s->ifname, radio->name);
53873ff40c12SJohn Marino 	dl_list_del(&wpa_s->radio_list);
5388*a1157835SDaniel Fojt 	radio_remove_works(wpa_s, NULL, 0);
53893ff40c12SJohn Marino 	wpa_s->radio = NULL;
5390*a1157835SDaniel Fojt 	if (!dl_list_empty(&radio->ifaces))
53913ff40c12SJohn Marino 		return; /* Interfaces remain for this radio */
53923ff40c12SJohn Marino 
53933ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "Remove radio %s", radio->name);
53943ff40c12SJohn Marino 	eloop_cancel_timeout(radio_start_next_work, radio, NULL);
53953ff40c12SJohn Marino 	os_free(radio);
53963ff40c12SJohn Marino }
53973ff40c12SJohn Marino 
53983ff40c12SJohn Marino 
radio_work_check_next(struct wpa_supplicant * wpa_s)53993ff40c12SJohn Marino void radio_work_check_next(struct wpa_supplicant *wpa_s)
54003ff40c12SJohn Marino {
54013ff40c12SJohn Marino 	struct wpa_radio *radio = wpa_s->radio;
54023ff40c12SJohn Marino 
54033ff40c12SJohn Marino 	if (dl_list_empty(&radio->work))
54043ff40c12SJohn Marino 		return;
5405*a1157835SDaniel Fojt 	if (wpa_s->ext_work_in_progress) {
5406*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
5407*a1157835SDaniel Fojt 			   "External radio work in progress - delay start of pending item");
5408*a1157835SDaniel Fojt 		return;
5409*a1157835SDaniel Fojt 	}
54103ff40c12SJohn Marino 	eloop_cancel_timeout(radio_start_next_work, radio, NULL);
54113ff40c12SJohn Marino 	eloop_register_timeout(0, 0, radio_start_next_work, radio, NULL);
54123ff40c12SJohn Marino }
54133ff40c12SJohn Marino 
54143ff40c12SJohn Marino 
54153ff40c12SJohn Marino /**
54163ff40c12SJohn Marino  * radio_add_work - Add a radio work item
54173ff40c12SJohn Marino  * @wpa_s: Pointer to wpa_supplicant data
54183ff40c12SJohn Marino  * @freq: Frequency of the offchannel operation in MHz or 0
54193ff40c12SJohn Marino  * @type: Unique identifier for each type of work
54203ff40c12SJohn Marino  * @next: Force as the next work to be executed
54213ff40c12SJohn Marino  * @cb: Callback function for indicating when radio is available
54223ff40c12SJohn Marino  * @ctx: Context pointer for the work (work->ctx in cb())
54233ff40c12SJohn Marino  * Returns: 0 on success, -1 on failure
54243ff40c12SJohn Marino  *
54253ff40c12SJohn Marino  * This function is used to request time for an operation that requires
54263ff40c12SJohn Marino  * exclusive radio control. Once the radio is available, the registered callback
54273ff40c12SJohn Marino  * function will be called. radio_work_done() must be called once the exclusive
54283ff40c12SJohn Marino  * radio operation has been completed, so that the radio is freed for other
54293ff40c12SJohn Marino  * operations. The special case of deinit=1 is used to free the context data
54303ff40c12SJohn Marino  * during interface removal. That does not allow the callback function to start
54313ff40c12SJohn Marino  * the radio operation, i.e., it must free any resources allocated for the radio
54323ff40c12SJohn Marino  * work and return.
54333ff40c12SJohn Marino  *
54343ff40c12SJohn Marino  * The @freq parameter can be used to indicate a single channel on which the
54353ff40c12SJohn Marino  * offchannel operation will occur. This may allow multiple radio work
54363ff40c12SJohn Marino  * operations to be performed in parallel if they apply for the same channel.
54373ff40c12SJohn Marino  * Setting this to 0 indicates that the work item may use multiple channels or
54383ff40c12SJohn Marino  * requires exclusive control of the radio.
54393ff40c12SJohn Marino  */
radio_add_work(struct wpa_supplicant * wpa_s,unsigned int freq,const char * type,int next,void (* cb)(struct wpa_radio_work * work,int deinit),void * ctx)54403ff40c12SJohn Marino int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq,
54413ff40c12SJohn Marino 		   const char *type, int next,
54423ff40c12SJohn Marino 		   void (*cb)(struct wpa_radio_work *work, int deinit),
54433ff40c12SJohn Marino 		   void *ctx)
54443ff40c12SJohn Marino {
5445*a1157835SDaniel Fojt 	struct wpa_radio *radio = wpa_s->radio;
54463ff40c12SJohn Marino 	struct wpa_radio_work *work;
54473ff40c12SJohn Marino 	int was_empty;
54483ff40c12SJohn Marino 
54493ff40c12SJohn Marino 	work = os_zalloc(sizeof(*work));
54503ff40c12SJohn Marino 	if (work == NULL)
54513ff40c12SJohn Marino 		return -1;
54523ff40c12SJohn Marino 	wpa_dbg(wpa_s, MSG_DEBUG, "Add radio work '%s'@%p", type, work);
54533ff40c12SJohn Marino 	os_get_reltime(&work->time);
54543ff40c12SJohn Marino 	work->freq = freq;
54553ff40c12SJohn Marino 	work->type = type;
54563ff40c12SJohn Marino 	work->wpa_s = wpa_s;
54573ff40c12SJohn Marino 	work->cb = cb;
54583ff40c12SJohn Marino 	work->ctx = ctx;
54593ff40c12SJohn Marino 
5460*a1157835SDaniel Fojt 	if (freq)
5461*a1157835SDaniel Fojt 		work->bands = wpas_freq_to_band(freq);
5462*a1157835SDaniel Fojt 	else if (os_strcmp(type, "scan") == 0 ||
5463*a1157835SDaniel Fojt 		 os_strcmp(type, "p2p-scan") == 0)
5464*a1157835SDaniel Fojt 		work->bands = wpas_get_bands(wpa_s,
5465*a1157835SDaniel Fojt 					     ((struct wpa_driver_scan_params *)
5466*a1157835SDaniel Fojt 					      ctx)->freqs);
5467*a1157835SDaniel Fojt 	else
5468*a1157835SDaniel Fojt 		work->bands = wpas_get_bands(wpa_s, NULL);
5469*a1157835SDaniel Fojt 
54703ff40c12SJohn Marino 	was_empty = dl_list_empty(&wpa_s->radio->work);
54713ff40c12SJohn Marino 	if (next)
54723ff40c12SJohn Marino 		dl_list_add(&wpa_s->radio->work, &work->list);
54733ff40c12SJohn Marino 	else
54743ff40c12SJohn Marino 		dl_list_add_tail(&wpa_s->radio->work, &work->list);
54753ff40c12SJohn Marino 	if (was_empty) {
54763ff40c12SJohn Marino 		wpa_dbg(wpa_s, MSG_DEBUG, "First radio work item in the queue - schedule start immediately");
54773ff40c12SJohn Marino 		radio_work_check_next(wpa_s);
5478*a1157835SDaniel Fojt 	} else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS)
5479*a1157835SDaniel Fojt 		   && radio->num_active_works < MAX_ACTIVE_WORKS) {
5480*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG,
5481*a1157835SDaniel Fojt 			"Try to schedule a radio work (num_active_works=%u)",
5482*a1157835SDaniel Fojt 			radio->num_active_works);
5483*a1157835SDaniel Fojt 		radio_work_check_next(wpa_s);
54843ff40c12SJohn Marino 	}
54853ff40c12SJohn Marino 
54863ff40c12SJohn Marino 	return 0;
54873ff40c12SJohn Marino }
54883ff40c12SJohn Marino 
54893ff40c12SJohn Marino 
54903ff40c12SJohn Marino /**
54913ff40c12SJohn Marino  * radio_work_done - Indicate that a radio work item has been completed
54923ff40c12SJohn Marino  * @work: Completed work
54933ff40c12SJohn Marino  *
54943ff40c12SJohn Marino  * This function is called once the callback function registered with
54953ff40c12SJohn Marino  * radio_add_work() has completed its work.
54963ff40c12SJohn Marino  */
radio_work_done(struct wpa_radio_work * work)54973ff40c12SJohn Marino void radio_work_done(struct wpa_radio_work *work)
54983ff40c12SJohn Marino {
54993ff40c12SJohn Marino 	struct wpa_supplicant *wpa_s = work->wpa_s;
55003ff40c12SJohn Marino 	struct os_reltime now, diff;
55013ff40c12SJohn Marino 	unsigned int started = work->started;
55023ff40c12SJohn Marino 
55033ff40c12SJohn Marino 	os_get_reltime(&now);
55043ff40c12SJohn Marino 	os_reltime_sub(&now, &work->time, &diff);
55053ff40c12SJohn Marino 	wpa_dbg(wpa_s, MSG_DEBUG, "Radio work '%s'@%p %s in %ld.%06ld seconds",
55063ff40c12SJohn Marino 		work->type, work, started ? "done" : "canceled",
55073ff40c12SJohn Marino 		diff.sec, diff.usec);
55083ff40c12SJohn Marino 	radio_work_free(work);
55093ff40c12SJohn Marino 	if (started)
55103ff40c12SJohn Marino 		radio_work_check_next(wpa_s);
55113ff40c12SJohn Marino }
55123ff40c12SJohn Marino 
55133ff40c12SJohn Marino 
5514*a1157835SDaniel Fojt struct wpa_radio_work *
radio_work_pending(struct wpa_supplicant * wpa_s,const char * type)5515*a1157835SDaniel Fojt radio_work_pending(struct wpa_supplicant *wpa_s, const char *type)
5516*a1157835SDaniel Fojt {
5517*a1157835SDaniel Fojt 	struct wpa_radio_work *work;
5518*a1157835SDaniel Fojt 	struct wpa_radio *radio = wpa_s->radio;
5519*a1157835SDaniel Fojt 
5520*a1157835SDaniel Fojt 	dl_list_for_each(work, &radio->work, struct wpa_radio_work, list) {
5521*a1157835SDaniel Fojt 		if (work->wpa_s == wpa_s && os_strcmp(work->type, type) == 0)
5522*a1157835SDaniel Fojt 			return work;
5523*a1157835SDaniel Fojt 	}
5524*a1157835SDaniel Fojt 
5525*a1157835SDaniel Fojt 	return NULL;
5526*a1157835SDaniel Fojt }
5527*a1157835SDaniel Fojt 
5528*a1157835SDaniel Fojt 
wpas_init_driver(struct wpa_supplicant * wpa_s,const struct wpa_interface * iface)55293ff40c12SJohn Marino static int wpas_init_driver(struct wpa_supplicant *wpa_s,
5530*a1157835SDaniel Fojt 			    const struct wpa_interface *iface)
55313ff40c12SJohn Marino {
55323ff40c12SJohn Marino 	const char *ifname, *driver, *rn;
55333ff40c12SJohn Marino 
55343ff40c12SJohn Marino 	driver = iface->driver;
55353ff40c12SJohn Marino next_driver:
55363ff40c12SJohn Marino 	if (wpa_supplicant_set_driver(wpa_s, driver) < 0)
55373ff40c12SJohn Marino 		return -1;
55383ff40c12SJohn Marino 
55393ff40c12SJohn Marino 	wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
55403ff40c12SJohn Marino 	if (wpa_s->drv_priv == NULL) {
55413ff40c12SJohn Marino 		const char *pos;
55423ff40c12SJohn Marino 		pos = driver ? os_strchr(driver, ',') : NULL;
55433ff40c12SJohn Marino 		if (pos) {
55443ff40c12SJohn Marino 			wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
55453ff40c12SJohn Marino 				"driver interface - try next driver wrapper");
55463ff40c12SJohn Marino 			driver = pos + 1;
55473ff40c12SJohn Marino 			goto next_driver;
55483ff40c12SJohn Marino 		}
55493ff40c12SJohn Marino 		wpa_msg(wpa_s, MSG_ERROR, "Failed to initialize driver "
55503ff40c12SJohn Marino 			"interface");
55513ff40c12SJohn Marino 		return -1;
55523ff40c12SJohn Marino 	}
55533ff40c12SJohn Marino 	if (wpa_drv_set_param(wpa_s, wpa_s->conf->driver_param) < 0) {
55543ff40c12SJohn Marino 		wpa_msg(wpa_s, MSG_ERROR, "Driver interface rejected "
55553ff40c12SJohn Marino 			"driver_param '%s'", wpa_s->conf->driver_param);
55563ff40c12SJohn Marino 		return -1;
55573ff40c12SJohn Marino 	}
55583ff40c12SJohn Marino 
55593ff40c12SJohn Marino 	ifname = wpa_drv_get_ifname(wpa_s);
55603ff40c12SJohn Marino 	if (ifname && os_strcmp(ifname, wpa_s->ifname) != 0) {
55613ff40c12SJohn Marino 		wpa_dbg(wpa_s, MSG_DEBUG, "Driver interface replaced "
55623ff40c12SJohn Marino 			"interface name with '%s'", ifname);
55633ff40c12SJohn Marino 		os_strlcpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
55643ff40c12SJohn Marino 	}
55653ff40c12SJohn Marino 
5566*a1157835SDaniel Fojt 	rn = wpa_driver_get_radio_name(wpa_s);
55673ff40c12SJohn Marino 	if (rn && rn[0] == '\0')
55683ff40c12SJohn Marino 		rn = NULL;
55693ff40c12SJohn Marino 
55703ff40c12SJohn Marino 	wpa_s->radio = radio_add_interface(wpa_s, rn);
55713ff40c12SJohn Marino 	if (wpa_s->radio == NULL)
55723ff40c12SJohn Marino 		return -1;
55733ff40c12SJohn Marino 
55743ff40c12SJohn Marino 	return 0;
55753ff40c12SJohn Marino }
55763ff40c12SJohn Marino 
55773ff40c12SJohn Marino 
5578*a1157835SDaniel Fojt #ifdef CONFIG_GAS_SERVER
5579*a1157835SDaniel Fojt 
wpas_gas_server_tx_status(struct wpa_supplicant * wpa_s,unsigned int freq,const u8 * dst,const u8 * src,const u8 * bssid,const u8 * data,size_t data_len,enum offchannel_send_action_result result)5580*a1157835SDaniel Fojt static void wpas_gas_server_tx_status(struct wpa_supplicant *wpa_s,
5581*a1157835SDaniel Fojt 				      unsigned int freq, const u8 *dst,
5582*a1157835SDaniel Fojt 				      const u8 *src, const u8 *bssid,
5583*a1157835SDaniel Fojt 				      const u8 *data, size_t data_len,
5584*a1157835SDaniel Fojt 				      enum offchannel_send_action_result result)
5585*a1157835SDaniel Fojt {
5586*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "GAS: TX status: freq=%u dst=" MACSTR
5587*a1157835SDaniel Fojt 		   " result=%s",
5588*a1157835SDaniel Fojt 		   freq, MAC2STR(dst),
5589*a1157835SDaniel Fojt 		   result == OFFCHANNEL_SEND_ACTION_SUCCESS ? "SUCCESS" :
5590*a1157835SDaniel Fojt 		   (result == OFFCHANNEL_SEND_ACTION_NO_ACK ? "no-ACK" :
5591*a1157835SDaniel Fojt 		    "FAILED"));
5592*a1157835SDaniel Fojt 	gas_server_tx_status(wpa_s->gas_server, dst, data, data_len,
5593*a1157835SDaniel Fojt 			     result == OFFCHANNEL_SEND_ACTION_SUCCESS);
5594*a1157835SDaniel Fojt }
5595*a1157835SDaniel Fojt 
5596*a1157835SDaniel Fojt 
wpas_gas_server_tx(void * ctx,int freq,const u8 * da,struct wpabuf * buf,unsigned int wait_time)5597*a1157835SDaniel Fojt static void wpas_gas_server_tx(void *ctx, int freq, const u8 *da,
5598*a1157835SDaniel Fojt 			       struct wpabuf *buf, unsigned int wait_time)
5599*a1157835SDaniel Fojt {
5600*a1157835SDaniel Fojt 	struct wpa_supplicant *wpa_s = ctx;
5601*a1157835SDaniel Fojt 	const u8 broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
5602*a1157835SDaniel Fojt 
5603*a1157835SDaniel Fojt 	if (wait_time > wpa_s->max_remain_on_chan)
5604*a1157835SDaniel Fojt 		wait_time = wpa_s->max_remain_on_chan;
5605*a1157835SDaniel Fojt 
5606*a1157835SDaniel Fojt 	offchannel_send_action(wpa_s, freq, da, wpa_s->own_addr, broadcast,
5607*a1157835SDaniel Fojt 			       wpabuf_head(buf), wpabuf_len(buf),
5608*a1157835SDaniel Fojt 			       wait_time, wpas_gas_server_tx_status, 0);
5609*a1157835SDaniel Fojt }
5610*a1157835SDaniel Fojt 
5611*a1157835SDaniel Fojt #endif /* CONFIG_GAS_SERVER */
5612*a1157835SDaniel Fojt 
wpa_supplicant_init_iface(struct wpa_supplicant * wpa_s,const struct wpa_interface * iface)56136d49e1aeSJan Lentfer static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
5614*a1157835SDaniel Fojt 				     const struct wpa_interface *iface)
56156d49e1aeSJan Lentfer {
56163ff40c12SJohn Marino 	struct wpa_driver_capa capa;
5617*a1157835SDaniel Fojt 	int capa_res;
5618*a1157835SDaniel Fojt 	u8 dfs_domain;
56193ff40c12SJohn Marino 
56206d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "Initializing interface '%s' conf '%s' driver "
56216d49e1aeSJan Lentfer 		   "'%s' ctrl_interface '%s' bridge '%s'", iface->ifname,
56226d49e1aeSJan Lentfer 		   iface->confname ? iface->confname : "N/A",
56236d49e1aeSJan Lentfer 		   iface->driver ? iface->driver : "default",
56246d49e1aeSJan Lentfer 		   iface->ctrl_interface ? iface->ctrl_interface : "N/A",
56256d49e1aeSJan Lentfer 		   iface->bridge_ifname ? iface->bridge_ifname : "N/A");
56266d49e1aeSJan Lentfer 
56276d49e1aeSJan Lentfer 	if (iface->confname) {
56286d49e1aeSJan Lentfer #ifdef CONFIG_BACKEND_FILE
56296d49e1aeSJan Lentfer 		wpa_s->confname = os_rel2abs_path(iface->confname);
56306d49e1aeSJan Lentfer 		if (wpa_s->confname == NULL) {
56316d49e1aeSJan Lentfer 			wpa_printf(MSG_ERROR, "Failed to get absolute path "
56326d49e1aeSJan Lentfer 				   "for configuration file '%s'.",
56336d49e1aeSJan Lentfer 				   iface->confname);
56346d49e1aeSJan Lentfer 			return -1;
56356d49e1aeSJan Lentfer 		}
56366d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "Configuration file '%s' -> '%s'",
56376d49e1aeSJan Lentfer 			   iface->confname, wpa_s->confname);
56386d49e1aeSJan Lentfer #else /* CONFIG_BACKEND_FILE */
56396d49e1aeSJan Lentfer 		wpa_s->confname = os_strdup(iface->confname);
56406d49e1aeSJan Lentfer #endif /* CONFIG_BACKEND_FILE */
56413ff40c12SJohn Marino 		wpa_s->conf = wpa_config_read(wpa_s->confname, NULL);
56426d49e1aeSJan Lentfer 		if (wpa_s->conf == NULL) {
56436d49e1aeSJan Lentfer 			wpa_printf(MSG_ERROR, "Failed to read or parse "
56446d49e1aeSJan Lentfer 				   "configuration '%s'.", wpa_s->confname);
56456d49e1aeSJan Lentfer 			return -1;
56466d49e1aeSJan Lentfer 		}
56473ff40c12SJohn Marino 		wpa_s->confanother = os_rel2abs_path(iface->confanother);
5648*a1157835SDaniel Fojt 		if (wpa_s->confanother &&
5649*a1157835SDaniel Fojt 		    !wpa_config_read(wpa_s->confanother, wpa_s->conf)) {
5650*a1157835SDaniel Fojt 			wpa_printf(MSG_ERROR,
5651*a1157835SDaniel Fojt 				   "Failed to read or parse configuration '%s'.",
5652*a1157835SDaniel Fojt 				   wpa_s->confanother);
5653*a1157835SDaniel Fojt 			return -1;
5654*a1157835SDaniel Fojt 		}
56556d49e1aeSJan Lentfer 
56566d49e1aeSJan Lentfer 		/*
56576d49e1aeSJan Lentfer 		 * Override ctrl_interface and driver_param if set on command
56586d49e1aeSJan Lentfer 		 * line.
56596d49e1aeSJan Lentfer 		 */
56606d49e1aeSJan Lentfer 		if (iface->ctrl_interface) {
56616d49e1aeSJan Lentfer 			os_free(wpa_s->conf->ctrl_interface);
56626d49e1aeSJan Lentfer 			wpa_s->conf->ctrl_interface =
56636d49e1aeSJan Lentfer 				os_strdup(iface->ctrl_interface);
56646d49e1aeSJan Lentfer 		}
56656d49e1aeSJan Lentfer 
56666d49e1aeSJan Lentfer 		if (iface->driver_param) {
56676d49e1aeSJan Lentfer 			os_free(wpa_s->conf->driver_param);
56686d49e1aeSJan Lentfer 			wpa_s->conf->driver_param =
56696d49e1aeSJan Lentfer 				os_strdup(iface->driver_param);
56706d49e1aeSJan Lentfer 		}
56713ff40c12SJohn Marino 
56723ff40c12SJohn Marino 		if (iface->p2p_mgmt && !iface->ctrl_interface) {
56733ff40c12SJohn Marino 			os_free(wpa_s->conf->ctrl_interface);
56743ff40c12SJohn Marino 			wpa_s->conf->ctrl_interface = NULL;
56753ff40c12SJohn Marino 		}
56766d49e1aeSJan Lentfer 	} else
56776d49e1aeSJan Lentfer 		wpa_s->conf = wpa_config_alloc_empty(iface->ctrl_interface,
56786d49e1aeSJan Lentfer 						     iface->driver_param);
56796d49e1aeSJan Lentfer 
56806d49e1aeSJan Lentfer 	if (wpa_s->conf == NULL) {
56816d49e1aeSJan Lentfer 		wpa_printf(MSG_ERROR, "\nNo configuration found.");
56826d49e1aeSJan Lentfer 		return -1;
56836d49e1aeSJan Lentfer 	}
56846d49e1aeSJan Lentfer 
56856d49e1aeSJan Lentfer 	if (iface->ifname == NULL) {
56866d49e1aeSJan Lentfer 		wpa_printf(MSG_ERROR, "\nInterface name is required.");
56876d49e1aeSJan Lentfer 		return -1;
56886d49e1aeSJan Lentfer 	}
56896d49e1aeSJan Lentfer 	if (os_strlen(iface->ifname) >= sizeof(wpa_s->ifname)) {
56906d49e1aeSJan Lentfer 		wpa_printf(MSG_ERROR, "\nToo long interface name '%s'.",
56916d49e1aeSJan Lentfer 			   iface->ifname);
56926d49e1aeSJan Lentfer 		return -1;
56936d49e1aeSJan Lentfer 	}
56946d49e1aeSJan Lentfer 	os_strlcpy(wpa_s->ifname, iface->ifname, sizeof(wpa_s->ifname));
56956d49e1aeSJan Lentfer 
56966d49e1aeSJan Lentfer 	if (iface->bridge_ifname) {
56976d49e1aeSJan Lentfer 		if (os_strlen(iface->bridge_ifname) >=
56986d49e1aeSJan Lentfer 		    sizeof(wpa_s->bridge_ifname)) {
56996d49e1aeSJan Lentfer 			wpa_printf(MSG_ERROR, "\nToo long bridge interface "
57006d49e1aeSJan Lentfer 				   "name '%s'.", iface->bridge_ifname);
57016d49e1aeSJan Lentfer 			return -1;
57026d49e1aeSJan Lentfer 		}
57036d49e1aeSJan Lentfer 		os_strlcpy(wpa_s->bridge_ifname, iface->bridge_ifname,
57046d49e1aeSJan Lentfer 			   sizeof(wpa_s->bridge_ifname));
57056d49e1aeSJan Lentfer 	}
57066d49e1aeSJan Lentfer 
57076d49e1aeSJan Lentfer 	/* RSNA Supplicant Key Management - INITIALIZE */
57086d49e1aeSJan Lentfer 	eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
57096d49e1aeSJan Lentfer 	eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
57106d49e1aeSJan Lentfer 
57116d49e1aeSJan Lentfer 	/* Initialize driver interface and register driver event handler before
57126d49e1aeSJan Lentfer 	 * L2 receive handler so that association events are processed before
57136d49e1aeSJan Lentfer 	 * EAPOL-Key packets if both become available for the same select()
57146d49e1aeSJan Lentfer 	 * call. */
57153ff40c12SJohn Marino 	if (wpas_init_driver(wpa_s, iface) < 0)
57166d49e1aeSJan Lentfer 		return -1;
57176d49e1aeSJan Lentfer 
57186d49e1aeSJan Lentfer 	if (wpa_supplicant_init_wpa(wpa_s) < 0)
57196d49e1aeSJan Lentfer 		return -1;
57206d49e1aeSJan Lentfer 
57216d49e1aeSJan Lentfer 	wpa_sm_set_ifname(wpa_s->wpa, wpa_s->ifname,
57226d49e1aeSJan Lentfer 			  wpa_s->bridge_ifname[0] ? wpa_s->bridge_ifname :
57236d49e1aeSJan Lentfer 			  NULL);
57246d49e1aeSJan Lentfer 	wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
57256d49e1aeSJan Lentfer 
57266d49e1aeSJan Lentfer 	if (wpa_s->conf->dot11RSNAConfigPMKLifetime &&
57276d49e1aeSJan Lentfer 	    wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
57286d49e1aeSJan Lentfer 			     wpa_s->conf->dot11RSNAConfigPMKLifetime)) {
57293ff40c12SJohn Marino 		wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for "
57306d49e1aeSJan Lentfer 			"dot11RSNAConfigPMKLifetime");
57316d49e1aeSJan Lentfer 		return -1;
57326d49e1aeSJan Lentfer 	}
57336d49e1aeSJan Lentfer 
57346d49e1aeSJan Lentfer 	if (wpa_s->conf->dot11RSNAConfigPMKReauthThreshold &&
57356d49e1aeSJan Lentfer 	    wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
57366d49e1aeSJan Lentfer 			     wpa_s->conf->dot11RSNAConfigPMKReauthThreshold)) {
57373ff40c12SJohn Marino 		wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for "
57386d49e1aeSJan Lentfer 			"dot11RSNAConfigPMKReauthThreshold");
57396d49e1aeSJan Lentfer 		return -1;
57406d49e1aeSJan Lentfer 	}
57416d49e1aeSJan Lentfer 
57426d49e1aeSJan Lentfer 	if (wpa_s->conf->dot11RSNAConfigSATimeout &&
57436d49e1aeSJan Lentfer 	    wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT,
57446d49e1aeSJan Lentfer 			     wpa_s->conf->dot11RSNAConfigSATimeout)) {
57453ff40c12SJohn Marino 		wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for "
57466d49e1aeSJan Lentfer 			"dot11RSNAConfigSATimeout");
57476d49e1aeSJan Lentfer 		return -1;
57486d49e1aeSJan Lentfer 	}
57496d49e1aeSJan Lentfer 
57503ff40c12SJohn Marino 	wpa_s->hw.modes = wpa_drv_get_hw_feature_data(wpa_s,
57513ff40c12SJohn Marino 						      &wpa_s->hw.num_modes,
5752*a1157835SDaniel Fojt 						      &wpa_s->hw.flags,
5753*a1157835SDaniel Fojt 						      &dfs_domain);
5754*a1157835SDaniel Fojt 	if (wpa_s->hw.modes) {
5755*a1157835SDaniel Fojt 		u16 i;
57563ff40c12SJohn Marino 
5757*a1157835SDaniel Fojt 		for (i = 0; i < wpa_s->hw.num_modes; i++) {
5758*a1157835SDaniel Fojt 			if (wpa_s->hw.modes[i].vht_capab) {
5759*a1157835SDaniel Fojt 				wpa_s->hw_capab = CAPAB_VHT;
5760*a1157835SDaniel Fojt 				break;
5761*a1157835SDaniel Fojt 			}
5762*a1157835SDaniel Fojt 
5763*a1157835SDaniel Fojt 			if (wpa_s->hw.modes[i].ht_capab &
5764*a1157835SDaniel Fojt 			    HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)
5765*a1157835SDaniel Fojt 				wpa_s->hw_capab = CAPAB_HT40;
5766*a1157835SDaniel Fojt 			else if (wpa_s->hw.modes[i].ht_capab &&
5767*a1157835SDaniel Fojt 				 wpa_s->hw_capab == CAPAB_NO_HT_VHT)
5768*a1157835SDaniel Fojt 				wpa_s->hw_capab = CAPAB_HT;
5769*a1157835SDaniel Fojt 		}
5770*a1157835SDaniel Fojt 	}
5771*a1157835SDaniel Fojt 
5772*a1157835SDaniel Fojt 	capa_res = wpa_drv_get_capa(wpa_s, &capa);
5773*a1157835SDaniel Fojt 	if (capa_res == 0) {
57743ff40c12SJohn Marino 		wpa_s->drv_capa_known = 1;
57753ff40c12SJohn Marino 		wpa_s->drv_flags = capa.flags;
57763ff40c12SJohn Marino 		wpa_s->drv_enc = capa.enc;
5777*a1157835SDaniel Fojt 		wpa_s->drv_smps_modes = capa.smps_modes;
5778*a1157835SDaniel Fojt 		wpa_s->drv_rrm_flags = capa.rrm_flags;
57793ff40c12SJohn Marino 		wpa_s->probe_resp_offloads = capa.probe_resp_offloads;
57803ff40c12SJohn Marino 		wpa_s->max_scan_ssids = capa.max_scan_ssids;
57813ff40c12SJohn Marino 		wpa_s->max_sched_scan_ssids = capa.max_sched_scan_ssids;
5782*a1157835SDaniel Fojt 		wpa_s->max_sched_scan_plans = capa.max_sched_scan_plans;
5783*a1157835SDaniel Fojt 		wpa_s->max_sched_scan_plan_interval =
5784*a1157835SDaniel Fojt 			capa.max_sched_scan_plan_interval;
5785*a1157835SDaniel Fojt 		wpa_s->max_sched_scan_plan_iterations =
5786*a1157835SDaniel Fojt 			capa.max_sched_scan_plan_iterations;
57873ff40c12SJohn Marino 		wpa_s->sched_scan_supported = capa.sched_scan_supported;
57883ff40c12SJohn Marino 		wpa_s->max_match_sets = capa.max_match_sets;
57893ff40c12SJohn Marino 		wpa_s->max_remain_on_chan = capa.max_remain_on_chan;
57903ff40c12SJohn Marino 		wpa_s->max_stations = capa.max_stations;
57913ff40c12SJohn Marino 		wpa_s->extended_capa = capa.extended_capa;
57923ff40c12SJohn Marino 		wpa_s->extended_capa_mask = capa.extended_capa_mask;
57933ff40c12SJohn Marino 		wpa_s->extended_capa_len = capa.extended_capa_len;
57943ff40c12SJohn Marino 		wpa_s->num_multichan_concurrent =
57953ff40c12SJohn Marino 			capa.num_multichan_concurrent;
5796*a1157835SDaniel Fojt 		wpa_s->wmm_ac_supported = capa.wmm_ac_supported;
5797*a1157835SDaniel Fojt 
5798*a1157835SDaniel Fojt 		if (capa.mac_addr_rand_scan_supported)
5799*a1157835SDaniel Fojt 			wpa_s->mac_addr_rand_supported |= MAC_ADDR_RAND_SCAN;
5800*a1157835SDaniel Fojt 		if (wpa_s->sched_scan_supported &&
5801*a1157835SDaniel Fojt 		    capa.mac_addr_rand_sched_scan_supported)
5802*a1157835SDaniel Fojt 			wpa_s->mac_addr_rand_supported |=
5803*a1157835SDaniel Fojt 				(MAC_ADDR_RAND_SCHED_SCAN | MAC_ADDR_RAND_PNO);
5804*a1157835SDaniel Fojt 
5805*a1157835SDaniel Fojt 		wpa_drv_get_ext_capa(wpa_s, WPA_IF_STATION);
5806*a1157835SDaniel Fojt 		if (wpa_s->extended_capa &&
5807*a1157835SDaniel Fojt 		    wpa_s->extended_capa_len >= 3 &&
5808*a1157835SDaniel Fojt 		    wpa_s->extended_capa[2] & 0x40)
5809*a1157835SDaniel Fojt 			wpa_s->multi_bss_support = 1;
58103ff40c12SJohn Marino 	}
58113ff40c12SJohn Marino 	if (wpa_s->max_remain_on_chan == 0)
58123ff40c12SJohn Marino 		wpa_s->max_remain_on_chan = 1000;
58133ff40c12SJohn Marino 
58143ff40c12SJohn Marino 	/*
58153ff40c12SJohn Marino 	 * Only take p2p_mgmt parameters when P2P Device is supported.
58163ff40c12SJohn Marino 	 * Doing it here as it determines whether l2_packet_init() will be done
58173ff40c12SJohn Marino 	 * during wpa_supplicant_driver_init().
58183ff40c12SJohn Marino 	 */
58193ff40c12SJohn Marino 	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)
58203ff40c12SJohn Marino 		wpa_s->p2p_mgmt = iface->p2p_mgmt;
58213ff40c12SJohn Marino 
58223ff40c12SJohn Marino 	if (wpa_s->num_multichan_concurrent == 0)
58233ff40c12SJohn Marino 		wpa_s->num_multichan_concurrent = 1;
58243ff40c12SJohn Marino 
58256d49e1aeSJan Lentfer 	if (wpa_supplicant_driver_init(wpa_s) < 0)
58266d49e1aeSJan Lentfer 		return -1;
58276d49e1aeSJan Lentfer 
58283ff40c12SJohn Marino #ifdef CONFIG_TDLS
5829*a1157835SDaniel Fojt 	if (!iface->p2p_mgmt && wpa_tdls_init(wpa_s->wpa))
58303ff40c12SJohn Marino 		return -1;
58313ff40c12SJohn Marino #endif /* CONFIG_TDLS */
58323ff40c12SJohn Marino 
58336d49e1aeSJan Lentfer 	if (wpa_s->conf->country[0] && wpa_s->conf->country[1] &&
58346d49e1aeSJan Lentfer 	    wpa_drv_set_country(wpa_s, wpa_s->conf->country)) {
58353ff40c12SJohn Marino 		wpa_dbg(wpa_s, MSG_DEBUG, "Failed to set country");
58366d49e1aeSJan Lentfer 		return -1;
58376d49e1aeSJan Lentfer 	}
58386d49e1aeSJan Lentfer 
5839*a1157835SDaniel Fojt #ifdef CONFIG_FST
5840*a1157835SDaniel Fojt 	if (wpa_s->conf->fst_group_id) {
5841*a1157835SDaniel Fojt 		struct fst_iface_cfg cfg;
5842*a1157835SDaniel Fojt 		struct fst_wpa_obj iface_obj;
5843*a1157835SDaniel Fojt 
5844*a1157835SDaniel Fojt 		fst_wpa_supplicant_fill_iface_obj(wpa_s, &iface_obj);
5845*a1157835SDaniel Fojt 		os_strlcpy(cfg.group_id, wpa_s->conf->fst_group_id,
5846*a1157835SDaniel Fojt 			   sizeof(cfg.group_id));
5847*a1157835SDaniel Fojt 		cfg.priority = wpa_s->conf->fst_priority;
5848*a1157835SDaniel Fojt 		cfg.llt = wpa_s->conf->fst_llt;
5849*a1157835SDaniel Fojt 
5850*a1157835SDaniel Fojt 		wpa_s->fst = fst_attach(wpa_s->ifname, wpa_s->own_addr,
5851*a1157835SDaniel Fojt 					&iface_obj, &cfg);
5852*a1157835SDaniel Fojt 		if (!wpa_s->fst) {
5853*a1157835SDaniel Fojt 			wpa_msg(wpa_s, MSG_ERROR,
5854*a1157835SDaniel Fojt 				"FST: Cannot attach iface %s to group %s",
5855*a1157835SDaniel Fojt 				wpa_s->ifname, cfg.group_id);
5856*a1157835SDaniel Fojt 			return -1;
5857*a1157835SDaniel Fojt 		}
5858*a1157835SDaniel Fojt 	}
5859*a1157835SDaniel Fojt #endif /* CONFIG_FST */
5860*a1157835SDaniel Fojt 
58616d49e1aeSJan Lentfer 	if (wpas_wps_init(wpa_s))
58626d49e1aeSJan Lentfer 		return -1;
58636d49e1aeSJan Lentfer 
5864*a1157835SDaniel Fojt #ifdef CONFIG_GAS_SERVER
5865*a1157835SDaniel Fojt 	wpa_s->gas_server = gas_server_init(wpa_s, wpas_gas_server_tx);
5866*a1157835SDaniel Fojt 	if (!wpa_s->gas_server) {
5867*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "Failed to initialize GAS server");
5868*a1157835SDaniel Fojt 		return -1;
5869*a1157835SDaniel Fojt 	}
5870*a1157835SDaniel Fojt #endif /* CONFIG_GAS_SERVER */
5871*a1157835SDaniel Fojt 
5872*a1157835SDaniel Fojt #ifdef CONFIG_DPP
5873*a1157835SDaniel Fojt 	if (wpas_dpp_init(wpa_s) < 0)
5874*a1157835SDaniel Fojt 		return -1;
5875*a1157835SDaniel Fojt #endif /* CONFIG_DPP */
5876*a1157835SDaniel Fojt 
58776d49e1aeSJan Lentfer 	if (wpa_supplicant_init_eapol(wpa_s) < 0)
58786d49e1aeSJan Lentfer 		return -1;
58796d49e1aeSJan Lentfer 	wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
58806d49e1aeSJan Lentfer 
58816d49e1aeSJan Lentfer 	wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
58826d49e1aeSJan Lentfer 	if (wpa_s->ctrl_iface == NULL) {
58836d49e1aeSJan Lentfer 		wpa_printf(MSG_ERROR,
58846d49e1aeSJan Lentfer 			   "Failed to initialize control interface '%s'.\n"
58856d49e1aeSJan Lentfer 			   "You may have another wpa_supplicant process "
58866d49e1aeSJan Lentfer 			   "already running or the file was\n"
58876d49e1aeSJan Lentfer 			   "left by an unclean termination of wpa_supplicant "
58886d49e1aeSJan Lentfer 			   "in which case you will need\n"
58896d49e1aeSJan Lentfer 			   "to manually remove this file before starting "
58906d49e1aeSJan Lentfer 			   "wpa_supplicant again.\n",
58916d49e1aeSJan Lentfer 			   wpa_s->conf->ctrl_interface);
58926d49e1aeSJan Lentfer 		return -1;
58936d49e1aeSJan Lentfer 	}
58946d49e1aeSJan Lentfer 
58953ff40c12SJohn Marino 	wpa_s->gas = gas_query_init(wpa_s);
58963ff40c12SJohn Marino 	if (wpa_s->gas == NULL) {
58973ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Failed to initialize GAS query");
58986d49e1aeSJan Lentfer 		return -1;
58996d49e1aeSJan Lentfer 	}
59003ff40c12SJohn Marino 
5901*a1157835SDaniel Fojt 	if ((!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) ||
5902*a1157835SDaniel Fojt 	     wpa_s->p2p_mgmt) &&
5903*a1157835SDaniel Fojt 	    wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
59043ff40c12SJohn Marino 		wpa_msg(wpa_s, MSG_ERROR, "Failed to init P2P");
59053ff40c12SJohn Marino 		return -1;
59066d49e1aeSJan Lentfer 	}
59073ff40c12SJohn Marino 
59083ff40c12SJohn Marino 	if (wpa_bss_init(wpa_s) < 0)
59093ff40c12SJohn Marino 		return -1;
59103ff40c12SJohn Marino 
5911*a1157835SDaniel Fojt #ifdef CONFIG_PMKSA_CACHE_EXTERNAL
5912*a1157835SDaniel Fojt #ifdef CONFIG_MESH
5913*a1157835SDaniel Fojt 	dl_list_init(&wpa_s->mesh_external_pmksa_cache);
5914*a1157835SDaniel Fojt #endif /* CONFIG_MESH */
5915*a1157835SDaniel Fojt #endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
5916*a1157835SDaniel Fojt 
5917*a1157835SDaniel Fojt 	/*
5918*a1157835SDaniel Fojt 	 * Set Wake-on-WLAN triggers, if configured.
5919*a1157835SDaniel Fojt 	 * Note: We don't restore/remove the triggers on shutdown (it doesn't
5920*a1157835SDaniel Fojt 	 * have effect anyway when the interface is down).
5921*a1157835SDaniel Fojt 	 */
5922*a1157835SDaniel Fojt 	if (capa_res == 0 && wpas_set_wowlan_triggers(wpa_s, &capa) < 0)
5923*a1157835SDaniel Fojt 		return -1;
5924*a1157835SDaniel Fojt 
59253ff40c12SJohn Marino #ifdef CONFIG_EAP_PROXY
59263ff40c12SJohn Marino {
59273ff40c12SJohn Marino 	size_t len;
5928*a1157835SDaniel Fojt 	wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol, -1,
5929*a1157835SDaniel Fojt 						     wpa_s->imsi, &len);
59303ff40c12SJohn Marino 	if (wpa_s->mnc_len > 0) {
59313ff40c12SJohn Marino 		wpa_s->imsi[len] = '\0';
59323ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "eap_proxy: IMSI %s (MNC length %d)",
59333ff40c12SJohn Marino 			   wpa_s->imsi, wpa_s->mnc_len);
59343ff40c12SJohn Marino 	} else {
59353ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available");
59363ff40c12SJohn Marino 	}
59373ff40c12SJohn Marino }
59383ff40c12SJohn Marino #endif /* CONFIG_EAP_PROXY */
59393ff40c12SJohn Marino 
59403ff40c12SJohn Marino 	if (pcsc_reader_init(wpa_s) < 0)
59413ff40c12SJohn Marino 		return -1;
59423ff40c12SJohn Marino 
59433ff40c12SJohn Marino 	if (wpas_init_ext_pw(wpa_s) < 0)
59443ff40c12SJohn Marino 		return -1;
59456d49e1aeSJan Lentfer 
5946*a1157835SDaniel Fojt 	wpas_rrm_reset(wpa_s);
5947*a1157835SDaniel Fojt 
5948*a1157835SDaniel Fojt 	wpas_sched_scan_plans_set(wpa_s, wpa_s->conf->sched_scan_plans);
5949*a1157835SDaniel Fojt 
5950*a1157835SDaniel Fojt #ifdef CONFIG_HS20
5951*a1157835SDaniel Fojt 	hs20_init(wpa_s);
5952*a1157835SDaniel Fojt #endif /* CONFIG_HS20 */
5953*a1157835SDaniel Fojt #ifdef CONFIG_MBO
5954*a1157835SDaniel Fojt 	if (wpa_s->conf->oce) {
5955*a1157835SDaniel Fojt 		if ((wpa_s->conf->oce & OCE_STA) &&
5956*a1157835SDaniel Fojt 		    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OCE_STA))
5957*a1157835SDaniel Fojt 			wpa_s->enable_oce = OCE_STA;
5958*a1157835SDaniel Fojt 		if ((wpa_s->conf->oce & OCE_STA_CFON) &&
5959*a1157835SDaniel Fojt 		    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OCE_STA_CFON)) {
5960*a1157835SDaniel Fojt 			/* TODO: Need to add STA-CFON support */
5961*a1157835SDaniel Fojt 			wpa_printf(MSG_ERROR,
5962*a1157835SDaniel Fojt 				   "OCE STA-CFON feature is not yet supported");
5963*a1157835SDaniel Fojt 		}
5964*a1157835SDaniel Fojt 	}
5965*a1157835SDaniel Fojt 	wpas_mbo_update_non_pref_chan(wpa_s, wpa_s->conf->non_pref_chan);
5966*a1157835SDaniel Fojt #endif /* CONFIG_MBO */
5967*a1157835SDaniel Fojt 
5968*a1157835SDaniel Fojt 	wpa_supplicant_set_default_scan_ies(wpa_s);
5969*a1157835SDaniel Fojt 
59706d49e1aeSJan Lentfer 	return 0;
59716d49e1aeSJan Lentfer }
59726d49e1aeSJan Lentfer 
59736d49e1aeSJan Lentfer 
wpa_supplicant_deinit_iface(struct wpa_supplicant * wpa_s,int notify,int terminate)59743ff40c12SJohn Marino static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
59753ff40c12SJohn Marino 					int notify, int terminate)
59766d49e1aeSJan Lentfer {
5977*a1157835SDaniel Fojt 	struct wpa_global *global = wpa_s->global;
5978*a1157835SDaniel Fojt 	struct wpa_supplicant *iface, *prev;
5979*a1157835SDaniel Fojt 
5980*a1157835SDaniel Fojt 	if (wpa_s == wpa_s->parent)
5981*a1157835SDaniel Fojt 		wpas_p2p_group_remove(wpa_s, "*");
5982*a1157835SDaniel Fojt 
5983*a1157835SDaniel Fojt 	iface = global->ifaces;
5984*a1157835SDaniel Fojt 	while (iface) {
5985*a1157835SDaniel Fojt 		if (iface->p2pdev == wpa_s)
5986*a1157835SDaniel Fojt 			iface->p2pdev = iface->parent;
5987*a1157835SDaniel Fojt 		if (iface == wpa_s || iface->parent != wpa_s) {
5988*a1157835SDaniel Fojt 			iface = iface->next;
5989*a1157835SDaniel Fojt 			continue;
5990*a1157835SDaniel Fojt 		}
5991*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
5992*a1157835SDaniel Fojt 			   "Remove remaining child interface %s from parent %s",
5993*a1157835SDaniel Fojt 			   iface->ifname, wpa_s->ifname);
5994*a1157835SDaniel Fojt 		prev = iface;
5995*a1157835SDaniel Fojt 		iface = iface->next;
5996*a1157835SDaniel Fojt 		wpa_supplicant_remove_iface(global, prev, terminate);
5997*a1157835SDaniel Fojt 	}
5998*a1157835SDaniel Fojt 
59993ff40c12SJohn Marino 	wpa_s->disconnected = 1;
60006d49e1aeSJan Lentfer 	if (wpa_s->drv_priv) {
60016d49e1aeSJan Lentfer 		wpa_supplicant_deauthenticate(wpa_s,
60026d49e1aeSJan Lentfer 					      WLAN_REASON_DEAUTH_LEAVING);
60036d49e1aeSJan Lentfer 
60046d49e1aeSJan Lentfer 		wpa_drv_set_countermeasures(wpa_s, 0);
60056d49e1aeSJan Lentfer 		wpa_clear_keys(wpa_s, NULL);
60066d49e1aeSJan Lentfer 	}
60076d49e1aeSJan Lentfer 
60086d49e1aeSJan Lentfer 	wpa_supplicant_cleanup(wpa_s);
6009*a1157835SDaniel Fojt 	wpas_p2p_deinit_iface(wpa_s);
60103ff40c12SJohn Marino 
60113ff40c12SJohn Marino 	wpas_ctrl_radio_work_flush(wpa_s);
60123ff40c12SJohn Marino 	radio_remove_interface(wpa_s);
60133ff40c12SJohn Marino 
6014*a1157835SDaniel Fojt #ifdef CONFIG_FST
6015*a1157835SDaniel Fojt 	if (wpa_s->fst) {
6016*a1157835SDaniel Fojt 		fst_detach(wpa_s->fst);
6017*a1157835SDaniel Fojt 		wpa_s->fst = NULL;
6018*a1157835SDaniel Fojt 	}
6019*a1157835SDaniel Fojt 	if (wpa_s->received_mb_ies) {
6020*a1157835SDaniel Fojt 		wpabuf_free(wpa_s->received_mb_ies);
6021*a1157835SDaniel Fojt 		wpa_s->received_mb_ies = NULL;
6022*a1157835SDaniel Fojt 	}
6023*a1157835SDaniel Fojt #endif /* CONFIG_FST */
6024*a1157835SDaniel Fojt 
60256d49e1aeSJan Lentfer 	if (wpa_s->drv_priv)
60266d49e1aeSJan Lentfer 		wpa_drv_deinit(wpa_s);
60273ff40c12SJohn Marino 
60283ff40c12SJohn Marino 	if (notify)
60293ff40c12SJohn Marino 		wpas_notify_iface_removed(wpa_s);
60303ff40c12SJohn Marino 
60313ff40c12SJohn Marino 	if (terminate)
60323ff40c12SJohn Marino 		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TERMINATING);
60333ff40c12SJohn Marino 
60343ff40c12SJohn Marino 	if (wpa_s->ctrl_iface) {
60353ff40c12SJohn Marino 		wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
60363ff40c12SJohn Marino 		wpa_s->ctrl_iface = NULL;
60373ff40c12SJohn Marino 	}
60383ff40c12SJohn Marino 
6039*a1157835SDaniel Fojt #ifdef CONFIG_MESH
6040*a1157835SDaniel Fojt 	if (wpa_s->ifmsh) {
6041*a1157835SDaniel Fojt 		wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh);
6042*a1157835SDaniel Fojt 		wpa_s->ifmsh = NULL;
6043*a1157835SDaniel Fojt 	}
6044*a1157835SDaniel Fojt #endif /* CONFIG_MESH */
6045*a1157835SDaniel Fojt 
60463ff40c12SJohn Marino 	if (wpa_s->conf != NULL) {
60473ff40c12SJohn Marino 		wpa_config_free(wpa_s->conf);
60483ff40c12SJohn Marino 		wpa_s->conf = NULL;
60493ff40c12SJohn Marino 	}
60503ff40c12SJohn Marino 
6051*a1157835SDaniel Fojt 	os_free(wpa_s->ssids_from_scan_req);
6052*a1157835SDaniel Fojt 
60533ff40c12SJohn Marino 	os_free(wpa_s);
60546d49e1aeSJan Lentfer }
60556d49e1aeSJan Lentfer 
60566d49e1aeSJan Lentfer 
6057*a1157835SDaniel Fojt #ifdef CONFIG_MATCH_IFACE
6058*a1157835SDaniel Fojt 
6059*a1157835SDaniel Fojt /**
6060*a1157835SDaniel Fojt  * wpa_supplicant_match_iface - Match an interface description to a name
6061*a1157835SDaniel Fojt  * @global: Pointer to global data from wpa_supplicant_init()
6062*a1157835SDaniel Fojt  * @ifname: Name of the interface to match
6063*a1157835SDaniel Fojt  * Returns: Pointer to the created interface description or %NULL on failure
6064*a1157835SDaniel Fojt  */
wpa_supplicant_match_iface(struct wpa_global * global,const char * ifname)6065*a1157835SDaniel Fojt struct wpa_interface * wpa_supplicant_match_iface(struct wpa_global *global,
6066*a1157835SDaniel Fojt 						  const char *ifname)
6067*a1157835SDaniel Fojt {
6068*a1157835SDaniel Fojt 	int i;
6069*a1157835SDaniel Fojt 	struct wpa_interface *iface, *miface;
6070*a1157835SDaniel Fojt 
6071*a1157835SDaniel Fojt 	for (i = 0; i < global->params.match_iface_count; i++) {
6072*a1157835SDaniel Fojt 		miface = &global->params.match_ifaces[i];
6073*a1157835SDaniel Fojt 		if (!miface->ifname ||
6074*a1157835SDaniel Fojt 		    fnmatch(miface->ifname, ifname, 0) == 0) {
6075*a1157835SDaniel Fojt 			iface = os_zalloc(sizeof(*iface));
6076*a1157835SDaniel Fojt 			if (!iface)
6077*a1157835SDaniel Fojt 				return NULL;
6078*a1157835SDaniel Fojt 			*iface = *miface;
6079*a1157835SDaniel Fojt 			iface->ifname = ifname;
6080*a1157835SDaniel Fojt 			return iface;
6081*a1157835SDaniel Fojt 		}
6082*a1157835SDaniel Fojt 	}
6083*a1157835SDaniel Fojt 
6084*a1157835SDaniel Fojt 	return NULL;
6085*a1157835SDaniel Fojt }
6086*a1157835SDaniel Fojt 
6087*a1157835SDaniel Fojt 
6088*a1157835SDaniel Fojt /**
6089*a1157835SDaniel Fojt  * wpa_supplicant_match_existing - Match existing interfaces
6090*a1157835SDaniel Fojt  * @global: Pointer to global data from wpa_supplicant_init()
6091*a1157835SDaniel Fojt  * Returns: 0 on success, -1 on failure
6092*a1157835SDaniel Fojt  */
wpa_supplicant_match_existing(struct wpa_global * global)6093*a1157835SDaniel Fojt static int wpa_supplicant_match_existing(struct wpa_global *global)
6094*a1157835SDaniel Fojt {
6095*a1157835SDaniel Fojt 	struct if_nameindex *ifi, *ifp;
6096*a1157835SDaniel Fojt 	struct wpa_supplicant *wpa_s;
6097*a1157835SDaniel Fojt 	struct wpa_interface *iface;
6098*a1157835SDaniel Fojt 
6099*a1157835SDaniel Fojt 	ifp = if_nameindex();
6100*a1157835SDaniel Fojt 	if (!ifp) {
6101*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "if_nameindex: %s", strerror(errno));
6102*a1157835SDaniel Fojt 		return -1;
6103*a1157835SDaniel Fojt 	}
6104*a1157835SDaniel Fojt 
6105*a1157835SDaniel Fojt 	for (ifi = ifp; ifi->if_name; ifi++) {
6106*a1157835SDaniel Fojt 		wpa_s = wpa_supplicant_get_iface(global, ifi->if_name);
6107*a1157835SDaniel Fojt 		if (wpa_s)
6108*a1157835SDaniel Fojt 			continue;
6109*a1157835SDaniel Fojt 		iface = wpa_supplicant_match_iface(global, ifi->if_name);
6110*a1157835SDaniel Fojt 		if (iface) {
6111*a1157835SDaniel Fojt 			wpa_s = wpa_supplicant_add_iface(global, iface, NULL);
6112*a1157835SDaniel Fojt 			os_free(iface);
6113*a1157835SDaniel Fojt 			if (wpa_s)
6114*a1157835SDaniel Fojt 				wpa_s->matched = 1;
6115*a1157835SDaniel Fojt 		}
6116*a1157835SDaniel Fojt 	}
6117*a1157835SDaniel Fojt 
6118*a1157835SDaniel Fojt 	if_freenameindex(ifp);
6119*a1157835SDaniel Fojt 	return 0;
6120*a1157835SDaniel Fojt }
6121*a1157835SDaniel Fojt 
6122*a1157835SDaniel Fojt #endif /* CONFIG_MATCH_IFACE */
6123*a1157835SDaniel Fojt 
6124*a1157835SDaniel Fojt 
61256d49e1aeSJan Lentfer /**
61266d49e1aeSJan Lentfer  * wpa_supplicant_add_iface - Add a new network interface
61276d49e1aeSJan Lentfer  * @global: Pointer to global data from wpa_supplicant_init()
61286d49e1aeSJan Lentfer  * @iface: Interface configuration options
6129*a1157835SDaniel Fojt  * @parent: Parent interface or %NULL to assign new interface as parent
61306d49e1aeSJan Lentfer  * Returns: Pointer to the created interface or %NULL on failure
61316d49e1aeSJan Lentfer  *
61326d49e1aeSJan Lentfer  * This function is used to add new network interfaces for %wpa_supplicant.
61336d49e1aeSJan Lentfer  * This can be called before wpa_supplicant_run() to add interfaces before the
61346d49e1aeSJan Lentfer  * main event loop has been started. In addition, new interfaces can be added
61356d49e1aeSJan Lentfer  * dynamically while %wpa_supplicant is already running. This could happen,
61366d49e1aeSJan Lentfer  * e.g., when a hotplug network adapter is inserted.
61376d49e1aeSJan Lentfer  */
wpa_supplicant_add_iface(struct wpa_global * global,struct wpa_interface * iface,struct wpa_supplicant * parent)61386d49e1aeSJan Lentfer struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
6139*a1157835SDaniel Fojt 						 struct wpa_interface *iface,
6140*a1157835SDaniel Fojt 						 struct wpa_supplicant *parent)
61416d49e1aeSJan Lentfer {
61426d49e1aeSJan Lentfer 	struct wpa_supplicant *wpa_s;
61433ff40c12SJohn Marino 	struct wpa_interface t_iface;
61443ff40c12SJohn Marino 	struct wpa_ssid *ssid;
61456d49e1aeSJan Lentfer 
61466d49e1aeSJan Lentfer 	if (global == NULL || iface == NULL)
61476d49e1aeSJan Lentfer 		return NULL;
61486d49e1aeSJan Lentfer 
6149*a1157835SDaniel Fojt 	wpa_s = wpa_supplicant_alloc(parent);
61506d49e1aeSJan Lentfer 	if (wpa_s == NULL)
61516d49e1aeSJan Lentfer 		return NULL;
61526d49e1aeSJan Lentfer 
61536d49e1aeSJan Lentfer 	wpa_s->global = global;
61546d49e1aeSJan Lentfer 
61553ff40c12SJohn Marino 	t_iface = *iface;
61563ff40c12SJohn Marino 	if (global->params.override_driver) {
61573ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "Override interface parameter: driver "
61583ff40c12SJohn Marino 			   "('%s' -> '%s')",
61593ff40c12SJohn Marino 			   iface->driver, global->params.override_driver);
61603ff40c12SJohn Marino 		t_iface.driver = global->params.override_driver;
61613ff40c12SJohn Marino 	}
61623ff40c12SJohn Marino 	if (global->params.override_ctrl_interface) {
61633ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "Override interface parameter: "
61643ff40c12SJohn Marino 			   "ctrl_interface ('%s' -> '%s')",
61653ff40c12SJohn Marino 			   iface->ctrl_interface,
61663ff40c12SJohn Marino 			   global->params.override_ctrl_interface);
61673ff40c12SJohn Marino 		t_iface.ctrl_interface =
61683ff40c12SJohn Marino 			global->params.override_ctrl_interface;
61693ff40c12SJohn Marino 	}
61703ff40c12SJohn Marino 	if (wpa_supplicant_init_iface(wpa_s, &t_iface)) {
61716d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "Failed to add interface %s",
61726d49e1aeSJan Lentfer 			   iface->ifname);
61733ff40c12SJohn Marino 		wpa_supplicant_deinit_iface(wpa_s, 0, 0);
61746d49e1aeSJan Lentfer 		return NULL;
61756d49e1aeSJan Lentfer 	}
61766d49e1aeSJan Lentfer 
6177*a1157835SDaniel Fojt 	if (iface->p2p_mgmt == 0) {
61783ff40c12SJohn Marino 		/* Notify the control interfaces about new iface */
61793ff40c12SJohn Marino 		if (wpas_notify_iface_added(wpa_s)) {
61803ff40c12SJohn Marino 			wpa_supplicant_deinit_iface(wpa_s, 1, 0);
61816d49e1aeSJan Lentfer 			return NULL;
61826d49e1aeSJan Lentfer 		}
61836d49e1aeSJan Lentfer 
61843ff40c12SJohn Marino 		for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
61853ff40c12SJohn Marino 			wpas_notify_network_added(wpa_s, ssid);
6186*a1157835SDaniel Fojt 	}
61873ff40c12SJohn Marino 
61886d49e1aeSJan Lentfer 	wpa_s->next = global->ifaces;
61896d49e1aeSJan Lentfer 	global->ifaces = wpa_s;
61906d49e1aeSJan Lentfer 
61913ff40c12SJohn Marino 	wpa_dbg(wpa_s, MSG_DEBUG, "Added interface %s", wpa_s->ifname);
61923ff40c12SJohn Marino 	wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
61936d49e1aeSJan Lentfer 
6194*a1157835SDaniel Fojt #ifdef CONFIG_P2P
6195*a1157835SDaniel Fojt 	if (wpa_s->global->p2p == NULL &&
6196*a1157835SDaniel Fojt 	    !wpa_s->global->p2p_disabled && !wpa_s->conf->p2p_disabled &&
6197*a1157835SDaniel Fojt 	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
6198*a1157835SDaniel Fojt 	    wpas_p2p_add_p2pdev_interface(
6199*a1157835SDaniel Fojt 		    wpa_s, wpa_s->global->params.conf_p2p_dev) < 0) {
6200*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
6201*a1157835SDaniel Fojt 			   "P2P: Failed to enable P2P Device interface");
6202*a1157835SDaniel Fojt 		/* Try to continue without. P2P will be disabled. */
6203*a1157835SDaniel Fojt 	}
6204*a1157835SDaniel Fojt #endif /* CONFIG_P2P */
6205*a1157835SDaniel Fojt 
62066d49e1aeSJan Lentfer 	return wpa_s;
62076d49e1aeSJan Lentfer }
62086d49e1aeSJan Lentfer 
62096d49e1aeSJan Lentfer 
62106d49e1aeSJan Lentfer /**
62116d49e1aeSJan Lentfer  * wpa_supplicant_remove_iface - Remove a network interface
62126d49e1aeSJan Lentfer  * @global: Pointer to global data from wpa_supplicant_init()
62136d49e1aeSJan Lentfer  * @wpa_s: Pointer to the network interface to be removed
62146d49e1aeSJan Lentfer  * Returns: 0 if interface was removed, -1 if interface was not found
62156d49e1aeSJan Lentfer  *
62166d49e1aeSJan Lentfer  * This function can be used to dynamically remove network interfaces from
62176d49e1aeSJan Lentfer  * %wpa_supplicant, e.g., when a hotplug network adapter is ejected. In
62186d49e1aeSJan Lentfer  * addition, this function is used to remove all remaining interfaces when
62196d49e1aeSJan Lentfer  * %wpa_supplicant is terminated.
62206d49e1aeSJan Lentfer  */
wpa_supplicant_remove_iface(struct wpa_global * global,struct wpa_supplicant * wpa_s,int terminate)62216d49e1aeSJan Lentfer int wpa_supplicant_remove_iface(struct wpa_global *global,
62223ff40c12SJohn Marino 				struct wpa_supplicant *wpa_s,
62233ff40c12SJohn Marino 				int terminate)
62246d49e1aeSJan Lentfer {
62256d49e1aeSJan Lentfer 	struct wpa_supplicant *prev;
6226*a1157835SDaniel Fojt #ifdef CONFIG_MESH
6227*a1157835SDaniel Fojt 	unsigned int mesh_if_created = wpa_s->mesh_if_created;
6228*a1157835SDaniel Fojt 	char *ifname = NULL;
6229*a1157835SDaniel Fojt 	struct wpa_supplicant *parent = wpa_s->parent;
6230*a1157835SDaniel Fojt #endif /* CONFIG_MESH */
62316d49e1aeSJan Lentfer 
62326d49e1aeSJan Lentfer 	/* Remove interface from the global list of interfaces */
62336d49e1aeSJan Lentfer 	prev = global->ifaces;
62346d49e1aeSJan Lentfer 	if (prev == wpa_s) {
62356d49e1aeSJan Lentfer 		global->ifaces = wpa_s->next;
62366d49e1aeSJan Lentfer 	} else {
62376d49e1aeSJan Lentfer 		while (prev && prev->next != wpa_s)
62386d49e1aeSJan Lentfer 			prev = prev->next;
62396d49e1aeSJan Lentfer 		if (prev == NULL)
62406d49e1aeSJan Lentfer 			return -1;
62416d49e1aeSJan Lentfer 		prev->next = wpa_s->next;
62426d49e1aeSJan Lentfer 	}
62436d49e1aeSJan Lentfer 
62443ff40c12SJohn Marino 	wpa_dbg(wpa_s, MSG_DEBUG, "Removing interface %s", wpa_s->ifname);
62456d49e1aeSJan Lentfer 
6246*a1157835SDaniel Fojt #ifdef CONFIG_MESH
6247*a1157835SDaniel Fojt 	if (mesh_if_created) {
6248*a1157835SDaniel Fojt 		ifname = os_strdup(wpa_s->ifname);
6249*a1157835SDaniel Fojt 		if (ifname == NULL) {
6250*a1157835SDaniel Fojt 			wpa_dbg(wpa_s, MSG_ERROR,
6251*a1157835SDaniel Fojt 				"mesh: Failed to malloc ifname");
6252*a1157835SDaniel Fojt 			return -1;
6253*a1157835SDaniel Fojt 		}
6254*a1157835SDaniel Fojt 	}
6255*a1157835SDaniel Fojt #endif /* CONFIG_MESH */
6256*a1157835SDaniel Fojt 
62573ff40c12SJohn Marino 	if (global->p2p_group_formation == wpa_s)
62583ff40c12SJohn Marino 		global->p2p_group_formation = NULL;
62593ff40c12SJohn Marino 	if (global->p2p_invite_group == wpa_s)
62603ff40c12SJohn Marino 		global->p2p_invite_group = NULL;
62613ff40c12SJohn Marino 	wpa_supplicant_deinit_iface(wpa_s, 1, terminate);
62626d49e1aeSJan Lentfer 
6263*a1157835SDaniel Fojt #ifdef CONFIG_MESH
6264*a1157835SDaniel Fojt 	if (mesh_if_created) {
6265*a1157835SDaniel Fojt 		wpa_drv_if_remove(parent, WPA_IF_MESH, ifname);
6266*a1157835SDaniel Fojt 		os_free(ifname);
6267*a1157835SDaniel Fojt 	}
6268*a1157835SDaniel Fojt #endif /* CONFIG_MESH */
6269*a1157835SDaniel Fojt 
62706d49e1aeSJan Lentfer 	return 0;
62716d49e1aeSJan Lentfer }
62726d49e1aeSJan Lentfer 
62736d49e1aeSJan Lentfer 
62746d49e1aeSJan Lentfer /**
62753ff40c12SJohn Marino  * wpa_supplicant_get_eap_mode - Get the current EAP mode
62763ff40c12SJohn Marino  * @wpa_s: Pointer to the network interface
62773ff40c12SJohn Marino  * Returns: Pointer to the eap mode or the string "UNKNOWN" if not found
62783ff40c12SJohn Marino  */
wpa_supplicant_get_eap_mode(struct wpa_supplicant * wpa_s)62793ff40c12SJohn Marino const char * wpa_supplicant_get_eap_mode(struct wpa_supplicant *wpa_s)
62803ff40c12SJohn Marino {
62813ff40c12SJohn Marino 	const char *eapol_method;
62823ff40c12SJohn Marino 
62833ff40c12SJohn Marino         if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) == 0 &&
62843ff40c12SJohn Marino             wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
62853ff40c12SJohn Marino 		return "NO-EAP";
62863ff40c12SJohn Marino 	}
62873ff40c12SJohn Marino 
62883ff40c12SJohn Marino 	eapol_method = eapol_sm_get_method_name(wpa_s->eapol);
62893ff40c12SJohn Marino 	if (eapol_method == NULL)
62903ff40c12SJohn Marino 		return "UNKNOWN-EAP";
62913ff40c12SJohn Marino 
62923ff40c12SJohn Marino 	return eapol_method;
62933ff40c12SJohn Marino }
62943ff40c12SJohn Marino 
62953ff40c12SJohn Marino 
62963ff40c12SJohn Marino /**
62976d49e1aeSJan Lentfer  * wpa_supplicant_get_iface - Get a new network interface
62986d49e1aeSJan Lentfer  * @global: Pointer to global data from wpa_supplicant_init()
62996d49e1aeSJan Lentfer  * @ifname: Interface name
63006d49e1aeSJan Lentfer  * Returns: Pointer to the interface or %NULL if not found
63016d49e1aeSJan Lentfer  */
wpa_supplicant_get_iface(struct wpa_global * global,const char * ifname)63026d49e1aeSJan Lentfer struct wpa_supplicant * wpa_supplicant_get_iface(struct wpa_global *global,
63036d49e1aeSJan Lentfer 						 const char *ifname)
63046d49e1aeSJan Lentfer {
63056d49e1aeSJan Lentfer 	struct wpa_supplicant *wpa_s;
63066d49e1aeSJan Lentfer 
63076d49e1aeSJan Lentfer 	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
63086d49e1aeSJan Lentfer 		if (os_strcmp(wpa_s->ifname, ifname) == 0)
63096d49e1aeSJan Lentfer 			return wpa_s;
63106d49e1aeSJan Lentfer 	}
63116d49e1aeSJan Lentfer 	return NULL;
63126d49e1aeSJan Lentfer }
63136d49e1aeSJan Lentfer 
63146d49e1aeSJan Lentfer 
63153ff40c12SJohn Marino #ifndef CONFIG_NO_WPA_MSG
wpa_supplicant_msg_ifname_cb(void * ctx)63163ff40c12SJohn Marino static const char * wpa_supplicant_msg_ifname_cb(void *ctx)
63173ff40c12SJohn Marino {
63183ff40c12SJohn Marino 	struct wpa_supplicant *wpa_s = ctx;
63193ff40c12SJohn Marino 	if (wpa_s == NULL)
63203ff40c12SJohn Marino 		return NULL;
63213ff40c12SJohn Marino 	return wpa_s->ifname;
63223ff40c12SJohn Marino }
63233ff40c12SJohn Marino #endif /* CONFIG_NO_WPA_MSG */
63243ff40c12SJohn Marino 
63253ff40c12SJohn Marino 
6326*a1157835SDaniel Fojt #ifndef WPA_SUPPLICANT_CLEANUP_INTERVAL
6327*a1157835SDaniel Fojt #define WPA_SUPPLICANT_CLEANUP_INTERVAL 10
6328*a1157835SDaniel Fojt #endif /* WPA_SUPPLICANT_CLEANUP_INTERVAL */
6329*a1157835SDaniel Fojt 
6330*a1157835SDaniel Fojt /* Periodic cleanup tasks */
wpas_periodic(void * eloop_ctx,void * timeout_ctx)6331*a1157835SDaniel Fojt static void wpas_periodic(void *eloop_ctx, void *timeout_ctx)
6332*a1157835SDaniel Fojt {
6333*a1157835SDaniel Fojt 	struct wpa_global *global = eloop_ctx;
6334*a1157835SDaniel Fojt 	struct wpa_supplicant *wpa_s;
6335*a1157835SDaniel Fojt 
6336*a1157835SDaniel Fojt 	eloop_register_timeout(WPA_SUPPLICANT_CLEANUP_INTERVAL, 0,
6337*a1157835SDaniel Fojt 			       wpas_periodic, global, NULL);
6338*a1157835SDaniel Fojt 
6339*a1157835SDaniel Fojt #ifdef CONFIG_P2P
6340*a1157835SDaniel Fojt 	if (global->p2p)
6341*a1157835SDaniel Fojt 		p2p_expire_peers(global->p2p);
6342*a1157835SDaniel Fojt #endif /* CONFIG_P2P */
6343*a1157835SDaniel Fojt 
6344*a1157835SDaniel Fojt 	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
6345*a1157835SDaniel Fojt 		wpa_bss_flush_by_age(wpa_s, wpa_s->conf->bss_expiration_age);
6346*a1157835SDaniel Fojt #ifdef CONFIG_AP
6347*a1157835SDaniel Fojt 		ap_periodic(wpa_s);
6348*a1157835SDaniel Fojt #endif /* CONFIG_AP */
6349*a1157835SDaniel Fojt 	}
6350*a1157835SDaniel Fojt }
6351*a1157835SDaniel Fojt 
6352*a1157835SDaniel Fojt 
63536d49e1aeSJan Lentfer /**
63546d49e1aeSJan Lentfer  * wpa_supplicant_init - Initialize %wpa_supplicant
63556d49e1aeSJan Lentfer  * @params: Parameters for %wpa_supplicant
63566d49e1aeSJan Lentfer  * Returns: Pointer to global %wpa_supplicant data, or %NULL on failure
63576d49e1aeSJan Lentfer  *
63586d49e1aeSJan Lentfer  * This function is used to initialize %wpa_supplicant. After successful
63596d49e1aeSJan Lentfer  * initialization, the returned data pointer can be used to add and remove
63606d49e1aeSJan Lentfer  * network interfaces, and eventually, to deinitialize %wpa_supplicant.
63616d49e1aeSJan Lentfer  */
wpa_supplicant_init(struct wpa_params * params)63626d49e1aeSJan Lentfer struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
63636d49e1aeSJan Lentfer {
63646d49e1aeSJan Lentfer 	struct wpa_global *global;
63656d49e1aeSJan Lentfer 	int ret, i;
63666d49e1aeSJan Lentfer 
63676d49e1aeSJan Lentfer 	if (params == NULL)
63686d49e1aeSJan Lentfer 		return NULL;
63696d49e1aeSJan Lentfer 
63703ff40c12SJohn Marino #ifdef UNMASK__CONFIG_DRIVER_NDIS
63713ff40c12SJohn Marino 	{
63723ff40c12SJohn Marino 		void driver_ndis_init_ops(void);
63733ff40c12SJohn Marino 		driver_ndis_init_ops();
63743ff40c12SJohn Marino 	}
63753ff40c12SJohn Marino #endif /* CONFIG_DRIVER_NDIS */
63766d49e1aeSJan Lentfer 
63773ff40c12SJohn Marino #ifndef CONFIG_NO_WPA_MSG
63783ff40c12SJohn Marino 	wpa_msg_register_ifname_cb(wpa_supplicant_msg_ifname_cb);
63793ff40c12SJohn Marino #endif /* CONFIG_NO_WPA_MSG */
63803ff40c12SJohn Marino 
6381*a1157835SDaniel Fojt 	if (params->wpa_debug_file_path)
63823ff40c12SJohn Marino 		wpa_debug_open_file(params->wpa_debug_file_path);
6383*a1157835SDaniel Fojt 	else
6384*a1157835SDaniel Fojt 		wpa_debug_setup_stdout();
63853ff40c12SJohn Marino 	if (params->wpa_debug_syslog)
63863ff40c12SJohn Marino 		wpa_debug_open_syslog();
63873ff40c12SJohn Marino 	if (params->wpa_debug_tracing) {
63883ff40c12SJohn Marino 		ret = wpa_debug_open_linux_tracing();
63893ff40c12SJohn Marino 		if (ret) {
63903ff40c12SJohn Marino 			wpa_printf(MSG_ERROR,
63913ff40c12SJohn Marino 				   "Failed to enable trace logging");
63923ff40c12SJohn Marino 			return NULL;
63933ff40c12SJohn Marino 		}
63943ff40c12SJohn Marino 	}
63953ff40c12SJohn Marino 
63963ff40c12SJohn Marino 	ret = eap_register_methods();
63976d49e1aeSJan Lentfer 	if (ret) {
63986d49e1aeSJan Lentfer 		wpa_printf(MSG_ERROR, "Failed to register EAP methods");
63996d49e1aeSJan Lentfer 		if (ret == -2)
64006d49e1aeSJan Lentfer 			wpa_printf(MSG_ERROR, "Two or more EAP methods used "
64016d49e1aeSJan Lentfer 				   "the same EAP type.");
64026d49e1aeSJan Lentfer 		return NULL;
64036d49e1aeSJan Lentfer 	}
64046d49e1aeSJan Lentfer 
64056d49e1aeSJan Lentfer 	global = os_zalloc(sizeof(*global));
64066d49e1aeSJan Lentfer 	if (global == NULL)
64076d49e1aeSJan Lentfer 		return NULL;
64083ff40c12SJohn Marino 	dl_list_init(&global->p2p_srv_bonjour);
64093ff40c12SJohn Marino 	dl_list_init(&global->p2p_srv_upnp);
64106d49e1aeSJan Lentfer 	global->params.daemonize = params->daemonize;
64116d49e1aeSJan Lentfer 	global->params.wait_for_monitor = params->wait_for_monitor;
64126d49e1aeSJan Lentfer 	global->params.dbus_ctrl_interface = params->dbus_ctrl_interface;
64136d49e1aeSJan Lentfer 	if (params->pid_file)
64146d49e1aeSJan Lentfer 		global->params.pid_file = os_strdup(params->pid_file);
64156d49e1aeSJan Lentfer 	if (params->ctrl_interface)
64166d49e1aeSJan Lentfer 		global->params.ctrl_interface =
64176d49e1aeSJan Lentfer 			os_strdup(params->ctrl_interface);
64183ff40c12SJohn Marino 	if (params->ctrl_interface_group)
64193ff40c12SJohn Marino 		global->params.ctrl_interface_group =
64203ff40c12SJohn Marino 			os_strdup(params->ctrl_interface_group);
64213ff40c12SJohn Marino 	if (params->override_driver)
64223ff40c12SJohn Marino 		global->params.override_driver =
64233ff40c12SJohn Marino 			os_strdup(params->override_driver);
64243ff40c12SJohn Marino 	if (params->override_ctrl_interface)
64253ff40c12SJohn Marino 		global->params.override_ctrl_interface =
64263ff40c12SJohn Marino 			os_strdup(params->override_ctrl_interface);
6427*a1157835SDaniel Fojt #ifdef CONFIG_MATCH_IFACE
6428*a1157835SDaniel Fojt 	global->params.match_iface_count = params->match_iface_count;
6429*a1157835SDaniel Fojt 	if (params->match_iface_count) {
6430*a1157835SDaniel Fojt 		global->params.match_ifaces =
6431*a1157835SDaniel Fojt 			os_calloc(params->match_iface_count,
6432*a1157835SDaniel Fojt 				  sizeof(struct wpa_interface));
6433*a1157835SDaniel Fojt 		os_memcpy(global->params.match_ifaces,
6434*a1157835SDaniel Fojt 			  params->match_ifaces,
6435*a1157835SDaniel Fojt 			  params->match_iface_count *
6436*a1157835SDaniel Fojt 			  sizeof(struct wpa_interface));
6437*a1157835SDaniel Fojt 	}
6438*a1157835SDaniel Fojt #endif /* CONFIG_MATCH_IFACE */
6439*a1157835SDaniel Fojt #ifdef CONFIG_P2P
6440*a1157835SDaniel Fojt 	if (params->conf_p2p_dev)
6441*a1157835SDaniel Fojt 		global->params.conf_p2p_dev =
6442*a1157835SDaniel Fojt 			os_strdup(params->conf_p2p_dev);
6443*a1157835SDaniel Fojt #endif /* CONFIG_P2P */
64446d49e1aeSJan Lentfer 	wpa_debug_level = global->params.wpa_debug_level =
64456d49e1aeSJan Lentfer 		params->wpa_debug_level;
64466d49e1aeSJan Lentfer 	wpa_debug_show_keys = global->params.wpa_debug_show_keys =
64476d49e1aeSJan Lentfer 		params->wpa_debug_show_keys;
64486d49e1aeSJan Lentfer 	wpa_debug_timestamp = global->params.wpa_debug_timestamp =
64496d49e1aeSJan Lentfer 		params->wpa_debug_timestamp;
64506d49e1aeSJan Lentfer 
64513ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "wpa_supplicant v" VERSION_STR);
64523ff40c12SJohn Marino 
64533ff40c12SJohn Marino 	if (eloop_init()) {
64546d49e1aeSJan Lentfer 		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
64556d49e1aeSJan Lentfer 		wpa_supplicant_deinit(global);
64566d49e1aeSJan Lentfer 		return NULL;
64576d49e1aeSJan Lentfer 	}
64586d49e1aeSJan Lentfer 
64593ff40c12SJohn Marino 	random_init(params->entropy_file);
64603ff40c12SJohn Marino 
64616d49e1aeSJan Lentfer 	global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global);
64626d49e1aeSJan Lentfer 	if (global->ctrl_iface == NULL) {
64636d49e1aeSJan Lentfer 		wpa_supplicant_deinit(global);
64646d49e1aeSJan Lentfer 		return NULL;
64656d49e1aeSJan Lentfer 	}
64666d49e1aeSJan Lentfer 
64673ff40c12SJohn Marino 	if (wpas_notify_supplicant_initialized(global)) {
64686d49e1aeSJan Lentfer 		wpa_supplicant_deinit(global);
64696d49e1aeSJan Lentfer 		return NULL;
64706d49e1aeSJan Lentfer 	}
64716d49e1aeSJan Lentfer 
64723ff40c12SJohn Marino 	for (i = 0; wpa_drivers[i]; i++)
64736d49e1aeSJan Lentfer 		global->drv_count++;
64746d49e1aeSJan Lentfer 	if (global->drv_count == 0) {
64756d49e1aeSJan Lentfer 		wpa_printf(MSG_ERROR, "No drivers enabled");
64766d49e1aeSJan Lentfer 		wpa_supplicant_deinit(global);
64776d49e1aeSJan Lentfer 		return NULL;
64786d49e1aeSJan Lentfer 	}
6479*a1157835SDaniel Fojt 	global->drv_priv = os_calloc(global->drv_count, sizeof(void *));
64806d49e1aeSJan Lentfer 	if (global->drv_priv == NULL) {
64816d49e1aeSJan Lentfer 		wpa_supplicant_deinit(global);
64826d49e1aeSJan Lentfer 		return NULL;
64836d49e1aeSJan Lentfer 	}
64843ff40c12SJohn Marino 
64853ff40c12SJohn Marino #ifdef CONFIG_WIFI_DISPLAY
64863ff40c12SJohn Marino 	if (wifi_display_init(global) < 0) {
64873ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Failed to initialize Wi-Fi Display");
64886d49e1aeSJan Lentfer 		wpa_supplicant_deinit(global);
64896d49e1aeSJan Lentfer 		return NULL;
64906d49e1aeSJan Lentfer 	}
64913ff40c12SJohn Marino #endif /* CONFIG_WIFI_DISPLAY */
64926d49e1aeSJan Lentfer 
6493*a1157835SDaniel Fojt 	eloop_register_timeout(WPA_SUPPLICANT_CLEANUP_INTERVAL, 0,
6494*a1157835SDaniel Fojt 			       wpas_periodic, global, NULL);
6495*a1157835SDaniel Fojt 
64966d49e1aeSJan Lentfer 	return global;
64976d49e1aeSJan Lentfer }
64986d49e1aeSJan Lentfer 
64996d49e1aeSJan Lentfer 
65006d49e1aeSJan Lentfer /**
65016d49e1aeSJan Lentfer  * wpa_supplicant_run - Run the %wpa_supplicant main event loop
65026d49e1aeSJan Lentfer  * @global: Pointer to global data from wpa_supplicant_init()
65036d49e1aeSJan Lentfer  * Returns: 0 after successful event loop run, -1 on failure
65046d49e1aeSJan Lentfer  *
65056d49e1aeSJan Lentfer  * This function starts the main event loop and continues running as long as
65066d49e1aeSJan Lentfer  * there are any remaining events. In most cases, this function is running as
65076d49e1aeSJan Lentfer  * long as the %wpa_supplicant process in still in use.
65086d49e1aeSJan Lentfer  */
wpa_supplicant_run(struct wpa_global * global)65096d49e1aeSJan Lentfer int wpa_supplicant_run(struct wpa_global *global)
65106d49e1aeSJan Lentfer {
65116d49e1aeSJan Lentfer 	struct wpa_supplicant *wpa_s;
65126d49e1aeSJan Lentfer 
65136d49e1aeSJan Lentfer 	if (global->params.daemonize &&
6514*a1157835SDaniel Fojt 	    (wpa_supplicant_daemon(global->params.pid_file) ||
6515*a1157835SDaniel Fojt 	     eloop_sock_requeue()))
65166d49e1aeSJan Lentfer 		return -1;
65176d49e1aeSJan Lentfer 
6518*a1157835SDaniel Fojt #ifdef CONFIG_MATCH_IFACE
6519*a1157835SDaniel Fojt 	if (wpa_supplicant_match_existing(global))
6520*a1157835SDaniel Fojt 		return -1;
6521*a1157835SDaniel Fojt #endif
6522*a1157835SDaniel Fojt 
65236d49e1aeSJan Lentfer 	if (global->params.wait_for_monitor) {
65246d49e1aeSJan Lentfer 		for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
6525*a1157835SDaniel Fojt 			if (wpa_s->ctrl_iface && !wpa_s->p2p_mgmt)
65266d49e1aeSJan Lentfer 				wpa_supplicant_ctrl_iface_wait(
65276d49e1aeSJan Lentfer 					wpa_s->ctrl_iface);
65286d49e1aeSJan Lentfer 	}
65296d49e1aeSJan Lentfer 
65303ff40c12SJohn Marino 	eloop_register_signal_terminate(wpa_supplicant_terminate, global);
65313ff40c12SJohn Marino 	eloop_register_signal_reconfig(wpa_supplicant_reconfig, global);
65326d49e1aeSJan Lentfer 
65336d49e1aeSJan Lentfer 	eloop_run();
65346d49e1aeSJan Lentfer 
65356d49e1aeSJan Lentfer 	return 0;
65366d49e1aeSJan Lentfer }
65376d49e1aeSJan Lentfer 
65386d49e1aeSJan Lentfer 
65396d49e1aeSJan Lentfer /**
65406d49e1aeSJan Lentfer  * wpa_supplicant_deinit - Deinitialize %wpa_supplicant
65416d49e1aeSJan Lentfer  * @global: Pointer to global data from wpa_supplicant_init()
65426d49e1aeSJan Lentfer  *
65436d49e1aeSJan Lentfer  * This function is called to deinitialize %wpa_supplicant and to free all
65446d49e1aeSJan Lentfer  * allocated resources. Remaining network interfaces will also be removed.
65456d49e1aeSJan Lentfer  */
wpa_supplicant_deinit(struct wpa_global * global)65466d49e1aeSJan Lentfer void wpa_supplicant_deinit(struct wpa_global *global)
65476d49e1aeSJan Lentfer {
65486d49e1aeSJan Lentfer 	int i;
65496d49e1aeSJan Lentfer 
65506d49e1aeSJan Lentfer 	if (global == NULL)
65516d49e1aeSJan Lentfer 		return;
65526d49e1aeSJan Lentfer 
6553*a1157835SDaniel Fojt 	eloop_cancel_timeout(wpas_periodic, global, NULL);
6554*a1157835SDaniel Fojt 
65553ff40c12SJohn Marino #ifdef CONFIG_WIFI_DISPLAY
65563ff40c12SJohn Marino 	wifi_display_deinit(global);
65573ff40c12SJohn Marino #endif /* CONFIG_WIFI_DISPLAY */
65583ff40c12SJohn Marino 
65596d49e1aeSJan Lentfer 	while (global->ifaces)
65603ff40c12SJohn Marino 		wpa_supplicant_remove_iface(global, global->ifaces, 1);
65616d49e1aeSJan Lentfer 
65626d49e1aeSJan Lentfer 	if (global->ctrl_iface)
65636d49e1aeSJan Lentfer 		wpa_supplicant_global_ctrl_iface_deinit(global->ctrl_iface);
65643ff40c12SJohn Marino 
65653ff40c12SJohn Marino 	wpas_notify_supplicant_deinitialized(global);
65666d49e1aeSJan Lentfer 
65676d49e1aeSJan Lentfer 	eap_peer_unregister_methods();
65683ff40c12SJohn Marino #ifdef CONFIG_AP
65693ff40c12SJohn Marino 	eap_server_unregister_methods();
65703ff40c12SJohn Marino #endif /* CONFIG_AP */
65716d49e1aeSJan Lentfer 
65723ff40c12SJohn Marino 	for (i = 0; wpa_drivers[i] && global->drv_priv; i++) {
65736d49e1aeSJan Lentfer 		if (!global->drv_priv[i])
65746d49e1aeSJan Lentfer 			continue;
65753ff40c12SJohn Marino 		wpa_drivers[i]->global_deinit(global->drv_priv[i]);
65766d49e1aeSJan Lentfer 	}
65776d49e1aeSJan Lentfer 	os_free(global->drv_priv);
65786d49e1aeSJan Lentfer 
65793ff40c12SJohn Marino 	random_deinit();
65803ff40c12SJohn Marino 
65816d49e1aeSJan Lentfer 	eloop_destroy();
65826d49e1aeSJan Lentfer 
65836d49e1aeSJan Lentfer 	if (global->params.pid_file) {
65846d49e1aeSJan Lentfer 		os_daemonize_terminate(global->params.pid_file);
65856d49e1aeSJan Lentfer 		os_free(global->params.pid_file);
65866d49e1aeSJan Lentfer 	}
65876d49e1aeSJan Lentfer 	os_free(global->params.ctrl_interface);
65883ff40c12SJohn Marino 	os_free(global->params.ctrl_interface_group);
65893ff40c12SJohn Marino 	os_free(global->params.override_driver);
65903ff40c12SJohn Marino 	os_free(global->params.override_ctrl_interface);
6591*a1157835SDaniel Fojt #ifdef CONFIG_MATCH_IFACE
6592*a1157835SDaniel Fojt 	os_free(global->params.match_ifaces);
6593*a1157835SDaniel Fojt #endif /* CONFIG_MATCH_IFACE */
6594*a1157835SDaniel Fojt #ifdef CONFIG_P2P
6595*a1157835SDaniel Fojt 	os_free(global->params.conf_p2p_dev);
6596*a1157835SDaniel Fojt #endif /* CONFIG_P2P */
65973ff40c12SJohn Marino 
65983ff40c12SJohn Marino 	os_free(global->p2p_disallow_freq.range);
65993ff40c12SJohn Marino 	os_free(global->p2p_go_avoid_freq.range);
66003ff40c12SJohn Marino 	os_free(global->add_psk);
66016d49e1aeSJan Lentfer 
66026d49e1aeSJan Lentfer 	os_free(global);
66033ff40c12SJohn Marino 	wpa_debug_close_syslog();
66046d49e1aeSJan Lentfer 	wpa_debug_close_file();
66053ff40c12SJohn Marino 	wpa_debug_close_linux_tracing();
66063ff40c12SJohn Marino }
66073ff40c12SJohn Marino 
66083ff40c12SJohn Marino 
wpa_supplicant_update_config(struct wpa_supplicant * wpa_s)66093ff40c12SJohn Marino void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
66103ff40c12SJohn Marino {
66113ff40c12SJohn Marino 	if ((wpa_s->conf->changed_parameters & CFG_CHANGED_COUNTRY) &&
66123ff40c12SJohn Marino 	    wpa_s->conf->country[0] && wpa_s->conf->country[1]) {
66133ff40c12SJohn Marino 		char country[3];
66143ff40c12SJohn Marino 		country[0] = wpa_s->conf->country[0];
66153ff40c12SJohn Marino 		country[1] = wpa_s->conf->country[1];
66163ff40c12SJohn Marino 		country[2] = '\0';
66173ff40c12SJohn Marino 		if (wpa_drv_set_country(wpa_s, country) < 0) {
66183ff40c12SJohn Marino 			wpa_printf(MSG_ERROR, "Failed to set country code "
66193ff40c12SJohn Marino 				   "'%s'", country);
66203ff40c12SJohn Marino 		}
66213ff40c12SJohn Marino 	}
66223ff40c12SJohn Marino 
66233ff40c12SJohn Marino 	if (wpa_s->conf->changed_parameters & CFG_CHANGED_EXT_PW_BACKEND)
66243ff40c12SJohn Marino 		wpas_init_ext_pw(wpa_s);
66253ff40c12SJohn Marino 
6626*a1157835SDaniel Fojt 	if (wpa_s->conf->changed_parameters & CFG_CHANGED_SCHED_SCAN_PLANS)
6627*a1157835SDaniel Fojt 		wpas_sched_scan_plans_set(wpa_s, wpa_s->conf->sched_scan_plans);
6628*a1157835SDaniel Fojt 
6629*a1157835SDaniel Fojt 	if (wpa_s->conf->changed_parameters & CFG_CHANGED_WOWLAN_TRIGGERS) {
6630*a1157835SDaniel Fojt 		struct wpa_driver_capa capa;
6631*a1157835SDaniel Fojt 		int res = wpa_drv_get_capa(wpa_s, &capa);
6632*a1157835SDaniel Fojt 
6633*a1157835SDaniel Fojt 		if (res == 0 && wpas_set_wowlan_triggers(wpa_s, &capa) < 0)
6634*a1157835SDaniel Fojt 			wpa_printf(MSG_ERROR,
6635*a1157835SDaniel Fojt 				   "Failed to update wowlan_triggers to '%s'",
6636*a1157835SDaniel Fojt 				   wpa_s->conf->wowlan_triggers);
6637*a1157835SDaniel Fojt 	}
6638*a1157835SDaniel Fojt 
6639*a1157835SDaniel Fojt 	if (wpa_s->conf->changed_parameters & CFG_CHANGED_DISABLE_BTM)
6640*a1157835SDaniel Fojt 		wpa_supplicant_set_default_scan_ies(wpa_s);
6641*a1157835SDaniel Fojt 
66423ff40c12SJohn Marino #ifdef CONFIG_WPS
66433ff40c12SJohn Marino 	wpas_wps_update_config(wpa_s);
66443ff40c12SJohn Marino #endif /* CONFIG_WPS */
66453ff40c12SJohn Marino 	wpas_p2p_update_config(wpa_s);
66463ff40c12SJohn Marino 	wpa_s->conf->changed_parameters = 0;
66473ff40c12SJohn Marino }
66483ff40c12SJohn Marino 
66493ff40c12SJohn Marino 
add_freq(int * freqs,int * num_freqs,int freq)6650*a1157835SDaniel Fojt void add_freq(int *freqs, int *num_freqs, int freq)
66513ff40c12SJohn Marino {
66523ff40c12SJohn Marino 	int i;
66533ff40c12SJohn Marino 
66543ff40c12SJohn Marino 	for (i = 0; i < *num_freqs; i++) {
66553ff40c12SJohn Marino 		if (freqs[i] == freq)
66563ff40c12SJohn Marino 			return;
66573ff40c12SJohn Marino 	}
66583ff40c12SJohn Marino 
66593ff40c12SJohn Marino 	freqs[*num_freqs] = freq;
66603ff40c12SJohn Marino 	(*num_freqs)++;
66613ff40c12SJohn Marino }
66623ff40c12SJohn Marino 
66633ff40c12SJohn Marino 
get_bss_freqs_in_ess(struct wpa_supplicant * wpa_s)66643ff40c12SJohn Marino static int * get_bss_freqs_in_ess(struct wpa_supplicant *wpa_s)
66653ff40c12SJohn Marino {
66663ff40c12SJohn Marino 	struct wpa_bss *bss, *cbss;
66673ff40c12SJohn Marino 	const int max_freqs = 10;
66683ff40c12SJohn Marino 	int *freqs;
66693ff40c12SJohn Marino 	int num_freqs = 0;
66703ff40c12SJohn Marino 
6671*a1157835SDaniel Fojt 	freqs = os_calloc(max_freqs + 1, sizeof(int));
66723ff40c12SJohn Marino 	if (freqs == NULL)
66733ff40c12SJohn Marino 		return NULL;
66743ff40c12SJohn Marino 
66753ff40c12SJohn Marino 	cbss = wpa_s->current_bss;
66763ff40c12SJohn Marino 
66773ff40c12SJohn Marino 	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
66783ff40c12SJohn Marino 		if (bss == cbss)
66793ff40c12SJohn Marino 			continue;
66803ff40c12SJohn Marino 		if (bss->ssid_len == cbss->ssid_len &&
66813ff40c12SJohn Marino 		    os_memcmp(bss->ssid, cbss->ssid, bss->ssid_len) == 0 &&
66823ff40c12SJohn Marino 		    wpa_blacklist_get(wpa_s, bss->bssid) == NULL) {
66833ff40c12SJohn Marino 			add_freq(freqs, &num_freqs, bss->freq);
66843ff40c12SJohn Marino 			if (num_freqs == max_freqs)
66853ff40c12SJohn Marino 				break;
66863ff40c12SJohn Marino 		}
66873ff40c12SJohn Marino 	}
66883ff40c12SJohn Marino 
66893ff40c12SJohn Marino 	if (num_freqs == 0) {
66903ff40c12SJohn Marino 		os_free(freqs);
66913ff40c12SJohn Marino 		freqs = NULL;
66923ff40c12SJohn Marino 	}
66933ff40c12SJohn Marino 
66943ff40c12SJohn Marino 	return freqs;
66953ff40c12SJohn Marino }
66963ff40c12SJohn Marino 
66973ff40c12SJohn Marino 
wpas_connection_failed(struct wpa_supplicant * wpa_s,const u8 * bssid)66983ff40c12SJohn Marino void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
66993ff40c12SJohn Marino {
67003ff40c12SJohn Marino 	int timeout;
67013ff40c12SJohn Marino 	int count;
67023ff40c12SJohn Marino 	int *freqs = NULL;
67033ff40c12SJohn Marino 
67043ff40c12SJohn Marino 	wpas_connect_work_done(wpa_s);
67053ff40c12SJohn Marino 
67063ff40c12SJohn Marino 	/*
67073ff40c12SJohn Marino 	 * Remove possible authentication timeout since the connection failed.
67083ff40c12SJohn Marino 	 */
67093ff40c12SJohn Marino 	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
67103ff40c12SJohn Marino 
67113ff40c12SJohn Marino 	/*
67123ff40c12SJohn Marino 	 * There is no point in blacklisting the AP if this event is
67133ff40c12SJohn Marino 	 * generated based on local request to disconnect.
67143ff40c12SJohn Marino 	 */
6715*a1157835SDaniel Fojt 	if (wpa_s->own_disconnect_req) {
6716*a1157835SDaniel Fojt 		wpa_s->own_disconnect_req = 0;
6717*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG,
6718*a1157835SDaniel Fojt 			"Ignore connection failure due to local request to disconnect");
6719*a1157835SDaniel Fojt 		return;
6720*a1157835SDaniel Fojt 	}
6721*a1157835SDaniel Fojt 	if (wpa_s->disconnected) {
67223ff40c12SJohn Marino 		wpa_dbg(wpa_s, MSG_DEBUG, "Ignore connection failure "
67233ff40c12SJohn Marino 			"indication since interface has been put into "
67243ff40c12SJohn Marino 			"disconnected state");
67253ff40c12SJohn Marino 		return;
67263ff40c12SJohn Marino 	}
67273ff40c12SJohn Marino 
67283ff40c12SJohn Marino 	/*
67293ff40c12SJohn Marino 	 * Add the failed BSSID into the blacklist and speed up next scan
67303ff40c12SJohn Marino 	 * attempt if there could be other APs that could accept association.
67313ff40c12SJohn Marino 	 * The current blacklist count indicates how many times we have tried
67323ff40c12SJohn Marino 	 * connecting to this AP and multiple attempts mean that other APs are
67333ff40c12SJohn Marino 	 * either not available or has already been tried, so that we can start
67343ff40c12SJohn Marino 	 * increasing the delay here to avoid constant scanning.
67353ff40c12SJohn Marino 	 */
67363ff40c12SJohn Marino 	count = wpa_blacklist_add(wpa_s, bssid);
67373ff40c12SJohn Marino 	if (count == 1 && wpa_s->current_bss) {
67383ff40c12SJohn Marino 		/*
67393ff40c12SJohn Marino 		 * This BSS was not in the blacklist before. If there is
67403ff40c12SJohn Marino 		 * another BSS available for the same ESS, we should try that
67413ff40c12SJohn Marino 		 * next. Otherwise, we may as well try this one once more
67423ff40c12SJohn Marino 		 * before allowing other, likely worse, ESSes to be considered.
67433ff40c12SJohn Marino 		 */
67443ff40c12SJohn Marino 		freqs = get_bss_freqs_in_ess(wpa_s);
67453ff40c12SJohn Marino 		if (freqs) {
67463ff40c12SJohn Marino 			wpa_dbg(wpa_s, MSG_DEBUG, "Another BSS in this ESS "
67473ff40c12SJohn Marino 				"has been seen; try it next");
67483ff40c12SJohn Marino 			wpa_blacklist_add(wpa_s, bssid);
67493ff40c12SJohn Marino 			/*
67503ff40c12SJohn Marino 			 * On the next scan, go through only the known channels
67513ff40c12SJohn Marino 			 * used in this ESS based on previous scans to speed up
67523ff40c12SJohn Marino 			 * common load balancing use case.
67533ff40c12SJohn Marino 			 */
67543ff40c12SJohn Marino 			os_free(wpa_s->next_scan_freqs);
67553ff40c12SJohn Marino 			wpa_s->next_scan_freqs = freqs;
67563ff40c12SJohn Marino 		}
67573ff40c12SJohn Marino 	}
67583ff40c12SJohn Marino 
67593ff40c12SJohn Marino 	/*
67603ff40c12SJohn Marino 	 * Add previous failure count in case the temporary blacklist was
67613ff40c12SJohn Marino 	 * cleared due to no other BSSes being available.
67623ff40c12SJohn Marino 	 */
67633ff40c12SJohn Marino 	count += wpa_s->extra_blacklist_count;
67643ff40c12SJohn Marino 
67653ff40c12SJohn Marino 	if (count > 3 && wpa_s->current_ssid) {
67663ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "Continuous association failures - "
67673ff40c12SJohn Marino 			   "consider temporary network disabling");
6768*a1157835SDaniel Fojt 		wpas_auth_failed(wpa_s, "CONN_FAILED");
67693ff40c12SJohn Marino 	}
67703ff40c12SJohn Marino 
67713ff40c12SJohn Marino 	switch (count) {
67723ff40c12SJohn Marino 	case 1:
67733ff40c12SJohn Marino 		timeout = 100;
67743ff40c12SJohn Marino 		break;
67753ff40c12SJohn Marino 	case 2:
67763ff40c12SJohn Marino 		timeout = 500;
67773ff40c12SJohn Marino 		break;
67783ff40c12SJohn Marino 	case 3:
67793ff40c12SJohn Marino 		timeout = 1000;
67803ff40c12SJohn Marino 		break;
67813ff40c12SJohn Marino 	case 4:
67823ff40c12SJohn Marino 		timeout = 5000;
67833ff40c12SJohn Marino 		break;
67843ff40c12SJohn Marino 	default:
67853ff40c12SJohn Marino 		timeout = 10000;
67863ff40c12SJohn Marino 		break;
67873ff40c12SJohn Marino 	}
67883ff40c12SJohn Marino 
67893ff40c12SJohn Marino 	wpa_dbg(wpa_s, MSG_DEBUG, "Blacklist count %d --> request scan in %d "
67903ff40c12SJohn Marino 		"ms", count, timeout);
67913ff40c12SJohn Marino 
67923ff40c12SJohn Marino 	/*
67933ff40c12SJohn Marino 	 * TODO: if more than one possible AP is available in scan results,
67943ff40c12SJohn Marino 	 * could try the other ones before requesting a new scan.
67953ff40c12SJohn Marino 	 */
6796*a1157835SDaniel Fojt 
6797*a1157835SDaniel Fojt 	/* speed up the connection attempt with normal scan */
6798*a1157835SDaniel Fojt 	wpa_s->normal_scans = 0;
67993ff40c12SJohn Marino 	wpa_supplicant_req_scan(wpa_s, timeout / 1000,
68003ff40c12SJohn Marino 				1000 * (timeout % 1000));
68013ff40c12SJohn Marino }
68023ff40c12SJohn Marino 
68033ff40c12SJohn Marino 
6804*a1157835SDaniel Fojt #ifdef CONFIG_FILS
fils_connection_failure(struct wpa_supplicant * wpa_s)6805*a1157835SDaniel Fojt void fils_connection_failure(struct wpa_supplicant *wpa_s)
6806*a1157835SDaniel Fojt {
6807*a1157835SDaniel Fojt 	struct wpa_ssid *ssid = wpa_s->current_ssid;
6808*a1157835SDaniel Fojt 	const u8 *realm, *username, *rrk;
6809*a1157835SDaniel Fojt 	size_t realm_len, username_len, rrk_len;
6810*a1157835SDaniel Fojt 	u16 next_seq_num;
6811*a1157835SDaniel Fojt 
6812*a1157835SDaniel Fojt 	if (!ssid || !ssid->eap.erp || !wpa_key_mgmt_fils(ssid->key_mgmt) ||
6813*a1157835SDaniel Fojt 	    eapol_sm_get_erp_info(wpa_s->eapol, &ssid->eap,
6814*a1157835SDaniel Fojt 				  &username, &username_len,
6815*a1157835SDaniel Fojt 				  &realm, &realm_len, &next_seq_num,
6816*a1157835SDaniel Fojt 				  &rrk, &rrk_len) != 0 ||
6817*a1157835SDaniel Fojt 	    !realm)
6818*a1157835SDaniel Fojt 		return;
6819*a1157835SDaniel Fojt 
6820*a1157835SDaniel Fojt 	wpa_hexdump_ascii(MSG_DEBUG,
6821*a1157835SDaniel Fojt 			  "FILS: Store last connection failure realm",
6822*a1157835SDaniel Fojt 			  realm, realm_len);
6823*a1157835SDaniel Fojt 	os_free(wpa_s->last_con_fail_realm);
6824*a1157835SDaniel Fojt 	wpa_s->last_con_fail_realm = os_malloc(realm_len);
6825*a1157835SDaniel Fojt 	if (wpa_s->last_con_fail_realm) {
6826*a1157835SDaniel Fojt 		wpa_s->last_con_fail_realm_len = realm_len;
6827*a1157835SDaniel Fojt 		os_memcpy(wpa_s->last_con_fail_realm, realm, realm_len);
6828*a1157835SDaniel Fojt 	}
6829*a1157835SDaniel Fojt }
6830*a1157835SDaniel Fojt #endif /* CONFIG_FILS */
6831*a1157835SDaniel Fojt 
6832*a1157835SDaniel Fojt 
wpas_driver_bss_selection(struct wpa_supplicant * wpa_s)68333ff40c12SJohn Marino int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s)
68343ff40c12SJohn Marino {
68353ff40c12SJohn Marino 	return wpa_s->conf->ap_scan == 2 ||
68363ff40c12SJohn Marino 		(wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION);
68373ff40c12SJohn Marino }
68383ff40c12SJohn Marino 
68393ff40c12SJohn Marino 
68403ff40c12SJohn Marino #if defined(CONFIG_CTRL_IFACE) || defined(CONFIG_CTRL_IFACE_DBUS_NEW)
wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid,const char * field,const char * value)68413ff40c12SJohn Marino int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
68423ff40c12SJohn Marino 					      struct wpa_ssid *ssid,
68433ff40c12SJohn Marino 					      const char *field,
68443ff40c12SJohn Marino 					      const char *value)
68453ff40c12SJohn Marino {
68463ff40c12SJohn Marino #ifdef IEEE8021X_EAPOL
68473ff40c12SJohn Marino 	struct eap_peer_config *eap = &ssid->eap;
68483ff40c12SJohn Marino 
68493ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "CTRL_IFACE: response handle field=%s", field);
68503ff40c12SJohn Marino 	wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: response value",
68513ff40c12SJohn Marino 			      (const u8 *) value, os_strlen(value));
68523ff40c12SJohn Marino 
68533ff40c12SJohn Marino 	switch (wpa_supplicant_ctrl_req_from_string(field)) {
68543ff40c12SJohn Marino 	case WPA_CTRL_REQ_EAP_IDENTITY:
68553ff40c12SJohn Marino 		os_free(eap->identity);
68563ff40c12SJohn Marino 		eap->identity = (u8 *) os_strdup(value);
68573ff40c12SJohn Marino 		eap->identity_len = os_strlen(value);
68583ff40c12SJohn Marino 		eap->pending_req_identity = 0;
68593ff40c12SJohn Marino 		if (ssid == wpa_s->current_ssid)
68603ff40c12SJohn Marino 			wpa_s->reassociate = 1;
68613ff40c12SJohn Marino 		break;
68623ff40c12SJohn Marino 	case WPA_CTRL_REQ_EAP_PASSWORD:
6863*a1157835SDaniel Fojt 		bin_clear_free(eap->password, eap->password_len);
68643ff40c12SJohn Marino 		eap->password = (u8 *) os_strdup(value);
68653ff40c12SJohn Marino 		eap->password_len = os_strlen(value);
68663ff40c12SJohn Marino 		eap->pending_req_password = 0;
68673ff40c12SJohn Marino 		if (ssid == wpa_s->current_ssid)
68683ff40c12SJohn Marino 			wpa_s->reassociate = 1;
68693ff40c12SJohn Marino 		break;
68703ff40c12SJohn Marino 	case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
6871*a1157835SDaniel Fojt 		bin_clear_free(eap->new_password, eap->new_password_len);
68723ff40c12SJohn Marino 		eap->new_password = (u8 *) os_strdup(value);
68733ff40c12SJohn Marino 		eap->new_password_len = os_strlen(value);
68743ff40c12SJohn Marino 		eap->pending_req_new_password = 0;
68753ff40c12SJohn Marino 		if (ssid == wpa_s->current_ssid)
68763ff40c12SJohn Marino 			wpa_s->reassociate = 1;
68773ff40c12SJohn Marino 		break;
68783ff40c12SJohn Marino 	case WPA_CTRL_REQ_EAP_PIN:
6879*a1157835SDaniel Fojt 		str_clear_free(eap->pin);
68803ff40c12SJohn Marino 		eap->pin = os_strdup(value);
68813ff40c12SJohn Marino 		eap->pending_req_pin = 0;
68823ff40c12SJohn Marino 		if (ssid == wpa_s->current_ssid)
68833ff40c12SJohn Marino 			wpa_s->reassociate = 1;
68843ff40c12SJohn Marino 		break;
68853ff40c12SJohn Marino 	case WPA_CTRL_REQ_EAP_OTP:
6886*a1157835SDaniel Fojt 		bin_clear_free(eap->otp, eap->otp_len);
68873ff40c12SJohn Marino 		eap->otp = (u8 *) os_strdup(value);
68883ff40c12SJohn Marino 		eap->otp_len = os_strlen(value);
68893ff40c12SJohn Marino 		os_free(eap->pending_req_otp);
68903ff40c12SJohn Marino 		eap->pending_req_otp = NULL;
68913ff40c12SJohn Marino 		eap->pending_req_otp_len = 0;
68923ff40c12SJohn Marino 		break;
68933ff40c12SJohn Marino 	case WPA_CTRL_REQ_EAP_PASSPHRASE:
6894*a1157835SDaniel Fojt 		str_clear_free(eap->private_key_passwd);
6895*a1157835SDaniel Fojt 		eap->private_key_passwd = os_strdup(value);
68963ff40c12SJohn Marino 		eap->pending_req_passphrase = 0;
68973ff40c12SJohn Marino 		if (ssid == wpa_s->current_ssid)
68983ff40c12SJohn Marino 			wpa_s->reassociate = 1;
68993ff40c12SJohn Marino 		break;
69003ff40c12SJohn Marino 	case WPA_CTRL_REQ_SIM:
6901*a1157835SDaniel Fojt 		str_clear_free(eap->external_sim_resp);
69023ff40c12SJohn Marino 		eap->external_sim_resp = os_strdup(value);
6903*a1157835SDaniel Fojt 		eap->pending_req_sim = 0;
6904*a1157835SDaniel Fojt 		break;
6905*a1157835SDaniel Fojt 	case WPA_CTRL_REQ_PSK_PASSPHRASE:
6906*a1157835SDaniel Fojt 		if (wpa_config_set(ssid, "psk", value, 0) < 0)
6907*a1157835SDaniel Fojt 			return -1;
6908*a1157835SDaniel Fojt 		ssid->mem_only_psk = 1;
6909*a1157835SDaniel Fojt 		if (ssid->passphrase)
6910*a1157835SDaniel Fojt 			wpa_config_update_psk(ssid);
6911*a1157835SDaniel Fojt 		if (wpa_s->wpa_state == WPA_SCANNING && !wpa_s->scanning)
6912*a1157835SDaniel Fojt 			wpa_supplicant_req_scan(wpa_s, 0, 0);
6913*a1157835SDaniel Fojt 		break;
6914*a1157835SDaniel Fojt 	case WPA_CTRL_REQ_EXT_CERT_CHECK:
6915*a1157835SDaniel Fojt 		if (eap->pending_ext_cert_check != PENDING_CHECK)
6916*a1157835SDaniel Fojt 			return -1;
6917*a1157835SDaniel Fojt 		if (os_strcmp(value, "good") == 0)
6918*a1157835SDaniel Fojt 			eap->pending_ext_cert_check = EXT_CERT_CHECK_GOOD;
6919*a1157835SDaniel Fojt 		else if (os_strcmp(value, "bad") == 0)
6920*a1157835SDaniel Fojt 			eap->pending_ext_cert_check = EXT_CERT_CHECK_BAD;
6921*a1157835SDaniel Fojt 		else
6922*a1157835SDaniel Fojt 			return -1;
69233ff40c12SJohn Marino 		break;
69243ff40c12SJohn Marino 	default:
69253ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field);
69263ff40c12SJohn Marino 		return -1;
69273ff40c12SJohn Marino 	}
69283ff40c12SJohn Marino 
69293ff40c12SJohn Marino 	return 0;
69303ff40c12SJohn Marino #else /* IEEE8021X_EAPOL */
69313ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "CTRL_IFACE: IEEE 802.1X not included");
69323ff40c12SJohn Marino 	return -1;
69333ff40c12SJohn Marino #endif /* IEEE8021X_EAPOL */
69343ff40c12SJohn Marino }
69353ff40c12SJohn Marino #endif /* CONFIG_CTRL_IFACE || CONFIG_CTRL_IFACE_DBUS_NEW */
69363ff40c12SJohn Marino 
69373ff40c12SJohn Marino 
wpas_network_disabled(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid)69383ff40c12SJohn Marino int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
69393ff40c12SJohn Marino {
69403ff40c12SJohn Marino 	int i;
69413ff40c12SJohn Marino 	unsigned int drv_enc;
69423ff40c12SJohn Marino 
6943*a1157835SDaniel Fojt 	if (wpa_s->p2p_mgmt)
6944*a1157835SDaniel Fojt 		return 1; /* no normal network profiles on p2p_mgmt interface */
6945*a1157835SDaniel Fojt 
69463ff40c12SJohn Marino 	if (ssid == NULL)
69473ff40c12SJohn Marino 		return 1;
69483ff40c12SJohn Marino 
69493ff40c12SJohn Marino 	if (ssid->disabled)
69503ff40c12SJohn Marino 		return 1;
69513ff40c12SJohn Marino 
6952*a1157835SDaniel Fojt 	if (wpa_s->drv_capa_known)
69533ff40c12SJohn Marino 		drv_enc = wpa_s->drv_enc;
69543ff40c12SJohn Marino 	else
69553ff40c12SJohn Marino 		drv_enc = (unsigned int) -1;
69563ff40c12SJohn Marino 
69573ff40c12SJohn Marino 	for (i = 0; i < NUM_WEP_KEYS; i++) {
69583ff40c12SJohn Marino 		size_t len = ssid->wep_key_len[i];
69593ff40c12SJohn Marino 		if (len == 0)
69603ff40c12SJohn Marino 			continue;
69613ff40c12SJohn Marino 		if (len == 5 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP40))
69623ff40c12SJohn Marino 			continue;
69633ff40c12SJohn Marino 		if (len == 13 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP104))
69643ff40c12SJohn Marino 			continue;
69653ff40c12SJohn Marino 		if (len == 16 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP128))
69663ff40c12SJohn Marino 			continue;
69673ff40c12SJohn Marino 		return 1; /* invalid WEP key */
69683ff40c12SJohn Marino 	}
69693ff40c12SJohn Marino 
69703ff40c12SJohn Marino 	if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
6971*a1157835SDaniel Fojt 	    (!ssid->passphrase || ssid->ssid_len != 0) && !ssid->ext_psk &&
6972*a1157835SDaniel Fojt 	    !(wpa_key_mgmt_sae(ssid->key_mgmt) && ssid->sae_password) &&
6973*a1157835SDaniel Fojt 	    !ssid->mem_only_psk)
69743ff40c12SJohn Marino 		return 1;
69753ff40c12SJohn Marino 
69763ff40c12SJohn Marino 	return 0;
69773ff40c12SJohn Marino }
69783ff40c12SJohn Marino 
69793ff40c12SJohn Marino 
wpas_get_ssid_pmf(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid)6980*a1157835SDaniel Fojt int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
6981*a1157835SDaniel Fojt {
6982*a1157835SDaniel Fojt #ifdef CONFIG_IEEE80211W
6983*a1157835SDaniel Fojt 	if (ssid == NULL || ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) {
6984*a1157835SDaniel Fojt 		if (wpa_s->conf->pmf == MGMT_FRAME_PROTECTION_OPTIONAL &&
6985*a1157835SDaniel Fojt 		    !(wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)) {
6986*a1157835SDaniel Fojt 			/*
6987*a1157835SDaniel Fojt 			 * Driver does not support BIP -- ignore pmf=1 default
6988*a1157835SDaniel Fojt 			 * since the connection with PMF would fail and the
6989*a1157835SDaniel Fojt 			 * configuration does not require PMF to be enabled.
6990*a1157835SDaniel Fojt 			 */
6991*a1157835SDaniel Fojt 			return NO_MGMT_FRAME_PROTECTION;
6992*a1157835SDaniel Fojt 		}
6993*a1157835SDaniel Fojt 
6994*a1157835SDaniel Fojt 		if (ssid &&
6995*a1157835SDaniel Fojt 		    (ssid->key_mgmt &
6996*a1157835SDaniel Fojt 		     ~(WPA_KEY_MGMT_NONE | WPA_KEY_MGMT_WPS |
6997*a1157835SDaniel Fojt 		       WPA_KEY_MGMT_IEEE8021X_NO_WPA)) == 0) {
6998*a1157835SDaniel Fojt 			/*
6999*a1157835SDaniel Fojt 			 * Do not use the default PMF value for non-RSN networks
7000*a1157835SDaniel Fojt 			 * since PMF is available only with RSN and pmf=2
7001*a1157835SDaniel Fojt 			 * configuration would otherwise prevent connections to
7002*a1157835SDaniel Fojt 			 * all open networks.
7003*a1157835SDaniel Fojt 			 */
7004*a1157835SDaniel Fojt 			return NO_MGMT_FRAME_PROTECTION;
7005*a1157835SDaniel Fojt 		}
7006*a1157835SDaniel Fojt 
7007*a1157835SDaniel Fojt 		return wpa_s->conf->pmf;
7008*a1157835SDaniel Fojt 	}
7009*a1157835SDaniel Fojt 
7010*a1157835SDaniel Fojt 	return ssid->ieee80211w;
7011*a1157835SDaniel Fojt #else /* CONFIG_IEEE80211W */
7012*a1157835SDaniel Fojt 	return NO_MGMT_FRAME_PROTECTION;
7013*a1157835SDaniel Fojt #endif /* CONFIG_IEEE80211W */
7014*a1157835SDaniel Fojt }
7015*a1157835SDaniel Fojt 
7016*a1157835SDaniel Fojt 
wpas_is_p2p_prioritized(struct wpa_supplicant * wpa_s)70173ff40c12SJohn Marino int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s)
70183ff40c12SJohn Marino {
70193ff40c12SJohn Marino 	if (wpa_s->global->conc_pref == WPA_CONC_PREF_P2P)
70203ff40c12SJohn Marino 		return 1;
70213ff40c12SJohn Marino 	if (wpa_s->global->conc_pref == WPA_CONC_PREF_STA)
70223ff40c12SJohn Marino 		return 0;
70233ff40c12SJohn Marino 	return -1;
70243ff40c12SJohn Marino }
70253ff40c12SJohn Marino 
70263ff40c12SJohn Marino 
wpas_auth_failed(struct wpa_supplicant * wpa_s,char * reason)7027*a1157835SDaniel Fojt void wpas_auth_failed(struct wpa_supplicant *wpa_s, char *reason)
70283ff40c12SJohn Marino {
70293ff40c12SJohn Marino 	struct wpa_ssid *ssid = wpa_s->current_ssid;
70303ff40c12SJohn Marino 	int dur;
70313ff40c12SJohn Marino 	struct os_reltime now;
70323ff40c12SJohn Marino 
70333ff40c12SJohn Marino 	if (ssid == NULL) {
70343ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "Authentication failure but no known "
70353ff40c12SJohn Marino 			   "SSID block");
70363ff40c12SJohn Marino 		return;
70373ff40c12SJohn Marino 	}
70383ff40c12SJohn Marino 
70393ff40c12SJohn Marino 	if (ssid->key_mgmt == WPA_KEY_MGMT_WPS)
70403ff40c12SJohn Marino 		return;
70413ff40c12SJohn Marino 
70423ff40c12SJohn Marino 	ssid->auth_failures++;
70433ff40c12SJohn Marino 
70443ff40c12SJohn Marino #ifdef CONFIG_P2P
70453ff40c12SJohn Marino 	if (ssid->p2p_group &&
70463ff40c12SJohn Marino 	    (wpa_s->p2p_in_provisioning || wpa_s->show_group_started)) {
70473ff40c12SJohn Marino 		/*
70483ff40c12SJohn Marino 		 * Skip the wait time since there is a short timeout on the
70493ff40c12SJohn Marino 		 * connection to a P2P group.
70503ff40c12SJohn Marino 		 */
70513ff40c12SJohn Marino 		return;
70523ff40c12SJohn Marino 	}
70533ff40c12SJohn Marino #endif /* CONFIG_P2P */
70543ff40c12SJohn Marino 
70553ff40c12SJohn Marino 	if (ssid->auth_failures > 50)
70563ff40c12SJohn Marino 		dur = 300;
70573ff40c12SJohn Marino 	else if (ssid->auth_failures > 10)
7058*a1157835SDaniel Fojt 		dur = 120;
70593ff40c12SJohn Marino 	else if (ssid->auth_failures > 5)
7060*a1157835SDaniel Fojt 		dur = 90;
7061*a1157835SDaniel Fojt 	else if (ssid->auth_failures > 3)
7062*a1157835SDaniel Fojt 		dur = 60;
7063*a1157835SDaniel Fojt 	else if (ssid->auth_failures > 2)
70643ff40c12SJohn Marino 		dur = 30;
70653ff40c12SJohn Marino 	else if (ssid->auth_failures > 1)
70663ff40c12SJohn Marino 		dur = 20;
70673ff40c12SJohn Marino 	else
70683ff40c12SJohn Marino 		dur = 10;
70693ff40c12SJohn Marino 
7070*a1157835SDaniel Fojt 	if (ssid->auth_failures > 1 &&
7071*a1157835SDaniel Fojt 	    wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt))
7072*a1157835SDaniel Fojt 		dur += os_random() % (ssid->auth_failures * 10);
7073*a1157835SDaniel Fojt 
70743ff40c12SJohn Marino 	os_get_reltime(&now);
70753ff40c12SJohn Marino 	if (now.sec + dur <= ssid->disabled_until.sec)
70763ff40c12SJohn Marino 		return;
70773ff40c12SJohn Marino 
70783ff40c12SJohn Marino 	ssid->disabled_until.sec = now.sec + dur;
70793ff40c12SJohn Marino 
70803ff40c12SJohn Marino 	wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TEMP_DISABLED
7081*a1157835SDaniel Fojt 		"id=%d ssid=\"%s\" auth_failures=%u duration=%d reason=%s",
70823ff40c12SJohn Marino 		ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
7083*a1157835SDaniel Fojt 		ssid->auth_failures, dur, reason);
70843ff40c12SJohn Marino }
70853ff40c12SJohn Marino 
70863ff40c12SJohn Marino 
wpas_clear_temp_disabled(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid,int clear_failures)70873ff40c12SJohn Marino void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s,
70883ff40c12SJohn Marino 			      struct wpa_ssid *ssid, int clear_failures)
70893ff40c12SJohn Marino {
70903ff40c12SJohn Marino 	if (ssid == NULL)
70913ff40c12SJohn Marino 		return;
70923ff40c12SJohn Marino 
70933ff40c12SJohn Marino 	if (ssid->disabled_until.sec) {
70943ff40c12SJohn Marino 		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_REENABLED
70953ff40c12SJohn Marino 			"id=%d ssid=\"%s\"",
70963ff40c12SJohn Marino 			ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
70973ff40c12SJohn Marino 	}
70983ff40c12SJohn Marino 	ssid->disabled_until.sec = 0;
70993ff40c12SJohn Marino 	ssid->disabled_until.usec = 0;
71003ff40c12SJohn Marino 	if (clear_failures)
71013ff40c12SJohn Marino 		ssid->auth_failures = 0;
71023ff40c12SJohn Marino }
71033ff40c12SJohn Marino 
71043ff40c12SJohn Marino 
disallowed_bssid(struct wpa_supplicant * wpa_s,const u8 * bssid)71053ff40c12SJohn Marino int disallowed_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid)
71063ff40c12SJohn Marino {
71073ff40c12SJohn Marino 	size_t i;
71083ff40c12SJohn Marino 
71093ff40c12SJohn Marino 	if (wpa_s->disallow_aps_bssid == NULL)
71103ff40c12SJohn Marino 		return 0;
71113ff40c12SJohn Marino 
71123ff40c12SJohn Marino 	for (i = 0; i < wpa_s->disallow_aps_bssid_count; i++) {
71133ff40c12SJohn Marino 		if (os_memcmp(wpa_s->disallow_aps_bssid + i * ETH_ALEN,
71143ff40c12SJohn Marino 			      bssid, ETH_ALEN) == 0)
71153ff40c12SJohn Marino 			return 1;
71163ff40c12SJohn Marino 	}
71173ff40c12SJohn Marino 
71183ff40c12SJohn Marino 	return 0;
71193ff40c12SJohn Marino }
71203ff40c12SJohn Marino 
71213ff40c12SJohn Marino 
disallowed_ssid(struct wpa_supplicant * wpa_s,const u8 * ssid,size_t ssid_len)71223ff40c12SJohn Marino int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid,
71233ff40c12SJohn Marino 		    size_t ssid_len)
71243ff40c12SJohn Marino {
71253ff40c12SJohn Marino 	size_t i;
71263ff40c12SJohn Marino 
71273ff40c12SJohn Marino 	if (wpa_s->disallow_aps_ssid == NULL || ssid == NULL)
71283ff40c12SJohn Marino 		return 0;
71293ff40c12SJohn Marino 
71303ff40c12SJohn Marino 	for (i = 0; i < wpa_s->disallow_aps_ssid_count; i++) {
71313ff40c12SJohn Marino 		struct wpa_ssid_value *s = &wpa_s->disallow_aps_ssid[i];
71323ff40c12SJohn Marino 		if (ssid_len == s->ssid_len &&
71333ff40c12SJohn Marino 		    os_memcmp(ssid, s->ssid, ssid_len) == 0)
71343ff40c12SJohn Marino 			return 1;
71353ff40c12SJohn Marino 	}
71363ff40c12SJohn Marino 
71373ff40c12SJohn Marino 	return 0;
71383ff40c12SJohn Marino }
71393ff40c12SJohn Marino 
71403ff40c12SJohn Marino 
71413ff40c12SJohn Marino /**
71423ff40c12SJohn Marino  * wpas_request_connection - Request a new connection
71433ff40c12SJohn Marino  * @wpa_s: Pointer to the network interface
71443ff40c12SJohn Marino  *
71453ff40c12SJohn Marino  * This function is used to request a new connection to be found. It will mark
71463ff40c12SJohn Marino  * the interface to allow reassociation and request a new scan to find a
71473ff40c12SJohn Marino  * suitable network to connect to.
71483ff40c12SJohn Marino  */
wpas_request_connection(struct wpa_supplicant * wpa_s)71493ff40c12SJohn Marino void wpas_request_connection(struct wpa_supplicant *wpa_s)
71503ff40c12SJohn Marino {
71513ff40c12SJohn Marino 	wpa_s->normal_scans = 0;
7152*a1157835SDaniel Fojt 	wpa_s->scan_req = NORMAL_SCAN_REQ;
71533ff40c12SJohn Marino 	wpa_supplicant_reinit_autoscan(wpa_s);
71543ff40c12SJohn Marino 	wpa_s->extra_blacklist_count = 0;
71553ff40c12SJohn Marino 	wpa_s->disconnected = 0;
71563ff40c12SJohn Marino 	wpa_s->reassociate = 1;
7157*a1157835SDaniel Fojt 	wpa_s->last_owe_group = 0;
71583ff40c12SJohn Marino 
71593ff40c12SJohn Marino 	if (wpa_supplicant_fast_associate(wpa_s) != 1)
71603ff40c12SJohn Marino 		wpa_supplicant_req_scan(wpa_s, 0, 0);
7161*a1157835SDaniel Fojt 	else
7162*a1157835SDaniel Fojt 		wpa_s->reattach = 0;
71633ff40c12SJohn Marino }
71643ff40c12SJohn Marino 
71653ff40c12SJohn Marino 
7166*a1157835SDaniel Fojt /**
7167*a1157835SDaniel Fojt  * wpas_request_disconnection - Request disconnection
7168*a1157835SDaniel Fojt  * @wpa_s: Pointer to the network interface
7169*a1157835SDaniel Fojt  *
7170*a1157835SDaniel Fojt  * This function is used to request disconnection from the currently connected
7171*a1157835SDaniel Fojt  * network. This will stop any ongoing scans and initiate deauthentication.
7172*a1157835SDaniel Fojt  */
wpas_request_disconnection(struct wpa_supplicant * wpa_s)7173*a1157835SDaniel Fojt void wpas_request_disconnection(struct wpa_supplicant *wpa_s)
7174*a1157835SDaniel Fojt {
7175*a1157835SDaniel Fojt #ifdef CONFIG_SME
7176*a1157835SDaniel Fojt 	wpa_s->sme.prev_bssid_set = 0;
7177*a1157835SDaniel Fojt #endif /* CONFIG_SME */
7178*a1157835SDaniel Fojt 	wpa_s->reassociate = 0;
7179*a1157835SDaniel Fojt 	wpa_s->disconnected = 1;
7180*a1157835SDaniel Fojt 	wpa_supplicant_cancel_sched_scan(wpa_s);
7181*a1157835SDaniel Fojt 	wpa_supplicant_cancel_scan(wpa_s);
7182*a1157835SDaniel Fojt 	wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
7183*a1157835SDaniel Fojt 	eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
7184*a1157835SDaniel Fojt 	radio_remove_works(wpa_s, "connect", 0);
7185*a1157835SDaniel Fojt 	radio_remove_works(wpa_s, "sme-connect", 0);
7186*a1157835SDaniel Fojt }
7187*a1157835SDaniel Fojt 
7188*a1157835SDaniel Fojt 
dump_freq_data(struct wpa_supplicant * wpa_s,const char * title,struct wpa_used_freq_data * freqs_data,unsigned int len)7189*a1157835SDaniel Fojt void dump_freq_data(struct wpa_supplicant *wpa_s, const char *title,
7190*a1157835SDaniel Fojt 		    struct wpa_used_freq_data *freqs_data,
7191*a1157835SDaniel Fojt 		    unsigned int len)
71923ff40c12SJohn Marino {
71933ff40c12SJohn Marino 	unsigned int i;
71943ff40c12SJohn Marino 
71953ff40c12SJohn Marino 	wpa_dbg(wpa_s, MSG_DEBUG, "Shared frequencies (len=%u): %s",
71963ff40c12SJohn Marino 		len, title);
7197*a1157835SDaniel Fojt 	for (i = 0; i < len; i++) {
7198*a1157835SDaniel Fojt 		struct wpa_used_freq_data *cur = &freqs_data[i];
7199*a1157835SDaniel Fojt 		wpa_dbg(wpa_s, MSG_DEBUG, "freq[%u]: %d, flags=0x%X",
7200*a1157835SDaniel Fojt 			i, cur->freq, cur->flags);
7201*a1157835SDaniel Fojt 	}
7202*a1157835SDaniel Fojt }
7203*a1157835SDaniel Fojt 
7204*a1157835SDaniel Fojt 
7205*a1157835SDaniel Fojt /*
7206*a1157835SDaniel Fojt  * Find the operating frequencies of any of the virtual interfaces that
7207*a1157835SDaniel Fojt  * are using the same radio as the current interface, and in addition, get
7208*a1157835SDaniel Fojt  * information about the interface types that are using the frequency.
7209*a1157835SDaniel Fojt  */
get_shared_radio_freqs_data(struct wpa_supplicant * wpa_s,struct wpa_used_freq_data * freqs_data,unsigned int len)7210*a1157835SDaniel Fojt int get_shared_radio_freqs_data(struct wpa_supplicant *wpa_s,
7211*a1157835SDaniel Fojt 				struct wpa_used_freq_data *freqs_data,
7212*a1157835SDaniel Fojt 				unsigned int len)
7213*a1157835SDaniel Fojt {
7214*a1157835SDaniel Fojt 	struct wpa_supplicant *ifs;
7215*a1157835SDaniel Fojt 	u8 bssid[ETH_ALEN];
7216*a1157835SDaniel Fojt 	int freq;
7217*a1157835SDaniel Fojt 	unsigned int idx = 0, i;
7218*a1157835SDaniel Fojt 
7219*a1157835SDaniel Fojt 	wpa_dbg(wpa_s, MSG_DEBUG,
7220*a1157835SDaniel Fojt 		"Determining shared radio frequencies (max len %u)", len);
7221*a1157835SDaniel Fojt 	os_memset(freqs_data, 0, sizeof(struct wpa_used_freq_data) * len);
7222*a1157835SDaniel Fojt 
7223*a1157835SDaniel Fojt 	dl_list_for_each(ifs, &wpa_s->radio->ifaces, struct wpa_supplicant,
7224*a1157835SDaniel Fojt 			 radio_list) {
7225*a1157835SDaniel Fojt 		if (idx == len)
7226*a1157835SDaniel Fojt 			break;
7227*a1157835SDaniel Fojt 
7228*a1157835SDaniel Fojt 		if (ifs->current_ssid == NULL || ifs->assoc_freq == 0)
7229*a1157835SDaniel Fojt 			continue;
7230*a1157835SDaniel Fojt 
7231*a1157835SDaniel Fojt 		if (ifs->current_ssid->mode == WPAS_MODE_AP ||
7232*a1157835SDaniel Fojt 		    ifs->current_ssid->mode == WPAS_MODE_P2P_GO ||
7233*a1157835SDaniel Fojt 		    ifs->current_ssid->mode == WPAS_MODE_MESH)
7234*a1157835SDaniel Fojt 			freq = ifs->current_ssid->frequency;
7235*a1157835SDaniel Fojt 		else if (wpa_drv_get_bssid(ifs, bssid) == 0)
7236*a1157835SDaniel Fojt 			freq = ifs->assoc_freq;
7237*a1157835SDaniel Fojt 		else
7238*a1157835SDaniel Fojt 			continue;
7239*a1157835SDaniel Fojt 
7240*a1157835SDaniel Fojt 		/* Hold only distinct freqs */
7241*a1157835SDaniel Fojt 		for (i = 0; i < idx; i++)
7242*a1157835SDaniel Fojt 			if (freqs_data[i].freq == freq)
7243*a1157835SDaniel Fojt 				break;
7244*a1157835SDaniel Fojt 
7245*a1157835SDaniel Fojt 		if (i == idx)
7246*a1157835SDaniel Fojt 			freqs_data[idx++].freq = freq;
7247*a1157835SDaniel Fojt 
7248*a1157835SDaniel Fojt 		if (ifs->current_ssid->mode == WPAS_MODE_INFRA) {
7249*a1157835SDaniel Fojt 			freqs_data[i].flags |= ifs->current_ssid->p2p_group ?
7250*a1157835SDaniel Fojt 				WPA_FREQ_USED_BY_P2P_CLIENT :
7251*a1157835SDaniel Fojt 				WPA_FREQ_USED_BY_INFRA_STATION;
7252*a1157835SDaniel Fojt 		}
7253*a1157835SDaniel Fojt 	}
7254*a1157835SDaniel Fojt 
7255*a1157835SDaniel Fojt 	dump_freq_data(wpa_s, "completed iteration", freqs_data, idx);
7256*a1157835SDaniel Fojt 	return idx;
72573ff40c12SJohn Marino }
72583ff40c12SJohn Marino 
72593ff40c12SJohn Marino 
72603ff40c12SJohn Marino /*
72613ff40c12SJohn Marino  * Find the operating frequencies of any of the virtual interfaces that
72623ff40c12SJohn Marino  * are using the same radio as the current interface.
72633ff40c12SJohn Marino  */
get_shared_radio_freqs(struct wpa_supplicant * wpa_s,int * freq_array,unsigned int len)72643ff40c12SJohn Marino int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
72653ff40c12SJohn Marino 			   int *freq_array, unsigned int len)
72663ff40c12SJohn Marino {
7267*a1157835SDaniel Fojt 	struct wpa_used_freq_data *freqs_data;
7268*a1157835SDaniel Fojt 	int num, i;
72693ff40c12SJohn Marino 
72703ff40c12SJohn Marino 	os_memset(freq_array, 0, sizeof(int) * len);
72713ff40c12SJohn Marino 
7272*a1157835SDaniel Fojt 	freqs_data = os_calloc(len, sizeof(struct wpa_used_freq_data));
7273*a1157835SDaniel Fojt 	if (!freqs_data)
7274*a1157835SDaniel Fojt 		return -1;
7275*a1157835SDaniel Fojt 
7276*a1157835SDaniel Fojt 	num = get_shared_radio_freqs_data(wpa_s, freqs_data, len);
7277*a1157835SDaniel Fojt 	for (i = 0; i < num; i++)
7278*a1157835SDaniel Fojt 		freq_array[i] = freqs_data[i].freq;
7279*a1157835SDaniel Fojt 
7280*a1157835SDaniel Fojt 	os_free(freqs_data);
7281*a1157835SDaniel Fojt 
7282*a1157835SDaniel Fojt 	return num;
72833ff40c12SJohn Marino }
72843ff40c12SJohn Marino 
7285*a1157835SDaniel Fojt 
7286*a1157835SDaniel Fojt struct wpa_supplicant *
wpas_vendor_elem(struct wpa_supplicant * wpa_s,enum wpa_vendor_elem_frame frame)7287*a1157835SDaniel Fojt wpas_vendor_elem(struct wpa_supplicant *wpa_s, enum wpa_vendor_elem_frame frame)
7288*a1157835SDaniel Fojt {
7289*a1157835SDaniel Fojt 	switch (frame) {
7290*a1157835SDaniel Fojt #ifdef CONFIG_P2P
7291*a1157835SDaniel Fojt 	case VENDOR_ELEM_PROBE_REQ_P2P:
7292*a1157835SDaniel Fojt 	case VENDOR_ELEM_PROBE_RESP_P2P:
7293*a1157835SDaniel Fojt 	case VENDOR_ELEM_PROBE_RESP_P2P_GO:
7294*a1157835SDaniel Fojt 	case VENDOR_ELEM_BEACON_P2P_GO:
7295*a1157835SDaniel Fojt 	case VENDOR_ELEM_P2P_PD_REQ:
7296*a1157835SDaniel Fojt 	case VENDOR_ELEM_P2P_PD_RESP:
7297*a1157835SDaniel Fojt 	case VENDOR_ELEM_P2P_GO_NEG_REQ:
7298*a1157835SDaniel Fojt 	case VENDOR_ELEM_P2P_GO_NEG_RESP:
7299*a1157835SDaniel Fojt 	case VENDOR_ELEM_P2P_GO_NEG_CONF:
7300*a1157835SDaniel Fojt 	case VENDOR_ELEM_P2P_INV_REQ:
7301*a1157835SDaniel Fojt 	case VENDOR_ELEM_P2P_INV_RESP:
7302*a1157835SDaniel Fojt 	case VENDOR_ELEM_P2P_ASSOC_REQ:
7303*a1157835SDaniel Fojt 	case VENDOR_ELEM_P2P_ASSOC_RESP:
7304*a1157835SDaniel Fojt 		return wpa_s->p2pdev;
7305*a1157835SDaniel Fojt #endif /* CONFIG_P2P */
7306*a1157835SDaniel Fojt 	default:
7307*a1157835SDaniel Fojt 		return wpa_s;
7308*a1157835SDaniel Fojt 	}
73093ff40c12SJohn Marino }
73103ff40c12SJohn Marino 
73113ff40c12SJohn Marino 
wpas_vendor_elem_update(struct wpa_supplicant * wpa_s)7312*a1157835SDaniel Fojt void wpas_vendor_elem_update(struct wpa_supplicant *wpa_s)
7313*a1157835SDaniel Fojt {
7314*a1157835SDaniel Fojt 	unsigned int i;
7315*a1157835SDaniel Fojt 	char buf[30];
73163ff40c12SJohn Marino 
7317*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "Update vendor elements");
73183ff40c12SJohn Marino 
7319*a1157835SDaniel Fojt 	for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) {
7320*a1157835SDaniel Fojt 		if (wpa_s->vendor_elem[i]) {
7321*a1157835SDaniel Fojt 			int res;
7322*a1157835SDaniel Fojt 
7323*a1157835SDaniel Fojt 			res = os_snprintf(buf, sizeof(buf), "frame[%u]", i);
7324*a1157835SDaniel Fojt 			if (!os_snprintf_error(sizeof(buf), res)) {
7325*a1157835SDaniel Fojt 				wpa_hexdump_buf(MSG_DEBUG, buf,
7326*a1157835SDaniel Fojt 						wpa_s->vendor_elem[i]);
7327*a1157835SDaniel Fojt 			}
7328*a1157835SDaniel Fojt 		}
7329*a1157835SDaniel Fojt 	}
7330*a1157835SDaniel Fojt 
7331*a1157835SDaniel Fojt #ifdef CONFIG_P2P
7332*a1157835SDaniel Fojt 	if (wpa_s->parent == wpa_s &&
7333*a1157835SDaniel Fojt 	    wpa_s->global->p2p &&
7334*a1157835SDaniel Fojt 	    !wpa_s->global->p2p_disabled)
7335*a1157835SDaniel Fojt 		p2p_set_vendor_elems(wpa_s->global->p2p, wpa_s->vendor_elem);
7336*a1157835SDaniel Fojt #endif /* CONFIG_P2P */
7337*a1157835SDaniel Fojt }
7338*a1157835SDaniel Fojt 
7339*a1157835SDaniel Fojt 
wpas_vendor_elem_remove(struct wpa_supplicant * wpa_s,int frame,const u8 * elem,size_t len)7340*a1157835SDaniel Fojt int wpas_vendor_elem_remove(struct wpa_supplicant *wpa_s, int frame,
7341*a1157835SDaniel Fojt 			    const u8 *elem, size_t len)
7342*a1157835SDaniel Fojt {
7343*a1157835SDaniel Fojt 	u8 *ie, *end;
7344*a1157835SDaniel Fojt 
7345*a1157835SDaniel Fojt 	ie = wpabuf_mhead_u8(wpa_s->vendor_elem[frame]);
7346*a1157835SDaniel Fojt 	end = ie + wpabuf_len(wpa_s->vendor_elem[frame]);
7347*a1157835SDaniel Fojt 
7348*a1157835SDaniel Fojt 	for (; ie + 1 < end; ie += 2 + ie[1]) {
7349*a1157835SDaniel Fojt 		if (ie + len > end)
73503ff40c12SJohn Marino 			break;
7351*a1157835SDaniel Fojt 		if (os_memcmp(ie, elem, len) != 0)
7352*a1157835SDaniel Fojt 			continue;
73533ff40c12SJohn Marino 
7354*a1157835SDaniel Fojt 		if (wpabuf_len(wpa_s->vendor_elem[frame]) == len) {
7355*a1157835SDaniel Fojt 			wpabuf_free(wpa_s->vendor_elem[frame]);
7356*a1157835SDaniel Fojt 			wpa_s->vendor_elem[frame] = NULL;
7357*a1157835SDaniel Fojt 		} else {
7358*a1157835SDaniel Fojt 			os_memmove(ie, ie + len, end - (ie + len));
7359*a1157835SDaniel Fojt 			wpa_s->vendor_elem[frame]->used -= len;
7360*a1157835SDaniel Fojt 		}
7361*a1157835SDaniel Fojt 		wpas_vendor_elem_update(wpa_s);
7362*a1157835SDaniel Fojt 		return 0;
73633ff40c12SJohn Marino 	}
73643ff40c12SJohn Marino 
7365*a1157835SDaniel Fojt 	return -1;
7366*a1157835SDaniel Fojt }
7367*a1157835SDaniel Fojt 
7368*a1157835SDaniel Fojt 
get_mode(struct hostapd_hw_modes * modes,u16 num_modes,enum hostapd_hw_mode mode)7369*a1157835SDaniel Fojt struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
7370*a1157835SDaniel Fojt 				   u16 num_modes, enum hostapd_hw_mode mode)
7371*a1157835SDaniel Fojt {
7372*a1157835SDaniel Fojt 	u16 i;
7373*a1157835SDaniel Fojt 
7374*a1157835SDaniel Fojt 	for (i = 0; i < num_modes; i++) {
7375*a1157835SDaniel Fojt 		if (modes[i].mode == mode)
7376*a1157835SDaniel Fojt 			return &modes[i];
7377*a1157835SDaniel Fojt 	}
7378*a1157835SDaniel Fojt 
7379*a1157835SDaniel Fojt 	return NULL;
7380*a1157835SDaniel Fojt }
7381*a1157835SDaniel Fojt 
7382*a1157835SDaniel Fojt 
7383*a1157835SDaniel Fojt static struct
wpas_get_disallowed_bss(struct wpa_supplicant * wpa_s,const u8 * bssid)7384*a1157835SDaniel Fojt wpa_bss_tmp_disallowed * wpas_get_disallowed_bss(struct wpa_supplicant *wpa_s,
7385*a1157835SDaniel Fojt 						 const u8 *bssid)
7386*a1157835SDaniel Fojt {
7387*a1157835SDaniel Fojt 	struct wpa_bss_tmp_disallowed *bss;
7388*a1157835SDaniel Fojt 
7389*a1157835SDaniel Fojt 	dl_list_for_each(bss, &wpa_s->bss_tmp_disallowed,
7390*a1157835SDaniel Fojt 			 struct wpa_bss_tmp_disallowed, list) {
7391*a1157835SDaniel Fojt 		if (os_memcmp(bssid, bss->bssid, ETH_ALEN) == 0)
7392*a1157835SDaniel Fojt 			return bss;
7393*a1157835SDaniel Fojt 	}
7394*a1157835SDaniel Fojt 
7395*a1157835SDaniel Fojt 	return NULL;
7396*a1157835SDaniel Fojt }
7397*a1157835SDaniel Fojt 
7398*a1157835SDaniel Fojt 
wpa_set_driver_tmp_disallow_list(struct wpa_supplicant * wpa_s)7399*a1157835SDaniel Fojt static int wpa_set_driver_tmp_disallow_list(struct wpa_supplicant *wpa_s)
7400*a1157835SDaniel Fojt {
7401*a1157835SDaniel Fojt 	struct wpa_bss_tmp_disallowed *tmp;
7402*a1157835SDaniel Fojt 	unsigned int num_bssid = 0;
7403*a1157835SDaniel Fojt 	u8 *bssids;
7404*a1157835SDaniel Fojt 	int ret;
7405*a1157835SDaniel Fojt 
7406*a1157835SDaniel Fojt 	bssids = os_malloc(dl_list_len(&wpa_s->bss_tmp_disallowed) * ETH_ALEN);
7407*a1157835SDaniel Fojt 	if (!bssids)
7408*a1157835SDaniel Fojt 		return -1;
7409*a1157835SDaniel Fojt 	dl_list_for_each(tmp, &wpa_s->bss_tmp_disallowed,
7410*a1157835SDaniel Fojt 			 struct wpa_bss_tmp_disallowed, list) {
7411*a1157835SDaniel Fojt 		os_memcpy(&bssids[num_bssid * ETH_ALEN], tmp->bssid,
7412*a1157835SDaniel Fojt 			  ETH_ALEN);
7413*a1157835SDaniel Fojt 		num_bssid++;
7414*a1157835SDaniel Fojt 	}
7415*a1157835SDaniel Fojt 	ret = wpa_drv_set_bssid_blacklist(wpa_s, num_bssid, bssids);
7416*a1157835SDaniel Fojt 	os_free(bssids);
7417*a1157835SDaniel Fojt 	return ret;
7418*a1157835SDaniel Fojt }
7419*a1157835SDaniel Fojt 
7420*a1157835SDaniel Fojt 
wpa_bss_tmp_disallow_timeout(void * eloop_ctx,void * timeout_ctx)7421*a1157835SDaniel Fojt static void wpa_bss_tmp_disallow_timeout(void *eloop_ctx, void *timeout_ctx)
7422*a1157835SDaniel Fojt {
7423*a1157835SDaniel Fojt 	struct wpa_supplicant *wpa_s = eloop_ctx;
7424*a1157835SDaniel Fojt 	struct wpa_bss_tmp_disallowed *tmp, *bss = timeout_ctx;
7425*a1157835SDaniel Fojt 
7426*a1157835SDaniel Fojt 	/* Make sure the bss is not already freed */
7427*a1157835SDaniel Fojt 	dl_list_for_each(tmp, &wpa_s->bss_tmp_disallowed,
7428*a1157835SDaniel Fojt 			 struct wpa_bss_tmp_disallowed, list) {
7429*a1157835SDaniel Fojt 		if (bss == tmp) {
7430*a1157835SDaniel Fojt 			dl_list_del(&tmp->list);
7431*a1157835SDaniel Fojt 			os_free(tmp);
7432*a1157835SDaniel Fojt 			wpa_set_driver_tmp_disallow_list(wpa_s);
7433*a1157835SDaniel Fojt 			break;
7434*a1157835SDaniel Fojt 		}
7435*a1157835SDaniel Fojt 	}
7436*a1157835SDaniel Fojt }
7437*a1157835SDaniel Fojt 
7438*a1157835SDaniel Fojt 
wpa_bss_tmp_disallow(struct wpa_supplicant * wpa_s,const u8 * bssid,unsigned int sec,int rssi_threshold)7439*a1157835SDaniel Fojt void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
7440*a1157835SDaniel Fojt 			  unsigned int sec, int rssi_threshold)
7441*a1157835SDaniel Fojt {
7442*a1157835SDaniel Fojt 	struct wpa_bss_tmp_disallowed *bss;
7443*a1157835SDaniel Fojt 
7444*a1157835SDaniel Fojt 	bss = wpas_get_disallowed_bss(wpa_s, bssid);
7445*a1157835SDaniel Fojt 	if (bss) {
7446*a1157835SDaniel Fojt 		eloop_cancel_timeout(wpa_bss_tmp_disallow_timeout, wpa_s, bss);
7447*a1157835SDaniel Fojt 		goto finish;
7448*a1157835SDaniel Fojt 	}
7449*a1157835SDaniel Fojt 
7450*a1157835SDaniel Fojt 	bss = os_malloc(sizeof(*bss));
7451*a1157835SDaniel Fojt 	if (!bss) {
7452*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
7453*a1157835SDaniel Fojt 			   "Failed to allocate memory for temp disallow BSS");
7454*a1157835SDaniel Fojt 		return;
7455*a1157835SDaniel Fojt 	}
7456*a1157835SDaniel Fojt 
7457*a1157835SDaniel Fojt 	os_memcpy(bss->bssid, bssid, ETH_ALEN);
7458*a1157835SDaniel Fojt 	dl_list_add(&wpa_s->bss_tmp_disallowed, &bss->list);
7459*a1157835SDaniel Fojt 	wpa_set_driver_tmp_disallow_list(wpa_s);
7460*a1157835SDaniel Fojt 
7461*a1157835SDaniel Fojt finish:
7462*a1157835SDaniel Fojt 	bss->rssi_threshold = rssi_threshold;
7463*a1157835SDaniel Fojt 	eloop_register_timeout(sec, 0, wpa_bss_tmp_disallow_timeout,
7464*a1157835SDaniel Fojt 			       wpa_s, bss);
7465*a1157835SDaniel Fojt }
7466*a1157835SDaniel Fojt 
7467*a1157835SDaniel Fojt 
wpa_is_bss_tmp_disallowed(struct wpa_supplicant * wpa_s,struct wpa_bss * bss)7468*a1157835SDaniel Fojt int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s,
7469*a1157835SDaniel Fojt 			      struct wpa_bss *bss)
7470*a1157835SDaniel Fojt {
7471*a1157835SDaniel Fojt 	struct wpa_bss_tmp_disallowed *disallowed = NULL, *tmp, *prev;
7472*a1157835SDaniel Fojt 
7473*a1157835SDaniel Fojt 	dl_list_for_each_safe(tmp, prev, &wpa_s->bss_tmp_disallowed,
7474*a1157835SDaniel Fojt 			 struct wpa_bss_tmp_disallowed, list) {
7475*a1157835SDaniel Fojt 		if (os_memcmp(bss->bssid, tmp->bssid, ETH_ALEN) == 0) {
7476*a1157835SDaniel Fojt 			disallowed = tmp;
7477*a1157835SDaniel Fojt 			break;
7478*a1157835SDaniel Fojt 		}
7479*a1157835SDaniel Fojt 	}
7480*a1157835SDaniel Fojt 	if (!disallowed)
7481*a1157835SDaniel Fojt 		return 0;
7482*a1157835SDaniel Fojt 
7483*a1157835SDaniel Fojt 	if (disallowed->rssi_threshold != 0 &&
7484*a1157835SDaniel Fojt 	    bss->level > disallowed->rssi_threshold)
7485*a1157835SDaniel Fojt 		return 0;
7486*a1157835SDaniel Fojt 
7487*a1157835SDaniel Fojt 	return 1;
7488*a1157835SDaniel Fojt }
7489*a1157835SDaniel Fojt 
7490*a1157835SDaniel Fojt 
wpas_enable_mac_addr_randomization(struct wpa_supplicant * wpa_s,unsigned int type,const u8 * addr,const u8 * mask)7491*a1157835SDaniel Fojt int wpas_enable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
7492*a1157835SDaniel Fojt 				       unsigned int type, const u8 *addr,
7493*a1157835SDaniel Fojt 				       const u8 *mask)
7494*a1157835SDaniel Fojt {
7495*a1157835SDaniel Fojt 	if ((addr && !mask) || (!addr && mask)) {
7496*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
7497*a1157835SDaniel Fojt 			   "MAC_ADDR_RAND_SCAN invalid addr/mask combination");
7498*a1157835SDaniel Fojt 		return -1;
7499*a1157835SDaniel Fojt 	}
7500*a1157835SDaniel Fojt 
7501*a1157835SDaniel Fojt 	if (addr && mask && (!(mask[0] & 0x01) || (addr[0] & 0x01))) {
7502*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
7503*a1157835SDaniel Fojt 			   "MAC_ADDR_RAND_SCAN cannot allow multicast address");
7504*a1157835SDaniel Fojt 		return -1;
7505*a1157835SDaniel Fojt 	}
7506*a1157835SDaniel Fojt 
7507*a1157835SDaniel Fojt 	if (type & MAC_ADDR_RAND_SCAN) {
7508*a1157835SDaniel Fojt 		if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
7509*a1157835SDaniel Fojt 						addr, mask))
7510*a1157835SDaniel Fojt 			return -1;
7511*a1157835SDaniel Fojt 	}
7512*a1157835SDaniel Fojt 
7513*a1157835SDaniel Fojt 	if (type & MAC_ADDR_RAND_SCHED_SCAN) {
7514*a1157835SDaniel Fojt 		if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
7515*a1157835SDaniel Fojt 						addr, mask))
7516*a1157835SDaniel Fojt 			return -1;
7517*a1157835SDaniel Fojt 
7518*a1157835SDaniel Fojt 		if (wpa_s->sched_scanning && !wpa_s->pno)
7519*a1157835SDaniel Fojt 			wpas_scan_restart_sched_scan(wpa_s);
7520*a1157835SDaniel Fojt 	}
7521*a1157835SDaniel Fojt 
7522*a1157835SDaniel Fojt 	if (type & MAC_ADDR_RAND_PNO) {
7523*a1157835SDaniel Fojt 		if (wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO,
7524*a1157835SDaniel Fojt 						addr, mask))
7525*a1157835SDaniel Fojt 			return -1;
7526*a1157835SDaniel Fojt 
7527*a1157835SDaniel Fojt 		if (wpa_s->pno) {
7528*a1157835SDaniel Fojt 			wpas_stop_pno(wpa_s);
7529*a1157835SDaniel Fojt 			wpas_start_pno(wpa_s);
7530*a1157835SDaniel Fojt 		}
7531*a1157835SDaniel Fojt 	}
7532*a1157835SDaniel Fojt 
7533*a1157835SDaniel Fojt 	return 0;
7534*a1157835SDaniel Fojt }
7535*a1157835SDaniel Fojt 
7536*a1157835SDaniel Fojt 
wpas_disable_mac_addr_randomization(struct wpa_supplicant * wpa_s,unsigned int type)7537*a1157835SDaniel Fojt int wpas_disable_mac_addr_randomization(struct wpa_supplicant *wpa_s,
7538*a1157835SDaniel Fojt 					unsigned int type)
7539*a1157835SDaniel Fojt {
7540*a1157835SDaniel Fojt 	wpas_mac_addr_rand_scan_clear(wpa_s, type);
7541*a1157835SDaniel Fojt 	if (wpa_s->pno) {
7542*a1157835SDaniel Fojt 		if (type & MAC_ADDR_RAND_PNO) {
7543*a1157835SDaniel Fojt 			wpas_stop_pno(wpa_s);
7544*a1157835SDaniel Fojt 			wpas_start_pno(wpa_s);
7545*a1157835SDaniel Fojt 		}
7546*a1157835SDaniel Fojt 	} else if (wpa_s->sched_scanning && (type & MAC_ADDR_RAND_SCHED_SCAN)) {
7547*a1157835SDaniel Fojt 		wpas_scan_restart_sched_scan(wpa_s);
7548*a1157835SDaniel Fojt 	}
7549*a1157835SDaniel Fojt 
7550*a1157835SDaniel Fojt 	return 0;
75516d49e1aeSJan Lentfer }
7552