diff options
Diffstat (limited to 'contrib/wpa_supplicant/wpa_supplicant.c')
-rw-r--r-- | contrib/wpa_supplicant/wpa_supplicant.c | 2483 |
1 files changed, 0 insertions, 2483 deletions
diff --git a/contrib/wpa_supplicant/wpa_supplicant.c b/contrib/wpa_supplicant/wpa_supplicant.c deleted file mode 100644 index 0c57143f826e..000000000000 --- a/contrib/wpa_supplicant/wpa_supplicant.c +++ /dev/null @@ -1,2483 +0,0 @@ -/* - * WPA Supplicant - * Copyright (c) 2003-2005, 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 - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. - */ - -#include <stdlib.h> -#include <stdio.h> -#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" -#include "l2_packet.h" -#include "wpa_supplicant_i.h" -#include "ctrl_iface.h" -#include "pcsc_funcs.h" -#include "version.h" - -static const char *wpa_supplicant_version = -"wpa_supplicant v" VERSION_STR "\n" -"Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi> and contributors"; - -static const char *wpa_supplicant_license = -"This program is free software. You can distribute it and/or modify it\n" -"under the terms of the GNU General Public License version 2.\n" -"\n" -"Alternatively, this software may be distributed under the terms of the\n" -"BSD license. See README and COPYING for more details.\n" -#ifdef EAP_TLS_FUNCS -"\nThis product includes software developed by the OpenSSL Project\n" -"for use in the OpenSSL Toolkit (http://www.openssl.org/)\n" -#endif /* EAP_TLS_FUNCS */ -; - -static 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" -"\n" -"This program is distributed in the hope that it will be useful,\n" -"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" -"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" -"GNU General Public License for more details.\n" -"\n" -"You should have received a copy of the GNU General Public License\n" -"along with this program; if not, write to the Free Software\n" -"Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n" -"\n" -"Alternatively, this software may be distributed under the terms of the\n" -"BSD license.\n" -"\n" -"Redistribution and use in source and binary forms, with or without\n" -"modification, are permitted provided that the following conditions are\n" -"met:\n" -"\n" -"1. Redistributions of source code must retain the above copyright\n" -" notice, this list of conditions and the following disclaimer.\n" -"\n" -"2. Redistributions in binary form must reproduce the above copyright\n" -" notice, this list of conditions and the following disclaimer in the\n" -" documentation and/or other materials provided with the distribution.\n" -"\n" -"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n" -" names of its contributors may be used to endorse or promote products\n" -" derived from this software without specific prior written permission.\n" -"\n" -"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n" -"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n" -"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n" -"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n" -"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n" -"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n" -"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n" -"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n" -"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n" -"(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"; - -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; - - -void wpa_msg(struct wpa_supplicant *wpa_s, int level, char *fmt, ...) -{ - va_list ap; - char *buf; - const int buflen = 2048; - int len; - - buf = malloc(buflen); - if (buf == NULL) { - printf("Failed to allocate message buffer for:\n"); - va_start(ap, fmt); - vprintf(fmt, ap); - printf("\n"); - va_end(ap); - return; - } - va_start(ap, fmt); - len = vsnprintf(buf, buflen, fmt, ap); - va_end(ap); - wpa_printf(level, "%s", buf); - wpa_supplicant_ctrl_iface_send(wpa_s, level, buf, len); - free(buf); -} - - -int wpa_eapol_send(void *ctx, int type, 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 - * extra copy here */ - - if (wpa_s->key_mgmt == WPA_KEY_MGMT_PSK || - wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) { - /* Current SSID is not using IEEE 802.1X/EAP, so drop possible - * EAPOL frames (mainly, EAPOL-Start) from EAPOL state - * machines. */ - wpa_printf(MSG_DEBUG, "WPA: drop TX EAPOL in non-IEEE 802.1X " - "mode (type=%d len=%lu)", type, - (unsigned long) len); - return -1; - } - - if (wpa_s->cur_pmksa && 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 " - "EAPOL-Start"); - return -1; - } - - if (memcmp(wpa_s->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0) { - wpa_printf(MSG_DEBUG, "BSSID not set when trying to send an " - "EAPOL frame"); - if (wpa_drv_get_bssid(wpa_s, bssid) == 0 && - memcmp(bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) != 0) { - dst = bssid; - wpa_printf(MSG_DEBUG, "Using current BSSID " MACSTR - " from the driver as the EAPOL destination", - MAC2STR(dst)); - } else { - dst = wpa_s->last_eapol_src; - wpa_printf(MSG_DEBUG, "Using the source address of the" - " last received EAPOL frame " MACSTR " as " - "the EAPOL destination", - MAC2STR(dst)); - } - } else { - /* BSSID was already set (from (Re)Assoc event, so use it as - * the EAPOL destination. */ - dst = wpa_s->bssid; - } - - msglen = sizeof(*ethhdr) + sizeof(*hdr) + len; - msg = malloc(msglen); - 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); - free(msg); - return res; -} - - -/** - * wpa_eapol_set_wep_key - set WEP key for the driver - * @ctx: pointer to wpa_supplicant data - * @unicast: 1 = individual unicast key, 0 = broadcast key - * @keyidx: WEP key index (0..3) - * @key: pointer to key data - * @keylen: key length in bytes - * - * 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) -{ - 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); -} - - -/* Configure default/group WEP key for static WEP */ -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); -} - - -static int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s, - struct wpa_ssid *ssid) -{ - u8 key[32]; - size_t keylen; - wpa_alg alg; - u8 seq[6] = { 0 }; - - /* IBSS/WPA-None uses only one key (Group) for both receiving and - * sending unicast and multicast packets. */ - - if (ssid->mode != IEEE80211_MODE_IBSS) { - wpa_printf(MSG_INFO, "WPA: Invalid mode %d (not IBSS/ad-hoc) " - "for WPA-None", ssid->mode); - return -1; - } - - if (!ssid->psk_set) { - wpa_printf(MSG_INFO, "WPA: No PSK configured for WPA-None"); - return -1; - } - - switch (wpa_s->group_cipher) { - case WPA_CIPHER_CCMP: - memcpy(key, ssid->psk, 16); - keylen = 16; - alg = WPA_ALG_CCMP; - break; - case WPA_CIPHER_TKIP: - /* WPA-None uses the same Michael MIC key for both TX and RX */ - memcpy(key, ssid->psk, 16 + 8); - memcpy(key + 16 + 8, ssid->psk + 16, 8); - keylen = 32; - alg = WPA_ALG_TKIP; - break; - default: - wpa_printf(MSG_INFO, "WPA: Invalid group cipher %d for " - "WPA-None", wpa_s->group_cipher); - return -1; - } - - /* TODO: should actually remember the previously used seq#, both for TX - * and RX from each STA.. */ - - return wpa_drv_set_key(wpa_s, alg, (u8 *) "\xff\xff\xff\xff\xff\xff", - 0, 1, seq, 6, key, keylen); -} - - -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); -} - - -static struct wpa_blacklist * -wpa_blacklist_get(struct wpa_supplicant *wpa_s, const u8 *bssid) -{ - struct wpa_blacklist *e; - - e = wpa_s->blacklist; - while (e) { - if (memcmp(e->bssid, bssid, ETH_ALEN) == 0) - return e; - e = e->next; - } - - return NULL; -} - - -static int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid) -{ - struct wpa_blacklist *e; - - e = wpa_blacklist_get(wpa_s, bssid); - if (e) { - e->count++; - wpa_printf(MSG_DEBUG, "BSSID " MACSTR " blacklist count " - "incremented to %d", - MAC2STR(bssid), e->count); - return 0; - } - - e = malloc(sizeof(*e)); - if (e == NULL) - return -1; - memset(e, 0, sizeof(*e)); - memcpy(e->bssid, bssid, ETH_ALEN); - e->count = 1; - e->next = wpa_s->blacklist; - wpa_s->blacklist = e; - wpa_printf(MSG_DEBUG, "Added BSSID " MACSTR " into blacklist", - MAC2STR(bssid)); - - return 0; -} - - -static int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid) -{ - struct wpa_blacklist *e, *prev = NULL; - - e = wpa_s->blacklist; - while (e) { - if (memcmp(e->bssid, bssid, ETH_ALEN) == 0) { - if (prev == NULL) { - wpa_s->blacklist = e->next; - } else { - prev->next = e->next; - } - wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR " from " - "blacklist", MAC2STR(bssid)); - free(e); - return 0; - } - prev = e; - e = e->next; - } - return -1; -} - - -static void wpa_blacklist_clear(struct wpa_supplicant *wpa_s) -{ - struct wpa_blacklist *e, *prev; - - e = wpa_s->blacklist; - wpa_s->blacklist = NULL; - while (e) { - prev = e; - e = e->next; - wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR " from " - "blacklist (clear)", MAC2STR(prev->bssid)); - free(prev); - } -} - - -const char * wpa_ssid_txt(u8 *ssid, size_t ssid_len) -{ - static char ssid_txt[MAX_SSID_LEN + 1]; - char *pos; - - if (ssid_len > MAX_SSID_LEN) - ssid_len = MAX_SSID_LEN; - memcpy(ssid_txt, ssid, ssid_len); - ssid_txt[ssid_len] = '\0'; - for (pos = ssid_txt; *pos != '\0'; pos++) { - if ((u8) *pos < 32 || (u8) *pos >= 127) - *pos = '_'; - } - return ssid_txt; -} - - -void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec) -{ - wpa_msg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec", - sec, usec); - eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); - eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL); -} - - -void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s) -{ - wpa_msg(wpa_s, MSG_DEBUG, "Cancelling scan request"); - eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL); -} - - -static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx) -{ - struct wpa_supplicant *wpa_s = eloop_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_supplicant_disassociate(wpa_s, REASON_DEAUTH_LEAVING); - wpa_s->reassociate = 1; - wpa_supplicant_req_scan(wpa_s, 0, 0); -} - - -void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s, - int sec, int usec) -{ - wpa_msg(wpa_s, MSG_DEBUG, "Setting authentication timeout: %d sec " - "%d usec", sec, usec); - eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL); - eloop_register_timeout(sec, usec, wpa_supplicant_timeout, wpa_s, NULL); -} - - -void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s) -{ - wpa_msg(wpa_s, MSG_DEBUG, "Cancelling authentication timeout"); - eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL); - wpa_blacklist_del(wpa_s, wpa_s->bssid); -} - - -static void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s) -{ - struct eapol_config eapol_conf; - struct wpa_ssid *ssid = wpa_s->current_ssid; - - if (wpa_s->key_mgmt == WPA_KEY_MGMT_PSK) { - eapol_sm_notify_eap_success(wpa_s->eapol, FALSE); - eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE); - } - if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE || - wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) - eapol_sm_notify_portControl(wpa_s->eapol, ForceAuthorized); - else - eapol_sm_notify_portControl(wpa_s->eapol, Auto); - - memset(&eapol_conf, 0, sizeof(eapol_conf)); - if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { - eapol_conf.accept_802_1x_keys = 1; - eapol_conf.required_keys = 0; - if (ssid->eapol_flags & EAPOL_FLAG_REQUIRE_KEY_UNICAST) { - eapol_conf.required_keys |= EAPOL_REQUIRE_KEY_UNICAST; - } - if (ssid->eapol_flags & EAPOL_FLAG_REQUIRE_KEY_BROADCAST) { - eapol_conf.required_keys |= - EAPOL_REQUIRE_KEY_BROADCAST; - } - } - eapol_conf.fast_reauth = wpa_s->conf->fast_reauth; - eapol_conf.workaround = ssid->eap_workaround; - 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) -{ - int i; - - if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) - 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_s->pairwise_cipher = WPA_CIPHER_NONE; - wpa_s->group_cipher = WPA_CIPHER_NONE; - - for (i = 0; i < NUM_WEP_KEYS; i++) { - if (ssid->wep_key_len[i] > 5) { - wpa_s->pairwise_cipher = WPA_CIPHER_WEP104; - wpa_s->group_cipher = WPA_CIPHER_WEP104; - break; - } else if (ssid->wep_key_len[i] > 0) { - wpa_s->pairwise_cipher = WPA_CIPHER_WEP40; - wpa_s->group_cipher = WPA_CIPHER_WEP40; - break; - } - } - - 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); - - return 0; -} - - -static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) -{ - scard_deinit(wpa_s->scard); - wpa_s->scard = 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; - - eapol_sm_deinit(wpa_s->eapol); - wpa_s->eapol = NULL; - - rsn_preauth_deinit(wpa_s); - - pmksa_candidate_free(wpa_s); - pmksa_cache_free(wpa_s); - wpa_blacklist_clear(wpa_s); - - free(wpa_s->scan_results); - wpa_s->scan_results = NULL; - wpa_s->num_scan_results = 0; -} - - -static void wpa_clear_keys(struct wpa_supplicant *wpa_s, u8 *addr) -{ - u8 *bcast = (u8 *) "\xff\xff\xff\xff\xff\xff"; - - if (wpa_s->keys_cleared) { - /* Some drivers (e.g., ndiswrapper & NDIS drivers) seem to have - * timing issues with keys being cleared just before new keys - * are set or just after association or something similar. This - * shows up in group key handshake failing often because of the - * client not receiving the first encrypted packets correctly. - * Skipping some of the extra key clearing steps seems to help - * in completing group key handshake more reliably. */ - wpa_printf(MSG_DEBUG, "No keys have been configured - " - "skip key clearing"); - return; - } - - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 0, 0, NULL, 0, NULL, 0); - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 1, 0, NULL, 0, NULL, 0); - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 2, 0, NULL, 0, NULL, 0); - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 3, 0, NULL, 0, NULL, 0); - if (addr) { - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL, - 0); - } - wpa_s->keys_cleared = 1; -} - - -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) -{ - 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; - } - - return 1; -} - - -static void wpa_supplicant_associnfo(struct wpa_supplicant *wpa_s, - union wpa_event_data *data) -{ - 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; - } - -} - - -void wpa_supplicant_event(struct wpa_supplicant *wpa_s, wpa_event_type event, - union wpa_event_data *data) -{ - 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; - } -} - - -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); - } - eloop_terminate(); -} - - -int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s) -{ - struct wpa_config *conf; - int reconf_ctrl; - if (wpa_s->confname == NULL) - return -1; - conf = wpa_config_read(wpa_s->confname); - if (conf == NULL) { - wpa_msg(wpa_s, MSG_ERROR, "Failed to parse the configuration " - "file '%s' - exiting", wpa_s->confname); - return -1; - } - - reconf_ctrl = !!conf->ctrl_interface != !!wpa_s->conf->ctrl_interface - || (conf->ctrl_interface && wpa_s->conf->ctrl_interface && - strcmp(conf->ctrl_interface, wpa_s->conf->ctrl_interface) - != 0); - - if (reconf_ctrl) - wpa_supplicant_ctrl_iface_deinit(wpa_s); - - wpa_s->current_ssid = NULL; - eapol_sm_notify_config(wpa_s->eapol, NULL, NULL); - rsn_preauth_deinit(wpa_s); - wpa_config_free(wpa_s->conf); - wpa_s->conf = conf; - if (reconf_ctrl) - wpa_supplicant_ctrl_iface_init(wpa_s); - wpa_s->reassociate = 1; - wpa_supplicant_req_scan(wpa_s, 0, 0); - wpa_msg(wpa_s, MSG_DEBUG, "Reconfiguration completed"); - return 0; -} - - -#ifndef CONFIG_NATIVE_WINDOWS -static void wpa_supplicant_reconfig(int sig, void *eloop_ctx, - void *signal_ctx) -{ - struct wpa_supplicant *wpa_s = eloop_ctx; - wpa_printf(MSG_DEBUG, "Signal %d received - reconfiguring", sig); - for (wpa_s = wpa_s->head; wpa_s; wpa_s = wpa_s->next) { - if (wpa_supplicant_reload_configuration(wpa_s) < 0) { - eloop_terminate(); - } - } -} -#endif /* CONFIG_NATIVE_WINDOWS */ - - -static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s) -{ - struct wpa_ssid *ssid; - union wpa_event_data data; - - ssid = wpa_supplicant_get_ssid(wpa_s); - if (ssid == NULL) - return; - - wpa_printf(MSG_DEBUG, "Already associated with a configured network - " - "generating associated event"); - memset(&data, 0, sizeof(data)); - wpa_supplicant_event(wpa_s, EVENT_ASSOC, &data); -} - - -void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) -{ - struct wpa_supplicant *wpa_s = eloop_ctx; - struct wpa_ssid *ssid; - - if (wpa_s->conf->ap_scan == 0) { - wpa_supplicant_gen_assoc_event(wpa_s); - return; - } - - if (wpa_s->conf->ap_scan == 2) { - ssid = wpa_s->conf->ssid; - if (ssid == NULL) - return; - wpa_supplicant_associate(wpa_s, NULL, ssid); - return; - } - - if (wpa_s->wpa_state == WPA_DISCONNECTED) - wpa_s->wpa_state = WPA_SCANNING; - - ssid = wpa_s->conf->ssid; - if (wpa_s->prev_scan_ssid != BROADCAST_SSID_SCAN) { - while (ssid) { - if (ssid == wpa_s->prev_scan_ssid) { - ssid = ssid->next; - break; - } - ssid = ssid->next; - } - } - while (ssid) { - if (ssid->scan_ssid) - break; - ssid = ssid->next; - } - - wpa_printf(MSG_DEBUG, "Starting AP scan (%s SSID)", - ssid ? "specific": "broadcast"); - if (ssid) { - wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID", - ssid->ssid, ssid->ssid_len); - wpa_s->prev_scan_ssid = ssid; - } else - wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN; - - if (wpa_drv_scan(wpa_s, ssid ? ssid->ssid : NULL, - ssid ? ssid->ssid_len : 0)) { - wpa_printf(MSG_WARNING, "Failed to initiate AP scan."); - wpa_supplicant_req_scan(wpa_s, 10, 0); - } -} - - -static wpa_cipher cipher_suite2driver(int cipher) -{ - switch (cipher) { - case WPA_CIPHER_NONE: - return CIPHER_NONE; - case WPA_CIPHER_WEP40: - return CIPHER_WEP40; - case WPA_CIPHER_WEP104: - return CIPHER_WEP104; - case WPA_CIPHER_CCMP: - return CIPHER_CCMP; - case WPA_CIPHER_TKIP: - default: - return CIPHER_TKIP; - } -} - - -static wpa_key_mgmt key_mgmt2driver(int key_mgmt) -{ - switch (key_mgmt) { - case WPA_KEY_MGMT_NONE: - return KEY_MGMT_NONE; - case WPA_KEY_MGMT_IEEE8021X_NO_WPA: - return KEY_MGMT_802_1X_NO_WPA; - case WPA_KEY_MGMT_IEEE8021X: - return KEY_MGMT_802_1X; - case WPA_KEY_MGMT_WPA_NONE: - return KEY_MGMT_WPA_NONE; - case WPA_KEY_MGMT_PSK: - default: - return KEY_MGMT_PSK; - } -} - - -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"); - return -1; - } - - wpa_printf(MSG_DEBUG, "WPA: Using WPA IE from AssocReq to set cipher " - "suites"); - if (!(ie->group_cipher & ssid->group_cipher)) { - wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled group " - "cipher 0x%x (mask 0x%x) - reject", - ie->group_cipher, ssid->group_cipher); - return -1; - } - if (!(ie->pairwise_cipher & ssid->pairwise_cipher)) { - wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled pairwise " - "cipher 0x%x (mask 0x%x) - reject", - ie->pairwise_cipher, ssid->pairwise_cipher); - return -1; - } - if (!(ie->key_mgmt & ssid->key_mgmt)) { - wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled key " - "management 0x%x (mask 0x%x) - reject", - ie->key_mgmt, ssid->key_mgmt); - return -1; - } - - return 0; -} - - -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) -{ - 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)) { - 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) { - 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 (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; - ie.pairwise_cipher = ssid->pairwise_cipher; - ie.key_mgmt = ssid->key_mgmt; - wpa_printf(MSG_DEBUG, "WPA: Set cipher suites based " - "on configuration"); - } - } - - 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; - } - - 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; - } - - sel = ie.group_cipher & ssid->group_cipher; - if (sel & WPA_CIPHER_CCMP) { - wpa_s->group_cipher = WPA_CIPHER_CCMP; - wpa_msg(wpa_s, MSG_DEBUG, "WPA: using GTK CCMP"); - } else if (sel & WPA_CIPHER_TKIP) { - wpa_s->group_cipher = WPA_CIPHER_TKIP; - wpa_msg(wpa_s, MSG_DEBUG, "WPA: using GTK TKIP"); - } else if (sel & WPA_CIPHER_WEP104) { - wpa_s->group_cipher = WPA_CIPHER_WEP104; - wpa_msg(wpa_s, MSG_DEBUG, "WPA: using GTK WEP104"); - } else if (sel & WPA_CIPHER_WEP40) { - wpa_s->group_cipher = WPA_CIPHER_WEP40; - wpa_msg(wpa_s, MSG_DEBUG, "WPA: using GTK WEP40"); - } else { - wpa_printf(MSG_WARNING, "WPA: Failed to select group cipher."); - return -1; - } - - sel = ie.pairwise_cipher & ssid->pairwise_cipher; - if (sel & WPA_CIPHER_CCMP) { - wpa_s->pairwise_cipher = WPA_CIPHER_CCMP; - wpa_msg(wpa_s, MSG_DEBUG, "WPA: using PTK CCMP"); - } else if (sel & WPA_CIPHER_TKIP) { - wpa_s->pairwise_cipher = WPA_CIPHER_TKIP; - wpa_msg(wpa_s, MSG_DEBUG, "WPA: using PTK TKIP"); - } else if (sel & WPA_CIPHER_NONE) { - wpa_s->pairwise_cipher = WPA_CIPHER_NONE; - wpa_msg(wpa_s, MSG_DEBUG, "WPA: using PTK NONE"); - } else { - wpa_printf(MSG_WARNING, "WPA: Failed to select pairwise " - "cipher."); - return -1; - } - - sel = ie.key_mgmt & ssid->key_mgmt; - if (sel & WPA_KEY_MGMT_IEEE8021X) { - wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X; - wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X"); - } else if (sel & WPA_KEY_MGMT_PSK) { - wpa_s->key_mgmt = WPA_KEY_MGMT_PSK; - wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-PSK"); - } else if (sel & WPA_KEY_MGMT_WPA_NONE) { - wpa_s->key_mgmt = WPA_KEY_MGMT_WPA_NONE; - wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-NONE"); - } else { - wpa_printf(MSG_WARNING, "WPA: Failed to select authenticated " - "key management type."); - return -1; - } - - *wpa_ie_len = wpa_gen_wpa_ie(wpa_s, wpa_ie); - if (*wpa_ie_len < 0) { - 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 */ - } - - return 0; -} - - -static 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; - 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; - - 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); - memset(wpa_s->bssid, 0, ETH_ALEN); - } else { - wpa_msg(wpa_s, MSG_INFO, "Trying to associate with SSID '%s'", - wpa_ssid_txt(ssid->ssid, ssid->ssid_len)); - } - wpa_supplicant_cancel_scan(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; - - if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) { - if (ssid->leap) { - if (ssid->non_leap == 0) - algs = AUTH_ALG_LEAP; - else - algs |= AUTH_ALG_LEAP; - } - } - wpa_printf(MSG_DEBUG, "Automatic auth_alg selection: 0x%x", algs); - if (ssid->auth_alg) { - algs = 0; - if (ssid->auth_alg & WPA_AUTH_ALG_OPEN) - algs |= AUTH_ALG_OPEN_SYSTEM; - if (ssid->auth_alg & WPA_AUTH_ALG_SHARED) - algs |= AUTH_ALG_SHARED_KEY; - if (ssid->auth_alg & WPA_AUTH_ALG_LEAP) - algs |= AUTH_ALG_LEAP; - wpa_printf(MSG_DEBUG, "Overriding auth_alg selection: 0x%x", - algs); - } - wpa_drv_set_auth_alg(wpa_s, algs); - - 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); - eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1); - } - if (wpa_supplicant_set_suites(wpa_s, bss, ssid, - wpa_ie, &wpa_ie_len)) { - wpa_printf(MSG_WARNING, "WPA: Failed to set WPA key " - "management and encryption suites"); - return; - } - } else if (ssid->key_mgmt & - (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X | - WPA_KEY_MGMT_WPA_NONE)) { - if (wpa_supplicant_set_suites(wpa_s, NULL, ssid, - wpa_ie, &wpa_ie_len)) { - wpa_printf(MSG_WARNING, "WPA: Failed to set WPA key " - "management and encryption suites (no scan " - "results)"); - return; - } - } else { - wpa_supplicant_set_non_wpa_policy(wpa_s, ssid); - wpa_ie_len = 0; - } - - wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL); - use_crypt = 1; - cipher_pairwise = cipher_suite2driver(wpa_s->pairwise_cipher); - cipher_group = cipher_suite2driver(wpa_s->group_cipher); - if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE || - wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { - int i; - if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) - use_crypt = 0; - for (i = 0; i < NUM_WEP_KEYS; i++) { - if (ssid->wep_key_len[i]) { - use_crypt = 1; - wep_keys_set = 1; - wpa_set_wep_key(wpa_s, - i == ssid->wep_tx_keyidx, - i, ssid->wep_key[i], - ssid->wep_key_len[i]); - } - } - } - - if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { - if ((ssid->eapol_flags & - (EAPOL_FLAG_REQUIRE_KEY_UNICAST | - EAPOL_FLAG_REQUIRE_KEY_BROADCAST)) == 0 && - !wep_keys_set) { - use_crypt = 0; - } else { - /* Assume that dynamic WEP-104 keys will be used and - * set cipher suites in order for drivers to expect - * encryption. */ - cipher_pairwise = cipher_group = CIPHER_WEP104; - } - } - - if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) { - /* Set the key before (and later after) association */ - wpa_supplicant_set_wpa_none_key(wpa_s, ssid); - } - - wpa_drv_set_drop_unencrypted(wpa_s, use_crypt); - wpa_s->wpa_state = WPA_ASSOCIATING; - memset(¶ms, 0, sizeof(params)); - if (bss) { - params.bssid = bss->bssid; - params.ssid = bss->ssid; - params.ssid_len = bss->ssid_len; - params.freq = bss->freq; - } else { - params.ssid = ssid->ssid; - params.ssid_len = ssid->ssid_len; - } - params.wpa_ie = wpa_ie; - params.wpa_ie_len = wpa_ie_len; - params.pairwise_suite = cipher_pairwise; - params.group_suite = cipher_group; - params.key_mgmt_suite = key_mgmt2driver(wpa_s->key_mgmt); - params.auth_alg = algs; - params.mode = ssid->mode; - if (wpa_drv_associate(wpa_s, ¶ms) < 0) { - wpa_msg(wpa_s, MSG_INFO, "Association request to the driver " - "failed"); - /* try to continue anyway; new association will be tried again - * after timeout */ - } - - if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) { - /* Set the key after the association just in case association - * cleared the previously configured key. */ - wpa_supplicant_set_wpa_none_key(wpa_s, ssid); - /* No need to timeout authentication since there is no key - * management. */ - wpa_supplicant_cancel_auth_timeout(wpa_s); - } else { - /* Timeout for IEEE 802.11 authentication and association */ - wpa_supplicant_req_auth_timeout(wpa_s, 5, 0); - } - - if (wep_keys_set && wpa_drv_get_capa(wpa_s, &capa) == 0 && - capa.flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC) { - /* Set static WEP keys again */ - int i; - for (i = 0; i < NUM_WEP_KEYS; i++) { - if (ssid->wep_key_len[i]) { - wpa_set_wep_key(wpa_s, - i == ssid->wep_tx_keyidx, - i, ssid->wep_key[i], - ssid->wep_key_len[i]); - } - } - } - - wpa_s->current_ssid = ssid; - wpa_supplicant_initiate_eapol(wpa_s); -} - - -void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s, - int reason_code) -{ - u8 *addr = NULL; - wpa_s->wpa_state = 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; - 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); -} - - -void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s, - int reason_code) -{ - u8 *addr = NULL; - wpa_s->wpa_state = 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; - 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) -{ -#define SCAN_AP_LIMIT 128 - struct wpa_scan_result *results, *tmp; - int num; - - results = malloc(SCAN_AP_LIMIT * sizeof(struct wpa_scan_result)); - if (results == NULL) { - wpa_printf(MSG_WARNING, "Failed to allocate memory for scan " - "results"); - return -1; - } - - num = wpa_drv_get_scan_results(wpa_s, results, SCAN_AP_LIMIT); - wpa_printf(MSG_DEBUG, "Scan results: %d", num); - if (num < 0) { - wpa_printf(MSG_DEBUG, "Failed to get scan results"); - free(results); - return -1; - } - if (num > SCAN_AP_LIMIT) { - wpa_printf(MSG_INFO, "Not enough room for all APs (%d < %d)", - num, SCAN_AP_LIMIT); - num = SCAN_AP_LIMIT; - } - - /* Free unneeded memory for unused scan result entries */ - tmp = realloc(results, num * sizeof(struct wpa_scan_result)); - if (tmp || num == 0) { - results = tmp; - } - - free(wpa_s->scan_results); - wpa_s->scan_results = results; - wpa_s->num_scan_results = num; - - return 0; -} - - -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); - } -} - - -static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s) -{ - int i, ret = 0; - struct wpa_scan_result *results, *curr = NULL; - - results = wpa_s->scan_results; - if (results == NULL) { - return -1; - } - - for (i = 0; i < wpa_s->num_scan_results; i++) { - if (memcmp(results[i].bssid, wpa_s->bssid, ETH_ALEN) == 0) { - curr = &results[i]; - break; - } - } - - 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; - } - } else { - ret = -1; - } - - return ret; -} - - -int wpa_supplicant_get_beacon_ie(struct wpa_supplicant *wpa_s) -{ - if (wpa_get_beacon_ie(wpa_s) == 0) { - return 0; - } - - /* No WPA/RSN IE found in the cached scan results. Try to get updated - * scan results from the driver. */ - if (wpa_supplicant_get_scan_results(wpa_s) < 0) { - return -1; - } - - return wpa_get_beacon_ie(wpa_s); -} - - -#ifdef CONFIG_XSUPPLICANT_IFACE -static void wpa_supplicant_dot1x_receive(int sock, void *eloop_ctx, - void *sock_ctx) -{ - struct wpa_supplicant *wpa_s = eloop_ctx; - u8 buf[128]; - int res; - - 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; - } - - if (res != PMK_LEN) { - wpa_printf(MSG_WARNING, "WPA: Invalid master key length (%d) " - "from dot1x", res); - return; - } - - 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); - } -} - - -static int wpa_supplicant_802_1x_init(struct wpa_supplicant *wpa_s) -{ - int s; - struct sockaddr_un addr; - - 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; - } - - wpa_s->dot1x_s = s; - eloop_register_read_sock(s, wpa_supplicant_dot1x_receive, wpa_s, - NULL); - return 0; -} -#endif /* CONFIG_XSUPPLICANT_IFACE */ - - -static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s, - const char *name) -{ - int i; - - if (wpa_s == NULL) - return -1; - - if (wpa_supplicant_drivers[0] == NULL) { - wpa_printf(MSG_ERROR, "No driver interfaces build into " - "wpa_supplicant."); - return -1; - } - - if (name == NULL) { - /* default to first driver in the list */ - wpa_s->driver = wpa_supplicant_drivers[0]; - return 0; - } - - for (i = 0; wpa_supplicant_drivers[i]; i++) { - if (strcmp(name, wpa_supplicant_drivers[i]->name) == 0) { - wpa_s->driver = wpa_supplicant_drivers[i]; - return 0; - } - } - - printf("Unsupported driver '%s'.\n", name); - return -1; -} - - -static void wpa_supplicant_fd_workaround(void) -{ - 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; - } - } -} - - -static int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s, - int wait_for_interface) -{ - static int interface_count = 0; - - for (;;) { - 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); - if (wpa_s->l2) - break; - else if (!wait_for_interface) - return -1; - printf("Waiting for interface..\n"); - sleep(5); - } - - if (l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) { - fprintf(stderr, "Failed to get own L2 address\n"); - return -1; - } - - wpa_printf(MSG_DEBUG, "Own MAC address: " MACSTR, - MAC2STR(wpa_s->own_addr)); - - if (wpa_drv_set_wpa(wpa_s, 1) < 0) { - fprintf(stderr, "Failed to enable WPA in the driver.\n"); - return -1; - } - - wpa_clear_keys(wpa_s, NULL); - - /* Make sure that TKIP countermeasures are not left enabled (could - * happen if wpa_supplicant is killed during countermeasures. */ - wpa_drv_set_countermeasures(wpa_s, 0); - - wpa_drv_set_drop_unencrypted(wpa_s, 1); - - wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN; - wpa_supplicant_req_scan(wpa_s, interface_count, 100000); - interface_count++; - - return 0; -} - - -static void usage(void) -{ - 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); - } - - 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"); -} - - -static void license(void) -{ - printf("%s\n\n%s\n", - wpa_supplicant_version, wpa_supplicant_full_license); -} - - -static struct wpa_supplicant * wpa_supplicant_alloc(void) -{ - struct wpa_supplicant *wpa_s; - - wpa_s = malloc(sizeof(*wpa_s)); - if (wpa_s == NULL) - 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 */ - - return wpa_s; -} - - -static int wpa_supplicant_init(struct wpa_supplicant *wpa_s, - const char *confname, const char *driver, - const char *ifname) -{ - wpa_printf(MSG_DEBUG, "Initializing interface '%s' conf '%s' driver " - "'%s'", ifname, confname, driver ? driver : "default"); - - if (wpa_supplicant_set_driver(wpa_s, driver) < 0) { - return -1; - } - - if (confname) { - wpa_s->confname = rel2abs_path(confname); - if (wpa_s->confname == NULL) { - wpa_printf(MSG_ERROR, "Failed to get absolute path " - "for configuration file '%s'.", confname); - return -1; - } - wpa_printf(MSG_DEBUG, "Configuration file '%s' -> '%s'", - confname, wpa_s->confname); - 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); - return -1; - } - } - - if (wpa_s->conf == NULL || wpa_s->conf->ssid == NULL) { - usage(); - printf("\nNo networks (SSID) configured.\n"); - return -1; - } - - if (ifname == NULL) { - usage(); - printf("\nInterface name is required.\n"); - return -1; - } - if (strlen(ifname) >= sizeof(wpa_s->ifname)) { - printf("Too long interface name '%s'.\n", ifname); - return -1; - } - strncpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname)); - - return 0; -} - - -static int wpa_supplicant_init2(struct wpa_supplicant *wpa_s, - int disable_eapol, 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; - } - } - - /* RSNA Supplicant Key Management - INITIALIZE */ - eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE); - eapol_sm_notify_portValid(wpa_s->eapol, FALSE); - - /* Initialize driver interface and register driver event handler before - * L2 receive handler so that association events are processed before - * EAPOL-Key packets if both become available for the same select() - * call. */ - wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname); - if (wpa_s->drv_priv == NULL) { - fprintf(stderr, "Failed to initialize driver interface\n"); - return -1; - } - - ifname = wpa_drv_get_ifname(wpa_s); - if (ifname && strcmp(ifname, wpa_s->ifname) != 0) { - wpa_printf(MSG_DEBUG, "Driver interface replaced interface " - "name with '%s'", ifname); - strncpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname)); - } - - wpa_s->renew_snonce = 1; - if (wpa_supplicant_driver_init(wpa_s, wait_for_interface) < 0) { - return -1; - } - - if (wpa_supplicant_ctrl_iface_init(wpa_s)) { - printf("Failed to initialize control interface '%s'.\n" - "You may have another wpa_supplicant process already " - "running or the file was\n" - "left by an unclean termination of wpa_supplicant in " - "which case you will need\n" - "to manually remove this file before starting " - "wpa_supplicant again.\n", - wpa_s->conf->ctrl_interface); - 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) -{ - if (wpa_s->drv_priv) { - if (wpa_drv_set_wpa(wpa_s, 0) < 0) { - fprintf(stderr, "Failed to disable WPA in the " - "driver.\n"); - } - - wpa_drv_set_drop_unencrypted(wpa_s, 0); - wpa_drv_set_countermeasures(wpa_s, 0); - wpa_clear_keys(wpa_s, NULL); - - wpa_drv_deinit(wpa_s); - } - wpa_supplicant_cleanup(wpa_s); -} - - -int main(int argc, char *argv[]) -{ - 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; - -#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 */ - - head = wpa_s = wpa_supplicant_alloc(); - if (wpa_s == NULL) - return -1; - wpa_s->head = head; - - wpa_supplicant_fd_workaround(); - eloop_init(head); - - ifname = confname = driver = NULL; - - 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(); - return -1; - } - } - - if (wpa_supplicant_init(wpa_s, confname, driver, ifname)) - return -1; - - exitcode = 0; - - if (wait_for_interface && daemonize) { - wpa_printf(MSG_DEBUG, "Daemonize.."); - if (daemon(0, 0)) { - perror("daemon"); - exitcode = -1; - goto cleanup; - } - } - - 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; - } - } - - if (!wait_for_interface && daemonize) { - wpa_printf(MSG_DEBUG, "Daemonize.."); - if (daemon(0, 0)) { - perror("daemon"); - exitcode = -1; - goto cleanup; - } - } - - if (pid_file) { - FILE *f = fopen(pid_file, "w"); - if (f) { - fprintf(f, "%u\n", getpid()); - fclose(f); - } - } - - eloop_register_signal(SIGINT, wpa_supplicant_terminate, NULL); - eloop_register_signal(SIGTERM, wpa_supplicant_terminate, NULL); -#ifndef CONFIG_NATIVE_WINDOWS - eloop_register_signal(SIGHUP, wpa_supplicant_reconfig, NULL); -#endif /* CONFIG_NATIVE_WINDOWS */ - - eloop_run(); - - for (wpa_s = head; wpa_s; wpa_s = wpa_s->next) { - wpa_supplicant_deauthenticate(wpa_s, REASON_DEAUTH_LEAVING); - } - -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); - } - - eloop_destroy(); - - if (pid_file) { - unlink(pid_file); - free(pid_file); - } - -#ifdef CONFIG_NATIVE_WINDOWS - WSACleanup(); -#endif /* CONFIG_NATIVE_WINDOWS */ - - return exitcode; -} |