1189251Ssam/* 2189251Ssam * WPA Supplicant - Glue code to setup EAPOL and RSN modules 3252726Srpaulo * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> 4189251Ssam * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7189251Ssam */ 8189251Ssam 9189251Ssam#include "includes.h" 10189251Ssam 11189251Ssam#include "common.h" 12189251Ssam#include "eapol_supp/eapol_supp_sm.h" 13214734Srpaulo#include "rsn_supp/wpa.h" 14189251Ssam#include "eloop.h" 15189251Ssam#include "config.h" 16189251Ssam#include "l2_packet/l2_packet.h" 17214734Srpaulo#include "common/wpa_common.h" 18189251Ssam#include "wpa_supplicant_i.h" 19214734Srpaulo#include "driver_i.h" 20214734Srpaulo#include "rsn_supp/pmksa_cache.h" 21214734Srpaulo#include "sme.h" 22214734Srpaulo#include "common/ieee802_11_defs.h" 23214734Srpaulo#include "common/wpa_ctrl.h" 24189251Ssam#include "wpas_glue.h" 25189251Ssam#include "wps_supplicant.h" 26214734Srpaulo#include "bss.h" 27214734Srpaulo#include "scan.h" 28252726Srpaulo#include "notify.h" 29189251Ssam 30189251Ssam 31189251Ssam#ifndef CONFIG_NO_CONFIG_BLOBS 32189251Ssam#if defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA) 33189251Ssamstatic void wpa_supplicant_set_config_blob(void *ctx, 34189251Ssam struct wpa_config_blob *blob) 35189251Ssam{ 36189251Ssam struct wpa_supplicant *wpa_s = ctx; 37189251Ssam wpa_config_set_blob(wpa_s->conf, blob); 38189251Ssam if (wpa_s->conf->update_config) { 39189251Ssam int ret = wpa_config_write(wpa_s->confname, wpa_s->conf); 40189251Ssam if (ret) { 41189251Ssam wpa_printf(MSG_DEBUG, "Failed to update config after " 42189251Ssam "blob set"); 43189251Ssam } 44189251Ssam } 45189251Ssam} 46189251Ssam 47189251Ssam 48189251Ssamstatic const struct wpa_config_blob * 49189251Ssamwpa_supplicant_get_config_blob(void *ctx, const char *name) 50189251Ssam{ 51189251Ssam struct wpa_supplicant *wpa_s = ctx; 52189251Ssam return wpa_config_get_blob(wpa_s->conf, name); 53189251Ssam} 54189251Ssam#endif /* defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA) */ 55189251Ssam#endif /* CONFIG_NO_CONFIG_BLOBS */ 56189251Ssam 57189251Ssam 58189251Ssam#if defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA) 59189251Ssamstatic u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type, 60189251Ssam const void *data, u16 data_len, 61189251Ssam size_t *msg_len, void **data_pos) 62189251Ssam{ 63189251Ssam struct ieee802_1x_hdr *hdr; 64189251Ssam 65189251Ssam *msg_len = sizeof(*hdr) + data_len; 66189251Ssam hdr = os_malloc(*msg_len); 67189251Ssam if (hdr == NULL) 68189251Ssam return NULL; 69189251Ssam 70189251Ssam hdr->version = wpa_s->conf->eapol_version; 71189251Ssam hdr->type = type; 72189251Ssam hdr->length = host_to_be16(data_len); 73189251Ssam 74189251Ssam if (data) 75189251Ssam os_memcpy(hdr + 1, data, data_len); 76189251Ssam else 77189251Ssam os_memset(hdr + 1, 0, data_len); 78189251Ssam 79189251Ssam if (data_pos) 80189251Ssam *data_pos = hdr + 1; 81189251Ssam 82189251Ssam return (u8 *) hdr; 83189251Ssam} 84189251Ssam 85189251Ssam 86189251Ssam/** 87189251Ssam * wpa_ether_send - Send Ethernet frame 88189251Ssam * @wpa_s: Pointer to wpa_supplicant data 89189251Ssam * @dest: Destination MAC address 90189251Ssam * @proto: Ethertype in host byte order 91189251Ssam * @buf: Frame payload starting from IEEE 802.1X header 92189251Ssam * @len: Frame payload length 93189251Ssam * Returns: >=0 on success, <0 on failure 94189251Ssam */ 95189251Ssamstatic int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest, 96189251Ssam u16 proto, const u8 *buf, size_t len) 97189251Ssam{ 98189251Ssam if (wpa_s->l2) { 99189251Ssam return l2_packet_send(wpa_s->l2, dest, proto, buf, len); 100189251Ssam } 101189251Ssam 102189251Ssam return wpa_drv_send_eapol(wpa_s, dest, proto, buf, len); 103189251Ssam} 104189251Ssam#endif /* IEEE8021X_EAPOL || !CONFIG_NO_WPA */ 105189251Ssam 106189251Ssam 107189251Ssam#ifdef IEEE8021X_EAPOL 108189251Ssam 109189251Ssam/** 110189251Ssam * wpa_supplicant_eapol_send - Send IEEE 802.1X EAPOL packet to Authenticator 111189251Ssam * @ctx: Pointer to wpa_supplicant data (wpa_s) 112189251Ssam * @type: IEEE 802.1X packet type (IEEE802_1X_TYPE_*) 113189251Ssam * @buf: EAPOL payload (after IEEE 802.1X header) 114189251Ssam * @len: EAPOL payload length 115189251Ssam * Returns: >=0 on success, <0 on failure 116189251Ssam * 117189251Ssam * This function adds Ethernet and IEEE 802.1X header and sends the EAPOL frame 118189251Ssam * to the current Authenticator. 119189251Ssam */ 120189251Ssamstatic int wpa_supplicant_eapol_send(void *ctx, int type, const u8 *buf, 121189251Ssam size_t len) 122189251Ssam{ 123189251Ssam struct wpa_supplicant *wpa_s = ctx; 124189251Ssam u8 *msg, *dst, bssid[ETH_ALEN]; 125189251Ssam size_t msglen; 126189251Ssam int res; 127189251Ssam 128189251Ssam /* TODO: could add l2_packet_sendmsg that allows fragments to avoid 129189251Ssam * extra copy here */ 130189251Ssam 131189251Ssam if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) || 132189251Ssam wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) { 133189251Ssam /* Current SSID is not using IEEE 802.1X/EAP, so drop possible 134189251Ssam * EAPOL frames (mainly, EAPOL-Start) from EAPOL state 135189251Ssam * machines. */ 136189251Ssam wpa_printf(MSG_DEBUG, "WPA: drop TX EAPOL in non-IEEE 802.1X " 137189251Ssam "mode (type=%d len=%lu)", type, 138189251Ssam (unsigned long) len); 139189251Ssam return -1; 140189251Ssam } 141189251Ssam 142189251Ssam if (pmksa_cache_get_current(wpa_s->wpa) && 143189251Ssam type == IEEE802_1X_TYPE_EAPOL_START) { 144189251Ssam /* Trying to use PMKSA caching - do not send EAPOL-Start frames 145189251Ssam * since they will trigger full EAPOL authentication. */ 146189251Ssam wpa_printf(MSG_DEBUG, "RSN: PMKSA caching - do not send " 147189251Ssam "EAPOL-Start"); 148189251Ssam return -1; 149189251Ssam } 150189251Ssam 151189251Ssam if (is_zero_ether_addr(wpa_s->bssid)) { 152189251Ssam wpa_printf(MSG_DEBUG, "BSSID not set when trying to send an " 153189251Ssam "EAPOL frame"); 154189251Ssam if (wpa_drv_get_bssid(wpa_s, bssid) == 0 && 155189251Ssam !is_zero_ether_addr(bssid)) { 156189251Ssam dst = bssid; 157189251Ssam wpa_printf(MSG_DEBUG, "Using current BSSID " MACSTR 158189251Ssam " from the driver as the EAPOL destination", 159189251Ssam MAC2STR(dst)); 160189251Ssam } else { 161189251Ssam dst = wpa_s->last_eapol_src; 162189251Ssam wpa_printf(MSG_DEBUG, "Using the source address of the" 163189251Ssam " last received EAPOL frame " MACSTR " as " 164189251Ssam "the EAPOL destination", 165189251Ssam MAC2STR(dst)); 166189251Ssam } 167189251Ssam } else { 168189251Ssam /* BSSID was already set (from (Re)Assoc event, so use it as 169189251Ssam * the EAPOL destination. */ 170189251Ssam dst = wpa_s->bssid; 171189251Ssam } 172189251Ssam 173189251Ssam msg = wpa_alloc_eapol(wpa_s, type, buf, len, &msglen, NULL); 174189251Ssam if (msg == NULL) 175189251Ssam return -1; 176189251Ssam 177189251Ssam wpa_printf(MSG_DEBUG, "TX EAPOL: dst=" MACSTR, MAC2STR(dst)); 178189251Ssam wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", msg, msglen); 179189251Ssam res = wpa_ether_send(wpa_s, dst, ETH_P_EAPOL, msg, msglen); 180189251Ssam os_free(msg); 181189251Ssam return res; 182189251Ssam} 183189251Ssam 184189251Ssam 185189251Ssam/** 186189251Ssam * wpa_eapol_set_wep_key - set WEP key for the driver 187189251Ssam * @ctx: Pointer to wpa_supplicant data (wpa_s) 188189251Ssam * @unicast: 1 = individual unicast key, 0 = broadcast key 189189251Ssam * @keyidx: WEP key index (0..3) 190189251Ssam * @key: Pointer to key data 191189251Ssam * @keylen: Key length in bytes 192189251Ssam * Returns: 0 on success or < 0 on error. 193189251Ssam */ 194189251Ssamstatic int wpa_eapol_set_wep_key(void *ctx, int unicast, int keyidx, 195189251Ssam const u8 *key, size_t keylen) 196189251Ssam{ 197189251Ssam struct wpa_supplicant *wpa_s = ctx; 198189251Ssam if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { 199189251Ssam int cipher = (keylen == 5) ? WPA_CIPHER_WEP40 : 200189251Ssam WPA_CIPHER_WEP104; 201189251Ssam if (unicast) 202189251Ssam wpa_s->pairwise_cipher = cipher; 203189251Ssam else 204189251Ssam wpa_s->group_cipher = cipher; 205189251Ssam } 206189251Ssam return wpa_drv_set_key(wpa_s, WPA_ALG_WEP, 207252726Srpaulo unicast ? wpa_s->bssid : NULL, 208252726Srpaulo keyidx, unicast, NULL, 0, key, keylen); 209189251Ssam} 210189251Ssam 211189251Ssam 212189251Ssamstatic void wpa_supplicant_aborted_cached(void *ctx) 213189251Ssam{ 214189251Ssam struct wpa_supplicant *wpa_s = ctx; 215189251Ssam wpa_sm_aborted_cached(wpa_s->wpa); 216189251Ssam} 217189251Ssam 218189251Ssam 219189251Ssamstatic void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, int success, 220189251Ssam void *ctx) 221189251Ssam{ 222189251Ssam struct wpa_supplicant *wpa_s = ctx; 223189251Ssam int res, pmk_len; 224189251Ssam u8 pmk[PMK_LEN]; 225189251Ssam 226189251Ssam wpa_printf(MSG_DEBUG, "EAPOL authentication completed %ssuccessfully", 227189251Ssam success ? "" : "un"); 228189251Ssam 229189251Ssam if (wpas_wps_eapol_cb(wpa_s) > 0) 230189251Ssam return; 231189251Ssam 232189251Ssam if (!success) { 233189251Ssam /* 234189251Ssam * Make sure we do not get stuck here waiting for long EAPOL 235189251Ssam * timeout if the AP does not disconnect in case of 236189251Ssam * authentication failure. 237189251Ssam */ 238189251Ssam wpa_supplicant_req_auth_timeout(wpa_s, 2, 0); 239189251Ssam } 240189251Ssam 241214734Srpaulo if (!success || !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE)) 242189251Ssam return; 243189251Ssam 244189251Ssam if (!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) 245189251Ssam return; 246189251Ssam 247189251Ssam wpa_printf(MSG_DEBUG, "Configure PMK for driver-based RSN 4-way " 248189251Ssam "handshake"); 249189251Ssam 250189251Ssam pmk_len = PMK_LEN; 251252726Srpaulo if (wpa_key_mgmt_ft(wpa_s->key_mgmt)) { 252252726Srpaulo#ifdef CONFIG_IEEE80211R 253252726Srpaulo u8 buf[2 * PMK_LEN]; 254252726Srpaulo wpa_printf(MSG_DEBUG, "RSN: Use FT XXKey as PMK for " 255252726Srpaulo "driver-based 4-way hs and FT"); 256252726Srpaulo res = eapol_sm_get_key(eapol, buf, 2 * PMK_LEN); 257252726Srpaulo if (res == 0) { 258252726Srpaulo os_memcpy(pmk, buf + PMK_LEN, PMK_LEN); 259252726Srpaulo os_memset(buf, 0, sizeof(buf)); 260252726Srpaulo } 261252726Srpaulo#else /* CONFIG_IEEE80211R */ 262252726Srpaulo res = -1; 263252726Srpaulo#endif /* CONFIG_IEEE80211R */ 264252726Srpaulo } else { 265252726Srpaulo res = eapol_sm_get_key(eapol, pmk, PMK_LEN); 266252726Srpaulo if (res) { 267252726Srpaulo /* 268252726Srpaulo * EAP-LEAP is an exception from other EAP methods: it 269252726Srpaulo * uses only 16-byte PMK. 270252726Srpaulo */ 271252726Srpaulo res = eapol_sm_get_key(eapol, pmk, 16); 272252726Srpaulo pmk_len = 16; 273252726Srpaulo } 274189251Ssam } 275189251Ssam 276189251Ssam if (res) { 277189251Ssam wpa_printf(MSG_DEBUG, "Failed to get PMK from EAPOL state " 278189251Ssam "machines"); 279189251Ssam return; 280189251Ssam } 281189251Ssam 282252726Srpaulo wpa_hexdump_key(MSG_DEBUG, "RSN: Configure PMK for driver-based 4-way " 283252726Srpaulo "handshake", pmk, pmk_len); 284252726Srpaulo 285189251Ssam if (wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0, NULL, 0, pmk, 286189251Ssam pmk_len)) { 287189251Ssam wpa_printf(MSG_DEBUG, "Failed to set PMK to the driver"); 288189251Ssam } 289189251Ssam 290189251Ssam wpa_supplicant_cancel_scan(wpa_s); 291189251Ssam wpa_supplicant_cancel_auth_timeout(wpa_s); 292189251Ssam wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); 293189251Ssam 294189251Ssam} 295189251Ssam 296189251Ssam 297189251Ssamstatic void wpa_supplicant_notify_eapol_done(void *ctx) 298189251Ssam{ 299189251Ssam struct wpa_supplicant *wpa_s = ctx; 300189251Ssam wpa_msg(wpa_s, MSG_DEBUG, "WPA: EAPOL processing complete"); 301189251Ssam if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) { 302189251Ssam wpa_supplicant_set_state(wpa_s, WPA_4WAY_HANDSHAKE); 303189251Ssam } else { 304189251Ssam wpa_supplicant_cancel_auth_timeout(wpa_s); 305189251Ssam wpa_supplicant_set_state(wpa_s, WPA_COMPLETED); 306189251Ssam } 307189251Ssam} 308189251Ssam 309189251Ssam#endif /* IEEE8021X_EAPOL */ 310189251Ssam 311189251Ssam 312189251Ssam#ifndef CONFIG_NO_WPA 313189251Ssam 314189251Ssamstatic int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s) 315189251Ssam{ 316189251Ssam int ret = 0; 317214734Srpaulo struct wpa_bss *curr = NULL, *bss; 318189251Ssam struct wpa_ssid *ssid = wpa_s->current_ssid; 319189251Ssam const u8 *ie; 320189251Ssam 321214734Srpaulo dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { 322214734Srpaulo if (os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) != 0) 323189251Ssam continue; 324189251Ssam if (ssid == NULL || 325214734Srpaulo ((bss->ssid_len == ssid->ssid_len && 326214734Srpaulo os_memcmp(bss->ssid, ssid->ssid, ssid->ssid_len) == 0) || 327189251Ssam ssid->ssid_len == 0)) { 328214734Srpaulo curr = bss; 329189251Ssam break; 330189251Ssam } 331189251Ssam } 332189251Ssam 333189251Ssam if (curr) { 334214734Srpaulo ie = wpa_bss_get_vendor_ie(curr, WPA_IE_VENDOR_TYPE); 335189251Ssam if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0)) 336189251Ssam ret = -1; 337189251Ssam 338214734Srpaulo ie = wpa_bss_get_ie(curr, WLAN_EID_RSN); 339189251Ssam if (wpa_sm_set_ap_rsn_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0)) 340189251Ssam ret = -1; 341189251Ssam } else { 342189251Ssam ret = -1; 343189251Ssam } 344189251Ssam 345189251Ssam return ret; 346189251Ssam} 347189251Ssam 348189251Ssam 349189251Ssamstatic int wpa_supplicant_get_beacon_ie(void *ctx) 350189251Ssam{ 351189251Ssam struct wpa_supplicant *wpa_s = ctx; 352189251Ssam if (wpa_get_beacon_ie(wpa_s) == 0) { 353189251Ssam return 0; 354189251Ssam } 355189251Ssam 356189251Ssam /* No WPA/RSN IE found in the cached scan results. Try to get updated 357189251Ssam * scan results from the driver. */ 358214734Srpaulo if (wpa_supplicant_update_scan_results(wpa_s) < 0) 359189251Ssam return -1; 360189251Ssam 361189251Ssam return wpa_get_beacon_ie(wpa_s); 362189251Ssam} 363189251Ssam 364189251Ssam 365189251Ssamstatic u8 * _wpa_alloc_eapol(void *wpa_s, u8 type, 366189251Ssam const void *data, u16 data_len, 367189251Ssam size_t *msg_len, void **data_pos) 368189251Ssam{ 369189251Ssam return wpa_alloc_eapol(wpa_s, type, data, data_len, msg_len, data_pos); 370189251Ssam} 371189251Ssam 372189251Ssam 373189251Ssamstatic int _wpa_ether_send(void *wpa_s, const u8 *dest, u16 proto, 374189251Ssam const u8 *buf, size_t len) 375189251Ssam{ 376189251Ssam return wpa_ether_send(wpa_s, dest, proto, buf, len); 377189251Ssam} 378189251Ssam 379189251Ssam 380189251Ssamstatic void _wpa_supplicant_cancel_auth_timeout(void *wpa_s) 381189251Ssam{ 382189251Ssam wpa_supplicant_cancel_auth_timeout(wpa_s); 383189251Ssam} 384189251Ssam 385189251Ssam 386214734Srpaulostatic void _wpa_supplicant_set_state(void *wpa_s, enum wpa_states state) 387189251Ssam{ 388189251Ssam wpa_supplicant_set_state(wpa_s, state); 389189251Ssam} 390189251Ssam 391189251Ssam 392189251Ssam/** 393189251Ssam * wpa_supplicant_get_state - Get the connection state 394189251Ssam * @wpa_s: Pointer to wpa_supplicant data 395189251Ssam * Returns: The current connection state (WPA_*) 396189251Ssam */ 397214734Srpaulostatic enum wpa_states wpa_supplicant_get_state(struct wpa_supplicant *wpa_s) 398189251Ssam{ 399189251Ssam return wpa_s->wpa_state; 400189251Ssam} 401189251Ssam 402189251Ssam 403214734Srpaulostatic enum wpa_states _wpa_supplicant_get_state(void *wpa_s) 404189251Ssam{ 405189251Ssam return wpa_supplicant_get_state(wpa_s); 406189251Ssam} 407189251Ssam 408189251Ssam 409189251Ssamstatic void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code) 410189251Ssam{ 411189251Ssam wpa_supplicant_deauthenticate(wpa_s, reason_code); 412189251Ssam /* Schedule a scan to make sure we continue looking for networks */ 413209158Srpaulo wpa_supplicant_req_scan(wpa_s, 5, 0); 414189251Ssam} 415189251Ssam 416189251Ssam 417189251Ssamstatic void * wpa_supplicant_get_network_ctx(void *wpa_s) 418189251Ssam{ 419189251Ssam return wpa_supplicant_get_ssid(wpa_s); 420189251Ssam} 421189251Ssam 422189251Ssam 423189251Ssamstatic int wpa_supplicant_get_bssid(void *ctx, u8 *bssid) 424189251Ssam{ 425189251Ssam struct wpa_supplicant *wpa_s = ctx; 426189251Ssam return wpa_drv_get_bssid(wpa_s, bssid); 427189251Ssam} 428189251Ssam 429189251Ssam 430214734Srpaulostatic int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg, 431189251Ssam const u8 *addr, int key_idx, int set_tx, 432189251Ssam const u8 *seq, size_t seq_len, 433189251Ssam const u8 *key, size_t key_len) 434189251Ssam{ 435189251Ssam struct wpa_supplicant *wpa_s = _wpa_s; 436189251Ssam if (alg == WPA_ALG_TKIP && key_idx == 0 && key_len == 32) { 437189251Ssam /* Clear the MIC error counter when setting a new PTK. */ 438189251Ssam wpa_s->mic_errors_seen = 0; 439189251Ssam } 440189251Ssam return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len, 441189251Ssam key, key_len); 442189251Ssam} 443189251Ssam 444189251Ssam 445189251Ssamstatic int wpa_supplicant_mlme_setprotection(void *wpa_s, const u8 *addr, 446189251Ssam int protection_type, 447189251Ssam int key_type) 448189251Ssam{ 449189251Ssam return wpa_drv_mlme_setprotection(wpa_s, addr, protection_type, 450189251Ssam key_type); 451189251Ssam} 452189251Ssam 453189251Ssam 454189251Ssamstatic int wpa_supplicant_add_pmkid(void *wpa_s, 455189251Ssam const u8 *bssid, const u8 *pmkid) 456189251Ssam{ 457189251Ssam return wpa_drv_add_pmkid(wpa_s, bssid, pmkid); 458189251Ssam} 459189251Ssam 460189251Ssam 461189251Ssamstatic int wpa_supplicant_remove_pmkid(void *wpa_s, 462189251Ssam const u8 *bssid, const u8 *pmkid) 463189251Ssam{ 464189251Ssam return wpa_drv_remove_pmkid(wpa_s, bssid, pmkid); 465189251Ssam} 466189251Ssam 467189251Ssam 468189251Ssam#ifdef CONFIG_IEEE80211R 469189251Ssamstatic int wpa_supplicant_update_ft_ies(void *ctx, const u8 *md, 470189251Ssam const u8 *ies, size_t ies_len) 471189251Ssam{ 472189251Ssam struct wpa_supplicant *wpa_s = ctx; 473214734Srpaulo if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) 474214734Srpaulo return sme_update_ft_ies(wpa_s, md, ies, ies_len); 475189251Ssam return wpa_drv_update_ft_ies(wpa_s, md, ies, ies_len); 476189251Ssam} 477189251Ssam 478189251Ssam 479189251Ssamstatic int wpa_supplicant_send_ft_action(void *ctx, u8 action, 480189251Ssam const u8 *target_ap, 481189251Ssam const u8 *ies, size_t ies_len) 482189251Ssam{ 483189251Ssam struct wpa_supplicant *wpa_s = ctx; 484189251Ssam return wpa_drv_send_ft_action(wpa_s, action, target_ap, ies, ies_len); 485189251Ssam} 486214734Srpaulo 487214734Srpaulo 488214734Srpaulostatic int wpa_supplicant_mark_authenticated(void *ctx, const u8 *target_ap) 489214734Srpaulo{ 490214734Srpaulo struct wpa_supplicant *wpa_s = ctx; 491214734Srpaulo struct wpa_driver_auth_params params; 492214734Srpaulo struct wpa_bss *bss; 493214734Srpaulo 494214734Srpaulo bss = wpa_bss_get_bssid(wpa_s, target_ap); 495214734Srpaulo if (bss == NULL) 496214734Srpaulo return -1; 497214734Srpaulo 498214734Srpaulo os_memset(¶ms, 0, sizeof(params)); 499214734Srpaulo params.bssid = target_ap; 500214734Srpaulo params.freq = bss->freq; 501214734Srpaulo params.ssid = bss->ssid; 502214734Srpaulo params.ssid_len = bss->ssid_len; 503214734Srpaulo params.auth_alg = WPA_AUTH_ALG_FT; 504214734Srpaulo params.local_state_change = 1; 505214734Srpaulo return wpa_drv_authenticate(wpa_s, ¶ms); 506214734Srpaulo} 507189251Ssam#endif /* CONFIG_IEEE80211R */ 508189251Ssam 509189251Ssam#endif /* CONFIG_NO_WPA */ 510189251Ssam 511189251Ssam 512252726Srpaulo#ifdef CONFIG_TDLS 513252726Srpaulo 514252726Srpaulostatic int wpa_supplicant_tdls_get_capa(void *ctx, int *tdls_supported, 515252726Srpaulo int *tdls_ext_setup) 516252726Srpaulo{ 517252726Srpaulo struct wpa_supplicant *wpa_s = ctx; 518252726Srpaulo 519252726Srpaulo *tdls_supported = 0; 520252726Srpaulo *tdls_ext_setup = 0; 521252726Srpaulo 522252726Srpaulo if (!wpa_s->drv_capa_known) 523252726Srpaulo return -1; 524252726Srpaulo 525252726Srpaulo if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) 526252726Srpaulo *tdls_supported = 1; 527252726Srpaulo 528252726Srpaulo if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP) 529252726Srpaulo *tdls_ext_setup = 1; 530252726Srpaulo 531252726Srpaulo return 0; 532252726Srpaulo} 533252726Srpaulo 534252726Srpaulo 535252726Srpaulostatic int wpa_supplicant_send_tdls_mgmt(void *ctx, const u8 *dst, 536252726Srpaulo u8 action_code, u8 dialog_token, 537252726Srpaulo u16 status_code, const u8 *buf, 538252726Srpaulo size_t len) 539252726Srpaulo{ 540252726Srpaulo struct wpa_supplicant *wpa_s = ctx; 541252726Srpaulo return wpa_drv_send_tdls_mgmt(wpa_s, dst, action_code, dialog_token, 542252726Srpaulo status_code, buf, len); 543252726Srpaulo} 544252726Srpaulo 545252726Srpaulo 546252726Srpaulostatic int wpa_supplicant_tdls_oper(void *ctx, int oper, const u8 *peer) 547252726Srpaulo{ 548252726Srpaulo struct wpa_supplicant *wpa_s = ctx; 549252726Srpaulo return wpa_drv_tdls_oper(wpa_s, oper, peer); 550252726Srpaulo} 551252726Srpaulo 552252726Srpaulo 553252726Srpaulostatic int wpa_supplicant_tdls_peer_addset( 554252726Srpaulo void *ctx, const u8 *peer, int add, u16 capability, 555252726Srpaulo const u8 *supp_rates, size_t supp_rates_len) 556252726Srpaulo{ 557252726Srpaulo struct wpa_supplicant *wpa_s = ctx; 558252726Srpaulo struct hostapd_sta_add_params params; 559252726Srpaulo 560252726Srpaulo params.addr = peer; 561252726Srpaulo params.aid = 1; 562252726Srpaulo params.capability = capability; 563252726Srpaulo params.flags = WPA_STA_TDLS_PEER | WPA_STA_AUTHORIZED; 564252726Srpaulo params.ht_capabilities = NULL; 565252726Srpaulo params.listen_interval = 0; 566252726Srpaulo params.supp_rates = supp_rates; 567252726Srpaulo params.supp_rates_len = supp_rates_len; 568252726Srpaulo params.set = !add; 569252726Srpaulo 570252726Srpaulo return wpa_drv_sta_add(wpa_s, ¶ms); 571252726Srpaulo} 572252726Srpaulo 573252726Srpaulo#endif /* CONFIG_TDLS */ 574252726Srpaulo 575252726Srpaulo 576252726Srpauloenum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field) 577252726Srpaulo{ 578252726Srpaulo if (os_strcmp(field, "IDENTITY") == 0) 579252726Srpaulo return WPA_CTRL_REQ_EAP_IDENTITY; 580252726Srpaulo else if (os_strcmp(field, "PASSWORD") == 0) 581252726Srpaulo return WPA_CTRL_REQ_EAP_PASSWORD; 582252726Srpaulo else if (os_strcmp(field, "NEW_PASSWORD") == 0) 583252726Srpaulo return WPA_CTRL_REQ_EAP_NEW_PASSWORD; 584252726Srpaulo else if (os_strcmp(field, "PIN") == 0) 585252726Srpaulo return WPA_CTRL_REQ_EAP_PIN; 586252726Srpaulo else if (os_strcmp(field, "OTP") == 0) 587252726Srpaulo return WPA_CTRL_REQ_EAP_OTP; 588252726Srpaulo else if (os_strcmp(field, "PASSPHRASE") == 0) 589252726Srpaulo return WPA_CTRL_REQ_EAP_PASSPHRASE; 590252726Srpaulo return WPA_CTRL_REQ_UNKNOWN; 591252726Srpaulo} 592252726Srpaulo 593252726Srpaulo 594252726Srpauloconst char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field, 595252726Srpaulo const char *default_txt, 596252726Srpaulo const char **txt) 597252726Srpaulo{ 598252726Srpaulo const char *ret = NULL; 599252726Srpaulo 600252726Srpaulo *txt = default_txt; 601252726Srpaulo 602252726Srpaulo switch (field) { 603252726Srpaulo case WPA_CTRL_REQ_EAP_IDENTITY: 604252726Srpaulo *txt = "Identity"; 605252726Srpaulo ret = "IDENTITY"; 606252726Srpaulo break; 607252726Srpaulo case WPA_CTRL_REQ_EAP_PASSWORD: 608252726Srpaulo *txt = "Password"; 609252726Srpaulo ret = "PASSWORD"; 610252726Srpaulo break; 611252726Srpaulo case WPA_CTRL_REQ_EAP_NEW_PASSWORD: 612252726Srpaulo *txt = "New Password"; 613252726Srpaulo ret = "NEW_PASSWORD"; 614252726Srpaulo break; 615252726Srpaulo case WPA_CTRL_REQ_EAP_PIN: 616252726Srpaulo *txt = "PIN"; 617252726Srpaulo ret = "PIN"; 618252726Srpaulo break; 619252726Srpaulo case WPA_CTRL_REQ_EAP_OTP: 620252726Srpaulo ret = "OTP"; 621252726Srpaulo break; 622252726Srpaulo case WPA_CTRL_REQ_EAP_PASSPHRASE: 623252726Srpaulo *txt = "Private key passphrase"; 624252726Srpaulo ret = "PASSPHRASE"; 625252726Srpaulo break; 626252726Srpaulo default: 627252726Srpaulo break; 628252726Srpaulo } 629252726Srpaulo 630252726Srpaulo /* txt needs to be something */ 631252726Srpaulo if (*txt == NULL) { 632252726Srpaulo wpa_printf(MSG_WARNING, "No message for request %d", field); 633252726Srpaulo ret = NULL; 634252726Srpaulo } 635252726Srpaulo 636252726Srpaulo return ret; 637252726Srpaulo} 638252726Srpaulo 639214734Srpaulo#ifdef IEEE8021X_EAPOL 640189251Ssam#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) 641252726Srpaulostatic void wpa_supplicant_eap_param_needed(void *ctx, 642252726Srpaulo enum wpa_ctrl_req_type field, 643252726Srpaulo const char *default_txt) 644189251Ssam{ 645189251Ssam struct wpa_supplicant *wpa_s = ctx; 646189251Ssam struct wpa_ssid *ssid = wpa_s->current_ssid; 647252726Srpaulo const char *field_name, *txt = NULL; 648189251Ssam char *buf; 649189251Ssam size_t buflen; 650189251Ssam int len; 651189251Ssam 652189251Ssam if (ssid == NULL) 653189251Ssam return; 654189251Ssam 655252726Srpaulo wpas_notify_network_request(wpa_s, ssid, field, default_txt); 656252726Srpaulo 657252726Srpaulo field_name = wpa_supplicant_ctrl_req_to_string(field, default_txt, 658252726Srpaulo &txt); 659252726Srpaulo if (field_name == NULL) { 660252726Srpaulo wpa_printf(MSG_WARNING, "Unhandled EAP param %d needed", 661252726Srpaulo field); 662252726Srpaulo return; 663252726Srpaulo } 664252726Srpaulo 665189251Ssam buflen = 100 + os_strlen(txt) + ssid->ssid_len; 666189251Ssam buf = os_malloc(buflen); 667189251Ssam if (buf == NULL) 668189251Ssam return; 669189251Ssam len = os_snprintf(buf, buflen, 670189251Ssam WPA_CTRL_REQ "%s-%d:%s needed for SSID ", 671252726Srpaulo field_name, ssid->id, txt); 672189251Ssam if (len < 0 || (size_t) len >= buflen) { 673189251Ssam os_free(buf); 674189251Ssam return; 675189251Ssam } 676189251Ssam if (ssid->ssid && buflen > len + ssid->ssid_len) { 677189251Ssam os_memcpy(buf + len, ssid->ssid, ssid->ssid_len); 678189251Ssam len += ssid->ssid_len; 679189251Ssam buf[len] = '\0'; 680189251Ssam } 681189251Ssam buf[buflen - 1] = '\0'; 682189251Ssam wpa_msg(wpa_s, MSG_INFO, "%s", buf); 683189251Ssam os_free(buf); 684189251Ssam} 685189251Ssam#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ 686189251Ssam#define wpa_supplicant_eap_param_needed NULL 687189251Ssam#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ 688189251Ssam 689189251Ssam 690214734Srpaulostatic void wpa_supplicant_port_cb(void *ctx, int authorized) 691214734Srpaulo{ 692214734Srpaulo struct wpa_supplicant *wpa_s = ctx; 693214734Srpaulo#ifdef CONFIG_AP 694214734Srpaulo if (wpa_s->ap_iface) { 695214734Srpaulo wpa_printf(MSG_DEBUG, "AP mode active - skip EAPOL Supplicant " 696214734Srpaulo "port status: %s", 697214734Srpaulo authorized ? "Authorized" : "Unauthorized"); 698214734Srpaulo return; 699214734Srpaulo } 700214734Srpaulo#endif /* CONFIG_AP */ 701214734Srpaulo wpa_printf(MSG_DEBUG, "EAPOL: Supplicant port status: %s", 702214734Srpaulo authorized ? "Authorized" : "Unauthorized"); 703214734Srpaulo wpa_drv_set_supp_port(wpa_s, authorized); 704214734Srpaulo} 705252726Srpaulo 706252726Srpaulo 707252726Srpaulostatic void wpa_supplicant_cert_cb(void *ctx, int depth, const char *subject, 708252726Srpaulo const char *cert_hash, 709252726Srpaulo const struct wpabuf *cert) 710252726Srpaulo{ 711252726Srpaulo struct wpa_supplicant *wpa_s = ctx; 712252726Srpaulo 713252726Srpaulo wpas_notify_certification(wpa_s, depth, subject, cert_hash, cert); 714252726Srpaulo} 715252726Srpaulo 716252726Srpaulo 717252726Srpaulostatic void wpa_supplicant_status_cb(void *ctx, const char *status, 718252726Srpaulo const char *parameter) 719252726Srpaulo{ 720252726Srpaulo struct wpa_supplicant *wpa_s = ctx; 721252726Srpaulo 722252726Srpaulo wpas_notify_eap_status(wpa_s, status, parameter); 723252726Srpaulo} 724252726Srpaulo 725252726Srpaulo 726252726Srpaulostatic void wpa_supplicant_set_anon_id(void *ctx, const u8 *id, size_t len) 727252726Srpaulo{ 728252726Srpaulo struct wpa_supplicant *wpa_s = ctx; 729252726Srpaulo char *str; 730252726Srpaulo int res; 731252726Srpaulo 732252726Srpaulo wpa_hexdump_ascii(MSG_DEBUG, "EAP method updated anonymous_identity", 733252726Srpaulo id, len); 734252726Srpaulo 735252726Srpaulo if (wpa_s->current_ssid == NULL) 736252726Srpaulo return; 737252726Srpaulo 738252726Srpaulo if (id == NULL) { 739252726Srpaulo if (wpa_config_set(wpa_s->current_ssid, "anonymous_identity", 740252726Srpaulo "NULL", 0) < 0) 741252726Srpaulo return; 742252726Srpaulo } else { 743252726Srpaulo str = os_malloc(len * 2 + 1); 744252726Srpaulo if (str == NULL) 745252726Srpaulo return; 746252726Srpaulo wpa_snprintf_hex(str, len * 2 + 1, id, len); 747252726Srpaulo res = wpa_config_set(wpa_s->current_ssid, "anonymous_identity", 748252726Srpaulo str, 0); 749252726Srpaulo os_free(str); 750252726Srpaulo if (res < 0) 751252726Srpaulo return; 752252726Srpaulo } 753252726Srpaulo 754252726Srpaulo if (wpa_s->conf->update_config) { 755252726Srpaulo res = wpa_config_write(wpa_s->confname, wpa_s->conf); 756252726Srpaulo if (res) { 757252726Srpaulo wpa_printf(MSG_DEBUG, "Failed to update config after " 758252726Srpaulo "anonymous_id update"); 759252726Srpaulo } 760252726Srpaulo } 761252726Srpaulo} 762214734Srpaulo#endif /* IEEE8021X_EAPOL */ 763214734Srpaulo 764214734Srpaulo 765189251Ssamint wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s) 766189251Ssam{ 767189251Ssam#ifdef IEEE8021X_EAPOL 768189251Ssam struct eapol_ctx *ctx; 769189251Ssam ctx = os_zalloc(sizeof(*ctx)); 770189251Ssam if (ctx == NULL) { 771189251Ssam wpa_printf(MSG_ERROR, "Failed to allocate EAPOL context."); 772189251Ssam return -1; 773189251Ssam } 774189251Ssam 775189251Ssam ctx->ctx = wpa_s; 776189251Ssam ctx->msg_ctx = wpa_s; 777189251Ssam ctx->eapol_send_ctx = wpa_s; 778189251Ssam ctx->preauth = 0; 779189251Ssam ctx->eapol_done_cb = wpa_supplicant_notify_eapol_done; 780189251Ssam ctx->eapol_send = wpa_supplicant_eapol_send; 781189251Ssam ctx->set_wep_key = wpa_eapol_set_wep_key; 782189251Ssam ctx->set_config_blob = wpa_supplicant_set_config_blob; 783189251Ssam ctx->get_config_blob = wpa_supplicant_get_config_blob; 784189251Ssam ctx->aborted_cached = wpa_supplicant_aborted_cached; 785189251Ssam ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path; 786189251Ssam ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path; 787189251Ssam ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path; 788189251Ssam ctx->wps = wpa_s->wps; 789189251Ssam ctx->eap_param_needed = wpa_supplicant_eap_param_needed; 790214734Srpaulo ctx->port_cb = wpa_supplicant_port_cb; 791189251Ssam ctx->cb = wpa_supplicant_eapol_cb; 792252726Srpaulo ctx->cert_cb = wpa_supplicant_cert_cb; 793252726Srpaulo ctx->status_cb = wpa_supplicant_status_cb; 794252726Srpaulo ctx->set_anon_id = wpa_supplicant_set_anon_id; 795189251Ssam ctx->cb_ctx = wpa_s; 796189251Ssam wpa_s->eapol = eapol_sm_init(ctx); 797189251Ssam if (wpa_s->eapol == NULL) { 798189251Ssam os_free(ctx); 799189251Ssam wpa_printf(MSG_ERROR, "Failed to initialize EAPOL state " 800189251Ssam "machines."); 801189251Ssam return -1; 802189251Ssam } 803189251Ssam#endif /* IEEE8021X_EAPOL */ 804189251Ssam 805189251Ssam return 0; 806189251Ssam} 807189251Ssam 808189251Ssam 809252726Srpaulo#ifndef CONFIG_NO_WPA 810252726Srpaulostatic void wpa_supplicant_set_rekey_offload(void *ctx, const u8 *kek, 811252726Srpaulo const u8 *kck, 812252726Srpaulo const u8 *replay_ctr) 813252726Srpaulo{ 814252726Srpaulo struct wpa_supplicant *wpa_s = ctx; 815252726Srpaulo 816252726Srpaulo wpa_drv_set_rekey_info(wpa_s, kek, kck, replay_ctr); 817252726Srpaulo} 818252726Srpaulo#endif /* CONFIG_NO_WPA */ 819252726Srpaulo 820252726Srpaulo 821189251Ssamint wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s) 822189251Ssam{ 823189251Ssam#ifndef CONFIG_NO_WPA 824189251Ssam struct wpa_sm_ctx *ctx; 825189251Ssam ctx = os_zalloc(sizeof(*ctx)); 826189251Ssam if (ctx == NULL) { 827189251Ssam wpa_printf(MSG_ERROR, "Failed to allocate WPA context."); 828189251Ssam return -1; 829189251Ssam } 830189251Ssam 831189251Ssam ctx->ctx = wpa_s; 832214734Srpaulo ctx->msg_ctx = wpa_s; 833189251Ssam ctx->set_state = _wpa_supplicant_set_state; 834189251Ssam ctx->get_state = _wpa_supplicant_get_state; 835189251Ssam ctx->deauthenticate = _wpa_supplicant_deauthenticate; 836189251Ssam ctx->set_key = wpa_supplicant_set_key; 837189251Ssam ctx->get_network_ctx = wpa_supplicant_get_network_ctx; 838189251Ssam ctx->get_bssid = wpa_supplicant_get_bssid; 839189251Ssam ctx->ether_send = _wpa_ether_send; 840189251Ssam ctx->get_beacon_ie = wpa_supplicant_get_beacon_ie; 841189251Ssam ctx->alloc_eapol = _wpa_alloc_eapol; 842189251Ssam ctx->cancel_auth_timeout = _wpa_supplicant_cancel_auth_timeout; 843189251Ssam ctx->add_pmkid = wpa_supplicant_add_pmkid; 844189251Ssam ctx->remove_pmkid = wpa_supplicant_remove_pmkid; 845189251Ssam#ifndef CONFIG_NO_CONFIG_BLOBS 846189251Ssam ctx->set_config_blob = wpa_supplicant_set_config_blob; 847189251Ssam ctx->get_config_blob = wpa_supplicant_get_config_blob; 848189251Ssam#endif /* CONFIG_NO_CONFIG_BLOBS */ 849189251Ssam ctx->mlme_setprotection = wpa_supplicant_mlme_setprotection; 850189251Ssam#ifdef CONFIG_IEEE80211R 851189251Ssam ctx->update_ft_ies = wpa_supplicant_update_ft_ies; 852189251Ssam ctx->send_ft_action = wpa_supplicant_send_ft_action; 853214734Srpaulo ctx->mark_authenticated = wpa_supplicant_mark_authenticated; 854189251Ssam#endif /* CONFIG_IEEE80211R */ 855252726Srpaulo#ifdef CONFIG_TDLS 856252726Srpaulo ctx->tdls_get_capa = wpa_supplicant_tdls_get_capa; 857252726Srpaulo ctx->send_tdls_mgmt = wpa_supplicant_send_tdls_mgmt; 858252726Srpaulo ctx->tdls_oper = wpa_supplicant_tdls_oper; 859252726Srpaulo ctx->tdls_peer_addset = wpa_supplicant_tdls_peer_addset; 860252726Srpaulo#endif /* CONFIG_TDLS */ 861252726Srpaulo ctx->set_rekey_offload = wpa_supplicant_set_rekey_offload; 862189251Ssam 863189251Ssam wpa_s->wpa = wpa_sm_init(ctx); 864189251Ssam if (wpa_s->wpa == NULL) { 865189251Ssam wpa_printf(MSG_ERROR, "Failed to initialize WPA state " 866189251Ssam "machine"); 867189251Ssam return -1; 868189251Ssam } 869189251Ssam#endif /* CONFIG_NO_WPA */ 870189251Ssam 871189251Ssam return 0; 872189251Ssam} 873189251Ssam 874189251Ssam 875189251Ssamvoid wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s, 876189251Ssam struct wpa_ssid *ssid) 877189251Ssam{ 878189251Ssam struct rsn_supp_config conf; 879189251Ssam if (ssid) { 880189251Ssam os_memset(&conf, 0, sizeof(conf)); 881189251Ssam conf.network_ctx = ssid; 882189251Ssam conf.peerkey_enabled = ssid->peerkey; 883189251Ssam conf.allowed_pairwise_cipher = ssid->pairwise_cipher; 884189251Ssam#ifdef IEEE8021X_EAPOL 885252726Srpaulo conf.proactive_key_caching = ssid->proactive_key_caching < 0 ? 886252726Srpaulo wpa_s->conf->okc : ssid->proactive_key_caching; 887189251Ssam conf.eap_workaround = ssid->eap_workaround; 888189251Ssam conf.eap_conf_ctx = &ssid->eap; 889189251Ssam#endif /* IEEE8021X_EAPOL */ 890189251Ssam conf.ssid = ssid->ssid; 891189251Ssam conf.ssid_len = ssid->ssid_len; 892189251Ssam conf.wpa_ptk_rekey = ssid->wpa_ptk_rekey; 893189251Ssam } 894189251Ssam wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL); 895189251Ssam} 896