summaryrefslogtreecommitdiffstats
path: root/contrib/wpa_supplicant/wpa_supplicant.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/wpa_supplicant/wpa_supplicant.c')
-rw-r--r--contrib/wpa_supplicant/wpa_supplicant.c2009
1 files changed, 855 insertions, 1154 deletions
diff --git a/contrib/wpa_supplicant/wpa_supplicant.c b/contrib/wpa_supplicant/wpa_supplicant.c
index 0c57143..8e5ea44 100644
--- a/contrib/wpa_supplicant/wpa_supplicant.c
+++ b/contrib/wpa_supplicant/wpa_supplicant.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2006, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -17,27 +17,16 @@
#include <stdarg.h>
#include <unistd.h>
#include <string.h>
-#include <sys/time.h>
#include <time.h>
#include <signal.h>
-#include <sys/types.h>
-#ifndef CONFIG_NATIVE_WINDOWS
-#include <sys/socket.h>
-#include <sys/un.h>
-#endif /* CONFIG_NATIVE_WINDOWS */
-#include <unistd.h>
-#include <ctype.h>
#ifndef CONFIG_NATIVE_WINDOWS
#include <netinet/in.h>
#endif /* CONFIG_NATIVE_WINDOWS */
-#include <fcntl.h>
-#define OPENSSL_DISABLE_OLD_DES_SUPPORT
#include "common.h"
#include "eapol_sm.h"
#include "eap.h"
#include "wpa.h"
-#include "driver.h"
#include "eloop.h"
#include "wpa_supplicant.h"
#include "config.h"
@@ -46,12 +35,14 @@
#include "ctrl_iface.h"
#include "pcsc_funcs.h"
#include "version.h"
+#include "preauth.h"
+#include "wpa_ctrl.h"
-static const char *wpa_supplicant_version =
+const char *wpa_supplicant_version =
"wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi> and contributors";
+"Copyright (c) 2003-2006, Jouni Malinen <jkmaline@cc.hut.fi> and contributors";
-static const char *wpa_supplicant_license =
+const char *wpa_supplicant_license =
"This program is free software. You can distribute it and/or modify it\n"
"under the terms of the GNU General Public License version 2.\n"
"\n"
@@ -63,7 +54,8 @@ static const char *wpa_supplicant_license =
#endif /* EAP_TLS_FUNCS */
;
-static const char *wpa_supplicant_full_license =
+#ifndef CONFIG_NO_STDOUT_DEBUG
+const char *wpa_supplicant_full_license =
"This program is free software; you can redistribute it and/or modify\n"
"it under the terms of the GNU General Public License version 2 as\n"
"published by the Free Software Foundation.\n"
@@ -107,25 +99,15 @@ static const char *wpa_supplicant_full_license =
"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
"\n";
+#endif /* CONFIG_NO_STDOUT_DEBUG */
extern struct wpa_driver_ops *wpa_supplicant_drivers[];
-static void wpa_supplicant_scan_results(struct wpa_supplicant *wpa_s);
-static int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s,
- int wait_for_interface);
-static void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
- struct wpa_scan_result *bss,
- struct wpa_ssid *ssid);
-static int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
- struct wpa_scan_result *bss,
- struct wpa_ssid *ssid,
- u8 *wpa_ie, int *wpa_ie_len);
-
-
extern int wpa_debug_level;
extern int wpa_debug_show_keys;
extern int wpa_debug_timestamp;
+static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx);
void wpa_msg(struct wpa_supplicant *wpa_s, int level, char *fmt, ...)
{
@@ -152,13 +134,69 @@ void wpa_msg(struct wpa_supplicant *wpa_s, int level, char *fmt, ...)
}
-int wpa_eapol_send(void *ctx, int type, u8 *buf, size_t len)
+static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type,
+ const void *data, u16 data_len,
+ size_t *msg_len, void **data_pos)
+{
+ struct ieee802_1x_hdr *hdr;
+
+ *msg_len = sizeof(*hdr) + data_len;
+ hdr = malloc(*msg_len);
+ if (hdr == NULL)
+ return NULL;
+
+ hdr->version = wpa_s->conf->eapol_version;
+ hdr->type = type;
+ hdr->length = htons(data_len);
+
+ if (data)
+ memcpy(hdr + 1, data, data_len);
+ else
+ memset(hdr + 1, 0, data_len);
+
+ if (data_pos)
+ *data_pos = hdr + 1;
+
+ return (u8 *) hdr;
+}
+
+
+/**
+ * wpa_ether_send - Send Ethernet frame
+ * @wpa_s: pointer to wpa_supplicant data
+ * @dest: Destination MAC address
+ * @proto: Ethertype
+ * @buf: Frame payload starting from IEEE 802.1X header
+ * @len: Frame payload length
+ */
+int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest, u16 proto,
+ const u8 *buf, size_t len)
+{
+ if (wpa_s->l2) {
+ return l2_packet_send(wpa_s->l2, dest, proto, buf, len);
+ }
+
+ return wpa_drv_send_eapol(wpa_s, dest, proto, buf, len);
+}
+
+
+#ifdef IEEE8021X_EAPOL
+/**
+ * wpa_supplicant_eapol_send - Send IEEE 802.1X EAPOL packet to Authenticator
+ * @ctx: pointer to wpa_supplicant data
+ * @type: IEEE 802.1X packet type (IEEE802_1X_TYPE_*)
+ * @buf: EAPOL payload (after IEEE 802.1X header)
+ * @len: EAPOL payload length
+ *
+ * This function adds Ethernet and IEEE 802.1X header and sends the EAPOL frame
+ * to the current Authenticator.
+ */
+static int wpa_supplicant_eapol_send(void *ctx, int type, const u8 *buf,
+ size_t len)
{
struct wpa_supplicant *wpa_s = ctx;
u8 *msg, *dst, bssid[ETH_ALEN];
size_t msglen;
- struct l2_ethhdr *ethhdr;
- struct ieee802_1x_hdr *hdr;
int res;
/* TODO: could add l2_packet_sendmsg that allows fragments to avoid
@@ -175,7 +213,8 @@ int wpa_eapol_send(void *ctx, int type, u8 *buf, size_t len)
return -1;
}
- if (wpa_s->cur_pmksa && type == IEEE802_1X_TYPE_EAPOL_START) {
+ if (pmksa_cache_get_current(wpa_s->wpa) &&
+ type == IEEE802_1X_TYPE_EAPOL_START) {
/* Trying to use PMKSA caching - do not send EAPOL-Start frames
* since they will trigger full EAPOL authentication. */
wpa_printf(MSG_DEBUG, "RSN: PMKSA caching - do not send "
@@ -205,64 +244,12 @@ int wpa_eapol_send(void *ctx, int type, u8 *buf, size_t len)
dst = wpa_s->bssid;
}
- msglen = sizeof(*ethhdr) + sizeof(*hdr) + len;
- msg = malloc(msglen);
+ msg = wpa_alloc_eapol(wpa_s, type, buf, len, &msglen, NULL);
if (msg == NULL)
return -1;
- ethhdr = (struct l2_ethhdr *) msg;
- memcpy(ethhdr->h_dest, dst, ETH_ALEN);
- memcpy(ethhdr->h_source, wpa_s->own_addr, ETH_ALEN);
- ethhdr->h_proto = htons(ETH_P_EAPOL);
-
- hdr = (struct ieee802_1x_hdr *) (ethhdr + 1);
- hdr->version = wpa_s->conf->eapol_version;
- hdr->type = type;
- hdr->length = htons(len);
-
- memcpy((u8 *) (hdr + 1), buf, len);
-
wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", msg, msglen);
- res = l2_packet_send(wpa_s->l2, msg, msglen);
- free(msg);
- return res;
-}
-
-
-int wpa_eapol_send_preauth(void *ctx, int type, u8 *buf, size_t len)
-{
- struct wpa_supplicant *wpa_s = ctx;
- u8 *msg;
- size_t msglen;
- struct l2_ethhdr *ethhdr;
- struct ieee802_1x_hdr *hdr;
- int res;
-
- /* TODO: could add l2_packet_sendmsg that allows fragments to avoid
- * extra copy here */
-
- if (wpa_s->l2_preauth == NULL)
- return -1;
-
- msglen = sizeof(*ethhdr) + sizeof(*hdr) + len;
- msg = malloc(msglen);
- if (msg == NULL)
- return -1;
-
- ethhdr = (struct l2_ethhdr *) msg;
- memcpy(ethhdr->h_dest, wpa_s->preauth_bssid, ETH_ALEN);
- memcpy(ethhdr->h_source, wpa_s->own_addr, ETH_ALEN);
- ethhdr->h_proto = htons(ETH_P_RSN_PREAUTH);
-
- hdr = (struct ieee802_1x_hdr *) (ethhdr + 1);
- hdr->version = wpa_s->conf->eapol_version;
- hdr->type = type;
- hdr->length = htons(len);
-
- memcpy((u8 *) (hdr + 1), buf, len);
-
- wpa_hexdump(MSG_MSGDUMP, "TX EAPOL (preauth)", msg, msglen);
- res = l2_packet_send(wpa_s->l2_preauth, msg, msglen);
+ res = wpa_ether_send(wpa_s, dst, ETH_P_EAPOL, msg, msglen);
free(msg);
return res;
}
@@ -279,15 +266,33 @@ int wpa_eapol_send_preauth(void *ctx, int type, u8 *buf, size_t len)
* Returns 0 on success or < 0 on error.
*/
static int wpa_eapol_set_wep_key(void *ctx, int unicast, int keyidx,
- u8 *key, size_t keylen)
+ const u8 *key, size_t keylen)
{
struct wpa_supplicant *wpa_s = ctx;
- wpa_s->keys_cleared = 0;
return wpa_drv_set_key(wpa_s, WPA_ALG_WEP,
unicast ? wpa_s->bssid :
(u8 *) "\xff\xff\xff\xff\xff\xff",
keyidx, unicast, (u8 *) "", 0, key, keylen);
}
+#endif /* IEEE8021X_EAPOL */
+
+
+#if defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA)
+static void wpa_supplicant_set_config_blob(void *ctx,
+ struct wpa_config_blob *blob)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ wpa_config_set_blob(wpa_s->conf, blob);
+}
+
+
+static const struct wpa_config_blob *
+wpa_supplicant_get_config_blob(void *ctx, const char *name)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ return wpa_config_get_blob(wpa_s->conf, name);
+}
+#endif /* defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA) */
/* Configure default/group WEP key for static WEP */
@@ -295,7 +300,6 @@ static int wpa_set_wep_key(void *ctx, int set_tx, int keyidx, const u8 *key,
size_t keylen)
{
struct wpa_supplicant *wpa_s = ctx;
- wpa_s->keys_cleared = 0;
return wpa_drv_set_key(wpa_s, WPA_ALG_WEP,
(u8 *) "\xff\xff\xff\xff\xff\xff",
keyidx, set_tx, (u8 *) "", 0, key, keylen);
@@ -351,17 +355,24 @@ static int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
}
-void wpa_supplicant_notify_eapol_done(void *ctx)
+#ifdef IEEE8021X_EAPOL
+static void wpa_supplicant_notify_eapol_done(void *ctx)
{
struct wpa_supplicant *wpa_s = ctx;
wpa_msg(wpa_s, MSG_DEBUG, "WPA: EAPOL processing complete");
- eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
- wpa_supplicant_cancel_auth_timeout(wpa_s);
+ if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
+ wpa_supplicant_set_state(wpa_s, WPA_4WAY_HANDSHAKE);
+ } else {
+ eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
+ wpa_supplicant_cancel_auth_timeout(wpa_s);
+ wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+ }
}
+#endif /* IEEE8021X_EAPOL */
-static struct wpa_blacklist *
-wpa_blacklist_get(struct wpa_supplicant *wpa_s, const u8 *bssid)
+struct wpa_blacklist * wpa_blacklist_get(struct wpa_supplicant *wpa_s,
+ const u8 *bssid)
{
struct wpa_blacklist *e;
@@ -376,7 +387,7 @@ wpa_blacklist_get(struct wpa_supplicant *wpa_s, const u8 *bssid)
}
-static int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
+int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
{
struct wpa_blacklist *e;
@@ -404,7 +415,7 @@ static int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
}
-static int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid)
+int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid)
{
struct wpa_blacklist *e, *prev = NULL;
@@ -428,7 +439,7 @@ static int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid)
}
-static void wpa_blacklist_clear(struct wpa_supplicant *wpa_s)
+void wpa_blacklist_clear(struct wpa_supplicant *wpa_s)
{
struct wpa_blacklist *e, *prev;
@@ -483,6 +494,7 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
wpa_msg(wpa_s, MSG_INFO, "Authentication with " MACSTR " timed out.",
MAC2STR(wpa_s->bssid));
wpa_blacklist_add(wpa_s, wpa_s->bssid);
+ wpa_sm_notify_disassoc(wpa_s->wpa);
wpa_supplicant_disassociate(wpa_s, REASON_DEAUTH_LEAVING);
wpa_s->reassociate = 1;
wpa_supplicant_req_scan(wpa_s, 0, 0);
@@ -492,6 +504,10 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
int sec, int usec)
{
+ if (wpa_s->conf && wpa_s->conf->ap_scan == 0 &&
+ wpa_s->driver && strcmp(wpa_s->driver->name, "wired") == 0)
+ return;
+
wpa_msg(wpa_s, MSG_DEBUG, "Setting authentication timeout: %d sec "
"%d usec", sec, usec);
eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
@@ -507,7 +523,7 @@ void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s)
}
-static void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
+void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
{
struct eapol_config eapol_conf;
struct wpa_ssid *ssid = wpa_s->current_ssid;
@@ -533,15 +549,22 @@ static void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
eapol_conf.required_keys |=
EAPOL_REQUIRE_KEY_BROADCAST;
}
+
+ if (wpa_s->conf && wpa_s->driver &&
+ strcmp(wpa_s->driver->name, "wired") == 0) {
+ eapol_conf.required_keys = 0;
+ }
}
eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
eapol_conf.workaround = ssid->eap_workaround;
+ eapol_conf.eap_disabled = wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X &&
+ wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA;
eapol_sm_notify_config(wpa_s->eapol, ssid, &eapol_conf);
}
-static void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid)
+void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
{
int i;
@@ -549,15 +572,9 @@ static void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA;
else
wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
- free(wpa_s->ap_wpa_ie);
- wpa_s->ap_wpa_ie = NULL;
- wpa_s->ap_wpa_ie_len = 0;
- free(wpa_s->ap_rsn_ie);
- wpa_s->ap_rsn_ie = NULL;
- wpa_s->ap_rsn_ie_len = 0;
- free(wpa_s->assoc_wpa_ie);
- wpa_s->assoc_wpa_ie = NULL;
- wpa_s->assoc_wpa_ie_len = 0;
+ wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
wpa_s->group_cipher = WPA_CIPHER_NONE;
@@ -573,40 +590,12 @@ static void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
}
}
- wpa_s->cur_pmksa = NULL;
-}
-
-
-static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
-{
- struct wpa_ssid *ssid;
-
- if (wpa_s->conf->ap_scan == 1)
- return 0;
-
- ssid = wpa_supplicant_get_ssid(wpa_s);
- if (ssid == NULL) {
- wpa_printf(MSG_INFO, "No network configuration found for the "
- "current AP");
- return -1;
- }
-
- wpa_printf(MSG_DEBUG, "Network configuration found for the current "
- "AP");
- if (ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
- WPA_KEY_MGMT_WPA_NONE)) {
- u8 wpa_ie[80];
- int wpa_ie_len;
- wpa_supplicant_set_suites(wpa_s, NULL, ssid,
- wpa_ie, &wpa_ie_len);
- } else {
- wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
- }
-
- wpa_s->current_ssid = ssid;
- wpa_supplicant_initiate_eapol(wpa_s);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE,
+ wpa_s->pairwise_cipher);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
- return 0;
+ pmksa_cache_clear_current(wpa_s->wpa);
}
@@ -614,50 +603,41 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
{
scard_deinit(wpa_s->scard);
wpa_s->scard = NULL;
+ wpa_sm_set_scard_ctx(wpa_s->wpa, NULL);
eapol_sm_register_scard_ctx(wpa_s->eapol, NULL);
l2_packet_deinit(wpa_s->l2);
wpa_s->l2 = NULL;
-#ifdef CONFIG_XSUPPLICANT_IFACE
- if (wpa_s->dot1x_s > -1) {
- close(wpa_s->dot1x_s);
- wpa_s->dot1x_s = -1;
- }
-#endif /* CONFIG_XSUPPLICANT_IFACE */
-
wpa_supplicant_ctrl_iface_deinit(wpa_s);
if (wpa_s->conf != NULL) {
wpa_config_free(wpa_s->conf);
wpa_s->conf = NULL;
}
- free(wpa_s->assoc_wpa_ie);
- wpa_s->assoc_wpa_ie = NULL;
-
- free(wpa_s->ap_wpa_ie);
- wpa_s->ap_wpa_ie = NULL;
- free(wpa_s->ap_rsn_ie);
- wpa_s->ap_rsn_ie = NULL;
-
free(wpa_s->confname);
wpa_s->confname = NULL;
+ wpa_sm_set_eapol(wpa_s->wpa, NULL);
eapol_sm_deinit(wpa_s->eapol);
wpa_s->eapol = NULL;
- rsn_preauth_deinit(wpa_s);
+ rsn_preauth_deinit(wpa_s->wpa);
- pmksa_candidate_free(wpa_s);
- pmksa_cache_free(wpa_s);
+ pmksa_candidate_free(wpa_s->wpa);
+ pmksa_cache_free(wpa_s->wpa);
+ wpa_sm_deinit(wpa_s->wpa);
+ wpa_s->wpa = NULL;
wpa_blacklist_clear(wpa_s);
free(wpa_s->scan_results);
wpa_s->scan_results = NULL;
wpa_s->num_scan_results = 0;
+
+ wpa_supplicant_cancel_scan(wpa_s);
}
-static void wpa_clear_keys(struct wpa_supplicant *wpa_s, u8 *addr)
+void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
{
u8 *bcast = (u8 *) "\xff\xff\xff\xff\xff\xff";
@@ -686,341 +666,65 @@ static void wpa_clear_keys(struct wpa_supplicant *wpa_s, u8 *addr)
}
-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);
- }
-}
-
-
-static void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
-{
- wpa_s->wpa_state = WPA_DISCONNECTED;
- memset(wpa_s->bssid, 0, ETH_ALEN);
- eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
- eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
- if (wpa_s->key_mgmt == WPA_KEY_MGMT_PSK)
- eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
-}
-
-
-static void wpa_find_assoc_pmkid(struct wpa_supplicant *wpa_s)
-{
- struct wpa_ie_data ie;
- int i;
-
- if (wpa_parse_wpa_ie(wpa_s, wpa_s->assoc_wpa_ie,
- wpa_s->assoc_wpa_ie_len, &ie) < 0 ||
- ie.pmkid == NULL)
- return;
-
- for (i = 0; i < ie.num_pmkid; i++) {
- wpa_s->cur_pmksa = pmksa_cache_get(wpa_s, NULL,
- ie.pmkid + i * PMKID_LEN);
- if (wpa_s->cur_pmksa) {
- eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
- break;
- }
- }
-
- wpa_printf(MSG_DEBUG, "RSN: PMKID from assoc IE %sfound from PMKSA "
- "cache", wpa_s->cur_pmksa ? "" : "not ");
-}
-
-
-static void wpa_supplicant_add_pmkid_candidate(struct wpa_supplicant *wpa_s,
- union wpa_event_data *data)
+const char * wpa_supplicant_state_txt(int state)
{
- if (data == NULL) {
- wpa_printf(MSG_DEBUG, "RSN: No data in PMKID candidate event");
- return;
- }
- wpa_printf(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);
-
- if (!data->pmkid_candidate.preauth) {
- wpa_printf(MSG_DEBUG, "RSN: Ignored PMKID candidate without "
- "preauth flag");
- return;
- }
-
- pmksa_candidate_add(wpa_s, data->pmkid_candidate.bssid,
- data->pmkid_candidate.index);
-}
-
-
-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;
-
- 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;
+ switch (state) {
+ case WPA_DISCONNECTED:
+ return "DISCONNECTED";
+ case WPA_INACTIVE:
+ return "INACTIVE";
+ case WPA_SCANNING:
+ return "SCANNING";
+ case WPA_ASSOCIATING:
+ return "ASSOCIATING";
+ case WPA_ASSOCIATED:
+ return "ASSOCIATED";
+ case WPA_4WAY_HANDSHAKE:
+ return "4WAY_HANDSHAKE";
+ case WPA_GROUP_HANDSHAKE:
+ return "GROUP_HANDSHAKE";
+ case WPA_COMPLETED:
+ return "COMPLETED";
+ default:
+ return "UNKNOWN";
}
-
- return 1;
}
-static void wpa_supplicant_associnfo(struct wpa_supplicant *wpa_s,
- union wpa_event_data *data)
+void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, wpa_states state)
{
- int l, len;
- u8 *p;
-
- wpa_printf(MSG_DEBUG, "Association info event");
- wpa_hexdump(MSG_DEBUG, "req_ies", data->assoc_info.req_ies,
- data->assoc_info.req_ies_len);
- wpa_hexdump(MSG_DEBUG, "resp_ies", data->assoc_info.resp_ies,
- data->assoc_info.resp_ies_len);
- if (wpa_s->assoc_wpa_ie) {
- free(wpa_s->assoc_wpa_ie);
- wpa_s->assoc_wpa_ie = NULL;
- wpa_s->assoc_wpa_ie_len = 0;
- }
-
- 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 (l >= 2) {
- len = p[1] + 2;
- if (len > l) {
- wpa_hexdump(MSG_DEBUG, "Truncated IE in assoc_info",
- p, l);
- break;
- }
- if ((p[0] == GENERIC_INFO_ELEM && p[1] >= 6 &&
- (memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) ||
- (p[0] == RSN_INFO_ELEM && p[1] >= 2)) {
- wpa_s->assoc_wpa_ie = malloc(len);
- if (wpa_s->assoc_wpa_ie == NULL)
- break;
- wpa_s->assoc_wpa_ie_len = len;
- memcpy(wpa_s->assoc_wpa_ie, p, len);
- wpa_hexdump(MSG_DEBUG, "assoc_wpa_ie",
- wpa_s->assoc_wpa_ie,
- wpa_s->assoc_wpa_ie_len);
- wpa_find_assoc_pmkid(wpa_s);
- break;
- }
- l -= len;
- p += len;
- }
-
- /* WPA/RSN IE from Beacon/ProbeResp */
- free(wpa_s->ap_wpa_ie);
- wpa_s->ap_wpa_ie = NULL;
- wpa_s->ap_wpa_ie_len = 0;
- free(wpa_s->ap_rsn_ie);
- wpa_s->ap_rsn_ie = NULL;
- wpa_s->ap_rsn_ie_len = 0;
-
- 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.
- */
- while (l >= 2) {
- len = p[1] + 2;
- if (len > l) {
- wpa_hexdump(MSG_DEBUG, "Truncated IE in beacon_ies",
- p, l);
- break;
- }
- if (wpa_s->ap_wpa_ie == NULL &&
- p[0] == GENERIC_INFO_ELEM && p[1] >= 6 &&
- memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0) {
- wpa_s->ap_wpa_ie = malloc(len);
- if (wpa_s->ap_wpa_ie) {
- memcpy(wpa_s->ap_wpa_ie, p, len);
- wpa_s->ap_wpa_ie_len = len;
- }
- }
-
- if (wpa_s->ap_rsn_ie == NULL &&
- p[0] == RSN_INFO_ELEM && p[1] >= 2) {
- wpa_s->ap_rsn_ie = malloc(len);
- if (wpa_s->ap_rsn_ie) {
- memcpy(wpa_s->ap_rsn_ie, p, len);
- wpa_s->ap_rsn_ie_len = len;
- }
-
- }
-
- l -= len;
- p += len;
- }
-
+ wpa_printf(MSG_DEBUG, "State: %s -> %s",
+ wpa_supplicant_state_txt(wpa_s->wpa_state),
+ wpa_supplicant_state_txt(state));
+ if (state == WPA_COMPLETED && wpa_s->new_connection) {
+ wpa_s->new_connection = 0;
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- Connection to "
+ MACSTR " completed %s",
+ MAC2STR(wpa_s->bssid), wpa_s->reassociated_connection ?
+ "(reauth)" : "(auth)");
+ wpa_s->reassociated_connection = 1;
+ } else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
+ state == WPA_ASSOCIATED) {
+ wpa_s->new_connection = 1;
+ }
+ wpa_s->wpa_state = state;
}
-void wpa_supplicant_event(struct wpa_supplicant *wpa_s, wpa_event_type event,
- union wpa_event_data *data)
+wpa_states wpa_supplicant_get_state(struct wpa_supplicant *wpa_s)
{
- int pairwise;
- time_t now;
- u8 bssid[ETH_ALEN];
-
- switch (event) {
- case EVENT_ASSOC:
- wpa_s->wpa_state = WPA_ASSOCIATED;
- wpa_printf(MSG_DEBUG, "Association event - clear replay "
- "counter");
- memset(wpa_s->rx_replay_counter, 0, WPA_REPLAY_COUNTER_LEN);
- wpa_s->rx_replay_counter_set = 0;
- wpa_s->renew_snonce = 1;
- if (wpa_drv_get_bssid(wpa_s, bssid) >= 0 &&
- memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) {
- wpa_msg(wpa_s, MSG_DEBUG, "Associated to a new BSS: "
- "BSSID=" MACSTR, MAC2STR(bssid));
- memcpy(wpa_s->bssid, bssid, ETH_ALEN);
- if (wpa_supplicant_dynamic_keys(wpa_s)) {
- wpa_clear_keys(wpa_s, bssid);
- }
- wpa_supplicant_select_config(wpa_s);
- }
- wpa_msg(wpa_s, MSG_INFO, "Associated with " MACSTR,
- MAC2STR(bssid));
- /* 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.
- */
- eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
- eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
- if (wpa_s->key_mgmt == WPA_KEY_MGMT_PSK)
- 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 ||
- wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
- wpa_supplicant_cancel_auth_timeout(wpa_s);
- } else {
- /* Timeout for receiving the first EAPOL packet */
- wpa_supplicant_req_auth_timeout(wpa_s, 10, 0);
- }
- break;
- case EVENT_DISASSOC:
- 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.
- */
- wpa_printf(MSG_DEBUG, "Disconnect event - ignore in "
- "IBSS/WPA-None mode");
- break;
- }
- if (wpa_s->wpa_state >= WPA_ASSOCIATED)
- wpa_supplicant_req_scan(wpa_s, 0, 100000);
- wpa_blacklist_add(wpa_s, wpa_s->bssid);
- wpa_supplicant_mark_disassoc(wpa_s);
- wpa_msg(wpa_s, MSG_INFO, "Disconnect event - remove keys");
- if (wpa_supplicant_dynamic_keys(wpa_s)) {
- wpa_s->keys_cleared = 0;
- wpa_clear_keys(wpa_s, wpa_s->bssid);
- }
- break;
- case EVENT_MICHAEL_MIC_FAILURE:
- wpa_msg(wpa_s, MSG_WARNING, "Michael MIC failure detected");
- pairwise = (data && data->michael_mic_failure.unicast);
- wpa_supplicant_key_request(wpa_s, 1, pairwise);
- time(&now);
- if (wpa_s->last_michael_mic_error &&
- now - wpa_s->last_michael_mic_error <= 60) {
- /* 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. */
- usleep(10000);
-
- wpa_drv_set_countermeasures(wpa_s, 1);
- wpa_supplicant_deauthenticate(
- wpa_s, 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.. */
- }
- wpa_s->last_michael_mic_error = now;
- break;
- case EVENT_SCAN_RESULTS:
- wpa_supplicant_scan_results(wpa_s);
- break;
- case EVENT_ASSOCINFO:
- wpa_supplicant_associnfo(wpa_s, data);
- break;
- case EVENT_INTERFACE_STATUS:
- if (strcmp(wpa_s->ifname, data->interface_status.ifname) != 0)
- break;
- switch (data->interface_status.ievent) {
- case EVENT_INTERFACE_ADDED:
- if (!wpa_s->interface_removed)
- break;
- wpa_s->interface_removed = 0;
- wpa_printf(MSG_DEBUG, "Configured interface was "
- "added.");
- if (wpa_supplicant_driver_init(wpa_s, 1) < 0) {
- wpa_printf(MSG_INFO, "Failed to initialize "
- "the driver after interface was "
- "added.");
- }
- break;
- case EVENT_INTERFACE_REMOVED:
- wpa_printf(MSG_DEBUG, "Configured interface was "
- "removed.");
- wpa_s->interface_removed = 1;
- wpa_supplicant_mark_disassoc(wpa_s);
- l2_packet_deinit(wpa_s->l2);
- wpa_s->l2 = NULL;
- break;
- }
- break;
- case EVENT_PMKID_CANDIDATE:
- wpa_supplicant_add_pmkid_candidate(wpa_s, data);
- break;
- default:
- wpa_printf(MSG_INFO, "Unknown event %d", event);
- break;
- }
+ return wpa_s->wpa_state;
}
static void wpa_supplicant_terminate(int sig, void *eloop_ctx,
void *signal_ctx)
{
- struct wpa_supplicant *wpa_s = eloop_ctx;
- for (wpa_s = wpa_s->head; wpa_s; wpa_s = wpa_s->next) {
- wpa_msg(wpa_s, MSG_INFO, "Signal %d received - terminating",
- sig);
+ struct wpa_global *global = eloop_ctx;
+ struct wpa_supplicant *wpa_s;
+ for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TERMINATING "- signal %d "
+ "received", sig);
}
eloop_terminate();
}
@@ -1048,8 +752,15 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
wpa_supplicant_ctrl_iface_deinit(wpa_s);
wpa_s->current_ssid = NULL;
+ /*
+ * TODO: should notify EAPOL SM about changes in opensc_engine_path,
+ * pkcs11_engine_path, pkcs11_module_path.
+ */
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
- rsn_preauth_deinit(wpa_s);
+ wpa_sm_set_config(wpa_s->wpa, NULL);
+ wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
+ pmksa_cache_notify_reconfig(wpa_s->wpa);
+ rsn_preauth_deinit(wpa_s->wpa);
wpa_config_free(wpa_s->conf);
wpa_s->conf = conf;
if (reconf_ctrl)
@@ -1065,9 +776,10 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
static void wpa_supplicant_reconfig(int sig, void *eloop_ctx,
void *signal_ctx)
{
- struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct wpa_global *global = eloop_ctx;
+ struct wpa_supplicant *wpa_s;
wpa_printf(MSG_DEBUG, "Signal %d received - reconfiguring", sig);
- for (wpa_s = wpa_s->head; wpa_s; wpa_s = wpa_s->next) {
+ for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
if (wpa_supplicant_reload_configuration(wpa_s) < 0) {
eloop_terminate();
}
@@ -1085,6 +797,9 @@ static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s)
if (ssid == NULL)
return;
+ if (wpa_s->current_ssid == NULL)
+ wpa_s->current_ssid = ssid;
+ wpa_supplicant_initiate_eapol(wpa_s);
wpa_printf(MSG_DEBUG, "Already associated with a configured network - "
"generating associated event");
memset(&data, 0, sizeof(data));
@@ -1092,26 +807,40 @@ static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s)
}
-void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
+static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
struct wpa_ssid *ssid;
+ int enabled, scan_req = 0;
- if (wpa_s->conf->ap_scan == 0) {
- wpa_supplicant_gen_assoc_event(wpa_s);
+ if (wpa_s->disconnected)
+ return;
+
+ enabled = 0;
+ ssid = wpa_s->conf->ssid;
+ while (ssid) {
+ if (!ssid->disabled) {
+ enabled++;
+ break;
+ }
+ ssid = ssid->next;
+ }
+ if (!enabled && !wpa_s->scan_req) {
+ wpa_printf(MSG_DEBUG, "No enabled networks - do not scan");
+ wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
return;
}
+ scan_req = wpa_s->scan_req;
+ wpa_s->scan_req = 0;
- if (wpa_s->conf->ap_scan == 2) {
- ssid = wpa_s->conf->ssid;
- if (ssid == NULL)
- return;
- wpa_supplicant_associate(wpa_s, NULL, ssid);
+ if (wpa_s->conf->ap_scan == 0) {
+ wpa_supplicant_gen_assoc_event(wpa_s);
return;
}
- if (wpa_s->wpa_state == WPA_DISCONNECTED)
- wpa_s->wpa_state = WPA_SCANNING;
+ if (wpa_s->wpa_state == WPA_DISCONNECTED ||
+ wpa_s->wpa_state == WPA_INACTIVE)
+ wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
ssid = wpa_s->conf->ssid;
if (wpa_s->prev_scan_ssid != BROADCAST_SSID_SCAN) {
@@ -1124,11 +853,30 @@ void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
}
}
while (ssid) {
- if (ssid->scan_ssid)
+ if (!ssid->disabled &&
+ (ssid->scan_ssid || wpa_s->conf->ap_scan == 2))
break;
ssid = ssid->next;
}
+ if (scan_req != 2 && wpa_s->conf->ap_scan == 2) {
+ /*
+ * ap_scan=2 mode - try to associate with each SSID instead of
+ * scanning for each scan_ssid=1 network.
+ */
+ if (ssid == NULL)
+ return;
+ if (ssid->next) {
+ /* Continue from the next SSID on the next attempt. */
+ wpa_s->prev_scan_ssid = ssid;
+ } else {
+ /* Start from the beginning of the SSID list. */
+ wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN;
+ }
+ wpa_supplicant_associate(wpa_s, NULL, ssid);
+ return;
+ }
+
wpa_printf(MSG_DEBUG, "Starting AP scan (%s SSID)",
ssid ? "specific": "broadcast");
if (ssid) {
@@ -1184,14 +932,14 @@ static wpa_key_mgmt key_mgmt2driver(int key_mgmt)
static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
- struct wpa_ie_data *ie) {
- if (wpa_s->assoc_wpa_ie == NULL)
- return -1;
-
- if (wpa_parse_wpa_ie(wpa_s, wpa_s->assoc_wpa_ie,
- wpa_s->assoc_wpa_ie_len, ie)) {
- wpa_msg(wpa_s, MSG_INFO, "WPA: Failed to parse WPA IE from "
- "association info");
+ struct wpa_ie_data *ie)
+{
+ int ret = wpa_sm_parse_own_wpa_ie(wpa_s->wpa, ie);
+ if (ret) {
+ if (ret == -2) {
+ wpa_msg(wpa_s, MSG_INFO, "WPA: Failed to parse WPA IE "
+ "from association info");
+ }
return -1;
}
@@ -1220,33 +968,36 @@ static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
}
-static int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
- struct wpa_scan_result *bss,
- struct wpa_ssid *ssid,
- u8 *wpa_ie, int *wpa_ie_len)
+int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_result *bss,
+ struct wpa_ssid *ssid,
+ u8 *wpa_ie, size_t *wpa_ie_len)
{
struct wpa_ie_data ie;
int sel, proto;
- u8 *ap_ie;
- size_t ap_ie_len;
- if (bss && bss->rsn_ie_len && (ssid->proto & WPA_PROTO_RSN)) {
+ if (bss && bss->rsn_ie_len && (ssid->proto & WPA_PROTO_RSN) &&
+ wpa_parse_wpa_ie(bss->rsn_ie, bss->rsn_ie_len, &ie) == 0 &&
+ (ie.group_cipher & ssid->group_cipher) &&
+ (ie.pairwise_cipher & ssid->pairwise_cipher) &&
+ (ie.key_mgmt & ssid->key_mgmt)) {
wpa_msg(wpa_s, MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0");
proto = WPA_PROTO_RSN;
- ap_ie = bss->rsn_ie;
- ap_ie_len = bss->rsn_ie_len;
- } else if (bss) {
+ } else if (bss && bss->wpa_ie_len && (ssid->proto & WPA_PROTO_WPA) &&
+ wpa_parse_wpa_ie(bss->wpa_ie, bss->wpa_ie_len, &ie) == 0 &&
+ (ie.group_cipher & ssid->group_cipher) &&
+ (ie.pairwise_cipher & ssid->pairwise_cipher) &&
+ (ie.key_mgmt & ssid->key_mgmt)) {
wpa_msg(wpa_s, MSG_DEBUG, "WPA: using IEEE 802.11i/D3.0");
proto = WPA_PROTO_WPA;
- ap_ie = bss->wpa_ie;
- ap_ie_len = bss->wpa_ie_len;
+ } else if (bss) {
+ wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select WPA/RSN");
+ return -1;
} else {
if (ssid->proto & WPA_PROTO_RSN)
proto = WPA_PROTO_RSN;
else
proto = WPA_PROTO_WPA;
- ap_ie = NULL;
- ap_ie_len = 0;
if (wpa_supplicant_suites_from_ai(wpa_s, ssid, &ie) < 0) {
memset(&ie, 0, sizeof(ie));
ie.group_cipher = ssid->group_cipher;
@@ -1257,42 +1008,17 @@ static int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
}
}
- if (ap_ie && wpa_parse_wpa_ie(wpa_s, ap_ie, ap_ie_len, &ie)) {
- wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to parse WPA IE for "
- "the selected BSS.");
- return -1;
- }
wpa_printf(MSG_DEBUG, "WPA: Selected cipher suites: group %d "
"pairwise %d key_mgmt %d",
ie.group_cipher, ie.pairwise_cipher, ie.key_mgmt);
- wpa_s->proto = proto;
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto);
- free(wpa_s->ap_wpa_ie);
- wpa_s->ap_wpa_ie = NULL;
- wpa_s->ap_wpa_ie_len = 0;
- if (bss && bss->wpa_ie_len) {
- wpa_s->ap_wpa_ie = malloc(bss->wpa_ie_len);
- if (wpa_s->ap_wpa_ie == NULL) {
- wpa_printf(MSG_INFO, "WPA: malloc failed");
- return -1;
- }
- memcpy(wpa_s->ap_wpa_ie, bss->wpa_ie, bss->wpa_ie_len);
- wpa_s->ap_wpa_ie_len = bss->wpa_ie_len;
- }
-
- free(wpa_s->ap_rsn_ie);
- wpa_s->ap_rsn_ie = NULL;
- wpa_s->ap_rsn_ie_len = 0;
- if (bss && bss->rsn_ie_len) {
- wpa_s->ap_rsn_ie = malloc(bss->rsn_ie_len);
- if (wpa_s->ap_rsn_ie == NULL) {
- wpa_printf(MSG_INFO, "WPA: malloc failed");
- return -1;
- }
- memcpy(wpa_s->ap_rsn_ie, bss->rsn_ie, bss->rsn_ie_len);
- wpa_s->ap_rsn_ie_len = bss->rsn_ie_len;
- }
+ if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss ? bss->wpa_ie : NULL,
+ bss ? bss->wpa_ie_len : 0) ||
+ wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss ? bss->rsn_ie : NULL,
+ bss ? bss->rsn_ie_len : 0))
+ return -1;
sel = ie.group_cipher & ssid->group_cipher;
if (sel & WPA_CIPHER_CCMP) {
@@ -1344,61 +1070,44 @@ static int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
return -1;
}
- *wpa_ie_len = wpa_gen_wpa_ie(wpa_s, wpa_ie);
- if (*wpa_ie_len < 0) {
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE,
+ wpa_s->pairwise_cipher);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
+
+ if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
wpa_printf(MSG_WARNING, "WPA: Failed to generate WPA IE.");
return -1;
}
- wpa_hexdump(MSG_DEBUG, "WPA: Own WPA IE", wpa_ie, *wpa_ie_len);
- if (wpa_s->assoc_wpa_ie == NULL) {
- /*
- * Make a copy of the WPA/RSN IE so that 4-Way Handshake gets
- * the correct version of the IE even if PMKSA caching is
- * aborted (which would remove PMKID from IE generation).
- */
- wpa_s->assoc_wpa_ie = malloc(*wpa_ie_len);
- if (wpa_s->assoc_wpa_ie) {
- memcpy(wpa_s->assoc_wpa_ie, wpa_ie, *wpa_ie_len);
- wpa_s->assoc_wpa_ie_len = *wpa_ie_len;
- }
- }
- if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
- wpa_s->pmk_len = PMK_LEN;
- memcpy(wpa_s->pmk, ssid->psk, PMK_LEN);
- } else if (wpa_s->cur_pmksa) {
- wpa_s->pmk_len = wpa_s->cur_pmksa->pmk_len;
- memcpy(wpa_s->pmk, wpa_s->cur_pmksa->pmk, wpa_s->pmk_len);
- } else {
- wpa_s->pmk_len = PMK_LEN;
- memset(wpa_s->pmk, 0, PMK_LEN);
-#ifdef CONFIG_XSUPPLICANT_IFACE
- wpa_s->ext_pmk_received = 0;
-#endif /* CONFIG_XSUPPLICANT_IFACE */
- }
+ if (ssid->key_mgmt & WPA_KEY_MGMT_PSK)
+ wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN);
+ else
+ wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
return 0;
}
-static void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
- struct wpa_scan_result *bss,
- struct wpa_ssid *ssid)
+void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_result *bss,
+ struct wpa_ssid *ssid)
{
u8 wpa_ie[80];
- int wpa_ie_len;
+ size_t wpa_ie_len;
int use_crypt;
int algs = AUTH_ALG_OPEN_SYSTEM;
int cipher_pairwise, cipher_group;
struct wpa_driver_associate_params params;
int wep_keys_set = 0;
struct wpa_driver_capa capa;
+ int assoc_failed = 0;
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),
- wpa_ssid_txt(ssid->ssid, ssid->ssid_len), bss->freq);
+ wpa_ssid_txt(bss->ssid, bss->ssid_len), bss->freq);
memset(wpa_s->bssid, 0, ETH_ALEN);
} else {
wpa_msg(wpa_s, MSG_INFO, "Trying to associate with SSID '%s'",
@@ -1408,9 +1117,7 @@ static void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
/* Starting new association, so clear the possibly used WPA IE from the
* previous association. */
- free(wpa_s->assoc_wpa_ie);
- wpa_s->assoc_wpa_ie = NULL;
- wpa_s->assoc_wpa_ie_len = 0;
+ wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
if (ssid->leap) {
@@ -1436,12 +1143,14 @@ static void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
if (bss && (bss->wpa_ie_len || bss->rsn_ie_len) &&
(ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK))) {
- wpa_s->cur_pmksa = pmksa_cache_get(wpa_s, bss->bssid, NULL);
- if (wpa_s->cur_pmksa) {
- wpa_hexdump(MSG_DEBUG, "RSN: PMKID",
- wpa_s->cur_pmksa->pmkid, PMKID_LEN);
+ int try_opportunistic;
+ try_opportunistic = ssid->proactive_key_caching &&
+ (ssid->proto & WPA_PROTO_RSN);
+ if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
+ wpa_s->current_ssid,
+ try_opportunistic) == 0)
eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
- }
+ wpa_ie_len = sizeof(wpa_ie);
if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
wpa_ie, &wpa_ie_len)) {
wpa_printf(MSG_WARNING, "WPA: Failed to set WPA key "
@@ -1451,6 +1160,7 @@ static void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
} else if (ssid->key_mgmt &
(WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
WPA_KEY_MGMT_WPA_NONE)) {
+ wpa_ie_len = sizeof(wpa_ie);
if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
wpa_ie, &wpa_ie_len)) {
wpa_printf(MSG_WARNING, "WPA: Failed to set WPA key "
@@ -1504,7 +1214,7 @@ static void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
}
wpa_drv_set_drop_unencrypted(wpa_s, use_crypt);
- wpa_s->wpa_state = WPA_ASSOCIATING;
+ wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
memset(&params, 0, sizeof(params));
if (bss) {
params.bssid = bss->bssid;
@@ -1527,6 +1237,7 @@ static void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
"failed");
/* try to continue anyway; new association will be tried again
* after timeout */
+ assoc_failed = 1;
}
if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
@@ -1536,9 +1247,17 @@ static void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
/* No need to timeout authentication since there is no key
* management. */
wpa_supplicant_cancel_auth_timeout(wpa_s);
+ wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
} else {
/* Timeout for IEEE 802.11 authentication and association */
- wpa_supplicant_req_auth_timeout(wpa_s, 5, 0);
+ int timeout;
+ if (assoc_failed)
+ timeout = 5;
+ else if (wpa_s->conf->ap_scan == 1)
+ timeout = 10;
+ else
+ timeout = 60;
+ wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
}
if (wep_keys_set && wpa_drv_get_capa(wpa_s, &capa) == 0 &&
@@ -1556,6 +1275,7 @@ static void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
}
wpa_s->current_ssid = ssid;
+ wpa_sm_set_config(wpa_s->wpa, wpa_s->current_ssid);
wpa_supplicant_initiate_eapol(wpa_s);
}
@@ -1564,13 +1284,14 @@ void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
int reason_code)
{
u8 *addr = NULL;
- wpa_s->wpa_state = WPA_DISCONNECTED;
+ wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
if (memcmp(wpa_s->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) != 0) {
wpa_drv_disassociate(wpa_s, wpa_s->bssid, reason_code);
addr = wpa_s->bssid;
}
wpa_clear_keys(wpa_s, addr);
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);
@@ -1581,211 +1302,21 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
int reason_code)
{
u8 *addr = NULL;
- wpa_s->wpa_state = WPA_DISCONNECTED;
+ wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
if (memcmp(wpa_s->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) != 0) {
wpa_drv_deauthenticate(wpa_s, wpa_s->bssid, reason_code);
addr = wpa_s->bssid;
}
wpa_clear_keys(wpa_s, addr);
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);
}
-static void wpa_supplicant_imsi_identity(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid)
-{
- int aka = 0;
- u8 *pos = ssid->eap_methods;
-
- while (pos && *pos != EAP_TYPE_NONE) {
- if (*pos == EAP_TYPE_AKA) {
- aka = 1;
- break;
- }
- pos++;
- }
-
- if (ssid->identity == NULL && wpa_s->imsi) {
- ssid->identity = malloc(1 + wpa_s->imsi_len);
- if (ssid->identity) {
- ssid->identity[0] = aka ? '0' : '1';
- memcpy(ssid->identity + 1, wpa_s->imsi,
- wpa_s->imsi_len);
- ssid->identity_len = 1 + wpa_s->imsi_len;
- wpa_hexdump_ascii(MSG_DEBUG, "permanent identity from "
- "IMSI", ssid->identity,
- ssid->identity_len);
- }
- }
-}
-
-
-static void wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid)
-{
- char buf[100];
- size_t len;
-
- if (ssid->pcsc == NULL)
- return;
- if (wpa_s->scard != NULL) {
- wpa_supplicant_imsi_identity(wpa_s, ssid);
- return;
- }
- wpa_printf(MSG_DEBUG, "Selected network is configured to use SIM - "
- "initialize PCSC");
- wpa_s->scard = scard_init(SCARD_TRY_BOTH, ssid->pin);
- if (wpa_s->scard == NULL) {
- wpa_printf(MSG_WARNING, "Failed to initialize SIM "
- "(pcsc-lite)");
- /* TODO: what to do here? */
- return;
- }
- eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
-
- len = sizeof(buf);
- if (scard_get_imsi(wpa_s->scard, buf, &len)) {
- wpa_printf(MSG_WARNING, "Failed to get IMSI from SIM");
- /* TODO: what to do here? */
- return;
- }
-
- wpa_hexdump_ascii(MSG_DEBUG, "IMSI", (u8 *) buf, len);
- free(wpa_s->imsi);
- wpa_s->imsi = malloc(len);
- if (wpa_s->imsi) {
- memcpy(wpa_s->imsi, buf, len);
- wpa_s->imsi_len = len;
- wpa_supplicant_imsi_identity(wpa_s, ssid);
- }
-}
-
-
-static struct wpa_scan_result *
-wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_ssid *group,
- struct wpa_scan_result *results, int num,
- struct wpa_ssid **selected_ssid)
-{
- struct wpa_ssid *ssid;
- struct wpa_scan_result *bss, *selected = NULL;
- int i;
- struct wpa_blacklist *e;
-
- wpa_printf(MSG_DEBUG, "Selecting BSS from priority group %d",
- group->priority);
-
- bss = NULL;
- ssid = NULL;
- /* First, try to find WPA-enabled AP */
- for (i = 0; i < num && !selected; i++) {
- bss = &results[i];
- wpa_printf(MSG_DEBUG, "%d: " MACSTR " ssid='%s' "
- "wpa_ie_len=%lu rsn_ie_len=%lu",
- i, MAC2STR(bss->bssid),
- wpa_ssid_txt(bss->ssid, bss->ssid_len),
- (unsigned long) bss->wpa_ie_len,
- (unsigned long) bss->rsn_ie_len);
- if ((e = wpa_blacklist_get(wpa_s, bss->bssid)) &&
- e->count > 1) {
- wpa_printf(MSG_DEBUG, " skip - blacklisted");
- continue;
- }
-
- if (bss->wpa_ie_len == 0 && bss->rsn_ie_len == 0) {
- wpa_printf(MSG_DEBUG, " skip - no WPA/RSN IE");
- continue;
- }
-
- for (ssid = group; ssid; ssid = ssid->pnext) {
- struct wpa_ie_data ie;
- if (bss->ssid_len != ssid->ssid_len ||
- memcmp(bss->ssid, ssid->ssid,
- bss->ssid_len) != 0) {
- wpa_printf(MSG_DEBUG, " skip - "
- "SSID mismatch");
- continue;
- }
- if (ssid->bssid_set &&
- memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) {
- wpa_printf(MSG_DEBUG, " skip - "
- "BSSID mismatch");
- continue;
- }
- if (!(((ssid->proto & WPA_PROTO_RSN) &&
- wpa_parse_wpa_ie(wpa_s, bss->rsn_ie,
- bss->rsn_ie_len, &ie) == 0) ||
- ((ssid->proto & WPA_PROTO_WPA) &&
- wpa_parse_wpa_ie(wpa_s, bss->wpa_ie,
- bss->wpa_ie_len, &ie) == 0))) {
- wpa_printf(MSG_DEBUG, " skip - "
- "could not parse WPA/RSN IE");
- continue;
- }
- if (!(ie.proto & ssid->proto)) {
- wpa_printf(MSG_DEBUG, " skip - "
- "proto mismatch");
- continue;
- }
- if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
- wpa_printf(MSG_DEBUG, " skip - "
- "PTK cipher mismatch");
- continue;
- }
- if (!(ie.group_cipher & ssid->group_cipher)) {
- wpa_printf(MSG_DEBUG, " skip - "
- "GTK cipher mismatch");
- continue;
- }
- if (!(ie.key_mgmt & ssid->key_mgmt)) {
- wpa_printf(MSG_DEBUG, " skip - "
- "key mgmt mismatch");
- continue;
- }
-
- selected = bss;
- *selected_ssid = ssid;
- wpa_printf(MSG_DEBUG, " selected");
- break;
- }
- }
-
- /* If no WPA-enabled AP found, try to find non-WPA AP, if configuration
- * allows this. */
- for (i = 0; i < num && !selected; i++) {
- bss = &results[i];
- if ((e = wpa_blacklist_get(wpa_s, bss->bssid)) &&
- e->count > 1) {
- continue;
- }
- for (ssid = group; ssid; ssid = ssid->pnext) {
- if (bss->ssid_len == ssid->ssid_len &&
- memcmp(bss->ssid, ssid->ssid, bss->ssid_len) == 0
- &&
- (!ssid->bssid_set ||
- memcmp(bss->bssid, ssid->bssid, ETH_ALEN) == 0) &&
- ((ssid->key_mgmt & WPA_KEY_MGMT_NONE) ||
- (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)))
- {
- selected = bss;
- *selected_ssid = ssid;
- wpa_printf(MSG_DEBUG, " selected non-WPA AP "
- MACSTR " ssid='%s'",
- MAC2STR(bss->bssid),
- wpa_ssid_txt(bss->ssid,
- bss->ssid_len));
- break;
- }
- }
- }
-
- return selected;
-}
-
-
-static int wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s)
+int wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s)
{
#define SCAN_AP_LIMIT 128
struct wpa_scan_result *results, *tmp;
@@ -1825,57 +1356,7 @@ static int wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s)
}
-static void wpa_supplicant_scan_results(struct wpa_supplicant *wpa_s)
-{
- int num, prio;
- struct wpa_scan_result *selected = NULL;
- struct wpa_ssid *ssid;
- struct wpa_scan_result *results;
-
- if (wpa_supplicant_get_scan_results(wpa_s) < 0) {
- wpa_printf(MSG_DEBUG, "Failed to get scan results - try "
- "scanning again");
- wpa_supplicant_req_scan(wpa_s, 1, 0);
- return;
- }
- results = wpa_s->scan_results;
- num = wpa_s->num_scan_results;
-
- while (selected == NULL) {
- for (prio = 0; prio < wpa_s->conf->num_prio; prio++) {
- selected = wpa_supplicant_select_bss(
- wpa_s, wpa_s->conf->pssid[prio], results, num,
- &ssid);
- if (selected)
- break;
- }
-
- if (selected == NULL && wpa_s->blacklist) {
- wpa_printf(MSG_DEBUG, "No APs found - clear blacklist "
- "and try again");
- wpa_blacklist_clear(wpa_s);
- } else if (selected == NULL) {
- break;
- }
- }
-
- if (selected) {
- if (wpa_s->reassociate ||
- memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0) {
- wpa_supplicant_scard_init(wpa_s, ssid);
- wpa_supplicant_associate(wpa_s, selected, ssid);
- } else {
- wpa_printf(MSG_DEBUG, "Already associated with the "
- "selected AP.");
- }
- rsn_preauth_scan_results(wpa_s, results, num);
- } else {
- wpa_printf(MSG_DEBUG, "No suitable AP found.");
- wpa_supplicant_req_scan(wpa_s, 5, 0);
- }
-}
-
-
+#ifndef CONFIG_NO_WPA
static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s)
{
int i, ret = 0;
@@ -1894,33 +1375,11 @@ static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s)
}
if (curr) {
- free(wpa_s->ap_wpa_ie);
- wpa_s->ap_wpa_ie_len = curr->wpa_ie_len;
- if (curr->wpa_ie_len) {
- wpa_s->ap_wpa_ie = malloc(wpa_s->ap_wpa_ie_len);
- if (wpa_s->ap_wpa_ie) {
- memcpy(wpa_s->ap_wpa_ie, curr->wpa_ie,
- curr->wpa_ie_len);
- } else {
- ret = -1;
- }
- } else {
- wpa_s->ap_wpa_ie = NULL;
- }
-
- free(wpa_s->ap_rsn_ie);
- wpa_s->ap_rsn_ie_len = curr->rsn_ie_len;
- if (curr->rsn_ie_len) {
- wpa_s->ap_rsn_ie = malloc(wpa_s->ap_rsn_ie_len);
- if (wpa_s->ap_rsn_ie) {
- memcpy(wpa_s->ap_rsn_ie, curr->rsn_ie,
- curr->rsn_ie_len);
- } else {
- ret = -1;
- }
- } else {
- wpa_s->ap_rsn_ie = NULL;
- }
+ if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, curr->wpa_ie,
+ curr->wpa_ie_len) ||
+ wpa_sm_set_ap_rsn_ie(wpa_s->wpa, curr->rsn_ie,
+ curr->rsn_ie_len))
+ ret = -1;
} else {
ret = -1;
}
@@ -1929,8 +1388,9 @@ static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s)
}
-int wpa_supplicant_get_beacon_ie(struct wpa_supplicant *wpa_s)
+static int wpa_supplicant_get_beacon_ie(void *ctx)
{
+ struct wpa_supplicant *wpa_s = ctx;
if (wpa_get_beacon_ie(wpa_s) == 0) {
return 0;
}
@@ -1943,69 +1403,135 @@ int wpa_supplicant_get_beacon_ie(struct wpa_supplicant *wpa_s)
return wpa_get_beacon_ie(wpa_s);
}
+#endif /* CONFIG_NO_WPA */
-#ifdef CONFIG_XSUPPLICANT_IFACE
-static void wpa_supplicant_dot1x_receive(int sock, void *eloop_ctx,
- void *sock_ctx)
+/**
+ * wpa_supplicant_get_ssid - get a pointer to the current network structure
+ * @wpa_s: pointer to wpa_supplicant data
+ *
+ * Returns: a pointer to the current network structure or %NULL on failure
+ */
+struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
{
- struct wpa_supplicant *wpa_s = eloop_ctx;
- u8 buf[128];
- int res;
+ struct wpa_ssid *entry;
+ u8 ssid[MAX_SSID_LEN];
+ int ssid_len;
+ u8 bssid[ETH_ALEN];
- res = recv(sock, buf, sizeof(buf), 0);
- wpa_printf(MSG_DEBUG, "WPA: Receive from dot1x (Xsupplicant) socket "
- "==> %d", res);
- if (res < 0) {
- perror("recv");
- return;
+ ssid_len = wpa_drv_get_ssid(wpa_s, ssid);
+ if (ssid_len < 0) {
+ wpa_printf(MSG_WARNING, "Could not read SSID from driver.");
+ return NULL;
}
- if (res != PMK_LEN) {
- wpa_printf(MSG_WARNING, "WPA: Invalid master key length (%d) "
- "from dot1x", res);
- return;
+ if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
+ wpa_printf(MSG_WARNING, "Could not read BSSID from driver.");
+ return NULL;
}
- wpa_hexdump(MSG_DEBUG, "WPA: Master key (dot1x)", buf, PMK_LEN);
- if (wpa_s->key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
- memcpy(wpa_s->pmk, buf, PMK_LEN);
- wpa_s->ext_pmk_received = 1;
- } else {
- wpa_printf(MSG_INFO, "WPA: Not in IEEE 802.1X mode - dropping "
- "dot1x PMK update (%d)", wpa_s->key_mgmt);
+ entry = wpa_s->conf->ssid;
+ while (entry) {
+ if (!entry->disabled &&
+ ssid_len == entry->ssid_len &&
+ memcmp(ssid, entry->ssid, ssid_len) == 0 &&
+ (!entry->bssid_set ||
+ memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
+ return entry;
+ entry = entry->next;
}
+
+ return NULL;
}
-static int wpa_supplicant_802_1x_init(struct wpa_supplicant *wpa_s)
+#ifndef CONFIG_NO_WPA
+static u8 * _wpa_alloc_eapol(void *wpa_s, u8 type,
+ const void *data, u16 data_len,
+ size_t *msg_len, void **data_pos)
{
- int s;
- struct sockaddr_un addr;
+ return wpa_alloc_eapol(wpa_s, type, data, data_len, msg_len, data_pos);
+}
- s = socket(AF_LOCAL, SOCK_DGRAM, 0);
- if (s < 0) {
- perror("socket");
- return -1;
- }
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_LOCAL;
- addr.sun_path[0] = '\0';
- snprintf(addr.sun_path + 1, sizeof(addr.sun_path) - 1,
- "wpa_supplicant");
- if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("bind");
- close(s);
- return -1;
- }
+static int _wpa_ether_send(void *wpa_s, const u8 *dest, u16 proto,
+ const u8 *buf, size_t len)
+{
+ return wpa_ether_send(wpa_s, dest, proto, buf, len);
+}
- wpa_s->dot1x_s = s;
- eloop_register_read_sock(s, wpa_supplicant_dot1x_receive, wpa_s,
- NULL);
- return 0;
+
+static void _wpa_supplicant_req_scan(void *wpa_s, int sec, int usec)
+{
+ wpa_supplicant_req_scan(wpa_s, sec, usec);
+}
+
+
+static void _wpa_supplicant_cancel_auth_timeout(void *wpa_s)
+{
+ wpa_supplicant_cancel_auth_timeout(wpa_s);
+}
+
+
+static void _wpa_supplicant_set_state(void *wpa_s, wpa_states state)
+{
+ wpa_supplicant_set_state(wpa_s, state);
+}
+
+
+static wpa_states _wpa_supplicant_get_state(void *wpa_s)
+{
+ return wpa_supplicant_get_state(wpa_s);
+}
+
+
+static void _wpa_supplicant_disassociate(void *wpa_s, int reason_code)
+{
+ wpa_supplicant_disassociate(wpa_s, reason_code);
+}
+
+
+static void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code)
+{
+ wpa_supplicant_deauthenticate(wpa_s, reason_code);
+}
+
+
+static struct wpa_ssid * _wpa_supplicant_get_ssid(void *wpa_s)
+{
+ return wpa_supplicant_get_ssid(wpa_s);
+}
+
+
+static int wpa_supplicant_get_bssid(void *wpa_s, u8 *bssid)
+{
+ return wpa_drv_get_bssid(wpa_s, bssid);
+}
+
+
+static int wpa_supplicant_set_key(void *wpa_s, wpa_alg alg,
+ const u8 *addr, int key_idx, int set_tx,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len,
+ key, key_len);
+}
+
+
+static int wpa_supplicant_add_pmkid(void *wpa_s,
+ const u8 *bssid, const u8 *pmkid)
+{
+ return wpa_drv_add_pmkid(wpa_s, bssid, pmkid);
+}
+
+
+static int wpa_supplicant_remove_pmkid(void *wpa_s,
+ const u8 *bssid, const u8 *pmkid)
+{
+ return wpa_drv_remove_pmkid(wpa_s, bssid, pmkid);
}
-#endif /* CONFIG_XSUPPLICANT_IFACE */
+#endif /* CONFIG_NO_WPA */
static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
@@ -2040,34 +1566,67 @@ static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
}
-static void wpa_supplicant_fd_workaround(void)
+void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len)
{
- int s, i;
- /* When started from pcmcia-cs scripts, wpa_supplicant might start with
- * fd 0, 1, and 2 closed. This will cause some issues because many
- * places in wpa_supplicant are still printing out to stdout. As a
- * workaround, make sure that fd's 0, 1, and 2 are not used for other
- * sockets. */
- for (i = 0; i < 3; i++) {
- s = open("/dev/null", O_RDWR);
- if (s > 2) {
- close(s);
- break;
- }
+ struct wpa_supplicant *wpa_s = ctx;
+
+ wpa_printf(MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
+ wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
+
+ if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
+ wpa_printf(MSG_DEBUG, "Ignored received EAPOL frame since "
+ "no key management is configured");
+ return;
+ }
+
+ if (wpa_s->eapol_received == 0) {
+ /* Timeout for completing IEEE 802.1X and WPA authentication */
+ wpa_supplicant_req_auth_timeout(
+ wpa_s,
+ (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
+ wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) ?
+ 70 : 10, 0);
+ }
+ wpa_s->eapol_received++;
+
+ if (wpa_s->countermeasures) {
+ wpa_printf(MSG_INFO, "WPA: Countermeasures - dropped EAPOL "
+ "packet");
+ return;
}
+
+ /* Source address of the incoming EAPOL frame could be compared to the
+ * current BSSID. However, it is possible that a centralized
+ * Authenticator could be using another MAC address than the BSSID of
+ * an AP, so just allow any address to be used for now. The replies are
+ * still sent to the current BSSID (if available), though. */
+
+ memcpy(wpa_s->last_eapol_src, src_addr, ETH_ALEN);
+ if (wpa_s->key_mgmt != WPA_KEY_MGMT_PSK &&
+ eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0)
+ return;
+ wpa_drv_poll(wpa_s);
+ wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
}
-static int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s,
- int wait_for_interface)
+int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s,
+ int wait_for_interface)
{
static int interface_count = 0;
for (;;) {
+ if (wpa_s->driver->send_eapol) {
+ const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
+ if (addr)
+ memcpy(wpa_s->own_addr, addr, ETH_ALEN);
+ break;
+ }
wpa_s->l2 = l2_packet_init(wpa_s->ifname,
wpa_drv_get_mac_addr(wpa_s),
ETH_P_EAPOL,
- wpa_supplicant_rx_eapol, wpa_s);
+ wpa_supplicant_rx_eapol, wpa_s, 0);
if (wpa_s->l2)
break;
else if (!wait_for_interface)
@@ -2076,7 +1635,7 @@ static int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s,
sleep(5);
}
- if (l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) {
+ if (wpa_s->l2 && l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) {
fprintf(stderr, "Failed to get own L2 address\n");
return -1;
}
@@ -2084,9 +1643,21 @@ static int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "Own MAC address: " MACSTR,
MAC2STR(wpa_s->own_addr));
+ /* 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) {
- fprintf(stderr, "Failed to enable WPA in the driver.\n");
- return -1;
+ 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 {
+ fprintf(stderr, "Failed to enable WPA in the "
+ "driver.\n");
+ return -1;
+ }
}
wpa_clear_keys(wpa_s, NULL);
@@ -2105,50 +1676,23 @@ static int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s,
}
-static void usage(void)
+static int wpa_supplicant_daemon(const char *pid_file)
{
- int i;
- printf("%s\n\n%s\n"
- "usage:\n"
- " wpa_supplicant [-BddehLqqvw] -i<ifname> -c<config file> "
- "[-D<driver>] \\\n"
- " [-P<pid file>] "
- "[-N -i<ifname> -c<conf> [-D<driver>] ...]\n"
- "\n"
- "drivers:\n",
- wpa_supplicant_version, wpa_supplicant_license);
-
- for (i = 0; wpa_supplicant_drivers[i]; i++) {
- printf(" %s = %s\n",
- wpa_supplicant_drivers[i]->name,
- wpa_supplicant_drivers[i]->desc);
+ wpa_printf(MSG_DEBUG, "Daemonize..");
+ if (daemon(0, 0)) {
+ perror("daemon");
+ return -1;
}
- printf("options:\n"
- " -B = run daemon in the background\n"
- " -d = increase debugging verbosity (-dd even more)\n"
- " -K = include keys (passwords, etc.) in debug output\n"
- " -t = include timestamp in debug messages\n"
-#ifdef CONFIG_XSUPPLICANT_IFACE
-#ifdef IEEE8021X_EAPOL
- " -e = use external IEEE 802.1X Supplicant (e.g., "
- "xsupplicant)\n"
- " (this disables the internal Supplicant)\n"
-#endif /* IEEE8021X_EAPOL */
-#endif /* CONFIG_XSUPPLICANT_IFACE */
- " -h = show this help text\n"
- " -L = show license (GPL and BSD)\n"
- " -q = decrease debugging verbosity (-qq even less)\n"
- " -v = show version\n"
- " -w = wait for interface to be added, if needed\n"
- " -N = start describing new interface\n");
-}
-
+ if (pid_file) {
+ FILE *f = fopen(pid_file, "w");
+ if (f) {
+ fprintf(f, "%u\n", getpid());
+ fclose(f);
+ }
+ }
-static void license(void)
-{
- printf("%s\n\n%s\n",
- wpa_supplicant_version, wpa_supplicant_full_license);
+ return 0;
}
@@ -2161,92 +1705,170 @@ static struct wpa_supplicant * wpa_supplicant_alloc(void)
return NULL;
memset(wpa_s, 0, sizeof(*wpa_s));
wpa_s->ctrl_sock = -1;
-#ifdef CONFIG_XSUPPLICANT_IFACE
- wpa_s->dot1x_s = -1;
-#endif /* CONFIG_XSUPPLICANT_IFACE */
+ wpa_s->scan_req = 1;
return wpa_s;
}
-static int wpa_supplicant_init(struct wpa_supplicant *wpa_s,
- const char *confname, const char *driver,
- const char *ifname)
+static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
+ struct wpa_interface *iface)
{
wpa_printf(MSG_DEBUG, "Initializing interface '%s' conf '%s' driver "
- "'%s'", ifname, confname, driver ? driver : "default");
+ "'%s' ctrl_interface '%s'", iface->ifname,
+ iface->confname ? iface->confname : "N/A",
+ iface->driver ? iface->driver : "default",
+ iface->ctrl_interface ? iface->ctrl_interface : "N/A");
- if (wpa_supplicant_set_driver(wpa_s, driver) < 0) {
+ if (wpa_supplicant_set_driver(wpa_s, iface->driver) < 0) {
return -1;
}
- if (confname) {
- wpa_s->confname = rel2abs_path(confname);
+ if (iface->confname) {
+#ifdef CONFIG_BACKEND_FILE
+ wpa_s->confname = rel2abs_path(iface->confname);
if (wpa_s->confname == NULL) {
wpa_printf(MSG_ERROR, "Failed to get absolute path "
- "for configuration file '%s'.", confname);
+ "for configuration file '%s'.",
+ iface->confname);
return -1;
}
wpa_printf(MSG_DEBUG, "Configuration file '%s' -> '%s'",
- confname, wpa_s->confname);
+ iface->confname, wpa_s->confname);
+#else /* CONFIG_BACKEND_FILE */
+ wpa_s->confname = strdup(iface->confname);
+#endif /* CONFIG_BACKEND_FILE */
wpa_s->conf = wpa_config_read(wpa_s->confname);
if (wpa_s->conf == NULL) {
- printf("Failed to read configuration file '%s'.\n",
- wpa_s->confname);
+ printf("Failed to read read or parse configuration "
+ "'%s'.\n", wpa_s->confname);
return -1;
}
- }
- if (wpa_s->conf == NULL || wpa_s->conf->ssid == NULL) {
- usage();
- printf("\nNo networks (SSID) configured.\n");
+ /*
+ * Override ctrl_interface and driver_param if set on command
+ * line.
+ */
+ if (iface->ctrl_interface) {
+ free(wpa_s->conf->ctrl_interface);
+ wpa_s->conf->ctrl_interface =
+ strdup(iface->ctrl_interface);
+ }
+
+ if (iface->driver_param) {
+ free(wpa_s->conf->driver_param);
+ wpa_s->conf->driver_param =
+ strdup(iface->driver_param);
+ }
+ } else
+ wpa_s->conf = wpa_config_alloc_empty(iface->ctrl_interface,
+ iface->driver_param);
+
+ if (wpa_s->conf == NULL) {
+ printf("\nNo configuration found.\n");
return -1;
}
- if (ifname == NULL) {
- usage();
+ if (iface->ifname == NULL) {
printf("\nInterface name is required.\n");
return -1;
}
- if (strlen(ifname) >= sizeof(wpa_s->ifname)) {
- printf("Too long interface name '%s'.\n", ifname);
+ if (strlen(iface->ifname) >= sizeof(wpa_s->ifname)) {
+ printf("Too long interface name '%s'.\n", iface->ifname);
+ return -1;
+ }
+ strncpy(wpa_s->ifname, iface->ifname, sizeof(wpa_s->ifname));
+
+ return 0;
+}
+
+
+static int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
+{
+#ifdef IEEE8021X_EAPOL
+ struct eapol_ctx *ctx;
+ ctx = malloc(sizeof(*ctx));
+ if (ctx == NULL) {
+ printf("Failed to allocate EAPOL context.\n");
+ return -1;
+ }
+
+ memset(ctx, 0, sizeof(*ctx));
+ ctx->ctx = wpa_s;
+ ctx->msg_ctx = wpa_s;
+ ctx->eapol_send_ctx = wpa_s;
+ ctx->preauth = 0;
+ ctx->eapol_done_cb = wpa_supplicant_notify_eapol_done;
+ ctx->eapol_send = wpa_supplicant_eapol_send;
+ ctx->set_wep_key = wpa_eapol_set_wep_key;
+ ctx->set_config_blob = wpa_supplicant_set_config_blob;
+ ctx->get_config_blob = wpa_supplicant_get_config_blob;
+ ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
+ ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
+ ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
+ wpa_s->eapol = eapol_sm_init(ctx);
+ if (wpa_s->eapol == NULL) {
+ free(ctx);
+ printf("Failed to initialize EAPOL state machines.\n");
+ return -1;
+ }
+#endif /* IEEE8021X_EAPOL */
+
+ return 0;
+}
+
+
+static int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
+{
+#ifndef CONFIG_NO_WPA
+ struct wpa_sm_ctx *ctx;
+ ctx = malloc(sizeof(*ctx));
+ if (ctx == NULL) {
+ printf("Failed to allocate WPA context.\n");
+ return -1;
+ }
+
+ memset(ctx, 0, sizeof(*ctx));
+ ctx->ctx = wpa_s;
+ ctx->set_state = _wpa_supplicant_set_state;
+ ctx->get_state = _wpa_supplicant_get_state;
+ ctx->req_scan = _wpa_supplicant_req_scan;
+ ctx->deauthenticate = _wpa_supplicant_deauthenticate;
+ ctx->disassociate = _wpa_supplicant_disassociate;
+ ctx->set_key = wpa_supplicant_set_key;
+ ctx->scan = wpa_supplicant_scan;
+ ctx->get_ssid = _wpa_supplicant_get_ssid;
+ ctx->get_bssid = wpa_supplicant_get_bssid;
+ ctx->ether_send = _wpa_ether_send;
+ ctx->get_beacon_ie = wpa_supplicant_get_beacon_ie;
+ ctx->alloc_eapol = _wpa_alloc_eapol;
+ ctx->cancel_auth_timeout = _wpa_supplicant_cancel_auth_timeout;
+ ctx->add_pmkid = wpa_supplicant_add_pmkid;
+ ctx->remove_pmkid = wpa_supplicant_remove_pmkid;
+ ctx->set_config_blob = wpa_supplicant_set_config_blob;
+ ctx->get_config_blob = wpa_supplicant_get_config_blob;
+
+ wpa_s->wpa = wpa_sm_init(ctx);
+ if (wpa_s->wpa == NULL) {
+ fprintf(stderr, "Failed to initialize WPA state machine\n");
return -1;
}
- strncpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
+#endif /* CONFIG_NO_WPA */
return 0;
}
-static int wpa_supplicant_init2(struct wpa_supplicant *wpa_s,
- int disable_eapol, int wait_for_interface)
+static int wpa_supplicant_init_iface2(struct wpa_supplicant *wpa_s,
+ int wait_for_interface)
{
const char *ifname;
wpa_printf(MSG_DEBUG, "Initializing interface (2) '%s'",
wpa_s->ifname);
- if (!disable_eapol) {
- struct eapol_ctx *ctx;
- ctx = malloc(sizeof(*ctx));
- if (ctx == NULL) {
- printf("Failed to allocate EAPOL context.\n");
- return -1;
- }
- memset(ctx, 0, sizeof(*ctx));
- ctx->ctx = wpa_s;
- ctx->msg_ctx = wpa_s;
- ctx->preauth = 0;
- ctx->eapol_done_cb = wpa_supplicant_notify_eapol_done;
- ctx->eapol_send = wpa_eapol_send;
- ctx->set_wep_key = wpa_eapol_set_wep_key;
- wpa_s->eapol = eapol_sm_init(ctx);
- if (wpa_s->eapol == NULL) {
- free(ctx);
- printf("Failed to initialize EAPOL state machines.\n");
- return -1;
- }
- }
+ if (wpa_supplicant_init_eapol(wpa_s) < 0)
+ return -1;
/* RSNA Supplicant Key Management - INITIALIZE */
eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
@@ -2261,6 +1883,11 @@ static int wpa_supplicant_init2(struct wpa_supplicant *wpa_s,
fprintf(stderr, "Failed to initialize driver interface\n");
return -1;
}
+ if (wpa_drv_set_param(wpa_s, wpa_s->conf->driver_param) < 0) {
+ fprintf(stderr, "Driver interface rejected driver_param "
+ "'%s'\n", wpa_s->conf->driver_param);
+ return -1;
+ }
ifname = wpa_drv_get_ifname(wpa_s);
if (ifname && strcmp(ifname, wpa_s->ifname) != 0) {
@@ -2269,10 +1896,41 @@ static int wpa_supplicant_init2(struct wpa_supplicant *wpa_s,
strncpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
}
- wpa_s->renew_snonce = 1;
+ if (wpa_supplicant_init_wpa(wpa_s) < 0)
+ return -1;
+
+ wpa_sm_set_ifname(wpa_s->wpa, wpa_s->ifname);
+ wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
+ wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
+
+ if (wpa_s->conf->dot11RSNAConfigPMKLifetime &&
+ wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
+ wpa_s->conf->dot11RSNAConfigPMKLifetime)) {
+ fprintf(stderr, "Invalid WPA parameter value for "
+ "dot11RSNAConfigPMKLifetime\n");
+ return -1;
+ }
+
+ if (wpa_s->conf->dot11RSNAConfigPMKReauthThreshold &&
+ wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
+ wpa_s->conf->dot11RSNAConfigPMKReauthThreshold)) {
+ fprintf(stderr, "Invalid WPA parameter value for "
+ "dot11RSNAConfigPMKReauthThreshold\n");
+ return -1;
+ }
+
+ if (wpa_s->conf->dot11RSNAConfigSATimeout &&
+ wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT,
+ wpa_s->conf->dot11RSNAConfigSATimeout)) {
+ fprintf(stderr, "Invalid WPA parameter value for "
+ "dot11RSNAConfigSATimeout\n");
+ return -1;
+ }
+
if (wpa_supplicant_driver_init(wpa_s, wait_for_interface) < 0) {
return -1;
}
+ wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
if (wpa_supplicant_ctrl_iface_init(wpa_s)) {
printf("Failed to initialize control interface '%s'.\n"
@@ -2286,18 +1944,18 @@ static int wpa_supplicant_init2(struct wpa_supplicant *wpa_s,
return -1;
}
-#ifdef CONFIG_XSUPPLICANT_IFACE
- if (disable_eapol)
- wpa_supplicant_802_1x_init(wpa_s);
-#endif /* CONFIG_XSUPPLICANT_IFACE */
-
return 0;
}
-static void wpa_supplicant_deinit(struct wpa_supplicant *wpa_s)
+static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s)
{
if (wpa_s->drv_priv) {
+ wpa_supplicant_deauthenticate(wpa_s, 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) {
fprintf(stderr, "Failed to disable WPA in the "
"driver.\n");
@@ -2313,137 +1971,176 @@ static void wpa_supplicant_deinit(struct wpa_supplicant *wpa_s)
}
-int main(int argc, char *argv[])
+/**
+ * wpa_supplicant_add_iface - Add a new network interface
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * @iface: Interface configuration options
+ * Returns: Pointer to the created interface or %NULL on failure
+ *
+ * This function is used to add new network interfaces for %wpa_supplicant.
+ * This can be called before wpa_supplicant_run() to add interfaces before the
+ * main event loop has been started. In addition, new interfaces can be added
+ * dynamically while %wpa_supplicant is already running. This could happen,
+ * e.g., when a hotplug network adapter is inserted.
+ */
+struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
+ struct wpa_interface *iface)
{
- struct wpa_supplicant *head, *wpa_s;
- int c;
- const char *confname, *driver, *ifname;
- char *pid_file = NULL;
- int daemonize = 0, wait_for_interface = 0, disable_eapol = 0, exitcode;
+ struct wpa_supplicant *wpa_s;
-#ifdef CONFIG_NATIVE_WINDOWS
- WSADATA wsaData;
- if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
- printf("Could not find a usable WinSock.dll\n");
- return -1;
- }
-#endif /* CONFIG_NATIVE_WINDOWS */
+ if (global == NULL || iface == NULL)
+ return NULL;
- head = wpa_s = wpa_supplicant_alloc();
+ wpa_s = wpa_supplicant_alloc();
if (wpa_s == NULL)
- return -1;
- wpa_s->head = head;
+ return NULL;
- wpa_supplicant_fd_workaround();
- eloop_init(head);
+ if (wpa_supplicant_init_iface(wpa_s, iface) ||
+ wpa_supplicant_init_iface2(wpa_s,
+ global->params.wait_for_interface)) {
+ wpa_printf(MSG_DEBUG, "Failed to add interface %s",
+ iface->ifname);
+ wpa_supplicant_deinit_iface(wpa_s);
+ free(wpa_s);
+ return NULL;
+ }
- ifname = confname = driver = NULL;
+ wpa_s->global = global;
+ wpa_s->next = global->ifaces;
+ global->ifaces = wpa_s;
- for (;;) {
- c = getopt(argc, argv, "Bc:D:dehi:KLNP:qtvw");
- if (c < 0)
- break;
- switch (c) {
- case 'B':
- daemonize++;
- break;
- case 'c':
- confname = optarg;
- break;
- case 'D':
- driver = optarg;
- break;
- case 'd':
- wpa_debug_level--;
- break;
-#ifdef CONFIG_XSUPPLICANT_IFACE
-#ifdef IEEE8021X_EAPOL
- case 'e':
- disable_eapol++;
- break;
-#endif /* IEEE8021X_EAPOL */
-#endif /* CONFIG_XSUPPLICANT_IFACE */
- case 'h':
- usage();
- return -1;
- case 'i':
- ifname = optarg;
- break;
- case 'K':
- wpa_debug_show_keys++;
- break;
- case 'L':
- license();
- return -1;
- case 'P':
- pid_file = rel2abs_path(optarg);
- break;
- case 'q':
- wpa_debug_level++;
- break;
- case 't':
- wpa_debug_timestamp++;
- break;
- case 'v':
- printf("%s\n", wpa_supplicant_version);
- return -1;
- case 'w':
- wait_for_interface++;
- break;
- case 'N':
- if (wpa_supplicant_init(wpa_s, confname, driver,
- ifname))
- return -1;
- wpa_s->next = wpa_supplicant_alloc();
- wpa_s = wpa_s->next;
- if (wpa_s == NULL)
- return -1;
- wpa_s->head = head;
- ifname = confname = driver = NULL;
- break;
- default:
- usage();
+ wpa_printf(MSG_DEBUG, "Added interface %s", wpa_s->ifname);
+
+ return wpa_s;
+}
+
+
+/**
+ * wpa_supplicant_remove_iface - Remove a network interface
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * @wpa_s: Pointer to the network interface to be removed
+ * Returns: 0 if interface was removed, -1 if interface was not found
+ *
+ * This function can be used to dynamically remove network interfaces from
+ * %wpa_supplicant, e.g., when a hotplug network adapter is ejected. In
+ * addition, this function is used to remove all remaining interdaces when
+ * %wpa_supplicant is terminated.
+ */
+int wpa_supplicant_remove_iface(struct wpa_global *global,
+ struct wpa_supplicant *wpa_s)
+{
+ struct wpa_supplicant *prev;
+
+ /* Remove interface from the global list of interfaces */
+ prev = global->ifaces;
+ if (prev == wpa_s) {
+ global->ifaces = wpa_s->next;
+ } else {
+ while (prev && prev->next != wpa_s)
+ prev = prev->next;
+ if (prev == NULL)
return -1;
- }
+ prev->next = wpa_s->next;
}
- if (wpa_supplicant_init(wpa_s, confname, driver, ifname))
- return -1;
+ wpa_printf(MSG_DEBUG, "Removing interface %s", wpa_s->ifname);
- exitcode = 0;
+ wpa_supplicant_deinit_iface(wpa_s);
+ free(wpa_s);
- if (wait_for_interface && daemonize) {
- wpa_printf(MSG_DEBUG, "Daemonize..");
- if (daemon(0, 0)) {
- perror("daemon");
- exitcode = -1;
- goto cleanup;
- }
+ return 0;
+}
+
+
+/**
+ * wpa_supplicant_get_iface - Get a new network interface
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * @ifname: Interface name
+ * Returns: Pointer to the interface or %NULL if not found
+ */
+struct wpa_supplicant * wpa_supplicant_get_iface(struct wpa_global *global,
+ const char *ifname)
+{
+ struct wpa_supplicant *wpa_s;
+
+ for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ if (strcmp(wpa_s->ifname, ifname) == 0)
+ return wpa_s;
}
+ return NULL;
+}
- for (wpa_s = head; wpa_s; wpa_s = wpa_s->next) {
- if (wpa_supplicant_init2(wpa_s, disable_eapol,
- wait_for_interface)) {
- exitcode = -1;
- goto cleanup;
- }
+
+/**
+ * wpa_supplicant_init - Initialize %wpa_supplicant
+ * @params: Parameters for %wpa_supplicant
+ * Returns: Pointer to global %wpa_supplicant data, or %NULL on failure
+ *
+ * This function is used to initialize %wpa_supplicant. After successful
+ * initialization, the returned data pointer can be used to add and remove
+ * network interfaces, and eventually, to deinitialize %wpa_supplicant.
+ */
+struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
+{
+ struct wpa_global *global;
+
+ if (params == NULL)
+ return NULL;
+ global = malloc(sizeof(*global));
+ if (global == NULL)
+ return NULL;
+ memset(global, 0, sizeof(*global));
+ global->params.daemonize = params->daemonize;
+ global->params.wait_for_interface = params->wait_for_interface;
+ global->params.wait_for_monitor = params->wait_for_monitor;
+ if (params->pid_file)
+ global->params.pid_file = strdup(params->pid_file);
+ if (params->ctrl_interface)
+ global->params.ctrl_interface = strdup(params->ctrl_interface);
+ wpa_debug_level = global->params.wpa_debug_level =
+ params->wpa_debug_level;
+ wpa_debug_show_keys = global->params.wpa_debug_show_keys =
+ params->wpa_debug_show_keys;
+ wpa_debug_timestamp = global->params.wpa_debug_timestamp =
+ params->wpa_debug_timestamp;
+
+ eloop_init(global);
+
+ if (wpa_supplicant_global_ctrl_iface_init(global)) {
+ eloop_destroy();
+ return NULL;
}
- if (!wait_for_interface && daemonize) {
- wpa_printf(MSG_DEBUG, "Daemonize..");
- if (daemon(0, 0)) {
- perror("daemon");
- exitcode = -1;
- goto cleanup;
- }
+ if (global->params.wait_for_interface && global->params.daemonize &&
+ wpa_supplicant_daemon(global->params.pid_file)) {
+ eloop_destroy();
+ return NULL;
}
- if (pid_file) {
- FILE *f = fopen(pid_file, "w");
- if (f) {
- fprintf(f, "%u\n", getpid());
- fclose(f);
- }
+ return global;
+}
+
+
+/**
+ * wpa_supplicant_run - Run the %wpa_supplicant main event loop
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * Returns: 0 after successful event loop run, -1 on failure
+ *
+ * This function starts the main event loop and continues running as long as
+ * there are any remaining events. In most cases, this function is running as
+ * long as the %wpa_supplicant process in still in use.
+ */
+int wpa_supplicant_run(struct wpa_global *global)
+{
+ struct wpa_supplicant *wpa_s;
+
+ if (!global->params.wait_for_interface && global->params.daemonize &&
+ wpa_supplicant_daemon(global->params.pid_file))
+ return -1;
+
+ if (global->params.wait_for_monitor) {
+ for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
+ wpa_supplicant_ctrl_iface_wait(wpa_s);
}
eloop_register_signal(SIGINT, wpa_supplicant_terminate, NULL);
@@ -2454,30 +2151,34 @@ int main(int argc, char *argv[])
eloop_run();
- for (wpa_s = head; wpa_s; wpa_s = wpa_s->next) {
- wpa_supplicant_deauthenticate(wpa_s, REASON_DEAUTH_LEAVING);
- }
+ return 0;
+}
-cleanup:
- wpa_s = head;
- while (wpa_s) {
- struct wpa_supplicant *prev;
- wpa_supplicant_deinit(wpa_s);
- prev = wpa_s;
- wpa_s = wpa_s->next;
- free(prev);
- }
+
+/**
+ * wpa_supplicant_deinit - Deinitialize %wpa_supplicant
+ * @global: Pointer to global data from wpa_supplicant_init()
+ *
+ * This function is called to deinitialize %wpa_supplicant and to free all
+ * allocated resources. Remaining network interfaces will also be removed.
+ */
+void wpa_supplicant_deinit(struct wpa_global *global)
+{
+ if (global == NULL)
+ return;
+
+ while (global->ifaces)
+ wpa_supplicant_remove_iface(global, global->ifaces);
+
+ wpa_supplicant_global_ctrl_iface_deinit(global);
eloop_destroy();
- if (pid_file) {
- unlink(pid_file);
- free(pid_file);
+ if (global->params.pid_file) {
+ unlink(global->params.pid_file);
+ free(global->params.pid_file);
}
+ free(global->params.ctrl_interface);
-#ifdef CONFIG_NATIVE_WINDOWS
- WSACleanup();
-#endif /* CONFIG_NATIVE_WINDOWS */
-
- return exitcode;
+ free(global);
}
OpenPOWER on IntegriCloud