139beb93cSSam Leffler /* 239beb93cSSam Leffler * WPA Supplicant - Glue code to setup EAPOL and RSN modules 339beb93cSSam Leffler * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 539beb93cSSam Leffler * This program is free software; you can redistribute it and/or modify 639beb93cSSam Leffler * it under the terms of the GNU General Public License version 2 as 739beb93cSSam Leffler * published by the Free Software Foundation. 839beb93cSSam Leffler * 939beb93cSSam Leffler * Alternatively, this software may be distributed under the terms of BSD 1039beb93cSSam Leffler * license. 1139beb93cSSam Leffler * 1239beb93cSSam Leffler * See README and COPYING for more details. 1339beb93cSSam Leffler */ 1439beb93cSSam Leffler 1539beb93cSSam Leffler #include "includes.h" 1639beb93cSSam Leffler 1739beb93cSSam Leffler #include "common.h" 1839beb93cSSam Leffler #include "eapol_supp/eapol_supp_sm.h" 19*e28a4053SRui Paulo #include "rsn_supp/wpa.h" 2039beb93cSSam Leffler #include "eloop.h" 2139beb93cSSam Leffler #include "config.h" 2239beb93cSSam Leffler #include "l2_packet/l2_packet.h" 23*e28a4053SRui Paulo #include "common/wpa_common.h" 2439beb93cSSam Leffler #include "wpa_supplicant_i.h" 25*e28a4053SRui Paulo #include "driver_i.h" 26*e28a4053SRui Paulo #include "rsn_supp/pmksa_cache.h" 2739beb93cSSam Leffler #include "mlme.h" 28*e28a4053SRui Paulo #include "sme.h" 29*e28a4053SRui Paulo #include "common/ieee802_11_defs.h" 30*e28a4053SRui Paulo #include "common/wpa_ctrl.h" 3139beb93cSSam Leffler #include "wpas_glue.h" 3239beb93cSSam Leffler #include "wps_supplicant.h" 33*e28a4053SRui Paulo #include "bss.h" 34*e28a4053SRui Paulo #include "scan.h" 3539beb93cSSam Leffler 3639beb93cSSam Leffler 3739beb93cSSam Leffler #ifndef CONFIG_NO_CONFIG_BLOBS 3839beb93cSSam Leffler #if defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA) 3939beb93cSSam Leffler static void wpa_supplicant_set_config_blob(void *ctx, 4039beb93cSSam Leffler struct wpa_config_blob *blob) 4139beb93cSSam Leffler { 4239beb93cSSam Leffler struct wpa_supplicant *wpa_s = ctx; 4339beb93cSSam Leffler wpa_config_set_blob(wpa_s->conf, blob); 4439beb93cSSam Leffler if (wpa_s->conf->update_config) { 4539beb93cSSam Leffler int ret = wpa_config_write(wpa_s->confname, wpa_s->conf); 4639beb93cSSam Leffler if (ret) { 4739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Failed to update config after " 4839beb93cSSam Leffler "blob set"); 4939beb93cSSam Leffler } 5039beb93cSSam Leffler } 5139beb93cSSam Leffler } 5239beb93cSSam Leffler 5339beb93cSSam Leffler 5439beb93cSSam Leffler static const struct wpa_config_blob * 5539beb93cSSam Leffler wpa_supplicant_get_config_blob(void *ctx, const char *name) 5639beb93cSSam Leffler { 5739beb93cSSam Leffler struct wpa_supplicant *wpa_s = ctx; 5839beb93cSSam Leffler return wpa_config_get_blob(wpa_s->conf, name); 5939beb93cSSam Leffler } 6039beb93cSSam Leffler #endif /* defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA) */ 6139beb93cSSam Leffler #endif /* CONFIG_NO_CONFIG_BLOBS */ 6239beb93cSSam Leffler 6339beb93cSSam Leffler 6439beb93cSSam Leffler #if defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA) 6539beb93cSSam Leffler static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type, 6639beb93cSSam Leffler const void *data, u16 data_len, 6739beb93cSSam Leffler size_t *msg_len, void **data_pos) 6839beb93cSSam Leffler { 6939beb93cSSam Leffler struct ieee802_1x_hdr *hdr; 7039beb93cSSam Leffler 7139beb93cSSam Leffler *msg_len = sizeof(*hdr) + data_len; 7239beb93cSSam Leffler hdr = os_malloc(*msg_len); 7339beb93cSSam Leffler if (hdr == NULL) 7439beb93cSSam Leffler return NULL; 7539beb93cSSam Leffler 7639beb93cSSam Leffler hdr->version = wpa_s->conf->eapol_version; 7739beb93cSSam Leffler hdr->type = type; 7839beb93cSSam Leffler hdr->length = host_to_be16(data_len); 7939beb93cSSam Leffler 8039beb93cSSam Leffler if (data) 8139beb93cSSam Leffler os_memcpy(hdr + 1, data, data_len); 8239beb93cSSam Leffler else 8339beb93cSSam Leffler os_memset(hdr + 1, 0, data_len); 8439beb93cSSam Leffler 8539beb93cSSam Leffler if (data_pos) 8639beb93cSSam Leffler *data_pos = hdr + 1; 8739beb93cSSam Leffler 8839beb93cSSam Leffler return (u8 *) hdr; 8939beb93cSSam Leffler } 9039beb93cSSam Leffler 9139beb93cSSam Leffler 9239beb93cSSam Leffler /** 9339beb93cSSam Leffler * wpa_ether_send - Send Ethernet frame 9439beb93cSSam Leffler * @wpa_s: Pointer to wpa_supplicant data 9539beb93cSSam Leffler * @dest: Destination MAC address 9639beb93cSSam Leffler * @proto: Ethertype in host byte order 9739beb93cSSam Leffler * @buf: Frame payload starting from IEEE 802.1X header 9839beb93cSSam Leffler * @len: Frame payload length 9939beb93cSSam Leffler * Returns: >=0 on success, <0 on failure 10039beb93cSSam Leffler */ 10139beb93cSSam Leffler static int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest, 10239beb93cSSam Leffler u16 proto, const u8 *buf, size_t len) 10339beb93cSSam Leffler { 10439beb93cSSam Leffler if (wpa_s->l2) { 10539beb93cSSam Leffler return l2_packet_send(wpa_s->l2, dest, proto, buf, len); 10639beb93cSSam Leffler } 10739beb93cSSam Leffler 10839beb93cSSam Leffler return wpa_drv_send_eapol(wpa_s, dest, proto, buf, len); 10939beb93cSSam Leffler } 11039beb93cSSam Leffler #endif /* IEEE8021X_EAPOL || !CONFIG_NO_WPA */ 11139beb93cSSam Leffler 11239beb93cSSam Leffler 11339beb93cSSam Leffler #ifdef IEEE8021X_EAPOL 11439beb93cSSam Leffler 11539beb93cSSam Leffler /** 11639beb93cSSam Leffler * wpa_supplicant_eapol_send - Send IEEE 802.1X EAPOL packet to Authenticator 11739beb93cSSam Leffler * @ctx: Pointer to wpa_supplicant data (wpa_s) 11839beb93cSSam Leffler * @type: IEEE 802.1X packet type (IEEE802_1X_TYPE_*) 11939beb93cSSam Leffler * @buf: EAPOL payload (after IEEE 802.1X header) 12039beb93cSSam Leffler * @len: EAPOL payload length 12139beb93cSSam Leffler * Returns: >=0 on success, <0 on failure 12239beb93cSSam Leffler * 12339beb93cSSam Leffler * This function adds Ethernet and IEEE 802.1X header and sends the EAPOL frame 12439beb93cSSam Leffler * to the current Authenticator. 12539beb93cSSam Leffler */ 12639beb93cSSam Leffler static int wpa_supplicant_eapol_send(void *ctx, int type, const u8 *buf, 12739beb93cSSam Leffler size_t len) 12839beb93cSSam Leffler { 12939beb93cSSam Leffler struct wpa_supplicant *wpa_s = ctx; 13039beb93cSSam Leffler u8 *msg, *dst, bssid[ETH_ALEN]; 13139beb93cSSam Leffler size_t msglen; 13239beb93cSSam Leffler int res; 13339beb93cSSam Leffler 13439beb93cSSam Leffler /* TODO: could add l2_packet_sendmsg that allows fragments to avoid 13539beb93cSSam Leffler * extra copy here */ 13639beb93cSSam Leffler 13739beb93cSSam Leffler if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) || 13839beb93cSSam Leffler wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) { 13939beb93cSSam Leffler /* Current SSID is not using IEEE 802.1X/EAP, so drop possible 14039beb93cSSam Leffler * EAPOL frames (mainly, EAPOL-Start) from EAPOL state 14139beb93cSSam Leffler * machines. */ 14239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPA: drop TX EAPOL in non-IEEE 802.1X " 14339beb93cSSam Leffler "mode (type=%d len=%lu)", type, 14439beb93cSSam Leffler (unsigned long) len); 14539beb93cSSam Leffler return -1; 14639beb93cSSam Leffler } 14739beb93cSSam Leffler 14839beb93cSSam Leffler if (pmksa_cache_get_current(wpa_s->wpa) && 14939beb93cSSam Leffler type == IEEE802_1X_TYPE_EAPOL_START) { 15039beb93cSSam Leffler /* Trying to use PMKSA caching - do not send EAPOL-Start frames 15139beb93cSSam Leffler * since they will trigger full EAPOL authentication. */ 15239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "RSN: PMKSA caching - do not send " 15339beb93cSSam Leffler "EAPOL-Start"); 15439beb93cSSam Leffler return -1; 15539beb93cSSam Leffler } 15639beb93cSSam Leffler 15739beb93cSSam Leffler if (is_zero_ether_addr(wpa_s->bssid)) { 15839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "BSSID not set when trying to send an " 15939beb93cSSam Leffler "EAPOL frame"); 16039beb93cSSam Leffler if (wpa_drv_get_bssid(wpa_s, bssid) == 0 && 16139beb93cSSam Leffler !is_zero_ether_addr(bssid)) { 16239beb93cSSam Leffler dst = bssid; 16339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Using current BSSID " MACSTR 16439beb93cSSam Leffler " from the driver as the EAPOL destination", 16539beb93cSSam Leffler MAC2STR(dst)); 16639beb93cSSam Leffler } else { 16739beb93cSSam Leffler dst = wpa_s->last_eapol_src; 16839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Using the source address of the" 16939beb93cSSam Leffler " last received EAPOL frame " MACSTR " as " 17039beb93cSSam Leffler "the EAPOL destination", 17139beb93cSSam Leffler MAC2STR(dst)); 17239beb93cSSam Leffler } 17339beb93cSSam Leffler } else { 17439beb93cSSam Leffler /* BSSID was already set (from (Re)Assoc event, so use it as 17539beb93cSSam Leffler * the EAPOL destination. */ 17639beb93cSSam Leffler dst = wpa_s->bssid; 17739beb93cSSam Leffler } 17839beb93cSSam Leffler 17939beb93cSSam Leffler msg = wpa_alloc_eapol(wpa_s, type, buf, len, &msglen, NULL); 18039beb93cSSam Leffler if (msg == NULL) 18139beb93cSSam Leffler return -1; 18239beb93cSSam Leffler 18339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TX EAPOL: dst=" MACSTR, MAC2STR(dst)); 18439beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", msg, msglen); 18539beb93cSSam Leffler res = wpa_ether_send(wpa_s, dst, ETH_P_EAPOL, msg, msglen); 18639beb93cSSam Leffler os_free(msg); 18739beb93cSSam Leffler return res; 18839beb93cSSam Leffler } 18939beb93cSSam Leffler 19039beb93cSSam Leffler 19139beb93cSSam Leffler /** 19239beb93cSSam Leffler * wpa_eapol_set_wep_key - set WEP key for the driver 19339beb93cSSam Leffler * @ctx: Pointer to wpa_supplicant data (wpa_s) 19439beb93cSSam Leffler * @unicast: 1 = individual unicast key, 0 = broadcast key 19539beb93cSSam Leffler * @keyidx: WEP key index (0..3) 19639beb93cSSam Leffler * @key: Pointer to key data 19739beb93cSSam Leffler * @keylen: Key length in bytes 19839beb93cSSam Leffler * Returns: 0 on success or < 0 on error. 19939beb93cSSam Leffler */ 20039beb93cSSam Leffler static int wpa_eapol_set_wep_key(void *ctx, int unicast, int keyidx, 20139beb93cSSam Leffler const u8 *key, size_t keylen) 20239beb93cSSam Leffler { 20339beb93cSSam Leffler struct wpa_supplicant *wpa_s = ctx; 20439beb93cSSam Leffler if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { 20539beb93cSSam Leffler int cipher = (keylen == 5) ? WPA_CIPHER_WEP40 : 20639beb93cSSam Leffler WPA_CIPHER_WEP104; 20739beb93cSSam Leffler if (unicast) 20839beb93cSSam Leffler wpa_s->pairwise_cipher = cipher; 20939beb93cSSam Leffler else 21039beb93cSSam Leffler wpa_s->group_cipher = cipher; 21139beb93cSSam Leffler } 21239beb93cSSam Leffler return wpa_drv_set_key(wpa_s, WPA_ALG_WEP, 21339beb93cSSam Leffler unicast ? wpa_s->bssid : 21439beb93cSSam Leffler (u8 *) "\xff\xff\xff\xff\xff\xff", 21539beb93cSSam Leffler keyidx, unicast, (u8 *) "", 0, key, keylen); 21639beb93cSSam Leffler } 21739beb93cSSam Leffler 21839beb93cSSam Leffler 21939beb93cSSam Leffler static void wpa_supplicant_aborted_cached(void *ctx) 22039beb93cSSam Leffler { 22139beb93cSSam Leffler struct wpa_supplicant *wpa_s = ctx; 22239beb93cSSam Leffler wpa_sm_aborted_cached(wpa_s->wpa); 22339beb93cSSam Leffler } 22439beb93cSSam Leffler 22539beb93cSSam Leffler 22639beb93cSSam Leffler static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, int success, 22739beb93cSSam Leffler void *ctx) 22839beb93cSSam Leffler { 22939beb93cSSam Leffler struct wpa_supplicant *wpa_s = ctx; 23039beb93cSSam Leffler int res, pmk_len; 23139beb93cSSam Leffler u8 pmk[PMK_LEN]; 23239beb93cSSam Leffler 23339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAPOL authentication completed %ssuccessfully", 23439beb93cSSam Leffler success ? "" : "un"); 23539beb93cSSam Leffler 23639beb93cSSam Leffler if (wpas_wps_eapol_cb(wpa_s) > 0) 23739beb93cSSam Leffler return; 23839beb93cSSam Leffler 23939beb93cSSam Leffler if (!success) { 24039beb93cSSam Leffler /* 24139beb93cSSam Leffler * Make sure we do not get stuck here waiting for long EAPOL 24239beb93cSSam Leffler * timeout if the AP does not disconnect in case of 24339beb93cSSam Leffler * authentication failure. 24439beb93cSSam Leffler */ 24539beb93cSSam Leffler wpa_supplicant_req_auth_timeout(wpa_s, 2, 0); 24639beb93cSSam Leffler } 24739beb93cSSam Leffler 248*e28a4053SRui Paulo if (!success || !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE)) 24939beb93cSSam Leffler return; 25039beb93cSSam Leffler 25139beb93cSSam Leffler if (!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) 25239beb93cSSam Leffler return; 25339beb93cSSam Leffler 25439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Configure PMK for driver-based RSN 4-way " 25539beb93cSSam Leffler "handshake"); 25639beb93cSSam Leffler 25739beb93cSSam Leffler pmk_len = PMK_LEN; 25839beb93cSSam Leffler res = eapol_sm_get_key(eapol, pmk, PMK_LEN); 25939beb93cSSam Leffler if (res) { 26039beb93cSSam Leffler /* 26139beb93cSSam Leffler * EAP-LEAP is an exception from other EAP methods: it 26239beb93cSSam Leffler * uses only 16-byte PMK. 26339beb93cSSam Leffler */ 26439beb93cSSam Leffler res = eapol_sm_get_key(eapol, pmk, 16); 26539beb93cSSam Leffler pmk_len = 16; 26639beb93cSSam Leffler } 26739beb93cSSam Leffler 26839beb93cSSam Leffler if (res) { 26939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Failed to get PMK from EAPOL state " 27039beb93cSSam Leffler "machines"); 27139beb93cSSam Leffler return; 27239beb93cSSam Leffler } 27339beb93cSSam Leffler 27439beb93cSSam Leffler if (wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0, NULL, 0, pmk, 27539beb93cSSam Leffler pmk_len)) { 27639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Failed to set PMK to the driver"); 27739beb93cSSam Leffler } 27839beb93cSSam Leffler 27939beb93cSSam Leffler wpa_supplicant_cancel_scan(wpa_s); 28039beb93cSSam Leffler wpa_supplicant_cancel_auth_timeout(wpa_s); 28139beb93cSSam Leffler wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); 28239beb93cSSam Leffler 28339beb93cSSam Leffler } 28439beb93cSSam Leffler 28539beb93cSSam Leffler 28639beb93cSSam Leffler static void wpa_supplicant_notify_eapol_done(void *ctx) 28739beb93cSSam Leffler { 28839beb93cSSam Leffler struct wpa_supplicant *wpa_s = ctx; 28939beb93cSSam Leffler wpa_msg(wpa_s, MSG_DEBUG, "WPA: EAPOL processing complete"); 29039beb93cSSam Leffler if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) { 29139beb93cSSam Leffler wpa_supplicant_set_state(wpa_s, WPA_4WAY_HANDSHAKE); 29239beb93cSSam Leffler } else { 29339beb93cSSam Leffler wpa_supplicant_cancel_auth_timeout(wpa_s); 29439beb93cSSam Leffler wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); 29539beb93cSSam Leffler } 29639beb93cSSam Leffler } 29739beb93cSSam Leffler 29839beb93cSSam Leffler #endif /* IEEE8021X_EAPOL */ 29939beb93cSSam Leffler 30039beb93cSSam Leffler 30139beb93cSSam Leffler #ifndef CONFIG_NO_WPA 30239beb93cSSam Leffler 30339beb93cSSam Leffler static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s) 30439beb93cSSam Leffler { 30539beb93cSSam Leffler int ret = 0; 306*e28a4053SRui Paulo struct wpa_bss *curr = NULL, *bss; 30739beb93cSSam Leffler struct wpa_ssid *ssid = wpa_s->current_ssid; 30839beb93cSSam Leffler const u8 *ie; 30939beb93cSSam Leffler 310*e28a4053SRui Paulo dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { 311*e28a4053SRui Paulo if (os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) != 0) 31239beb93cSSam Leffler continue; 31339beb93cSSam Leffler if (ssid == NULL || 314*e28a4053SRui Paulo ((bss->ssid_len == ssid->ssid_len && 315*e28a4053SRui Paulo os_memcmp(bss->ssid, ssid->ssid, ssid->ssid_len) == 0) || 31639beb93cSSam Leffler ssid->ssid_len == 0)) { 317*e28a4053SRui Paulo curr = bss; 31839beb93cSSam Leffler break; 31939beb93cSSam Leffler } 32039beb93cSSam Leffler } 32139beb93cSSam Leffler 32239beb93cSSam Leffler if (curr) { 323*e28a4053SRui Paulo ie = wpa_bss_get_vendor_ie(curr, WPA_IE_VENDOR_TYPE); 32439beb93cSSam Leffler if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0)) 32539beb93cSSam Leffler ret = -1; 32639beb93cSSam Leffler 327*e28a4053SRui Paulo ie = wpa_bss_get_ie(curr, WLAN_EID_RSN); 32839beb93cSSam Leffler if (wpa_sm_set_ap_rsn_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0)) 32939beb93cSSam Leffler ret = -1; 33039beb93cSSam Leffler } else { 33139beb93cSSam Leffler ret = -1; 33239beb93cSSam Leffler } 33339beb93cSSam Leffler 33439beb93cSSam Leffler return ret; 33539beb93cSSam Leffler } 33639beb93cSSam Leffler 33739beb93cSSam Leffler 33839beb93cSSam Leffler static int wpa_supplicant_get_beacon_ie(void *ctx) 33939beb93cSSam Leffler { 34039beb93cSSam Leffler struct wpa_supplicant *wpa_s = ctx; 34139beb93cSSam Leffler if (wpa_get_beacon_ie(wpa_s) == 0) { 34239beb93cSSam Leffler return 0; 34339beb93cSSam Leffler } 34439beb93cSSam Leffler 34539beb93cSSam Leffler /* No WPA/RSN IE found in the cached scan results. Try to get updated 34639beb93cSSam Leffler * scan results from the driver. */ 347*e28a4053SRui Paulo if (wpa_supplicant_update_scan_results(wpa_s) < 0) 34839beb93cSSam Leffler return -1; 34939beb93cSSam Leffler 35039beb93cSSam Leffler return wpa_get_beacon_ie(wpa_s); 35139beb93cSSam Leffler } 35239beb93cSSam Leffler 35339beb93cSSam Leffler 35439beb93cSSam Leffler static u8 * _wpa_alloc_eapol(void *wpa_s, u8 type, 35539beb93cSSam Leffler const void *data, u16 data_len, 35639beb93cSSam Leffler size_t *msg_len, void **data_pos) 35739beb93cSSam Leffler { 35839beb93cSSam Leffler return wpa_alloc_eapol(wpa_s, type, data, data_len, msg_len, data_pos); 35939beb93cSSam Leffler } 36039beb93cSSam Leffler 36139beb93cSSam Leffler 36239beb93cSSam Leffler static int _wpa_ether_send(void *wpa_s, const u8 *dest, u16 proto, 36339beb93cSSam Leffler const u8 *buf, size_t len) 36439beb93cSSam Leffler { 36539beb93cSSam Leffler return wpa_ether_send(wpa_s, dest, proto, buf, len); 36639beb93cSSam Leffler } 36739beb93cSSam Leffler 36839beb93cSSam Leffler 36939beb93cSSam Leffler static void _wpa_supplicant_cancel_auth_timeout(void *wpa_s) 37039beb93cSSam Leffler { 37139beb93cSSam Leffler wpa_supplicant_cancel_auth_timeout(wpa_s); 37239beb93cSSam Leffler } 37339beb93cSSam Leffler 37439beb93cSSam Leffler 375*e28a4053SRui Paulo static void _wpa_supplicant_set_state(void *wpa_s, enum wpa_states state) 37639beb93cSSam Leffler { 37739beb93cSSam Leffler wpa_supplicant_set_state(wpa_s, state); 37839beb93cSSam Leffler } 37939beb93cSSam Leffler 38039beb93cSSam Leffler 38139beb93cSSam Leffler /** 38239beb93cSSam Leffler * wpa_supplicant_get_state - Get the connection state 38339beb93cSSam Leffler * @wpa_s: Pointer to wpa_supplicant data 38439beb93cSSam Leffler * Returns: The current connection state (WPA_*) 38539beb93cSSam Leffler */ 386*e28a4053SRui Paulo static enum wpa_states wpa_supplicant_get_state(struct wpa_supplicant *wpa_s) 38739beb93cSSam Leffler { 38839beb93cSSam Leffler return wpa_s->wpa_state; 38939beb93cSSam Leffler } 39039beb93cSSam Leffler 39139beb93cSSam Leffler 392*e28a4053SRui Paulo static enum wpa_states _wpa_supplicant_get_state(void *wpa_s) 39339beb93cSSam Leffler { 39439beb93cSSam Leffler return wpa_supplicant_get_state(wpa_s); 39539beb93cSSam Leffler } 39639beb93cSSam Leffler 39739beb93cSSam Leffler 39839beb93cSSam Leffler static void _wpa_supplicant_disassociate(void *wpa_s, int reason_code) 39939beb93cSSam Leffler { 40039beb93cSSam Leffler wpa_supplicant_disassociate(wpa_s, reason_code); 40139beb93cSSam Leffler /* Schedule a scan to make sure we continue looking for networks */ 4023157ba21SRui Paulo wpa_supplicant_req_scan(wpa_s, 5, 0); 40339beb93cSSam Leffler } 40439beb93cSSam Leffler 40539beb93cSSam Leffler 40639beb93cSSam Leffler static void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code) 40739beb93cSSam Leffler { 40839beb93cSSam Leffler wpa_supplicant_deauthenticate(wpa_s, reason_code); 40939beb93cSSam Leffler /* Schedule a scan to make sure we continue looking for networks */ 4103157ba21SRui Paulo wpa_supplicant_req_scan(wpa_s, 5, 0); 41139beb93cSSam Leffler } 41239beb93cSSam Leffler 41339beb93cSSam Leffler 41439beb93cSSam Leffler static void * wpa_supplicant_get_network_ctx(void *wpa_s) 41539beb93cSSam Leffler { 41639beb93cSSam Leffler return wpa_supplicant_get_ssid(wpa_s); 41739beb93cSSam Leffler } 41839beb93cSSam Leffler 41939beb93cSSam Leffler 42039beb93cSSam Leffler static int wpa_supplicant_get_bssid(void *ctx, u8 *bssid) 42139beb93cSSam Leffler { 42239beb93cSSam Leffler struct wpa_supplicant *wpa_s = ctx; 423*e28a4053SRui Paulo if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) { 42439beb93cSSam Leffler os_memcpy(bssid, wpa_s->bssid, ETH_ALEN); 42539beb93cSSam Leffler return 0; 42639beb93cSSam Leffler } 42739beb93cSSam Leffler return wpa_drv_get_bssid(wpa_s, bssid); 42839beb93cSSam Leffler } 42939beb93cSSam Leffler 43039beb93cSSam Leffler 431*e28a4053SRui Paulo static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg, 43239beb93cSSam Leffler const u8 *addr, int key_idx, int set_tx, 43339beb93cSSam Leffler const u8 *seq, size_t seq_len, 43439beb93cSSam Leffler const u8 *key, size_t key_len) 43539beb93cSSam Leffler { 43639beb93cSSam Leffler struct wpa_supplicant *wpa_s = _wpa_s; 43739beb93cSSam Leffler if (alg == WPA_ALG_TKIP && key_idx == 0 && key_len == 32) { 43839beb93cSSam Leffler /* Clear the MIC error counter when setting a new PTK. */ 43939beb93cSSam Leffler wpa_s->mic_errors_seen = 0; 44039beb93cSSam Leffler } 44139beb93cSSam Leffler return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len, 44239beb93cSSam Leffler key, key_len); 44339beb93cSSam Leffler } 44439beb93cSSam Leffler 44539beb93cSSam Leffler 44639beb93cSSam Leffler static int wpa_supplicant_mlme_setprotection(void *wpa_s, const u8 *addr, 44739beb93cSSam Leffler int protection_type, 44839beb93cSSam Leffler int key_type) 44939beb93cSSam Leffler { 45039beb93cSSam Leffler return wpa_drv_mlme_setprotection(wpa_s, addr, protection_type, 45139beb93cSSam Leffler key_type); 45239beb93cSSam Leffler } 45339beb93cSSam Leffler 45439beb93cSSam Leffler 45539beb93cSSam Leffler static int wpa_supplicant_add_pmkid(void *wpa_s, 45639beb93cSSam Leffler const u8 *bssid, const u8 *pmkid) 45739beb93cSSam Leffler { 45839beb93cSSam Leffler return wpa_drv_add_pmkid(wpa_s, bssid, pmkid); 45939beb93cSSam Leffler } 46039beb93cSSam Leffler 46139beb93cSSam Leffler 46239beb93cSSam Leffler static int wpa_supplicant_remove_pmkid(void *wpa_s, 46339beb93cSSam Leffler const u8 *bssid, const u8 *pmkid) 46439beb93cSSam Leffler { 46539beb93cSSam Leffler return wpa_drv_remove_pmkid(wpa_s, bssid, pmkid); 46639beb93cSSam Leffler } 46739beb93cSSam Leffler 46839beb93cSSam Leffler 46939beb93cSSam Leffler #ifdef CONFIG_IEEE80211R 47039beb93cSSam Leffler static int wpa_supplicant_update_ft_ies(void *ctx, const u8 *md, 47139beb93cSSam Leffler const u8 *ies, size_t ies_len) 47239beb93cSSam Leffler { 47339beb93cSSam Leffler struct wpa_supplicant *wpa_s = ctx; 474*e28a4053SRui Paulo if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) 47539beb93cSSam Leffler return ieee80211_sta_update_ft_ies(wpa_s, md, ies, ies_len); 476*e28a4053SRui Paulo if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) 477*e28a4053SRui Paulo return sme_update_ft_ies(wpa_s, md, ies, ies_len); 47839beb93cSSam Leffler return wpa_drv_update_ft_ies(wpa_s, md, ies, ies_len); 47939beb93cSSam Leffler } 48039beb93cSSam Leffler 48139beb93cSSam Leffler 48239beb93cSSam Leffler static int wpa_supplicant_send_ft_action(void *ctx, u8 action, 48339beb93cSSam Leffler const u8 *target_ap, 48439beb93cSSam Leffler const u8 *ies, size_t ies_len) 48539beb93cSSam Leffler { 48639beb93cSSam Leffler struct wpa_supplicant *wpa_s = ctx; 487*e28a4053SRui Paulo if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) 48839beb93cSSam Leffler return ieee80211_sta_send_ft_action(wpa_s, action, target_ap, 48939beb93cSSam Leffler ies, ies_len); 49039beb93cSSam Leffler return wpa_drv_send_ft_action(wpa_s, action, target_ap, ies, ies_len); 49139beb93cSSam Leffler } 492*e28a4053SRui Paulo 493*e28a4053SRui Paulo 494*e28a4053SRui Paulo static int wpa_supplicant_mark_authenticated(void *ctx, const u8 *target_ap) 495*e28a4053SRui Paulo { 496*e28a4053SRui Paulo struct wpa_supplicant *wpa_s = ctx; 497*e28a4053SRui Paulo struct wpa_driver_auth_params params; 498*e28a4053SRui Paulo struct wpa_bss *bss; 499*e28a4053SRui Paulo 500*e28a4053SRui Paulo if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) 501*e28a4053SRui Paulo return -1; 502*e28a4053SRui Paulo 503*e28a4053SRui Paulo bss = wpa_bss_get_bssid(wpa_s, target_ap); 504*e28a4053SRui Paulo if (bss == NULL) 505*e28a4053SRui Paulo return -1; 506*e28a4053SRui Paulo 507*e28a4053SRui Paulo os_memset(¶ms, 0, sizeof(params)); 508*e28a4053SRui Paulo params.bssid = target_ap; 509*e28a4053SRui Paulo params.freq = bss->freq; 510*e28a4053SRui Paulo params.ssid = bss->ssid; 511*e28a4053SRui Paulo params.ssid_len = bss->ssid_len; 512*e28a4053SRui Paulo params.auth_alg = WPA_AUTH_ALG_FT; 513*e28a4053SRui Paulo params.local_state_change = 1; 514*e28a4053SRui Paulo return wpa_drv_authenticate(wpa_s, ¶ms); 515*e28a4053SRui Paulo } 51639beb93cSSam Leffler #endif /* CONFIG_IEEE80211R */ 51739beb93cSSam Leffler 51839beb93cSSam Leffler #endif /* CONFIG_NO_WPA */ 51939beb93cSSam Leffler 52039beb93cSSam Leffler 521*e28a4053SRui Paulo #ifdef IEEE8021X_EAPOL 52239beb93cSSam Leffler #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) 52339beb93cSSam Leffler static void wpa_supplicant_eap_param_needed(void *ctx, const char *field, 52439beb93cSSam Leffler const char *txt) 52539beb93cSSam Leffler { 52639beb93cSSam Leffler struct wpa_supplicant *wpa_s = ctx; 52739beb93cSSam Leffler struct wpa_ssid *ssid = wpa_s->current_ssid; 52839beb93cSSam Leffler char *buf; 52939beb93cSSam Leffler size_t buflen; 53039beb93cSSam Leffler int len; 53139beb93cSSam Leffler 53239beb93cSSam Leffler if (ssid == NULL) 53339beb93cSSam Leffler return; 53439beb93cSSam Leffler 53539beb93cSSam Leffler buflen = 100 + os_strlen(txt) + ssid->ssid_len; 53639beb93cSSam Leffler buf = os_malloc(buflen); 53739beb93cSSam Leffler if (buf == NULL) 53839beb93cSSam Leffler return; 53939beb93cSSam Leffler len = os_snprintf(buf, buflen, 54039beb93cSSam Leffler WPA_CTRL_REQ "%s-%d:%s needed for SSID ", 54139beb93cSSam Leffler field, ssid->id, txt); 54239beb93cSSam Leffler if (len < 0 || (size_t) len >= buflen) { 54339beb93cSSam Leffler os_free(buf); 54439beb93cSSam Leffler return; 54539beb93cSSam Leffler } 54639beb93cSSam Leffler if (ssid->ssid && buflen > len + ssid->ssid_len) { 54739beb93cSSam Leffler os_memcpy(buf + len, ssid->ssid, ssid->ssid_len); 54839beb93cSSam Leffler len += ssid->ssid_len; 54939beb93cSSam Leffler buf[len] = '\0'; 55039beb93cSSam Leffler } 55139beb93cSSam Leffler buf[buflen - 1] = '\0'; 55239beb93cSSam Leffler wpa_msg(wpa_s, MSG_INFO, "%s", buf); 55339beb93cSSam Leffler os_free(buf); 55439beb93cSSam Leffler } 55539beb93cSSam Leffler #else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ 55639beb93cSSam Leffler #define wpa_supplicant_eap_param_needed NULL 55739beb93cSSam Leffler #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ 55839beb93cSSam Leffler 55939beb93cSSam Leffler 560*e28a4053SRui Paulo static void wpa_supplicant_port_cb(void *ctx, int authorized) 561*e28a4053SRui Paulo { 562*e28a4053SRui Paulo struct wpa_supplicant *wpa_s = ctx; 563*e28a4053SRui Paulo #ifdef CONFIG_AP 564*e28a4053SRui Paulo if (wpa_s->ap_iface) { 565*e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "AP mode active - skip EAPOL Supplicant " 566*e28a4053SRui Paulo "port status: %s", 567*e28a4053SRui Paulo authorized ? "Authorized" : "Unauthorized"); 568*e28a4053SRui Paulo return; 569*e28a4053SRui Paulo } 570*e28a4053SRui Paulo #endif /* CONFIG_AP */ 571*e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "EAPOL: Supplicant port status: %s", 572*e28a4053SRui Paulo authorized ? "Authorized" : "Unauthorized"); 573*e28a4053SRui Paulo wpa_drv_set_supp_port(wpa_s, authorized); 574*e28a4053SRui Paulo } 575*e28a4053SRui Paulo #endif /* IEEE8021X_EAPOL */ 576*e28a4053SRui Paulo 577*e28a4053SRui Paulo 57839beb93cSSam Leffler int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s) 57939beb93cSSam Leffler { 58039beb93cSSam Leffler #ifdef IEEE8021X_EAPOL 58139beb93cSSam Leffler struct eapol_ctx *ctx; 58239beb93cSSam Leffler ctx = os_zalloc(sizeof(*ctx)); 58339beb93cSSam Leffler if (ctx == NULL) { 58439beb93cSSam Leffler wpa_printf(MSG_ERROR, "Failed to allocate EAPOL context."); 58539beb93cSSam Leffler return -1; 58639beb93cSSam Leffler } 58739beb93cSSam Leffler 58839beb93cSSam Leffler ctx->ctx = wpa_s; 58939beb93cSSam Leffler ctx->msg_ctx = wpa_s; 59039beb93cSSam Leffler ctx->eapol_send_ctx = wpa_s; 59139beb93cSSam Leffler ctx->preauth = 0; 59239beb93cSSam Leffler ctx->eapol_done_cb = wpa_supplicant_notify_eapol_done; 59339beb93cSSam Leffler ctx->eapol_send = wpa_supplicant_eapol_send; 59439beb93cSSam Leffler ctx->set_wep_key = wpa_eapol_set_wep_key; 59539beb93cSSam Leffler ctx->set_config_blob = wpa_supplicant_set_config_blob; 59639beb93cSSam Leffler ctx->get_config_blob = wpa_supplicant_get_config_blob; 59739beb93cSSam Leffler ctx->aborted_cached = wpa_supplicant_aborted_cached; 59839beb93cSSam Leffler ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path; 59939beb93cSSam Leffler ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path; 60039beb93cSSam Leffler ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path; 60139beb93cSSam Leffler ctx->wps = wpa_s->wps; 60239beb93cSSam Leffler ctx->eap_param_needed = wpa_supplicant_eap_param_needed; 603*e28a4053SRui Paulo ctx->port_cb = wpa_supplicant_port_cb; 60439beb93cSSam Leffler ctx->cb = wpa_supplicant_eapol_cb; 60539beb93cSSam Leffler ctx->cb_ctx = wpa_s; 60639beb93cSSam Leffler wpa_s->eapol = eapol_sm_init(ctx); 60739beb93cSSam Leffler if (wpa_s->eapol == NULL) { 60839beb93cSSam Leffler os_free(ctx); 60939beb93cSSam Leffler wpa_printf(MSG_ERROR, "Failed to initialize EAPOL state " 61039beb93cSSam Leffler "machines."); 61139beb93cSSam Leffler return -1; 61239beb93cSSam Leffler } 61339beb93cSSam Leffler #endif /* IEEE8021X_EAPOL */ 61439beb93cSSam Leffler 61539beb93cSSam Leffler return 0; 61639beb93cSSam Leffler } 61739beb93cSSam Leffler 61839beb93cSSam Leffler 61939beb93cSSam Leffler int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s) 62039beb93cSSam Leffler { 62139beb93cSSam Leffler #ifndef CONFIG_NO_WPA 62239beb93cSSam Leffler struct wpa_sm_ctx *ctx; 62339beb93cSSam Leffler ctx = os_zalloc(sizeof(*ctx)); 62439beb93cSSam Leffler if (ctx == NULL) { 62539beb93cSSam Leffler wpa_printf(MSG_ERROR, "Failed to allocate WPA context."); 62639beb93cSSam Leffler return -1; 62739beb93cSSam Leffler } 62839beb93cSSam Leffler 62939beb93cSSam Leffler ctx->ctx = wpa_s; 630*e28a4053SRui Paulo ctx->msg_ctx = wpa_s; 63139beb93cSSam Leffler ctx->set_state = _wpa_supplicant_set_state; 63239beb93cSSam Leffler ctx->get_state = _wpa_supplicant_get_state; 63339beb93cSSam Leffler ctx->deauthenticate = _wpa_supplicant_deauthenticate; 63439beb93cSSam Leffler ctx->disassociate = _wpa_supplicant_disassociate; 63539beb93cSSam Leffler ctx->set_key = wpa_supplicant_set_key; 63639beb93cSSam Leffler ctx->get_network_ctx = wpa_supplicant_get_network_ctx; 63739beb93cSSam Leffler ctx->get_bssid = wpa_supplicant_get_bssid; 63839beb93cSSam Leffler ctx->ether_send = _wpa_ether_send; 63939beb93cSSam Leffler ctx->get_beacon_ie = wpa_supplicant_get_beacon_ie; 64039beb93cSSam Leffler ctx->alloc_eapol = _wpa_alloc_eapol; 64139beb93cSSam Leffler ctx->cancel_auth_timeout = _wpa_supplicant_cancel_auth_timeout; 64239beb93cSSam Leffler ctx->add_pmkid = wpa_supplicant_add_pmkid; 64339beb93cSSam Leffler ctx->remove_pmkid = wpa_supplicant_remove_pmkid; 64439beb93cSSam Leffler #ifndef CONFIG_NO_CONFIG_BLOBS 64539beb93cSSam Leffler ctx->set_config_blob = wpa_supplicant_set_config_blob; 64639beb93cSSam Leffler ctx->get_config_blob = wpa_supplicant_get_config_blob; 64739beb93cSSam Leffler #endif /* CONFIG_NO_CONFIG_BLOBS */ 64839beb93cSSam Leffler ctx->mlme_setprotection = wpa_supplicant_mlme_setprotection; 64939beb93cSSam Leffler #ifdef CONFIG_IEEE80211R 65039beb93cSSam Leffler ctx->update_ft_ies = wpa_supplicant_update_ft_ies; 65139beb93cSSam Leffler ctx->send_ft_action = wpa_supplicant_send_ft_action; 652*e28a4053SRui Paulo ctx->mark_authenticated = wpa_supplicant_mark_authenticated; 65339beb93cSSam Leffler #endif /* CONFIG_IEEE80211R */ 65439beb93cSSam Leffler 65539beb93cSSam Leffler wpa_s->wpa = wpa_sm_init(ctx); 65639beb93cSSam Leffler if (wpa_s->wpa == NULL) { 65739beb93cSSam Leffler wpa_printf(MSG_ERROR, "Failed to initialize WPA state " 65839beb93cSSam Leffler "machine"); 65939beb93cSSam Leffler return -1; 66039beb93cSSam Leffler } 66139beb93cSSam Leffler #endif /* CONFIG_NO_WPA */ 66239beb93cSSam Leffler 66339beb93cSSam Leffler return 0; 66439beb93cSSam Leffler } 66539beb93cSSam Leffler 66639beb93cSSam Leffler 66739beb93cSSam Leffler void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s, 66839beb93cSSam Leffler struct wpa_ssid *ssid) 66939beb93cSSam Leffler { 67039beb93cSSam Leffler struct rsn_supp_config conf; 67139beb93cSSam Leffler if (ssid) { 67239beb93cSSam Leffler os_memset(&conf, 0, sizeof(conf)); 67339beb93cSSam Leffler conf.network_ctx = ssid; 67439beb93cSSam Leffler conf.peerkey_enabled = ssid->peerkey; 67539beb93cSSam Leffler conf.allowed_pairwise_cipher = ssid->pairwise_cipher; 67639beb93cSSam Leffler #ifdef IEEE8021X_EAPOL 67739beb93cSSam Leffler conf.eap_workaround = ssid->eap_workaround; 67839beb93cSSam Leffler conf.eap_conf_ctx = &ssid->eap; 67939beb93cSSam Leffler #endif /* IEEE8021X_EAPOL */ 68039beb93cSSam Leffler conf.ssid = ssid->ssid; 68139beb93cSSam Leffler conf.ssid_len = ssid->ssid_len; 68239beb93cSSam Leffler conf.wpa_ptk_rekey = ssid->wpa_ptk_rekey; 68339beb93cSSam Leffler } 68439beb93cSSam Leffler wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL); 68539beb93cSSam Leffler } 686