diff options
Diffstat (limited to 'contrib/wpa_supplicant/wpa_supplicant.c')
-rw-r--r-- | contrib/wpa_supplicant/wpa_supplicant.c | 2021 |
1 files changed, 855 insertions, 1166 deletions
diff --git a/contrib/wpa_supplicant/wpa_supplicant.c b/contrib/wpa_supplicant/wpa_supplicant.c index a1524ab..2b2d6e0 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 @@ -19,27 +19,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" @@ -48,12 +37,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" @@ -65,7 +56,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" @@ -109,25 +101,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, ...) { @@ -154,13 +136,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 @@ -177,7 +215,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 " @@ -207,64 +246,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; } @@ -281,15 +268,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 */ @@ -297,7 +302,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); @@ -353,17 +357,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; @@ -378,7 +389,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; @@ -406,7 +417,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; @@ -430,7 +441,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; @@ -485,6 +496,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); @@ -494,6 +506,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); @@ -509,7 +525,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; @@ -535,15 +551,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; @@ -551,15 +574,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; @@ -575,40 +592,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); } @@ -616,50 +605,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"; @@ -688,353 +668,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; } -static int any_interfaces(struct wpa_supplicant *head) -{ - struct wpa_supplicant *wpa_s; - - for (wpa_s = head; wpa_s != NULL; wpa_s = wpa_s->next) - if (!wpa_s->interface_removed) - return 1; - return 0; -} -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; - /* check if last interface */ - if (!any_interfaces(wpa_s->head)) - eloop_terminate(); - 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(); } @@ -1062,8 +754,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) @@ -1079,9 +778,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(); } @@ -1099,6 +799,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)); @@ -1106,26 +809,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) { @@ -1138,11 +855,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) { @@ -1198,14 +934,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; } @@ -1234,33 +970,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; @@ -1271,42 +1010,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; - - 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; - } + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto); - 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) { @@ -1358,61 +1072,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'", @@ -1422,9 +1119,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) { @@ -1450,12 +1145,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 " @@ -1465,6 +1162,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 " @@ -1518,7 +1216,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(¶ms, 0, sizeof(params)); if (bss) { params.bssid = bss->bssid; @@ -1541,6 +1239,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) { @@ -1550,9 +1249,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 && @@ -1570,6 +1277,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); } @@ -1578,13 +1286,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); @@ -1595,211 +1304,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; @@ -1839,57 +1358,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; @@ -1908,33 +1377,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; } @@ -1943,8 +1390,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; } @@ -1957,69 +1405,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; +} + + +#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) +{ + return wpa_alloc_eapol(wpa_s, type, data, data_len, msg_len, data_pos); } -static int wpa_supplicant_802_1x_init(struct wpa_supplicant *wpa_s) +static int _wpa_ether_send(void *wpa_s, const u8 *dest, u16 proto, + const u8 *buf, size_t len) { - int s; - struct sockaddr_un addr; + return wpa_ether_send(wpa_s, dest, proto, buf, len); +} - 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 void _wpa_supplicant_req_scan(void *wpa_s, int sec, int usec) +{ + wpa_supplicant_req_scan(wpa_s, sec, usec); +} - wpa_s->dot1x_s = s; - eloop_register_read_sock(s, wpa_supplicant_dot1x_receive, wpa_s, - NULL); - return 0; + +static void _wpa_supplicant_cancel_auth_timeout(void *wpa_s) +{ + wpa_supplicant_cancel_auth_timeout(wpa_s); } -#endif /* CONFIG_XSUPPLICANT_IFACE */ + + +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_NO_WPA */ static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s, @@ -2054,34 +1568,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) @@ -2090,7 +1637,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; } @@ -2098,9 +1645,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); @@ -2119,50 +1678,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; } @@ -2175,92 +1707,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; } - strncpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname)); +#endif /* IEEE8021X_EAPOL */ return 0; } -static int wpa_supplicant_init2(struct wpa_supplicant *wpa_s, - int disable_eapol, int wait_for_interface) +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; + } +#endif /* CONFIG_NO_WPA */ + + return 0; +} + + +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); @@ -2275,6 +1885,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) { @@ -2283,10 +1898,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" @@ -2300,18 +1946,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"); @@ -2327,137 +1973,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); @@ -2468,30 +2153,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); } |