/*
* WPA Supplicant
- * Copyright (c) 2003-2011, 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
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*
* This file implements functions for registering and unregistering
* %wpa_supplicant interfaces. In addition, this file contains number of
#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 "p2p_supplicant.h"
#include "notify.h"
#include "bgscan.h"
+#include "autoscan.h"
#include "bss.h"
#include "scan.h"
#include "offchannel.h"
+#include "hs20_supplicant.h"
const char *wpa_supplicant_version =
"wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2011, 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"
}
+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);
+ autoscan_deinit(wpa_s);
scard_deinit(wpa_s->scard);
wpa_s->scard = NULL;
wpa_sm_set_scard_ctx(wpa_s->wpa, NULL);
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);
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);
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);
+
+ os_free(wpa_s->bssid_filter);
+ wpa_s->bssid_filter = NULL;
+
+ wnm_bss_keep_alive_deinit(wpa_s);
}
#endif /* CONFIG_BGSCAN */
+static void wpa_supplicant_start_autoscan(struct wpa_supplicant *wpa_s)
+{
+ if (autoscan_init(wpa_s))
+ wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize autoscan");
+}
+
+
+static void wpa_supplicant_stop_autoscan(struct wpa_supplicant *wpa_s)
+{
+ autoscan_deinit(wpa_s);
+}
+
+
/**
* wpa_supplicant_set_state - Set current connection state
* @wpa_s: Pointer to wpa_supplicant data
#ifdef CONFIG_P2P
wpas_p2p_completed(wpa_s);
#endif /* CONFIG_P2P */
+
+ sme_sched_obss_scan(wpa_s, 1);
} else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
state == WPA_ASSOCIATED) {
wpa_s->new_connection = 1;
#ifndef IEEE8021X_EAPOL
wpa_drv_set_supp_port(wpa_s, 0);
#endif /* IEEE8021X_EAPOL */
+ sme_sched_obss_scan(wpa_s, 0);
}
wpa_s->wpa_state = state;
wpa_supplicant_stop_bgscan(wpa_s);
#endif /* CONFIG_BGSCAN */
+ if (state == WPA_AUTHENTICATING)
+ wpa_supplicant_stop_autoscan(wpa_s);
+
+ if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
+ wpa_supplicant_start_autoscan(wpa_s);
+
if (wpa_s->wpa_state != old_state) {
wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
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);
}
wpa_supplicant_update_config(wpa_s);
wpa_supplicant_clear_status(wpa_s);
- if (wpa_supplicant_enabled_networks(wpa_s->conf)) {
+ if (wpa_supplicant_enabled_networks(wpa_s)) {
wpa_s->reassociate = 1;
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
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);
#ifndef CONFIG_NO_PBKDF2
if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
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 */
#ifdef CONFIG_IBSS_RSN
ibss_rsn_deinit(wpa_s->ibss_rsn);
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
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);
"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)) {
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);
+ res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len,
+ ssid->p2p_group);
if (res >= 0)
wpa_ie_len += res;
}
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_HS20
+ if (wpa_s->conf->hs20) {
+ struct wpabuf *hs20;
+ hs20 = wpabuf_alloc(20);
+ if (hs20) {
+ wpas_hs20_add_indication(hs20);
+ os_memcpy(wpa_ie + wpa_ie_len, wpabuf_head(hs20),
+ wpabuf_len(hs20));
+ wpa_ie_len += wpabuf_len(hs20);
+ wpabuf_free(hs20);
+ }
+ }
+#endif /* CONFIG_HS20 */
+
+#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;
cipher_pairwise = cipher_suite2driver(wpa_s->pairwise_cipher);
if (bss) {
params.ssid = bss->ssid;
params.ssid_len = bss->ssid_len;
- if (!wpas_driver_bss_selection(wpa_s)) {
+ if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) {
+ wpa_printf(MSG_DEBUG, "Limit connection to BSSID "
+ MACSTR " freq=%u MHz based on scan results "
+ "(bssid_set=%d)",
+ MAC2STR(bss->bssid), bss->freq,
+ ssid->bssid_set);
params.bssid = bss->bssid;
params.freq = bss->freq;
}
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.wpa_proto = wpa_s->wpa_proto;
params.auth_alg = algs;
params.mode = ssid->mode;
+ params.bg_scan_period = ssid->bg_scan_period;
for (i = 0; i < NUM_WEP_KEYS; i++) {
if (ssid->wep_key_len[i])
params.wep_key[i] = ssid->wep_key[i];
else
params.uapsd = -1;
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
- ret = ieee80211_sta_associate(wpa_s, ¶ms);
- else
- ret = wpa_drv_associate(wpa_s, ¶ms);
+#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");
* succeed.
*/
wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+ wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
return;
}
int reason_code)
{
u8 *addr = NULL;
+ union wpa_event_data event;
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;
+ os_memset(&event, 0, sizeof(event));
+ event.disassoc_info.reason_code = (u16) reason_code;
+ event.disassoc_info.locally_generated = 1;
+ wpa_supplicant_event(wpa_s, EVENT_DISASSOC, &event);
}
wpa_supplicant_clear_connection(wpa_s, addr);
int reason_code)
{
u8 *addr = NULL;
+ union wpa_event_data event;
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;
+ os_memset(&event, 0, sizeof(event));
+ event.deauth_info.reason_code = (u16) reason_code;
+ event.deauth_info.locally_generated = 1;
+ wpa_supplicant_event(wpa_s, EVENT_DEAUTH, &event);
}
wpa_supplicant_clear_connection(wpa_s, addr);
{
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
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_scan_interval - Set scan interval
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @scan_interval: scan interval in seconds
+ * Returns: 0 if succeed or -1 if scan_interval has an invalid value
+ *
+ */
+int wpa_supplicant_set_scan_interval(struct wpa_supplicant *wpa_s,
+ int scan_interval)
+{
+ if (scan_interval < 0) {
+ wpa_msg(wpa_s, MSG_ERROR, "Invalid scan interval %d",
+ scan_interval);
+ return -1;
+ }
+ wpa_msg(wpa_s, MSG_DEBUG, "Setting scan interval: %d sec",
+ scan_interval);
+ wpa_s->scan_interval = scan_interval;
+
+ return 0;
+}
+
+
+/**
* wpa_supplicant_set_debug_params - Set global debug params
* @global: wpa_global structure
* @debug_level: debug level
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_msg(wpa_s, MSG_WARNING, "Could not read SSID from "
- "MLME");
- return NULL;
- }
- } else {
- 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;
+ 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) {
+ if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
wpa_msg(wpa_s, MSG_WARNING, "Could not read BSSID from "
"driver");
return NULL;
entry = wpa_s->conf->ssid;
while (entry) {
- if (!entry->disabled &&
+ if (!wpas_network_disabled(wpa_s, entry) &&
((ssid_len == entry->ssid_len &&
os_memcmp(ssid, entry->ssid, ssid_len) == 0) || wired) &&
(!entry->bssid_set ||
os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
return entry;
#ifdef CONFIG_WPS
- if (!entry->disabled &&
+ if (!wpas_network_disabled(wpa_s, entry) &&
(entry->key_mgmt & WPA_KEY_MGMT_WPS) &&
(entry->ssid == NULL || entry->ssid_len == 0) &&
(!entry->bssid_set ||
return entry;
#endif /* CONFIG_WPS */
- if (!entry->disabled && entry->bssid_set &&
+ if (!wpas_network_disabled(wpa_s, entry) && entry->bssid_set &&
entry->ssid_len == 0 &&
os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)
return entry;
}
+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)
{
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);
}
do {
if (os_strlen(wpa_drivers[i]->name) == len &&
os_strncmp(driver, 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;
+ /* First driver that succeeds wins */
+ if (select_driver(wpa_s, i) == 0)
+ 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)
+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 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_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;
+}
+
+
+static void wpa_supplicant_rx_eapol_bridge(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ const struct l2_ethhdr *eth;
+
+ if (len < sizeof(*eth))
+ return;
+ eth = (const struct l2_ethhdr *) buf;
+
+ if (os_memcmp(eth->h_dest, wpa_s->own_addr, ETH_ALEN) != 0 &&
+ !(eth->h_dest[0] & 0x01)) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " to " MACSTR
+ " (bridge - not for this interface - ignore)",
+ MAC2STR(src_addr), MAC2STR(eth->h_dest));
+ return;
+ }
+
+ wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " to " MACSTR
+ " (bridge)", MAC2STR(src_addr), MAC2STR(eth->h_dest));
+ wpa_supplicant_rx_eapol(wpa_s, src_addr, buf + sizeof(*eth),
+ len - sizeof(*eth));
+}
+
+
+/**
+ * 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_dbg(wpa_s, MSG_DEBUG, "Receiving packets from bridge "
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);
+ wpa_supplicant_rx_eapol_bridge,
+ wpa_s, 1);
if (wpa_s->l2_br == NULL) {
wpa_msg(wpa_s, MSG_ERROR, "Failed to open l2_packet "
"connection for the bridge interface '%s'",
wpa_drv_flush_pmkid(wpa_s);
wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
- if (wpa_supplicant_enabled_networks(wpa_s->conf)) {
- wpa_supplicant_req_scan(wpa_s, interface_count, 100000);
+ wpa_s->prev_scan_wildcard = 0;
+
+ if (wpa_supplicant_enabled_networks(wpa_s)) {
+ 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);
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 pcsc_reader_init(struct wpa_supplicant *wpa_s)
+{
+#ifdef PCSC_FUNCS
+ size_t len;
+
+ if (!wpa_s->conf->pcsc_reader)
+ return 0;
+
+ wpa_s->scard = scard_init(SCARD_TRY_BOTH, wpa_s->conf->pcsc_reader);
+ if (!wpa_s->scard)
+ return 1;
+
+ if (wpa_s->conf->pcsc_pin &&
+ scard_set_pin(wpa_s->scard, wpa_s->conf->pcsc_pin) < 0) {
+ scard_deinit(wpa_s->scard);
+ wpa_s->scard = NULL;
+ wpa_msg(wpa_s, MSG_ERROR, "PC/SC PIN validation failed");
+ return -1;
+ }
+
+ len = sizeof(wpa_s->imsi) - 1;
+ if (scard_get_imsi(wpa_s->scard, wpa_s->imsi, &len)) {
+ scard_deinit(wpa_s->scard);
+ wpa_s->scard = NULL;
+ wpa_msg(wpa_s, MSG_ERROR, "Could not read IMSI");
+ return -1;
+ }
+ wpa_s->imsi[len] = '\0';
+
+ wpa_s->mnc_len = scard_get_mnc_len(wpa_s->scard);
+
+ wpa_printf(MSG_DEBUG, "SCARD: IMSI %s (MNC length %d)",
+ wpa_s->imsi, wpa_s->mnc_len);
+
+ wpa_sm_set_scard_ctx(wpa_s->wpa, wpa_s->scard);
+ eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
+#endif /* PCSC_FUNCS */
+
+ return 0;
+}
+
+
static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
struct wpa_interface *iface)
{
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->drv_enc = capa.enc;
+ 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;
}
return -1;
}
- wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
-
if (wpas_wps_init(wpa_s))
return -1;
if (wpa_bss_init(wpa_s) < 0)
return -1;
+ if (pcsc_reader_init(wpa_s) < 0)
+ return -1;
+
return 0;
}
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 (notify)
- wpas_notify_iface_removed(wpa_s);
+#ifdef CONFIG_P2P
+ if (wpa_s == wpa_s->global->p2p_init_wpa_s && wpa_s->global->p2p) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Disable P2P since removing "
+ "the management interface is being removed");
+ wpas_p2p_deinit_global(wpa_s->global);
+ }
+#endif /* CONFIG_P2P */
if (wpa_s->drv_priv)
wpa_drv_deinit(wpa_s);
+
+ if (notify)
+ wpas_notify_iface_removed(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_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;
if (global->p2p_group_formation == wpa_s)
global->p2p_group_formation = NULL;
- wpa_supplicant_deinit_iface(wpa_s, 1);
+ wpa_supplicant_deinit_iface(wpa_s, 1, terminate);
os_free(wpa_s);
return 0;
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();
+ if (params->wpa_debug_tracing) {
+ ret = wpa_debug_open_linux_tracing();
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "Failed to enable trace logging");
+ return NULL;
+ }
+ }
ret = eap_register_methods();
if (ret) {
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;
}
#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->params.override_driver);
os_free(global->params.override_ctrl_interface);
+ os_free(global->p2p_disallow_freq);
+
os_free(global);
wpa_debug_close_syslog();
wpa_debug_close_file();
+ wpa_debug_close_linux_tracing();
}
}
-void ieee80211_sta_free_hw_features(struct hostapd_hw_modes *hw_features,
- size_t num_hw_features)
-{
- size_t i;
-
- if (hw_features == NULL)
- return;
-
- for (i = 0; i < num_hw_features; i++) {
- os_free(hw_features[i].channels);
- os_free(hw_features[i].rates);
- }
-
- os_free(hw_features);
-}
-
-
static void add_freq(int *freqs, int *num_freqs, int freq)
{
int i;
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
return wpa_s->conf->ap_scan == 2 ||
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION);
}
+
+
+#if defined(CONFIG_CTRL_IFACE) || defined(CONFIG_CTRL_IFACE_DBUS_NEW)
+int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ const char *field,
+ const char *value)
+{
+#ifdef IEEE8021X_EAPOL
+ struct eap_peer_config *eap = &ssid->eap;
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: response handle field=%s", field);
+ wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: response value",
+ (const u8 *) value, os_strlen(value));
+
+ switch (wpa_supplicant_ctrl_req_from_string(field)) {
+ case WPA_CTRL_REQ_EAP_IDENTITY:
+ os_free(eap->identity);
+ eap->identity = (u8 *) os_strdup(value);
+ eap->identity_len = os_strlen(value);
+ eap->pending_req_identity = 0;
+ if (ssid == wpa_s->current_ssid)
+ wpa_s->reassociate = 1;
+ break;
+ case WPA_CTRL_REQ_EAP_PASSWORD:
+ os_free(eap->password);
+ eap->password = (u8 *) os_strdup(value);
+ eap->password_len = os_strlen(value);
+ eap->pending_req_password = 0;
+ if (ssid == wpa_s->current_ssid)
+ wpa_s->reassociate = 1;
+ break;
+ case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
+ os_free(eap->new_password);
+ eap->new_password = (u8 *) os_strdup(value);
+ eap->new_password_len = os_strlen(value);
+ eap->pending_req_new_password = 0;
+ if (ssid == wpa_s->current_ssid)
+ wpa_s->reassociate = 1;
+ break;
+ case WPA_CTRL_REQ_EAP_PIN:
+ os_free(eap->pin);
+ eap->pin = os_strdup(value);
+ eap->pending_req_pin = 0;
+ if (ssid == wpa_s->current_ssid)
+ wpa_s->reassociate = 1;
+ break;
+ case WPA_CTRL_REQ_EAP_OTP:
+ os_free(eap->otp);
+ eap->otp = (u8 *) os_strdup(value);
+ eap->otp_len = os_strlen(value);
+ os_free(eap->pending_req_otp);
+ eap->pending_req_otp = NULL;
+ eap->pending_req_otp_len = 0;
+ break;
+ case WPA_CTRL_REQ_EAP_PASSPHRASE:
+ os_free(eap->private_key_passwd);
+ eap->private_key_passwd = (u8 *) os_strdup(value);
+ eap->pending_req_passphrase = 0;
+ if (ssid == wpa_s->current_ssid)
+ wpa_s->reassociate = 1;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field);
+ return -1;
+ }
+
+ return 0;
+#else /* IEEE8021X_EAPOL */
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: IEEE 802.1X not included");
+ return -1;
+#endif /* IEEE8021X_EAPOL */
+}
+#endif /* CONFIG_CTRL_IFACE || CONFIG_CTRL_IFACE_DBUS_NEW */
+
+
+int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+ int i;
+ unsigned int drv_enc;
+
+ if (ssid == NULL)
+ return 1;
+
+ if (ssid->disabled)
+ return 1;
+
+ if (wpa_s && wpa_s->drv_capa_known)
+ drv_enc = wpa_s->drv_enc;
+ else
+ drv_enc = (unsigned int) -1;
+
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ size_t len = ssid->wep_key_len[i];
+ if (len == 0)
+ continue;
+ if (len == 5 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP40))
+ continue;
+ if (len == 13 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP104))
+ continue;
+ if (len == 16 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP128))
+ continue;
+ return 1; /* invalid WEP key */
+ }
+
+ return 0;
+}
+
+
+int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->global->conc_pref == WPA_CONC_PREF_P2P)
+ return 1;
+ if (wpa_s->global->conc_pref == WPA_CONC_PREF_STA)
+ return 0;
+ return -1;
+}