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(¶ms, 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, ¶ms); 1230189251Ssam else 1231189251Ssam ret = wpa_drv_associate(wpa_s, ¶ms); 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