1189251Ssam/*
2189251Ssam * WPA Supplicant
3214734Srpaulo * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
4189251Ssam *
5189251Ssam * This program is free software; you can redistribute it and/or modify
6189251Ssam * it under the terms of the GNU General Public License version 2 as
7189251Ssam * published by the Free Software Foundation.
8189251Ssam *
9189251Ssam * Alternatively, this software may be distributed under the terms of BSD
10189251Ssam * license.
11189251Ssam *
12189251Ssam * See README and COPYING for more details.
13189251Ssam *
14189251Ssam * This file implements functions for registering and unregistering
15189251Ssam * %wpa_supplicant interfaces. In addition, this file contains number of
16189251Ssam * functions for managing network connections.
17189251Ssam */
18189251Ssam
19189251Ssam#include "includes.h"
20189251Ssam
21189251Ssam#include "common.h"
22189251Ssam#include "eapol_supp/eapol_supp_sm.h"
23189251Ssam#include "eap_peer/eap.h"
24214734Srpaulo#include "eap_server/eap_methods.h"
25214734Srpaulo#include "rsn_supp/wpa.h"
26189251Ssam#include "eloop.h"
27189251Ssam#include "config.h"
28189251Ssam#include "l2_packet/l2_packet.h"
29189251Ssam#include "wpa_supplicant_i.h"
30214734Srpaulo#include "driver_i.h"
31189251Ssam#include "ctrl_iface.h"
32189251Ssam#include "pcsc_funcs.h"
33214734Srpaulo#include "common/version.h"
34214734Srpaulo#include "rsn_supp/preauth.h"
35214734Srpaulo#include "rsn_supp/pmksa_cache.h"
36214734Srpaulo#include "common/wpa_ctrl.h"
37189251Ssam#include "mlme.h"
38214734Srpaulo#include "common/ieee802_11_defs.h"
39189251Ssam#include "blacklist.h"
40189251Ssam#include "wpas_glue.h"
41189251Ssam#include "wps_supplicant.h"
42214734Srpaulo#include "ibss_rsn.h"
43214734Srpaulo#include "sme.h"
44214734Srpaulo#include "ap.h"
45214734Srpaulo#include "notify.h"
46214734Srpaulo#include "bgscan.h"
47214734Srpaulo#include "bss.h"
48214734Srpaulo#include "scan.h"
49189251Ssam
50189251Ssamconst char *wpa_supplicant_version =
51189251Ssam"wpa_supplicant v" VERSION_STR "\n"
52214734Srpaulo"Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi> and contributors";
53189251Ssam
54189251Ssamconst char *wpa_supplicant_license =
55189251Ssam"This program is free software. You can distribute it and/or modify it\n"
56189251Ssam"under the terms of the GNU General Public License version 2.\n"
57189251Ssam"\n"
58189251Ssam"Alternatively, this software may be distributed under the terms of the\n"
59189251Ssam"BSD license. See README and COPYING for more details.\n"
60189251Ssam#ifdef EAP_TLS_OPENSSL
61189251Ssam"\nThis product includes software developed by the OpenSSL Project\n"
62189251Ssam"for use in the OpenSSL Toolkit (http://www.openssl.org/)\n"
63189251Ssam#endif /* EAP_TLS_OPENSSL */
64189251Ssam;
65189251Ssam
66189251Ssam#ifndef CONFIG_NO_STDOUT_DEBUG
67189251Ssam/* Long text divided into parts in order to fit in C89 strings size limits. */
68189251Ssamconst char *wpa_supplicant_full_license1 =
69189251Ssam"This program is free software; you can redistribute it and/or modify\n"
70189251Ssam"it under the terms of the GNU General Public License version 2 as\n"
71189251Ssam"published by the Free Software Foundation.\n"
72189251Ssam"\n"
73189251Ssam"This program is distributed in the hope that it will be useful,\n"
74189251Ssam"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
75189251Ssam"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
76189251Ssam"GNU General Public License for more details.\n"
77189251Ssam"\n";
78189251Ssamconst char *wpa_supplicant_full_license2 =
79189251Ssam"You should have received a copy of the GNU General Public License\n"
80189251Ssam"along with this program; if not, write to the Free Software\n"
81189251Ssam"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n"
82189251Ssam"\n"
83189251Ssam"Alternatively, this software may be distributed under the terms of the\n"
84189251Ssam"BSD license.\n"
85189251Ssam"\n"
86189251Ssam"Redistribution and use in source and binary forms, with or without\n"
87189251Ssam"modification, are permitted provided that the following conditions are\n"
88189251Ssam"met:\n"
89189251Ssam"\n";
90189251Ssamconst char *wpa_supplicant_full_license3 =
91189251Ssam"1. Redistributions of source code must retain the above copyright\n"
92189251Ssam"   notice, this list of conditions and the following disclaimer.\n"
93189251Ssam"\n"
94189251Ssam"2. Redistributions in binary form must reproduce the above copyright\n"
95189251Ssam"   notice, this list of conditions and the following disclaimer in the\n"
96189251Ssam"   documentation and/or other materials provided with the distribution.\n"
97189251Ssam"\n";
98189251Ssamconst char *wpa_supplicant_full_license4 =
99189251Ssam"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
100189251Ssam"   names of its contributors may be used to endorse or promote products\n"
101189251Ssam"   derived from this software without specific prior written permission.\n"
102189251Ssam"\n"
103189251Ssam"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
104189251Ssam"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
105189251Ssam"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
106189251Ssam"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n";
107189251Ssamconst char *wpa_supplicant_full_license5 =
108189251Ssam"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
109189251Ssam"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
110189251Ssam"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
111189251Ssam"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
112189251Ssam"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
113189251Ssam"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
114189251Ssam"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
115189251Ssam"\n";
116189251Ssam#endif /* CONFIG_NO_STDOUT_DEBUG */
117189251Ssam
118189251Ssamextern int wpa_debug_level;
119189251Ssamextern int wpa_debug_show_keys;
120189251Ssamextern int wpa_debug_timestamp;
121214734Srpauloextern struct wpa_driver_ops *wpa_drivers[];
122189251Ssam
123189251Ssam/* Configure default/group WEP keys for static WEP */
124214734Srpauloint wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
125189251Ssam{
126189251Ssam	int i, set = 0;
127189251Ssam
128189251Ssam	for (i = 0; i < NUM_WEP_KEYS; i++) {
129189251Ssam		if (ssid->wep_key_len[i] == 0)
130189251Ssam			continue;
131189251Ssam
132189251Ssam		set = 1;
133189251Ssam		wpa_drv_set_key(wpa_s, WPA_ALG_WEP,
134189251Ssam				(u8 *) "\xff\xff\xff\xff\xff\xff",
135189251Ssam				i, i == ssid->wep_tx_keyidx, (u8 *) "", 0,
136189251Ssam				ssid->wep_key[i], ssid->wep_key_len[i]);
137189251Ssam	}
138189251Ssam
139189251Ssam	return set;
140189251Ssam}
141189251Ssam
142189251Ssam
143189251Ssamstatic int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
144189251Ssam					   struct wpa_ssid *ssid)
145189251Ssam{
146189251Ssam	u8 key[32];
147189251Ssam	size_t keylen;
148214734Srpaulo	enum wpa_alg alg;
149189251Ssam	u8 seq[6] = { 0 };
150189251Ssam
151189251Ssam	/* IBSS/WPA-None uses only one key (Group) for both receiving and
152189251Ssam	 * sending unicast and multicast packets. */
153189251Ssam
154214734Srpaulo	if (ssid->mode != WPAS_MODE_IBSS) {
155189251Ssam		wpa_printf(MSG_INFO, "WPA: Invalid mode %d (not IBSS/ad-hoc) "
156189251Ssam			   "for WPA-None", ssid->mode);
157189251Ssam		return -1;
158189251Ssam	}
159189251Ssam
160189251Ssam	if (!ssid->psk_set) {
161189251Ssam		wpa_printf(MSG_INFO, "WPA: No PSK configured for WPA-None");
162189251Ssam		return -1;
163189251Ssam	}
164189251Ssam
165189251Ssam	switch (wpa_s->group_cipher) {
166189251Ssam	case WPA_CIPHER_CCMP:
167189251Ssam		os_memcpy(key, ssid->psk, 16);
168189251Ssam		keylen = 16;
169189251Ssam		alg = WPA_ALG_CCMP;
170189251Ssam		break;
171189251Ssam	case WPA_CIPHER_TKIP:
172189251Ssam		/* WPA-None uses the same Michael MIC key for both TX and RX */
173189251Ssam		os_memcpy(key, ssid->psk, 16 + 8);
174189251Ssam		os_memcpy(key + 16 + 8, ssid->psk + 16, 8);
175189251Ssam		keylen = 32;
176189251Ssam		alg = WPA_ALG_TKIP;
177189251Ssam		break;
178189251Ssam	default:
179189251Ssam		wpa_printf(MSG_INFO, "WPA: Invalid group cipher %d for "
180189251Ssam			   "WPA-None", wpa_s->group_cipher);
181189251Ssam		return -1;
182189251Ssam	}
183189251Ssam
184189251Ssam	/* TODO: should actually remember the previously used seq#, both for TX
185189251Ssam	 * and RX from each STA.. */
186189251Ssam
187189251Ssam	return wpa_drv_set_key(wpa_s, alg, (u8 *) "\xff\xff\xff\xff\xff\xff",
188189251Ssam			       0, 1, seq, 6, key, keylen);
189189251Ssam}
190189251Ssam
191189251Ssam
192189251Ssamstatic void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
193189251Ssam{
194189251Ssam	struct wpa_supplicant *wpa_s = eloop_ctx;
195189251Ssam	const u8 *bssid = wpa_s->bssid;
196189251Ssam	if (is_zero_ether_addr(bssid))
197189251Ssam		bssid = wpa_s->pending_bssid;
198189251Ssam	wpa_msg(wpa_s, MSG_INFO, "Authentication with " MACSTR " timed out.",
199189251Ssam		MAC2STR(bssid));
200189251Ssam	wpa_blacklist_add(wpa_s, bssid);
201189251Ssam	wpa_sm_notify_disassoc(wpa_s->wpa);
202189251Ssam	wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
203189251Ssam	wpa_s->reassociate = 1;
204189251Ssam	wpa_supplicant_req_scan(wpa_s, 0, 0);
205189251Ssam}
206189251Ssam
207189251Ssam
208189251Ssam/**
209189251Ssam * wpa_supplicant_req_auth_timeout - Schedule a timeout for authentication
210189251Ssam * @wpa_s: Pointer to wpa_supplicant data
211189251Ssam * @sec: Number of seconds after which to time out authentication
212189251Ssam * @usec: Number of microseconds after which to time out authentication
213189251Ssam *
214189251Ssam * This function is used to schedule a timeout for the current authentication
215189251Ssam * attempt.
216189251Ssam */
217189251Ssamvoid wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
218189251Ssam				     int sec, int usec)
219189251Ssam{
220189251Ssam	if (wpa_s->conf && wpa_s->conf->ap_scan == 0 &&
221214734Srpaulo	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED))
222189251Ssam		return;
223189251Ssam
224189251Ssam	wpa_msg(wpa_s, MSG_DEBUG, "Setting authentication timeout: %d sec "
225189251Ssam		"%d usec", sec, usec);
226189251Ssam	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
227189251Ssam	eloop_register_timeout(sec, usec, wpa_supplicant_timeout, wpa_s, NULL);
228189251Ssam}
229189251Ssam
230189251Ssam
231189251Ssam/**
232189251Ssam * wpa_supplicant_cancel_auth_timeout - Cancel authentication timeout
233189251Ssam * @wpa_s: Pointer to wpa_supplicant data
234189251Ssam *
235189251Ssam * This function is used to cancel authentication timeout scheduled with
236189251Ssam * wpa_supplicant_req_auth_timeout() and it is called when authentication has
237189251Ssam * been completed.
238189251Ssam */
239189251Ssamvoid wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s)
240189251Ssam{
241189251Ssam	wpa_msg(wpa_s, MSG_DEBUG, "Cancelling authentication timeout");
242189251Ssam	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
243189251Ssam	wpa_blacklist_del(wpa_s, wpa_s->bssid);
244189251Ssam}
245189251Ssam
246189251Ssam
247189251Ssam/**
248189251Ssam * wpa_supplicant_initiate_eapol - Configure EAPOL state machine
249189251Ssam * @wpa_s: Pointer to wpa_supplicant data
250189251Ssam *
251189251Ssam * This function is used to configure EAPOL state machine based on the selected
252189251Ssam * authentication mode.
253189251Ssam */
254189251Ssamvoid wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
255189251Ssam{
256189251Ssam#ifdef IEEE8021X_EAPOL
257189251Ssam	struct eapol_config eapol_conf;
258189251Ssam	struct wpa_ssid *ssid = wpa_s->current_ssid;
259189251Ssam
260214734Srpaulo#ifdef CONFIG_IBSS_RSN
261214734Srpaulo	if (ssid->mode == WPAS_MODE_IBSS &&
262214734Srpaulo	    wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
263214734Srpaulo	    wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE) {
264214734Srpaulo		/*
265214734Srpaulo		 * RSN IBSS authentication is per-STA and we can disable the
266214734Srpaulo		 * per-BSSID EAPOL authentication.
267214734Srpaulo		 */
268214734Srpaulo		eapol_sm_notify_portControl(wpa_s->eapol, ForceAuthorized);
269214734Srpaulo		eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
270214734Srpaulo		eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE);
271214734Srpaulo		return;
272214734Srpaulo	}
273214734Srpaulo#endif /* CONFIG_IBSS_RSN */
274214734Srpaulo
275189251Ssam	eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
276189251Ssam	eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE);
277189251Ssam
278189251Ssam	if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
279189251Ssam	    wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE)
280189251Ssam		eapol_sm_notify_portControl(wpa_s->eapol, ForceAuthorized);
281189251Ssam	else
282189251Ssam		eapol_sm_notify_portControl(wpa_s->eapol, Auto);
283189251Ssam
284189251Ssam	os_memset(&eapol_conf, 0, sizeof(eapol_conf));
285189251Ssam	if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
286189251Ssam		eapol_conf.accept_802_1x_keys = 1;
287189251Ssam		eapol_conf.required_keys = 0;
288189251Ssam		if (ssid->eapol_flags & EAPOL_FLAG_REQUIRE_KEY_UNICAST) {
289189251Ssam			eapol_conf.required_keys |= EAPOL_REQUIRE_KEY_UNICAST;
290189251Ssam		}
291189251Ssam		if (ssid->eapol_flags & EAPOL_FLAG_REQUIRE_KEY_BROADCAST) {
292189251Ssam			eapol_conf.required_keys |=
293189251Ssam				EAPOL_REQUIRE_KEY_BROADCAST;
294189251Ssam		}
295189251Ssam
296214734Srpaulo		if (wpa_s->conf && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED))
297189251Ssam			eapol_conf.required_keys = 0;
298189251Ssam	}
299189251Ssam	if (wpa_s->conf)
300189251Ssam		eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
301189251Ssam	eapol_conf.workaround = ssid->eap_workaround;
302189251Ssam	eapol_conf.eap_disabled =
303189251Ssam		!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) &&
304189251Ssam		wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
305189251Ssam		wpa_s->key_mgmt != WPA_KEY_MGMT_WPS;
306189251Ssam	eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
307189251Ssam#endif /* IEEE8021X_EAPOL */
308189251Ssam}
309189251Ssam
310189251Ssam
311189251Ssam/**
312189251Ssam * wpa_supplicant_set_non_wpa_policy - Set WPA parameters to non-WPA mode
313189251Ssam * @wpa_s: Pointer to wpa_supplicant data
314189251Ssam * @ssid: Configuration data for the network
315189251Ssam *
316189251Ssam * This function is used to configure WPA state machine and related parameters
317189251Ssam * to a mode where WPA is not enabled. This is called as part of the
318189251Ssam * authentication configuration when the selected network does not use WPA.
319189251Ssam */
320189251Ssamvoid wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
321189251Ssam				       struct wpa_ssid *ssid)
322189251Ssam{
323189251Ssam	int i;
324189251Ssam
325189251Ssam	if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
326189251Ssam		wpa_s->key_mgmt = WPA_KEY_MGMT_WPS;
327189251Ssam	else if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)
328189251Ssam		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA;
329189251Ssam	else
330189251Ssam		wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
331189251Ssam	wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
332189251Ssam	wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
333189251Ssam	wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
334189251Ssam	wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
335189251Ssam	wpa_s->group_cipher = WPA_CIPHER_NONE;
336189251Ssam	wpa_s->mgmt_group_cipher = 0;
337189251Ssam
338189251Ssam	for (i = 0; i < NUM_WEP_KEYS; i++) {
339189251Ssam		if (ssid->wep_key_len[i] > 5) {
340189251Ssam			wpa_s->pairwise_cipher = WPA_CIPHER_WEP104;
341189251Ssam			wpa_s->group_cipher = WPA_CIPHER_WEP104;
342189251Ssam			break;
343189251Ssam		} else if (ssid->wep_key_len[i] > 0) {
344189251Ssam			wpa_s->pairwise_cipher = WPA_CIPHER_WEP40;
345189251Ssam			wpa_s->group_cipher = WPA_CIPHER_WEP40;
346189251Ssam			break;
347189251Ssam		}
348189251Ssam	}
349189251Ssam
350189251Ssam	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED, 0);
351189251Ssam	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt);
352189251Ssam	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE,
353189251Ssam			 wpa_s->pairwise_cipher);
354189251Ssam	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
355189251Ssam#ifdef CONFIG_IEEE80211W
356189251Ssam	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
357189251Ssam			 wpa_s->mgmt_group_cipher);
358189251Ssam#endif /* CONFIG_IEEE80211W */
359189251Ssam
360189251Ssam	pmksa_cache_clear_current(wpa_s->wpa);
361189251Ssam}
362189251Ssam
363189251Ssam
364189251Ssamstatic void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
365189251Ssam{
366214734Srpaulo	bgscan_deinit(wpa_s);
367189251Ssam	scard_deinit(wpa_s->scard);
368189251Ssam	wpa_s->scard = NULL;
369189251Ssam	wpa_sm_set_scard_ctx(wpa_s->wpa, NULL);
370189251Ssam	eapol_sm_register_scard_ctx(wpa_s->eapol, NULL);
371189251Ssam	l2_packet_deinit(wpa_s->l2);
372189251Ssam	wpa_s->l2 = NULL;
373189251Ssam	if (wpa_s->l2_br) {
374189251Ssam		l2_packet_deinit(wpa_s->l2_br);
375189251Ssam		wpa_s->l2_br = NULL;
376189251Ssam	}
377189251Ssam
378189251Ssam	if (wpa_s->ctrl_iface) {
379189251Ssam		wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
380189251Ssam		wpa_s->ctrl_iface = NULL;
381189251Ssam	}
382189251Ssam	if (wpa_s->conf != NULL) {
383214734Srpaulo		struct wpa_ssid *ssid;
384214734Srpaulo		for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
385214734Srpaulo			wpas_notify_network_removed(wpa_s, ssid);
386189251Ssam		wpa_config_free(wpa_s->conf);
387189251Ssam		wpa_s->conf = NULL;
388189251Ssam	}
389189251Ssam
390189251Ssam	os_free(wpa_s->confname);
391189251Ssam	wpa_s->confname = NULL;
392189251Ssam
393189251Ssam	wpa_sm_set_eapol(wpa_s->wpa, NULL);
394189251Ssam	eapol_sm_deinit(wpa_s->eapol);
395189251Ssam	wpa_s->eapol = NULL;
396189251Ssam
397189251Ssam	rsn_preauth_deinit(wpa_s->wpa);
398189251Ssam
399189251Ssam	pmksa_candidate_free(wpa_s->wpa);
400189251Ssam	wpa_sm_deinit(wpa_s->wpa);
401189251Ssam	wpa_s->wpa = NULL;
402189251Ssam	wpa_blacklist_clear(wpa_s);
403189251Ssam
404214734Srpaulo	wpa_bss_deinit(wpa_s);
405189251Ssam
406189251Ssam	wpa_supplicant_cancel_scan(wpa_s);
407189251Ssam	wpa_supplicant_cancel_auth_timeout(wpa_s);
408189251Ssam
409189251Ssam	ieee80211_sta_deinit(wpa_s);
410189251Ssam
411189251Ssam	wpas_wps_deinit(wpa_s);
412209158Srpaulo
413209158Srpaulo	wpabuf_free(wpa_s->pending_eapol_rx);
414209158Srpaulo	wpa_s->pending_eapol_rx = NULL;
415214734Srpaulo
416214734Srpaulo#ifdef CONFIG_IBSS_RSN
417214734Srpaulo	ibss_rsn_deinit(wpa_s->ibss_rsn);
418214734Srpaulo	wpa_s->ibss_rsn = NULL;
419214734Srpaulo#endif /* CONFIG_IBSS_RSN */
420214734Srpaulo
421214734Srpaulo#ifdef CONFIG_SME
422214734Srpaulo	os_free(wpa_s->sme.ft_ies);
423214734Srpaulo	wpa_s->sme.ft_ies = NULL;
424214734Srpaulo	wpa_s->sme.ft_ies_len = 0;
425214734Srpaulo#endif /* CONFIG_SME */
426214734Srpaulo
427214734Srpaulo#ifdef CONFIG_AP
428214734Srpaulo	wpa_supplicant_ap_deinit(wpa_s);
429214734Srpaulo#endif /* CONFIG_AP */
430189251Ssam}
431189251Ssam
432189251Ssam
433189251Ssam/**
434189251Ssam * wpa_clear_keys - Clear keys configured for the driver
435189251Ssam * @wpa_s: Pointer to wpa_supplicant data
436189251Ssam * @addr: Previously used BSSID or %NULL if not available
437189251Ssam *
438189251Ssam * This function clears the encryption keys that has been previously configured
439189251Ssam * for the driver.
440189251Ssam */
441189251Ssamvoid wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
442189251Ssam{
443189251Ssam	u8 *bcast = (u8 *) "\xff\xff\xff\xff\xff\xff";
444189251Ssam
445189251Ssam	if (wpa_s->keys_cleared) {
446189251Ssam		/* Some drivers (e.g., ndiswrapper & NDIS drivers) seem to have
447189251Ssam		 * timing issues with keys being cleared just before new keys
448189251Ssam		 * are set or just after association or something similar. This
449189251Ssam		 * shows up in group key handshake failing often because of the
450189251Ssam		 * client not receiving the first encrypted packets correctly.
451189251Ssam		 * Skipping some of the extra key clearing steps seems to help
452189251Ssam		 * in completing group key handshake more reliably. */
453189251Ssam		wpa_printf(MSG_DEBUG, "No keys have been configured - "
454189251Ssam			   "skip key clearing");
455189251Ssam		return;
456189251Ssam	}
457189251Ssam
458189251Ssam	/* MLME-DELETEKEYS.request */
459189251Ssam	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 0, 0, NULL, 0, NULL, 0);
460189251Ssam	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 1, 0, NULL, 0, NULL, 0);
461189251Ssam	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 2, 0, NULL, 0, NULL, 0);
462189251Ssam	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 3, 0, NULL, 0, NULL, 0);
463209158Srpaulo#ifdef CONFIG_IEEE80211W
464209158Srpaulo	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 4, 0, NULL, 0, NULL, 0);
465209158Srpaulo	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 5, 0, NULL, 0, NULL, 0);
466209158Srpaulo#endif /* CONFIG_IEEE80211W */
467189251Ssam	if (addr) {
468189251Ssam		wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL,
469189251Ssam				0);
470189251Ssam		/* MLME-SETPROTECTION.request(None) */
471189251Ssam		wpa_drv_mlme_setprotection(
472189251Ssam			wpa_s, addr,
473189251Ssam			MLME_SETPROTECTION_PROTECT_TYPE_NONE,
474189251Ssam			MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
475189251Ssam	}
476189251Ssam	wpa_s->keys_cleared = 1;
477189251Ssam}
478189251Ssam
479189251Ssam
480189251Ssam/**
481189251Ssam * wpa_supplicant_state_txt - Get the connection state name as a text string
482189251Ssam * @state: State (wpa_state; WPA_*)
483189251Ssam * Returns: The state name as a printable text string
484189251Ssam */
485214734Srpauloconst char * wpa_supplicant_state_txt(enum wpa_states state)
486189251Ssam{
487189251Ssam	switch (state) {
488189251Ssam	case WPA_DISCONNECTED:
489189251Ssam		return "DISCONNECTED";
490189251Ssam	case WPA_INACTIVE:
491189251Ssam		return "INACTIVE";
492189251Ssam	case WPA_SCANNING:
493189251Ssam		return "SCANNING";
494214734Srpaulo	case WPA_AUTHENTICATING:
495214734Srpaulo		return "AUTHENTICATING";
496189251Ssam	case WPA_ASSOCIATING:
497189251Ssam		return "ASSOCIATING";
498189251Ssam	case WPA_ASSOCIATED:
499189251Ssam		return "ASSOCIATED";
500189251Ssam	case WPA_4WAY_HANDSHAKE:
501189251Ssam		return "4WAY_HANDSHAKE";
502189251Ssam	case WPA_GROUP_HANDSHAKE:
503189251Ssam		return "GROUP_HANDSHAKE";
504189251Ssam	case WPA_COMPLETED:
505189251Ssam		return "COMPLETED";
506189251Ssam	default:
507189251Ssam		return "UNKNOWN";
508189251Ssam	}
509189251Ssam}
510189251Ssam
511189251Ssam
512189251Ssam/**
513189251Ssam * wpa_supplicant_set_state - Set current connection state
514189251Ssam * @wpa_s: Pointer to wpa_supplicant data
515189251Ssam * @state: The new connection state
516189251Ssam *
517189251Ssam * This function is called whenever the connection state changes, e.g.,
518189251Ssam * association is completed for WPA/WPA2 4-Way Handshake is started.
519189251Ssam */
520214734Srpaulovoid wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
521214734Srpaulo			      enum wpa_states state)
522189251Ssam{
523214734Srpaulo	enum wpa_states old_state = wpa_s->wpa_state;
524214734Srpaulo
525189251Ssam	wpa_printf(MSG_DEBUG, "State: %s -> %s",
526189251Ssam		   wpa_supplicant_state_txt(wpa_s->wpa_state),
527189251Ssam		   wpa_supplicant_state_txt(state));
528189251Ssam
529209158Srpaulo	if (state != WPA_SCANNING)
530209158Srpaulo		wpa_supplicant_notify_scanning(wpa_s, 0);
531209158Srpaulo
532189251Ssam	if (state == WPA_COMPLETED && wpa_s->new_connection) {
533189251Ssam#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
534189251Ssam		struct wpa_ssid *ssid = wpa_s->current_ssid;
535189251Ssam		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- Connection to "
536189251Ssam			MACSTR " completed %s [id=%d id_str=%s]",
537189251Ssam			MAC2STR(wpa_s->bssid), wpa_s->reassociated_connection ?
538189251Ssam			"(reauth)" : "(auth)",
539189251Ssam			ssid ? ssid->id : -1,
540189251Ssam			ssid && ssid->id_str ? ssid->id_str : "");
541189251Ssam#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
542189251Ssam		wpa_s->new_connection = 0;
543189251Ssam		wpa_s->reassociated_connection = 1;
544189251Ssam		wpa_drv_set_operstate(wpa_s, 1);
545214734Srpaulo		wpa_s->after_wps = 0;
546189251Ssam	} else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
547189251Ssam		   state == WPA_ASSOCIATED) {
548189251Ssam		wpa_s->new_connection = 1;
549189251Ssam		wpa_drv_set_operstate(wpa_s, 0);
550189251Ssam	}
551189251Ssam	wpa_s->wpa_state = state;
552214734Srpaulo
553214734Srpaulo	if (wpa_s->wpa_state != old_state)
554214734Srpaulo		wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
555189251Ssam}
556189251Ssam
557189251Ssam
558214734Srpaulovoid wpa_supplicant_terminate_proc(struct wpa_global *global)
559189251Ssam{
560214734Srpaulo	int pending = 0;
561214734Srpaulo#ifdef CONFIG_WPS
562214734Srpaulo	struct wpa_supplicant *wpa_s = global->ifaces;
563214734Srpaulo	while (wpa_s) {
564214734Srpaulo		if (wpas_wps_terminate_pending(wpa_s) == 1)
565214734Srpaulo			pending = 1;
566214734Srpaulo		wpa_s = wpa_s->next;
567214734Srpaulo	}
568214734Srpaulo#endif /* CONFIG_WPS */
569214734Srpaulo	if (pending)
570214734Srpaulo		return;
571214734Srpaulo	eloop_terminate();
572214734Srpaulo}
573214734Srpaulo
574214734Srpaulo
575214734Srpaulostatic void wpa_supplicant_terminate(int sig, void *signal_ctx)
576214734Srpaulo{
577214734Srpaulo	struct wpa_global *global = signal_ctx;
578189251Ssam	struct wpa_supplicant *wpa_s;
579189251Ssam	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
580189251Ssam		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TERMINATING "- signal %d "
581189251Ssam			"received", sig);
582189251Ssam	}
583214734Srpaulo	wpa_supplicant_terminate_proc(global);
584189251Ssam}
585189251Ssam
586189251Ssam
587189251Ssamstatic void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
588189251Ssam{
589214734Srpaulo	enum wpa_states old_state = wpa_s->wpa_state;
590214734Srpaulo
591189251Ssam	wpa_s->pairwise_cipher = 0;
592189251Ssam	wpa_s->group_cipher = 0;
593189251Ssam	wpa_s->mgmt_group_cipher = 0;
594189251Ssam	wpa_s->key_mgmt = 0;
595189251Ssam	wpa_s->wpa_state = WPA_DISCONNECTED;
596214734Srpaulo
597214734Srpaulo	if (wpa_s->wpa_state != old_state)
598214734Srpaulo		wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
599189251Ssam}
600189251Ssam
601189251Ssam
602189251Ssam/**
603189251Ssam * wpa_supplicant_reload_configuration - Reload configuration data
604189251Ssam * @wpa_s: Pointer to wpa_supplicant data
605189251Ssam * Returns: 0 on success or -1 if configuration parsing failed
606189251Ssam *
607189251Ssam * This function can be used to request that the configuration data is reloaded
608189251Ssam * (e.g., after configuration file change). This function is reloading
609189251Ssam * configuration only for one interface, so this may need to be called multiple
610189251Ssam * times if %wpa_supplicant is controlling multiple interfaces and all
611189251Ssam * interfaces need reconfiguration.
612189251Ssam */
613189251Ssamint wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
614189251Ssam{
615189251Ssam	struct wpa_config *conf;
616214734Srpaulo	struct wpa_ssid *old_ssid;
617189251Ssam	int reconf_ctrl;
618214734Srpaulo	int old_ap_scan;
619214734Srpaulo
620189251Ssam	if (wpa_s->confname == NULL)
621189251Ssam		return -1;
622189251Ssam	conf = wpa_config_read(wpa_s->confname);
623189251Ssam	if (conf == NULL) {
624189251Ssam		wpa_msg(wpa_s, MSG_ERROR, "Failed to parse the configuration "
625189251Ssam			"file '%s' - exiting", wpa_s->confname);
626189251Ssam		return -1;
627189251Ssam	}
628189251Ssam
629189251Ssam	reconf_ctrl = !!conf->ctrl_interface != !!wpa_s->conf->ctrl_interface
630189251Ssam		|| (conf->ctrl_interface && wpa_s->conf->ctrl_interface &&
631189251Ssam		    os_strcmp(conf->ctrl_interface,
632189251Ssam			      wpa_s->conf->ctrl_interface) != 0);
633189251Ssam
634189251Ssam	if (reconf_ctrl && wpa_s->ctrl_iface) {
635189251Ssam		wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
636189251Ssam		wpa_s->ctrl_iface = NULL;
637189251Ssam	}
638189251Ssam
639189251Ssam	eapol_sm_invalidate_cached_session(wpa_s->eapol);
640214734Srpaulo	old_ssid = wpa_s->current_ssid;
641189251Ssam	wpa_s->current_ssid = NULL;
642214734Srpaulo	if (old_ssid != wpa_s->current_ssid)
643214734Srpaulo		wpas_notify_network_changed(wpa_s);
644214734Srpaulo
645189251Ssam	/*
646189251Ssam	 * TODO: should notify EAPOL SM about changes in opensc_engine_path,
647189251Ssam	 * pkcs11_engine_path, pkcs11_module_path.
648189251Ssam	 */
649189251Ssam	if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
650189251Ssam		/*
651189251Ssam		 * Clear forced success to clear EAP state for next
652189251Ssam		 * authentication.
653189251Ssam		 */
654189251Ssam		eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
655189251Ssam	}
656189251Ssam	eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
657189251Ssam	wpa_sm_set_config(wpa_s->wpa, NULL);
658189251Ssam	wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
659189251Ssam	rsn_preauth_deinit(wpa_s->wpa);
660214734Srpaulo
661214734Srpaulo	old_ap_scan = wpa_s->conf->ap_scan;
662189251Ssam	wpa_config_free(wpa_s->conf);
663189251Ssam	wpa_s->conf = conf;
664214734Srpaulo	if (old_ap_scan != wpa_s->conf->ap_scan)
665214734Srpaulo		wpas_notify_ap_scan_changed(wpa_s);
666214734Srpaulo
667189251Ssam	if (reconf_ctrl)
668189251Ssam		wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
669189251Ssam
670189251Ssam	wpa_supplicant_clear_status(wpa_s);
671189251Ssam	wpa_s->reassociate = 1;
672189251Ssam	wpa_supplicant_req_scan(wpa_s, 0, 0);
673189251Ssam	wpa_msg(wpa_s, MSG_DEBUG, "Reconfiguration completed");
674189251Ssam	return 0;
675189251Ssam}
676189251Ssam
677189251Ssam
678214734Srpaulostatic void wpa_supplicant_reconfig(int sig, void *signal_ctx)
679189251Ssam{
680214734Srpaulo	struct wpa_global *global = signal_ctx;
681189251Ssam	struct wpa_supplicant *wpa_s;
682189251Ssam	wpa_printf(MSG_DEBUG, "Signal %d received - reconfiguring", sig);
683189251Ssam	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
684189251Ssam		if (wpa_supplicant_reload_configuration(wpa_s) < 0) {
685214734Srpaulo			wpa_supplicant_terminate_proc(global);
686189251Ssam		}
687189251Ssam	}
688189251Ssam}
689189251Ssam
690189251Ssam
691214734Srpauloenum wpa_cipher cipher_suite2driver(int cipher)
692189251Ssam{
693189251Ssam	switch (cipher) {
694189251Ssam	case WPA_CIPHER_NONE:
695189251Ssam		return CIPHER_NONE;
696189251Ssam	case WPA_CIPHER_WEP40:
697189251Ssam		return CIPHER_WEP40;
698189251Ssam	case WPA_CIPHER_WEP104:
699189251Ssam		return CIPHER_WEP104;
700189251Ssam	case WPA_CIPHER_CCMP:
701189251Ssam		return CIPHER_CCMP;
702189251Ssam	case WPA_CIPHER_TKIP:
703189251Ssam	default:
704189251Ssam		return CIPHER_TKIP;
705189251Ssam	}
706189251Ssam}
707189251Ssam
708189251Ssam
709214734Srpauloenum wpa_key_mgmt key_mgmt2driver(int key_mgmt)
710189251Ssam{
711189251Ssam	switch (key_mgmt) {
712189251Ssam	case WPA_KEY_MGMT_NONE:
713189251Ssam		return KEY_MGMT_NONE;
714189251Ssam	case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
715189251Ssam		return KEY_MGMT_802_1X_NO_WPA;
716189251Ssam	case WPA_KEY_MGMT_IEEE8021X:
717189251Ssam		return KEY_MGMT_802_1X;
718189251Ssam	case WPA_KEY_MGMT_WPA_NONE:
719189251Ssam		return KEY_MGMT_WPA_NONE;
720189251Ssam	case WPA_KEY_MGMT_FT_IEEE8021X:
721189251Ssam		return KEY_MGMT_FT_802_1X;
722189251Ssam	case WPA_KEY_MGMT_FT_PSK:
723189251Ssam		return KEY_MGMT_FT_PSK;
724189251Ssam	case WPA_KEY_MGMT_IEEE8021X_SHA256:
725189251Ssam		return KEY_MGMT_802_1X_SHA256;
726189251Ssam	case WPA_KEY_MGMT_PSK_SHA256:
727189251Ssam		return KEY_MGMT_PSK_SHA256;
728189251Ssam	case WPA_KEY_MGMT_WPS:
729189251Ssam		return KEY_MGMT_WPS;
730189251Ssam	case WPA_KEY_MGMT_PSK:
731189251Ssam	default:
732189251Ssam		return KEY_MGMT_PSK;
733189251Ssam	}
734189251Ssam}
735189251Ssam
736189251Ssam
737189251Ssamstatic int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
738189251Ssam					 struct wpa_ssid *ssid,
739189251Ssam					 struct wpa_ie_data *ie)
740189251Ssam{
741189251Ssam	int ret = wpa_sm_parse_own_wpa_ie(wpa_s->wpa, ie);
742189251Ssam	if (ret) {
743189251Ssam		if (ret == -2) {
744189251Ssam			wpa_msg(wpa_s, MSG_INFO, "WPA: Failed to parse WPA IE "
745189251Ssam				"from association info");
746189251Ssam		}
747189251Ssam		return -1;
748189251Ssam	}
749189251Ssam
750189251Ssam	wpa_printf(MSG_DEBUG, "WPA: Using WPA IE from AssocReq to set cipher "
751189251Ssam		   "suites");
752189251Ssam	if (!(ie->group_cipher & ssid->group_cipher)) {
753189251Ssam		wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled group "
754189251Ssam			"cipher 0x%x (mask 0x%x) - reject",
755189251Ssam			ie->group_cipher, ssid->group_cipher);
756189251Ssam		return -1;
757189251Ssam	}
758189251Ssam	if (!(ie->pairwise_cipher & ssid->pairwise_cipher)) {
759189251Ssam		wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled pairwise "
760189251Ssam			"cipher 0x%x (mask 0x%x) - reject",
761189251Ssam			ie->pairwise_cipher, ssid->pairwise_cipher);
762189251Ssam		return -1;
763189251Ssam	}
764189251Ssam	if (!(ie->key_mgmt & ssid->key_mgmt)) {
765189251Ssam		wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled key "
766189251Ssam			"management 0x%x (mask 0x%x) - reject",
767189251Ssam			ie->key_mgmt, ssid->key_mgmt);
768189251Ssam		return -1;
769189251Ssam	}
770189251Ssam
771189251Ssam#ifdef CONFIG_IEEE80211W
772189251Ssam	if (!(ie->capabilities & WPA_CAPABILITY_MFPC) &&
773214734Srpaulo	    ssid->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) {
774189251Ssam		wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP "
775189251Ssam			"that does not support management frame protection - "
776189251Ssam			"reject");
777189251Ssam		return -1;
778189251Ssam	}
779189251Ssam#endif /* CONFIG_IEEE80211W */
780189251Ssam
781189251Ssam	return 0;
782189251Ssam}
783189251Ssam
784189251Ssam
785189251Ssam/**
786189251Ssam * wpa_supplicant_set_suites - Set authentication and encryption parameters
787189251Ssam * @wpa_s: Pointer to wpa_supplicant data
788189251Ssam * @bss: Scan results for the selected BSS, or %NULL if not available
789189251Ssam * @ssid: Configuration data for the selected network
790189251Ssam * @wpa_ie: Buffer for the WPA/RSN IE
791189251Ssam * @wpa_ie_len: Maximum wpa_ie buffer size on input. This is changed to be the
792189251Ssam * used buffer length in case the functions returns success.
793189251Ssam * Returns: 0 on success or -1 on failure
794189251Ssam *
795189251Ssam * This function is used to configure authentication and encryption parameters
796189251Ssam * based on the network configuration and scan result for the selected BSS (if
797189251Ssam * available).
798189251Ssam */
799189251Ssamint wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
800214734Srpaulo			      struct wpa_bss *bss, struct wpa_ssid *ssid,
801189251Ssam			      u8 *wpa_ie, size_t *wpa_ie_len)
802189251Ssam{
803189251Ssam	struct wpa_ie_data ie;
804189251Ssam	int sel, proto;
805189251Ssam	const u8 *bss_wpa, *bss_rsn;
806189251Ssam
807189251Ssam	if (bss) {
808214734Srpaulo		bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
809214734Srpaulo		bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
810189251Ssam	} else
811189251Ssam		bss_wpa = bss_rsn = NULL;
812189251Ssam
813189251Ssam	if (bss_rsn && (ssid->proto & WPA_PROTO_RSN) &&
814189251Ssam	    wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 &&
815189251Ssam	    (ie.group_cipher & ssid->group_cipher) &&
816189251Ssam	    (ie.pairwise_cipher & ssid->pairwise_cipher) &&
817189251Ssam	    (ie.key_mgmt & ssid->key_mgmt)) {
818189251Ssam		wpa_msg(wpa_s, MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0");
819189251Ssam		proto = WPA_PROTO_RSN;
820189251Ssam	} else if (bss_wpa && (ssid->proto & WPA_PROTO_WPA) &&
821189251Ssam		   wpa_parse_wpa_ie(bss_wpa, 2 +bss_wpa[1], &ie) == 0 &&
822189251Ssam		   (ie.group_cipher & ssid->group_cipher) &&
823189251Ssam		   (ie.pairwise_cipher & ssid->pairwise_cipher) &&
824189251Ssam		   (ie.key_mgmt & ssid->key_mgmt)) {
825189251Ssam		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using IEEE 802.11i/D3.0");
826189251Ssam		proto = WPA_PROTO_WPA;
827189251Ssam	} else if (bss) {
828189251Ssam		wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select WPA/RSN");
829189251Ssam		return -1;
830189251Ssam	} else {
831189251Ssam		if (ssid->proto & WPA_PROTO_RSN)
832189251Ssam			proto = WPA_PROTO_RSN;
833189251Ssam		else
834189251Ssam			proto = WPA_PROTO_WPA;
835189251Ssam		if (wpa_supplicant_suites_from_ai(wpa_s, ssid, &ie) < 0) {
836189251Ssam			os_memset(&ie, 0, sizeof(ie));
837189251Ssam			ie.group_cipher = ssid->group_cipher;
838189251Ssam			ie.pairwise_cipher = ssid->pairwise_cipher;
839189251Ssam			ie.key_mgmt = ssid->key_mgmt;
840189251Ssam#ifdef CONFIG_IEEE80211W
841189251Ssam			ie.mgmt_group_cipher =
842214734Srpaulo				ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION ?
843189251Ssam				WPA_CIPHER_AES_128_CMAC : 0;
844189251Ssam#endif /* CONFIG_IEEE80211W */
845189251Ssam			wpa_printf(MSG_DEBUG, "WPA: Set cipher suites based "
846189251Ssam				   "on configuration");
847189251Ssam		} else
848189251Ssam			proto = ie.proto;
849189251Ssam	}
850189251Ssam
851189251Ssam	wpa_printf(MSG_DEBUG, "WPA: Selected cipher suites: group %d "
852189251Ssam		   "pairwise %d key_mgmt %d proto %d",
853189251Ssam		   ie.group_cipher, ie.pairwise_cipher, ie.key_mgmt, proto);
854189251Ssam#ifdef CONFIG_IEEE80211W
855189251Ssam	if (ssid->ieee80211w) {
856189251Ssam		wpa_printf(MSG_DEBUG, "WPA: Selected mgmt group cipher %d",
857189251Ssam			   ie.mgmt_group_cipher);
858189251Ssam	}
859189251Ssam#endif /* CONFIG_IEEE80211W */
860189251Ssam
861189251Ssam	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto);
862189251Ssam	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED,
863189251Ssam			 !!(ssid->proto & WPA_PROTO_RSN));
864189251Ssam
865189251Ssam	if (bss || !wpa_s->ap_ies_from_associnfo) {
866189251Ssam		if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
867189251Ssam					 bss_wpa ? 2 + bss_wpa[1] : 0) ||
868189251Ssam		    wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
869189251Ssam					 bss_rsn ? 2 + bss_rsn[1] : 0))
870189251Ssam			return -1;
871189251Ssam	}
872189251Ssam
873189251Ssam	sel = ie.group_cipher & ssid->group_cipher;
874189251Ssam	if (sel & WPA_CIPHER_CCMP) {
875189251Ssam		wpa_s->group_cipher = WPA_CIPHER_CCMP;
876189251Ssam		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using GTK CCMP");
877189251Ssam	} else if (sel & WPA_CIPHER_TKIP) {
878189251Ssam		wpa_s->group_cipher = WPA_CIPHER_TKIP;
879189251Ssam		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using GTK TKIP");
880189251Ssam	} else if (sel & WPA_CIPHER_WEP104) {
881189251Ssam		wpa_s->group_cipher = WPA_CIPHER_WEP104;
882189251Ssam		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using GTK WEP104");
883189251Ssam	} else if (sel & WPA_CIPHER_WEP40) {
884189251Ssam		wpa_s->group_cipher = WPA_CIPHER_WEP40;
885189251Ssam		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using GTK WEP40");
886189251Ssam	} else {
887189251Ssam		wpa_printf(MSG_WARNING, "WPA: Failed to select group cipher.");
888189251Ssam		return -1;
889189251Ssam	}
890189251Ssam
891189251Ssam	sel = ie.pairwise_cipher & ssid->pairwise_cipher;
892189251Ssam	if (sel & WPA_CIPHER_CCMP) {
893189251Ssam		wpa_s->pairwise_cipher = WPA_CIPHER_CCMP;
894189251Ssam		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using PTK CCMP");
895189251Ssam	} else if (sel & WPA_CIPHER_TKIP) {
896189251Ssam		wpa_s->pairwise_cipher = WPA_CIPHER_TKIP;
897189251Ssam		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using PTK TKIP");
898189251Ssam	} else if (sel & WPA_CIPHER_NONE) {
899189251Ssam		wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
900189251Ssam		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using PTK NONE");
901189251Ssam	} else {
902189251Ssam		wpa_printf(MSG_WARNING, "WPA: Failed to select pairwise "
903189251Ssam			   "cipher.");
904189251Ssam		return -1;
905189251Ssam	}
906189251Ssam
907189251Ssam	sel = ie.key_mgmt & ssid->key_mgmt;
908189251Ssam	if (0) {
909189251Ssam#ifdef CONFIG_IEEE80211R
910189251Ssam	} else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
911189251Ssam		wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
912189251Ssam		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/802.1X");
913189251Ssam	} else if (sel & WPA_KEY_MGMT_FT_PSK) {
914189251Ssam		wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
915189251Ssam		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
916189251Ssam#endif /* CONFIG_IEEE80211R */
917189251Ssam#ifdef CONFIG_IEEE80211W
918189251Ssam	} else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) {
919189251Ssam		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
920189251Ssam		wpa_msg(wpa_s, MSG_DEBUG,
921189251Ssam			"WPA: using KEY_MGMT 802.1X with SHA256");
922189251Ssam	} else if (sel & WPA_KEY_MGMT_PSK_SHA256) {
923189251Ssam		wpa_s->key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
924189251Ssam		wpa_msg(wpa_s, MSG_DEBUG,
925189251Ssam			"WPA: using KEY_MGMT PSK with SHA256");
926189251Ssam#endif /* CONFIG_IEEE80211W */
927189251Ssam	} else if (sel & WPA_KEY_MGMT_IEEE8021X) {
928189251Ssam		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
929189251Ssam		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X");
930189251Ssam	} else if (sel & WPA_KEY_MGMT_PSK) {
931189251Ssam		wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
932189251Ssam		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-PSK");
933189251Ssam	} else if (sel & WPA_KEY_MGMT_WPA_NONE) {
934189251Ssam		wpa_s->key_mgmt = WPA_KEY_MGMT_WPA_NONE;
935189251Ssam		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-NONE");
936189251Ssam	} else {
937189251Ssam		wpa_printf(MSG_WARNING, "WPA: Failed to select authenticated "
938189251Ssam			   "key management type.");
939189251Ssam		return -1;
940189251Ssam	}
941189251Ssam
942189251Ssam	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt);
943189251Ssam	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE,
944189251Ssam			 wpa_s->pairwise_cipher);
945189251Ssam	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
946189251Ssam
947189251Ssam#ifdef CONFIG_IEEE80211W
948189251Ssam	sel = ie.mgmt_group_cipher;
949214734Srpaulo	if (ssid->ieee80211w == NO_MGMT_FRAME_PROTECTION ||
950189251Ssam	    !(ie.capabilities & WPA_CAPABILITY_MFPC))
951189251Ssam		sel = 0;
952189251Ssam	if (sel & WPA_CIPHER_AES_128_CMAC) {
953189251Ssam		wpa_s->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
954189251Ssam		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
955189251Ssam			"AES-128-CMAC");
956189251Ssam	} else {
957189251Ssam		wpa_s->mgmt_group_cipher = 0;
958189251Ssam		wpa_msg(wpa_s, MSG_DEBUG, "WPA: not using MGMT group cipher");
959189251Ssam	}
960189251Ssam	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
961189251Ssam			 wpa_s->mgmt_group_cipher);
962214734Srpaulo	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP, ssid->ieee80211w);
963189251Ssam#endif /* CONFIG_IEEE80211W */
964189251Ssam
965189251Ssam	if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
966189251Ssam		wpa_printf(MSG_WARNING, "WPA: Failed to generate WPA IE.");
967189251Ssam		return -1;
968189251Ssam	}
969189251Ssam
970189251Ssam	if (ssid->key_mgmt &
971189251Ssam	    (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK | WPA_KEY_MGMT_PSK_SHA256))
972189251Ssam		wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN);
973189251Ssam	else
974189251Ssam		wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
975189251Ssam
976189251Ssam	return 0;
977189251Ssam}
978189251Ssam
979189251Ssam
980189251Ssam/**
981189251Ssam * wpa_supplicant_associate - Request association
982189251Ssam * @wpa_s: Pointer to wpa_supplicant data
983189251Ssam * @bss: Scan results for the selected BSS, or %NULL if not available
984189251Ssam * @ssid: Configuration data for the selected network
985189251Ssam *
986189251Ssam * This function is used to request %wpa_supplicant to associate with a BSS.
987189251Ssam */
988189251Ssamvoid wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
989214734Srpaulo			      struct wpa_bss *bss, struct wpa_ssid *ssid)
990189251Ssam{
991189251Ssam	u8 wpa_ie[80];
992189251Ssam	size_t wpa_ie_len;
993214734Srpaulo	int use_crypt, ret, i, bssid_changed;
994214734Srpaulo	int algs = WPA_AUTH_ALG_OPEN;
995214734Srpaulo	enum wpa_cipher cipher_pairwise, cipher_group;
996189251Ssam	struct wpa_driver_associate_params params;
997189251Ssam	int wep_keys_set = 0;
998189251Ssam	struct wpa_driver_capa capa;
999189251Ssam	int assoc_failed = 0;
1000214734Srpaulo	struct wpa_ssid *old_ssid;
1001189251Ssam
1002214734Srpaulo	if (ssid->mode == WPAS_MODE_AP) {
1003214734Srpaulo#ifdef CONFIG_AP
1004214734Srpaulo		if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP)) {
1005214734Srpaulo			wpa_printf(MSG_INFO, "Driver does not support AP "
1006214734Srpaulo				   "mode");
1007214734Srpaulo			return;
1008214734Srpaulo		}
1009214734Srpaulo		wpa_supplicant_create_ap(wpa_s, ssid);
1010214734Srpaulo		wpa_s->current_bss = bss;
1011214734Srpaulo#else /* CONFIG_AP */
1012214734Srpaulo		wpa_printf(MSG_ERROR, "AP mode support not included in the "
1013214734Srpaulo			   "build");
1014214734Srpaulo#endif /* CONFIG_AP */
1015214734Srpaulo		return;
1016214734Srpaulo	}
1017214734Srpaulo
1018214734Srpaulo	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
1019214734Srpaulo	    ssid->mode == IEEE80211_MODE_INFRA) {
1020214734Srpaulo		sme_authenticate(wpa_s, bss, ssid);
1021214734Srpaulo		return;
1022214734Srpaulo	}
1023214734Srpaulo
1024189251Ssam	wpa_s->reassociate = 0;
1025189251Ssam	if (bss) {
1026189251Ssam#ifdef CONFIG_IEEE80211R
1027214734Srpaulo		const u8 *ie, *md = NULL;
1028189251Ssam#endif /* CONFIG_IEEE80211R */
1029189251Ssam		wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR
1030189251Ssam			" (SSID='%s' freq=%d MHz)", MAC2STR(bss->bssid),
1031214734Srpaulo			wpa_ssid_txt(bss->ssid, bss->ssid_len), bss->freq);
1032214734Srpaulo		bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
1033189251Ssam		os_memset(wpa_s->bssid, 0, ETH_ALEN);
1034189251Ssam		os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
1035214734Srpaulo		if (bssid_changed)
1036214734Srpaulo			wpas_notify_bssid_changed(wpa_s);
1037189251Ssam#ifdef CONFIG_IEEE80211R
1038214734Srpaulo		ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
1039189251Ssam		if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN)
1040189251Ssam			md = ie + 2;
1041214734Srpaulo		wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0);
1042189251Ssam		if (md) {
1043189251Ssam			/* Prepare for the next transition */
1044214734Srpaulo			wpa_ft_prepare_auth_request(wpa_s->wpa, ie);
1045189251Ssam		}
1046189251Ssam#endif /* CONFIG_IEEE80211R */
1047189251Ssam#ifdef CONFIG_WPS
1048189251Ssam	} else if ((ssid->ssid == NULL || ssid->ssid_len == 0) &&
1049189251Ssam		   wpa_s->conf->ap_scan == 2 &&
1050189251Ssam		   (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
1051189251Ssam		/* Use ap_scan==1 style network selection to find the network
1052189251Ssam		 */
1053189251Ssam		wpa_s->scan_req = 2;
1054189251Ssam		wpa_s->reassociate = 1;
1055189251Ssam		wpa_supplicant_req_scan(wpa_s, 0, 0);
1056189251Ssam		return;
1057189251Ssam#endif /* CONFIG_WPS */
1058189251Ssam	} else {
1059189251Ssam		wpa_msg(wpa_s, MSG_INFO, "Trying to associate with SSID '%s'",
1060189251Ssam			wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
1061189251Ssam		os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
1062189251Ssam	}
1063189251Ssam	wpa_supplicant_cancel_scan(wpa_s);
1064189251Ssam
1065189251Ssam	/* Starting new association, so clear the possibly used WPA IE from the
1066189251Ssam	 * previous association. */
1067189251Ssam	wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
1068189251Ssam
1069189251Ssam#ifdef IEEE8021X_EAPOL
1070189251Ssam	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
1071189251Ssam		if (ssid->leap) {
1072189251Ssam			if (ssid->non_leap == 0)
1073214734Srpaulo				algs = WPA_AUTH_ALG_LEAP;
1074189251Ssam			else
1075214734Srpaulo				algs |= WPA_AUTH_ALG_LEAP;
1076189251Ssam		}
1077189251Ssam	}
1078189251Ssam#endif /* IEEE8021X_EAPOL */
1079189251Ssam	wpa_printf(MSG_DEBUG, "Automatic auth_alg selection: 0x%x", algs);
1080189251Ssam	if (ssid->auth_alg) {
1081214734Srpaulo		algs = ssid->auth_alg;
1082189251Ssam		wpa_printf(MSG_DEBUG, "Overriding auth_alg selection: 0x%x",
1083189251Ssam			   algs);
1084189251Ssam	}
1085189251Ssam
1086214734Srpaulo	if (bss && (wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
1087214734Srpaulo		    wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
1088189251Ssam	    (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK |
1089189251Ssam			       WPA_KEY_MGMT_FT_IEEE8021X |
1090189251Ssam			       WPA_KEY_MGMT_FT_PSK |
1091189251Ssam			       WPA_KEY_MGMT_IEEE8021X_SHA256 |
1092189251Ssam			       WPA_KEY_MGMT_PSK_SHA256))) {
1093189251Ssam		int try_opportunistic;
1094189251Ssam		try_opportunistic = ssid->proactive_key_caching &&
1095189251Ssam			(ssid->proto & WPA_PROTO_RSN);
1096189251Ssam		if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
1097189251Ssam					    wpa_s->current_ssid,
1098189251Ssam					    try_opportunistic) == 0)
1099189251Ssam			eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
1100189251Ssam		wpa_ie_len = sizeof(wpa_ie);
1101189251Ssam		if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
1102189251Ssam					      wpa_ie, &wpa_ie_len)) {
1103189251Ssam			wpa_printf(MSG_WARNING, "WPA: Failed to set WPA key "
1104189251Ssam				   "management and encryption suites");
1105189251Ssam			return;
1106189251Ssam		}
1107189251Ssam	} else if (ssid->key_mgmt &
1108189251Ssam		   (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
1109189251Ssam		    WPA_KEY_MGMT_WPA_NONE | WPA_KEY_MGMT_FT_PSK |
1110189251Ssam		    WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_PSK_SHA256 |
1111189251Ssam		    WPA_KEY_MGMT_IEEE8021X_SHA256)) {
1112189251Ssam		wpa_ie_len = sizeof(wpa_ie);
1113189251Ssam		if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
1114189251Ssam					      wpa_ie, &wpa_ie_len)) {
1115189251Ssam			wpa_printf(MSG_WARNING, "WPA: Failed to set WPA key "
1116189251Ssam				   "management and encryption suites (no scan "
1117189251Ssam				   "results)");
1118189251Ssam			return;
1119189251Ssam		}
1120189251Ssam#ifdef CONFIG_WPS
1121189251Ssam	} else if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
1122189251Ssam		struct wpabuf *wps_ie;
1123189251Ssam		wps_ie = wps_build_assoc_req_ie(wpas_wps_get_req_type(ssid));
1124189251Ssam		if (wps_ie && wpabuf_len(wps_ie) <= sizeof(wpa_ie)) {
1125189251Ssam			wpa_ie_len = wpabuf_len(wps_ie);
1126189251Ssam			os_memcpy(wpa_ie, wpabuf_head(wps_ie), wpa_ie_len);
1127189251Ssam		} else
1128189251Ssam			wpa_ie_len = 0;
1129189251Ssam		wpabuf_free(wps_ie);
1130189251Ssam		wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
1131189251Ssam#endif /* CONFIG_WPS */
1132189251Ssam	} else {
1133189251Ssam		wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
1134189251Ssam		wpa_ie_len = 0;
1135189251Ssam	}
1136189251Ssam
1137189251Ssam	wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
1138189251Ssam	use_crypt = 1;
1139189251Ssam	cipher_pairwise = cipher_suite2driver(wpa_s->pairwise_cipher);
1140189251Ssam	cipher_group = cipher_suite2driver(wpa_s->group_cipher);
1141189251Ssam	if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
1142189251Ssam	    wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
1143189251Ssam		if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE)
1144189251Ssam			use_crypt = 0;
1145189251Ssam		if (wpa_set_wep_keys(wpa_s, ssid)) {
1146189251Ssam			use_crypt = 1;
1147189251Ssam			wep_keys_set = 1;
1148189251Ssam		}
1149189251Ssam	}
1150189251Ssam	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS)
1151189251Ssam		use_crypt = 0;
1152189251Ssam
1153189251Ssam#ifdef IEEE8021X_EAPOL
1154189251Ssam	if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
1155189251Ssam		if ((ssid->eapol_flags &
1156189251Ssam		     (EAPOL_FLAG_REQUIRE_KEY_UNICAST |
1157189251Ssam		      EAPOL_FLAG_REQUIRE_KEY_BROADCAST)) == 0 &&
1158189251Ssam		    !wep_keys_set) {
1159189251Ssam			use_crypt = 0;
1160189251Ssam		} else {
1161189251Ssam			/* Assume that dynamic WEP-104 keys will be used and
1162189251Ssam			 * set cipher suites in order for drivers to expect
1163189251Ssam			 * encryption. */
1164189251Ssam			cipher_pairwise = cipher_group = CIPHER_WEP104;
1165189251Ssam		}
1166189251Ssam	}
1167189251Ssam#endif /* IEEE8021X_EAPOL */
1168189251Ssam
1169189251Ssam	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
1170189251Ssam		/* Set the key before (and later after) association */
1171189251Ssam		wpa_supplicant_set_wpa_none_key(wpa_s, ssid);
1172189251Ssam	}
1173189251Ssam
1174189251Ssam	wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
1175189251Ssam	os_memset(&params, 0, sizeof(params));
1176189251Ssam	if (bss) {
1177189251Ssam		params.bssid = bss->bssid;
1178214734Srpaulo		params.ssid = bss->ssid;
1179214734Srpaulo		params.ssid_len = bss->ssid_len;
1180189251Ssam		params.freq = bss->freq;
1181189251Ssam	} else {
1182189251Ssam		params.ssid = ssid->ssid;
1183189251Ssam		params.ssid_len = ssid->ssid_len;
1184189251Ssam	}
1185214734Srpaulo	if (ssid->mode == WPAS_MODE_IBSS && ssid->frequency > 0 &&
1186214734Srpaulo	    params.freq == 0)
1187189251Ssam		params.freq = ssid->frequency; /* Initial channel for IBSS */
1188189251Ssam	params.wpa_ie = wpa_ie;
1189189251Ssam	params.wpa_ie_len = wpa_ie_len;
1190189251Ssam	params.pairwise_suite = cipher_pairwise;
1191189251Ssam	params.group_suite = cipher_group;
1192189251Ssam	params.key_mgmt_suite = key_mgmt2driver(wpa_s->key_mgmt);
1193189251Ssam	params.auth_alg = algs;
1194189251Ssam	params.mode = ssid->mode;
1195189251Ssam	for (i = 0; i < NUM_WEP_KEYS; i++) {
1196189251Ssam		if (ssid->wep_key_len[i])
1197189251Ssam			params.wep_key[i] = ssid->wep_key[i];
1198189251Ssam		params.wep_key_len[i] = ssid->wep_key_len[i];
1199189251Ssam	}
1200189251Ssam	params.wep_tx_keyidx = ssid->wep_tx_keyidx;
1201189251Ssam
1202214734Srpaulo	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
1203189251Ssam	    (params.key_mgmt_suite == KEY_MGMT_PSK ||
1204189251Ssam	     params.key_mgmt_suite == KEY_MGMT_FT_PSK)) {
1205189251Ssam		params.passphrase = ssid->passphrase;
1206189251Ssam		if (ssid->psk_set)
1207189251Ssam			params.psk = ssid->psk;
1208189251Ssam	}
1209189251Ssam
1210214734Srpaulo	params.drop_unencrypted = use_crypt;
1211214734Srpaulo
1212189251Ssam#ifdef CONFIG_IEEE80211W
1213214734Srpaulo	params.mgmt_frame_protection = ssid->ieee80211w;
1214214734Srpaulo	if (ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION && bss) {
1215214734Srpaulo		const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
1216189251Ssam		struct wpa_ie_data ie;
1217189251Ssam		if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie) == 0 &&
1218189251Ssam		    ie.capabilities &
1219189251Ssam		    (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) {
1220189251Ssam			wpa_printf(MSG_DEBUG, "WPA: Selected AP supports MFP: "
1221189251Ssam				   "require MFP");
1222189251Ssam			params.mgmt_frame_protection =
1223189251Ssam				MGMT_FRAME_PROTECTION_REQUIRED;
1224189251Ssam		}
1225189251Ssam	}
1226189251Ssam#endif /* CONFIG_IEEE80211W */
1227189251Ssam
1228214734Srpaulo	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
1229189251Ssam		ret = ieee80211_sta_associate(wpa_s, &params);
1230189251Ssam	else
1231189251Ssam		ret = wpa_drv_associate(wpa_s, &params);
1232189251Ssam	if (ret < 0) {
1233189251Ssam		wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
1234189251Ssam			"failed");
1235189251Ssam		/* try to continue anyway; new association will be tried again
1236189251Ssam		 * after timeout */
1237189251Ssam		assoc_failed = 1;
1238189251Ssam	}
1239189251Ssam
1240189251Ssam	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
1241189251Ssam		/* Set the key after the association just in case association
1242189251Ssam		 * cleared the previously configured key. */
1243189251Ssam		wpa_supplicant_set_wpa_none_key(wpa_s, ssid);
1244189251Ssam		/* No need to timeout authentication since there is no key
1245189251Ssam		 * management. */
1246189251Ssam		wpa_supplicant_cancel_auth_timeout(wpa_s);
1247189251Ssam		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
1248214734Srpaulo#ifdef CONFIG_IBSS_RSN
1249214734Srpaulo	} else if (ssid->mode == WPAS_MODE_IBSS &&
1250214734Srpaulo		   wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
1251214734Srpaulo		   wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE) {
1252214734Srpaulo		ibss_rsn_set_psk(wpa_s->ibss_rsn, ssid->psk);
1253214734Srpaulo		/*
1254214734Srpaulo		 * RSN IBSS authentication is per-STA and we can disable the
1255214734Srpaulo		 * per-BSSID authentication.
1256214734Srpaulo		 */
1257214734Srpaulo		wpa_supplicant_cancel_auth_timeout(wpa_s);
1258214734Srpaulo#endif /* CONFIG_IBSS_RSN */
1259189251Ssam	} else {
1260189251Ssam		/* Timeout for IEEE 802.11 authentication and association */
1261189251Ssam		int timeout = 60;
1262189251Ssam
1263189251Ssam		if (assoc_failed) {
1264189251Ssam			/* give IBSS a bit more time */
1265214734Srpaulo			timeout = ssid->mode == WPAS_MODE_IBSS ? 10 : 5;
1266189251Ssam		} else if (wpa_s->conf->ap_scan == 1) {
1267189251Ssam			/* give IBSS a bit more time */
1268214734Srpaulo			timeout = ssid->mode == WPAS_MODE_IBSS ? 20 : 10;
1269189251Ssam		}
1270189251Ssam		wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
1271189251Ssam	}
1272189251Ssam
1273189251Ssam	if (wep_keys_set && wpa_drv_get_capa(wpa_s, &capa) == 0 &&
1274189251Ssam	    capa.flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC) {
1275189251Ssam		/* Set static WEP keys again */
1276189251Ssam		wpa_set_wep_keys(wpa_s, ssid);
1277189251Ssam	}
1278189251Ssam
1279189251Ssam	if (wpa_s->current_ssid && wpa_s->current_ssid != ssid) {
1280189251Ssam		/*
1281189251Ssam		 * Do not allow EAP session resumption between different
1282189251Ssam		 * network configurations.
1283189251Ssam		 */
1284189251Ssam		eapol_sm_invalidate_cached_session(wpa_s->eapol);
1285189251Ssam	}
1286214734Srpaulo	old_ssid = wpa_s->current_ssid;
1287189251Ssam	wpa_s->current_ssid = ssid;
1288214734Srpaulo	wpa_s->current_bss = bss;
1289189251Ssam	wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
1290189251Ssam	wpa_supplicant_initiate_eapol(wpa_s);
1291214734Srpaulo	if (old_ssid != wpa_s->current_ssid)
1292214734Srpaulo		wpas_notify_network_changed(wpa_s);
1293189251Ssam}
1294189251Ssam
1295189251Ssam
1296189251Ssam/**
1297189251Ssam * wpa_supplicant_disassociate - Disassociate the current connection
1298189251Ssam * @wpa_s: Pointer to wpa_supplicant data
1299189251Ssam * @reason_code: IEEE 802.11 reason code for the disassociate frame
1300189251Ssam *
1301189251Ssam * This function is used to request %wpa_supplicant to disassociate with the
1302189251Ssam * current AP.
1303189251Ssam */
1304189251Ssamvoid wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
1305189251Ssam				 int reason_code)
1306189251Ssam{
1307214734Srpaulo	struct wpa_ssid *old_ssid;
1308189251Ssam	u8 *addr = NULL;
1309214734Srpaulo
1310189251Ssam	if (!is_zero_ether_addr(wpa_s->bssid)) {
1311214734Srpaulo		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
1312189251Ssam			ieee80211_sta_disassociate(wpa_s, reason_code);
1313189251Ssam		else
1314189251Ssam			wpa_drv_disassociate(wpa_s, wpa_s->bssid, reason_code);
1315189251Ssam		addr = wpa_s->bssid;
1316189251Ssam	}
1317189251Ssam	wpa_clear_keys(wpa_s, addr);
1318189251Ssam	wpa_supplicant_mark_disassoc(wpa_s);
1319214734Srpaulo	old_ssid = wpa_s->current_ssid;
1320189251Ssam	wpa_s->current_ssid = NULL;
1321214734Srpaulo	wpa_s->current_bss = NULL;
1322189251Ssam	wpa_sm_set_config(wpa_s->wpa, NULL);
1323189251Ssam	eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
1324214734Srpaulo	if (old_ssid != wpa_s->current_ssid)
1325214734Srpaulo		wpas_notify_network_changed(wpa_s);
1326214734Srpaulo	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
1327189251Ssam}
1328189251Ssam
1329189251Ssam
1330189251Ssam/**
1331189251Ssam * wpa_supplicant_deauthenticate - Deauthenticate the current connection
1332189251Ssam * @wpa_s: Pointer to wpa_supplicant data
1333189251Ssam * @reason_code: IEEE 802.11 reason code for the deauthenticate frame
1334189251Ssam *
1335189251Ssam * This function is used to request %wpa_supplicant to deauthenticate from the
1336189251Ssam * current AP.
1337189251Ssam */
1338189251Ssamvoid wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
1339189251Ssam				   int reason_code)
1340189251Ssam{
1341214734Srpaulo	struct wpa_ssid *old_ssid;
1342189251Ssam	u8 *addr = NULL;
1343214734Srpaulo
1344189251Ssam	if (!is_zero_ether_addr(wpa_s->bssid)) {
1345214734Srpaulo		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
1346189251Ssam			ieee80211_sta_deauthenticate(wpa_s, reason_code);
1347189251Ssam		else
1348189251Ssam			wpa_drv_deauthenticate(wpa_s, wpa_s->bssid,
1349189251Ssam					       reason_code);
1350189251Ssam		addr = wpa_s->bssid;
1351189251Ssam	}
1352189251Ssam	wpa_clear_keys(wpa_s, addr);
1353209158Srpaulo	wpa_supplicant_mark_disassoc(wpa_s);
1354214734Srpaulo	old_ssid = wpa_s->current_ssid;
1355189251Ssam	wpa_s->current_ssid = NULL;
1356214734Srpaulo	wpa_s->current_bss = NULL;
1357189251Ssam	wpa_sm_set_config(wpa_s->wpa, NULL);
1358189251Ssam	eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
1359214734Srpaulo	if (old_ssid != wpa_s->current_ssid)
1360214734Srpaulo		wpas_notify_network_changed(wpa_s);
1361214734Srpaulo	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
1362189251Ssam}
1363189251Ssam
1364189251Ssam
1365214734Srpaulo/**
1366214734Srpaulo * wpa_supplicant_enable_network - Mark a configured network as enabled
1367214734Srpaulo * @wpa_s: wpa_supplicant structure for a network interface
1368214734Srpaulo * @ssid: wpa_ssid structure for a configured network or %NULL
1369214734Srpaulo *
1370214734Srpaulo * Enables the specified network or all networks if no network specified.
1371214734Srpaulo */
1372214734Srpaulovoid wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
1373214734Srpaulo				   struct wpa_ssid *ssid)
1374189251Ssam{
1375214734Srpaulo	struct wpa_ssid *other_ssid;
1376214734Srpaulo	int was_disabled;
1377189251Ssam
1378214734Srpaulo	if (ssid == NULL) {
1379214734Srpaulo		other_ssid = wpa_s->conf->ssid;
1380214734Srpaulo		while (other_ssid) {
1381214734Srpaulo			if (other_ssid == wpa_s->current_ssid &&
1382214734Srpaulo			    other_ssid->disabled)
1383214734Srpaulo				wpa_s->reassociate = 1;
1384189251Ssam
1385214734Srpaulo			was_disabled = other_ssid->disabled;
1386189251Ssam
1387214734Srpaulo			other_ssid->disabled = 0;
1388189251Ssam
1389214734Srpaulo			if (was_disabled != other_ssid->disabled)
1390214734Srpaulo				wpas_notify_network_enabled_changed(
1391214734Srpaulo					wpa_s, other_ssid);
1392189251Ssam
1393214734Srpaulo			other_ssid = other_ssid->next;
1394214734Srpaulo		}
1395214734Srpaulo		if (wpa_s->reassociate)
1396214734Srpaulo			wpa_supplicant_req_scan(wpa_s, 0, 0);
1397214734Srpaulo	} else if (ssid->disabled) {
1398214734Srpaulo		if (wpa_s->current_ssid == NULL) {
1399214734Srpaulo			/*
1400214734Srpaulo			 * Try to reassociate since there is no current
1401214734Srpaulo			 * configuration and a new network was made available.
1402214734Srpaulo			 */
1403214734Srpaulo			wpa_s->reassociate = 1;
1404214734Srpaulo			wpa_supplicant_req_scan(wpa_s, 0, 0);
1405214734Srpaulo		}
1406189251Ssam
1407214734Srpaulo		was_disabled = ssid->disabled;
1408189251Ssam
1409214734Srpaulo		ssid->disabled = 0;
1410189251Ssam
1411214734Srpaulo		if (was_disabled != ssid->disabled)
1412214734Srpaulo			wpas_notify_network_enabled_changed(wpa_s, ssid);
1413214734Srpaulo	}
1414214734Srpaulo}
1415189251Ssam
1416189251Ssam
1417214734Srpaulo/**
1418214734Srpaulo * wpa_supplicant_disable_network - Mark a configured network as disabled
1419214734Srpaulo * @wpa_s: wpa_supplicant structure for a network interface
1420214734Srpaulo * @ssid: wpa_ssid structure for a configured network or %NULL
1421214734Srpaulo *
1422214734Srpaulo * Disables the specified network or all networks if no network specified.
1423214734Srpaulo */
1424214734Srpaulovoid wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
1425214734Srpaulo				    struct wpa_ssid *ssid)
1426214734Srpaulo{
1427214734Srpaulo	struct wpa_ssid *other_ssid;
1428214734Srpaulo	int was_disabled;
1429189251Ssam
1430214734Srpaulo	if (ssid == NULL) {
1431214734Srpaulo		other_ssid = wpa_s->conf->ssid;
1432214734Srpaulo		while (other_ssid) {
1433214734Srpaulo			was_disabled = other_ssid->disabled;
1434189251Ssam
1435214734Srpaulo			other_ssid->disabled = 1;
1436189251Ssam
1437214734Srpaulo			if (was_disabled != other_ssid->disabled)
1438214734Srpaulo				wpas_notify_network_enabled_changed(
1439214734Srpaulo					wpa_s, other_ssid);
1440189251Ssam
1441214734Srpaulo			other_ssid = other_ssid->next;
1442189251Ssam		}
1443214734Srpaulo		if (wpa_s->current_ssid)
1444214734Srpaulo			wpa_supplicant_disassociate(
1445214734Srpaulo				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
1446214734Srpaulo	} else {
1447214734Srpaulo		if (ssid == wpa_s->current_ssid)
1448214734Srpaulo			wpa_supplicant_disassociate(
1449214734Srpaulo				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
1450189251Ssam
1451214734Srpaulo		was_disabled = ssid->disabled;
1452214734Srpaulo
1453214734Srpaulo		ssid->disabled = 1;
1454214734Srpaulo
1455214734Srpaulo		if (was_disabled != ssid->disabled)
1456214734Srpaulo			wpas_notify_network_enabled_changed(wpa_s, ssid);
1457189251Ssam	}
1458214734Srpaulo}
1459189251Ssam
1460189251Ssam
1461214734Srpaulo/**
1462214734Srpaulo * wpa_supplicant_select_network - Attempt association with a network
1463214734Srpaulo * @wpa_s: wpa_supplicant structure for a network interface
1464214734Srpaulo * @ssid: wpa_ssid structure for a configured network or %NULL for any network
1465214734Srpaulo */
1466214734Srpaulovoid wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
1467214734Srpaulo				   struct wpa_ssid *ssid)
1468214734Srpaulo{
1469214734Srpaulo
1470214734Srpaulo	struct wpa_ssid *other_ssid;
1471214734Srpaulo
1472214734Srpaulo	if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid)
1473214734Srpaulo		wpa_supplicant_disassociate(
1474214734Srpaulo			wpa_s, WLAN_REASON_DEAUTH_LEAVING);
1475214734Srpaulo
1476214734Srpaulo	/*
1477214734Srpaulo	 * Mark all other networks disabled or mark all networks enabled if no
1478214734Srpaulo	 * network specified.
1479214734Srpaulo	 */
1480214734Srpaulo	other_ssid = wpa_s->conf->ssid;
1481214734Srpaulo	while (other_ssid) {
1482214734Srpaulo		int was_disabled = other_ssid->disabled;
1483214734Srpaulo
1484214734Srpaulo		other_ssid->disabled = ssid ? (ssid->id != other_ssid->id) : 0;
1485214734Srpaulo
1486214734Srpaulo		if (was_disabled != other_ssid->disabled)
1487214734Srpaulo			wpas_notify_network_enabled_changed(wpa_s, other_ssid);
1488214734Srpaulo
1489214734Srpaulo		other_ssid = other_ssid->next;
1490214734Srpaulo	}
1491214734Srpaulo	wpa_s->disconnected = 0;
1492214734Srpaulo	wpa_s->reassociate = 1;
1493214734Srpaulo	wpa_supplicant_req_scan(wpa_s, 0, 0);
1494214734Srpaulo
1495214734Srpaulo	if (ssid)
1496214734Srpaulo		wpas_notify_network_selected(wpa_s, ssid);
1497189251Ssam}
1498189251Ssam
1499189251Ssam
1500189251Ssam/**
1501214734Srpaulo * wpa_supplicant_set_ap_scan - Set AP scan mode for interface
1502214734Srpaulo * @wpa_s: wpa_supplicant structure for a network interface
1503214734Srpaulo * @ap_scan: AP scan mode
1504214734Srpaulo * Returns: 0 if succeed or -1 if ap_scan has an invalid value
1505189251Ssam *
1506189251Ssam */
1507214734Srpauloint wpa_supplicant_set_ap_scan(struct wpa_supplicant *wpa_s, int ap_scan)
1508189251Ssam{
1509189251Ssam
1510214734Srpaulo	int old_ap_scan;
1511189251Ssam
1512214734Srpaulo	if (ap_scan < 0 || ap_scan > 2)
1513214734Srpaulo		return -1;
1514189251Ssam
1515214734Srpaulo	old_ap_scan = wpa_s->conf->ap_scan;
1516214734Srpaulo	wpa_s->conf->ap_scan = ap_scan;
1517214734Srpaulo
1518214734Srpaulo	if (old_ap_scan != wpa_s->conf->ap_scan)
1519214734Srpaulo		wpas_notify_ap_scan_changed(wpa_s);
1520214734Srpaulo
1521214734Srpaulo	return 0;
1522189251Ssam}
1523189251Ssam
1524189251Ssam
1525189251Ssam/**
1526214734Srpaulo * wpa_supplicant_set_debug_params - Set global debug params
1527214734Srpaulo * @global: wpa_global structure
1528214734Srpaulo * @debug_level: debug level
1529214734Srpaulo * @debug_timestamp: determines if show timestamp in debug data
1530214734Srpaulo * @debug_show_keys: determines if show keys in debug data
1531214734Srpaulo * Returns: 0 if succeed or -1 if debug_level has wrong value
1532214734Srpaulo */
1533214734Srpauloint wpa_supplicant_set_debug_params(struct wpa_global *global, int debug_level,
1534214734Srpaulo				    int debug_timestamp, int debug_show_keys)
1535214734Srpaulo{
1536214734Srpaulo
1537214734Srpaulo	int old_level, old_timestamp, old_show_keys;
1538214734Srpaulo
1539214734Srpaulo	/* check for allowed debuglevels */
1540214734Srpaulo	if (debug_level != MSG_MSGDUMP &&
1541214734Srpaulo	    debug_level != MSG_DEBUG &&
1542214734Srpaulo	    debug_level != MSG_INFO &&
1543214734Srpaulo	    debug_level != MSG_WARNING &&
1544214734Srpaulo	    debug_level != MSG_ERROR)
1545214734Srpaulo		return -1;
1546214734Srpaulo
1547214734Srpaulo	old_level = wpa_debug_level;
1548214734Srpaulo	old_timestamp = wpa_debug_timestamp;
1549214734Srpaulo	old_show_keys = wpa_debug_show_keys;
1550214734Srpaulo
1551214734Srpaulo	wpa_debug_level = debug_level;
1552214734Srpaulo	wpa_debug_timestamp = debug_timestamp ? 1 : 0;
1553214734Srpaulo	wpa_debug_show_keys = debug_show_keys ? 1 : 0;
1554214734Srpaulo
1555214734Srpaulo	if (wpa_debug_level != old_level)
1556214734Srpaulo		wpas_notify_debug_level_changed(global);
1557214734Srpaulo	if (wpa_debug_timestamp != old_timestamp)
1558214734Srpaulo		wpas_notify_debug_timestamp_changed(global);
1559214734Srpaulo	if (wpa_debug_show_keys != old_show_keys)
1560214734Srpaulo		wpas_notify_debug_show_keys_changed(global);
1561214734Srpaulo
1562214734Srpaulo	return 0;
1563214734Srpaulo}
1564214734Srpaulo
1565214734Srpaulo
1566214734Srpaulo/**
1567189251Ssam * wpa_supplicant_get_ssid - Get a pointer to the current network structure
1568189251Ssam * @wpa_s: Pointer to wpa_supplicant data
1569189251Ssam * Returns: A pointer to the current network structure or %NULL on failure
1570189251Ssam */
1571189251Ssamstruct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
1572189251Ssam{
1573189251Ssam	struct wpa_ssid *entry;
1574189251Ssam	u8 ssid[MAX_SSID_LEN];
1575189251Ssam	int res;
1576189251Ssam	size_t ssid_len;
1577189251Ssam	u8 bssid[ETH_ALEN];
1578189251Ssam	int wired;
1579189251Ssam
1580214734Srpaulo	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
1581189251Ssam		if (ieee80211_sta_get_ssid(wpa_s, ssid, &ssid_len)) {
1582189251Ssam			wpa_printf(MSG_WARNING, "Could not read SSID from "
1583189251Ssam				   "MLME.");
1584189251Ssam			return NULL;
1585189251Ssam		}
1586189251Ssam	} else {
1587189251Ssam		res = wpa_drv_get_ssid(wpa_s, ssid);
1588189251Ssam		if (res < 0) {
1589189251Ssam			wpa_printf(MSG_WARNING, "Could not read SSID from "
1590189251Ssam				   "driver.");
1591189251Ssam			return NULL;
1592189251Ssam		}
1593189251Ssam		ssid_len = res;
1594189251Ssam	}
1595189251Ssam
1596214734Srpaulo	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
1597189251Ssam		os_memcpy(bssid, wpa_s->bssid, ETH_ALEN);
1598189251Ssam	else if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
1599189251Ssam		wpa_printf(MSG_WARNING, "Could not read BSSID from driver.");
1600189251Ssam		return NULL;
1601189251Ssam	}
1602189251Ssam
1603214734Srpaulo	wired = wpa_s->conf->ap_scan == 0 &&
1604214734Srpaulo		(wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED);
1605189251Ssam
1606189251Ssam	entry = wpa_s->conf->ssid;
1607189251Ssam	while (entry) {
1608189251Ssam		if (!entry->disabled &&
1609189251Ssam		    ((ssid_len == entry->ssid_len &&
1610189251Ssam		      os_memcmp(ssid, entry->ssid, ssid_len) == 0) || wired) &&
1611189251Ssam		    (!entry->bssid_set ||
1612189251Ssam		     os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
1613189251Ssam			return entry;
1614189251Ssam#ifdef CONFIG_WPS
1615189251Ssam		if (!entry->disabled &&
1616189251Ssam		    (entry->key_mgmt & WPA_KEY_MGMT_WPS) &&
1617189251Ssam		    (entry->ssid == NULL || entry->ssid_len == 0) &&
1618189251Ssam		    (!entry->bssid_set ||
1619189251Ssam		     os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
1620189251Ssam			return entry;
1621189251Ssam#endif /* CONFIG_WPS */
1622189251Ssam		entry = entry->next;
1623189251Ssam	}
1624189251Ssam
1625189251Ssam	return NULL;
1626189251Ssam}
1627189251Ssam
1628189251Ssam
1629189251Ssamstatic int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
1630189251Ssam				     const char *name)
1631189251Ssam{
1632189251Ssam	int i;
1633214734Srpaulo	size_t len;
1634214734Srpaulo	const char *pos;
1635189251Ssam
1636189251Ssam	if (wpa_s == NULL)
1637189251Ssam		return -1;
1638189251Ssam
1639214734Srpaulo	if (wpa_drivers[0] == NULL) {
1640189251Ssam		wpa_printf(MSG_ERROR, "No driver interfaces build into "
1641189251Ssam			   "wpa_supplicant.");
1642189251Ssam		return -1;
1643189251Ssam	}
1644189251Ssam
1645189251Ssam	if (name == NULL) {
1646189251Ssam		/* default to first driver in the list */
1647214734Srpaulo		wpa_s->driver = wpa_drivers[0];
1648209158Srpaulo		wpa_s->global_drv_priv = wpa_s->global->drv_priv[0];
1649189251Ssam		return 0;
1650189251Ssam	}
1651189251Ssam
1652214734Srpaulo	pos = os_strchr(name, ',');
1653214734Srpaulo	if (pos)
1654214734Srpaulo		len = pos - name;
1655214734Srpaulo	else
1656214734Srpaulo		len = os_strlen(name);
1657214734Srpaulo	for (i = 0; wpa_drivers[i]; i++) {
1658214734Srpaulo		if (os_strlen(wpa_drivers[i]->name) == len &&
1659214734Srpaulo		    os_strncmp(name, wpa_drivers[i]->name, len) ==
1660214734Srpaulo		    0) {
1661214734Srpaulo			wpa_s->driver = wpa_drivers[i];
1662209158Srpaulo			wpa_s->global_drv_priv = wpa_s->global->drv_priv[i];
1663189251Ssam			return 0;
1664189251Ssam		}
1665189251Ssam	}
1666189251Ssam
1667214734Srpaulo	wpa_printf(MSG_ERROR, "Unsupported driver '%s'.", name);
1668189251Ssam	return -1;
1669189251Ssam}
1670189251Ssam
1671189251Ssam
1672214734Srpaulo/**
1673214734Srpaulo * wpa_supplicant_rx_eapol - Deliver a received EAPOL frame to wpa_supplicant
1674214734Srpaulo * @ctx: Context pointer (wpa_s); this is the ctx variable registered
1675214734Srpaulo *	with struct wpa_driver_ops::init()
1676214734Srpaulo * @src_addr: Source address of the EAPOL frame
1677214734Srpaulo * @buf: EAPOL data starting from the EAPOL header (i.e., no Ethernet header)
1678214734Srpaulo * @len: Length of the EAPOL data
1679214734Srpaulo *
1680214734Srpaulo * This function is called for each received EAPOL frame. Most driver
1681214734Srpaulo * interfaces rely on more generic OS mechanism for receiving frames through
1682214734Srpaulo * l2_packet, but if such a mechanism is not available, the driver wrapper may
1683214734Srpaulo * take care of received EAPOL frames and deliver them to the core supplicant
1684214734Srpaulo * code by calling this function.
1685214734Srpaulo */
1686189251Ssamvoid wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
1687189251Ssam			     const u8 *buf, size_t len)
1688189251Ssam{
1689189251Ssam	struct wpa_supplicant *wpa_s = ctx;
1690189251Ssam
1691189251Ssam	wpa_printf(MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
1692189251Ssam	wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
1693189251Ssam
1694209158Srpaulo	if (wpa_s->wpa_state < WPA_ASSOCIATED) {
1695209158Srpaulo		/*
1696209158Srpaulo		 * There is possible race condition between receiving the
1697209158Srpaulo		 * association event and the EAPOL frame since they are coming
1698209158Srpaulo		 * through different paths from the driver. In order to avoid
1699209158Srpaulo		 * issues in trying to process the EAPOL frame before receiving
1700209158Srpaulo		 * association information, lets queue it for processing until
1701209158Srpaulo		 * the association event is received.
1702209158Srpaulo		 */
1703209158Srpaulo		wpa_printf(MSG_DEBUG, "Not associated - Delay processing of "
1704209158Srpaulo			   "received EAPOL frame");
1705209158Srpaulo		wpabuf_free(wpa_s->pending_eapol_rx);
1706209158Srpaulo		wpa_s->pending_eapol_rx = wpabuf_alloc_copy(buf, len);
1707209158Srpaulo		if (wpa_s->pending_eapol_rx) {
1708209158Srpaulo			os_get_time(&wpa_s->pending_eapol_rx_time);
1709209158Srpaulo			os_memcpy(wpa_s->pending_eapol_rx_src, src_addr,
1710209158Srpaulo				  ETH_ALEN);
1711209158Srpaulo		}
1712209158Srpaulo		return;
1713209158Srpaulo	}
1714209158Srpaulo
1715214734Srpaulo#ifdef CONFIG_AP
1716214734Srpaulo	if (wpa_s->ap_iface) {
1717214734Srpaulo		wpa_supplicant_ap_rx_eapol(wpa_s, src_addr, buf, len);
1718214734Srpaulo		return;
1719214734Srpaulo	}
1720214734Srpaulo#endif /* CONFIG_AP */
1721214734Srpaulo
1722189251Ssam	if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
1723189251Ssam		wpa_printf(MSG_DEBUG, "Ignored received EAPOL frame since "
1724189251Ssam			   "no key management is configured");
1725189251Ssam		return;
1726189251Ssam	}
1727189251Ssam
1728189251Ssam	if (wpa_s->eapol_received == 0 &&
1729214734Srpaulo	    (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) ||
1730189251Ssam	     !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
1731214734Srpaulo	     wpa_s->wpa_state != WPA_COMPLETED) &&
1732214734Srpaulo	    (wpa_s->current_ssid == NULL ||
1733214734Srpaulo	     wpa_s->current_ssid->mode != IEEE80211_MODE_IBSS)) {
1734189251Ssam		/* Timeout for completing IEEE 802.1X and WPA authentication */
1735189251Ssam		wpa_supplicant_req_auth_timeout(
1736189251Ssam			wpa_s,
1737189251Ssam			(wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
1738189251Ssam			 wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA ||
1739189251Ssam			 wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) ?
1740189251Ssam			70 : 10, 0);
1741189251Ssam	}
1742189251Ssam	wpa_s->eapol_received++;
1743189251Ssam
1744189251Ssam	if (wpa_s->countermeasures) {
1745189251Ssam		wpa_printf(MSG_INFO, "WPA: Countermeasures - dropped EAPOL "
1746189251Ssam			   "packet");
1747189251Ssam		return;
1748189251Ssam	}
1749189251Ssam
1750214734Srpaulo#ifdef CONFIG_IBSS_RSN
1751214734Srpaulo	if (wpa_s->current_ssid &&
1752214734Srpaulo	    wpa_s->current_ssid->mode == WPAS_MODE_IBSS) {
1753214734Srpaulo		ibss_rsn_rx_eapol(wpa_s->ibss_rsn, src_addr, buf, len);
1754214734Srpaulo		return;
1755214734Srpaulo	}
1756214734Srpaulo#endif /* CONFIG_IBSS_RSN */
1757214734Srpaulo
1758189251Ssam	/* Source address of the incoming EAPOL frame could be compared to the
1759189251Ssam	 * current BSSID. However, it is possible that a centralized
1760189251Ssam	 * Authenticator could be using another MAC address than the BSSID of
1761189251Ssam	 * an AP, so just allow any address to be used for now. The replies are
1762189251Ssam	 * still sent to the current BSSID (if available), though. */
1763189251Ssam
1764189251Ssam	os_memcpy(wpa_s->last_eapol_src, src_addr, ETH_ALEN);
1765189251Ssam	if (!wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) &&
1766189251Ssam	    eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0)
1767189251Ssam		return;
1768189251Ssam	wpa_drv_poll(wpa_s);
1769214734Srpaulo	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
1770189251Ssam		wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
1771189251Ssam	else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
1772189251Ssam		/*
1773189251Ssam		 * Set portValid = TRUE here since we are going to skip 4-way
1774189251Ssam		 * handshake processing which would normally set portValid. We
1775189251Ssam		 * need this to allow the EAPOL state machines to be completed
1776189251Ssam		 * without going through EAPOL-Key handshake.
1777189251Ssam		 */
1778189251Ssam		eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
1779189251Ssam	}
1780189251Ssam}
1781189251Ssam
1782189251Ssam
1783189251Ssam/**
1784189251Ssam * wpa_supplicant_driver_init - Initialize driver interface parameters
1785189251Ssam * @wpa_s: Pointer to wpa_supplicant data
1786189251Ssam * Returns: 0 on success, -1 on failure
1787189251Ssam *
1788189251Ssam * This function is called to initialize driver interface parameters.
1789189251Ssam * wpa_drv_init() must have been called before this function to initialize the
1790189251Ssam * driver interface.
1791189251Ssam */
1792189251Ssamint wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
1793189251Ssam{
1794189251Ssam	static int interface_count = 0;
1795189251Ssam
1796189251Ssam	if (wpa_s->driver->send_eapol) {
1797189251Ssam		const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
1798189251Ssam		if (addr)
1799189251Ssam			os_memcpy(wpa_s->own_addr, addr, ETH_ALEN);
1800189251Ssam	} else {
1801189251Ssam		wpa_s->l2 = l2_packet_init(wpa_s->ifname,
1802189251Ssam					   wpa_drv_get_mac_addr(wpa_s),
1803189251Ssam					   ETH_P_EAPOL,
1804189251Ssam					   wpa_supplicant_rx_eapol, wpa_s, 0);
1805189251Ssam		if (wpa_s->l2 == NULL)
1806189251Ssam			return -1;
1807189251Ssam	}
1808189251Ssam
1809189251Ssam	if (wpa_s->l2 && l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) {
1810189251Ssam		wpa_printf(MSG_ERROR, "Failed to get own L2 address");
1811189251Ssam		return -1;
1812189251Ssam	}
1813189251Ssam
1814189251Ssam	wpa_printf(MSG_DEBUG, "Own MAC address: " MACSTR,
1815189251Ssam		   MAC2STR(wpa_s->own_addr));
1816189251Ssam
1817189251Ssam	if (wpa_s->bridge_ifname[0]) {
1818189251Ssam		wpa_printf(MSG_DEBUG, "Receiving packets from bridge interface"
1819189251Ssam			   " '%s'", wpa_s->bridge_ifname);
1820189251Ssam		wpa_s->l2_br = l2_packet_init(wpa_s->bridge_ifname,
1821189251Ssam					      wpa_s->own_addr,
1822189251Ssam					      ETH_P_EAPOL,
1823189251Ssam					      wpa_supplicant_rx_eapol, wpa_s,
1824189251Ssam					      0);
1825189251Ssam		if (wpa_s->l2_br == NULL) {
1826189251Ssam			wpa_printf(MSG_ERROR, "Failed to open l2_packet "
1827189251Ssam				   "connection for the bridge interface '%s'",
1828189251Ssam				   wpa_s->bridge_ifname);
1829189251Ssam			return -1;
1830189251Ssam		}
1831189251Ssam	}
1832189251Ssam
1833189251Ssam	wpa_clear_keys(wpa_s, NULL);
1834189251Ssam
1835189251Ssam	/* Make sure that TKIP countermeasures are not left enabled (could
1836189251Ssam	 * happen if wpa_supplicant is killed during countermeasures. */
1837189251Ssam	wpa_drv_set_countermeasures(wpa_s, 0);
1838189251Ssam
1839189251Ssam	wpa_printf(MSG_DEBUG, "RSN: flushing PMKID list in the driver");
1840189251Ssam	wpa_drv_flush_pmkid(wpa_s);
1841189251Ssam
1842214734Srpaulo	wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
1843214734Srpaulo	if (wpa_supplicant_enabled_networks(wpa_s->conf)) {
1844214734Srpaulo		wpa_supplicant_req_scan(wpa_s, interface_count, 100000);
1845214734Srpaulo		interface_count++;
1846214734Srpaulo	} else
1847214734Srpaulo		wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
1848189251Ssam
1849189251Ssam	return 0;
1850189251Ssam}
1851189251Ssam
1852189251Ssam
1853189251Ssamstatic int wpa_supplicant_daemon(const char *pid_file)
1854189251Ssam{
1855189251Ssam	wpa_printf(MSG_DEBUG, "Daemonize..");
1856189251Ssam	return os_daemonize(pid_file);
1857189251Ssam}
1858189251Ssam
1859189251Ssam
1860189251Ssamstatic struct wpa_supplicant * wpa_supplicant_alloc(void)
1861189251Ssam{
1862189251Ssam	struct wpa_supplicant *wpa_s;
1863189251Ssam
1864189251Ssam	wpa_s = os_zalloc(sizeof(*wpa_s));
1865189251Ssam	if (wpa_s == NULL)
1866189251Ssam		return NULL;
1867189251Ssam	wpa_s->scan_req = 1;
1868214734Srpaulo	wpa_s->new_connection = 1;
1869189251Ssam
1870189251Ssam	return wpa_s;
1871189251Ssam}
1872189251Ssam
1873189251Ssam
1874189251Ssamstatic int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
1875189251Ssam				     struct wpa_interface *iface)
1876189251Ssam{
1877214734Srpaulo	const char *ifname, *driver;
1878214734Srpaulo	struct wpa_driver_capa capa;
1879214734Srpaulo
1880189251Ssam	wpa_printf(MSG_DEBUG, "Initializing interface '%s' conf '%s' driver "
1881189251Ssam		   "'%s' ctrl_interface '%s' bridge '%s'", iface->ifname,
1882189251Ssam		   iface->confname ? iface->confname : "N/A",
1883189251Ssam		   iface->driver ? iface->driver : "default",
1884189251Ssam		   iface->ctrl_interface ? iface->ctrl_interface : "N/A",
1885189251Ssam		   iface->bridge_ifname ? iface->bridge_ifname : "N/A");
1886189251Ssam
1887189251Ssam	if (iface->confname) {
1888189251Ssam#ifdef CONFIG_BACKEND_FILE
1889189251Ssam		wpa_s->confname = os_rel2abs_path(iface->confname);
1890189251Ssam		if (wpa_s->confname == NULL) {
1891189251Ssam			wpa_printf(MSG_ERROR, "Failed to get absolute path "
1892189251Ssam				   "for configuration file '%s'.",
1893189251Ssam				   iface->confname);
1894189251Ssam			return -1;
1895189251Ssam		}
1896189251Ssam		wpa_printf(MSG_DEBUG, "Configuration file '%s' -> '%s'",
1897189251Ssam			   iface->confname, wpa_s->confname);
1898189251Ssam#else /* CONFIG_BACKEND_FILE */
1899189251Ssam		wpa_s->confname = os_strdup(iface->confname);
1900189251Ssam#endif /* CONFIG_BACKEND_FILE */
1901189251Ssam		wpa_s->conf = wpa_config_read(wpa_s->confname);
1902189251Ssam		if (wpa_s->conf == NULL) {
1903189251Ssam			wpa_printf(MSG_ERROR, "Failed to read or parse "
1904189251Ssam				   "configuration '%s'.", wpa_s->confname);
1905189251Ssam			return -1;
1906189251Ssam		}
1907189251Ssam
1908189251Ssam		/*
1909189251Ssam		 * Override ctrl_interface and driver_param if set on command
1910189251Ssam		 * line.
1911189251Ssam		 */
1912189251Ssam		if (iface->ctrl_interface) {
1913189251Ssam			os_free(wpa_s->conf->ctrl_interface);
1914189251Ssam			wpa_s->conf->ctrl_interface =
1915189251Ssam				os_strdup(iface->ctrl_interface);
1916189251Ssam		}
1917189251Ssam
1918189251Ssam		if (iface->driver_param) {
1919189251Ssam			os_free(wpa_s->conf->driver_param);
1920189251Ssam			wpa_s->conf->driver_param =
1921189251Ssam				os_strdup(iface->driver_param);
1922189251Ssam		}
1923189251Ssam	} else
1924189251Ssam		wpa_s->conf = wpa_config_alloc_empty(iface->ctrl_interface,
1925189251Ssam						     iface->driver_param);
1926189251Ssam
1927189251Ssam	if (wpa_s->conf == NULL) {
1928189251Ssam		wpa_printf(MSG_ERROR, "\nNo configuration found.");
1929189251Ssam		return -1;
1930189251Ssam	}
1931189251Ssam
1932189251Ssam	if (iface->ifname == NULL) {
1933189251Ssam		wpa_printf(MSG_ERROR, "\nInterface name is required.");
1934189251Ssam		return -1;
1935189251Ssam	}
1936189251Ssam	if (os_strlen(iface->ifname) >= sizeof(wpa_s->ifname)) {
1937189251Ssam		wpa_printf(MSG_ERROR, "\nToo long interface name '%s'.",
1938189251Ssam			   iface->ifname);
1939189251Ssam		return -1;
1940189251Ssam	}
1941189251Ssam	os_strlcpy(wpa_s->ifname, iface->ifname, sizeof(wpa_s->ifname));
1942189251Ssam
1943189251Ssam	if (iface->bridge_ifname) {
1944189251Ssam		if (os_strlen(iface->bridge_ifname) >=
1945189251Ssam		    sizeof(wpa_s->bridge_ifname)) {
1946189251Ssam			wpa_printf(MSG_ERROR, "\nToo long bridge interface "
1947189251Ssam				   "name '%s'.", iface->bridge_ifname);
1948189251Ssam			return -1;
1949189251Ssam		}
1950189251Ssam		os_strlcpy(wpa_s->bridge_ifname, iface->bridge_ifname,
1951189251Ssam			   sizeof(wpa_s->bridge_ifname));
1952189251Ssam	}
1953189251Ssam
1954189251Ssam	/* RSNA Supplicant Key Management - INITIALIZE */
1955189251Ssam	eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
1956189251Ssam	eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
1957189251Ssam
1958189251Ssam	/* Initialize driver interface and register driver event handler before
1959189251Ssam	 * L2 receive handler so that association events are processed before
1960189251Ssam	 * EAPOL-Key packets if both become available for the same select()
1961189251Ssam	 * call. */
1962214734Srpaulo	driver = iface->driver;
1963214734Srpaulonext_driver:
1964214734Srpaulo	if (wpa_supplicant_set_driver(wpa_s, driver) < 0)
1965214734Srpaulo		return -1;
1966214734Srpaulo
1967189251Ssam	wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
1968189251Ssam	if (wpa_s->drv_priv == NULL) {
1969214734Srpaulo		const char *pos;
1970214734Srpaulo		pos = driver ? os_strchr(driver, ',') : NULL;
1971214734Srpaulo		if (pos) {
1972214734Srpaulo			wpa_printf(MSG_DEBUG, "Failed to initialize driver "
1973214734Srpaulo				   "interface - try next driver wrapper");
1974214734Srpaulo			driver = pos + 1;
1975214734Srpaulo			goto next_driver;
1976214734Srpaulo		}
1977189251Ssam		wpa_printf(MSG_ERROR, "Failed to initialize driver interface");
1978189251Ssam		return -1;
1979189251Ssam	}
1980189251Ssam	if (wpa_drv_set_param(wpa_s, wpa_s->conf->driver_param) < 0) {
1981189251Ssam		wpa_printf(MSG_ERROR, "Driver interface rejected "
1982189251Ssam			   "driver_param '%s'", wpa_s->conf->driver_param);
1983189251Ssam		return -1;
1984189251Ssam	}
1985189251Ssam
1986189251Ssam	ifname = wpa_drv_get_ifname(wpa_s);
1987189251Ssam	if (ifname && os_strcmp(ifname, wpa_s->ifname) != 0) {
1988189251Ssam		wpa_printf(MSG_DEBUG, "Driver interface replaced interface "
1989189251Ssam			   "name with '%s'", ifname);
1990189251Ssam		os_strlcpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
1991189251Ssam	}
1992189251Ssam
1993189251Ssam	if (wpa_supplicant_init_wpa(wpa_s) < 0)
1994189251Ssam		return -1;
1995189251Ssam
1996189251Ssam	wpa_sm_set_ifname(wpa_s->wpa, wpa_s->ifname,
1997189251Ssam			  wpa_s->bridge_ifname[0] ? wpa_s->bridge_ifname :
1998189251Ssam			  NULL);
1999189251Ssam	wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
2000189251Ssam
2001189251Ssam	if (wpa_s->conf->dot11RSNAConfigPMKLifetime &&
2002189251Ssam	    wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
2003189251Ssam			     wpa_s->conf->dot11RSNAConfigPMKLifetime)) {
2004189251Ssam		wpa_printf(MSG_ERROR, "Invalid WPA parameter value for "
2005189251Ssam			   "dot11RSNAConfigPMKLifetime");
2006189251Ssam		return -1;
2007189251Ssam	}
2008189251Ssam
2009189251Ssam	if (wpa_s->conf->dot11RSNAConfigPMKReauthThreshold &&
2010189251Ssam	    wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
2011189251Ssam			     wpa_s->conf->dot11RSNAConfigPMKReauthThreshold)) {
2012189251Ssam		wpa_printf(MSG_ERROR, "Invalid WPA parameter value for "
2013189251Ssam			"dot11RSNAConfigPMKReauthThreshold");
2014189251Ssam		return -1;
2015189251Ssam	}
2016189251Ssam
2017189251Ssam	if (wpa_s->conf->dot11RSNAConfigSATimeout &&
2018189251Ssam	    wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT,
2019189251Ssam			     wpa_s->conf->dot11RSNAConfigSATimeout)) {
2020189251Ssam		wpa_printf(MSG_ERROR, "Invalid WPA parameter value for "
2021189251Ssam			   "dot11RSNAConfigSATimeout");
2022189251Ssam		return -1;
2023189251Ssam	}
2024189251Ssam
2025214734Srpaulo	if (wpa_drv_get_capa(wpa_s, &capa) == 0) {
2026214734Srpaulo		wpa_s->drv_flags = capa.flags;
2027214734Srpaulo		if (capa.flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
2028214734Srpaulo			if (ieee80211_sta_init(wpa_s))
2029214734Srpaulo				return -1;
2030214734Srpaulo		}
2031214734Srpaulo		wpa_s->max_scan_ssids = capa.max_scan_ssids;
2032214734Srpaulo		wpa_s->max_remain_on_chan = capa.max_remain_on_chan;
2033214734Srpaulo	}
2034214734Srpaulo	if (wpa_s->max_remain_on_chan == 0)
2035214734Srpaulo		wpa_s->max_remain_on_chan = 1000;
2036214734Srpaulo
2037189251Ssam	if (wpa_supplicant_driver_init(wpa_s) < 0)
2038189251Ssam		return -1;
2039189251Ssam
2040189251Ssam	if (wpa_s->conf->country[0] && wpa_s->conf->country[1] &&
2041189251Ssam	    wpa_drv_set_country(wpa_s, wpa_s->conf->country)) {
2042189251Ssam		wpa_printf(MSG_DEBUG, "Failed to set country");
2043189251Ssam		return -1;
2044189251Ssam	}
2045189251Ssam
2046189251Ssam	wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
2047189251Ssam
2048189251Ssam	if (wpas_wps_init(wpa_s))
2049189251Ssam		return -1;
2050189251Ssam
2051189251Ssam	if (wpa_supplicant_init_eapol(wpa_s) < 0)
2052189251Ssam		return -1;
2053189251Ssam	wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
2054189251Ssam
2055189251Ssam	wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
2056189251Ssam	if (wpa_s->ctrl_iface == NULL) {
2057189251Ssam		wpa_printf(MSG_ERROR,
2058189251Ssam			   "Failed to initialize control interface '%s'.\n"
2059189251Ssam			   "You may have another wpa_supplicant process "
2060189251Ssam			   "already running or the file was\n"
2061189251Ssam			   "left by an unclean termination of wpa_supplicant "
2062189251Ssam			   "in which case you will need\n"
2063189251Ssam			   "to manually remove this file before starting "
2064189251Ssam			   "wpa_supplicant again.\n",
2065189251Ssam			   wpa_s->conf->ctrl_interface);
2066189251Ssam		return -1;
2067189251Ssam	}
2068189251Ssam
2069214734Srpaulo#ifdef CONFIG_IBSS_RSN
2070214734Srpaulo	wpa_s->ibss_rsn = ibss_rsn_init(wpa_s);
2071214734Srpaulo	if (!wpa_s->ibss_rsn) {
2072214734Srpaulo		wpa_printf(MSG_DEBUG, "Failed to init IBSS RSN");
2073214734Srpaulo		return -1;
2074189251Ssam	}
2075214734Srpaulo#endif /* CONFIG_IBSS_RSN */
2076189251Ssam
2077214734Srpaulo	if (wpa_bss_init(wpa_s) < 0)
2078214734Srpaulo		return -1;
2079214734Srpaulo
2080189251Ssam	return 0;
2081189251Ssam}
2082189251Ssam
2083189251Ssam
2084214734Srpaulostatic void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
2085214734Srpaulo					int notify)
2086189251Ssam{
2087189251Ssam	if (wpa_s->drv_priv) {
2088189251Ssam		wpa_supplicant_deauthenticate(wpa_s,
2089189251Ssam					      WLAN_REASON_DEAUTH_LEAVING);
2090189251Ssam
2091189251Ssam		wpa_drv_set_countermeasures(wpa_s, 0);
2092189251Ssam		wpa_clear_keys(wpa_s, NULL);
2093189251Ssam	}
2094189251Ssam
2095189251Ssam	wpa_supplicant_cleanup(wpa_s);
2096189251Ssam
2097214734Srpaulo	if (notify)
2098214734Srpaulo		wpas_notify_iface_removed(wpa_s);
2099214734Srpaulo
2100189251Ssam	if (wpa_s->drv_priv)
2101189251Ssam		wpa_drv_deinit(wpa_s);
2102189251Ssam}
2103189251Ssam
2104189251Ssam
2105189251Ssam/**
2106189251Ssam * wpa_supplicant_add_iface - Add a new network interface
2107189251Ssam * @global: Pointer to global data from wpa_supplicant_init()
2108189251Ssam * @iface: Interface configuration options
2109189251Ssam * Returns: Pointer to the created interface or %NULL on failure
2110189251Ssam *
2111189251Ssam * This function is used to add new network interfaces for %wpa_supplicant.
2112189251Ssam * This can be called before wpa_supplicant_run() to add interfaces before the
2113189251Ssam * main event loop has been started. In addition, new interfaces can be added
2114189251Ssam * dynamically while %wpa_supplicant is already running. This could happen,
2115189251Ssam * e.g., when a hotplug network adapter is inserted.
2116189251Ssam */
2117189251Ssamstruct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
2118189251Ssam						 struct wpa_interface *iface)
2119189251Ssam{
2120189251Ssam	struct wpa_supplicant *wpa_s;
2121214734Srpaulo	struct wpa_interface t_iface;
2122214734Srpaulo	struct wpa_ssid *ssid;
2123189251Ssam
2124189251Ssam	if (global == NULL || iface == NULL)
2125189251Ssam		return NULL;
2126189251Ssam
2127189251Ssam	wpa_s = wpa_supplicant_alloc();
2128189251Ssam	if (wpa_s == NULL)
2129189251Ssam		return NULL;
2130189251Ssam
2131209158Srpaulo	wpa_s->global = global;
2132209158Srpaulo
2133214734Srpaulo	t_iface = *iface;
2134214734Srpaulo	if (global->params.override_driver) {
2135214734Srpaulo		wpa_printf(MSG_DEBUG, "Override interface parameter: driver "
2136214734Srpaulo			   "('%s' -> '%s')",
2137214734Srpaulo			   iface->driver, global->params.override_driver);
2138214734Srpaulo		t_iface.driver = global->params.override_driver;
2139214734Srpaulo	}
2140214734Srpaulo	if (global->params.override_ctrl_interface) {
2141214734Srpaulo		wpa_printf(MSG_DEBUG, "Override interface parameter: "
2142214734Srpaulo			   "ctrl_interface ('%s' -> '%s')",
2143214734Srpaulo			   iface->ctrl_interface,
2144214734Srpaulo			   global->params.override_ctrl_interface);
2145214734Srpaulo		t_iface.ctrl_interface =
2146214734Srpaulo			global->params.override_ctrl_interface;
2147214734Srpaulo	}
2148214734Srpaulo	if (wpa_supplicant_init_iface(wpa_s, &t_iface)) {
2149189251Ssam		wpa_printf(MSG_DEBUG, "Failed to add interface %s",
2150189251Ssam			   iface->ifname);
2151214734Srpaulo		wpa_supplicant_deinit_iface(wpa_s, 0);
2152189251Ssam		os_free(wpa_s);
2153189251Ssam		return NULL;
2154189251Ssam	}
2155189251Ssam
2156214734Srpaulo	/* Notify the control interfaces about new iface */
2157214734Srpaulo	if (wpas_notify_iface_added(wpa_s)) {
2158214734Srpaulo		wpa_supplicant_deinit_iface(wpa_s, 1);
2159189251Ssam		os_free(wpa_s);
2160189251Ssam		return NULL;
2161189251Ssam	}
2162209158Srpaulo
2163214734Srpaulo	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
2164214734Srpaulo		wpas_notify_network_added(wpa_s, ssid);
2165214734Srpaulo
2166189251Ssam	wpa_s->next = global->ifaces;
2167189251Ssam	global->ifaces = wpa_s;
2168189251Ssam
2169189251Ssam	wpa_printf(MSG_DEBUG, "Added interface %s", wpa_s->ifname);
2170189251Ssam
2171189251Ssam	return wpa_s;
2172189251Ssam}
2173189251Ssam
2174189251Ssam
2175189251Ssam/**
2176189251Ssam * wpa_supplicant_remove_iface - Remove a network interface
2177189251Ssam * @global: Pointer to global data from wpa_supplicant_init()
2178189251Ssam * @wpa_s: Pointer to the network interface to be removed
2179189251Ssam * Returns: 0 if interface was removed, -1 if interface was not found
2180189251Ssam *
2181189251Ssam * This function can be used to dynamically remove network interfaces from
2182189251Ssam * %wpa_supplicant, e.g., when a hotplug network adapter is ejected. In
2183189251Ssam * addition, this function is used to remove all remaining interfaces when
2184189251Ssam * %wpa_supplicant is terminated.
2185189251Ssam */
2186189251Ssamint wpa_supplicant_remove_iface(struct wpa_global *global,
2187189251Ssam				struct wpa_supplicant *wpa_s)
2188189251Ssam{
2189189251Ssam	struct wpa_supplicant *prev;
2190189251Ssam
2191189251Ssam	/* Remove interface from the global list of interfaces */
2192189251Ssam	prev = global->ifaces;
2193189251Ssam	if (prev == wpa_s) {
2194189251Ssam		global->ifaces = wpa_s->next;
2195189251Ssam	} else {
2196189251Ssam		while (prev && prev->next != wpa_s)
2197189251Ssam			prev = prev->next;
2198189251Ssam		if (prev == NULL)
2199189251Ssam			return -1;
2200189251Ssam		prev->next = wpa_s->next;
2201189251Ssam	}
2202189251Ssam
2203189251Ssam	wpa_printf(MSG_DEBUG, "Removing interface %s", wpa_s->ifname);
2204189251Ssam
2205214734Srpaulo	wpa_supplicant_deinit_iface(wpa_s, 1);
2206189251Ssam	os_free(wpa_s);
2207189251Ssam
2208189251Ssam	return 0;
2209189251Ssam}
2210189251Ssam
2211189251Ssam
2212189251Ssam/**
2213189251Ssam * wpa_supplicant_get_iface - Get a new network interface
2214189251Ssam * @global: Pointer to global data from wpa_supplicant_init()
2215189251Ssam * @ifname: Interface name
2216189251Ssam * Returns: Pointer to the interface or %NULL if not found
2217189251Ssam */
2218189251Ssamstruct wpa_supplicant * wpa_supplicant_get_iface(struct wpa_global *global,
2219189251Ssam						 const char *ifname)
2220189251Ssam{
2221189251Ssam	struct wpa_supplicant *wpa_s;
2222189251Ssam
2223189251Ssam	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
2224189251Ssam		if (os_strcmp(wpa_s->ifname, ifname) == 0)
2225189251Ssam			return wpa_s;
2226189251Ssam	}
2227189251Ssam	return NULL;
2228189251Ssam}
2229189251Ssam
2230189251Ssam
2231189251Ssam/**
2232189251Ssam * wpa_supplicant_init - Initialize %wpa_supplicant
2233189251Ssam * @params: Parameters for %wpa_supplicant
2234189251Ssam * Returns: Pointer to global %wpa_supplicant data, or %NULL on failure
2235189251Ssam *
2236189251Ssam * This function is used to initialize %wpa_supplicant. After successful
2237189251Ssam * initialization, the returned data pointer can be used to add and remove
2238189251Ssam * network interfaces, and eventually, to deinitialize %wpa_supplicant.
2239189251Ssam */
2240189251Ssamstruct wpa_global * wpa_supplicant_init(struct wpa_params *params)
2241189251Ssam{
2242189251Ssam	struct wpa_global *global;
2243189251Ssam	int ret, i;
2244189251Ssam
2245189251Ssam	if (params == NULL)
2246189251Ssam		return NULL;
2247189251Ssam
2248189251Ssam	wpa_debug_open_file(params->wpa_debug_file_path);
2249189262Ssam	if (params->wpa_debug_syslog)
2250189262Ssam		wpa_debug_open_syslog();
2251189251Ssam
2252214734Srpaulo	ret = eap_register_methods();
2253189251Ssam	if (ret) {
2254189251Ssam		wpa_printf(MSG_ERROR, "Failed to register EAP methods");
2255189251Ssam		if (ret == -2)
2256189251Ssam			wpa_printf(MSG_ERROR, "Two or more EAP methods used "
2257189251Ssam				   "the same EAP type.");
2258189251Ssam		return NULL;
2259189251Ssam	}
2260189251Ssam
2261189251Ssam	global = os_zalloc(sizeof(*global));
2262189251Ssam	if (global == NULL)
2263189251Ssam		return NULL;
2264189251Ssam	global->params.daemonize = params->daemonize;
2265189251Ssam	global->params.wait_for_monitor = params->wait_for_monitor;
2266189251Ssam	global->params.dbus_ctrl_interface = params->dbus_ctrl_interface;
2267189251Ssam	if (params->pid_file)
2268189251Ssam		global->params.pid_file = os_strdup(params->pid_file);
2269189251Ssam	if (params->ctrl_interface)
2270189251Ssam		global->params.ctrl_interface =
2271189251Ssam			os_strdup(params->ctrl_interface);
2272214734Srpaulo	if (params->override_driver)
2273214734Srpaulo		global->params.override_driver =
2274214734Srpaulo			os_strdup(params->override_driver);
2275214734Srpaulo	if (params->override_ctrl_interface)
2276214734Srpaulo		global->params.override_ctrl_interface =
2277214734Srpaulo			os_strdup(params->override_ctrl_interface);
2278189251Ssam	wpa_debug_level = global->params.wpa_debug_level =
2279189251Ssam		params->wpa_debug_level;
2280189251Ssam	wpa_debug_show_keys = global->params.wpa_debug_show_keys =
2281189251Ssam		params->wpa_debug_show_keys;
2282189251Ssam	wpa_debug_timestamp = global->params.wpa_debug_timestamp =
2283189251Ssam		params->wpa_debug_timestamp;
2284189251Ssam
2285214734Srpaulo	if (eloop_init()) {
2286189251Ssam		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
2287189251Ssam		wpa_supplicant_deinit(global);
2288189251Ssam		return NULL;
2289189251Ssam	}
2290189251Ssam
2291189251Ssam	global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global);
2292189251Ssam	if (global->ctrl_iface == NULL) {
2293189251Ssam		wpa_supplicant_deinit(global);
2294189251Ssam		return NULL;
2295189251Ssam	}
2296189251Ssam
2297214734Srpaulo	if (wpas_notify_supplicant_initialized(global)) {
2298214734Srpaulo		wpa_supplicant_deinit(global);
2299214734Srpaulo		return NULL;
2300189251Ssam	}
2301189251Ssam
2302214734Srpaulo	for (i = 0; wpa_drivers[i]; i++)
2303189251Ssam		global->drv_count++;
2304189251Ssam	if (global->drv_count == 0) {
2305189251Ssam		wpa_printf(MSG_ERROR, "No drivers enabled");
2306189251Ssam		wpa_supplicant_deinit(global);
2307189251Ssam		return NULL;
2308189251Ssam	}
2309189251Ssam	global->drv_priv = os_zalloc(global->drv_count * sizeof(void *));
2310189251Ssam	if (global->drv_priv == NULL) {
2311189251Ssam		wpa_supplicant_deinit(global);
2312189251Ssam		return NULL;
2313189251Ssam	}
2314214734Srpaulo	for (i = 0; wpa_drivers[i]; i++) {
2315214734Srpaulo		if (!wpa_drivers[i]->global_init)
2316189251Ssam			continue;
2317214734Srpaulo		global->drv_priv[i] = wpa_drivers[i]->global_init();
2318189251Ssam		if (global->drv_priv[i] == NULL) {
2319189251Ssam			wpa_printf(MSG_ERROR, "Failed to initialize driver "
2320214734Srpaulo				   "'%s'", wpa_drivers[i]->name);
2321189251Ssam			wpa_supplicant_deinit(global);
2322189251Ssam			return NULL;
2323189251Ssam		}
2324189251Ssam	}
2325189251Ssam
2326189251Ssam	return global;
2327189251Ssam}
2328189251Ssam
2329189251Ssam
2330189251Ssam/**
2331189251Ssam * wpa_supplicant_run - Run the %wpa_supplicant main event loop
2332189251Ssam * @global: Pointer to global data from wpa_supplicant_init()
2333189251Ssam * Returns: 0 after successful event loop run, -1 on failure
2334189251Ssam *
2335189251Ssam * This function starts the main event loop and continues running as long as
2336189251Ssam * there are any remaining events. In most cases, this function is running as
2337189251Ssam * long as the %wpa_supplicant process in still in use.
2338189251Ssam */
2339189251Ssamint wpa_supplicant_run(struct wpa_global *global)
2340189251Ssam{
2341189251Ssam	struct wpa_supplicant *wpa_s;
2342189251Ssam
2343189251Ssam	if (global->params.daemonize &&
2344189251Ssam	    wpa_supplicant_daemon(global->params.pid_file))
2345189251Ssam		return -1;
2346189251Ssam
2347189251Ssam	if (global->params.wait_for_monitor) {
2348189251Ssam		for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
2349189251Ssam			if (wpa_s->ctrl_iface)
2350189251Ssam				wpa_supplicant_ctrl_iface_wait(
2351189251Ssam					wpa_s->ctrl_iface);
2352189251Ssam	}
2353189251Ssam
2354214734Srpaulo	eloop_register_signal_terminate(wpa_supplicant_terminate, global);
2355214734Srpaulo	eloop_register_signal_reconfig(wpa_supplicant_reconfig, global);
2356189251Ssam
2357189251Ssam	eloop_run();
2358189251Ssam
2359189251Ssam	return 0;
2360189251Ssam}
2361189251Ssam
2362189251Ssam
2363189251Ssam/**
2364189251Ssam * wpa_supplicant_deinit - Deinitialize %wpa_supplicant
2365189251Ssam * @global: Pointer to global data from wpa_supplicant_init()
2366189251Ssam *
2367189251Ssam * This function is called to deinitialize %wpa_supplicant and to free all
2368189251Ssam * allocated resources. Remaining network interfaces will also be removed.
2369189251Ssam */
2370189251Ssamvoid wpa_supplicant_deinit(struct wpa_global *global)
2371189251Ssam{
2372189251Ssam	int i;
2373189251Ssam
2374189251Ssam	if (global == NULL)
2375189251Ssam		return;
2376189251Ssam
2377189251Ssam	while (global->ifaces)
2378189251Ssam		wpa_supplicant_remove_iface(global, global->ifaces);
2379189251Ssam
2380189251Ssam	if (global->ctrl_iface)
2381189251Ssam		wpa_supplicant_global_ctrl_iface_deinit(global->ctrl_iface);
2382189251Ssam
2383214734Srpaulo	wpas_notify_supplicant_deinitialized(global);
2384214734Srpaulo
2385189251Ssam	eap_peer_unregister_methods();
2386214734Srpaulo#ifdef CONFIG_AP
2387214734Srpaulo	eap_server_unregister_methods();
2388214734Srpaulo#endif /* CONFIG_AP */
2389189251Ssam
2390214734Srpaulo	for (i = 0; wpa_drivers[i] && global->drv_priv; i++) {
2391189251Ssam		if (!global->drv_priv[i])
2392189251Ssam			continue;
2393214734Srpaulo		wpa_drivers[i]->global_deinit(global->drv_priv[i]);
2394189251Ssam	}
2395189251Ssam	os_free(global->drv_priv);
2396189251Ssam
2397189251Ssam	eloop_destroy();
2398189251Ssam
2399189251Ssam	if (global->params.pid_file) {
2400189251Ssam		os_daemonize_terminate(global->params.pid_file);
2401189251Ssam		os_free(global->params.pid_file);
2402189251Ssam	}
2403189251Ssam	os_free(global->params.ctrl_interface);
2404214734Srpaulo	os_free(global->params.override_driver);
2405214734Srpaulo	os_free(global->params.override_ctrl_interface);
2406189251Ssam
2407189251Ssam	os_free(global);
2408189262Ssam	wpa_debug_close_syslog();
2409189251Ssam	wpa_debug_close_file();
2410189251Ssam}
2411