2008-02-28 02:34:43 +01:00
|
|
|
/*
|
|
|
|
* WPA Supplicant - Driver event processing
|
2011-02-20 20:57:53 +01:00
|
|
|
* Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
|
2008-02-28 02:34:43 +01:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "includes.h"
|
|
|
|
|
|
|
|
#include "common.h"
|
|
|
|
#include "eapol_supp/eapol_supp_sm.h"
|
2009-11-29 17:28:08 +01:00
|
|
|
#include "rsn_supp/wpa.h"
|
2008-02-28 02:34:43 +01:00
|
|
|
#include "eloop.h"
|
|
|
|
#include "config.h"
|
|
|
|
#include "l2_packet/l2_packet.h"
|
|
|
|
#include "wpa_supplicant_i.h"
|
2009-03-26 19:37:05 +01:00
|
|
|
#include "driver_i.h"
|
2008-02-28 02:34:43 +01:00
|
|
|
#include "pcsc_funcs.h"
|
2009-11-29 17:28:08 +01:00
|
|
|
#include "rsn_supp/preauth.h"
|
|
|
|
#include "rsn_supp/pmksa_cache.h"
|
2009-11-29 16:51:55 +01:00
|
|
|
#include "common/wpa_ctrl.h"
|
2008-02-28 02:34:43 +01:00
|
|
|
#include "eap_peer/eap.h"
|
2010-01-03 17:22:22 +01:00
|
|
|
#include "ap/hostapd.h"
|
2010-10-19 11:47:33 +02:00
|
|
|
#include "p2p/p2p.h"
|
2009-09-13 19:53:32 +02:00
|
|
|
#include "notify.h"
|
2009-11-29 16:51:55 +01:00
|
|
|
#include "common/ieee802_11_defs.h"
|
2010-05-26 16:16:14 +02:00
|
|
|
#include "common/ieee802_11_common.h"
|
Maintain internal entropy pool for augmenting random number generation
By default, make hostapd and wpa_supplicant maintain an internal
entropy pool that is fed with following information:
hostapd:
- Probe Request frames (timing, RSSI)
- Association events (timing)
- SNonce from Supplicants
wpa_supplicant:
- Scan results (timing, signal/noise)
- Association events (timing)
The internal pool is used to augment the random numbers generated
with the OS mechanism (os_get_random()). While the internal
implementation is not expected to be very strong due to limited
amount of generic (non-platform specific) information to feed the
pool, this may strengthen key derivation on some devices that are
not configured to provide strong random numbers through
os_get_random() (e.g., /dev/urandom on Linux/BSD).
This new mechanism is not supposed to replace proper OS provided
random number generation mechanism. The OS mechanism needs to be
initialized properly (e.g., hw random number generator,
maintaining entropy pool over reboots, etc.) for any of the
security assumptions to hold.
If the os_get_random() is known to provide strong ramdom data (e.g., on
Linux/BSD, the board in question is known to have reliable source of
random data from /dev/urandom), the internal hostapd random pool can be
disabled. This will save some in binary size and CPU use. However, this
should only be considered for builds that are known to be used on
devices that meet the requirements described above. The internal pool
is disabled by adding CONFIG_NO_RANDOM_POOL=y to the .config file.
2010-11-24 00:29:40 +01:00
|
|
|
#include "crypto/random.h"
|
2008-02-28 02:34:43 +01:00
|
|
|
#include "blacklist.h"
|
|
|
|
#include "wpas_glue.h"
|
2008-11-29 21:06:34 +01:00
|
|
|
#include "wps_supplicant.h"
|
2009-01-15 00:21:55 +01:00
|
|
|
#include "ibss_rsn.h"
|
2009-03-20 21:26:41 +01:00
|
|
|
#include "sme.h"
|
2011-09-28 18:44:25 +02:00
|
|
|
#include "gas_query.h"
|
2010-07-18 23:30:25 +02:00
|
|
|
#include "p2p_supplicant.h"
|
2009-09-14 23:08:24 +02:00
|
|
|
#include "bgscan.h"
|
2009-12-13 22:05:39 +01:00
|
|
|
#include "ap.h"
|
2010-01-02 15:16:02 +01:00
|
|
|
#include "bss.h"
|
2010-01-03 17:48:11 +01:00
|
|
|
#include "scan.h"
|
2011-09-29 18:22:08 +02:00
|
|
|
#include "offchannel.h"
|
2008-02-28 02:34:43 +01:00
|
|
|
|
|
|
|
|
|
|
|
static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
|
|
|
|
{
|
2009-09-13 19:53:32 +02:00
|
|
|
struct wpa_ssid *ssid, *old_ssid;
|
2008-02-28 02:34:43 +01:00
|
|
|
|
|
|
|
if (wpa_s->conf->ap_scan == 1 && wpa_s->current_ssid)
|
|
|
|
return 0;
|
|
|
|
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Select network based on association "
|
|
|
|
"information");
|
2008-02-28 02:34:43 +01:00
|
|
|
ssid = wpa_supplicant_get_ssid(wpa_s);
|
|
|
|
if (ssid == NULL) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_msg(wpa_s, MSG_INFO,
|
|
|
|
"No network configuration found for the current AP");
|
2008-02-28 02:34:43 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ssid->disabled) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is disabled");
|
2008-02-28 02:34:43 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Network configuration found for the "
|
|
|
|
"current AP");
|
2008-02-28 02:34:43 +01:00
|
|
|
if (ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
|
|
|
|
WPA_KEY_MGMT_WPA_NONE |
|
2008-08-31 21:57:28 +02:00
|
|
|
WPA_KEY_MGMT_FT_PSK | WPA_KEY_MGMT_FT_IEEE8021X |
|
|
|
|
WPA_KEY_MGMT_PSK_SHA256 |
|
|
|
|
WPA_KEY_MGMT_IEEE8021X_SHA256)) {
|
2008-02-28 02:34:43 +01:00
|
|
|
u8 wpa_ie[80];
|
|
|
|
size_t wpa_ie_len = sizeof(wpa_ie);
|
|
|
|
wpa_supplicant_set_suites(wpa_s, NULL, ssid,
|
|
|
|
wpa_ie, &wpa_ie_len);
|
|
|
|
} else {
|
|
|
|
wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wpa_s->current_ssid && wpa_s->current_ssid != ssid)
|
|
|
|
eapol_sm_invalidate_cached_session(wpa_s->eapol);
|
2009-09-13 19:53:32 +02:00
|
|
|
old_ssid = wpa_s->current_ssid;
|
2008-02-28 02:34:43 +01:00
|
|
|
wpa_s->current_ssid = ssid;
|
|
|
|
wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
|
|
|
|
wpa_supplicant_initiate_eapol(wpa_s);
|
2009-09-13 19:53:32 +02:00
|
|
|
if (old_ssid != wpa_s->current_ssid)
|
|
|
|
wpas_notify_network_changed(wpa_s);
|
2008-02-28 02:34:43 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void wpa_supplicant_stop_countermeasures(void *eloop_ctx,
|
|
|
|
void *sock_ctx)
|
|
|
|
{
|
|
|
|
struct wpa_supplicant *wpa_s = eloop_ctx;
|
|
|
|
|
|
|
|
if (wpa_s->countermeasures) {
|
|
|
|
wpa_s->countermeasures = 0;
|
|
|
|
wpa_drv_set_countermeasures(wpa_s, 0);
|
|
|
|
wpa_msg(wpa_s, MSG_INFO, "WPA: TKIP countermeasures stopped");
|
|
|
|
wpa_supplicant_req_scan(wpa_s, 0, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
|
|
|
|
{
|
2009-09-13 19:53:32 +02:00
|
|
|
int bssid_changed;
|
|
|
|
|
2011-03-23 20:15:46 +01:00
|
|
|
#ifdef CONFIG_IBSS_RSN
|
|
|
|
ibss_rsn_deinit(wpa_s->ibss_rsn);
|
|
|
|
wpa_s->ibss_rsn = NULL;
|
|
|
|
#endif /* CONFIG_IBSS_RSN */
|
|
|
|
|
2011-07-05 15:38:30 +02:00
|
|
|
#ifdef CONFIG_AP
|
|
|
|
wpa_supplicant_ap_deinit(wpa_s);
|
|
|
|
#endif /* CONFIG_AP */
|
|
|
|
|
2010-05-23 09:27:32 +02:00
|
|
|
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
|
|
|
|
return;
|
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
|
2009-09-13 19:53:32 +02:00
|
|
|
bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
|
2008-02-28 02:34:43 +01:00
|
|
|
os_memset(wpa_s->bssid, 0, ETH_ALEN);
|
|
|
|
os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
|
2010-02-27 17:40:25 +01:00
|
|
|
wpa_s->current_bss = NULL;
|
2010-11-25 15:04:07 +01:00
|
|
|
wpa_s->assoc_freq = 0;
|
2011-07-05 20:17:31 +02:00
|
|
|
#ifdef CONFIG_IEEE80211R
|
|
|
|
#ifdef CONFIG_SME
|
|
|
|
if (wpa_s->sme.ft_ies)
|
|
|
|
sme_update_ft_ies(wpa_s, NULL, NULL, 0);
|
|
|
|
#endif /* CONFIG_SME */
|
|
|
|
#endif /* CONFIG_IEEE80211R */
|
|
|
|
|
2009-09-13 19:53:32 +02:00
|
|
|
if (bssid_changed)
|
|
|
|
wpas_notify_bssid_changed(wpa_s);
|
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
|
|
|
|
eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
|
2008-08-31 21:57:28 +02:00
|
|
|
if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt))
|
2008-02-28 02:34:43 +01:00
|
|
|
eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
|
|
|
|
wpa_s->ap_ies_from_associnfo = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void wpa_find_assoc_pmkid(struct wpa_supplicant *wpa_s)
|
|
|
|
{
|
|
|
|
struct wpa_ie_data ie;
|
|
|
|
int pmksa_set = -1;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (wpa_sm_parse_own_wpa_ie(wpa_s->wpa, &ie) < 0 ||
|
|
|
|
ie.pmkid == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (i = 0; i < ie.num_pmkid; i++) {
|
|
|
|
pmksa_set = pmksa_cache_set_current(wpa_s->wpa,
|
|
|
|
ie.pmkid + i * PMKID_LEN,
|
|
|
|
NULL, NULL, 0);
|
|
|
|
if (pmksa_set == 0) {
|
|
|
|
eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "RSN: PMKID from assoc IE %sfound from "
|
|
|
|
"PMKSA cache", pmksa_set == 0 ? "" : "not ");
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void wpa_supplicant_event_pmkid_candidate(struct wpa_supplicant *wpa_s,
|
|
|
|
union wpa_event_data *data)
|
|
|
|
{
|
|
|
|
if (data == NULL) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "RSN: No data in PMKID candidate "
|
|
|
|
"event");
|
2008-02-28 02:34:43 +01:00
|
|
|
return;
|
|
|
|
}
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "RSN: PMKID candidate event - bssid=" MACSTR
|
|
|
|
" index=%d preauth=%d",
|
|
|
|
MAC2STR(data->pmkid_candidate.bssid),
|
|
|
|
data->pmkid_candidate.index,
|
|
|
|
data->pmkid_candidate.preauth);
|
2008-02-28 02:34:43 +01:00
|
|
|
|
|
|
|
pmksa_candidate_add(wpa_s->wpa, data->pmkid_candidate.bssid,
|
|
|
|
data->pmkid_candidate.index,
|
|
|
|
data->pmkid_candidate.preauth);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int wpa_supplicant_dynamic_keys(struct wpa_supplicant *wpa_s)
|
|
|
|
{
|
|
|
|
if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
|
|
|
|
wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
#ifdef IEEE8021X_EAPOL
|
|
|
|
if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
|
|
|
|
wpa_s->current_ssid &&
|
|
|
|
!(wpa_s->current_ssid->eapol_flags &
|
|
|
|
(EAPOL_FLAG_REQUIRE_KEY_UNICAST |
|
|
|
|
EAPOL_FLAG_REQUIRE_KEY_BROADCAST))) {
|
|
|
|
/* IEEE 802.1X, but not using dynamic WEP keys (i.e., either
|
|
|
|
* plaintext or static WEP keys). */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif /* IEEE8021X_EAPOL */
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* wpa_supplicant_scard_init - Initialize SIM/USIM access with PC/SC
|
|
|
|
* @wpa_s: pointer to wpa_supplicant data
|
|
|
|
* @ssid: Configuration data for the network
|
|
|
|
* Returns: 0 on success, -1 on failure
|
|
|
|
*
|
|
|
|
* This function is called when starting authentication with a network that is
|
|
|
|
* configured to use PC/SC for SIM/USIM access (EAP-SIM or EAP-AKA).
|
|
|
|
*/
|
|
|
|
int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
|
|
|
|
struct wpa_ssid *ssid)
|
|
|
|
{
|
|
|
|
#ifdef IEEE8021X_EAPOL
|
2011-10-23 11:24:36 +02:00
|
|
|
#ifdef PCSC_FUNCS
|
2008-02-28 02:34:43 +01:00
|
|
|
int aka = 0, sim = 0, type;
|
|
|
|
|
|
|
|
if (ssid->eap.pcsc == NULL || wpa_s->scard != NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (ssid->eap.eap_methods == NULL) {
|
|
|
|
sim = 1;
|
|
|
|
aka = 1;
|
|
|
|
} else {
|
|
|
|
struct eap_method_type *eap = ssid->eap.eap_methods;
|
|
|
|
while (eap->vendor != EAP_VENDOR_IETF ||
|
|
|
|
eap->method != EAP_TYPE_NONE) {
|
|
|
|
if (eap->vendor == EAP_VENDOR_IETF) {
|
|
|
|
if (eap->method == EAP_TYPE_SIM)
|
|
|
|
sim = 1;
|
|
|
|
else if (eap->method == EAP_TYPE_AKA)
|
|
|
|
aka = 1;
|
|
|
|
}
|
|
|
|
eap++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (eap_peer_get_eap_method(EAP_VENDOR_IETF, EAP_TYPE_SIM) == NULL)
|
|
|
|
sim = 0;
|
|
|
|
if (eap_peer_get_eap_method(EAP_VENDOR_IETF, EAP_TYPE_AKA) == NULL)
|
|
|
|
aka = 0;
|
|
|
|
|
|
|
|
if (!sim && !aka) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is configured to "
|
|
|
|
"use SIM, but neither EAP-SIM nor EAP-AKA are "
|
|
|
|
"enabled");
|
2008-02-28 02:34:43 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is configured to use SIM "
|
|
|
|
"(sim=%d aka=%d) - initialize PCSC", sim, aka);
|
2008-02-28 02:34:43 +01:00
|
|
|
if (sim && aka)
|
|
|
|
type = SCARD_TRY_BOTH;
|
|
|
|
else if (aka)
|
|
|
|
type = SCARD_USIM_ONLY;
|
|
|
|
else
|
|
|
|
type = SCARD_GSM_SIM_ONLY;
|
|
|
|
|
|
|
|
wpa_s->scard = scard_init(type);
|
|
|
|
if (wpa_s->scard == NULL) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_msg(wpa_s, MSG_WARNING, "Failed to initialize SIM "
|
|
|
|
"(pcsc-lite)");
|
2008-02-28 02:34:43 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
wpa_sm_set_scard_ctx(wpa_s->wpa, wpa_s->scard);
|
|
|
|
eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
|
2011-10-23 11:24:36 +02:00
|
|
|
#endif /* PCSC_FUNCS */
|
2008-02-28 02:34:43 +01:00
|
|
|
#endif /* IEEE8021X_EAPOL */
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef CONFIG_NO_SCAN_PROCESSING
|
|
|
|
static int wpa_supplicant_match_privacy(struct wpa_scan_res *bss,
|
|
|
|
struct wpa_ssid *ssid)
|
|
|
|
{
|
|
|
|
int i, privacy = 0;
|
|
|
|
|
|
|
|
if (ssid->mixed_cell)
|
|
|
|
return 1;
|
|
|
|
|
2009-02-17 09:17:24 +01:00
|
|
|
#ifdef CONFIG_WPS
|
|
|
|
if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
|
|
|
|
return 1;
|
|
|
|
#endif /* CONFIG_WPS */
|
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
for (i = 0; i < NUM_WEP_KEYS; i++) {
|
|
|
|
if (ssid->wep_key_len[i]) {
|
|
|
|
privacy = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef IEEE8021X_EAPOL
|
|
|
|
if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
|
|
|
|
ssid->eapol_flags & (EAPOL_FLAG_REQUIRE_KEY_UNICAST |
|
|
|
|
EAPOL_FLAG_REQUIRE_KEY_BROADCAST))
|
|
|
|
privacy = 1;
|
|
|
|
#endif /* IEEE8021X_EAPOL */
|
|
|
|
|
2011-06-23 14:39:00 +02:00
|
|
|
if (wpa_key_mgmt_wpa(ssid->key_mgmt))
|
|
|
|
privacy = 1;
|
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
if (bss->caps & IEEE80211_CAP_PRIVACY)
|
|
|
|
return privacy;
|
|
|
|
return !privacy;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-23 12:10:58 +01:00
|
|
|
static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
|
|
|
|
struct wpa_ssid *ssid,
|
2008-02-28 02:34:43 +01:00
|
|
|
struct wpa_scan_res *bss)
|
|
|
|
{
|
|
|
|
struct wpa_ie_data ie;
|
|
|
|
int proto_match = 0;
|
|
|
|
const u8 *rsn_ie, *wpa_ie;
|
2008-11-29 21:06:34 +01:00
|
|
|
int ret;
|
2010-11-08 20:14:32 +01:00
|
|
|
int wep_ok;
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2009-01-23 12:10:58 +01:00
|
|
|
ret = wpas_wps_ssid_bss_match(wpa_s, ssid, bss);
|
2008-11-29 21:06:34 +01:00
|
|
|
if (ret >= 0)
|
|
|
|
return ret;
|
2008-11-23 18:34:26 +01:00
|
|
|
|
2010-11-08 20:14:32 +01:00
|
|
|
/* Allow TSN if local configuration accepts WEP use without WPA/WPA2 */
|
|
|
|
wep_ok = !wpa_key_mgmt_wpa(ssid->key_mgmt) &&
|
|
|
|
(((ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
|
|
|
|
ssid->wep_key_len[ssid->wep_tx_keyidx] > 0) ||
|
|
|
|
(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA));
|
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
rsn_ie = wpa_scan_get_ie(bss, WLAN_EID_RSN);
|
|
|
|
while ((ssid->proto & WPA_PROTO_RSN) && rsn_ie) {
|
|
|
|
proto_match++;
|
|
|
|
|
|
|
|
if (wpa_parse_wpa_ie(rsn_ie, 2 + rsn_ie[1], &ie)) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - parse "
|
|
|
|
"failed");
|
2008-02-28 02:34:43 +01:00
|
|
|
break;
|
|
|
|
}
|
2010-11-08 20:14:32 +01:00
|
|
|
|
|
|
|
if (wep_ok &&
|
|
|
|
(ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
|
|
|
|
{
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " selected based on TSN "
|
|
|
|
"in RSN IE");
|
2010-11-08 20:14:32 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
if (!(ie.proto & ssid->proto)) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - proto "
|
|
|
|
"mismatch");
|
2008-02-28 02:34:43 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - PTK "
|
|
|
|
"cipher mismatch");
|
2008-02-28 02:34:43 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(ie.group_cipher & ssid->group_cipher)) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - GTK "
|
|
|
|
"cipher mismatch");
|
2008-02-28 02:34:43 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(ie.key_mgmt & ssid->key_mgmt)) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - key mgmt "
|
|
|
|
"mismatch");
|
2008-02-28 02:34:43 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_IEEE80211W
|
2008-08-30 13:59:39 +02:00
|
|
|
if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
|
2010-01-03 20:02:51 +01:00
|
|
|
ssid->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - no mgmt "
|
|
|
|
"frame protection");
|
2008-02-28 02:34:43 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_IEEE80211W */
|
|
|
|
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " selected based on RSN IE");
|
2008-02-28 02:34:43 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
wpa_ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
|
|
|
|
while ((ssid->proto & WPA_PROTO_WPA) && wpa_ie) {
|
|
|
|
proto_match++;
|
|
|
|
|
|
|
|
if (wpa_parse_wpa_ie(wpa_ie, 2 + wpa_ie[1], &ie)) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - parse "
|
|
|
|
"failed");
|
2008-02-28 02:34:43 +01:00
|
|
|
break;
|
|
|
|
}
|
2010-11-08 20:14:32 +01:00
|
|
|
|
|
|
|
if (wep_ok &&
|
|
|
|
(ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
|
|
|
|
{
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " selected based on TSN "
|
|
|
|
"in WPA IE");
|
2010-11-08 20:14:32 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
if (!(ie.proto & ssid->proto)) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - proto "
|
|
|
|
"mismatch");
|
2008-02-28 02:34:43 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - PTK "
|
|
|
|
"cipher mismatch");
|
2008-02-28 02:34:43 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(ie.group_cipher & ssid->group_cipher)) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - GTK "
|
|
|
|
"cipher mismatch");
|
2008-02-28 02:34:43 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(ie.key_mgmt & ssid->key_mgmt)) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " skip WPA IE - key mgmt "
|
|
|
|
"mismatch");
|
2008-02-28 02:34:43 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " selected based on WPA IE");
|
2008-02-28 02:34:43 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2010-12-28 07:56:23 +01:00
|
|
|
if ((ssid->proto & (WPA_PROTO_WPA | WPA_PROTO_RSN)) &&
|
2010-12-30 17:27:33 +01:00
|
|
|
wpa_key_mgmt_wpa(ssid->key_mgmt) && proto_match == 0) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " skip - no WPA/RSN proto match");
|
2010-12-28 07:56:23 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2011-04-08 18:13:58 +02:00
|
|
|
if (!wpa_key_mgmt_wpa(ssid->key_mgmt)) {
|
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " allow in non-WPA/WPA2");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " reject due to mismatch with "
|
|
|
|
"WPA/WPA2");
|
|
|
|
|
|
|
|
return 0;
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-27 06:45:50 +01:00
|
|
|
static int freq_allowed(int *freqs, int freq)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (freqs == NULL)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
for (i = 0; freqs[i]; i++)
|
|
|
|
if (freqs[i] == freq)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-10-23 10:58:54 +02:00
|
|
|
static int ht_supported(const struct hostapd_hw_modes *mode)
|
|
|
|
{
|
|
|
|
if (!(mode->flags & HOSTAPD_MODE_FLAG_HT_INFO_KNOWN)) {
|
|
|
|
/*
|
|
|
|
* The driver did not indicate whether it supports HT. Assume
|
|
|
|
* it does to avoid connection issues.
|
|
|
|
*/
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* IEEE Std 802.11n-2009 20.1.1:
|
|
|
|
* An HT non-AP STA shall support all EQM rates for one spatial stream.
|
|
|
|
*/
|
|
|
|
return mode->mcs_set[0] == 0xff;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_scan_res *bss)
|
|
|
|
{
|
|
|
|
const struct hostapd_hw_modes *mode = NULL, *modes;
|
|
|
|
const u8 scan_ie[2] = { WLAN_EID_SUPP_RATES, WLAN_EID_EXT_SUPP_RATES };
|
|
|
|
const u8 *rate_ie;
|
|
|
|
int i, j, k;
|
|
|
|
|
|
|
|
modes = wpa_s->hw.modes;
|
|
|
|
if (modes == NULL) {
|
|
|
|
/*
|
|
|
|
* The driver does not provide any additional information
|
|
|
|
* about the utilized hardware, so allow the connection attempt
|
|
|
|
* to continue.
|
|
|
|
*/
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < wpa_s->hw.num_modes; i++) {
|
|
|
|
for (j = 0; j < modes[i].num_channels; j++) {
|
|
|
|
int freq = modes[i].channels[j].freq;
|
|
|
|
if (freq == bss->freq) {
|
|
|
|
if (mode &&
|
|
|
|
mode->mode == HOSTAPD_MODE_IEEE80211G)
|
|
|
|
break; /* do not allow 802.11b replace
|
|
|
|
* 802.11g */
|
|
|
|
mode = &modes[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mode == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (i = 0; i < (int) sizeof(scan_ie); i++) {
|
|
|
|
rate_ie = wpa_scan_get_ie(bss, scan_ie[i]);
|
|
|
|
if (rate_ie == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (j = 2; j < rate_ie[1] + 2; j++) {
|
|
|
|
int flagged = !!(rate_ie[j] & 0x80);
|
|
|
|
int r = (rate_ie[j] & 0x7f) * 5;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* IEEE Std 802.11n-2009 7.3.2.2:
|
|
|
|
* The new BSS Membership selector value is encoded
|
|
|
|
* like a legacy basic rate, but it is not a rate and
|
|
|
|
* only indicates if the BSS members are required to
|
|
|
|
* support the mandatory features of Clause 20 [HT PHY]
|
|
|
|
* in order to join the BSS.
|
|
|
|
*/
|
|
|
|
if (flagged && ((rate_ie[j] & 0x7f) ==
|
|
|
|
BSS_MEMBERSHIP_SELECTOR_HT_PHY)) {
|
|
|
|
if (!ht_supported(mode)) {
|
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG,
|
|
|
|
" hardware does not support "
|
|
|
|
"HT PHY");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!flagged)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* check for legacy basic rates */
|
|
|
|
for (k = 0; k < mode->num_rates; k++) {
|
|
|
|
if (mode->rates[k] == r)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (k == mode->num_rates) {
|
|
|
|
/*
|
|
|
|
* IEEE Std 802.11-2007 7.3.2.2 demands that in
|
|
|
|
* order to join a BSS all required rates
|
|
|
|
* have to be supported by the hardware.
|
|
|
|
*/
|
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " hardware does "
|
|
|
|
"not support required rate %d.%d Mbps",
|
|
|
|
r / 10, r % 10);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-08-27 19:05:49 +02:00
|
|
|
static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
|
|
|
|
int i, struct wpa_scan_res *bss,
|
|
|
|
struct wpa_ssid *group)
|
2008-02-28 02:34:43 +01:00
|
|
|
{
|
2010-08-27 19:05:49 +02:00
|
|
|
const u8 *ssid_;
|
|
|
|
u8 wpa_ie_len, rsn_ie_len, ssid_len;
|
|
|
|
int wpa;
|
2008-02-28 02:34:43 +01:00
|
|
|
struct wpa_blacklist *e;
|
|
|
|
const u8 *ie;
|
2010-08-27 19:05:49 +02:00
|
|
|
struct wpa_ssid *ssid;
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2010-08-27 19:05:49 +02:00
|
|
|
ie = wpa_scan_get_ie(bss, WLAN_EID_SSID);
|
|
|
|
ssid_ = ie ? ie + 2 : (u8 *) "";
|
|
|
|
ssid_len = ie ? ie[1] : 0;
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2010-08-27 19:05:49 +02:00
|
|
|
ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
|
|
|
|
wpa_ie_len = ie ? ie[1] : 0;
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2010-08-27 19:05:49 +02:00
|
|
|
ie = wpa_scan_get_ie(bss, WLAN_EID_RSN);
|
|
|
|
rsn_ie_len = ie ? ie[1] : 0;
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "%d: " MACSTR " ssid='%s' "
|
|
|
|
"wpa_ie_len=%u rsn_ie_len=%u caps=0x%x level=%d%s",
|
|
|
|
i, MAC2STR(bss->bssid), wpa_ssid_txt(ssid_, ssid_len),
|
|
|
|
wpa_ie_len, rsn_ie_len, bss->caps, bss->level,
|
|
|
|
wpa_scan_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE) ? " wps" : "");
|
2008-09-26 16:24:40 +02:00
|
|
|
|
2010-08-27 19:05:49 +02:00
|
|
|
e = wpa_blacklist_get(wpa_s, bss->bssid);
|
2010-11-26 10:23:50 +01:00
|
|
|
if (e) {
|
|
|
|
int limit = 1;
|
|
|
|
if (wpa_supplicant_enabled_networks(wpa_s->conf) == 1) {
|
|
|
|
/*
|
|
|
|
* When only a single network is enabled, we can
|
|
|
|
* trigger blacklisting on the first failure. This
|
|
|
|
* should not be done with multiple enabled networks to
|
|
|
|
* avoid getting forced to move into a worse ESS on
|
|
|
|
* single error if there are no other BSSes of the
|
|
|
|
* current ESS.
|
|
|
|
*/
|
|
|
|
limit = 0;
|
|
|
|
}
|
|
|
|
if (e->count > limit) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " skip - blacklisted "
|
|
|
|
"(count=%d limit=%d)", e->count, limit);
|
2011-04-08 18:16:20 +02:00
|
|
|
return NULL;
|
2010-11-26 10:23:50 +01:00
|
|
|
}
|
2010-08-27 19:05:49 +02:00
|
|
|
}
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2010-08-27 19:05:49 +02:00
|
|
|
if (ssid_len == 0) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID not known");
|
2011-04-08 18:16:20 +02:00
|
|
|
return NULL;
|
2010-08-27 19:05:49 +02:00
|
|
|
}
|
2009-10-15 20:58:58 +02:00
|
|
|
|
2010-08-27 19:05:49 +02:00
|
|
|
wpa = wpa_ie_len > 0 || rsn_ie_len > 0;
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2010-08-27 19:05:49 +02:00
|
|
|
for (ssid = group; ssid; ssid = ssid->pnext) {
|
|
|
|
int check_ssid = wpa ? 1 : (ssid->ssid_len != 0);
|
2008-11-23 18:34:26 +01:00
|
|
|
|
2010-08-27 19:05:49 +02:00
|
|
|
if (ssid->disabled) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled");
|
2010-08-28 11:04:21 +02:00
|
|
|
continue;
|
2010-08-27 19:05:49 +02:00
|
|
|
}
|
2008-09-26 16:24:40 +02:00
|
|
|
|
2008-11-23 18:34:26 +01:00
|
|
|
#ifdef CONFIG_WPS
|
2010-09-22 20:50:15 +02:00
|
|
|
if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && e && e->count > 0) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " skip - blacklisted "
|
|
|
|
"(WPS)");
|
2010-09-22 20:50:15 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2010-08-27 19:05:49 +02:00
|
|
|
if (wpa && ssid->ssid_len == 0 &&
|
|
|
|
wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss))
|
|
|
|
check_ssid = 0;
|
|
|
|
|
|
|
|
if (!wpa && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
|
|
|
|
/* Only allow wildcard SSID match if an AP
|
|
|
|
* advertises active WPS operation that matches
|
|
|
|
* with our mode. */
|
|
|
|
check_ssid = 1;
|
2008-11-23 18:34:26 +01:00
|
|
|
if (ssid->ssid_len == 0 &&
|
2009-01-23 12:10:58 +01:00
|
|
|
wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss))
|
2008-11-23 18:34:26 +01:00
|
|
|
check_ssid = 0;
|
2010-08-27 19:05:49 +02:00
|
|
|
}
|
2008-11-23 18:34:26 +01:00
|
|
|
#endif /* CONFIG_WPS */
|
|
|
|
|
2011-09-30 21:01:42 +02:00
|
|
|
if (ssid->bssid_set && ssid->ssid_len == 0 &&
|
|
|
|
os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) == 0)
|
|
|
|
check_ssid = 0;
|
|
|
|
|
2010-08-27 19:05:49 +02:00
|
|
|
if (check_ssid &&
|
|
|
|
(ssid_len != ssid->ssid_len ||
|
|
|
|
os_memcmp(ssid_, ssid->ssid, ssid_len) != 0)) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " skip - SSID mismatch");
|
2010-08-28 11:04:21 +02:00
|
|
|
continue;
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
|
|
|
|
2010-08-27 19:05:49 +02:00
|
|
|
if (ssid->bssid_set &&
|
|
|
|
os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " skip - BSSID mismatch");
|
2010-08-28 11:04:21 +02:00
|
|
|
continue;
|
2010-08-27 19:05:49 +02:00
|
|
|
}
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2010-12-28 07:56:23 +01:00
|
|
|
if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss))
|
2010-08-28 11:04:21 +02:00
|
|
|
continue;
|
2008-09-26 16:24:40 +02:00
|
|
|
|
2010-08-27 19:05:49 +02:00
|
|
|
if (!wpa &&
|
|
|
|
!(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
|
|
|
|
!(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
|
|
|
|
!(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " skip - non-WPA network "
|
|
|
|
"not allowed");
|
2010-08-28 11:04:21 +02:00
|
|
|
continue;
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
2008-09-26 16:24:40 +02:00
|
|
|
|
2011-06-23 14:39:00 +02:00
|
|
|
if (!wpa_supplicant_match_privacy(bss, ssid)) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " skip - privacy "
|
|
|
|
"mismatch");
|
2010-08-28 11:04:21 +02:00
|
|
|
continue;
|
2009-10-15 20:58:58 +02:00
|
|
|
}
|
|
|
|
|
2011-06-23 14:39:00 +02:00
|
|
|
if (bss->caps & IEEE80211_CAP_IBSS) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " skip - IBSS (adhoc) "
|
|
|
|
"network");
|
2010-08-28 11:04:21 +02:00
|
|
|
continue;
|
2010-08-27 19:05:49 +02:00
|
|
|
}
|
2010-03-27 06:45:50 +01:00
|
|
|
|
2010-08-27 19:05:49 +02:00
|
|
|
if (!freq_allowed(ssid->freq_list, bss->freq)) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " skip - frequency not "
|
|
|
|
"allowed");
|
2010-08-28 11:04:21 +02:00
|
|
|
continue;
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
2010-08-27 19:05:49 +02:00
|
|
|
|
2011-10-23 10:58:54 +02:00
|
|
|
if (!rate_match(wpa_s, bss)) {
|
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " skip - rate sets do "
|
|
|
|
"not match");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2010-07-18 23:30:25 +02:00
|
|
|
#ifdef CONFIG_P2P
|
|
|
|
/*
|
|
|
|
* TODO: skip the AP if its P2P IE has Group Formation
|
|
|
|
* bit set in the P2P Group Capability Bitmap and we
|
|
|
|
* are not in Group Formation with that device.
|
|
|
|
*/
|
|
|
|
#endif /* CONFIG_P2P */
|
|
|
|
|
2010-08-27 19:05:49 +02:00
|
|
|
/* Matching configuration found */
|
|
|
|
return ssid;
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
|
|
|
|
2010-08-27 19:05:49 +02:00
|
|
|
/* No matching configuration found */
|
2011-04-08 18:16:20 +02:00
|
|
|
return NULL;
|
2008-09-26 16:24:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-02 15:16:02 +01:00
|
|
|
static struct wpa_bss *
|
2010-01-02 15:41:38 +01:00
|
|
|
wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s,
|
|
|
|
struct wpa_scan_results *scan_res,
|
|
|
|
struct wpa_ssid *group,
|
2008-09-26 16:24:40 +02:00
|
|
|
struct wpa_ssid **selected_ssid)
|
|
|
|
{
|
2010-08-27 19:05:49 +02:00
|
|
|
size_t i;
|
2008-09-26 16:24:40 +02:00
|
|
|
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Selecting BSS from priority group %d",
|
|
|
|
group->priority);
|
2008-09-26 16:24:40 +02:00
|
|
|
|
2010-08-27 19:05:49 +02:00
|
|
|
for (i = 0; i < scan_res->num; i++) {
|
|
|
|
struct wpa_scan_res *bss = scan_res->res[i];
|
|
|
|
const u8 *ie, *ssid;
|
|
|
|
u8 ssid_len;
|
|
|
|
|
|
|
|
*selected_ssid = wpa_scan_res_match(wpa_s, i, bss, group);
|
|
|
|
if (!*selected_ssid)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
ie = wpa_scan_get_ie(bss, WLAN_EID_SSID);
|
|
|
|
ssid = ie ? ie + 2 : (u8 *) "";
|
|
|
|
ssid_len = ie ? ie[1] : 0;
|
2008-09-26 16:24:40 +02:00
|
|
|
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " selected BSS " MACSTR
|
|
|
|
" ssid='%s'",
|
|
|
|
MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len));
|
2010-08-27 19:05:49 +02:00
|
|
|
return wpa_bss_get(wpa_s, bss->bssid, ssid, ssid_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-02 15:16:02 +01:00
|
|
|
static struct wpa_bss *
|
2009-09-29 13:30:11 +02:00
|
|
|
wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
|
2010-01-02 15:41:38 +01:00
|
|
|
struct wpa_scan_results *scan_res,
|
2009-09-29 13:30:11 +02:00
|
|
|
struct wpa_ssid **selected_ssid)
|
2008-02-28 02:34:43 +01:00
|
|
|
{
|
2010-01-02 15:16:02 +01:00
|
|
|
struct wpa_bss *selected = NULL;
|
2009-09-29 13:30:11 +02:00
|
|
|
int prio;
|
|
|
|
|
|
|
|
while (selected == NULL) {
|
|
|
|
for (prio = 0; prio < wpa_s->conf->num_prio; prio++) {
|
|
|
|
selected = wpa_supplicant_select_bss(
|
2010-01-02 15:41:38 +01:00
|
|
|
wpa_s, scan_res, wpa_s->conf->pssid[prio],
|
2009-09-29 13:30:11 +02:00
|
|
|
selected_ssid);
|
|
|
|
if (selected)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (selected == NULL && wpa_s->blacklist) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "No APs found - clear "
|
|
|
|
"blacklist and try again");
|
2009-09-29 13:30:11 +02:00
|
|
|
wpa_blacklist_clear(wpa_s);
|
|
|
|
wpa_s->blacklist_cleared++;
|
|
|
|
} else if (selected == NULL)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return selected;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void wpa_supplicant_req_new_scan(struct wpa_supplicant *wpa_s,
|
2010-04-11 18:10:01 +02:00
|
|
|
int timeout_sec, int timeout_usec)
|
2009-09-29 13:30:11 +02:00
|
|
|
{
|
2010-07-07 05:31:10 +02:00
|
|
|
if (!wpa_supplicant_enabled_networks(wpa_s->conf)) {
|
2009-10-14 21:05:58 +02:00
|
|
|
/*
|
|
|
|
* No networks are enabled; short-circuit request so
|
|
|
|
* we don't wait timeout seconds before transitioning
|
|
|
|
* to INACTIVE state.
|
|
|
|
*/
|
|
|
|
wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
|
|
|
|
return;
|
2009-09-29 13:30:11 +02:00
|
|
|
}
|
2010-04-11 18:10:01 +02:00
|
|
|
wpa_supplicant_req_scan(wpa_s, timeout_sec, timeout_usec);
|
2009-09-29 13:30:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-04-10 21:56:55 +02:00
|
|
|
void wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
|
|
|
|
struct wpa_bss *selected,
|
|
|
|
struct wpa_ssid *ssid)
|
2009-09-29 13:30:11 +02:00
|
|
|
{
|
|
|
|
if (wpas_wps_scan_pbc_overlap(wpa_s, selected, ssid)) {
|
|
|
|
wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OVERLAP
|
|
|
|
"PBC session overlap");
|
2010-09-07 12:42:55 +02:00
|
|
|
#ifdef CONFIG_P2P
|
|
|
|
if (wpas_p2p_notif_pbc_overlap(wpa_s) == 1)
|
|
|
|
return;
|
|
|
|
#endif /* CONFIG_P2P */
|
2010-10-07 09:41:58 +02:00
|
|
|
|
|
|
|
#ifdef CONFIG_WPS
|
2010-09-20 02:04:04 +02:00
|
|
|
wpas_wps_cancel(wpa_s);
|
2010-10-07 09:41:58 +02:00
|
|
|
#endif /* CONFIG_WPS */
|
2009-09-29 13:30:11 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Do not trigger new association unless the BSSID has changed or if
|
|
|
|
* reassociation is requested. If we are in process of associating with
|
|
|
|
* the selected BSSID, do not trigger new attempt.
|
|
|
|
*/
|
|
|
|
if (wpa_s->reassociate ||
|
|
|
|
(os_memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0 &&
|
2011-02-24 15:59:46 +01:00
|
|
|
((wpa_s->wpa_state != WPA_ASSOCIATING &&
|
|
|
|
wpa_s->wpa_state != WPA_AUTHENTICATING) ||
|
2009-09-29 13:30:11 +02:00
|
|
|
os_memcmp(selected->bssid, wpa_s->pending_bssid, ETH_ALEN) !=
|
|
|
|
0))) {
|
|
|
|
if (wpa_supplicant_scard_init(wpa_s, ssid)) {
|
2010-04-11 18:10:01 +02:00
|
|
|
wpa_supplicant_req_new_scan(wpa_s, 10, 0);
|
2009-09-29 13:30:11 +02:00
|
|
|
return;
|
|
|
|
}
|
2011-02-24 15:59:46 +01:00
|
|
|
wpa_msg(wpa_s, MSG_DEBUG, "Request association: "
|
|
|
|
"reassociate: %d selected: "MACSTR " bssid: " MACSTR
|
|
|
|
" pending: " MACSTR " wpa_state: %s",
|
|
|
|
wpa_s->reassociate, MAC2STR(selected->bssid),
|
|
|
|
MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
|
|
|
|
wpa_supplicant_state_txt(wpa_s->wpa_state));
|
2009-09-29 13:30:11 +02:00
|
|
|
wpa_supplicant_associate(wpa_s, selected, ssid);
|
|
|
|
} else {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with the "
|
|
|
|
"selected AP");
|
2009-09-29 13:30:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-09-29 16:11:36 +02:00
|
|
|
static struct wpa_ssid *
|
|
|
|
wpa_supplicant_pick_new_network(struct wpa_supplicant *wpa_s)
|
|
|
|
{
|
|
|
|
int prio;
|
|
|
|
struct wpa_ssid *ssid;
|
|
|
|
|
|
|
|
for (prio = 0; prio < wpa_s->conf->num_prio; prio++) {
|
|
|
|
for (ssid = wpa_s->conf->pssid[prio]; ssid; ssid = ssid->pnext)
|
|
|
|
{
|
|
|
|
if (ssid->disabled)
|
|
|
|
continue;
|
|
|
|
if (ssid->mode == IEEE80211_MODE_IBSS ||
|
|
|
|
ssid->mode == IEEE80211_MODE_AP)
|
|
|
|
return ssid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-02 15:41:38 +01:00
|
|
|
/* TODO: move the rsn_preauth_scan_result*() to be called from notify.c based
|
|
|
|
* on BSS added and BSS changed events */
|
2009-11-29 16:06:03 +01:00
|
|
|
static void wpa_supplicant_rsn_preauth_scan_results(
|
2011-05-19 16:52:46 +02:00
|
|
|
struct wpa_supplicant *wpa_s)
|
2009-11-29 16:06:03 +01:00
|
|
|
{
|
2011-05-19 16:52:46 +02:00
|
|
|
struct wpa_bss *bss;
|
2009-11-29 16:06:03 +01:00
|
|
|
|
|
|
|
if (rsn_preauth_scan_results(wpa_s->wpa) < 0)
|
|
|
|
return;
|
|
|
|
|
2011-05-19 16:52:46 +02:00
|
|
|
dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
|
2009-11-29 16:06:03 +01:00
|
|
|
const u8 *ssid, *rsn;
|
|
|
|
|
2011-05-19 16:52:46 +02:00
|
|
|
ssid = wpa_bss_get_ie(bss, WLAN_EID_SSID);
|
2009-11-29 16:06:03 +01:00
|
|
|
if (ssid == NULL)
|
|
|
|
continue;
|
|
|
|
|
2011-05-19 16:52:46 +02:00
|
|
|
rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
|
2009-11-29 16:06:03 +01:00
|
|
|
if (rsn == NULL)
|
|
|
|
continue;
|
|
|
|
|
2011-05-19 16:52:46 +02:00
|
|
|
rsn_preauth_scan_result(wpa_s->wpa, bss->bssid, ssid, rsn);
|
2009-11-29 16:06:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-25 03:19:50 +01:00
|
|
|
static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
|
|
|
|
struct wpa_bss *selected,
|
|
|
|
struct wpa_ssid *ssid,
|
|
|
|
struct wpa_scan_results *scan_res)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
struct wpa_scan_res *current_bss = NULL;
|
|
|
|
int min_diff;
|
|
|
|
|
|
|
|
if (wpa_s->reassociate)
|
|
|
|
return 1; /* explicit request to reassociate */
|
|
|
|
if (wpa_s->wpa_state < WPA_ASSOCIATED)
|
|
|
|
return 1; /* we are not associated; continue */
|
|
|
|
if (wpa_s->current_ssid == NULL)
|
|
|
|
return 1; /* unknown current SSID */
|
|
|
|
if (wpa_s->current_ssid != ssid)
|
|
|
|
return 1; /* different network block */
|
|
|
|
|
2011-09-26 13:57:23 +02:00
|
|
|
if (wpas_driver_bss_selection(wpa_s))
|
|
|
|
return 0; /* Driver-based roaming */
|
|
|
|
|
2010-01-25 03:19:50 +01:00
|
|
|
for (i = 0; i < scan_res->num; i++) {
|
|
|
|
struct wpa_scan_res *res = scan_res->res[i];
|
|
|
|
const u8 *ie;
|
|
|
|
if (os_memcmp(res->bssid, wpa_s->bssid, ETH_ALEN) != 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
ie = wpa_scan_get_ie(res, WLAN_EID_SSID);
|
|
|
|
if (ie == NULL)
|
|
|
|
continue;
|
|
|
|
if (ie[1] != wpa_s->current_ssid->ssid_len ||
|
|
|
|
os_memcmp(ie + 2, wpa_s->current_ssid->ssid, ie[1]) != 0)
|
|
|
|
continue;
|
|
|
|
current_bss = res;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!current_bss)
|
|
|
|
return 1; /* current BSS not seen in scan results */
|
|
|
|
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Considering within-ESS reassociation");
|
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Current BSS: " MACSTR " level=%d",
|
|
|
|
MAC2STR(current_bss->bssid), current_bss->level);
|
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Selected BSS: " MACSTR " level=%d",
|
|
|
|
MAC2STR(selected->bssid), selected->level);
|
2010-01-25 03:19:50 +01:00
|
|
|
|
2010-02-28 10:09:58 +01:00
|
|
|
if (wpa_s->current_ssid->bssid_set &&
|
|
|
|
os_memcmp(selected->bssid, wpa_s->current_ssid->bssid, ETH_ALEN) ==
|
|
|
|
0) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Allow reassociation - selected BSS "
|
|
|
|
"has preferred BSSID");
|
2010-02-28 10:09:58 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2010-01-25 03:19:50 +01:00
|
|
|
min_diff = 2;
|
|
|
|
if (current_bss->level < 0) {
|
|
|
|
if (current_bss->level < -85)
|
|
|
|
min_diff = 1;
|
|
|
|
else if (current_bss->level < -80)
|
|
|
|
min_diff = 2;
|
|
|
|
else if (current_bss->level < -75)
|
|
|
|
min_diff = 3;
|
|
|
|
else if (current_bss->level < -70)
|
|
|
|
min_diff = 4;
|
|
|
|
else
|
|
|
|
min_diff = 5;
|
|
|
|
}
|
|
|
|
if (abs(current_bss->level - selected->level) < min_diff) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - too small difference "
|
|
|
|
"in signal level");
|
2010-01-25 03:19:50 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-02-16 17:55:37 +01:00
|
|
|
/* Return < 0 if no scan results could be fetched. */
|
|
|
|
static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
|
|
|
|
union wpa_event_data *data)
|
2009-09-29 13:30:11 +02:00
|
|
|
{
|
2010-01-02 15:16:02 +01:00
|
|
|
struct wpa_bss *selected;
|
2008-02-28 02:34:43 +01:00
|
|
|
struct wpa_ssid *ssid = NULL;
|
2010-01-02 15:41:38 +01:00
|
|
|
struct wpa_scan_results *scan_res;
|
2010-07-18 05:32:25 +02:00
|
|
|
int ap = 0;
|
|
|
|
|
|
|
|
#ifdef CONFIG_AP
|
|
|
|
if (wpa_s->ap_iface)
|
|
|
|
ap = 1;
|
|
|
|
#endif /* CONFIG_AP */
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2009-05-27 20:06:40 +02:00
|
|
|
wpa_supplicant_notify_scanning(wpa_s, 0);
|
|
|
|
|
2010-01-02 15:41:38 +01:00
|
|
|
scan_res = wpa_supplicant_get_scan_results(wpa_s,
|
|
|
|
data ? &data->scan_info :
|
|
|
|
NULL, 1);
|
|
|
|
if (scan_res == NULL) {
|
2010-07-18 05:32:25 +02:00
|
|
|
if (wpa_s->conf->ap_scan == 2 || ap)
|
2011-02-16 17:55:37 +01:00
|
|
|
return -1;
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results - try "
|
|
|
|
"scanning again");
|
2010-04-11 18:10:01 +02:00
|
|
|
wpa_supplicant_req_new_scan(wpa_s, 1, 0);
|
2011-02-16 17:55:37 +01:00
|
|
|
return -1;
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
|
|
|
|
Maintain internal entropy pool for augmenting random number generation
By default, make hostapd and wpa_supplicant maintain an internal
entropy pool that is fed with following information:
hostapd:
- Probe Request frames (timing, RSSI)
- Association events (timing)
- SNonce from Supplicants
wpa_supplicant:
- Scan results (timing, signal/noise)
- Association events (timing)
The internal pool is used to augment the random numbers generated
with the OS mechanism (os_get_random()). While the internal
implementation is not expected to be very strong due to limited
amount of generic (non-platform specific) information to feed the
pool, this may strengthen key derivation on some devices that are
not configured to provide strong random numbers through
os_get_random() (e.g., /dev/urandom on Linux/BSD).
This new mechanism is not supposed to replace proper OS provided
random number generation mechanism. The OS mechanism needs to be
initialized properly (e.g., hw random number generator,
maintaining entropy pool over reboots, etc.) for any of the
security assumptions to hold.
If the os_get_random() is known to provide strong ramdom data (e.g., on
Linux/BSD, the board in question is known to have reliable source of
random data from /dev/urandom), the internal hostapd random pool can be
disabled. This will save some in binary size and CPU use. However, this
should only be considered for builds that are known to be used on
devices that meet the requirements described above. The internal pool
is disabled by adding CONFIG_NO_RANDOM_POOL=y to the .config file.
2010-11-24 00:29:40 +01:00
|
|
|
#ifndef CONFIG_NO_RANDOM_POOL
|
|
|
|
size_t i, num;
|
|
|
|
num = scan_res->num;
|
|
|
|
if (num > 10)
|
|
|
|
num = 10;
|
|
|
|
for (i = 0; i < num; i++) {
|
|
|
|
u8 buf[5];
|
|
|
|
struct wpa_scan_res *res = scan_res->res[i];
|
|
|
|
buf[0] = res->bssid[5];
|
|
|
|
buf[1] = res->qual & 0xff;
|
|
|
|
buf[2] = res->noise & 0xff;
|
|
|
|
buf[3] = res->level & 0xff;
|
|
|
|
buf[4] = res->tsf & 0xff;
|
|
|
|
random_add_randomness(buf, sizeof(buf));
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_NO_RANDOM_POOL */
|
|
|
|
|
2010-04-11 18:53:31 +02:00
|
|
|
if (wpa_s->scan_res_handler) {
|
2010-12-17 14:31:05 +01:00
|
|
|
void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
|
|
|
|
struct wpa_scan_results *scan_res);
|
|
|
|
|
|
|
|
scan_res_handler = wpa_s->scan_res_handler;
|
2010-04-11 18:53:31 +02:00
|
|
|
wpa_s->scan_res_handler = NULL;
|
2010-12-17 14:31:05 +01:00
|
|
|
scan_res_handler(wpa_s, scan_res);
|
|
|
|
|
2010-04-11 18:53:31 +02:00
|
|
|
wpa_scan_results_free(scan_res);
|
2011-02-16 17:55:37 +01:00
|
|
|
return 0;
|
2010-04-11 18:53:31 +02:00
|
|
|
}
|
|
|
|
|
2010-07-18 05:32:25 +02:00
|
|
|
if (ap) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Ignore scan results in AP mode");
|
2011-03-19 12:08:08 +01:00
|
|
|
#ifdef CONFIG_AP
|
|
|
|
if (wpa_s->ap_iface->scan_cb)
|
|
|
|
wpa_s->ap_iface->scan_cb(wpa_s->ap_iface);
|
|
|
|
#endif /* CONFIG_AP */
|
2010-07-18 05:32:25 +02:00
|
|
|
wpa_scan_results_free(scan_res);
|
2011-02-16 17:55:37 +01:00
|
|
|
return 0;
|
2010-07-18 05:32:25 +02:00
|
|
|
}
|
|
|
|
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available");
|
2010-07-07 05:31:10 +02:00
|
|
|
wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
|
|
|
|
wpas_notify_scan_results(wpa_s);
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2009-09-13 19:53:32 +02:00
|
|
|
wpas_notify_scan_done(wpa_s, 1);
|
|
|
|
|
2010-01-02 15:41:38 +01:00
|
|
|
if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s))) {
|
|
|
|
wpa_scan_results_free(scan_res);
|
2011-02-16 17:55:37 +01:00
|
|
|
return 0;
|
2010-01-02 15:41:38 +01:00
|
|
|
}
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2009-09-14 16:25:03 +02:00
|
|
|
if (wpa_s->disconnected) {
|
|
|
|
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
|
2010-01-02 15:41:38 +01:00
|
|
|
wpa_scan_results_free(scan_res);
|
2011-02-16 17:55:37 +01:00
|
|
|
return 0;
|
2009-09-14 16:25:03 +02:00
|
|
|
}
|
|
|
|
|
2011-09-26 13:57:23 +02:00
|
|
|
if (!wpas_driver_bss_selection(wpa_s) &&
|
|
|
|
bgscan_notify_scan(wpa_s, scan_res) == 1) {
|
2010-01-02 15:41:38 +01:00
|
|
|
wpa_scan_results_free(scan_res);
|
2011-02-16 17:55:37 +01:00
|
|
|
return 0;
|
2010-01-02 15:41:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
selected = wpa_supplicant_pick_network(wpa_s, scan_res, &ssid);
|
2009-11-29 16:06:03 +01:00
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
if (selected) {
|
2010-01-25 03:19:50 +01:00
|
|
|
int skip;
|
|
|
|
skip = !wpa_supplicant_need_to_roam(wpa_s, selected, ssid,
|
|
|
|
scan_res);
|
|
|
|
wpa_scan_results_free(scan_res);
|
|
|
|
if (skip)
|
2011-02-16 17:55:37 +01:00
|
|
|
return 0;
|
2009-09-29 13:30:11 +02:00
|
|
|
wpa_supplicant_connect(wpa_s, selected, ssid);
|
2011-05-19 16:52:46 +02:00
|
|
|
wpa_supplicant_rsn_preauth_scan_results(wpa_s);
|
2008-02-28 02:34:43 +01:00
|
|
|
} else {
|
2010-01-25 03:19:50 +01:00
|
|
|
wpa_scan_results_free(scan_res);
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "No suitable network found");
|
2009-09-29 16:11:36 +02:00
|
|
|
ssid = wpa_supplicant_pick_new_network(wpa_s);
|
|
|
|
if (ssid) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Setup a new network");
|
2009-09-29 16:11:36 +02:00
|
|
|
wpa_supplicant_associate(wpa_s, NULL, ssid);
|
2011-05-19 16:52:46 +02:00
|
|
|
wpa_supplicant_rsn_preauth_scan_results(wpa_s);
|
2010-04-11 18:10:01 +02:00
|
|
|
} else {
|
2011-04-11 22:14:38 +02:00
|
|
|
int timeout_sec = wpa_s->scan_interval;
|
2010-04-11 18:10:01 +02:00
|
|
|
int timeout_usec = 0;
|
2010-07-18 23:30:25 +02:00
|
|
|
#ifdef CONFIG_P2P
|
|
|
|
if (wpa_s->p2p_in_provisioning) {
|
|
|
|
/*
|
|
|
|
* Use shorter wait during P2P Provisioning
|
|
|
|
* state to speed up group formation.
|
|
|
|
*/
|
|
|
|
timeout_sec = 0;
|
|
|
|
timeout_usec = 250000;
|
2011-09-27 21:21:31 +02:00
|
|
|
wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
|
|
|
|
timeout_usec);
|
|
|
|
return 0;
|
2010-07-18 23:30:25 +02:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_P2P */
|
2011-09-27 21:21:31 +02:00
|
|
|
if (wpa_supplicant_req_sched_scan(wpa_s))
|
|
|
|
wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
|
|
|
|
timeout_usec);
|
2010-04-11 18:10:01 +02:00
|
|
|
}
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
2011-02-16 17:55:37 +01:00
|
|
|
return 0;
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
2010-11-26 20:46:30 +01:00
|
|
|
|
|
|
|
|
|
|
|
static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
|
|
|
|
union wpa_event_data *data)
|
|
|
|
{
|
|
|
|
const char *rn, *rn2;
|
|
|
|
struct wpa_supplicant *ifs;
|
|
|
|
|
2011-02-16 17:55:37 +01:00
|
|
|
if (_wpa_supplicant_event_scan_results(wpa_s, data) < 0) {
|
|
|
|
/*
|
|
|
|
* If no scan results could be fetched, then no need to
|
|
|
|
* notify those interfaces that did not actually request
|
|
|
|
* this scan.
|
|
|
|
*/
|
|
|
|
return;
|
|
|
|
}
|
2010-11-26 20:46:30 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check other interfaces to see if they have the same radio-name. If
|
|
|
|
* so, they get updated with this same scan info.
|
|
|
|
*/
|
|
|
|
if (!wpa_s->driver->get_radio_name)
|
|
|
|
return;
|
|
|
|
|
|
|
|
rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
|
|
|
|
if (rn == NULL || rn[0] == '\0')
|
|
|
|
return;
|
|
|
|
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Checking for other virtual interfaces "
|
|
|
|
"sharing same radio (%s) in event_scan_results", rn);
|
2010-11-26 20:46:30 +01:00
|
|
|
|
|
|
|
for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
|
|
|
|
if (ifs == wpa_s || !ifs->driver->get_radio_name)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
|
|
|
|
if (rn2 && os_strcmp(rn, rn2) == 0) {
|
|
|
|
wpa_printf(MSG_DEBUG, "%s: Updating scan results from "
|
|
|
|
"sibling", ifs->ifname);
|
|
|
|
_wpa_supplicant_event_scan_results(ifs, data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
#endif /* CONFIG_NO_SCAN_PROCESSING */
|
|
|
|
|
|
|
|
|
2010-04-09 15:59:27 +02:00
|
|
|
static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
|
|
|
|
union wpa_event_data *data)
|
2008-02-28 02:34:43 +01:00
|
|
|
{
|
|
|
|
int l, len, found = 0, wpa_found, rsn_found;
|
2009-03-20 21:26:41 +01:00
|
|
|
const u8 *p;
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Association info event");
|
2008-02-28 02:34:43 +01:00
|
|
|
if (data->assoc_info.req_ies)
|
|
|
|
wpa_hexdump(MSG_DEBUG, "req_ies", data->assoc_info.req_ies,
|
|
|
|
data->assoc_info.req_ies_len);
|
2011-01-28 18:27:28 +01:00
|
|
|
if (data->assoc_info.resp_ies) {
|
2008-02-28 02:34:43 +01:00
|
|
|
wpa_hexdump(MSG_DEBUG, "resp_ies", data->assoc_info.resp_ies,
|
|
|
|
data->assoc_info.resp_ies_len);
|
2011-01-28 18:27:28 +01:00
|
|
|
#ifdef CONFIG_TDLS
|
|
|
|
wpa_tdls_assoc_resp_ies(wpa_s->wpa, data->assoc_info.resp_ies,
|
|
|
|
data->assoc_info.resp_ies_len);
|
|
|
|
#endif /* CONFIG_TDLS */
|
|
|
|
}
|
2008-02-28 02:34:43 +01:00
|
|
|
if (data->assoc_info.beacon_ies)
|
|
|
|
wpa_hexdump(MSG_DEBUG, "beacon_ies",
|
|
|
|
data->assoc_info.beacon_ies,
|
|
|
|
data->assoc_info.beacon_ies_len);
|
2009-12-28 12:23:13 +01:00
|
|
|
if (data->assoc_info.freq)
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "freq=%u MHz",
|
|
|
|
data->assoc_info.freq);
|
2008-02-28 02:34:43 +01:00
|
|
|
|
|
|
|
p = data->assoc_info.req_ies;
|
|
|
|
l = data->assoc_info.req_ies_len;
|
|
|
|
|
|
|
|
/* Go through the IEs and make a copy of the WPA/RSN IE, if present. */
|
|
|
|
while (p && l >= 2) {
|
|
|
|
len = p[1] + 2;
|
|
|
|
if (len > l) {
|
|
|
|
wpa_hexdump(MSG_DEBUG, "Truncated IE in assoc_info",
|
|
|
|
p, l);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if ((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
|
|
|
|
(os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) ||
|
|
|
|
(p[0] == WLAN_EID_RSN && p[1] >= 2)) {
|
|
|
|
if (wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, p, len))
|
|
|
|
break;
|
|
|
|
found = 1;
|
|
|
|
wpa_find_assoc_pmkid(wpa_s);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
l -= len;
|
|
|
|
p += len;
|
|
|
|
}
|
|
|
|
if (!found && data->assoc_info.req_ies)
|
|
|
|
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
|
|
|
|
|
2009-03-20 21:26:41 +01:00
|
|
|
#ifdef CONFIG_IEEE80211R
|
2010-03-13 20:13:18 +01:00
|
|
|
#ifdef CONFIG_SME
|
|
|
|
if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FT) {
|
|
|
|
u8 bssid[ETH_ALEN];
|
|
|
|
if (wpa_drv_get_bssid(wpa_s, bssid) < 0 ||
|
|
|
|
wpa_ft_validate_reassoc_resp(wpa_s->wpa,
|
|
|
|
data->assoc_info.resp_ies,
|
|
|
|
data->assoc_info.resp_ies_len,
|
|
|
|
bssid) < 0) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "FT: Validation of "
|
|
|
|
"Reassociation Response failed");
|
2010-04-09 15:59:27 +02:00
|
|
|
wpa_supplicant_deauthenticate(
|
|
|
|
wpa_s, WLAN_REASON_INVALID_IE);
|
|
|
|
return -1;
|
2010-03-13 20:13:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-20 21:26:41 +01:00
|
|
|
p = data->assoc_info.resp_ies;
|
|
|
|
l = data->assoc_info.resp_ies_len;
|
|
|
|
|
2010-05-26 16:16:14 +02:00
|
|
|
#ifdef CONFIG_WPS_STRICT
|
2011-04-14 01:55:38 +02:00
|
|
|
if (p && wpa_s->current_ssid &&
|
2010-05-26 16:16:14 +02:00
|
|
|
wpa_s->current_ssid->key_mgmt == WPA_KEY_MGMT_WPS) {
|
|
|
|
struct wpabuf *wps;
|
|
|
|
wps = ieee802_11_vendor_ie_concat(p, l, WPS_IE_VENDOR_TYPE);
|
|
|
|
if (wps == NULL) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_msg(wpa_s, MSG_INFO, "WPS-STRICT: AP did not "
|
|
|
|
"include WPS IE in (Re)Association Response");
|
2010-05-26 16:16:14 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wps_validate_assoc_resp(wps) < 0) {
|
|
|
|
wpabuf_free(wps);
|
|
|
|
wpa_supplicant_deauthenticate(
|
|
|
|
wpa_s, WLAN_REASON_INVALID_IE);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
wpabuf_free(wps);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_WPS_STRICT */
|
|
|
|
|
2010-04-10 10:36:35 +02:00
|
|
|
/* Go through the IEs and make a copy of the MDIE, if present. */
|
2009-03-20 21:26:41 +01:00
|
|
|
while (p && l >= 2) {
|
|
|
|
len = p[1] + 2;
|
|
|
|
if (len > l) {
|
|
|
|
wpa_hexdump(MSG_DEBUG, "Truncated IE in assoc_info",
|
|
|
|
p, l);
|
|
|
|
break;
|
|
|
|
}
|
2010-04-10 10:36:35 +02:00
|
|
|
if (p[0] == WLAN_EID_MOBILITY_DOMAIN &&
|
|
|
|
p[1] >= MOBILITY_DOMAIN_ID_LEN) {
|
|
|
|
wpa_s->sme.ft_used = 1;
|
|
|
|
os_memcpy(wpa_s->sme.mobility_domain, p + 2,
|
|
|
|
MOBILITY_DOMAIN_ID_LEN);
|
|
|
|
break;
|
|
|
|
}
|
2009-03-20 21:26:41 +01:00
|
|
|
l -= len;
|
|
|
|
p += len;
|
|
|
|
}
|
2010-04-10 10:36:35 +02:00
|
|
|
#endif /* CONFIG_SME */
|
2009-03-20 21:26:41 +01:00
|
|
|
|
2010-04-10 10:36:35 +02:00
|
|
|
wpa_sm_set_ft_params(wpa_s->wpa, data->assoc_info.resp_ies,
|
|
|
|
data->assoc_info.resp_ies_len);
|
2009-03-20 21:26:41 +01:00
|
|
|
#endif /* CONFIG_IEEE80211R */
|
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
/* WPA/RSN IE from Beacon/ProbeResp */
|
|
|
|
p = data->assoc_info.beacon_ies;
|
|
|
|
l = data->assoc_info.beacon_ies_len;
|
|
|
|
|
|
|
|
/* Go through the IEs and make a copy of the WPA/RSN IEs, if present.
|
|
|
|
*/
|
|
|
|
wpa_found = rsn_found = 0;
|
|
|
|
while (p && l >= 2) {
|
|
|
|
len = p[1] + 2;
|
|
|
|
if (len > l) {
|
|
|
|
wpa_hexdump(MSG_DEBUG, "Truncated IE in beacon_ies",
|
|
|
|
p, l);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!wpa_found &&
|
|
|
|
p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
|
|
|
|
os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0) {
|
|
|
|
wpa_found = 1;
|
|
|
|
wpa_sm_set_ap_wpa_ie(wpa_s->wpa, p, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!rsn_found &&
|
|
|
|
p[0] == WLAN_EID_RSN && p[1] >= 2) {
|
|
|
|
rsn_found = 1;
|
|
|
|
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, p, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
l -= len;
|
|
|
|
p += len;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!wpa_found && data->assoc_info.beacon_ies)
|
|
|
|
wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
|
|
|
|
if (!rsn_found && data->assoc_info.beacon_ies)
|
|
|
|
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
|
|
|
|
if (wpa_found || rsn_found)
|
|
|
|
wpa_s->ap_ies_from_associnfo = 1;
|
2009-12-28 12:23:13 +01:00
|
|
|
|
2011-05-16 18:19:30 +02:00
|
|
|
if (wpa_s->assoc_freq && data->assoc_info.freq &&
|
|
|
|
wpa_s->assoc_freq != data->assoc_info.freq) {
|
|
|
|
wpa_printf(MSG_DEBUG, "Operating frequency changed from "
|
|
|
|
"%u to %u MHz",
|
|
|
|
wpa_s->assoc_freq, data->assoc_info.freq);
|
|
|
|
wpa_supplicant_update_scan_results(wpa_s);
|
|
|
|
}
|
|
|
|
|
2009-12-28 12:23:13 +01:00
|
|
|
wpa_s->assoc_freq = data->assoc_info.freq;
|
2010-04-09 15:59:27 +02:00
|
|
|
|
|
|
|
return 0;
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
|
|
|
|
union wpa_event_data *data)
|
|
|
|
{
|
|
|
|
u8 bssid[ETH_ALEN];
|
2010-01-03 17:22:22 +01:00
|
|
|
int ft_completed;
|
2009-09-13 19:53:32 +02:00
|
|
|
int bssid_changed;
|
2009-09-15 09:48:30 +02:00
|
|
|
struct wpa_driver_capa capa;
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2010-01-03 17:22:22 +01:00
|
|
|
#ifdef CONFIG_AP
|
|
|
|
if (wpa_s->ap_iface) {
|
|
|
|
hostapd_notif_assoc(wpa_s->ap_iface->bss[0],
|
|
|
|
data->assoc_info.addr,
|
|
|
|
data->assoc_info.req_ies,
|
2010-10-25 12:50:34 +02:00
|
|
|
data->assoc_info.req_ies_len,
|
|
|
|
data->assoc_info.reassoc);
|
2010-01-03 17:22:22 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_AP */
|
|
|
|
|
|
|
|
ft_completed = wpa_ft_is_completed(wpa_s->wpa);
|
2010-04-09 15:59:27 +02:00
|
|
|
if (data && wpa_supplicant_event_associnfo(wpa_s, data) < 0)
|
|
|
|
return;
|
2008-02-28 02:34:43 +01:00
|
|
|
|
|
|
|
wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED);
|
2011-10-22 21:45:38 +02:00
|
|
|
if (wpa_drv_get_bssid(wpa_s, bssid) >= 0 &&
|
|
|
|
os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Associated to a new BSS: BSSID="
|
2008-02-28 02:34:43 +01:00
|
|
|
MACSTR, MAC2STR(bssid));
|
Maintain internal entropy pool for augmenting random number generation
By default, make hostapd and wpa_supplicant maintain an internal
entropy pool that is fed with following information:
hostapd:
- Probe Request frames (timing, RSSI)
- Association events (timing)
- SNonce from Supplicants
wpa_supplicant:
- Scan results (timing, signal/noise)
- Association events (timing)
The internal pool is used to augment the random numbers generated
with the OS mechanism (os_get_random()). While the internal
implementation is not expected to be very strong due to limited
amount of generic (non-platform specific) information to feed the
pool, this may strengthen key derivation on some devices that are
not configured to provide strong random numbers through
os_get_random() (e.g., /dev/urandom on Linux/BSD).
This new mechanism is not supposed to replace proper OS provided
random number generation mechanism. The OS mechanism needs to be
initialized properly (e.g., hw random number generator,
maintaining entropy pool over reboots, etc.) for any of the
security assumptions to hold.
If the os_get_random() is known to provide strong ramdom data (e.g., on
Linux/BSD, the board in question is known to have reliable source of
random data from /dev/urandom), the internal hostapd random pool can be
disabled. This will save some in binary size and CPU use. However, this
should only be considered for builds that are known to be used on
devices that meet the requirements described above. The internal pool
is disabled by adding CONFIG_NO_RANDOM_POOL=y to the .config file.
2010-11-24 00:29:40 +01:00
|
|
|
random_add_randomness(bssid, ETH_ALEN);
|
2009-09-13 19:53:32 +02:00
|
|
|
bssid_changed = os_memcmp(wpa_s->bssid, bssid, ETH_ALEN);
|
2008-02-28 02:34:43 +01:00
|
|
|
os_memcpy(wpa_s->bssid, bssid, ETH_ALEN);
|
|
|
|
os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
|
2009-09-13 19:53:32 +02:00
|
|
|
if (bssid_changed)
|
|
|
|
wpas_notify_bssid_changed(wpa_s);
|
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
if (wpa_supplicant_dynamic_keys(wpa_s) && !ft_completed) {
|
|
|
|
wpa_clear_keys(wpa_s, bssid);
|
|
|
|
}
|
|
|
|
if (wpa_supplicant_select_config(wpa_s) < 0) {
|
|
|
|
wpa_supplicant_disassociate(
|
|
|
|
wpa_s, WLAN_REASON_DEAUTH_LEAVING);
|
|
|
|
return;
|
|
|
|
}
|
2010-01-02 15:59:19 +01:00
|
|
|
if (wpa_s->current_ssid) {
|
|
|
|
struct wpa_bss *bss = NULL;
|
|
|
|
struct wpa_ssid *ssid = wpa_s->current_ssid;
|
|
|
|
if (ssid->ssid_len > 0)
|
|
|
|
bss = wpa_bss_get(wpa_s, bssid,
|
|
|
|
ssid->ssid, ssid->ssid_len);
|
|
|
|
if (!bss)
|
|
|
|
bss = wpa_bss_get_bssid(wpa_s, bssid);
|
|
|
|
if (bss)
|
|
|
|
wpa_s->current_bss = bss;
|
|
|
|
}
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
|
|
|
|
2009-11-17 18:25:05 +01:00
|
|
|
#ifdef CONFIG_SME
|
|
|
|
os_memcpy(wpa_s->sme.prev_bssid, bssid, ETH_ALEN);
|
|
|
|
wpa_s->sme.prev_bssid_set = 1;
|
|
|
|
#endif /* CONFIG_SME */
|
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
wpa_msg(wpa_s, MSG_INFO, "Associated with " MACSTR, MAC2STR(bssid));
|
|
|
|
if (wpa_s->current_ssid) {
|
|
|
|
/* When using scanning (ap_scan=1), SIM PC/SC interface can be
|
|
|
|
* initialized before association, but for other modes,
|
|
|
|
* initialize PC/SC here, if the current configuration needs
|
|
|
|
* smartcard or SIM/USIM. */
|
|
|
|
wpa_supplicant_scard_init(wpa_s, wpa_s->current_ssid);
|
|
|
|
}
|
|
|
|
wpa_sm_notify_assoc(wpa_s->wpa, bssid);
|
2010-07-18 05:26:47 +02:00
|
|
|
if (wpa_s->l2)
|
|
|
|
l2_packet_notify_auth_start(wpa_s->l2);
|
2008-02-28 02:34:43 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Set portEnabled first to FALSE in order to get EAP state machine out
|
|
|
|
* of the SUCCESS state and eapSuccess cleared. Without this, EAPOL PAE
|
|
|
|
* state machine may transit to AUTHENTICATING state based on obsolete
|
|
|
|
* eapSuccess and then trigger BE_AUTH to SUCCESS and PAE to
|
|
|
|
* AUTHENTICATED without ever giving chance to EAP state machine to
|
|
|
|
* reset the state.
|
|
|
|
*/
|
|
|
|
if (!ft_completed) {
|
|
|
|
eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
|
|
|
|
eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
|
|
|
|
}
|
2008-08-31 21:57:28 +02:00
|
|
|
if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) || ft_completed)
|
2008-02-28 02:34:43 +01:00
|
|
|
eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
|
|
|
|
/* 802.1X::portControl = Auto */
|
|
|
|
eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);
|
|
|
|
wpa_s->eapol_received = 0;
|
|
|
|
if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
|
2009-12-04 21:09:06 +01:00
|
|
|
wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE ||
|
|
|
|
(wpa_s->current_ssid &&
|
|
|
|
wpa_s->current_ssid->mode == IEEE80211_MODE_IBSS)) {
|
2008-02-28 02:34:43 +01:00
|
|
|
wpa_supplicant_cancel_auth_timeout(wpa_s);
|
|
|
|
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
|
|
|
|
} else if (!ft_completed) {
|
|
|
|
/* Timeout for receiving the first EAPOL packet */
|
|
|
|
wpa_supplicant_req_auth_timeout(wpa_s, 10, 0);
|
|
|
|
}
|
|
|
|
wpa_supplicant_cancel_scan(wpa_s);
|
|
|
|
|
2009-03-20 21:26:41 +01:00
|
|
|
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
|
2008-08-31 21:57:28 +02:00
|
|
|
wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
|
2008-02-28 02:34:43 +01:00
|
|
|
/*
|
|
|
|
* We are done; the driver will take care of RSN 4-way
|
|
|
|
* handshake.
|
|
|
|
*/
|
|
|
|
wpa_supplicant_cancel_auth_timeout(wpa_s);
|
|
|
|
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
|
|
|
|
eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
|
|
|
|
eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
|
2011-01-31 23:04:02 +01:00
|
|
|
} else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
|
|
|
|
wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
|
|
|
|
/*
|
|
|
|
* The driver will take care of RSN 4-way handshake, so we need
|
|
|
|
* to allow EAPOL supplicant to complete its work without
|
|
|
|
* waiting for WPA supplicant.
|
|
|
|
*/
|
|
|
|
eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
|
2011-02-20 20:57:53 +01:00
|
|
|
} else if (ft_completed) {
|
|
|
|
/*
|
|
|
|
* FT protocol completed - make sure EAPOL state machine ends
|
|
|
|
* up in authenticated.
|
|
|
|
*/
|
|
|
|
wpa_supplicant_cancel_auth_timeout(wpa_s);
|
|
|
|
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
|
|
|
|
eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
|
|
|
|
eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
2009-09-04 17:04:41 +02:00
|
|
|
|
|
|
|
if (wpa_s->pending_eapol_rx) {
|
|
|
|
struct os_time now, age;
|
|
|
|
os_get_time(&now);
|
|
|
|
os_time_sub(&now, &wpa_s->pending_eapol_rx_time, &age);
|
|
|
|
if (age.sec == 0 && age.usec < 100000 &&
|
|
|
|
os_memcmp(wpa_s->pending_eapol_rx_src, bssid, ETH_ALEN) ==
|
|
|
|
0) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Process pending EAPOL "
|
|
|
|
"frame that was received just before "
|
|
|
|
"association notification");
|
2009-09-04 17:04:41 +02:00
|
|
|
wpa_supplicant_rx_eapol(
|
|
|
|
wpa_s, wpa_s->pending_eapol_rx_src,
|
|
|
|
wpabuf_head(wpa_s->pending_eapol_rx),
|
|
|
|
wpabuf_len(wpa_s->pending_eapol_rx));
|
|
|
|
}
|
|
|
|
wpabuf_free(wpa_s->pending_eapol_rx);
|
|
|
|
wpa_s->pending_eapol_rx = NULL;
|
|
|
|
}
|
2009-09-14 23:08:24 +02:00
|
|
|
|
2009-09-15 09:48:30 +02:00
|
|
|
if ((wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
|
|
|
|
wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
|
|
|
|
wpa_s->current_ssid && wpa_drv_get_capa(wpa_s, &capa) == 0 &&
|
|
|
|
capa.flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE) {
|
|
|
|
/* Set static WEP keys again */
|
|
|
|
wpa_set_wep_keys(wpa_s, wpa_s->current_ssid);
|
|
|
|
}
|
2011-01-15 13:07:02 +01:00
|
|
|
|
|
|
|
#ifdef CONFIG_IBSS_RSN
|
|
|
|
if (wpa_s->current_ssid &&
|
|
|
|
wpa_s->current_ssid->mode == WPAS_MODE_IBSS &&
|
|
|
|
wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
|
2011-03-23 20:15:46 +01:00
|
|
|
wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE &&
|
|
|
|
wpa_s->ibss_rsn == NULL) {
|
|
|
|
wpa_s->ibss_rsn = ibss_rsn_init(wpa_s);
|
|
|
|
if (!wpa_s->ibss_rsn) {
|
|
|
|
wpa_msg(wpa_s, MSG_INFO, "Failed to init IBSS RSN");
|
|
|
|
wpa_supplicant_deauthenticate(
|
|
|
|
wpa_s, WLAN_REASON_DEAUTH_LEAVING);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ibss_rsn_set_psk(wpa_s->ibss_rsn, wpa_s->current_ssid->psk);
|
|
|
|
}
|
2011-01-15 13:07:02 +01:00
|
|
|
#endif /* CONFIG_IBSS_RSN */
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-04-11 20:25:15 +02:00
|
|
|
static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
|
|
|
|
u16 reason_code)
|
2008-02-28 02:34:43 +01:00
|
|
|
{
|
|
|
|
const u8 *bssid;
|
2009-10-12 08:39:55 +02:00
|
|
|
int authenticating;
|
|
|
|
u8 prev_pending_bssid[ETH_ALEN];
|
|
|
|
|
|
|
|
authenticating = wpa_s->wpa_state == WPA_AUTHENTICATING;
|
|
|
|
os_memcpy(prev_pending_bssid, wpa_s->pending_bssid, ETH_ALEN);
|
2008-02-28 02:34:43 +01:00
|
|
|
|
|
|
|
if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
|
|
|
|
/*
|
|
|
|
* At least Host AP driver and a Prism3 card seemed to be
|
|
|
|
* generating streams of disconnected events when configuring
|
|
|
|
* IBSS for WPA-None. Ignore them for now.
|
|
|
|
*/
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Disconnect event - ignore in "
|
|
|
|
"IBSS/WPA-None mode");
|
2008-02-28 02:34:43 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wpa_s->wpa_state == WPA_4WAY_HANDSHAKE &&
|
2008-08-31 21:57:28 +02:00
|
|
|
wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
|
2008-02-28 02:34:43 +01:00
|
|
|
wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - "
|
|
|
|
"pre-shared key may be incorrect");
|
|
|
|
}
|
2010-09-06 16:28:45 +02:00
|
|
|
if (!wpa_s->auto_reconnect_disabled ||
|
|
|
|
wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Auto connect enabled: try to "
|
|
|
|
"reconnect (wps=%d)",
|
|
|
|
wpa_s->key_mgmt == WPA_KEY_MGMT_WPS);
|
2010-09-14 09:07:54 +02:00
|
|
|
if (wpa_s->wpa_state >= WPA_ASSOCIATING)
|
2010-09-06 16:28:45 +02:00
|
|
|
wpa_supplicant_req_scan(wpa_s, 0, 100000);
|
|
|
|
} else {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Auto connect disabled: do not "
|
|
|
|
"try to re-connect");
|
2010-09-06 16:28:45 +02:00
|
|
|
wpa_s->reassociate = 0;
|
|
|
|
wpa_s->disconnected = 1;
|
|
|
|
}
|
2008-02-28 02:34:43 +01:00
|
|
|
bssid = wpa_s->bssid;
|
2008-06-03 17:08:48 +02:00
|
|
|
if (is_zero_ether_addr(bssid))
|
2008-02-28 02:34:43 +01:00
|
|
|
bssid = wpa_s->pending_bssid;
|
2010-11-26 10:36:03 +01:00
|
|
|
wpas_connection_failed(wpa_s, bssid);
|
2008-02-28 02:34:43 +01:00
|
|
|
wpa_sm_notify_disassoc(wpa_s->wpa);
|
2010-04-11 20:25:15 +02:00
|
|
|
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" MACSTR
|
|
|
|
" reason=%d",
|
|
|
|
MAC2STR(bssid), reason_code);
|
2008-02-28 02:34:43 +01:00
|
|
|
if (wpa_supplicant_dynamic_keys(wpa_s)) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Disconnect event - remove keys");
|
2008-02-28 02:34:43 +01:00
|
|
|
wpa_s->keys_cleared = 0;
|
|
|
|
wpa_clear_keys(wpa_s, wpa_s->bssid);
|
|
|
|
}
|
|
|
|
wpa_supplicant_mark_disassoc(wpa_s);
|
2011-02-24 15:59:46 +01:00
|
|
|
|
|
|
|
if (authenticating && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))
|
|
|
|
sme_disassoc_while_authenticating(wpa_s, prev_pending_bssid);
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-11-08 03:43:12 +01:00
|
|
|
#ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
|
|
|
|
static void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx,
|
|
|
|
void *sock_ctx)
|
|
|
|
{
|
|
|
|
struct wpa_supplicant *wpa_s = eloop_ctx;
|
|
|
|
|
|
|
|
if (!wpa_s->pending_mic_error_report)
|
|
|
|
return;
|
|
|
|
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Sending pending MIC error report");
|
2008-11-08 03:43:12 +01:00
|
|
|
wpa_sm_key_request(wpa_s->wpa, 1, wpa_s->pending_mic_error_pairwise);
|
|
|
|
wpa_s->pending_mic_error_report = 0;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
|
|
|
|
|
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
static void
|
|
|
|
wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s,
|
|
|
|
union wpa_event_data *data)
|
|
|
|
{
|
|
|
|
int pairwise;
|
|
|
|
struct os_time t;
|
|
|
|
|
|
|
|
wpa_msg(wpa_s, MSG_WARNING, "Michael MIC failure detected");
|
|
|
|
pairwise = (data && data->michael_mic_failure.unicast);
|
|
|
|
os_get_time(&t);
|
2008-11-08 03:43:12 +01:00
|
|
|
if ((wpa_s->last_michael_mic_error &&
|
|
|
|
t.sec - wpa_s->last_michael_mic_error <= 60) ||
|
|
|
|
wpa_s->pending_mic_error_report) {
|
|
|
|
if (wpa_s->pending_mic_error_report) {
|
|
|
|
/*
|
|
|
|
* Send the pending MIC error report immediately since
|
|
|
|
* we are going to start countermeasures and AP better
|
|
|
|
* do the same.
|
|
|
|
*/
|
|
|
|
wpa_sm_key_request(wpa_s->wpa, 1,
|
|
|
|
wpa_s->pending_mic_error_pairwise);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Send the new MIC error report immediately since we are going
|
|
|
|
* to start countermeasures and AP better do the same.
|
|
|
|
*/
|
|
|
|
wpa_sm_key_request(wpa_s->wpa, 1, pairwise);
|
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
/* initialize countermeasures */
|
|
|
|
wpa_s->countermeasures = 1;
|
|
|
|
wpa_msg(wpa_s, MSG_WARNING, "TKIP countermeasures started");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Need to wait for completion of request frame. We do not get
|
|
|
|
* any callback for the message completion, so just wait a
|
|
|
|
* short while and hope for the best. */
|
|
|
|
os_sleep(0, 10000);
|
|
|
|
|
|
|
|
wpa_drv_set_countermeasures(wpa_s, 1);
|
|
|
|
wpa_supplicant_deauthenticate(wpa_s,
|
|
|
|
WLAN_REASON_MICHAEL_MIC_FAILURE);
|
|
|
|
eloop_cancel_timeout(wpa_supplicant_stop_countermeasures,
|
|
|
|
wpa_s, NULL);
|
|
|
|
eloop_register_timeout(60, 0,
|
|
|
|
wpa_supplicant_stop_countermeasures,
|
|
|
|
wpa_s, NULL);
|
|
|
|
/* TODO: mark the AP rejected for 60 second. STA is
|
|
|
|
* allowed to associate with another AP.. */
|
2008-11-08 03:43:12 +01:00
|
|
|
} else {
|
|
|
|
#ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
|
|
|
|
if (wpa_s->mic_errors_seen) {
|
|
|
|
/*
|
|
|
|
* Reduce the effectiveness of Michael MIC error
|
|
|
|
* reports as a means for attacking against TKIP if
|
|
|
|
* more than one MIC failure is noticed with the same
|
|
|
|
* PTK. We delay the transmission of the reports by a
|
|
|
|
* random time between 0 and 60 seconds in order to
|
|
|
|
* force the attacker wait 60 seconds before getting
|
|
|
|
* the information on whether a frame resulted in a MIC
|
|
|
|
* failure.
|
|
|
|
*/
|
|
|
|
u8 rval[4];
|
|
|
|
int sec;
|
|
|
|
|
|
|
|
if (os_get_random(rval, sizeof(rval)) < 0)
|
|
|
|
sec = os_random() % 60;
|
|
|
|
else
|
|
|
|
sec = WPA_GET_BE32(rval) % 60;
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Delay MIC error "
|
|
|
|
"report %d seconds", sec);
|
2008-11-08 03:43:12 +01:00
|
|
|
wpa_s->pending_mic_error_report = 1;
|
|
|
|
wpa_s->pending_mic_error_pairwise = pairwise;
|
|
|
|
eloop_cancel_timeout(
|
|
|
|
wpa_supplicant_delayed_mic_error_report,
|
|
|
|
wpa_s, NULL);
|
|
|
|
eloop_register_timeout(
|
|
|
|
sec, os_random() % 1000000,
|
|
|
|
wpa_supplicant_delayed_mic_error_report,
|
|
|
|
wpa_s, NULL);
|
|
|
|
} else {
|
|
|
|
wpa_sm_key_request(wpa_s->wpa, 1, pairwise);
|
|
|
|
}
|
|
|
|
#else /* CONFIG_DELAYED_MIC_ERROR_REPORT */
|
|
|
|
wpa_sm_key_request(wpa_s->wpa, 1, pairwise);
|
|
|
|
#endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
|
|
|
wpa_s->last_michael_mic_error = t.sec;
|
2008-11-08 03:43:12 +01:00
|
|
|
wpa_s->mic_errors_seen++;
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-02 20:57:00 +01:00
|
|
|
#ifdef CONFIG_TERMINATE_ONLASTIF
|
|
|
|
static int any_interfaces(struct wpa_supplicant *head)
|
|
|
|
{
|
|
|
|
struct wpa_supplicant *wpa_s;
|
|
|
|
|
|
|
|
for (wpa_s = head; wpa_s != NULL; wpa_s = wpa_s->next)
|
|
|
|
if (!wpa_s->interface_removed)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_TERMINATE_ONLASTIF */
|
|
|
|
|
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
static void
|
|
|
|
wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s,
|
|
|
|
union wpa_event_data *data)
|
|
|
|
{
|
|
|
|
if (os_strcmp(wpa_s->ifname, data->interface_status.ifname) != 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch (data->interface_status.ievent) {
|
|
|
|
case EVENT_INTERFACE_ADDED:
|
|
|
|
if (!wpa_s->interface_removed)
|
|
|
|
break;
|
|
|
|
wpa_s->interface_removed = 0;
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Configured interface was added");
|
2008-02-28 02:34:43 +01:00
|
|
|
if (wpa_supplicant_driver_init(wpa_s) < 0) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_msg(wpa_s, MSG_INFO, "Failed to initialize the "
|
|
|
|
"driver after interface was added");
|
2008-02-28 02:34:43 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case EVENT_INTERFACE_REMOVED:
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Configured interface was removed");
|
2008-02-28 02:34:43 +01:00
|
|
|
wpa_s->interface_removed = 1;
|
|
|
|
wpa_supplicant_mark_disassoc(wpa_s);
|
|
|
|
l2_packet_deinit(wpa_s->l2);
|
|
|
|
wpa_s->l2 = NULL;
|
2011-03-18 16:04:46 +01:00
|
|
|
#ifdef CONFIG_IBSS_RSN
|
2011-03-23 20:15:46 +01:00
|
|
|
ibss_rsn_deinit(wpa_s->ibss_rsn);
|
|
|
|
wpa_s->ibss_rsn = NULL;
|
2011-03-18 16:04:46 +01:00
|
|
|
#endif /* CONFIG_IBSS_RSN */
|
2009-03-02 20:57:00 +01:00
|
|
|
#ifdef CONFIG_TERMINATE_ONLASTIF
|
|
|
|
/* check if last interface */
|
|
|
|
if (!any_interfaces(wpa_s->global->ifaces))
|
|
|
|
eloop_terminate();
|
|
|
|
#endif /* CONFIG_TERMINATE_ONLASTIF */
|
2008-02-28 02:34:43 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_PEERKEY
|
|
|
|
static void
|
|
|
|
wpa_supplicant_event_stkstart(struct wpa_supplicant *wpa_s,
|
|
|
|
union wpa_event_data *data)
|
|
|
|
{
|
|
|
|
if (data == NULL)
|
|
|
|
return;
|
|
|
|
wpa_sm_stkstart(wpa_s->wpa, data->stkstart.peer);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_PEERKEY */
|
|
|
|
|
|
|
|
|
2010-10-07 09:26:56 +02:00
|
|
|
#ifdef CONFIG_TDLS
|
|
|
|
static void wpa_supplicant_event_tdls(struct wpa_supplicant *wpa_s,
|
|
|
|
union wpa_event_data *data)
|
|
|
|
{
|
|
|
|
if (data == NULL)
|
|
|
|
return;
|
|
|
|
switch (data->tdls.oper) {
|
|
|
|
case TDLS_REQUEST_SETUP:
|
|
|
|
wpa_tdls_start(wpa_s->wpa, data->tdls.peer);
|
|
|
|
break;
|
|
|
|
case TDLS_REQUEST_TEARDOWN:
|
2011-09-26 12:55:28 +02:00
|
|
|
wpa_tdls_send_teardown(wpa_s->wpa, data->tdls.peer,
|
|
|
|
data->tdls.reason_code);
|
2010-10-07 09:26:56 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_TDLS */
|
|
|
|
|
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
#ifdef CONFIG_IEEE80211R
|
|
|
|
static void
|
|
|
|
wpa_supplicant_event_ft_response(struct wpa_supplicant *wpa_s,
|
|
|
|
union wpa_event_data *data)
|
|
|
|
{
|
|
|
|
if (data == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (wpa_ft_process_response(wpa_s->wpa, data->ft_ies.ies,
|
|
|
|
data->ft_ies.ies_len,
|
|
|
|
data->ft_ies.ft_action,
|
2009-03-09 19:45:17 +01:00
|
|
|
data->ft_ies.target_ap,
|
|
|
|
data->ft_ies.ric_ies,
|
|
|
|
data->ft_ies.ric_ies_len) < 0) {
|
2008-02-28 02:34:43 +01:00
|
|
|
/* TODO: prevent MLME/driver from trying to associate? */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_IEEE80211R */
|
|
|
|
|
|
|
|
|
2009-01-15 00:21:55 +01:00
|
|
|
#ifdef CONFIG_IBSS_RSN
|
|
|
|
static void wpa_supplicant_event_ibss_rsn_start(struct wpa_supplicant *wpa_s,
|
|
|
|
union wpa_event_data *data)
|
|
|
|
{
|
2010-12-05 03:17:05 +01:00
|
|
|
struct wpa_ssid *ssid;
|
2011-03-16 15:26:26 +01:00
|
|
|
if (wpa_s->wpa_state < WPA_ASSOCIATED)
|
|
|
|
return;
|
2009-01-15 00:21:55 +01:00
|
|
|
if (data == NULL)
|
|
|
|
return;
|
2010-12-05 03:17:05 +01:00
|
|
|
ssid = wpa_s->current_ssid;
|
|
|
|
if (ssid == NULL)
|
|
|
|
return;
|
|
|
|
if (ssid->mode != WPAS_MODE_IBSS || !wpa_key_mgmt_wpa(ssid->key_mgmt))
|
|
|
|
return;
|
|
|
|
|
2009-01-15 00:21:55 +01:00
|
|
|
ibss_rsn_start(wpa_s->ibss_rsn, data->ibss_rsn_start.peer);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_IBSS_RSN */
|
|
|
|
|
|
|
|
|
2010-03-11 23:43:00 +01:00
|
|
|
#ifdef CONFIG_IEEE80211R
|
|
|
|
static void ft_rx_action(struct wpa_supplicant *wpa_s, const u8 *data,
|
|
|
|
size_t len)
|
|
|
|
{
|
|
|
|
const u8 *sta_addr, *target_ap_addr;
|
|
|
|
u16 status;
|
|
|
|
|
|
|
|
wpa_hexdump(MSG_MSGDUMP, "FT: RX Action", data, len);
|
|
|
|
if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))
|
|
|
|
return; /* only SME case supported for now */
|
|
|
|
if (len < 1 + 2 * ETH_ALEN + 2)
|
|
|
|
return;
|
|
|
|
if (data[0] != 2)
|
|
|
|
return; /* Only FT Action Response is supported for now */
|
|
|
|
sta_addr = data + 1;
|
|
|
|
target_ap_addr = data + 1 + ETH_ALEN;
|
|
|
|
status = WPA_GET_LE16(data + 1 + 2 * ETH_ALEN);
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "FT: Received FT Action Response: STA "
|
|
|
|
MACSTR " TargetAP " MACSTR " status %u",
|
|
|
|
MAC2STR(sta_addr), MAC2STR(target_ap_addr), status);
|
2010-03-11 23:43:00 +01:00
|
|
|
|
|
|
|
if (os_memcmp(sta_addr, wpa_s->own_addr, ETH_ALEN) != 0) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "FT: Foreign STA Address " MACSTR
|
|
|
|
" in FT Action Response", MAC2STR(sta_addr));
|
2010-03-11 23:43:00 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (status) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "FT: FT Action Response indicates "
|
|
|
|
"failure (status code %d)", status);
|
2010-03-11 23:43:00 +01:00
|
|
|
/* TODO: report error to FT code(?) */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wpa_ft_process_response(wpa_s->wpa, data + 1 + 2 * ETH_ALEN + 2,
|
|
|
|
len - (1 + 2 * ETH_ALEN + 2), 1,
|
|
|
|
target_ap_addr, NULL, 0) < 0)
|
|
|
|
return;
|
|
|
|
|
2010-03-13 17:26:25 +01:00
|
|
|
#ifdef CONFIG_SME
|
|
|
|
{
|
|
|
|
struct wpa_bss *bss;
|
|
|
|
bss = wpa_bss_get_bssid(wpa_s, target_ap_addr);
|
|
|
|
if (bss)
|
|
|
|
wpa_s->sme.freq = bss->freq;
|
2010-03-13 20:13:18 +01:00
|
|
|
wpa_s->sme.auth_alg = WPA_AUTH_ALG_FT;
|
2010-03-13 17:26:25 +01:00
|
|
|
sme_associate(wpa_s, WPAS_MODE_INFRA, target_ap_addr,
|
|
|
|
WLAN_AUTH_FT);
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_SME */
|
2010-03-11 23:43:00 +01:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_IEEE80211R */
|
|
|
|
|
|
|
|
|
2010-12-19 10:58:00 +01:00
|
|
|
static void wpa_supplicant_event_unprot_deauth(struct wpa_supplicant *wpa_s,
|
|
|
|
struct unprot_deauth *e)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_IEEE80211W
|
|
|
|
wpa_printf(MSG_DEBUG, "Unprotected Deauthentication frame "
|
|
|
|
"dropped: " MACSTR " -> " MACSTR
|
|
|
|
" (reason code %u)",
|
|
|
|
MAC2STR(e->sa), MAC2STR(e->da), e->reason_code);
|
|
|
|
sme_event_unprot_disconnect(wpa_s, e->sa, e->da, e->reason_code);
|
|
|
|
#endif /* CONFIG_IEEE80211W */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void wpa_supplicant_event_unprot_disassoc(struct wpa_supplicant *wpa_s,
|
|
|
|
struct unprot_disassoc *e)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_IEEE80211W
|
|
|
|
wpa_printf(MSG_DEBUG, "Unprotected Disassociation frame "
|
|
|
|
"dropped: " MACSTR " -> " MACSTR
|
|
|
|
" (reason code %u)",
|
|
|
|
MAC2STR(e->sa), MAC2STR(e->da), e->reason_code);
|
|
|
|
sme_event_unprot_disconnect(wpa_s, e->sa, e->da, e->reason_code);
|
|
|
|
#endif /* CONFIG_IEEE80211W */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-10-07 12:33:04 +02:00
|
|
|
static void wnm_action_rx(struct wpa_supplicant *wpa_s, struct rx_action *rx)
|
|
|
|
{
|
|
|
|
u8 action, mode;
|
|
|
|
const u8 *pos, *end;
|
|
|
|
|
|
|
|
if (rx->data == NULL || rx->len == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
pos = rx->data;
|
|
|
|
end = pos + rx->len;
|
|
|
|
action = *pos++;
|
|
|
|
|
|
|
|
wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR,
|
|
|
|
action, MAC2STR(rx->sa));
|
|
|
|
switch (action) {
|
|
|
|
case WNM_BSS_TRANS_MGMT_REQ:
|
|
|
|
if (pos + 5 > end)
|
|
|
|
break;
|
|
|
|
wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management "
|
|
|
|
"Request: dialog_token=%u request_mode=0x%x "
|
|
|
|
"disassoc_timer=%u validity_interval=%u",
|
|
|
|
pos[0], pos[1], WPA_GET_LE16(pos + 2), pos[4]);
|
|
|
|
mode = pos[1];
|
|
|
|
pos += 5;
|
|
|
|
if (mode & 0x08)
|
|
|
|
pos += 12; /* BSS Termination Duration */
|
|
|
|
if (mode & 0x10) {
|
|
|
|
char url[256];
|
|
|
|
if (pos + 1 > end || pos + 1 + pos[0] > end) {
|
|
|
|
wpa_printf(MSG_DEBUG, "WNM: Invalid BSS "
|
|
|
|
"Transition Management Request "
|
|
|
|
"(URL)");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
os_memcpy(url, pos + 1, pos[0]);
|
|
|
|
url[pos[0]] = '\0';
|
|
|
|
wpa_msg(wpa_s, MSG_INFO, "WNM: ESS Disassociation "
|
|
|
|
"Imminent - session_info_url=%s", url);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-03 12:10:12 +01:00
|
|
|
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
2008-02-28 02:34:43 +01:00
|
|
|
union wpa_event_data *data)
|
|
|
|
{
|
|
|
|
struct wpa_supplicant *wpa_s = ctx;
|
2010-04-11 20:25:15 +02:00
|
|
|
u16 reason_code = 0;
|
2008-02-28 02:34:43 +01:00
|
|
|
|
2010-05-23 09:27:32 +02:00
|
|
|
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED &&
|
|
|
|
event != EVENT_INTERFACE_ENABLED &&
|
|
|
|
event != EVENT_INTERFACE_STATUS) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Ignore event %d while interface is "
|
|
|
|
"disabled", event);
|
2010-05-23 09:27:32 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Event %d received on interface %s",
|
|
|
|
event, wpa_s->ifname);
|
2010-07-18 05:33:34 +02:00
|
|
|
|
2008-02-28 02:34:43 +01:00
|
|
|
switch (event) {
|
2009-03-20 21:26:41 +01:00
|
|
|
case EVENT_AUTH:
|
|
|
|
sme_event_auth(wpa_s, data);
|
|
|
|
break;
|
2008-02-28 02:34:43 +01:00
|
|
|
case EVENT_ASSOC:
|
|
|
|
wpa_supplicant_event_assoc(wpa_s, data);
|
|
|
|
break;
|
|
|
|
case EVENT_DISASSOC:
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Disassociation notification");
|
2010-08-17 20:04:38 +02:00
|
|
|
if (data) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u",
|
|
|
|
data->disassoc_info.reason_code);
|
2010-08-17 20:04:38 +02:00
|
|
|
if (data->disassoc_info.addr)
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " * address " MACSTR,
|
|
|
|
MAC2STR(data->disassoc_info.addr));
|
2010-08-17 20:04:38 +02:00
|
|
|
}
|
2010-01-03 17:22:22 +01:00
|
|
|
#ifdef CONFIG_AP
|
2010-09-04 20:50:12 +02:00
|
|
|
if (wpa_s->ap_iface && data && data->disassoc_info.addr) {
|
2010-01-03 17:22:22 +01:00
|
|
|
hostapd_notif_disassoc(wpa_s->ap_iface->bss[0],
|
|
|
|
data->disassoc_info.addr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_AP */
|
2010-07-18 23:30:25 +02:00
|
|
|
if (data) {
|
|
|
|
reason_code = data->disassoc_info.reason_code;
|
|
|
|
wpa_hexdump(MSG_DEBUG, "Disassociation frame IE(s)",
|
|
|
|
data->disassoc_info.ie,
|
|
|
|
data->disassoc_info.ie_len);
|
|
|
|
#ifdef CONFIG_P2P
|
|
|
|
wpas_p2p_disassoc_notif(
|
|
|
|
wpa_s, data->disassoc_info.addr, reason_code,
|
|
|
|
data->disassoc_info.ie,
|
|
|
|
data->disassoc_info.ie_len);
|
|
|
|
#endif /* CONFIG_P2P */
|
|
|
|
}
|
2009-12-04 20:44:13 +01:00
|
|
|
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
|
|
|
|
sme_event_disassoc(wpa_s, data);
|
2009-12-02 16:26:28 +01:00
|
|
|
/* fall through */
|
|
|
|
case EVENT_DEAUTH:
|
2010-04-11 20:25:15 +02:00
|
|
|
if (event == EVENT_DEAUTH) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG,
|
|
|
|
"Deauthentication notification");
|
2010-08-17 20:04:38 +02:00
|
|
|
if (data) {
|
2010-04-11 20:25:15 +02:00
|
|
|
reason_code = data->deauth_info.reason_code;
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u",
|
|
|
|
data->deauth_info.reason_code);
|
2010-08-17 20:04:38 +02:00
|
|
|
if (data->deauth_info.addr) {
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, " * address "
|
|
|
|
MACSTR,
|
|
|
|
MAC2STR(data->deauth_info.
|
|
|
|
addr));
|
2010-08-17 20:04:38 +02:00
|
|
|
}
|
2010-07-18 23:30:25 +02:00
|
|
|
wpa_hexdump(MSG_DEBUG,
|
|
|
|
"Deauthentication frame IE(s)",
|
|
|
|
data->deauth_info.ie,
|
|
|
|
data->deauth_info.ie_len);
|
|
|
|
#ifdef CONFIG_P2P
|
|
|
|
wpas_p2p_deauth_notif(
|
|
|
|
wpa_s, data->deauth_info.addr,
|
|
|
|
reason_code,
|
|
|
|
data->deauth_info.ie,
|
|
|
|
data->deauth_info.ie_len);
|
|
|
|
#endif /* CONFIG_P2P */
|
2010-08-17 20:04:38 +02:00
|
|
|
}
|
2010-04-11 20:25:15 +02:00
|
|
|
}
|
2010-01-03 17:22:22 +01:00
|
|
|
#ifdef CONFIG_AP
|
2010-09-04 20:50:12 +02:00
|
|
|
if (wpa_s->ap_iface && data && data->deauth_info.addr) {
|
2010-01-03 17:22:22 +01:00
|
|
|
hostapd_notif_disassoc(wpa_s->ap_iface->bss[0],
|
|
|
|
data->deauth_info.addr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_AP */
|
2010-04-11 20:25:15 +02:00
|
|
|
wpa_supplicant_event_disassoc(wpa_s, reason_code);
|
2008-02-28 02:34:43 +01:00
|
|
|
break;
|
|
|
|
case EVENT_MICHAEL_MIC_FAILURE:
|
|
|
|
wpa_supplicant_event_michael_mic_failure(wpa_s, data);
|
|
|
|
break;
|
|
|
|
#ifndef CONFIG_NO_SCAN_PROCESSING
|
|
|
|
case EVENT_SCAN_RESULTS:
|
2010-01-02 12:57:44 +01:00
|
|
|
wpa_supplicant_event_scan_results(wpa_s, data);
|
2008-02-28 02:34:43 +01:00
|
|
|
break;
|
|
|
|
#endif /* CONFIG_NO_SCAN_PROCESSING */
|
|
|
|
case EVENT_ASSOCINFO:
|
|
|
|
wpa_supplicant_event_associnfo(wpa_s, data);
|
|
|
|
break;
|
|
|
|
case EVENT_INTERFACE_STATUS:
|
|
|
|
wpa_supplicant_event_interface_status(wpa_s, data);
|
|
|
|
break;
|
|
|
|
case EVENT_PMKID_CANDIDATE:
|
|
|
|
wpa_supplicant_event_pmkid_candidate(wpa_s, data);
|
|
|
|
break;
|
|
|
|
#ifdef CONFIG_PEERKEY
|
|
|
|
case EVENT_STKSTART:
|
|
|
|
wpa_supplicant_event_stkstart(wpa_s, data);
|
|
|
|
break;
|
|
|
|
#endif /* CONFIG_PEERKEY */
|
2010-10-07 09:26:56 +02:00
|
|
|
#ifdef CONFIG_TDLS
|
|
|
|
case EVENT_TDLS:
|
|
|
|
wpa_supplicant_event_tdls(wpa_s, data);
|
|
|
|
break;
|
|
|
|
#endif /* CONFIG_TDLS */
|
2008-02-28 02:34:43 +01:00
|
|
|
#ifdef CONFIG_IEEE80211R
|
|
|
|
case EVENT_FT_RESPONSE:
|
|
|
|
wpa_supplicant_event_ft_response(wpa_s, data);
|
|
|
|
break;
|
|
|
|
#endif /* CONFIG_IEEE80211R */
|
2009-01-15 00:21:55 +01:00
|
|
|
#ifdef CONFIG_IBSS_RSN
|
|
|
|
case EVENT_IBSS_RSN_START:
|
|
|
|
wpa_supplicant_event_ibss_rsn_start(wpa_s, data);
|
|
|
|
break;
|
|
|
|
#endif /* CONFIG_IBSS_RSN */
|
2009-04-01 16:10:36 +02:00
|
|
|
case EVENT_ASSOC_REJECT:
|
2010-11-26 16:38:46 +01:00
|
|
|
if (data->assoc_reject.bssid)
|
|
|
|
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
|
|
|
|
"bssid=" MACSTR " status_code=%u",
|
|
|
|
MAC2STR(data->assoc_reject.bssid),
|
|
|
|
data->assoc_reject.status_code);
|
|
|
|
else
|
|
|
|
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
|
|
|
|
"status_code=%u",
|
|
|
|
data->assoc_reject.status_code);
|
2010-10-27 19:28:16 +02:00
|
|
|
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
|
|
|
|
sme_event_assoc_reject(wpa_s, data);
|
2009-04-01 16:10:36 +02:00
|
|
|
break;
|
2009-04-23 23:08:24 +02:00
|
|
|
case EVENT_AUTH_TIMED_OUT:
|
2010-10-27 19:28:16 +02:00
|
|
|
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
|
|
|
|
sme_event_auth_timed_out(wpa_s, data);
|
2009-04-23 23:08:24 +02:00
|
|
|
break;
|
|
|
|
case EVENT_ASSOC_TIMED_OUT:
|
2010-10-27 19:28:16 +02:00
|
|
|
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
|
|
|
|
sme_event_assoc_timed_out(wpa_s, data);
|
2009-04-23 23:08:24 +02:00
|
|
|
break;
|
2009-12-13 22:05:39 +01:00
|
|
|
case EVENT_TX_STATUS:
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "EVENT_TX_STATUS dst=" MACSTR
|
|
|
|
" type=%d stype=%d",
|
|
|
|
MAC2STR(data->tx_status.dst),
|
|
|
|
data->tx_status.type, data->tx_status.stype);
|
2011-09-29 18:22:08 +02:00
|
|
|
#ifdef CONFIG_AP
|
2010-07-18 23:30:25 +02:00
|
|
|
if (wpa_s->ap_iface == NULL) {
|
2011-09-29 18:22:08 +02:00
|
|
|
#ifdef CONFIG_OFFCHANNEL
|
2010-07-18 23:30:25 +02:00
|
|
|
if (data->tx_status.type == WLAN_FC_TYPE_MGMT &&
|
|
|
|
data->tx_status.stype == WLAN_FC_STYPE_ACTION)
|
2011-09-29 18:22:08 +02:00
|
|
|
offchannel_send_action_tx_status(
|
2010-07-18 23:30:25 +02:00
|
|
|
wpa_s, data->tx_status.dst,
|
|
|
|
data->tx_status.data,
|
|
|
|
data->tx_status.data_len,
|
2010-10-19 11:47:33 +02:00
|
|
|
data->tx_status.ack ?
|
2011-09-29 18:22:08 +02:00
|
|
|
OFFCHANNEL_SEND_ACTION_SUCCESS :
|
|
|
|
OFFCHANNEL_SEND_ACTION_NO_ACK);
|
|
|
|
#endif /* CONFIG_OFFCHANNEL */
|
2010-07-18 23:30:25 +02:00
|
|
|
break;
|
|
|
|
}
|
2011-09-29 18:22:08 +02:00
|
|
|
#endif /* CONFIG_AP */
|
|
|
|
#ifdef CONFIG_OFFCHANNEL
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "EVENT_TX_STATUS pending_dst="
|
|
|
|
MACSTR, MAC2STR(wpa_s->parent->pending_action_dst));
|
2010-07-18 23:30:25 +02:00
|
|
|
/*
|
|
|
|
* Catch TX status events for Action frames we sent via group
|
|
|
|
* interface in GO mode.
|
|
|
|
*/
|
|
|
|
if (data->tx_status.type == WLAN_FC_TYPE_MGMT &&
|
|
|
|
data->tx_status.stype == WLAN_FC_STYPE_ACTION &&
|
|
|
|
os_memcmp(wpa_s->parent->pending_action_dst,
|
|
|
|
data->tx_status.dst, ETH_ALEN) == 0) {
|
2011-09-29 18:22:08 +02:00
|
|
|
offchannel_send_action_tx_status(
|
2010-07-18 23:30:25 +02:00
|
|
|
wpa_s->parent, data->tx_status.dst,
|
|
|
|
data->tx_status.data,
|
|
|
|
data->tx_status.data_len,
|
2010-11-24 13:25:33 +01:00
|
|
|
data->tx_status.ack ?
|
2011-09-29 18:22:08 +02:00
|
|
|
OFFCHANNEL_SEND_ACTION_SUCCESS :
|
|
|
|
OFFCHANNEL_SEND_ACTION_NO_ACK);
|
2009-12-13 22:05:39 +01:00
|
|
|
break;
|
2010-07-18 23:30:25 +02:00
|
|
|
}
|
2011-09-29 18:22:08 +02:00
|
|
|
#endif /* CONFIG_OFFCHANNEL */
|
|
|
|
#ifdef CONFIG_AP
|
2009-12-13 22:05:39 +01:00
|
|
|
switch (data->tx_status.type) {
|
|
|
|
case WLAN_FC_TYPE_MGMT:
|
|
|
|
ap_mgmt_tx_cb(wpa_s, data->tx_status.data,
|
|
|
|
data->tx_status.data_len,
|
|
|
|
data->tx_status.stype,
|
|
|
|
data->tx_status.ack);
|
|
|
|
break;
|
|
|
|
case WLAN_FC_TYPE_DATA:
|
|
|
|
ap_tx_status(wpa_s, data->tx_status.dst,
|
|
|
|
data->tx_status.data,
|
|
|
|
data->tx_status.data_len,
|
|
|
|
data->tx_status.ack);
|
|
|
|
break;
|
|
|
|
}
|
2011-09-29 18:22:08 +02:00
|
|
|
#endif /* CONFIG_AP */
|
2009-12-13 22:05:39 +01:00
|
|
|
break;
|
2011-09-29 18:22:08 +02:00
|
|
|
#ifdef CONFIG_AP
|
2011-10-20 20:03:08 +02:00
|
|
|
case EVENT_DRIVER_CLIENT_POLL_OK:
|
|
|
|
ap_client_poll_ok(wpa_s, data->client_poll.addr);
|
|
|
|
break;
|
2009-12-13 22:05:39 +01:00
|
|
|
case EVENT_RX_FROM_UNKNOWN:
|
|
|
|
if (wpa_s->ap_iface == NULL)
|
|
|
|
break;
|
2011-10-20 20:51:32 +02:00
|
|
|
ap_rx_from_unknown_sta(wpa_s, data->rx_from_unknown.addr,
|
|
|
|
data->rx_from_unknown.wds);
|
2009-12-13 22:05:39 +01:00
|
|
|
break;
|
|
|
|
case EVENT_RX_MGMT:
|
2010-07-18 23:30:25 +02:00
|
|
|
if (wpa_s->ap_iface == NULL) {
|
|
|
|
#ifdef CONFIG_P2P
|
|
|
|
u16 fc, stype;
|
|
|
|
const struct ieee80211_mgmt *mgmt;
|
|
|
|
mgmt = (const struct ieee80211_mgmt *)
|
|
|
|
data->rx_mgmt.frame;
|
|
|
|
fc = le_to_host16(mgmt->frame_control);
|
|
|
|
stype = WLAN_FC_GET_STYPE(fc);
|
|
|
|
if (stype == WLAN_FC_STYPE_PROBE_REQ &&
|
|
|
|
data->rx_mgmt.frame_len > 24) {
|
|
|
|
const u8 *src = mgmt->sa;
|
|
|
|
const u8 *ie = mgmt->u.probe_req.variable;
|
|
|
|
size_t ie_len = data->rx_mgmt.frame_len -
|
|
|
|
(mgmt->u.probe_req.variable -
|
|
|
|
data->rx_mgmt.frame);
|
2011-07-15 19:25:53 +02:00
|
|
|
wpas_p2p_probe_req_rx(wpa_s, src, mgmt->da,
|
|
|
|
mgmt->bssid, ie, ie_len);
|
2010-07-18 23:30:25 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_P2P */
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "AP: ignore received "
|
|
|
|
"management frame in non-AP mode");
|
2009-12-13 22:05:39 +01:00
|
|
|
break;
|
2010-07-18 23:30:25 +02:00
|
|
|
}
|
2010-01-03 11:37:02 +01:00
|
|
|
ap_mgmt_rx(wpa_s, &data->rx_mgmt);
|
2009-12-13 22:05:39 +01:00
|
|
|
break;
|
|
|
|
#endif /* CONFIG_AP */
|
2010-03-11 23:43:00 +01:00
|
|
|
case EVENT_RX_ACTION:
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Received Action frame: SA=" MACSTR
|
|
|
|
" Category=%u DataLen=%d freq=%d MHz",
|
|
|
|
MAC2STR(data->rx_action.sa),
|
|
|
|
data->rx_action.category, (int) data->rx_action.len,
|
|
|
|
data->rx_action.freq);
|
2010-03-11 23:43:00 +01:00
|
|
|
#ifdef CONFIG_IEEE80211R
|
|
|
|
if (data->rx_action.category == WLAN_ACTION_FT) {
|
|
|
|
ft_rx_action(wpa_s, data->rx_action.data,
|
|
|
|
data->rx_action.len);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_IEEE80211R */
|
2010-12-19 10:58:00 +01:00
|
|
|
#ifdef CONFIG_IEEE80211W
|
|
|
|
#ifdef CONFIG_SME
|
|
|
|
if (data->rx_action.category == WLAN_ACTION_SA_QUERY) {
|
|
|
|
sme_sa_query_rx(wpa_s, data->rx_action.sa,
|
|
|
|
data->rx_action.data,
|
|
|
|
data->rx_action.len);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_SME */
|
|
|
|
#endif /* CONFIG_IEEE80211W */
|
2011-09-28 18:44:25 +02:00
|
|
|
#ifdef CONFIG_GAS
|
|
|
|
if (data->rx_action.category == WLAN_ACTION_PUBLIC &&
|
|
|
|
gas_query_rx(wpa_s->gas, data->rx_action.da,
|
|
|
|
data->rx_action.sa, data->rx_action.bssid,
|
|
|
|
data->rx_action.data, data->rx_action.len,
|
|
|
|
data->rx_action.freq) == 0)
|
|
|
|
break;
|
|
|
|
#endif /* CONFIG_GAS */
|
2011-10-07 12:33:04 +02:00
|
|
|
if (data->rx_action.category == WLAN_ACTION_WNM) {
|
|
|
|
wnm_action_rx(wpa_s, &data->rx_action);
|
|
|
|
break;
|
|
|
|
}
|
2011-09-26 12:55:27 +02:00
|
|
|
#ifdef CONFIG_TDLS
|
|
|
|
if (data->rx_action.category == WLAN_ACTION_PUBLIC &&
|
|
|
|
data->rx_action.len >= 4 &&
|
|
|
|
data->rx_action.data[0] == WLAN_TDLS_DISCOVERY_RESPONSE) {
|
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "TDLS: Received Discovery "
|
|
|
|
"Response from " MACSTR,
|
|
|
|
MAC2STR(data->rx_action.sa));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_TDLS */
|
2010-07-18 23:30:25 +02:00
|
|
|
#ifdef CONFIG_P2P
|
|
|
|
wpas_p2p_rx_action(wpa_s, data->rx_action.da,
|
|
|
|
data->rx_action.sa,
|
|
|
|
data->rx_action.bssid,
|
|
|
|
data->rx_action.category,
|
|
|
|
data->rx_action.data,
|
|
|
|
data->rx_action.len, data->rx_action.freq);
|
2011-02-08 13:32:35 +01:00
|
|
|
#endif /* CONFIG_P2P */
|
|
|
|
break;
|
|
|
|
case EVENT_RX_PROBE_REQ:
|
2011-04-14 01:39:25 +02:00
|
|
|
if (data->rx_probe_req.sa == NULL ||
|
|
|
|
data->rx_probe_req.ie == NULL)
|
|
|
|
break;
|
2011-02-08 13:32:35 +01:00
|
|
|
#ifdef CONFIG_AP
|
|
|
|
if (wpa_s->ap_iface) {
|
|
|
|
hostapd_probe_req_rx(wpa_s->ap_iface->bss[0],
|
|
|
|
data->rx_probe_req.sa,
|
2011-07-15 19:25:53 +02:00
|
|
|
data->rx_probe_req.da,
|
|
|
|
data->rx_probe_req.bssid,
|
2011-02-08 13:32:35 +01:00
|
|
|
data->rx_probe_req.ie,
|
|
|
|
data->rx_probe_req.ie_len);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_AP */
|
|
|
|
#ifdef CONFIG_P2P
|
|
|
|
wpas_p2p_probe_req_rx(wpa_s, data->rx_probe_req.sa,
|
2011-07-15 19:25:53 +02:00
|
|
|
data->rx_probe_req.da,
|
|
|
|
data->rx_probe_req.bssid,
|
2011-02-08 13:32:35 +01:00
|
|
|
data->rx_probe_req.ie,
|
|
|
|
data->rx_probe_req.ie_len);
|
2010-07-18 23:30:25 +02:00
|
|
|
#endif /* CONFIG_P2P */
|
2010-03-11 23:43:00 +01:00
|
|
|
break;
|
2010-07-18 23:30:25 +02:00
|
|
|
case EVENT_REMAIN_ON_CHANNEL:
|
2011-09-29 18:22:08 +02:00
|
|
|
#ifdef CONFIG_OFFCHANNEL
|
|
|
|
offchannel_remain_on_channel_cb(
|
|
|
|
wpa_s, data->remain_on_channel.freq,
|
|
|
|
data->remain_on_channel.duration);
|
|
|
|
#endif /* CONFIG_OFFCHANNEL */
|
|
|
|
#ifdef CONFIG_P2P
|
2010-07-18 23:30:25 +02:00
|
|
|
wpas_p2p_remain_on_channel_cb(
|
|
|
|
wpa_s, data->remain_on_channel.freq,
|
|
|
|
data->remain_on_channel.duration);
|
2011-09-29 18:22:08 +02:00
|
|
|
#endif /* CONFIG_P2P */
|
2010-07-18 23:30:25 +02:00
|
|
|
break;
|
|
|
|
case EVENT_CANCEL_REMAIN_ON_CHANNEL:
|
2011-09-29 18:22:08 +02:00
|
|
|
#ifdef CONFIG_OFFCHANNEL
|
|
|
|
offchannel_cancel_remain_on_channel_cb(
|
|
|
|
wpa_s, data->remain_on_channel.freq);
|
|
|
|
#endif /* CONFIG_OFFCHANNEL */
|
|
|
|
#ifdef CONFIG_P2P
|
2010-07-18 23:30:25 +02:00
|
|
|
wpas_p2p_cancel_remain_on_channel_cb(
|
|
|
|
wpa_s, data->remain_on_channel.freq);
|
2011-09-29 18:22:08 +02:00
|
|
|
#endif /* CONFIG_P2P */
|
2010-07-18 23:30:25 +02:00
|
|
|
break;
|
2011-09-29 18:22:08 +02:00
|
|
|
#ifdef CONFIG_P2P
|
2011-02-24 20:51:17 +01:00
|
|
|
case EVENT_P2P_DEV_FOUND: {
|
|
|
|
struct p2p_peer_info peer_info;
|
|
|
|
|
|
|
|
os_memset(&peer_info, 0, sizeof(peer_info));
|
|
|
|
if (data->p2p_dev_found.dev_addr)
|
|
|
|
os_memcpy(peer_info.p2p_device_addr,
|
|
|
|
data->p2p_dev_found.dev_addr, ETH_ALEN);
|
|
|
|
if (data->p2p_dev_found.pri_dev_type)
|
|
|
|
os_memcpy(peer_info.pri_dev_type,
|
|
|
|
data->p2p_dev_found.pri_dev_type,
|
|
|
|
sizeof(peer_info.pri_dev_type));
|
|
|
|
if (data->p2p_dev_found.dev_name)
|
|
|
|
os_strlcpy(peer_info.device_name,
|
|
|
|
data->p2p_dev_found.dev_name,
|
|
|
|
sizeof(peer_info.device_name));
|
|
|
|
peer_info.config_methods = data->p2p_dev_found.config_methods;
|
|
|
|
peer_info.dev_capab = data->p2p_dev_found.dev_capab;
|
|
|
|
peer_info.group_capab = data->p2p_dev_found.group_capab;
|
|
|
|
|
2011-02-24 20:59:58 +01:00
|
|
|
/*
|
|
|
|
* FIX: new_device=1 is not necessarily correct. We should
|
|
|
|
* maintain a P2P peer database in wpa_supplicant and update
|
|
|
|
* this information based on whether the peer is truly new.
|
|
|
|
*/
|
|
|
|
wpas_dev_found(wpa_s, data->p2p_dev_found.addr, &peer_info, 1);
|
2010-12-30 11:48:55 +01:00
|
|
|
break;
|
2011-02-24 20:51:17 +01:00
|
|
|
}
|
2010-12-30 11:48:55 +01:00
|
|
|
case EVENT_P2P_GO_NEG_REQ_RX:
|
|
|
|
wpas_go_neg_req_rx(wpa_s, data->p2p_go_neg_req_rx.src,
|
|
|
|
data->p2p_go_neg_req_rx.dev_passwd_id);
|
|
|
|
break;
|
|
|
|
case EVENT_P2P_GO_NEG_COMPLETED:
|
|
|
|
wpas_go_neg_completed(wpa_s, data->p2p_go_neg_completed.res);
|
|
|
|
break;
|
|
|
|
case EVENT_P2P_PROV_DISC_REQUEST:
|
|
|
|
wpas_prov_disc_req(wpa_s, data->p2p_prov_disc_req.peer,
|
|
|
|
data->p2p_prov_disc_req.config_methods,
|
|
|
|
data->p2p_prov_disc_req.dev_addr,
|
|
|
|
data->p2p_prov_disc_req.pri_dev_type,
|
|
|
|
data->p2p_prov_disc_req.dev_name,
|
|
|
|
data->p2p_prov_disc_req.supp_config_methods,
|
|
|
|
data->p2p_prov_disc_req.dev_capab,
|
|
|
|
data->p2p_prov_disc_req.group_capab);
|
|
|
|
break;
|
|
|
|
case EVENT_P2P_PROV_DISC_RESPONSE:
|
|
|
|
wpas_prov_disc_resp(wpa_s, data->p2p_prov_disc_resp.peer,
|
|
|
|
data->p2p_prov_disc_resp.config_methods);
|
|
|
|
break;
|
|
|
|
case EVENT_P2P_SD_REQUEST:
|
|
|
|
wpas_sd_request(wpa_s, data->p2p_sd_req.freq,
|
|
|
|
data->p2p_sd_req.sa,
|
|
|
|
data->p2p_sd_req.dialog_token,
|
|
|
|
data->p2p_sd_req.update_indic,
|
|
|
|
data->p2p_sd_req.tlvs,
|
|
|
|
data->p2p_sd_req.tlvs_len);
|
|
|
|
break;
|
|
|
|
case EVENT_P2P_SD_RESPONSE:
|
|
|
|
wpas_sd_response(wpa_s, data->p2p_sd_resp.sa,
|
|
|
|
data->p2p_sd_resp.update_indic,
|
|
|
|
data->p2p_sd_resp.tlvs,
|
|
|
|
data->p2p_sd_resp.tlvs_len);
|
|
|
|
break;
|
2010-07-18 23:30:25 +02:00
|
|
|
#endif /* CONFIG_P2P */
|
2010-01-03 16:44:40 +01:00
|
|
|
case EVENT_EAPOL_RX:
|
|
|
|
wpa_supplicant_rx_eapol(wpa_s, data->eapol_rx.src,
|
|
|
|
data->eapol_rx.data,
|
|
|
|
data->eapol_rx.data_len);
|
|
|
|
break;
|
2010-03-29 00:32:34 +02:00
|
|
|
case EVENT_SIGNAL_CHANGE:
|
|
|
|
bgscan_notify_signal_change(
|
2010-08-27 15:58:06 +02:00
|
|
|
wpa_s, data->signal_change.above_threshold,
|
2010-10-12 19:03:36 +02:00
|
|
|
data->signal_change.current_signal,
|
|
|
|
data->signal_change.current_noise,
|
|
|
|
data->signal_change.current_txrate);
|
2010-03-29 00:32:34 +02:00
|
|
|
break;
|
2010-05-23 09:27:32 +02:00
|
|
|
case EVENT_INTERFACE_ENABLED:
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Interface was enabled");
|
2010-05-23 09:27:32 +02:00
|
|
|
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
|
2010-10-07 09:41:58 +02:00
|
|
|
#ifdef CONFIG_AP
|
2010-10-06 16:10:07 +02:00
|
|
|
if (!wpa_s->ap_iface) {
|
|
|
|
wpa_supplicant_set_state(wpa_s,
|
|
|
|
WPA_DISCONNECTED);
|
|
|
|
wpa_supplicant_req_scan(wpa_s, 0, 0);
|
|
|
|
} else
|
|
|
|
wpa_supplicant_set_state(wpa_s,
|
|
|
|
WPA_COMPLETED);
|
2010-10-07 09:41:58 +02:00
|
|
|
#else /* CONFIG_AP */
|
|
|
|
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
|
|
|
|
wpa_supplicant_req_scan(wpa_s, 0, 0);
|
|
|
|
#endif /* CONFIG_AP */
|
2010-05-23 09:27:32 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case EVENT_INTERFACE_DISABLED:
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Interface was disabled");
|
2010-05-23 09:27:32 +02:00
|
|
|
wpa_supplicant_mark_disassoc(wpa_s);
|
|
|
|
wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
|
|
|
|
break;
|
2010-10-15 17:55:22 +02:00
|
|
|
case EVENT_CHANNEL_LIST_CHANGED:
|
2010-10-20 18:30:55 +02:00
|
|
|
if (wpa_s->drv_priv == NULL)
|
|
|
|
break; /* Ignore event during drv initialization */
|
2010-10-15 17:55:22 +02:00
|
|
|
#ifdef CONFIG_P2P
|
|
|
|
wpas_p2p_update_channel_list(wpa_s);
|
2010-10-25 18:16:11 +02:00
|
|
|
#endif /* CONFIG_P2P */
|
|
|
|
break;
|
|
|
|
case EVENT_INTERFACE_UNAVAILABLE:
|
|
|
|
#ifdef CONFIG_P2P
|
|
|
|
wpas_p2p_interface_unavailable(wpa_s);
|
2010-11-10 12:33:47 +01:00
|
|
|
#endif /* CONFIG_P2P */
|
|
|
|
break;
|
|
|
|
case EVENT_BEST_CHANNEL:
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_dbg(wpa_s, MSG_DEBUG, "Best channel event received "
|
|
|
|
"(%d %d %d)",
|
|
|
|
data->best_chan.freq_24, data->best_chan.freq_5,
|
|
|
|
data->best_chan.freq_overall);
|
2010-11-10 12:33:47 +01:00
|
|
|
wpa_s->best_24_freq = data->best_chan.freq_24;
|
|
|
|
wpa_s->best_5_freq = data->best_chan.freq_5;
|
|
|
|
wpa_s->best_overall_freq = data->best_chan.freq_overall;
|
|
|
|
#ifdef CONFIG_P2P
|
|
|
|
wpas_p2p_update_best_channels(wpa_s, data->best_chan.freq_24,
|
|
|
|
data->best_chan.freq_5,
|
|
|
|
data->best_chan.freq_overall);
|
2010-10-15 17:55:22 +02:00
|
|
|
#endif /* CONFIG_P2P */
|
|
|
|
break;
|
2010-12-19 10:58:00 +01:00
|
|
|
case EVENT_UNPROT_DEAUTH:
|
|
|
|
wpa_supplicant_event_unprot_deauth(wpa_s,
|
|
|
|
&data->unprot_deauth);
|
|
|
|
break;
|
|
|
|
case EVENT_UNPROT_DISASSOC:
|
|
|
|
wpa_supplicant_event_unprot_disassoc(wpa_s,
|
|
|
|
&data->unprot_disassoc);
|
|
|
|
break;
|
2010-12-28 16:15:01 +01:00
|
|
|
case EVENT_STATION_LOW_ACK:
|
|
|
|
#ifdef CONFIG_AP
|
|
|
|
if (wpa_s->ap_iface && data)
|
|
|
|
hostapd_event_sta_low_ack(wpa_s->ap_iface->bss[0],
|
|
|
|
data->low_ack.addr);
|
|
|
|
#endif /* CONFIG_AP */
|
|
|
|
break;
|
2011-03-18 16:04:46 +01:00
|
|
|
case EVENT_IBSS_PEER_LOST:
|
|
|
|
#ifdef CONFIG_IBSS_RSN
|
|
|
|
ibss_rsn_stop(wpa_s->ibss_rsn, data->ibss_peer_lost.peer);
|
|
|
|
#endif /* CONFIG_IBSS_RSN */
|
|
|
|
break;
|
2011-07-12 20:22:51 +02:00
|
|
|
case EVENT_DRIVER_GTK_REKEY:
|
|
|
|
if (os_memcmp(data->driver_gtk_rekey.bssid,
|
|
|
|
wpa_s->bssid, ETH_ALEN))
|
|
|
|
break;
|
|
|
|
if (!wpa_s->wpa)
|
|
|
|
break;
|
|
|
|
wpa_sm_update_replay_ctr(wpa_s->wpa,
|
|
|
|
data->driver_gtk_rekey.replay_ctr);
|
|
|
|
break;
|
2011-09-27 21:21:29 +02:00
|
|
|
case EVENT_SCHED_SCAN_STOPPED:
|
|
|
|
wpa_s->sched_scanning = 0;
|
|
|
|
wpa_supplicant_notify_scanning(wpa_s, 0);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we timed out, start a new sched scan to continue
|
|
|
|
* searching for more SSIDs.
|
|
|
|
*/
|
|
|
|
if (wpa_s->sched_scan_timed_out)
|
|
|
|
wpa_supplicant_req_sched_scan(wpa_s);
|
|
|
|
break;
|
2011-03-15 17:59:36 +01:00
|
|
|
case EVENT_WPS_BUTTON_PUSHED:
|
|
|
|
#ifdef CONFIG_WPS
|
|
|
|
wpas_wps_start_pbc(wpa_s, NULL, 0);
|
|
|
|
#endif /* CONFIG_WPS */
|
|
|
|
break;
|
2008-02-28 02:34:43 +01:00
|
|
|
default:
|
2011-02-10 19:14:46 +01:00
|
|
|
wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
|
2008-02-28 02:34:43 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|