index 5563f0bc406b8ae5951d256f3e47138a8ec98c7a..39b2147afbcaffea4071e5d5f376fafcfa626af9 100644 (file)
/*
* WPA Supplicant
- * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#include "includes.h"
#include "common.h"
+#include "crypto/random.h"
+#include "crypto/sha1.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "eap_peer/eap.h"
#include "eap_server/eap_methods.h"
#include "rsn_supp/preauth.h"
#include "rsn_supp/pmksa_cache.h"
#include "common/wpa_ctrl.h"
-#include "mlme.h"
#include "common/ieee802_11_defs.h"
+#include "p2p/p2p.h"
#include "blacklist.h"
#include "wpas_glue.h"
#include "wps_supplicant.h"
#include "ibss_rsn.h"
#include "sme.h"
+#include "gas_query.h"
#include "ap.h"
+#include "p2p_supplicant.h"
#include "notify.h"
#include "bgscan.h"
#include "bss.h"
#include "scan.h"
+#include "offchannel.h"
const char *wpa_supplicant_version =
"wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> and contributors";
const char *wpa_supplicant_license =
-"This program is free software. You can distribute it and/or modify it\n"
-"under the terms of the GNU General Public License version 2.\n"
-"\n"
-"Alternatively, this software may be distributed under the terms of the\n"
-"BSD license. See README and COPYING for more details.\n"
+"This software may be distributed under the terms of the BSD license.\n"
+"See README for more details.\n"
#ifdef EAP_TLS_OPENSSL
"\nThis product includes software developed by the OpenSSL Project\n"
"for use in the OpenSSL Toolkit (http://www.openssl.org/)\n"
#ifndef CONFIG_NO_STDOUT_DEBUG
/* Long text divided into parts in order to fit in C89 strings size limits. */
const char *wpa_supplicant_full_license1 =
-"This program is free software; you can redistribute it and/or modify\n"
-"it under the terms of the GNU General Public License version 2 as\n"
-"published by the Free Software Foundation.\n"
-"\n"
-"This program is distributed in the hope that it will be useful,\n"
-"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
-"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
-"GNU General Public License for more details.\n"
-"\n";
+"";
const char *wpa_supplicant_full_license2 =
-"You should have received a copy of the GNU General Public License\n"
-"along with this program; if not, write to the Free Software\n"
-"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n"
-"\n"
-"Alternatively, this software may be distributed under the terms of the\n"
-"BSD license.\n"
+"This software may be distributed under the terms of the BSD license.\n"
"\n"
"Redistribution and use in source and binary forms, with or without\n"
"modification, are permitted provided that the following conditions are\n"
continue;
set = 1;
- wpa_drv_set_key(wpa_s, WPA_ALG_WEP,
- (u8 *) "\xff\xff\xff\xff\xff\xff",
- i, i == ssid->wep_tx_keyidx, (u8 *) "", 0,
+ wpa_drv_set_key(wpa_s, WPA_ALG_WEP, NULL,
+ i, i == ssid->wep_tx_keyidx, NULL, 0,
ssid->wep_key[i], ssid->wep_key_len[i]);
}
* sending unicast and multicast packets. */
if (ssid->mode != WPAS_MODE_IBSS) {
- wpa_printf(MSG_INFO, "WPA: Invalid mode %d (not IBSS/ad-hoc) "
- "for WPA-None", ssid->mode);
+ wpa_msg(wpa_s, MSG_INFO, "WPA: Invalid mode %d (not "
+ "IBSS/ad-hoc) for WPA-None", ssid->mode);
return -1;
}
if (!ssid->psk_set) {
- wpa_printf(MSG_INFO, "WPA: No PSK configured for WPA-None");
+ wpa_msg(wpa_s, MSG_INFO, "WPA: No PSK configured for "
+ "WPA-None");
return -1;
}
alg = WPA_ALG_TKIP;
break;
default:
- wpa_printf(MSG_INFO, "WPA: Invalid group cipher %d for "
- "WPA-None", wpa_s->group_cipher);
+ wpa_msg(wpa_s, MSG_INFO, "WPA: Invalid group cipher %d for "
+ "WPA-None", wpa_s->group_cipher);
return -1;
}
/* TODO: should actually remember the previously used seq#, both for TX
* and RX from each STA.. */
- return wpa_drv_set_key(wpa_s, alg, (u8 *) "\xff\xff\xff\xff\xff\xff",
- 0, 1, seq, 6, key, keylen);
+ return wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen);
}
wpa_sm_notify_disassoc(wpa_s->wpa);
wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
wpa_s->reassociate = 1;
- wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+ /*
+ * If we timed out, the AP or the local radio may be busy.
+ * So, wait a second until scanning again.
+ */
+ wpa_supplicant_req_scan(wpa_s, 1, 0);
}
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED))
return;
- wpa_msg(wpa_s, MSG_DEBUG, "Setting authentication timeout: %d sec "
+ wpa_dbg(wpa_s, MSG_DEBUG, "Setting authentication timeout: %d sec "
"%d usec", sec, usec);
eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
eloop_register_timeout(sec, usec, wpa_supplicant_timeout, wpa_s, NULL);
*/
void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s)
{
- wpa_msg(wpa_s, MSG_DEBUG, "Cancelling authentication timeout");
+ wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling authentication timeout");
eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
wpa_blacklist_del(wpa_s, wpa_s->bssid);
}
}
+static void free_hw_features(struct wpa_supplicant *wpa_s)
+{
+ int i;
+ if (wpa_s->hw.modes == NULL)
+ return;
+
+ for (i = 0; i < wpa_s->hw.num_modes; i++) {
+ os_free(wpa_s->hw.modes[i].channels);
+ os_free(wpa_s->hw.modes[i].rates);
+ }
+
+ os_free(wpa_s->hw.modes);
+ wpa_s->hw.modes = NULL;
+}
+
+
static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
{
bgscan_deinit(wpa_s);
wpa_s->l2_br = NULL;
}
- if (wpa_s->ctrl_iface) {
- wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
- wpa_s->ctrl_iface = NULL;
- }
if (wpa_s->conf != NULL) {
struct wpa_ssid *ssid;
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
wpas_notify_network_removed(wpa_s, ssid);
- wpa_config_free(wpa_s->conf);
- wpa_s->conf = NULL;
}
os_free(wpa_s->confname);
rsn_preauth_deinit(wpa_s->wpa);
+#ifdef CONFIG_TDLS
+ wpa_tdls_deinit(wpa_s->wpa);
+#endif /* CONFIG_TDLS */
+
pmksa_candidate_free(wpa_s->wpa);
wpa_sm_deinit(wpa_s->wpa);
wpa_s->wpa = NULL;
wpa_supplicant_cancel_scan(wpa_s);
wpa_supplicant_cancel_auth_timeout(wpa_s);
-
- ieee80211_sta_deinit(wpa_s);
+ eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL);
+#ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
+ eloop_cancel_timeout(wpa_supplicant_delayed_mic_error_report,
+ wpa_s, NULL);
+#endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
wpas_wps_deinit(wpa_s);
wpa_s->ibss_rsn = NULL;
#endif /* CONFIG_IBSS_RSN */
-#ifdef CONFIG_SME
- os_free(wpa_s->sme.ft_ies);
- wpa_s->sme.ft_ies = NULL;
- wpa_s->sme.ft_ies_len = 0;
-#endif /* CONFIG_SME */
+ sme_deinit(wpa_s);
#ifdef CONFIG_AP
wpa_supplicant_ap_deinit(wpa_s);
#endif /* CONFIG_AP */
+
+#ifdef CONFIG_P2P
+ wpas_p2p_deinit(wpa_s);
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_OFFCHANNEL
+ offchannel_deinit(wpa_s);
+#endif /* CONFIG_OFFCHANNEL */
+
+ wpa_supplicant_cancel_sched_scan(wpa_s);
+
+ os_free(wpa_s->next_scan_freqs);
+ wpa_s->next_scan_freqs = NULL;
+
+ gas_query_deinit(wpa_s->gas);
+ wpa_s->gas = NULL;
+
+ free_hw_features(wpa_s);
}
*/
void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
{
- u8 *bcast = (u8 *) "\xff\xff\xff\xff\xff\xff";
-
if (wpa_s->keys_cleared) {
/* Some drivers (e.g., ndiswrapper & NDIS drivers) seem to have
* timing issues with keys being cleared just before new keys
* client not receiving the first encrypted packets correctly.
* Skipping some of the extra key clearing steps seems to help
* in completing group key handshake more reliably. */
- wpa_printf(MSG_DEBUG, "No keys have been configured - "
- "skip key clearing");
+ wpa_dbg(wpa_s, MSG_DEBUG, "No keys have been configured - "
+ "skip key clearing");
return;
}
/* MLME-DELETEKEYS.request */
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 0, 0, NULL, 0, NULL, 0);
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 1, 0, NULL, 0, NULL, 0);
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 2, 0, NULL, 0, NULL, 0);
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 3, 0, NULL, 0, NULL, 0);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
#ifdef CONFIG_IEEE80211W
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 4, 0, NULL, 0, NULL, 0);
- wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 5, 0, NULL, 0, NULL, 0);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
#endif /* CONFIG_IEEE80211W */
if (addr) {
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL,
return "DISCONNECTED";
case WPA_INACTIVE:
return "INACTIVE";
+ case WPA_INTERFACE_DISABLED:
+ return "INTERFACE_DISABLED";
case WPA_SCANNING:
return "SCANNING";
case WPA_AUTHENTICATING:
}
+#ifdef CONFIG_BGSCAN
+
+static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
+{
+ if (wpas_driver_bss_selection(wpa_s))
+ return;
+ if (wpa_s->current_ssid == wpa_s->bgscan_ssid)
+ return;
+
+ bgscan_deinit(wpa_s);
+ if (wpa_s->current_ssid && wpa_s->current_ssid->bgscan) {
+ if (bgscan_init(wpa_s, wpa_s->current_ssid)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
+ "bgscan");
+ /*
+ * Live without bgscan; it is only used as a roaming
+ * optimization, so the initial connection is not
+ * affected.
+ */
+ } else
+ wpa_s->bgscan_ssid = wpa_s->current_ssid;
+ } else
+ wpa_s->bgscan_ssid = NULL;
+}
+
+
+static void wpa_supplicant_stop_bgscan(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->bgscan_ssid != NULL) {
+ bgscan_deinit(wpa_s);
+ wpa_s->bgscan_ssid = NULL;
+ }
+}
+
+#endif /* CONFIG_BGSCAN */
+
+
/**
* wpa_supplicant_set_state - Set current connection state
* @wpa_s: Pointer to wpa_supplicant data
{
enum wpa_states old_state = wpa_s->wpa_state;
- wpa_printf(MSG_DEBUG, "State: %s -> %s",
- wpa_supplicant_state_txt(wpa_s->wpa_state),
- wpa_supplicant_state_txt(state));
+ wpa_dbg(wpa_s, MSG_DEBUG, "State: %s -> %s",
+ wpa_supplicant_state_txt(wpa_s->wpa_state),
+ wpa_supplicant_state_txt(state));
if (state != WPA_SCANNING)
wpa_supplicant_notify_scanning(wpa_s, 0);
wpa_s->new_connection = 0;
wpa_s->reassociated_connection = 1;
wpa_drv_set_operstate(wpa_s, 1);
+#ifndef IEEE8021X_EAPOL
+ wpa_drv_set_supp_port(wpa_s, 1);
+#endif /* IEEE8021X_EAPOL */
wpa_s->after_wps = 0;
+#ifdef CONFIG_P2P
+ wpas_p2p_completed(wpa_s);
+#endif /* CONFIG_P2P */
} else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
state == WPA_ASSOCIATED) {
wpa_s->new_connection = 1;
wpa_drv_set_operstate(wpa_s, 0);
+#ifndef IEEE8021X_EAPOL
+ wpa_drv_set_supp_port(wpa_s, 0);
+#endif /* IEEE8021X_EAPOL */
}
wpa_s->wpa_state = state;
- if (wpa_s->wpa_state != old_state)
+#ifdef CONFIG_BGSCAN
+ if (state == WPA_COMPLETED)
+ wpa_supplicant_start_bgscan(wpa_s);
+ else
+ wpa_supplicant_stop_bgscan(wpa_s);
+#endif /* CONFIG_BGSCAN */
+
+ if (wpa_s->wpa_state != old_state) {
wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
+
+ if (wpa_s->wpa_state == WPA_COMPLETED ||
+ old_state == WPA_COMPLETED)
+ wpas_notify_auth_changed(wpa_s);
+ }
}
static void wpa_supplicant_terminate(int sig, void *signal_ctx)
{
struct wpa_global *global = signal_ctx;
- struct wpa_supplicant *wpa_s;
- for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
- wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TERMINATING "- signal %d "
- "received", sig);
- }
wpa_supplicant_terminate_proc(global);
}
-static void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
+void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
{
enum wpa_states old_state = wpa_s->wpa_state;
wpa_s->group_cipher = 0;
wpa_s->mgmt_group_cipher = 0;
wpa_s->key_mgmt = 0;
- wpa_s->wpa_state = WPA_DISCONNECTED;
+ if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED)
+ wpa_s->wpa_state = WPA_DISCONNECTED;
if (wpa_s->wpa_state != old_state)
wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
{
struct wpa_config *conf;
- struct wpa_ssid *old_ssid;
int reconf_ctrl;
int old_ap_scan;
"file '%s' - exiting", wpa_s->confname);
return -1;
}
+ conf->changed_parameters = (unsigned int) -1;
reconf_ctrl = !!conf->ctrl_interface != !!wpa_s->conf->ctrl_interface
|| (conf->ctrl_interface && wpa_s->conf->ctrl_interface &&
}
eapol_sm_invalidate_cached_session(wpa_s->eapol);
- old_ssid = wpa_s->current_ssid;
- wpa_s->current_ssid = NULL;
- if (old_ssid != wpa_s->current_ssid)
- wpas_notify_network_changed(wpa_s);
+ if (wpa_s->current_ssid) {
+ wpa_supplicant_deauthenticate(wpa_s,
+ WLAN_REASON_DEAUTH_LEAVING);
+ }
/*
* TODO: should notify EAPOL SM about changes in opensc_engine_path,
}
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
wpa_sm_set_config(wpa_s->wpa, NULL);
+ wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
rsn_preauth_deinit(wpa_s->wpa);
if (reconf_ctrl)
wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
+ wpa_supplicant_update_config(wpa_s);
+
wpa_supplicant_clear_status(wpa_s);
- wpa_s->reassociate = 1;
- wpa_supplicant_req_scan(wpa_s, 0, 0);
- wpa_msg(wpa_s, MSG_DEBUG, "Reconfiguration completed");
+ if (wpa_supplicant_enabled_networks(wpa_s->conf)) {
+ wpa_s->reassociate = 1;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ }
+ wpa_dbg(wpa_s, MSG_DEBUG, "Reconfiguration completed");
return 0;
}
{
struct wpa_global *global = signal_ctx;
struct wpa_supplicant *wpa_s;
- wpa_printf(MSG_DEBUG, "Signal %d received - reconfiguring", sig);
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Signal %d received - reconfiguring",
+ sig);
if (wpa_supplicant_reload_configuration(wpa_s) < 0) {
wpa_supplicant_terminate_proc(global);
}
return -1;
}
- wpa_printf(MSG_DEBUG, "WPA: Using WPA IE from AssocReq to set cipher "
- "suites");
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Using WPA IE from AssocReq to set "
+ "cipher suites");
if (!(ie->group_cipher & ssid->group_cipher)) {
wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled group "
"cipher 0x%x (mask 0x%x) - reject",
(ie.group_cipher & ssid->group_cipher) &&
(ie.pairwise_cipher & ssid->pairwise_cipher) &&
(ie.key_mgmt & ssid->key_mgmt)) {
- wpa_msg(wpa_s, MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0");
+ wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0");
proto = WPA_PROTO_RSN;
} else if (bss_wpa && (ssid->proto & WPA_PROTO_WPA) &&
wpa_parse_wpa_ie(bss_wpa, 2 +bss_wpa[1], &ie) == 0 &&
(ie.group_cipher & ssid->group_cipher) &&
(ie.pairwise_cipher & ssid->pairwise_cipher) &&
(ie.key_mgmt & ssid->key_mgmt)) {
- wpa_msg(wpa_s, MSG_DEBUG, "WPA: using IEEE 802.11i/D3.0");
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using IEEE 802.11i/D3.0");
proto = WPA_PROTO_WPA;
} else if (bss) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select WPA/RSN");
ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION ?
WPA_CIPHER_AES_128_CMAC : 0;
#endif /* CONFIG_IEEE80211W */
- wpa_printf(MSG_DEBUG, "WPA: Set cipher suites based "
- "on configuration");
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Set cipher suites "
+ "based on configuration");
} else
proto = ie.proto;
}
- wpa_printf(MSG_DEBUG, "WPA: Selected cipher suites: group %d "
- "pairwise %d key_mgmt %d proto %d",
- ie.group_cipher, ie.pairwise_cipher, ie.key_mgmt, proto);
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected cipher suites: group %d "
+ "pairwise %d key_mgmt %d proto %d",
+ ie.group_cipher, ie.pairwise_cipher, ie.key_mgmt, proto);
#ifdef CONFIG_IEEE80211W
if (ssid->ieee80211w) {
- wpa_printf(MSG_DEBUG, "WPA: Selected mgmt group cipher %d",
- ie.mgmt_group_cipher);
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected mgmt group cipher %d",
+ ie.mgmt_group_cipher);
}
#endif /* CONFIG_IEEE80211W */
+ wpa_s->wpa_proto = proto;
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED,
!!(ssid->proto & WPA_PROTO_RSN));
sel = ie.group_cipher & ssid->group_cipher;
if (sel & WPA_CIPHER_CCMP) {
wpa_s->group_cipher = WPA_CIPHER_CCMP;
- wpa_msg(wpa_s, MSG_DEBUG, "WPA: using GTK CCMP");
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK CCMP");
} else if (sel & WPA_CIPHER_TKIP) {
wpa_s->group_cipher = WPA_CIPHER_TKIP;
- wpa_msg(wpa_s, MSG_DEBUG, "WPA: using GTK TKIP");
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK TKIP");
} else if (sel & WPA_CIPHER_WEP104) {
wpa_s->group_cipher = WPA_CIPHER_WEP104;
- wpa_msg(wpa_s, MSG_DEBUG, "WPA: using GTK WEP104");
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK WEP104");
} else if (sel & WPA_CIPHER_WEP40) {
wpa_s->group_cipher = WPA_CIPHER_WEP40;
- wpa_msg(wpa_s, MSG_DEBUG, "WPA: using GTK WEP40");
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK WEP40");
} else {
- wpa_printf(MSG_WARNING, "WPA: Failed to select group cipher.");
+ wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select group "
+ "cipher");
return -1;
}
sel = ie.pairwise_cipher & ssid->pairwise_cipher;
if (sel & WPA_CIPHER_CCMP) {
wpa_s->pairwise_cipher = WPA_CIPHER_CCMP;
- wpa_msg(wpa_s, MSG_DEBUG, "WPA: using PTK CCMP");
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK CCMP");
} else if (sel & WPA_CIPHER_TKIP) {
wpa_s->pairwise_cipher = WPA_CIPHER_TKIP;
- wpa_msg(wpa_s, MSG_DEBUG, "WPA: using PTK TKIP");
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK TKIP");
} else if (sel & WPA_CIPHER_NONE) {
wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
- wpa_msg(wpa_s, MSG_DEBUG, "WPA: using PTK NONE");
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK NONE");
} else {
- wpa_printf(MSG_WARNING, "WPA: Failed to select pairwise "
- "cipher.");
+ wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select pairwise "
+ "cipher");
return -1;
}
#ifdef CONFIG_IEEE80211R
} else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
- wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/802.1X");
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/802.1X");
} else if (sel & WPA_KEY_MGMT_FT_PSK) {
wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
- wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
} else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) {
wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
- wpa_msg(wpa_s, MSG_DEBUG,
+ wpa_dbg(wpa_s, MSG_DEBUG,
"WPA: using KEY_MGMT 802.1X with SHA256");
} else if (sel & WPA_KEY_MGMT_PSK_SHA256) {
wpa_s->key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
- wpa_msg(wpa_s, MSG_DEBUG,
+ wpa_dbg(wpa_s, MSG_DEBUG,
"WPA: using KEY_MGMT PSK with SHA256");
#endif /* CONFIG_IEEE80211W */
} else if (sel & WPA_KEY_MGMT_IEEE8021X) {
wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
- wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X");
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X");
} else if (sel & WPA_KEY_MGMT_PSK) {
wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
- wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-PSK");
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-PSK");
} else if (sel & WPA_KEY_MGMT_WPA_NONE) {
wpa_s->key_mgmt = WPA_KEY_MGMT_WPA_NONE;
- wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-NONE");
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-NONE");
} else {
- wpa_printf(MSG_WARNING, "WPA: Failed to select authenticated "
- "key management type.");
+ wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select "
+ "authenticated key management type");
return -1;
}
sel = 0;
if (sel & WPA_CIPHER_AES_128_CMAC) {
wpa_s->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
- wpa_msg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
"AES-128-CMAC");
} else {
wpa_s->mgmt_group_cipher = 0;
- wpa_msg(wpa_s, MSG_DEBUG, "WPA: not using MGMT group cipher");
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: not using MGMT group cipher");
}
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
wpa_s->mgmt_group_cipher);
#endif /* CONFIG_IEEE80211W */
if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
- wpa_printf(MSG_WARNING, "WPA: Failed to generate WPA IE.");
+ wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to generate WPA IE");
return -1;
}
- if (ssid->key_mgmt &
- (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK | WPA_KEY_MGMT_PSK_SHA256))
+ if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN);
- else
+#ifndef CONFIG_NO_PBKDF2
+ if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
+ ssid->passphrase) {
+ u8 psk[PMK_LEN];
+ pbkdf2_sha1(ssid->passphrase, (char *) bss->ssid,
+ bss->ssid_len, 4096, psk, PMK_LEN);
+ wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
+ psk, PMK_LEN);
+ wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
+ }
+#endif /* CONFIG_NO_PBKDF2 */
+ } else
wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
return 0;
void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, struct wpa_ssid *ssid)
{
- u8 wpa_ie[80];
+ u8 wpa_ie[200];
size_t wpa_ie_len;
int use_crypt, ret, i, bssid_changed;
int algs = WPA_AUTH_ALG_OPEN;
struct wpa_driver_capa capa;
int assoc_failed = 0;
struct wpa_ssid *old_ssid;
+#ifdef CONFIG_HT_OVERRIDES
+ struct ieee80211_ht_capabilities htcaps;
+ struct ieee80211_ht_capabilities htcaps_mask;
+#endif /* CONFIG_HT_OVERRIDES */
- if (ssid->mode == WPAS_MODE_AP) {
+#ifdef CONFIG_IBSS_RSN
+ ibss_rsn_deinit(wpa_s->ibss_rsn);
+ wpa_s->ibss_rsn = NULL;
+#endif /* CONFIG_IBSS_RSN */
+
+ if (ssid->mode == WPAS_MODE_AP || ssid->mode == WPAS_MODE_P2P_GO ||
+ ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) {
#ifdef CONFIG_AP
if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP)) {
- wpa_printf(MSG_INFO, "Driver does not support AP "
- "mode");
+ wpa_msg(wpa_s, MSG_INFO, "Driver does not support AP "
+ "mode");
return;
}
wpa_supplicant_create_ap(wpa_s, ssid);
wpa_s->current_bss = bss;
#else /* CONFIG_AP */
- wpa_printf(MSG_ERROR, "AP mode support not included in the "
- "build");
+ wpa_msg(wpa_s, MSG_ERROR, "AP mode support not included in "
+ "the build");
#endif /* CONFIG_AP */
return;
}
+#ifdef CONFIG_TDLS
+ if (bss)
+ wpa_tdls_ap_ies(wpa_s->wpa, (const u8 *) (bss + 1),
+ bss->ie_len);
+#endif /* CONFIG_TDLS */
+
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
ssid->mode == IEEE80211_MODE_INFRA) {
sme_authenticate(wpa_s, bss, ssid);
return;
}
+ os_memset(¶ms, 0, sizeof(params));
wpa_s->reassociate = 0;
- if (bss) {
+ if (bss && !wpas_driver_bss_selection(wpa_s)) {
#ifdef CONFIG_IEEE80211R
const u8 *ie, *md = NULL;
#endif /* CONFIG_IEEE80211R */
wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
}
+ wpa_supplicant_cancel_sched_scan(wpa_s);
wpa_supplicant_cancel_scan(wpa_s);
/* Starting new association, so clear the possibly used WPA IE from the
}
}
#endif /* IEEE8021X_EAPOL */
- wpa_printf(MSG_DEBUG, "Automatic auth_alg selection: 0x%x", algs);
+ wpa_dbg(wpa_s, MSG_DEBUG, "Automatic auth_alg selection: 0x%x", algs);
if (ssid->auth_alg) {
algs = ssid->auth_alg;
- wpa_printf(MSG_DEBUG, "Overriding auth_alg selection: 0x%x",
- algs);
+ wpa_dbg(wpa_s, MSG_DEBUG, "Overriding auth_alg selection: "
+ "0x%x", algs);
}
if (bss && (wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
- (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK |
- WPA_KEY_MGMT_FT_IEEE8021X |
- WPA_KEY_MGMT_FT_PSK |
- WPA_KEY_MGMT_IEEE8021X_SHA256 |
- WPA_KEY_MGMT_PSK_SHA256))) {
+ wpa_key_mgmt_wpa(ssid->key_mgmt)) {
int try_opportunistic;
try_opportunistic = ssid->proactive_key_caching &&
(ssid->proto & WPA_PROTO_RSN);
wpa_ie_len = sizeof(wpa_ie);
if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
wpa_ie, &wpa_ie_len)) {
- wpa_printf(MSG_WARNING, "WPA: Failed to set WPA key "
- "management and encryption suites");
+ wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
+ "key management and encryption suites");
return;
}
- } else if (ssid->key_mgmt &
- (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
- WPA_KEY_MGMT_WPA_NONE | WPA_KEY_MGMT_FT_PSK |
- WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_PSK_SHA256 |
- WPA_KEY_MGMT_IEEE8021X_SHA256)) {
+ } else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
wpa_ie_len = sizeof(wpa_ie);
if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
wpa_ie, &wpa_ie_len)) {
- wpa_printf(MSG_WARNING, "WPA: Failed to set WPA key "
- "management and encryption suites (no scan "
- "results)");
+ wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
+ "key management and encryption suites (no "
+ "scan results)");
return;
}
#ifdef CONFIG_WPS
wpa_ie_len = 0;
wpabuf_free(wps_ie);
wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+ if (!bss || (bss->caps & IEEE80211_CAP_PRIVACY))
+ params.wps = WPS_MODE_PRIVACY;
+ else
+ params.wps = WPS_MODE_OPEN;
+ wpa_s->wpa_proto = 0;
#endif /* CONFIG_WPS */
} else {
wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
wpa_ie_len = 0;
+ wpa_s->wpa_proto = 0;
+ }
+
+#ifdef CONFIG_P2P
+ if (wpa_s->global->p2p) {
+ u8 *pos;
+ size_t len;
+ int res;
+ int p2p_group;
+ p2p_group = wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE;
+ pos = wpa_ie + wpa_ie_len;
+ len = sizeof(wpa_ie) - wpa_ie_len;
+ res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len, p2p_group);
+ if (res >= 0)
+ wpa_ie_len += res;
+ }
+
+ wpa_s->cross_connect_disallowed = 0;
+ if (bss) {
+ struct wpabuf *p2p;
+ p2p = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE);
+ if (p2p) {
+ wpa_s->cross_connect_disallowed =
+ p2p_get_cross_connect_disallowed(p2p);
+ wpabuf_free(p2p);
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: WLAN AP %s cross "
+ "connection",
+ wpa_s->cross_connect_disallowed ?
+ "disallows" : "allows");
+ }
+ }
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_INTERWORKING
+ if (wpa_s->conf->interworking) {
+ u8 *pos = wpa_ie;
+ if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN)
+ pos += 2 + pos[1];
+ os_memmove(pos + 6, pos, wpa_ie_len - (pos - wpa_ie));
+ wpa_ie_len += 6;
+ *pos++ = WLAN_EID_EXT_CAPAB;
+ *pos++ = 4;
+ *pos++ = 0x00;
+ *pos++ = 0x00;
+ *pos++ = 0x00;
+ *pos++ = 0x80; /* Bit 31 - Interworking */
}
+#endif /* CONFIG_INTERWORKING */
wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
use_crypt = 1;
}
wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
- os_memset(¶ms, 0, sizeof(params));
if (bss) {
- params.bssid = bss->bssid;
params.ssid = bss->ssid;
params.ssid_len = bss->ssid_len;
- params.freq = bss->freq;
+ if (!wpas_driver_bss_selection(wpa_s)) {
+ params.bssid = bss->bssid;
+ params.freq = bss->freq;
+ }
} else {
params.ssid = ssid->ssid;
params.ssid_len = ssid->ssid_len;
}
+
+ if (ssid->mode == WPAS_MODE_IBSS && ssid->bssid_set &&
+ wpa_s->conf->ap_scan == 2) {
+ params.bssid = ssid->bssid;
+ params.fixed_bssid = 1;
+ }
+
if (ssid->mode == WPAS_MODE_IBSS && ssid->frequency > 0 &&
params.freq == 0)
params.freq = ssid->frequency; /* Initial channel for IBSS */
params.pairwise_suite = cipher_pairwise;
params.group_suite = cipher_group;
params.key_mgmt_suite = key_mgmt2driver(wpa_s->key_mgmt);
+ params.wpa_proto = wpa_s->wpa_proto;
params.auth_alg = algs;
params.mode = ssid->mode;
for (i = 0; i < NUM_WEP_KEYS; i++) {
if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie) == 0 &&
ie.capabilities &
(WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) {
- wpa_printf(MSG_DEBUG, "WPA: Selected AP supports MFP: "
- "require MFP");
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected AP supports "
+ "MFP: require MFP");
params.mgmt_frame_protection =
MGMT_FRAME_PROTECTION_REQUIRED;
}
}
#endif /* CONFIG_IEEE80211W */
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
- ret = ieee80211_sta_associate(wpa_s, ¶ms);
+ params.p2p = ssid->p2p_group;
+
+ if (wpa_s->parent->set_sta_uapsd)
+ params.uapsd = wpa_s->parent->sta_uapsd;
else
- ret = wpa_drv_associate(wpa_s, ¶ms);
+ params.uapsd = -1;
+
+#ifdef CONFIG_HT_OVERRIDES
+ os_memset(&htcaps, 0, sizeof(htcaps));
+ os_memset(&htcaps_mask, 0, sizeof(htcaps_mask));
+ params.htcaps = (u8 *) &htcaps;
+ params.htcaps_mask = (u8 *) &htcaps_mask;
+ wpa_supplicant_apply_ht_overrides(wpa_s, ssid, ¶ms);
+#endif /* CONFIG_HT_OVERRIDES */
+
+ ret = wpa_drv_associate(wpa_s, ¶ms);
if (ret < 0) {
wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
"failed");
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SANE_ERROR_CODES) {
+ /*
+ * The driver is known to mean what is saying, so we
+ * can stop right here; the association will not
+ * succeed.
+ */
+ wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+ os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
+ return;
+ }
/* try to continue anyway; new association will be tried again
* after timeout */
assoc_failed = 1;
} else if (ssid->mode == WPAS_MODE_IBSS &&
wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE) {
- ibss_rsn_set_psk(wpa_s->ibss_rsn, ssid->psk);
/*
* RSN IBSS authentication is per-STA and we can disable the
* per-BSSID authentication.
}
+static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s,
+ const u8 *addr)
+{
+ struct wpa_ssid *old_ssid;
+
+ wpa_clear_keys(wpa_s, addr);
+ wpa_supplicant_mark_disassoc(wpa_s);
+ old_ssid = wpa_s->current_ssid;
+ wpa_s->current_ssid = NULL;
+ wpa_s->current_bss = NULL;
+ wpa_sm_set_config(wpa_s->wpa, NULL);
+ eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+ if (old_ssid != wpa_s->current_ssid)
+ wpas_notify_network_changed(wpa_s);
+ eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
+}
+
+
/**
* wpa_supplicant_disassociate - Disassociate the current connection
* @wpa_s: Pointer to wpa_supplicant data
void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
int reason_code)
{
- struct wpa_ssid *old_ssid;
u8 *addr = NULL;
if (!is_zero_ether_addr(wpa_s->bssid)) {
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
- ieee80211_sta_disassociate(wpa_s, reason_code);
- else
- wpa_drv_disassociate(wpa_s, wpa_s->bssid, reason_code);
+ wpa_drv_disassociate(wpa_s, wpa_s->bssid, reason_code);
addr = wpa_s->bssid;
}
- wpa_clear_keys(wpa_s, addr);
- wpa_supplicant_mark_disassoc(wpa_s);
- old_ssid = wpa_s->current_ssid;
- wpa_s->current_ssid = NULL;
- wpa_s->current_bss = NULL;
- wpa_sm_set_config(wpa_s->wpa, NULL);
- eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
- if (old_ssid != wpa_s->current_ssid)
- wpas_notify_network_changed(wpa_s);
+
+ wpa_supplicant_clear_connection(wpa_s, addr);
}
void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
int reason_code)
{
- struct wpa_ssid *old_ssid;
u8 *addr = NULL;
if (!is_zero_ether_addr(wpa_s->bssid)) {
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
- ieee80211_sta_deauthenticate(wpa_s, reason_code);
- else
- wpa_drv_deauthenticate(wpa_s, wpa_s->bssid,
- reason_code);
+ wpa_drv_deauthenticate(wpa_s, wpa_s->bssid, reason_code);
addr = wpa_s->bssid;
}
- wpa_clear_keys(wpa_s, addr);
- wpa_supplicant_mark_disassoc(wpa_s);
- old_ssid = wpa_s->current_ssid;
- wpa_s->current_ssid = NULL;
- wpa_s->current_bss = NULL;
- wpa_sm_set_config(wpa_s->wpa, NULL);
- eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
- if (old_ssid != wpa_s->current_ssid)
- wpas_notify_network_changed(wpa_s);
+
+ wpa_supplicant_clear_connection(wpa_s, addr);
}
int was_disabled;
if (ssid == NULL) {
- other_ssid = wpa_s->conf->ssid;
- while (other_ssid) {
+ for (other_ssid = wpa_s->conf->ssid; other_ssid;
+ other_ssid = other_ssid->next) {
+ if (other_ssid->disabled == 2)
+ continue; /* do not change persistent P2P group
+ * data */
if (other_ssid == wpa_s->current_ssid &&
other_ssid->disabled)
wpa_s->reassociate = 1;
if (was_disabled != other_ssid->disabled)
wpas_notify_network_enabled_changed(
wpa_s, other_ssid);
-
- other_ssid = other_ssid->next;
}
if (wpa_s->reassociate)
wpa_supplicant_req_scan(wpa_s, 0, 0);
- } else if (ssid->disabled) {
+ } else if (ssid->disabled && ssid->disabled != 2) {
if (wpa_s->current_ssid == NULL) {
/*
* Try to reassociate since there is no current
int was_disabled;
if (ssid == NULL) {
- other_ssid = wpa_s->conf->ssid;
- while (other_ssid) {
+ for (other_ssid = wpa_s->conf->ssid; other_ssid;
+ other_ssid = other_ssid->next) {
was_disabled = other_ssid->disabled;
+ if (was_disabled == 2)
+ continue; /* do not change persistent P2P group
+ * data */
other_ssid->disabled = 1;
if (was_disabled != other_ssid->disabled)
wpas_notify_network_enabled_changed(
wpa_s, other_ssid);
-
- other_ssid = other_ssid->next;
}
if (wpa_s->current_ssid)
wpa_supplicant_disassociate(
wpa_s, WLAN_REASON_DEAUTH_LEAVING);
- } else {
+ } else if (ssid->disabled != 2) {
if (ssid == wpa_s->current_ssid)
wpa_supplicant_disassociate(
wpa_s, WLAN_REASON_DEAUTH_LEAVING);
{
struct wpa_ssid *other_ssid;
+ int disconnected = 0;
- if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid)
+ if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid) {
wpa_supplicant_disassociate(
wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ disconnected = 1;
+ }
/*
* Mark all other networks disabled or mark all networks enabled if no
* network specified.
*/
- other_ssid = wpa_s->conf->ssid;
- while (other_ssid) {
+ for (other_ssid = wpa_s->conf->ssid; other_ssid;
+ other_ssid = other_ssid->next) {
int was_disabled = other_ssid->disabled;
+ if (was_disabled == 2)
+ continue; /* do not change persistent P2P group data */
other_ssid->disabled = ssid ? (ssid->id != other_ssid->id) : 0;
if (was_disabled != other_ssid->disabled)
wpas_notify_network_enabled_changed(wpa_s, other_ssid);
+ }
- other_ssid = other_ssid->next;
+ if (ssid && ssid == wpa_s->current_ssid && wpa_s->current_ssid) {
+ /* We are already associated with the selected network */
+ wpa_printf(MSG_DEBUG, "Already associated with the "
+ "selected network - do nothing");
+ return;
}
+
+ if (ssid)
+ wpa_s->current_ssid = ssid;
+ wpa_s->connect_without_scan = NULL;
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
- wpa_supplicant_req_scan(wpa_s, 0, 0);
+ wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
if (ssid)
wpas_notify_network_selected(wpa_s, ssid);
if (ap_scan < 0 || ap_scan > 2)
return -1;
+#ifdef ANDROID
+ if (ap_scan == 2 && ap_scan != wpa_s->conf->ap_scan &&
+ wpa_s->wpa_state >= WPA_ASSOCIATING &&
+ wpa_s->wpa_state < WPA_COMPLETED) {
+ wpa_printf(MSG_ERROR, "ap_scan = %d (%d) rejected while "
+ "associating", wpa_s->conf->ap_scan, ap_scan);
+ return 0;
+ }
+#endif /* ANDROID */
+
old_ap_scan = wpa_s->conf->ap_scan;
wpa_s->conf->ap_scan = ap_scan;
}
+/**
+ * wpa_supplicant_set_bss_expiration_age - Set BSS entry expiration age
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @expire_age: Expiration age in seconds
+ * Returns: 0 if succeed or -1 if expire_age has an invalid value
+ *
+ */
+int wpa_supplicant_set_bss_expiration_age(struct wpa_supplicant *wpa_s,
+ unsigned int bss_expire_age)
+{
+ if (bss_expire_age < 10) {
+ wpa_msg(wpa_s, MSG_ERROR, "Invalid bss expiration age %u",
+ bss_expire_age);
+ return -1;
+ }
+ wpa_msg(wpa_s, MSG_DEBUG, "Setting bss expiration age: %d sec",
+ bss_expire_age);
+ wpa_s->conf->bss_expiration_age = bss_expire_age;
+
+ return 0;
+}
+
+
+/**
+ * wpa_supplicant_set_bss_expiration_count - Set BSS entry expiration scan count
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @expire_count: number of scans after which an unseen BSS is reclaimed
+ * Returns: 0 if succeed or -1 if expire_count has an invalid value
+ *
+ */
+int wpa_supplicant_set_bss_expiration_count(struct wpa_supplicant *wpa_s,
+ unsigned int bss_expire_count)
+{
+ if (bss_expire_count < 1) {
+ wpa_msg(wpa_s, MSG_ERROR, "Invalid bss expiration count %u",
+ bss_expire_count);
+ return -1;
+ }
+ wpa_msg(wpa_s, MSG_DEBUG, "Setting bss expiration scan count: %u",
+ bss_expire_count);
+ wpa_s->conf->bss_expiration_scan_count = bss_expire_count;
+
+ return 0;
+}
+
+
/**
* wpa_supplicant_set_debug_params - Set global debug params
* @global: wpa_global structure
@@ -1535,7 +1790,8 @@ int wpa_supplicant_set_debug_params(struct wpa_global *global, int debug_level,
int old_level, old_timestamp, old_show_keys;
/* check for allowed debuglevels */
- if (debug_level != MSG_MSGDUMP &&
+ if (debug_level != MSG_EXCESSIVE &&
+ debug_level != MSG_MSGDUMP &&
debug_level != MSG_DEBUG &&
debug_level != MSG_INFO &&
debug_level != MSG_WARNING &&
u8 bssid[ETH_ALEN];
int wired;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
- if (ieee80211_sta_get_ssid(wpa_s, ssid, &ssid_len)) {
- wpa_printf(MSG_WARNING, "Could not read SSID from "
- "MLME.");
- return NULL;
- }
- } else {
- res = wpa_drv_get_ssid(wpa_s, ssid);
- if (res < 0) {
- wpa_printf(MSG_WARNING, "Could not read SSID from "
- "driver.");
- return NULL;
- }
- ssid_len = res;
+ res = wpa_drv_get_ssid(wpa_s, ssid);
+ if (res < 0) {
+ wpa_msg(wpa_s, MSG_WARNING, "Could not read SSID from "
+ "driver");
+ return NULL;
}
+ ssid_len = res;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
- os_memcpy(bssid, wpa_s->bssid, ETH_ALEN);
- else if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
- wpa_printf(MSG_WARNING, "Could not read BSSID from driver.");
+ if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
+ wpa_msg(wpa_s, MSG_WARNING, "Could not read BSSID from "
+ "driver");
return NULL;
}
os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
return entry;
#endif /* CONFIG_WPS */
+
+ if (!entry->disabled && entry->bssid_set &&
+ entry->ssid_len == 0 &&
+ os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)
+ return entry;
+
entry = entry->next;
}
}
+static int select_driver(struct wpa_supplicant *wpa_s, int i)
+{
+ struct wpa_global *global = wpa_s->global;
+
+ if (wpa_drivers[i]->global_init && global->drv_priv[i] == NULL) {
+ global->drv_priv[i] = wpa_drivers[i]->global_init();
+ if (global->drv_priv[i] == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to initialize driver "
+ "'%s'", wpa_drivers[i]->name);
+ return -1;
+ }
+ }
+
+ wpa_s->driver = wpa_drivers[i];
+ wpa_s->global_drv_priv = global->drv_priv[i];
+
+ return 0;
+}
+
+
static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
const char *name)
{
int i;
size_t len;
- const char *pos;
+ const char *pos, *driver = name;
if (wpa_s == NULL)
return -1;
if (wpa_drivers[0] == NULL) {
- wpa_printf(MSG_ERROR, "No driver interfaces build into "
- "wpa_supplicant.");
+ wpa_msg(wpa_s, MSG_ERROR, "No driver interfaces build into "
+ "wpa_supplicant");
return -1;
}
if (name == NULL) {
/* default to first driver in the list */
- wpa_s->driver = wpa_drivers[0];
- wpa_s->global_drv_priv = wpa_s->global->drv_priv[0];
- return 0;
+ return select_driver(wpa_s, 0);
}
- pos = os_strchr(name, ',');
- if (pos)
- len = pos - name;
- else
- len = os_strlen(name);
- for (i = 0; wpa_drivers[i]; i++) {
- if (os_strlen(wpa_drivers[i]->name) == len &&
- os_strncmp(name, wpa_drivers[i]->name, len) ==
- 0) {
- wpa_s->driver = wpa_drivers[i];
- wpa_s->global_drv_priv = wpa_s->global->drv_priv[i];
- return 0;
+ do {
+ pos = os_strchr(driver, ',');
+ if (pos)
+ len = pos - driver;
+ else
+ len = os_strlen(driver);
+
+ for (i = 0; wpa_drivers[i]; i++) {
+ if (os_strlen(wpa_drivers[i]->name) == len &&
+ os_strncmp(driver, wpa_drivers[i]->name, len) ==
+ 0) {
+ /* First driver that succeeds wins */
+ if (select_driver(wpa_s, i) == 0)
+ return 0;
+ }
}
- }
- wpa_printf(MSG_ERROR, "Unsupported driver '%s'.", name);
+ driver = pos + 1;
+ } while (pos);
+
+ wpa_msg(wpa_s, MSG_ERROR, "Unsupported driver '%s'", name);
return -1;
}
{
struct wpa_supplicant *wpa_s = ctx;
- wpa_printf(MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
+ wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
if (wpa_s->wpa_state < WPA_ASSOCIATED) {
* association information, lets queue it for processing until
* the association event is received.
*/
- wpa_printf(MSG_DEBUG, "Not associated - Delay processing of "
- "received EAPOL frame");
+ wpa_dbg(wpa_s, MSG_DEBUG, "Not associated - Delay processing "
+ "of received EAPOL frame");
wpabuf_free(wpa_s->pending_eapol_rx);
wpa_s->pending_eapol_rx = wpabuf_alloc_copy(buf, len);
if (wpa_s->pending_eapol_rx) {
#endif /* CONFIG_AP */
if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
- wpa_printf(MSG_DEBUG, "Ignored received EAPOL frame since "
- "no key management is configured");
+ wpa_dbg(wpa_s, MSG_DEBUG, "Ignored received EAPOL frame since "
+ "no key management is configured");
return;
}
wpa_s->eapol_received++;
if (wpa_s->countermeasures) {
- wpa_printf(MSG_INFO, "WPA: Countermeasures - dropped EAPOL "
- "packet");
+ wpa_msg(wpa_s, MSG_INFO, "WPA: Countermeasures - dropped "
+ "EAPOL packet");
return;
}
}
-/**
- * wpa_supplicant_driver_init - Initialize driver interface parameters
- * @wpa_s: Pointer to wpa_supplicant data
- * Returns: 0 on success, -1 on failure
- *
- * This function is called to initialize driver interface parameters.
- * wpa_drv_init() must have been called before this function to initialize the
- * driver interface.
- */
-int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
+int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
{
- static int interface_count = 0;
-
if (wpa_s->driver->send_eapol) {
const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
if (addr)
os_memcpy(wpa_s->own_addr, addr, ETH_ALEN);
- } else {
+ } else if (!(wpa_s->drv_flags &
+ WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)) {
+ l2_packet_deinit(wpa_s->l2);
wpa_s->l2 = l2_packet_init(wpa_s->ifname,
wpa_drv_get_mac_addr(wpa_s),
ETH_P_EAPOL,
wpa_supplicant_rx_eapol, wpa_s, 0);
if (wpa_s->l2 == NULL)
return -1;
+ } else {
+ const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
+ if (addr)
+ os_memcpy(wpa_s->own_addr, addr, ETH_ALEN);
}
if (wpa_s->l2 && l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) {
- wpa_printf(MSG_ERROR, "Failed to get own L2 address");
+ wpa_msg(wpa_s, MSG_ERROR, "Failed to get own L2 address");
return -1;
}
- wpa_printf(MSG_DEBUG, "Own MAC address: " MACSTR,
- MAC2STR(wpa_s->own_addr));
+ wpa_dbg(wpa_s, MSG_DEBUG, "Own MAC address: " MACSTR,
+ MAC2STR(wpa_s->own_addr));
+ wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
+
+ return 0;
+}
+
+
+/**
+ * wpa_supplicant_driver_init - Initialize driver interface parameters
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called to initialize driver interface parameters.
+ * wpa_drv_init() must have been called before this function to initialize the
+ * driver interface.
+ */
+int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
+{
+ static int interface_count = 0;
+
+ if (wpa_supplicant_update_mac_addr(wpa_s) < 0)
+ return -1;
if (wpa_s->bridge_ifname[0]) {
- wpa_printf(MSG_DEBUG, "Receiving packets from bridge interface"
- " '%s'", wpa_s->bridge_ifname);
+ wpa_dbg(wpa_s, MSG_DEBUG, "Receiving packets from bridge "
+ "interface '%s'", wpa_s->bridge_ifname);
wpa_s->l2_br = l2_packet_init(wpa_s->bridge_ifname,
wpa_s->own_addr,
ETH_P_EAPOL,
wpa_supplicant_rx_eapol, wpa_s,
0);
if (wpa_s->l2_br == NULL) {
- wpa_printf(MSG_ERROR, "Failed to open l2_packet "
- "connection for the bridge interface '%s'",
- wpa_s->bridge_ifname);
+ wpa_msg(wpa_s, MSG_ERROR, "Failed to open l2_packet "
+ "connection for the bridge interface '%s'",
+ wpa_s->bridge_ifname);
return -1;
}
}
* happen if wpa_supplicant is killed during countermeasures. */
wpa_drv_set_countermeasures(wpa_s, 0);
- wpa_printf(MSG_DEBUG, "RSN: flushing PMKID list in the driver");
+ wpa_dbg(wpa_s, MSG_DEBUG, "RSN: flushing PMKID list in the driver");
wpa_drv_flush_pmkid(wpa_s);
wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
+ wpa_s->prev_scan_wildcard = 0;
+
if (wpa_supplicant_enabled_networks(wpa_s->conf)) {
- wpa_supplicant_req_scan(wpa_s, interface_count, 100000);
+ if (wpa_supplicant_delayed_sched_scan(wpa_s, interface_count,
+ 100000))
+ wpa_supplicant_req_scan(wpa_s, interface_count,
+ 100000);
interface_count++;
} else
wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
if (wpa_s == NULL)
return NULL;
wpa_s->scan_req = 1;
+ wpa_s->scan_interval = 5;
wpa_s->new_connection = 1;
+ wpa_s->parent = wpa_s;
+ wpa_s->sched_scanning = 0;
return wpa_s;
}
+#ifdef CONFIG_HT_OVERRIDES
+
+static int wpa_set_htcap_mcs(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ const char *ht_mcs)
+{
+ /* parse ht_mcs into hex array */
+ int i;
+ const char *tmp = ht_mcs;
+ char *end = NULL;
+
+ /* If ht_mcs is null, do not set anything */
+ if (!ht_mcs)
+ return 0;
+
+ /* This is what we are setting in the kernel */
+ os_memset(&htcaps->supported_mcs_set, 0, IEEE80211_HT_MCS_MASK_LEN);
+
+ wpa_msg(wpa_s, MSG_DEBUG, "set_htcap, ht_mcs -:%s:-", ht_mcs);
+
+ for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
+ errno = 0;
+ long v = strtol(tmp, &end, 16);
+ if (errno == 0) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "htcap value[%i]: %ld end: %p tmp: %p",
+ i, v, end, tmp);
+ if (end == tmp)
+ break;
+
+ htcaps->supported_mcs_set[i] = v;
+ tmp = end;
+ } else {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "Failed to parse ht-mcs: %s, error: %s\n",
+ ht_mcs, strerror(errno));
+ return -1;
+ }
+ }
+
+ /*
+ * If we were able to parse any values, then set mask for the MCS set.
+ */
+ if (i) {
+ os_memset(&htcaps_mask->supported_mcs_set, 0xff,
+ IEEE80211_HT_MCS_MASK_LEN - 1);
+ /* skip the 3 reserved bits */
+ htcaps_mask->supported_mcs_set[IEEE80211_HT_MCS_MASK_LEN - 1] =
+ 0x1f;
+ }
+
+ return 0;
+}
+
+
+static int wpa_disable_max_amsdu(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ int disabled)
+{
+ u16 msk;
+
+ wpa_msg(wpa_s, MSG_DEBUG, "set_disable_max_amsdu: %d", disabled);
+
+ if (disabled == -1)
+ return 0;
+
+ msk = host_to_le16(HT_CAP_INFO_MAX_AMSDU_SIZE);
+ htcaps_mask->ht_capabilities_info |= msk;
+ if (disabled)
+ htcaps->ht_capabilities_info &= msk;
+ else
+ htcaps->ht_capabilities_info |= msk;
+
+ return 0;
+}
+
+
+static int wpa_set_ampdu_factor(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ int factor)
+{
+ wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_factor: %d", factor);
+
+ if (factor == -1)
+ return 0;
+
+ if (factor < 0 || factor > 3) {
+ wpa_msg(wpa_s, MSG_ERROR, "ampdu_factor: %d out of range. "
+ "Must be 0-3 or -1", factor);
+ return -EINVAL;
+ }
+
+ htcaps_mask->a_mpdu_params |= 0x3; /* 2 bits for factor */
+ htcaps->a_mpdu_params &= ~0x3;
+ htcaps->a_mpdu_params |= factor & 0x3;
+
+ return 0;
+}
+
+
+static int wpa_set_ampdu_density(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ int density)
+{
+ wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_density: %d", density);
+
+ if (density == -1)
+ return 0;
+
+ if (density < 0 || density > 7) {
+ wpa_msg(wpa_s, MSG_ERROR,
+ "ampdu_density: %d out of range. Must be 0-7 or -1.",
+ density);
+ return -EINVAL;
+ }
+
+ htcaps_mask->a_mpdu_params |= 0x1C;
+ htcaps->a_mpdu_params &= ~(0x1C);
+ htcaps->a_mpdu_params |= (density << 2) & 0x1C;
+
+ return 0;
+}
+
+
+static int wpa_set_disable_ht40(struct wpa_supplicant *wpa_s,
+ struct ieee80211_ht_capabilities *htcaps,
+ struct ieee80211_ht_capabilities *htcaps_mask,
+ int disabled)
+{
+ /* Masking these out disables HT40 */
+ u16 msk = host_to_le16(HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET |
+ HT_CAP_INFO_SHORT_GI40MHZ);
+
+ wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ht40: %d", disabled);
+
+ if (disabled)
+ htcaps->ht_capabilities_info &= ~msk;
+ else
+ htcaps->ht_capabilities_info |= msk;
+
+ htcaps_mask->ht_capabilities_info |= msk;
+
+ return 0;
+}
+
+
+void wpa_supplicant_apply_ht_overrides(
+ struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+ struct wpa_driver_associate_params *params)
+{
+ struct ieee80211_ht_capabilities *htcaps;
+ struct ieee80211_ht_capabilities *htcaps_mask;
+
+ if (!ssid)
+ return;
+
+ params->disable_ht = ssid->disable_ht;
+ if (!params->htcaps || !params->htcaps_mask)
+ return;
+
+ htcaps = (struct ieee80211_ht_capabilities *) params->htcaps;
+ htcaps_mask = (struct ieee80211_ht_capabilities *) params->htcaps_mask;
+ wpa_set_htcap_mcs(wpa_s, htcaps, htcaps_mask, ssid->ht_mcs);
+ wpa_disable_max_amsdu(wpa_s, htcaps, htcaps_mask,
+ ssid->disable_max_amsdu);
+ wpa_set_ampdu_factor(wpa_s, htcaps, htcaps_mask, ssid->ampdu_factor);
+ wpa_set_ampdu_density(wpa_s, htcaps, htcaps_mask, ssid->ampdu_density);
+ wpa_set_disable_ht40(wpa_s, htcaps, htcaps_mask, ssid->disable_ht40);
+}
+
+#endif /* CONFIG_HT_OVERRIDES */
+
+
static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
struct wpa_interface *iface)
{
const char *pos;
pos = driver ? os_strchr(driver, ',') : NULL;
if (pos) {
- wpa_printf(MSG_DEBUG, "Failed to initialize driver "
- "interface - try next driver wrapper");
+ wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
+ "driver interface - try next driver wrapper");
driver = pos + 1;
goto next_driver;
}
- wpa_printf(MSG_ERROR, "Failed to initialize driver interface");
+ wpa_msg(wpa_s, MSG_ERROR, "Failed to initialize driver "
+ "interface");
return -1;
}
if (wpa_drv_set_param(wpa_s, wpa_s->conf->driver_param) < 0) {
- wpa_printf(MSG_ERROR, "Driver interface rejected "
- "driver_param '%s'", wpa_s->conf->driver_param);
+ wpa_msg(wpa_s, MSG_ERROR, "Driver interface rejected "
+ "driver_param '%s'", wpa_s->conf->driver_param);
return -1;
}
ifname = wpa_drv_get_ifname(wpa_s);
if (ifname && os_strcmp(ifname, wpa_s->ifname) != 0) {
- wpa_printf(MSG_DEBUG, "Driver interface replaced interface "
- "name with '%s'", ifname);
+ wpa_dbg(wpa_s, MSG_DEBUG, "Driver interface replaced "
+ "interface name with '%s'", ifname);
os_strlcpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
}
if (wpa_s->conf->dot11RSNAConfigPMKLifetime &&
wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
wpa_s->conf->dot11RSNAConfigPMKLifetime)) {
- wpa_printf(MSG_ERROR, "Invalid WPA parameter value for "
- "dot11RSNAConfigPMKLifetime");
+ wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for "
+ "dot11RSNAConfigPMKLifetime");
return -1;
}
if (wpa_s->conf->dot11RSNAConfigPMKReauthThreshold &&
wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
wpa_s->conf->dot11RSNAConfigPMKReauthThreshold)) {
- wpa_printf(MSG_ERROR, "Invalid WPA parameter value for "
+ wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for "
"dot11RSNAConfigPMKReauthThreshold");
return -1;
}
if (wpa_s->conf->dot11RSNAConfigSATimeout &&
wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT,
wpa_s->conf->dot11RSNAConfigSATimeout)) {
- wpa_printf(MSG_ERROR, "Invalid WPA parameter value for "
- "dot11RSNAConfigSATimeout");
+ wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for "
+ "dot11RSNAConfigSATimeout");
return -1;
}
+ wpa_s->hw.modes = wpa_drv_get_hw_feature_data(wpa_s,
+ &wpa_s->hw.num_modes,
+ &wpa_s->hw.flags);
+
if (wpa_drv_get_capa(wpa_s, &capa) == 0) {
+ wpa_s->drv_capa_known = 1;
wpa_s->drv_flags = capa.flags;
- if (capa.flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
- if (ieee80211_sta_init(wpa_s))
- return -1;
- }
+ wpa_s->probe_resp_offloads = capa.probe_resp_offloads;
wpa_s->max_scan_ssids = capa.max_scan_ssids;
+ wpa_s->max_sched_scan_ssids = capa.max_sched_scan_ssids;
+ wpa_s->sched_scan_supported = capa.sched_scan_supported;
+ wpa_s->max_match_sets = capa.max_match_sets;
wpa_s->max_remain_on_chan = capa.max_remain_on_chan;
+ wpa_s->max_stations = capa.max_stations;
}
if (wpa_s->max_remain_on_chan == 0)
wpa_s->max_remain_on_chan = 1000;
if (wpa_supplicant_driver_init(wpa_s) < 0)
return -1;
+#ifdef CONFIG_TDLS
+ if (wpa_tdls_init(wpa_s->wpa))
+ return -1;
+#endif /* CONFIG_TDLS */
+
if (wpa_s->conf->country[0] && wpa_s->conf->country[1] &&
wpa_drv_set_country(wpa_s, wpa_s->conf->country)) {
- wpa_printf(MSG_DEBUG, "Failed to set country");
+ wpa_dbg(wpa_s, MSG_DEBUG, "Failed to set country");
return -1;
}
- wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
-
if (wpas_wps_init(wpa_s))
return -1;
return -1;
}
-#ifdef CONFIG_IBSS_RSN
- wpa_s->ibss_rsn = ibss_rsn_init(wpa_s);
- if (!wpa_s->ibss_rsn) {
- wpa_printf(MSG_DEBUG, "Failed to init IBSS RSN");
+ wpa_s->gas = gas_query_init(wpa_s);
+ if (wpa_s->gas == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to initialize GAS query");
return -1;
}
-#endif /* CONFIG_IBSS_RSN */
+
+#ifdef CONFIG_P2P
+ if (wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
+ wpa_msg(wpa_s, MSG_ERROR, "Failed to init P2P");
+ return -1;
+ }
+#endif /* CONFIG_P2P */
if (wpa_bss_init(wpa_s) < 0)
return -1;
static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
- int notify)
+ int notify, int terminate)
{
if (wpa_s->drv_priv) {
wpa_supplicant_deauthenticate(wpa_s,
wpa_supplicant_cleanup(wpa_s);
+ if (wpa_s->drv_priv)
+ wpa_drv_deinit(wpa_s);
+
if (notify)
wpas_notify_iface_removed(wpa_s);
- if (wpa_s->drv_priv)
- wpa_drv_deinit(wpa_s);
+ if (terminate)
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TERMINATING);
+
+ if (wpa_s->ctrl_iface) {
+ wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
+ wpa_s->ctrl_iface = NULL;
+ }
+
+ if (wpa_s->conf != NULL) {
+ wpa_config_free(wpa_s->conf);
+ wpa_s->conf = NULL;
+ }
}
if (wpa_supplicant_init_iface(wpa_s, &t_iface)) {
wpa_printf(MSG_DEBUG, "Failed to add interface %s",
iface->ifname);
- wpa_supplicant_deinit_iface(wpa_s, 0);
+ wpa_supplicant_deinit_iface(wpa_s, 0, 0);
os_free(wpa_s);
return NULL;
}
/* Notify the control interfaces about new iface */
if (wpas_notify_iface_added(wpa_s)) {
- wpa_supplicant_deinit_iface(wpa_s, 1);
+ wpa_supplicant_deinit_iface(wpa_s, 1, 0);
os_free(wpa_s);
return NULL;
}
wpa_s->next = global->ifaces;
global->ifaces = wpa_s;
- wpa_printf(MSG_DEBUG, "Added interface %s", wpa_s->ifname);
+ wpa_dbg(wpa_s, MSG_DEBUG, "Added interface %s", wpa_s->ifname);
return wpa_s;
}
* %wpa_supplicant is terminated.
*/
int wpa_supplicant_remove_iface(struct wpa_global *global,
- struct wpa_supplicant *wpa_s)
+ struct wpa_supplicant *wpa_s,
+ int terminate)
{
struct wpa_supplicant *prev;
prev->next = wpa_s->next;
}
- wpa_printf(MSG_DEBUG, "Removing interface %s", wpa_s->ifname);
+ wpa_dbg(wpa_s, MSG_DEBUG, "Removing interface %s", wpa_s->ifname);
- wpa_supplicant_deinit_iface(wpa_s, 1);
+ if (global->p2p_group_formation == wpa_s)
+ global->p2p_group_formation = NULL;
+ wpa_supplicant_deinit_iface(wpa_s, 1, terminate);
os_free(wpa_s);
return 0;
}
+/**
+ * wpa_supplicant_get_eap_mode - Get the current EAP mode
+ * @wpa_s: Pointer to the network interface
+ * Returns: Pointer to the eap mode or the string "UNKNOWN" if not found
+ */
+const char * wpa_supplicant_get_eap_mode(struct wpa_supplicant *wpa_s)
+{
+ const char *eapol_method;
+
+ if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) == 0 &&
+ wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+ return "NO-EAP";
+ }
+
+ eapol_method = eapol_sm_get_method_name(wpa_s->eapol);
+ if (eapol_method == NULL)
+ return "UNKNOWN-EAP";
+
+ return eapol_method;
+}
+
+
/**
* wpa_supplicant_get_iface - Get a new network interface
* @global: Pointer to global data from wpa_supplicant_init()
}
+#ifndef CONFIG_NO_WPA_MSG
+static const char * wpa_supplicant_msg_ifname_cb(void *ctx)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ if (wpa_s == NULL)
+ return NULL;
+ return wpa_s->ifname;
+}
+#endif /* CONFIG_NO_WPA_MSG */
+
+
/**
* wpa_supplicant_init - Initialize %wpa_supplicant
* @params: Parameters for %wpa_supplicant
if (params == NULL)
return NULL;
+#ifdef CONFIG_DRIVER_NDIS
+ {
+ void driver_ndis_init_ops(void);
+ driver_ndis_init_ops();
+ }
+#endif /* CONFIG_DRIVER_NDIS */
+
+#ifndef CONFIG_NO_WPA_MSG
+ wpa_msg_register_ifname_cb(wpa_supplicant_msg_ifname_cb);
+#endif /* CONFIG_NO_WPA_MSG */
+
wpa_debug_open_file(params->wpa_debug_file_path);
if (params->wpa_debug_syslog)
wpa_debug_open_syslog();
global = os_zalloc(sizeof(*global));
if (global == NULL)
return NULL;
+ dl_list_init(&global->p2p_srv_bonjour);
+ dl_list_init(&global->p2p_srv_upnp);
global->params.daemonize = params->daemonize;
global->params.wait_for_monitor = params->wait_for_monitor;
global->params.dbus_ctrl_interface = params->dbus_ctrl_interface;
wpa_debug_timestamp = global->params.wpa_debug_timestamp =
params->wpa_debug_timestamp;
+ wpa_printf(MSG_DEBUG, "wpa_supplicant v" VERSION_STR);
+
if (eloop_init()) {
wpa_printf(MSG_ERROR, "Failed to initialize event loop");
wpa_supplicant_deinit(global);
return NULL;
}
+ random_init(params->entropy_file);
+
global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global);
if (global->ctrl_iface == NULL) {
wpa_supplicant_deinit(global);
wpa_supplicant_deinit(global);
return NULL;
}
- for (i = 0; wpa_drivers[i]; i++) {
- if (!wpa_drivers[i]->global_init)
- continue;
- global->drv_priv[i] = wpa_drivers[i]->global_init();
- if (global->drv_priv[i] == NULL) {
- wpa_printf(MSG_ERROR, "Failed to initialize driver "
- "'%s'", wpa_drivers[i]->name);
- wpa_supplicant_deinit(global);
- return NULL;
- }
- }
return global;
}
if (global == NULL)
return;
+#ifdef CONFIG_P2P
+ wpas_p2p_deinit_global(global);
+#endif /* CONFIG_P2P */
+
while (global->ifaces)
- wpa_supplicant_remove_iface(global, global->ifaces);
+ wpa_supplicant_remove_iface(global, global->ifaces, 1);
if (global->ctrl_iface)
wpa_supplicant_global_ctrl_iface_deinit(global->ctrl_iface);
}
os_free(global->drv_priv);
+ random_deinit();
+
eloop_destroy();
if (global->params.pid_file) {
wpa_debug_close_syslog();
wpa_debug_close_file();
}
+
+
+void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
+{
+ if ((wpa_s->conf->changed_parameters & CFG_CHANGED_COUNTRY) &&
+ wpa_s->conf->country[0] && wpa_s->conf->country[1]) {
+ char country[3];
+ country[0] = wpa_s->conf->country[0];
+ country[1] = wpa_s->conf->country[1];
+ country[2] = '\0';
+ if (wpa_drv_set_country(wpa_s, country) < 0) {
+ wpa_printf(MSG_ERROR, "Failed to set country code "
+ "'%s'", country);
+ }
+ }
+
+#ifdef CONFIG_WPS
+ wpas_wps_update_config(wpa_s);
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_P2P
+ wpas_p2p_update_config(wpa_s);
+#endif /* CONFIG_P2P */
+
+ wpa_s->conf->changed_parameters = 0;
+}
+
+
+static void add_freq(int *freqs, int *num_freqs, int freq)
+{
+ int i;
+
+ for (i = 0; i < *num_freqs; i++) {
+ if (freqs[i] == freq)
+ return;
+ }
+
+ freqs[*num_freqs] = freq;
+ (*num_freqs)++;
+}
+
+
+static int * get_bss_freqs_in_ess(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_bss *bss, *cbss;
+ const int max_freqs = 10;
+ int *freqs;
+ int num_freqs = 0;
+
+ freqs = os_zalloc(sizeof(int) * (max_freqs + 1));
+ if (freqs == NULL)
+ return NULL;
+
+ cbss = wpa_s->current_bss;
+
+ dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+ if (bss == cbss)
+ continue;
+ if (bss->ssid_len == cbss->ssid_len &&
+ os_memcmp(bss->ssid, cbss->ssid, bss->ssid_len) == 0 &&
+ wpa_blacklist_get(wpa_s, bss->bssid) == NULL) {
+ add_freq(freqs, &num_freqs, bss->freq);
+ if (num_freqs == max_freqs)
+ break;
+ }
+ }
+
+ if (num_freqs == 0) {
+ os_free(freqs);
+ freqs = NULL;
+ }
+
+ return freqs;
+}
+
+
+void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+ int timeout;
+ int count;
+ int *freqs = NULL;
+
+ /*
+ * Remove possible authentication timeout since the connection failed.
+ */
+ eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
+
+ /*
+ * Add the failed BSSID into the blacklist and speed up next scan
+ * attempt if there could be other APs that could accept association.
+ * The current blacklist count indicates how many times we have tried
+ * connecting to this AP and multiple attempts mean that other APs are
+ * either not available or has already been tried, so that we can start
+ * increasing the delay here to avoid constant scanning.
+ */
+ count = wpa_blacklist_add(wpa_s, bssid);
+ if (count == 1 && wpa_s->current_bss) {
+ /*
+ * This BSS was not in the blacklist before. If there is
+ * another BSS available for the same ESS, we should try that
+ * next. Otherwise, we may as well try this one once more
+ * before allowing other, likely worse, ESSes to be considered.
+ */
+ freqs = get_bss_freqs_in_ess(wpa_s);
+ if (freqs) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Another BSS in this ESS "
+ "has been seen; try it next");
+ wpa_blacklist_add(wpa_s, bssid);
+ /*
+ * On the next scan, go through only the known channels
+ * used in this ESS based on previous scans to speed up
+ * common load balancing use case.
+ */
+ os_free(wpa_s->next_scan_freqs);
+ wpa_s->next_scan_freqs = freqs;
+ }
+ }
+
+ switch (count) {
+ case 1:
+ timeout = 100;
+ break;
+ case 2:
+ timeout = 500;
+ break;
+ case 3:
+ timeout = 1000;
+ break;
+ default:
+ timeout = 5000;
+ }
+
+ /*
+ * TODO: if more than one possible AP is available in scan results,
+ * could try the other ones before requesting a new scan.
+ */
+ wpa_supplicant_req_scan(wpa_s, timeout / 1000,
+ 1000 * (timeout % 1000));
+}
+
+
+int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s)
+{
+ return wpa_s->conf->ap_scan == 2 ||
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION);
+}