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" 1939beb93cSSam Leffler #include "wpa.h" 2039beb93cSSam Leffler #include "eloop.h" 2139beb93cSSam Leffler #include "config.h" 2239beb93cSSam Leffler #include "l2_packet/l2_packet.h" 2339beb93cSSam Leffler #include "wpa_common.h" 2439beb93cSSam Leffler #include "wpa_supplicant_i.h" 2539beb93cSSam Leffler #include "pmksa_cache.h" 2639beb93cSSam Leffler #include "mlme.h" 2739beb93cSSam Leffler #include "ieee802_11_defs.h" 2839beb93cSSam Leffler #include "wpa_ctrl.h" 2939beb93cSSam Leffler #include "wpas_glue.h" 3039beb93cSSam Leffler #include "wps_supplicant.h" 3139beb93cSSam Leffler 3239beb93cSSam Leffler 3339beb93cSSam Leffler #ifndef CONFIG_NO_CONFIG_BLOBS 3439beb93cSSam Leffler #if defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA) 3539beb93cSSam Leffler static void wpa_supplicant_set_config_blob(void *ctx, 3639beb93cSSam Leffler struct wpa_config_blob *blob) 3739beb93cSSam Leffler { 3839beb93cSSam Leffler struct wpa_supplicant *wpa_s = ctx; 3939beb93cSSam Leffler wpa_config_set_blob(wpa_s->conf, blob); 4039beb93cSSam Leffler if (wpa_s->conf->update_config) { 4139beb93cSSam Leffler int ret = wpa_config_write(wpa_s->confname, wpa_s->conf); 4239beb93cSSam Leffler if (ret) { 4339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Failed to update config after " 4439beb93cSSam Leffler "blob set"); 4539beb93cSSam Leffler } 4639beb93cSSam Leffler } 4739beb93cSSam Leffler } 4839beb93cSSam Leffler 4939beb93cSSam Leffler 5039beb93cSSam Leffler static const struct wpa_config_blob * 5139beb93cSSam Leffler wpa_supplicant_get_config_blob(void *ctx, const char *name) 5239beb93cSSam Leffler { 5339beb93cSSam Leffler struct wpa_supplicant *wpa_s = ctx; 5439beb93cSSam Leffler return wpa_config_get_blob(wpa_s->conf, name); 5539beb93cSSam Leffler } 5639beb93cSSam Leffler #endif /* defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA) */ 5739beb93cSSam Leffler #endif /* CONFIG_NO_CONFIG_BLOBS */ 5839beb93cSSam Leffler 5939beb93cSSam Leffler 6039beb93cSSam Leffler #if defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA) 6139beb93cSSam Leffler static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type, 6239beb93cSSam Leffler const void *data, u16 data_len, 6339beb93cSSam Leffler size_t *msg_len, void **data_pos) 6439beb93cSSam Leffler { 6539beb93cSSam Leffler struct ieee802_1x_hdr *hdr; 6639beb93cSSam Leffler 6739beb93cSSam Leffler *msg_len = sizeof(*hdr) + data_len; 6839beb93cSSam Leffler hdr = os_malloc(*msg_len); 6939beb93cSSam Leffler if (hdr == NULL) 7039beb93cSSam Leffler return NULL; 7139beb93cSSam Leffler 7239beb93cSSam Leffler hdr->version = wpa_s->conf->eapol_version; 7339beb93cSSam Leffler hdr->type = type; 7439beb93cSSam Leffler hdr->length = host_to_be16(data_len); 7539beb93cSSam Leffler 7639beb93cSSam Leffler if (data) 7739beb93cSSam Leffler os_memcpy(hdr + 1, data, data_len); 7839beb93cSSam Leffler else 7939beb93cSSam Leffler os_memset(hdr + 1, 0, data_len); 8039beb93cSSam Leffler 8139beb93cSSam Leffler if (data_pos) 8239beb93cSSam Leffler *data_pos = hdr + 1; 8339beb93cSSam Leffler 8439beb93cSSam Leffler return (u8 *) hdr; 8539beb93cSSam Leffler } 8639beb93cSSam Leffler 8739beb93cSSam Leffler 8839beb93cSSam Leffler /** 8939beb93cSSam Leffler * wpa_ether_send - Send Ethernet frame 9039beb93cSSam Leffler * @wpa_s: Pointer to wpa_supplicant data 9139beb93cSSam Leffler * @dest: Destination MAC address 9239beb93cSSam Leffler * @proto: Ethertype in host byte order 9339beb93cSSam Leffler * @buf: Frame payload starting from IEEE 802.1X header 9439beb93cSSam Leffler * @len: Frame payload length 9539beb93cSSam Leffler * Returns: >=0 on success, <0 on failure 9639beb93cSSam Leffler */ 9739beb93cSSam Leffler static int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest, 9839beb93cSSam Leffler u16 proto, const u8 *buf, size_t len) 9939beb93cSSam Leffler { 10039beb93cSSam Leffler if (wpa_s->l2) { 10139beb93cSSam Leffler return l2_packet_send(wpa_s->l2, dest, proto, buf, len); 10239beb93cSSam Leffler } 10339beb93cSSam Leffler 10439beb93cSSam Leffler return wpa_drv_send_eapol(wpa_s, dest, proto, buf, len); 10539beb93cSSam Leffler } 10639beb93cSSam Leffler #endif /* IEEE8021X_EAPOL || !CONFIG_NO_WPA */ 10739beb93cSSam Leffler 10839beb93cSSam Leffler 10939beb93cSSam Leffler #ifdef IEEE8021X_EAPOL 11039beb93cSSam Leffler 11139beb93cSSam Leffler /** 11239beb93cSSam Leffler * wpa_supplicant_eapol_send - Send IEEE 802.1X EAPOL packet to Authenticator 11339beb93cSSam Leffler * @ctx: Pointer to wpa_supplicant data (wpa_s) 11439beb93cSSam Leffler * @type: IEEE 802.1X packet type (IEEE802_1X_TYPE_*) 11539beb93cSSam Leffler * @buf: EAPOL payload (after IEEE 802.1X header) 11639beb93cSSam Leffler * @len: EAPOL payload length 11739beb93cSSam Leffler * Returns: >=0 on success, <0 on failure 11839beb93cSSam Leffler * 11939beb93cSSam Leffler * This function adds Ethernet and IEEE 802.1X header and sends the EAPOL frame 12039beb93cSSam Leffler * to the current Authenticator. 12139beb93cSSam Leffler */ 12239beb93cSSam Leffler static int wpa_supplicant_eapol_send(void *ctx, int type, const u8 *buf, 12339beb93cSSam Leffler size_t len) 12439beb93cSSam Leffler { 12539beb93cSSam Leffler struct wpa_supplicant *wpa_s = ctx; 12639beb93cSSam Leffler u8 *msg, *dst, bssid[ETH_ALEN]; 12739beb93cSSam Leffler size_t msglen; 12839beb93cSSam Leffler int res; 12939beb93cSSam Leffler 13039beb93cSSam Leffler /* TODO: could add l2_packet_sendmsg that allows fragments to avoid 13139beb93cSSam Leffler * extra copy here */ 13239beb93cSSam Leffler 13339beb93cSSam Leffler if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) || 13439beb93cSSam Leffler wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) { 13539beb93cSSam Leffler /* Current SSID is not using IEEE 802.1X/EAP, so drop possible 13639beb93cSSam Leffler * EAPOL frames (mainly, EAPOL-Start) from EAPOL state 13739beb93cSSam Leffler * machines. */ 13839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPA: drop TX EAPOL in non-IEEE 802.1X " 13939beb93cSSam Leffler "mode (type=%d len=%lu)", type, 14039beb93cSSam Leffler (unsigned long) len); 14139beb93cSSam Leffler return -1; 14239beb93cSSam Leffler } 14339beb93cSSam Leffler 14439beb93cSSam Leffler if (pmksa_cache_get_current(wpa_s->wpa) && 14539beb93cSSam Leffler type == IEEE802_1X_TYPE_EAPOL_START) { 14639beb93cSSam Leffler /* Trying to use PMKSA caching - do not send EAPOL-Start frames 14739beb93cSSam Leffler * since they will trigger full EAPOL authentication. */ 14839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "RSN: PMKSA caching - do not send " 14939beb93cSSam Leffler "EAPOL-Start"); 15039beb93cSSam Leffler return -1; 15139beb93cSSam Leffler } 15239beb93cSSam Leffler 15339beb93cSSam Leffler if (is_zero_ether_addr(wpa_s->bssid)) { 15439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "BSSID not set when trying to send an " 15539beb93cSSam Leffler "EAPOL frame"); 15639beb93cSSam Leffler if (wpa_drv_get_bssid(wpa_s, bssid) == 0 && 15739beb93cSSam Leffler !is_zero_ether_addr(bssid)) { 15839beb93cSSam Leffler dst = bssid; 15939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Using current BSSID " MACSTR 16039beb93cSSam Leffler " from the driver as the EAPOL destination", 16139beb93cSSam Leffler MAC2STR(dst)); 16239beb93cSSam Leffler } else { 16339beb93cSSam Leffler dst = wpa_s->last_eapol_src; 16439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Using the source address of the" 16539beb93cSSam Leffler " last received EAPOL frame " MACSTR " as " 16639beb93cSSam Leffler "the EAPOL destination", 16739beb93cSSam Leffler MAC2STR(dst)); 16839beb93cSSam Leffler } 16939beb93cSSam Leffler } else { 17039beb93cSSam Leffler /* BSSID was already set (from (Re)Assoc event, so use it as 17139beb93cSSam Leffler * the EAPOL destination. */ 17239beb93cSSam Leffler dst = wpa_s->bssid; 17339beb93cSSam Leffler } 17439beb93cSSam Leffler 17539beb93cSSam Leffler msg = wpa_alloc_eapol(wpa_s, type, buf, len, &msglen, NULL); 17639beb93cSSam Leffler if (msg == NULL) 17739beb93cSSam Leffler return -1; 17839beb93cSSam Leffler 17939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "TX EAPOL: dst=" MACSTR, MAC2STR(dst)); 18039beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", msg, msglen); 18139beb93cSSam Leffler res = wpa_ether_send(wpa_s, dst, ETH_P_EAPOL, msg, msglen); 18239beb93cSSam Leffler os_free(msg); 18339beb93cSSam Leffler return res; 18439beb93cSSam Leffler } 18539beb93cSSam Leffler 18639beb93cSSam Leffler 18739beb93cSSam Leffler /** 18839beb93cSSam Leffler * wpa_eapol_set_wep_key - set WEP key for the driver 18939beb93cSSam Leffler * @ctx: Pointer to wpa_supplicant data (wpa_s) 19039beb93cSSam Leffler * @unicast: 1 = individual unicast key, 0 = broadcast key 19139beb93cSSam Leffler * @keyidx: WEP key index (0..3) 19239beb93cSSam Leffler * @key: Pointer to key data 19339beb93cSSam Leffler * @keylen: Key length in bytes 19439beb93cSSam Leffler * Returns: 0 on success or < 0 on error. 19539beb93cSSam Leffler */ 19639beb93cSSam Leffler static int wpa_eapol_set_wep_key(void *ctx, int unicast, int keyidx, 19739beb93cSSam Leffler const u8 *key, size_t keylen) 19839beb93cSSam Leffler { 19939beb93cSSam Leffler struct wpa_supplicant *wpa_s = ctx; 20039beb93cSSam Leffler if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { 20139beb93cSSam Leffler int cipher = (keylen == 5) ? WPA_CIPHER_WEP40 : 20239beb93cSSam Leffler WPA_CIPHER_WEP104; 20339beb93cSSam Leffler if (unicast) 20439beb93cSSam Leffler wpa_s->pairwise_cipher = cipher; 20539beb93cSSam Leffler else 20639beb93cSSam Leffler wpa_s->group_cipher = cipher; 20739beb93cSSam Leffler } 20839beb93cSSam Leffler return wpa_drv_set_key(wpa_s, WPA_ALG_WEP, 20939beb93cSSam Leffler unicast ? wpa_s->bssid : 21039beb93cSSam Leffler (u8 *) "\xff\xff\xff\xff\xff\xff", 21139beb93cSSam Leffler keyidx, unicast, (u8 *) "", 0, key, keylen); 21239beb93cSSam Leffler } 21339beb93cSSam Leffler 21439beb93cSSam Leffler 21539beb93cSSam Leffler static void wpa_supplicant_aborted_cached(void *ctx) 21639beb93cSSam Leffler { 21739beb93cSSam Leffler struct wpa_supplicant *wpa_s = ctx; 21839beb93cSSam Leffler wpa_sm_aborted_cached(wpa_s->wpa); 21939beb93cSSam Leffler } 22039beb93cSSam Leffler 22139beb93cSSam Leffler 22239beb93cSSam Leffler static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, int success, 22339beb93cSSam Leffler void *ctx) 22439beb93cSSam Leffler { 22539beb93cSSam Leffler struct wpa_supplicant *wpa_s = ctx; 22639beb93cSSam Leffler int res, pmk_len; 22739beb93cSSam Leffler u8 pmk[PMK_LEN]; 22839beb93cSSam Leffler 22939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAPOL authentication completed %ssuccessfully", 23039beb93cSSam Leffler success ? "" : "un"); 23139beb93cSSam Leffler 23239beb93cSSam Leffler if (wpas_wps_eapol_cb(wpa_s) > 0) 23339beb93cSSam Leffler return; 23439beb93cSSam Leffler 23539beb93cSSam Leffler if (!success) { 23639beb93cSSam Leffler /* 23739beb93cSSam Leffler * Make sure we do not get stuck here waiting for long EAPOL 23839beb93cSSam Leffler * timeout if the AP does not disconnect in case of 23939beb93cSSam Leffler * authentication failure. 24039beb93cSSam Leffler */ 24139beb93cSSam Leffler wpa_supplicant_req_auth_timeout(wpa_s, 2, 0); 24239beb93cSSam Leffler } 24339beb93cSSam Leffler 24439beb93cSSam Leffler if (!success || !wpa_s->driver_4way_handshake) 24539beb93cSSam Leffler return; 24639beb93cSSam Leffler 24739beb93cSSam Leffler if (!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) 24839beb93cSSam Leffler return; 24939beb93cSSam Leffler 25039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Configure PMK for driver-based RSN 4-way " 25139beb93cSSam Leffler "handshake"); 25239beb93cSSam Leffler 25339beb93cSSam Leffler pmk_len = PMK_LEN; 25439beb93cSSam Leffler res = eapol_sm_get_key(eapol, pmk, PMK_LEN); 25539beb93cSSam Leffler if (res) { 25639beb93cSSam Leffler /* 25739beb93cSSam Leffler * EAP-LEAP is an exception from other EAP methods: it 25839beb93cSSam Leffler * uses only 16-byte PMK. 25939beb93cSSam Leffler */ 26039beb93cSSam Leffler res = eapol_sm_get_key(eapol, pmk, 16); 26139beb93cSSam Leffler pmk_len = 16; 26239beb93cSSam Leffler } 26339beb93cSSam Leffler 26439beb93cSSam Leffler if (res) { 26539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Failed to get PMK from EAPOL state " 26639beb93cSSam Leffler "machines"); 26739beb93cSSam Leffler return; 26839beb93cSSam Leffler } 26939beb93cSSam Leffler 27039beb93cSSam Leffler if (wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0, NULL, 0, pmk, 27139beb93cSSam Leffler pmk_len)) { 27239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "Failed to set PMK to the driver"); 27339beb93cSSam Leffler } 27439beb93cSSam Leffler 27539beb93cSSam Leffler wpa_supplicant_cancel_scan(wpa_s); 27639beb93cSSam Leffler wpa_supplicant_cancel_auth_timeout(wpa_s); 27739beb93cSSam Leffler wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); 27839beb93cSSam Leffler 27939beb93cSSam Leffler } 28039beb93cSSam Leffler 28139beb93cSSam Leffler 28239beb93cSSam Leffler static void wpa_supplicant_notify_eapol_done(void *ctx) 28339beb93cSSam Leffler { 28439beb93cSSam Leffler struct wpa_supplicant *wpa_s = ctx; 28539beb93cSSam Leffler wpa_msg(wpa_s, MSG_DEBUG, "WPA: EAPOL processing complete"); 28639beb93cSSam Leffler if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) { 28739beb93cSSam Leffler wpa_supplicant_set_state(wpa_s, WPA_4WAY_HANDSHAKE); 28839beb93cSSam Leffler } else { 28939beb93cSSam Leffler wpa_supplicant_cancel_auth_timeout(wpa_s); 29039beb93cSSam Leffler wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); 29139beb93cSSam Leffler } 29239beb93cSSam Leffler } 29339beb93cSSam Leffler 29439beb93cSSam Leffler #endif /* IEEE8021X_EAPOL */ 29539beb93cSSam Leffler 29639beb93cSSam Leffler 29739beb93cSSam Leffler #ifndef CONFIG_NO_WPA 29839beb93cSSam Leffler 29939beb93cSSam Leffler static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s) 30039beb93cSSam Leffler { 30139beb93cSSam Leffler size_t i; 30239beb93cSSam Leffler int ret = 0; 30339beb93cSSam Leffler struct wpa_scan_res *curr = NULL; 30439beb93cSSam Leffler struct wpa_ssid *ssid = wpa_s->current_ssid; 30539beb93cSSam Leffler const u8 *ie; 30639beb93cSSam Leffler 30739beb93cSSam Leffler if (wpa_s->scan_res == NULL) 30839beb93cSSam Leffler return -1; 30939beb93cSSam Leffler 31039beb93cSSam Leffler for (i = 0; i < wpa_s->scan_res->num; i++) { 31139beb93cSSam Leffler struct wpa_scan_res *r = wpa_s->scan_res->res[i]; 31239beb93cSSam Leffler if (os_memcmp(r->bssid, wpa_s->bssid, ETH_ALEN) != 0) 31339beb93cSSam Leffler continue; 31439beb93cSSam Leffler ie = wpa_scan_get_ie(r, WLAN_EID_SSID); 31539beb93cSSam Leffler if (ssid == NULL || 31639beb93cSSam Leffler ((ie && ie[1] == ssid->ssid_len && 31739beb93cSSam Leffler os_memcmp(ie + 2, ssid->ssid, ssid->ssid_len) == 0) || 31839beb93cSSam Leffler ssid->ssid_len == 0)) { 31939beb93cSSam Leffler curr = r; 32039beb93cSSam Leffler break; 32139beb93cSSam Leffler } 32239beb93cSSam Leffler } 32339beb93cSSam Leffler 32439beb93cSSam Leffler if (curr) { 32539beb93cSSam Leffler ie = wpa_scan_get_vendor_ie(curr, WPA_IE_VENDOR_TYPE); 32639beb93cSSam Leffler if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0)) 32739beb93cSSam Leffler ret = -1; 32839beb93cSSam Leffler 32939beb93cSSam Leffler ie = wpa_scan_get_ie(curr, WLAN_EID_RSN); 33039beb93cSSam Leffler if (wpa_sm_set_ap_rsn_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0)) 33139beb93cSSam Leffler ret = -1; 33239beb93cSSam Leffler } else { 33339beb93cSSam Leffler ret = -1; 33439beb93cSSam Leffler } 33539beb93cSSam Leffler 33639beb93cSSam Leffler return ret; 33739beb93cSSam Leffler } 33839beb93cSSam Leffler 33939beb93cSSam Leffler 34039beb93cSSam Leffler static int wpa_supplicant_get_beacon_ie(void *ctx) 34139beb93cSSam Leffler { 34239beb93cSSam Leffler struct wpa_supplicant *wpa_s = ctx; 34339beb93cSSam Leffler if (wpa_get_beacon_ie(wpa_s) == 0) { 34439beb93cSSam Leffler return 0; 34539beb93cSSam Leffler } 34639beb93cSSam Leffler 34739beb93cSSam Leffler /* No WPA/RSN IE found in the cached scan results. Try to get updated 34839beb93cSSam Leffler * scan results from the driver. */ 34939beb93cSSam Leffler if (wpa_supplicant_get_scan_results(wpa_s) < 0) { 35039beb93cSSam Leffler return -1; 35139beb93cSSam Leffler } 35239beb93cSSam Leffler 35339beb93cSSam Leffler return wpa_get_beacon_ie(wpa_s); 35439beb93cSSam Leffler } 35539beb93cSSam Leffler 35639beb93cSSam Leffler 35739beb93cSSam Leffler static u8 * _wpa_alloc_eapol(void *wpa_s, u8 type, 35839beb93cSSam Leffler const void *data, u16 data_len, 35939beb93cSSam Leffler size_t *msg_len, void **data_pos) 36039beb93cSSam Leffler { 36139beb93cSSam Leffler return wpa_alloc_eapol(wpa_s, type, data, data_len, msg_len, data_pos); 36239beb93cSSam Leffler } 36339beb93cSSam Leffler 36439beb93cSSam Leffler 36539beb93cSSam Leffler static int _wpa_ether_send(void *wpa_s, const u8 *dest, u16 proto, 36639beb93cSSam Leffler const u8 *buf, size_t len) 36739beb93cSSam Leffler { 36839beb93cSSam Leffler return wpa_ether_send(wpa_s, dest, proto, buf, len); 36939beb93cSSam Leffler } 37039beb93cSSam Leffler 37139beb93cSSam Leffler 37239beb93cSSam Leffler static void _wpa_supplicant_cancel_auth_timeout(void *wpa_s) 37339beb93cSSam Leffler { 37439beb93cSSam Leffler wpa_supplicant_cancel_auth_timeout(wpa_s); 37539beb93cSSam Leffler } 37639beb93cSSam Leffler 37739beb93cSSam Leffler 37839beb93cSSam Leffler static void _wpa_supplicant_set_state(void *wpa_s, wpa_states state) 37939beb93cSSam Leffler { 38039beb93cSSam Leffler wpa_supplicant_set_state(wpa_s, state); 38139beb93cSSam Leffler } 38239beb93cSSam Leffler 38339beb93cSSam Leffler 38439beb93cSSam Leffler /** 38539beb93cSSam Leffler * wpa_supplicant_get_state - Get the connection state 38639beb93cSSam Leffler * @wpa_s: Pointer to wpa_supplicant data 38739beb93cSSam Leffler * Returns: The current connection state (WPA_*) 38839beb93cSSam Leffler */ 38939beb93cSSam Leffler static wpa_states wpa_supplicant_get_state(struct wpa_supplicant *wpa_s) 39039beb93cSSam Leffler { 39139beb93cSSam Leffler return wpa_s->wpa_state; 39239beb93cSSam Leffler } 39339beb93cSSam Leffler 39439beb93cSSam Leffler 39539beb93cSSam Leffler static wpa_states _wpa_supplicant_get_state(void *wpa_s) 39639beb93cSSam Leffler { 39739beb93cSSam Leffler return wpa_supplicant_get_state(wpa_s); 39839beb93cSSam Leffler } 39939beb93cSSam Leffler 40039beb93cSSam Leffler 40139beb93cSSam Leffler static void _wpa_supplicant_disassociate(void *wpa_s, int reason_code) 40239beb93cSSam Leffler { 40339beb93cSSam Leffler wpa_supplicant_disassociate(wpa_s, reason_code); 40439beb93cSSam Leffler /* Schedule a scan to make sure we continue looking for networks */ 40539beb93cSSam Leffler wpa_supplicant_req_scan(wpa_s, 0, 0); 40639beb93cSSam Leffler } 40739beb93cSSam Leffler 40839beb93cSSam Leffler 40939beb93cSSam Leffler static void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code) 41039beb93cSSam Leffler { 41139beb93cSSam Leffler wpa_supplicant_deauthenticate(wpa_s, reason_code); 41239beb93cSSam Leffler /* Schedule a scan to make sure we continue looking for networks */ 41339beb93cSSam Leffler wpa_supplicant_req_scan(wpa_s, 0, 0); 41439beb93cSSam Leffler } 41539beb93cSSam Leffler 41639beb93cSSam Leffler 41739beb93cSSam Leffler static void * wpa_supplicant_get_network_ctx(void *wpa_s) 41839beb93cSSam Leffler { 41939beb93cSSam Leffler return wpa_supplicant_get_ssid(wpa_s); 42039beb93cSSam Leffler } 42139beb93cSSam Leffler 42239beb93cSSam Leffler 42339beb93cSSam Leffler static int wpa_supplicant_get_bssid(void *ctx, u8 *bssid) 42439beb93cSSam Leffler { 42539beb93cSSam Leffler struct wpa_supplicant *wpa_s = ctx; 42639beb93cSSam Leffler if (wpa_s->use_client_mlme) { 42739beb93cSSam Leffler os_memcpy(bssid, wpa_s->bssid, ETH_ALEN); 42839beb93cSSam Leffler return 0; 42939beb93cSSam Leffler } 43039beb93cSSam Leffler return wpa_drv_get_bssid(wpa_s, bssid); 43139beb93cSSam Leffler } 43239beb93cSSam Leffler 43339beb93cSSam Leffler 43439beb93cSSam Leffler static int wpa_supplicant_set_key(void *_wpa_s, wpa_alg alg, 43539beb93cSSam Leffler const u8 *addr, int key_idx, int set_tx, 43639beb93cSSam Leffler const u8 *seq, size_t seq_len, 43739beb93cSSam Leffler const u8 *key, size_t key_len) 43839beb93cSSam Leffler { 43939beb93cSSam Leffler struct wpa_supplicant *wpa_s = _wpa_s; 44039beb93cSSam Leffler if (alg == WPA_ALG_TKIP && key_idx == 0 && key_len == 32) { 44139beb93cSSam Leffler /* Clear the MIC error counter when setting a new PTK. */ 44239beb93cSSam Leffler wpa_s->mic_errors_seen = 0; 44339beb93cSSam Leffler } 44439beb93cSSam Leffler return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len, 44539beb93cSSam Leffler key, key_len); 44639beb93cSSam Leffler } 44739beb93cSSam Leffler 44839beb93cSSam Leffler 44939beb93cSSam Leffler static int wpa_supplicant_mlme_setprotection(void *wpa_s, const u8 *addr, 45039beb93cSSam Leffler int protection_type, 45139beb93cSSam Leffler int key_type) 45239beb93cSSam Leffler { 45339beb93cSSam Leffler return wpa_drv_mlme_setprotection(wpa_s, addr, protection_type, 45439beb93cSSam Leffler key_type); 45539beb93cSSam Leffler } 45639beb93cSSam Leffler 45739beb93cSSam Leffler 45839beb93cSSam Leffler static int wpa_supplicant_add_pmkid(void *wpa_s, 45939beb93cSSam Leffler const u8 *bssid, const u8 *pmkid) 46039beb93cSSam Leffler { 46139beb93cSSam Leffler return wpa_drv_add_pmkid(wpa_s, bssid, pmkid); 46239beb93cSSam Leffler } 46339beb93cSSam Leffler 46439beb93cSSam Leffler 46539beb93cSSam Leffler static int wpa_supplicant_remove_pmkid(void *wpa_s, 46639beb93cSSam Leffler const u8 *bssid, const u8 *pmkid) 46739beb93cSSam Leffler { 46839beb93cSSam Leffler return wpa_drv_remove_pmkid(wpa_s, bssid, pmkid); 46939beb93cSSam Leffler } 47039beb93cSSam Leffler 47139beb93cSSam Leffler 47239beb93cSSam Leffler #ifdef CONFIG_IEEE80211R 47339beb93cSSam Leffler static int wpa_supplicant_update_ft_ies(void *ctx, const u8 *md, 47439beb93cSSam Leffler const u8 *ies, size_t ies_len) 47539beb93cSSam Leffler { 47639beb93cSSam Leffler struct wpa_supplicant *wpa_s = ctx; 47739beb93cSSam Leffler if (wpa_s->use_client_mlme) 47839beb93cSSam Leffler return ieee80211_sta_update_ft_ies(wpa_s, md, ies, ies_len); 47939beb93cSSam Leffler return wpa_drv_update_ft_ies(wpa_s, md, ies, ies_len); 48039beb93cSSam Leffler } 48139beb93cSSam Leffler 48239beb93cSSam Leffler 48339beb93cSSam Leffler static int wpa_supplicant_send_ft_action(void *ctx, u8 action, 48439beb93cSSam Leffler const u8 *target_ap, 48539beb93cSSam Leffler const u8 *ies, size_t ies_len) 48639beb93cSSam Leffler { 48739beb93cSSam Leffler struct wpa_supplicant *wpa_s = ctx; 48839beb93cSSam Leffler if (wpa_s->use_client_mlme) 48939beb93cSSam Leffler return ieee80211_sta_send_ft_action(wpa_s, action, target_ap, 49039beb93cSSam Leffler ies, ies_len); 49139beb93cSSam Leffler return wpa_drv_send_ft_action(wpa_s, action, target_ap, ies, ies_len); 49239beb93cSSam Leffler } 49339beb93cSSam Leffler #endif /* CONFIG_IEEE80211R */ 49439beb93cSSam Leffler 49539beb93cSSam Leffler #endif /* CONFIG_NO_WPA */ 49639beb93cSSam Leffler 49739beb93cSSam Leffler 49839beb93cSSam Leffler #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) 49939beb93cSSam Leffler static void wpa_supplicant_eap_param_needed(void *ctx, const char *field, 50039beb93cSSam Leffler const char *txt) 50139beb93cSSam Leffler { 50239beb93cSSam Leffler struct wpa_supplicant *wpa_s = ctx; 50339beb93cSSam Leffler struct wpa_ssid *ssid = wpa_s->current_ssid; 50439beb93cSSam Leffler char *buf; 50539beb93cSSam Leffler size_t buflen; 50639beb93cSSam Leffler int len; 50739beb93cSSam Leffler 50839beb93cSSam Leffler if (ssid == NULL) 50939beb93cSSam Leffler return; 51039beb93cSSam Leffler 51139beb93cSSam Leffler buflen = 100 + os_strlen(txt) + ssid->ssid_len; 51239beb93cSSam Leffler buf = os_malloc(buflen); 51339beb93cSSam Leffler if (buf == NULL) 51439beb93cSSam Leffler return; 51539beb93cSSam Leffler len = os_snprintf(buf, buflen, 51639beb93cSSam Leffler WPA_CTRL_REQ "%s-%d:%s needed for SSID ", 51739beb93cSSam Leffler field, ssid->id, txt); 51839beb93cSSam Leffler if (len < 0 || (size_t) len >= buflen) { 51939beb93cSSam Leffler os_free(buf); 52039beb93cSSam Leffler return; 52139beb93cSSam Leffler } 52239beb93cSSam Leffler if (ssid->ssid && buflen > len + ssid->ssid_len) { 52339beb93cSSam Leffler os_memcpy(buf + len, ssid->ssid, ssid->ssid_len); 52439beb93cSSam Leffler len += ssid->ssid_len; 52539beb93cSSam Leffler buf[len] = '\0'; 52639beb93cSSam Leffler } 52739beb93cSSam Leffler buf[buflen - 1] = '\0'; 52839beb93cSSam Leffler wpa_msg(wpa_s, MSG_INFO, "%s", buf); 52939beb93cSSam Leffler os_free(buf); 53039beb93cSSam Leffler } 53139beb93cSSam Leffler #else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ 53239beb93cSSam Leffler #define wpa_supplicant_eap_param_needed NULL 53339beb93cSSam Leffler #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ 53439beb93cSSam Leffler 53539beb93cSSam Leffler 53639beb93cSSam Leffler int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s) 53739beb93cSSam Leffler { 53839beb93cSSam Leffler #ifdef IEEE8021X_EAPOL 53939beb93cSSam Leffler struct eapol_ctx *ctx; 54039beb93cSSam Leffler ctx = os_zalloc(sizeof(*ctx)); 54139beb93cSSam Leffler if (ctx == NULL) { 54239beb93cSSam Leffler wpa_printf(MSG_ERROR, "Failed to allocate EAPOL context."); 54339beb93cSSam Leffler return -1; 54439beb93cSSam Leffler } 54539beb93cSSam Leffler 54639beb93cSSam Leffler ctx->ctx = wpa_s; 54739beb93cSSam Leffler ctx->msg_ctx = wpa_s; 54839beb93cSSam Leffler ctx->eapol_send_ctx = wpa_s; 54939beb93cSSam Leffler ctx->preauth = 0; 55039beb93cSSam Leffler ctx->eapol_done_cb = wpa_supplicant_notify_eapol_done; 55139beb93cSSam Leffler ctx->eapol_send = wpa_supplicant_eapol_send; 55239beb93cSSam Leffler ctx->set_wep_key = wpa_eapol_set_wep_key; 55339beb93cSSam Leffler ctx->set_config_blob = wpa_supplicant_set_config_blob; 55439beb93cSSam Leffler ctx->get_config_blob = wpa_supplicant_get_config_blob; 55539beb93cSSam Leffler ctx->aborted_cached = wpa_supplicant_aborted_cached; 55639beb93cSSam Leffler #ifdef EAP_TLS_OPENSSL 55739beb93cSSam Leffler ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path; 55839beb93cSSam Leffler ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path; 55939beb93cSSam Leffler ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path; 56039beb93cSSam Leffler #endif /* EAP_TLS_OPENSSL */ 56139beb93cSSam Leffler ctx->wps = wpa_s->wps; 56239beb93cSSam Leffler ctx->eap_param_needed = wpa_supplicant_eap_param_needed; 56339beb93cSSam Leffler ctx->cb = wpa_supplicant_eapol_cb; 56439beb93cSSam Leffler ctx->cb_ctx = wpa_s; 56539beb93cSSam Leffler wpa_s->eapol = eapol_sm_init(ctx); 56639beb93cSSam Leffler if (wpa_s->eapol == NULL) { 56739beb93cSSam Leffler os_free(ctx); 56839beb93cSSam Leffler wpa_printf(MSG_ERROR, "Failed to initialize EAPOL state " 56939beb93cSSam Leffler "machines."); 57039beb93cSSam Leffler return -1; 57139beb93cSSam Leffler } 57239beb93cSSam Leffler #endif /* IEEE8021X_EAPOL */ 57339beb93cSSam Leffler 57439beb93cSSam Leffler return 0; 57539beb93cSSam Leffler } 57639beb93cSSam Leffler 57739beb93cSSam Leffler 57839beb93cSSam Leffler int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s) 57939beb93cSSam Leffler { 58039beb93cSSam Leffler #ifndef CONFIG_NO_WPA 58139beb93cSSam Leffler struct wpa_sm_ctx *ctx; 58239beb93cSSam Leffler ctx = os_zalloc(sizeof(*ctx)); 58339beb93cSSam Leffler if (ctx == NULL) { 58439beb93cSSam Leffler wpa_printf(MSG_ERROR, "Failed to allocate WPA context."); 58539beb93cSSam Leffler return -1; 58639beb93cSSam Leffler } 58739beb93cSSam Leffler 58839beb93cSSam Leffler ctx->ctx = wpa_s; 58939beb93cSSam Leffler ctx->set_state = _wpa_supplicant_set_state; 59039beb93cSSam Leffler ctx->get_state = _wpa_supplicant_get_state; 59139beb93cSSam Leffler ctx->deauthenticate = _wpa_supplicant_deauthenticate; 59239beb93cSSam Leffler ctx->disassociate = _wpa_supplicant_disassociate; 59339beb93cSSam Leffler ctx->set_key = wpa_supplicant_set_key; 59439beb93cSSam Leffler ctx->get_network_ctx = wpa_supplicant_get_network_ctx; 59539beb93cSSam Leffler ctx->get_bssid = wpa_supplicant_get_bssid; 59639beb93cSSam Leffler ctx->ether_send = _wpa_ether_send; 59739beb93cSSam Leffler ctx->get_beacon_ie = wpa_supplicant_get_beacon_ie; 59839beb93cSSam Leffler ctx->alloc_eapol = _wpa_alloc_eapol; 59939beb93cSSam Leffler ctx->cancel_auth_timeout = _wpa_supplicant_cancel_auth_timeout; 60039beb93cSSam Leffler ctx->add_pmkid = wpa_supplicant_add_pmkid; 60139beb93cSSam Leffler ctx->remove_pmkid = wpa_supplicant_remove_pmkid; 60239beb93cSSam Leffler #ifndef CONFIG_NO_CONFIG_BLOBS 60339beb93cSSam Leffler ctx->set_config_blob = wpa_supplicant_set_config_blob; 60439beb93cSSam Leffler ctx->get_config_blob = wpa_supplicant_get_config_blob; 60539beb93cSSam Leffler #endif /* CONFIG_NO_CONFIG_BLOBS */ 60639beb93cSSam Leffler ctx->mlme_setprotection = wpa_supplicant_mlme_setprotection; 60739beb93cSSam Leffler #ifdef CONFIG_IEEE80211R 60839beb93cSSam Leffler ctx->update_ft_ies = wpa_supplicant_update_ft_ies; 60939beb93cSSam Leffler ctx->send_ft_action = wpa_supplicant_send_ft_action; 61039beb93cSSam Leffler #endif /* CONFIG_IEEE80211R */ 61139beb93cSSam Leffler 61239beb93cSSam Leffler wpa_s->wpa = wpa_sm_init(ctx); 61339beb93cSSam Leffler if (wpa_s->wpa == NULL) { 61439beb93cSSam Leffler wpa_printf(MSG_ERROR, "Failed to initialize WPA state " 61539beb93cSSam Leffler "machine"); 61639beb93cSSam Leffler return -1; 61739beb93cSSam Leffler } 61839beb93cSSam Leffler #endif /* CONFIG_NO_WPA */ 61939beb93cSSam Leffler 62039beb93cSSam Leffler return 0; 62139beb93cSSam Leffler } 62239beb93cSSam Leffler 62339beb93cSSam Leffler 62439beb93cSSam Leffler void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s, 62539beb93cSSam Leffler struct wpa_ssid *ssid) 62639beb93cSSam Leffler { 62739beb93cSSam Leffler struct rsn_supp_config conf; 62839beb93cSSam Leffler if (ssid) { 62939beb93cSSam Leffler os_memset(&conf, 0, sizeof(conf)); 63039beb93cSSam Leffler conf.network_ctx = ssid; 63139beb93cSSam Leffler conf.peerkey_enabled = ssid->peerkey; 63239beb93cSSam Leffler conf.allowed_pairwise_cipher = ssid->pairwise_cipher; 63339beb93cSSam Leffler #ifdef IEEE8021X_EAPOL 63439beb93cSSam Leffler conf.eap_workaround = ssid->eap_workaround; 63539beb93cSSam Leffler conf.eap_conf_ctx = &ssid->eap; 63639beb93cSSam Leffler #endif /* IEEE8021X_EAPOL */ 63739beb93cSSam Leffler conf.ssid = ssid->ssid; 63839beb93cSSam Leffler conf.ssid_len = ssid->ssid_len; 63939beb93cSSam Leffler conf.wpa_ptk_rekey = ssid->wpa_ptk_rekey; 64039beb93cSSam Leffler } 64139beb93cSSam Leffler wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL); 64239beb93cSSam Leffler } 643