#include "common.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "eap_peer/eap.h"
+#include "eap_server/eap_methods.h"
#include "wpa.h"
#include "eloop.h"
-#include "drivers/driver.h"
#include "config.h"
#include "l2_packet/l2_packet.h"
#include "wpa_supplicant_i.h"
+#include "driver_i.h"
#include "ctrl_iface.h"
-#include "ctrl_iface_dbus.h"
#include "pcsc_funcs.h"
#include "version.h"
#include "preauth.h"
#include "wpas_glue.h"
#include "wps_supplicant.h"
#include "ibss_rsn.h"
+#include "sme.h"
+#include "ap.h"
+#include "notify.h"
+#include "bgscan.h"
const char *wpa_supplicant_version =
"wpa_supplicant v" VERSION_STR "\n"
extern int wpa_debug_level;
extern int wpa_debug_show_keys;
extern int wpa_debug_timestamp;
+extern struct wpa_driver_ops *wpa_drivers[];
/* Configure default/group WEP keys for static WEP */
-static int wpa_set_wep_keys(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid)
+int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
{
int i, set = 0;
int sec, int usec)
{
if (wpa_s->conf && wpa_s->conf->ap_scan == 0 &&
- wpa_s->driver && IS_WIRED(wpa_s->driver))
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED))
return;
wpa_msg(wpa_s, MSG_DEBUG, "Setting authentication timeout: %d sec "
EAPOL_REQUIRE_KEY_BROADCAST;
}
- if (wpa_s->conf && wpa_s->driver && IS_WIRED(wpa_s->driver)) {
+ if (wpa_s->conf && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED))
eapol_conf.required_keys = 0;
- }
}
if (wpa_s->conf)
eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
{
+ bgscan_deinit(wpa_s);
scard_deinit(wpa_s->scard);
wpa_s->scard = NULL;
wpa_sm_set_scard_ctx(wpa_s->wpa, NULL);
wpas_wps_deinit(wpa_s);
+ wpabuf_free(wpa_s->pending_eapol_rx);
+ wpa_s->pending_eapol_rx = NULL;
+
#ifdef CONFIG_IBSS_RSN
ibss_rsn_deinit(wpa_s->ibss_rsn);
wpa_s->ibss_rsn = NULL;
#endif /* CONFIG_IBSS_RSN */
+
+#ifdef CONFIG_SME
+ os_free(wpa_s->sme.ft_ies);
+ wpa_s->sme.ft_ies = NULL;
+ wpa_s->sme.ft_ies_len = 0;
+#endif /* CONFIG_SME */
+
+#ifdef CONFIG_AP
+ wpa_supplicant_ap_deinit(wpa_s);
+#endif /* CONFIG_AP */
}
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 1, 0, NULL, 0, NULL, 0);
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 2, 0, NULL, 0, NULL, 0);
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 3, 0, NULL, 0, NULL, 0);
+#ifdef CONFIG_IEEE80211W
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 4, 0, NULL, 0, NULL, 0);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 5, 0, NULL, 0, NULL, 0);
+#endif /* CONFIG_IEEE80211W */
if (addr) {
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL,
0);
return "INACTIVE";
case WPA_SCANNING:
return "SCANNING";
+ case WPA_AUTHENTICATING:
+ return "AUTHENTICATING";
case WPA_ASSOCIATING:
return "ASSOCIATING";
case WPA_ASSOCIATED:
wpa_supplicant_state_txt(wpa_s->wpa_state),
wpa_supplicant_state_txt(state));
- wpa_supplicant_dbus_notify_state_change(wpa_s, state,
- wpa_s->wpa_state);
+ if (state != WPA_SCANNING)
+ wpa_supplicant_notify_scanning(wpa_s, 0);
+
+ wpas_notify_state_changed(wpa_s, state, wpa_s->wpa_state);
if (state == WPA_COMPLETED && wpa_s->new_connection) {
#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
static void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
{
+ wpa_states old_state = wpa_s->wpa_state;
wpa_s->pairwise_cipher = 0;
wpa_s->group_cipher = 0;
wpa_s->mgmt_group_cipher = 0;
wpa_s->key_mgmt = 0;
wpa_s->wpa_state = WPA_DISCONNECTED;
+ wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
}
int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
{
struct wpa_config *conf;
+ struct wpa_ssid *old_ssid;
int reconf_ctrl;
+ int old_ap_scan;
+
if (wpa_s->confname == NULL)
return -1;
conf = wpa_config_read(wpa_s->confname);
}
eapol_sm_invalidate_cached_session(wpa_s->eapol);
+ old_ssid = wpa_s->current_ssid;
wpa_s->current_ssid = NULL;
+ if (old_ssid != wpa_s->current_ssid)
+ wpas_notify_network_changed(wpa_s);
+
/*
* TODO: should notify EAPOL SM about changes in opensc_engine_path,
* pkcs11_engine_path, pkcs11_module_path.
wpa_sm_set_config(wpa_s->wpa, NULL);
wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
rsn_preauth_deinit(wpa_s->wpa);
+
+ old_ap_scan = wpa_s->conf->ap_scan;
wpa_config_free(wpa_s->conf);
wpa_s->conf = conf;
+ if (old_ap_scan != wpa_s->conf->ap_scan)
+ wpas_notify_ap_scan_changed(wpa_s);
+
if (reconf_ctrl)
wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
{
u8 wpa_ie[80];
size_t wpa_ie_len;
- int use_crypt, ret, i;
+ int use_crypt, ret, i, bssid_changed;
int algs = AUTH_ALG_OPEN_SYSTEM;
wpa_cipher cipher_pairwise, cipher_group;
struct wpa_driver_associate_params params;
int wep_keys_set = 0;
struct wpa_driver_capa capa;
int assoc_failed = 0;
+ struct wpa_ssid *old_ssid;
+
+ if (ssid->mode == 2) {
+#ifdef CONFIG_AP
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP)) {
+ wpa_printf(MSG_INFO, "Driver does not support AP "
+ "mode");
+ return;
+ }
+ wpa_supplicant_create_ap(wpa_s, ssid);
+#else /* CONFIG_AP */
+ wpa_printf(MSG_ERROR, "AP mode support not included in the "
+ "build");
+#endif /* CONFIG_AP */
+ return;
+ }
+
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) {
+ sme_authenticate(wpa_s, bss, ssid);
+ return;
+ }
wpa_s->reassociate = 0;
if (bss) {
wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR
" (SSID='%s' freq=%d MHz)", MAC2STR(bss->bssid),
ie ? wpa_ssid_txt(ie + 2, ie[1]) : "", bss->freq);
+ bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
os_memset(wpa_s->bssid, 0, ETH_ALEN);
os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
+ if (bssid_changed)
+ wpas_notify_bssid_changed(wpa_s);
#ifdef CONFIG_IEEE80211R
ie = wpa_scan_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN)
* previous association. */
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
- if (wpa_drv_set_mode(wpa_s, ssid->mode)) {
- wpa_printf(MSG_WARNING, "Failed to set operating mode");
- assoc_failed = 1;
- }
-
#ifdef IEEE8021X_EAPOL
if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
if (ssid->leap) {
wpa_printf(MSG_DEBUG, "Overriding auth_alg selection: 0x%x",
algs);
}
- wpa_drv_set_auth_alg(wpa_s, algs);
if (bss && (wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
wpa_scan_get_ie(bss, WLAN_EID_RSN)) &&
wpa_supplicant_set_wpa_none_key(wpa_s, ssid);
}
- wpa_drv_set_drop_unencrypted(wpa_s, use_crypt);
wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
os_memset(¶ms, 0, sizeof(params));
if (bss) {
}
params.wep_tx_keyidx = ssid->wep_tx_keyidx;
- if (wpa_s->driver_4way_handshake &&
+ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
(params.key_mgmt_suite == KEY_MGMT_PSK ||
params.key_mgmt_suite == KEY_MGMT_FT_PSK)) {
params.passphrase = ssid->passphrase;
params.psk = ssid->psk;
}
+ params.drop_unencrypted = use_crypt;
+
#ifdef CONFIG_IEEE80211W
switch (ssid->ieee80211w) {
case NO_IEEE80211W:
}
#endif /* CONFIG_IEEE80211W */
- if (wpa_s->use_client_mlme)
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
ret = ieee80211_sta_associate(wpa_s, ¶ms);
else
ret = wpa_drv_associate(wpa_s, ¶ms);
} else if (ssid->mode == IEEE80211_MODE_IBSS &&
wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE) {
+ ibss_rsn_set_psk(wpa_s->ibss_rsn, ssid->psk);
/*
* RSN IBSS authentication is per-STA and we can disable the
* per-BSSID authentication.
*/
eapol_sm_invalidate_cached_session(wpa_s->eapol);
}
+ old_ssid = wpa_s->current_ssid;
wpa_s->current_ssid = ssid;
wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
wpa_supplicant_initiate_eapol(wpa_s);
+ if (old_ssid != wpa_s->current_ssid)
+ wpas_notify_network_changed(wpa_s);
}
void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
int reason_code)
{
+ struct wpa_ssid *old_ssid;
u8 *addr = NULL;
+
if (!is_zero_ether_addr(wpa_s->bssid)) {
- if (wpa_s->use_client_mlme)
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
ieee80211_sta_disassociate(wpa_s, reason_code);
else
wpa_drv_disassociate(wpa_s, wpa_s->bssid, reason_code);
}
wpa_clear_keys(wpa_s, addr);
wpa_supplicant_mark_disassoc(wpa_s);
+ old_ssid = wpa_s->current_ssid;
wpa_s->current_ssid = NULL;
wpa_sm_set_config(wpa_s->wpa, NULL);
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+ if (old_ssid != wpa_s->current_ssid)
+ wpas_notify_network_changed(wpa_s);
}
* @wpa_s: Pointer to wpa_supplicant data
* @reason_code: IEEE 802.11 reason code for the deauthenticate frame
*
- * This function is used to request %wpa_supplicant to disassociate with the
+ * This function is used to request %wpa_supplicant to deauthenticate from the
* current AP.
*/
void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
int reason_code)
{
+ struct wpa_ssid *old_ssid;
u8 *addr = NULL;
- wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+
if (!is_zero_ether_addr(wpa_s->bssid)) {
- if (wpa_s->use_client_mlme)
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
ieee80211_sta_deauthenticate(wpa_s, reason_code);
else
wpa_drv_deauthenticate(wpa_s, wpa_s->bssid,
addr = wpa_s->bssid;
}
wpa_clear_keys(wpa_s, addr);
+ wpa_supplicant_mark_disassoc(wpa_s);
+ old_ssid = wpa_s->current_ssid;
wpa_s->current_ssid = NULL;
wpa_sm_set_config(wpa_s->wpa, NULL);
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
- eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
- eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
+ if (old_ssid != wpa_s->current_ssid)
+ wpas_notify_network_changed(wpa_s);
}
-static int wpa_supplicant_get_scan_results_old(struct wpa_supplicant *wpa_s)
+/**
+ * wpa_supplicant_enable_network - Mark a configured network as enabled
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @ssid: wpa_ssid structure for a configured network or %NULL
+ *
+ * Enables the specified network or all networks if no network specified.
+ */
+void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
{
-#define SCAN_AP_LIMIT 128
- struct wpa_scan_result *results;
- int num, i;
- struct wpa_scan_results *res;
-
- results = os_malloc(SCAN_AP_LIMIT * sizeof(struct wpa_scan_result));
- if (results == NULL) {
- wpa_printf(MSG_WARNING, "Failed to allocate memory for scan "
- "results");
- return -1;
- }
+ struct wpa_ssid *other_ssid;
+ int was_disabled;
- num = wpa_drv_get_scan_results(wpa_s, results, SCAN_AP_LIMIT);
- wpa_printf(MSG_DEBUG, "Scan results: %d", num);
- if (num < 0) {
- wpa_printf(MSG_DEBUG, "Failed to get scan results");
- os_free(results);
- return -1;
+ if (ssid == NULL) {
+ other_ssid = wpa_s->conf->ssid;
+ while (other_ssid) {
+ if (other_ssid == wpa_s->current_ssid &&
+ other_ssid->disabled)
+ wpa_s->reassociate = 1;
+
+ was_disabled = other_ssid->disabled;
+
+ other_ssid->disabled = 0;
+
+ if (was_disabled != other_ssid->disabled)
+ wpas_notify_network_enabled_changed(
+ wpa_s, other_ssid);
+
+ other_ssid = other_ssid->next;
+ }
+ if (wpa_s->reassociate)
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ } else if (wpa_s->current_ssid == NULL && ssid->disabled) {
+ /*
+ * Try to reassociate since there is no current configuration
+ * and a new network was made available.
+ */
+ wpa_s->reassociate = 1;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+ was_disabled = ssid->disabled;
+
+ ssid->disabled = 0;
+
+ if (was_disabled != ssid->disabled)
+ wpas_notify_network_enabled_changed(wpa_s, ssid);
}
- if (num > SCAN_AP_LIMIT) {
- wpa_printf(MSG_INFO, "Not enough room for all APs (%d < %d)",
- num, SCAN_AP_LIMIT);
- num = SCAN_AP_LIMIT;
+}
+
+
+/**
+ * wpa_supplicant_disable_network - Mark a configured network as disabled
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @ssid: wpa_ssid structure for a configured network or %NULL
+ *
+ * Disables the specified network or all networks if no network specified.
+ */
+void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ struct wpa_ssid *other_ssid;
+ int was_disabled;
+
+ if (ssid == NULL) {
+ other_ssid = wpa_s->conf->ssid;
+ while (other_ssid) {
+ was_disabled = other_ssid->disabled;
+
+ other_ssid->disabled = 1;
+
+ if (was_disabled != other_ssid->disabled)
+ wpas_notify_network_enabled_changed(
+ wpa_s, other_ssid);
+
+ other_ssid = other_ssid->next;
+ }
+ if (wpa_s->current_ssid)
+ wpa_supplicant_disassociate(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ } else {
+ if (ssid == wpa_s->current_ssid)
+ wpa_supplicant_disassociate(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+
+ was_disabled = ssid->disabled;
+
+ ssid->disabled = 1;
+
+ if (was_disabled != ssid->disabled)
+ wpas_notify_network_enabled_changed(wpa_s, ssid);
}
+}
- wpa_scan_results_free(wpa_s->scan_res);
- wpa_s->scan_res = NULL;
- /* Convert old scan result data structure to the new one */
- res = os_zalloc(sizeof(*res));
- if (res == NULL) {
- os_free(results);
- return -1;
+/**
+ * wpa_supplicant_select_network - Attempt association with a network
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @ssid: wpa_ssid structure for a configured network or %NULL for any network
+ */
+void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+
+ struct wpa_ssid *other_ssid;
+
+ if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid)
+ wpa_supplicant_disassociate(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+
+ /*
+ * Mark all other networks disabled or mark all networks enabled if no
+ * network specified.
+ */
+ other_ssid = wpa_s->conf->ssid;
+ while (other_ssid) {
+ int was_disabled = other_ssid->disabled;
+
+ other_ssid->disabled = ssid ? (ssid->id != other_ssid->id) : 0;
+
+ if (was_disabled != other_ssid->disabled)
+ wpas_notify_network_enabled_changed(wpa_s, other_ssid);
+
+ other_ssid = other_ssid->next;
}
- res->res = os_zalloc(num * sizeof(struct wpa_scan_res *));
- if (res->res == NULL) {
- os_free(results);
- os_free(res);
+ wpa_s->disconnected = 0;
+ wpa_s->reassociate = 1;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+ if (ssid)
+ wpas_notify_network_selected(wpa_s, ssid);
+}
+
+
+/**
+ * wpa_supplicant_set_ap_scan - Set AP scan mode for interface
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @ap_scan: AP scan mode
+ * Returns: 0 if succeed or -1 if ap_scan has an invalid value
+ *
+ */
+int wpa_supplicant_set_ap_scan(struct wpa_supplicant *wpa_s, int ap_scan)
+{
+
+ int old_ap_scan;
+
+ if (ap_scan < 0 || ap_scan > 2)
return -1;
- }
- for (i = 0; i < num; i++) {
- struct wpa_scan_result *bss = &results[i];
- struct wpa_scan_res *r;
- size_t ie_len;
- u8 *pos;
+ old_ap_scan = wpa_s->conf->ap_scan;
+ wpa_s->conf->ap_scan = ap_scan;
- ie_len = 2 + bss->ssid_len + bss->rsn_ie_len + bss->wpa_ie_len;
- if (bss->maxrate)
- ie_len += 3;
- if (bss->mdie_present)
- ie_len += 5;
+ if (old_ap_scan != wpa_s->conf->ap_scan)
+ wpas_notify_ap_scan_changed(wpa_s);
- r = os_zalloc(sizeof(*r) + ie_len);
- if (r == NULL)
- break;
+ return 0;
+}
- os_memcpy(r->bssid, bss->bssid, ETH_ALEN);
- r->freq = bss->freq;
- r->caps = bss->caps;
- r->qual = bss->qual;
- r->noise = bss->noise;
- r->level = bss->level;
- r->tsf = bss->tsf;
- r->ie_len = ie_len;
-
- pos = (u8 *) (r + 1);
-
- /* SSID IE */
- *pos++ = WLAN_EID_SSID;
- *pos++ = bss->ssid_len;
- os_memcpy(pos, bss->ssid, bss->ssid_len);
- pos += bss->ssid_len;
-
- if (bss->maxrate) {
- /* Fake Supported Rate IE to include max rate */
- *pos++ = WLAN_EID_SUPP_RATES;
- *pos++ = 1;
- *pos++ = bss->maxrate;
- }
- if (bss->rsn_ie_len) {
- os_memcpy(pos, bss->rsn_ie, bss->rsn_ie_len);
- pos += bss->rsn_ie_len;
- }
+/**
+ * wpa_supplicant_set_debug_params - Set global debug params
+ * @global: wpa_global structure
+ * @debug_level: debug level
+ * @debug_timestamp: determines if show timestamp in debug data
+ * @debug_show_keys: determines if show keys in debug data
+ * Returns: 0 if succeed or -1 if debug_level has wrong value
+ */
+int wpa_supplicant_set_debug_params(struct wpa_global *global, int debug_level,
+ int debug_timestamp, int debug_show_keys)
+{
- if (bss->mdie_present) {
- os_memcpy(pos, bss->mdie, 5);
- pos += 5;
- }
+ int old_level, old_timestamp, old_show_keys;
- if (bss->wpa_ie_len) {
- os_memcpy(pos, bss->wpa_ie, bss->wpa_ie_len);
- pos += bss->wpa_ie_len;
- }
+ /* check for allowed debuglevels */
+ if (debug_level != MSG_MSGDUMP &&
+ debug_level != MSG_DEBUG &&
+ debug_level != MSG_INFO &&
+ debug_level != MSG_WARNING &&
+ debug_level != MSG_ERROR)
+ return -1;
- res->res[res->num++] = r;
- }
+ old_level = wpa_debug_level;
+ old_timestamp = wpa_debug_timestamp;
+ old_show_keys = wpa_debug_show_keys;
+
+ wpa_debug_level = debug_level;
+ wpa_debug_timestamp = debug_timestamp ? 1 : 0;
+ wpa_debug_show_keys = debug_show_keys ? 1 : 0;
- os_free(results);
- wpa_s->scan_res = res;
+ if (wpa_debug_level != old_level ||
+ wpa_debug_timestamp != old_timestamp ||
+ wpa_debug_show_keys != old_show_keys)
+ wpas_notify_debug_params_changed(global);
return 0;
}
+static void notify_bss_changes(struct wpa_supplicant *wpa_s,
+ u8 (*prev_bssids)[ETH_ALEN], int prev_num,
+ struct wpa_scan_results *new)
+{
+ int new_num, i, j;
+
+ new_num = new != NULL ? new->num : 0;
+ if (prev_bssids == NULL)
+ prev_num = 0;
+
+ for (i = 0; i < prev_num; i++) {
+ for (j = 0; j < new_num; j++) {
+ if (!os_memcmp(prev_bssids[i], new->res[j]->bssid,
+ ETH_ALEN))
+ break;
+ }
+ if (j == new_num)
+ wpas_notify_bss_removed(wpa_s, prev_bssids[i]);
+ }
+ for (i = 0; i < new_num; i++) {
+ for (j = 0; j < prev_num; j++) {
+ if (!os_memcmp(new->res[i]->bssid, prev_bssids[j],
+ ETH_ALEN))
+ break;
+ }
+ if (j == prev_num)
+ wpas_notify_bss_added(wpa_s, new->res[i]->bssid);
+ }
+}
+
+
/**
* wpa_supplicant_get_scan_results - Get scan results
* @wpa_s: Pointer to wpa_supplicant data
*/
int wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s)
{
- int ret;
+ int ret, i, prev_scan_res_num;
+ u8 (*prev_scan_bssids)[ETH_ALEN];
+
+ prev_scan_res_num = wpa_s->scan_res ? wpa_s->scan_res->num : 0;
+ prev_scan_bssids = os_malloc(prev_scan_res_num * ETH_ALEN);
+
+ if (prev_scan_bssids) {
+ for (i = 0; i < prev_scan_res_num; i++) {
+ os_memcpy(prev_scan_bssids[i],
+ wpa_s->scan_res->res[i]->bssid, ETH_ALEN);
+ }
+ } else {
+ wpa_printf(MSG_WARNING, "Not enough memory for old scan "
+ "results list");
+ prev_scan_res_num = 0;
+ }
- if (wpa_s->use_client_mlme) {
- wpa_scan_results_free(wpa_s->scan_res);
+ wpa_scan_results_free(wpa_s->scan_res);
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
wpa_s->scan_res = ieee80211_sta_get_scan_results(wpa_s);
- if (wpa_s->scan_res == NULL) {
- wpa_printf(MSG_DEBUG, "Failed to get scan results");
- ret = -1;
- } else
- ret = 0;
- } else if (wpa_s->driver->get_scan_results2 == NULL)
- ret = wpa_supplicant_get_scan_results_old(wpa_s);
- else {
- wpa_scan_results_free(wpa_s->scan_res);
+ else
wpa_s->scan_res = wpa_drv_get_scan_results2(wpa_s);
- if (wpa_s->scan_res == NULL) {
- wpa_printf(MSG_DEBUG, "Failed to get scan results");
- ret = -1;
- } else
- ret = 0;
+ if (wpa_s->scan_res == NULL) {
+ wpa_printf(MSG_DEBUG, "Failed to get scan results");
+ ret = -1;
+ } else {
+ ret = 0;
+ wpa_scan_sort_results(wpa_s->scan_res);
}
- if (wpa_s->scan_res)
- wpa_scan_sort_results(wpa_s->scan_res);
+ notify_bss_changes(wpa_s, prev_scan_bssids, prev_scan_res_num,
+ wpa_s->scan_res);
+ os_free(prev_scan_bssids);
return ret;
}
u8 bssid[ETH_ALEN];
int wired;
- if (wpa_s->use_client_mlme) {
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
if (ieee80211_sta_get_ssid(wpa_s, ssid, &ssid_len)) {
wpa_printf(MSG_WARNING, "Could not read SSID from "
"MLME.");
ssid_len = res;
}
- if (wpa_s->use_client_mlme)
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
os_memcpy(bssid, wpa_s->bssid, ETH_ALEN);
else if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
wpa_printf(MSG_WARNING, "Could not read BSSID from driver.");
return NULL;
}
- wired = wpa_s->conf->ap_scan == 0 && wpa_s->driver &&
- IS_WIRED(wpa_s->driver);
+ wired = wpa_s->conf->ap_scan == 0 &&
+ (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED);
entry = wpa_s->conf->ssid;
while (entry) {
const char *name)
{
int i;
+ size_t len;
+ const char *pos;
if (wpa_s == NULL)
return -1;
- if (wpa_supplicant_drivers[0] == NULL) {
+ if (wpa_drivers[0] == NULL) {
wpa_printf(MSG_ERROR, "No driver interfaces build into "
"wpa_supplicant.");
return -1;
if (name == NULL) {
/* default to first driver in the list */
- wpa_s->driver = wpa_supplicant_drivers[0];
+ wpa_s->driver = wpa_drivers[0];
+ wpa_s->global_drv_priv = wpa_s->global->drv_priv[0];
return 0;
}
- for (i = 0; wpa_supplicant_drivers[i]; i++) {
- if (os_strcmp(name, wpa_supplicant_drivers[i]->name) == 0) {
- wpa_s->driver = wpa_supplicant_drivers[i];
+ pos = os_strchr(name, ',');
+ if (pos)
+ len = pos - name;
+ else
+ len = os_strlen(name);
+ for (i = 0; wpa_drivers[i]; i++) {
+ if (os_strlen(wpa_drivers[i]->name) == len &&
+ os_strncmp(name, wpa_drivers[i]->name, len) ==
+ 0) {
+ wpa_s->driver = wpa_drivers[i];
+ wpa_s->global_drv_priv = wpa_s->global->drv_priv[i];
return 0;
}
}
- wpa_printf(MSG_ERROR, "Unsupported driver '%s'.\n", name);
+ wpa_printf(MSG_ERROR, "Unsupported driver '%s'.", name);
return -1;
}
wpa_printf(MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
+ if (wpa_s->wpa_state < WPA_ASSOCIATED) {
+ /*
+ * There is possible race condition between receiving the
+ * association event and the EAPOL frame since they are coming
+ * through different paths from the driver. In order to avoid
+ * issues in trying to process the EAPOL frame before receiving
+ * association information, lets queue it for processing until
+ * the association event is received.
+ */
+ wpa_printf(MSG_DEBUG, "Not associated - Delay processing of "
+ "received EAPOL frame");
+ wpabuf_free(wpa_s->pending_eapol_rx);
+ wpa_s->pending_eapol_rx = wpabuf_alloc_copy(buf, len);
+ if (wpa_s->pending_eapol_rx) {
+ os_get_time(&wpa_s->pending_eapol_rx_time);
+ os_memcpy(wpa_s->pending_eapol_rx_src, src_addr,
+ ETH_ALEN);
+ }
+ return;
+ }
+
+#ifdef CONFIG_AP
+ if (wpa_s->ap_iface) {
+ wpa_supplicant_ap_rx_eapol(wpa_s, src_addr, buf, len);
+ return;
+ }
+#endif /* CONFIG_AP */
+
if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
wpa_printf(MSG_DEBUG, "Ignored received EAPOL frame since "
"no key management is configured");
}
if (wpa_s->eapol_received == 0 &&
- (!wpa_s->driver_4way_handshake ||
+ (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) ||
!wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
wpa_s->wpa_state != WPA_COMPLETED)) {
/* Timeout for completing IEEE 802.1X and WPA authentication */
eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0)
return;
wpa_drv_poll(wpa_s);
- if (!wpa_s->driver_4way_handshake)
+ if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
/*
}
-void wpa_supplicant_sta_free_hw_features(struct wpa_hw_modes *hw_features,
- size_t num_hw_features)
-{
- ieee80211_sta_free_hw_features(hw_features, num_hw_features);
-}
-
-
void wpa_supplicant_sta_rx(void *ctx, const u8 *buf, size_t len,
struct ieee80211_rx_status *rx_status)
{
}
}
- /* Backwards compatibility call to set_wpa() handler. This is called
- * only just after init and just before deinit, so these handler can be
- * used to implement same functionality. */
- if (wpa_drv_set_wpa(wpa_s, 1) < 0) {
- struct wpa_driver_capa capa;
- if (wpa_drv_get_capa(wpa_s, &capa) < 0 ||
- !(capa.flags & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2))) {
- wpa_printf(MSG_DEBUG, "Driver does not support WPA.");
- /* Continue to allow non-WPA modes to be used. */
- } else {
- wpa_printf(MSG_ERROR, "Failed to enable WPA in the "
- "driver.");
- return -1;
- }
- }
-
wpa_clear_keys(wpa_s, NULL);
/* Make sure that TKIP countermeasures are not left enabled (could
* happen if wpa_supplicant is killed during countermeasures. */
wpa_drv_set_countermeasures(wpa_s, 0);
- wpa_drv_set_drop_unencrypted(wpa_s, 1);
-
wpa_printf(MSG_DEBUG, "RSN: flushing PMKID list in the driver");
wpa_drv_flush_pmkid(wpa_s);
- wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN;
+ wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
wpa_supplicant_req_scan(wpa_s, interface_count, 100000);
interface_count++;
static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
struct wpa_interface *iface)
{
+ const char *ifname, *driver;
+ struct wpa_driver_capa capa;
+
wpa_printf(MSG_DEBUG, "Initializing interface '%s' conf '%s' driver "
"'%s' ctrl_interface '%s' bridge '%s'", iface->ifname,
iface->confname ? iface->confname : "N/A",
iface->ctrl_interface ? iface->ctrl_interface : "N/A",
iface->bridge_ifname ? iface->bridge_ifname : "N/A");
- if (wpa_supplicant_set_driver(wpa_s, iface->driver) < 0) {
- return -1;
- }
-
if (iface->confname) {
#ifdef CONFIG_BACKEND_FILE
wpa_s->confname = os_rel2abs_path(iface->confname);
sizeof(wpa_s->bridge_ifname));
}
- return 0;
-}
-
-
-static int wpa_supplicant_init_iface2(struct wpa_supplicant *wpa_s)
-{
- const char *ifname;
- struct wpa_driver_capa capa;
-
- wpa_printf(MSG_DEBUG, "Initializing interface (2) '%s'",
- wpa_s->ifname);
-
/* RSNA Supplicant Key Management - INITIALIZE */
eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
* L2 receive handler so that association events are processed before
* EAPOL-Key packets if both become available for the same select()
* call. */
+ driver = iface->driver;
+next_driver:
+ if (wpa_supplicant_set_driver(wpa_s, driver) < 0)
+ return -1;
+
wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
if (wpa_s->drv_priv == NULL) {
+ const char *pos;
+ pos = os_strchr(driver, ',');
+ if (pos) {
+ wpa_printf(MSG_DEBUG, "Failed to initialize driver "
+ "interface - try next driver wrapper");
+ driver = pos + 1;
+ goto next_driver;
+ }
wpa_printf(MSG_ERROR, "Failed to initialize driver interface");
return -1;
}
}
if (wpa_drv_get_capa(wpa_s, &capa) == 0) {
+ wpa_s->drv_flags = capa.flags;
if (capa.flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
- wpa_s->use_client_mlme = 1;
if (ieee80211_sta_init(wpa_s))
return -1;
}
- if (capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE)
- wpa_s->driver_4way_handshake = 1;
+ wpa_s->max_scan_ssids = capa.max_scan_ssids;
}
#ifdef CONFIG_IBSS_RSN
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
- /* Backwards compatibility call to set_wpa() handler. This is
- * called only just after init and just before deinit, so these
- * handler can be used to implement same functionality. */
- if (wpa_drv_set_wpa(wpa_s, 0) < 0) {
- wpa_printf(MSG_ERROR, "Failed to disable WPA in the "
- "driver.");
- }
-
- wpa_drv_set_drop_unencrypted(wpa_s, 0);
wpa_drv_set_countermeasures(wpa_s, 0);
wpa_clear_keys(wpa_s, NULL);
}
- wpas_dbus_unregister_iface(wpa_s);
+ wpas_notify_iface_removed(wpa_s);
wpa_supplicant_cleanup(wpa_s);
struct wpa_interface *iface)
{
struct wpa_supplicant *wpa_s;
+ struct wpa_interface t_iface;
if (global == NULL || iface == NULL)
return NULL;
if (wpa_s == NULL)
return NULL;
- if (wpa_supplicant_init_iface(wpa_s, iface) ||
- wpa_supplicant_init_iface2(wpa_s)) {
+ t_iface = *iface;
+ if (global->params.override_driver) {
+ wpa_printf(MSG_DEBUG, "Override interface parameter: driver "
+ "('%s' -> '%s')",
+ iface->driver, global->params.override_driver);
+ t_iface.driver = global->params.override_driver;
+ }
+ if (global->params.override_ctrl_interface) {
+ wpa_printf(MSG_DEBUG, "Override interface parameter: "
+ "ctrl_interface ('%s' -> '%s')",
+ iface->ctrl_interface,
+ global->params.override_ctrl_interface);
+ t_iface.ctrl_interface =
+ global->params.override_ctrl_interface;
+ }
+ if (wpa_supplicant_init_iface(wpa_s, &t_iface)) {
wpa_printf(MSG_DEBUG, "Failed to add interface %s",
iface->ifname);
wpa_supplicant_deinit_iface(wpa_s);
wpa_s->global = global;
- /* Register the interface with the dbus control interface */
- if (wpas_dbus_register_iface(wpa_s)) {
+ /* Notify the control interfaces about new iface */
+ if (wpas_notify_iface_added(wpa_s)) {
wpa_supplicant_deinit_iface(wpa_s);
os_free(wpa_s);
return NULL;
}
-
+
wpa_s->next = global->ifaces;
global->ifaces = wpa_s;
return NULL;
wpa_debug_open_file(params->wpa_debug_file_path);
+ if (params->wpa_debug_syslog)
+ wpa_debug_open_syslog();
ret = eap_peer_register_methods();
if (ret) {
return NULL;
}
+#ifdef CONFIG_AP
+ ret = eap_server_register_methods();
+ if (ret) {
+ wpa_printf(MSG_ERROR, "Failed to register EAP server methods");
+ if (ret == -2)
+ wpa_printf(MSG_ERROR, "Two or more EAP methods used "
+ "the same EAP type.");
+ return NULL;
+ }
+#endif /* CONFIG_AP */
+
global = os_zalloc(sizeof(*global));
if (global == NULL)
return NULL;
if (params->ctrl_interface)
global->params.ctrl_interface =
os_strdup(params->ctrl_interface);
+ if (params->override_driver)
+ global->params.override_driver =
+ os_strdup(params->override_driver);
+ if (params->override_ctrl_interface)
+ global->params.override_ctrl_interface =
+ os_strdup(params->override_ctrl_interface);
wpa_debug_level = global->params.wpa_debug_level =
params->wpa_debug_level;
wpa_debug_show_keys = global->params.wpa_debug_show_keys =
return NULL;
}
- if (global->params.dbus_ctrl_interface) {
- global->dbus_ctrl_iface =
- wpa_supplicant_dbus_ctrl_iface_init(global);
- if (global->dbus_ctrl_iface == NULL) {
- wpa_supplicant_deinit(global);
- return NULL;
- }
+ if (wpas_notify_supplicant_initialized(global)) {
+ wpa_supplicant_deinit(global);
+ return NULL;
}
- for (i = 0; wpa_supplicant_drivers[i]; i++)
+ for (i = 0; wpa_drivers[i]; i++)
global->drv_count++;
if (global->drv_count == 0) {
wpa_printf(MSG_ERROR, "No drivers enabled");
wpa_supplicant_deinit(global);
return NULL;
}
- for (i = 0; wpa_supplicant_drivers[i]; i++) {
- if (!wpa_supplicant_drivers[i]->global_init)
+ for (i = 0; wpa_drivers[i]; i++) {
+ if (!wpa_drivers[i]->global_init)
continue;
- global->drv_priv[i] = wpa_supplicant_drivers[i]->global_init();
+ global->drv_priv[i] = wpa_drivers[i]->global_init();
if (global->drv_priv[i] == NULL) {
wpa_printf(MSG_ERROR, "Failed to initialize driver "
- "'%s'", wpa_supplicant_drivers[i]->name);
+ "'%s'", wpa_drivers[i]->name);
wpa_supplicant_deinit(global);
return NULL;
}
if (global->ctrl_iface)
wpa_supplicant_global_ctrl_iface_deinit(global->ctrl_iface);
- if (global->dbus_ctrl_iface)
- wpa_supplicant_dbus_ctrl_iface_deinit(global->dbus_ctrl_iface);
+
+ wpas_notify_supplicant_deinitialized(global);
eap_peer_unregister_methods();
+#ifdef CONFIG_AP
+ eap_server_unregister_methods();
+#endif /* CONFIG_AP */
- for (i = 0; wpa_supplicant_drivers[i]; i++) {
+ for (i = 0; wpa_drivers[i] && global->drv_priv; i++) {
if (!global->drv_priv[i])
continue;
- wpa_supplicant_drivers[i]->global_deinit(global->drv_priv[i]);
+ wpa_drivers[i]->global_deinit(global->drv_priv[i]);
}
os_free(global->drv_priv);
os_free(global->params.pid_file);
}
os_free(global->params.ctrl_interface);
+ os_free(global->params.override_driver);
+ os_free(global->params.override_ctrl_interface);
os_free(global);
+ wpa_debug_close_syslog();
wpa_debug_close_file();
}