1214501Srpaulo/* 2214501Srpaulo * hostapd / IEEE 802.1X-2004 Authenticator 3346981Scy * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7214501Srpaulo */ 8214501Srpaulo 9214501Srpaulo#include "utils/includes.h" 10351611Scy#ifdef CONFIG_SQLITE 11351611Scy#include <sqlite3.h> 12351611Scy#endif /* CONFIG_SQLITE */ 13214501Srpaulo 14214501Srpaulo#include "utils/common.h" 15214501Srpaulo#include "utils/eloop.h" 16214501Srpaulo#include "crypto/md5.h" 17214501Srpaulo#include "crypto/crypto.h" 18252726Srpaulo#include "crypto/random.h" 19214501Srpaulo#include "common/ieee802_11_defs.h" 20214501Srpaulo#include "radius/radius.h" 21214501Srpaulo#include "radius/radius_client.h" 22214501Srpaulo#include "eap_server/eap.h" 23214501Srpaulo#include "eap_common/eap_wsc_common.h" 24214501Srpaulo#include "eapol_auth/eapol_auth_sm.h" 25214501Srpaulo#include "eapol_auth/eapol_auth_sm_i.h" 26252726Srpaulo#include "p2p/p2p.h" 27214501Srpaulo#include "hostapd.h" 28214501Srpaulo#include "accounting.h" 29214501Srpaulo#include "sta_info.h" 30214501Srpaulo#include "wpa_auth.h" 31214501Srpaulo#include "preauth_auth.h" 32214501Srpaulo#include "pmksa_cache_auth.h" 33214501Srpaulo#include "ap_config.h" 34252726Srpaulo#include "ap_drv_ops.h" 35281806Srpaulo#include "wps_hostapd.h" 36281806Srpaulo#include "hs20.h" 37346981Scy/* FIX: Not really a good thing to require ieee802_11.h here.. (FILS) */ 38346981Scy#include "ieee802_11.h" 39214501Srpaulo#include "ieee802_1x.h" 40351611Scy#include "wpa_auth_kay.h" 41214501Srpaulo 42214501Srpaulo 43337817Scy#ifdef CONFIG_HS20 44337817Scystatic void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx); 45337817Scy#endif /* CONFIG_HS20 */ 46214501Srpaulostatic void ieee802_1x_finished(struct hostapd_data *hapd, 47281806Srpaulo struct sta_info *sta, int success, 48281806Srpaulo int remediation); 49214501Srpaulo 50214501Srpaulo 51214501Srpaulostatic void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta, 52214501Srpaulo u8 type, const u8 *data, size_t datalen) 53214501Srpaulo{ 54214501Srpaulo u8 *buf; 55214501Srpaulo struct ieee802_1x_hdr *xhdr; 56214501Srpaulo size_t len; 57214501Srpaulo int encrypt = 0; 58214501Srpaulo 59214501Srpaulo len = sizeof(*xhdr) + datalen; 60214501Srpaulo buf = os_zalloc(len); 61214501Srpaulo if (buf == NULL) { 62214501Srpaulo wpa_printf(MSG_ERROR, "malloc() failed for " 63214501Srpaulo "ieee802_1x_send(len=%lu)", 64214501Srpaulo (unsigned long) len); 65214501Srpaulo return; 66214501Srpaulo } 67214501Srpaulo 68214501Srpaulo xhdr = (struct ieee802_1x_hdr *) buf; 69214501Srpaulo xhdr->version = hapd->conf->eapol_version; 70351611Scy#ifdef CONFIG_MACSEC 71351611Scy if (xhdr->version > 2 && hapd->conf->macsec_policy == 0) 72351611Scy xhdr->version = 2; 73351611Scy#endif /* CONFIG_MACSEC */ 74214501Srpaulo xhdr->type = type; 75214501Srpaulo xhdr->length = host_to_be16(datalen); 76214501Srpaulo 77214501Srpaulo if (datalen > 0 && data != NULL) 78214501Srpaulo os_memcpy(xhdr + 1, data, datalen); 79214501Srpaulo 80214501Srpaulo if (wpa_auth_pairwise_set(sta->wpa_sm)) 81214501Srpaulo encrypt = 1; 82281806Srpaulo#ifdef CONFIG_TESTING_OPTIONS 83281806Srpaulo if (hapd->ext_eapol_frame_io) { 84281806Srpaulo size_t hex_len = 2 * len + 1; 85281806Srpaulo char *hex = os_malloc(hex_len); 86281806Srpaulo 87281806Srpaulo if (hex) { 88281806Srpaulo wpa_snprintf_hex(hex, hex_len, buf, len); 89281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, 90281806Srpaulo "EAPOL-TX " MACSTR " %s", 91281806Srpaulo MAC2STR(sta->addr), hex); 92281806Srpaulo os_free(hex); 93281806Srpaulo } 94281806Srpaulo } else 95281806Srpaulo#endif /* CONFIG_TESTING_OPTIONS */ 96214501Srpaulo if (sta->flags & WLAN_STA_PREAUTH) { 97214501Srpaulo rsn_preauth_send(hapd, sta, buf, len); 98214501Srpaulo } else { 99252726Srpaulo hostapd_drv_hapd_send_eapol( 100252726Srpaulo hapd, sta->addr, buf, len, 101252726Srpaulo encrypt, hostapd_sta_flags_to_drv(sta->flags)); 102214501Srpaulo } 103214501Srpaulo 104214501Srpaulo os_free(buf); 105214501Srpaulo} 106214501Srpaulo 107214501Srpaulo 108214501Srpaulovoid ieee802_1x_set_sta_authorized(struct hostapd_data *hapd, 109214501Srpaulo struct sta_info *sta, int authorized) 110214501Srpaulo{ 111214501Srpaulo int res; 112214501Srpaulo 113214501Srpaulo if (sta->flags & WLAN_STA_PREAUTH) 114214501Srpaulo return; 115214501Srpaulo 116214501Srpaulo if (authorized) { 117252726Srpaulo ap_sta_set_authorized(hapd, sta, 1); 118252726Srpaulo res = hostapd_set_authorized(hapd, sta, 1); 119214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 120214501Srpaulo HOSTAPD_LEVEL_DEBUG, "authorizing port"); 121214501Srpaulo } else { 122252726Srpaulo ap_sta_set_authorized(hapd, sta, 0); 123252726Srpaulo res = hostapd_set_authorized(hapd, sta, 0); 124214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 125214501Srpaulo HOSTAPD_LEVEL_DEBUG, "unauthorizing port"); 126214501Srpaulo } 127214501Srpaulo 128214501Srpaulo if (res && errno != ENOENT) { 129281806Srpaulo wpa_printf(MSG_DEBUG, "Could not set station " MACSTR 130281806Srpaulo " flags for kernel driver (errno=%d).", 131281806Srpaulo MAC2STR(sta->addr), errno); 132214501Srpaulo } 133214501Srpaulo 134252726Srpaulo if (authorized) { 135281806Srpaulo os_get_reltime(&sta->connected_time); 136214501Srpaulo accounting_sta_start(hapd, sta); 137252726Srpaulo } 138214501Srpaulo} 139214501Srpaulo 140214501Srpaulo 141289549Srpaulo#ifndef CONFIG_FIPS 142289549Srpaulo#ifndef CONFIG_NO_RC4 143289549Srpaulo 144214501Srpaulostatic void ieee802_1x_tx_key_one(struct hostapd_data *hapd, 145214501Srpaulo struct sta_info *sta, 146214501Srpaulo int idx, int broadcast, 147214501Srpaulo u8 *key_data, size_t key_len) 148214501Srpaulo{ 149214501Srpaulo u8 *buf, *ekey; 150214501Srpaulo struct ieee802_1x_hdr *hdr; 151214501Srpaulo struct ieee802_1x_eapol_key *key; 152214501Srpaulo size_t len, ekey_len; 153214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 154214501Srpaulo 155214501Srpaulo if (sm == NULL) 156214501Srpaulo return; 157214501Srpaulo 158214501Srpaulo len = sizeof(*key) + key_len; 159214501Srpaulo buf = os_zalloc(sizeof(*hdr) + len); 160214501Srpaulo if (buf == NULL) 161214501Srpaulo return; 162214501Srpaulo 163214501Srpaulo hdr = (struct ieee802_1x_hdr *) buf; 164214501Srpaulo key = (struct ieee802_1x_eapol_key *) (hdr + 1); 165214501Srpaulo key->type = EAPOL_KEY_TYPE_RC4; 166252726Srpaulo WPA_PUT_BE16(key->key_length, key_len); 167214501Srpaulo wpa_get_ntp_timestamp(key->replay_counter); 168351611Scy if (os_memcmp(key->replay_counter, 169351611Scy hapd->last_1x_eapol_key_replay_counter, 170351611Scy IEEE8021X_REPLAY_COUNTER_LEN) <= 0) { 171351611Scy /* NTP timestamp did not increment from last EAPOL-Key frame; 172351611Scy * use previously used value + 1 instead. */ 173351611Scy inc_byte_array(hapd->last_1x_eapol_key_replay_counter, 174351611Scy IEEE8021X_REPLAY_COUNTER_LEN); 175351611Scy os_memcpy(key->replay_counter, 176351611Scy hapd->last_1x_eapol_key_replay_counter, 177351611Scy IEEE8021X_REPLAY_COUNTER_LEN); 178351611Scy } else { 179351611Scy os_memcpy(hapd->last_1x_eapol_key_replay_counter, 180351611Scy key->replay_counter, 181351611Scy IEEE8021X_REPLAY_COUNTER_LEN); 182351611Scy } 183214501Srpaulo 184252726Srpaulo if (random_get_bytes(key->key_iv, sizeof(key->key_iv))) { 185214501Srpaulo wpa_printf(MSG_ERROR, "Could not get random numbers"); 186214501Srpaulo os_free(buf); 187214501Srpaulo return; 188214501Srpaulo } 189214501Srpaulo 190214501Srpaulo key->key_index = idx | (broadcast ? 0 : BIT(7)); 191214501Srpaulo if (hapd->conf->eapol_key_index_workaround) { 192214501Srpaulo /* According to some information, WinXP Supplicant seems to 193214501Srpaulo * interpret bit7 as an indication whether the key is to be 194214501Srpaulo * activated, so make it possible to enable workaround that 195214501Srpaulo * sets this bit for all keys. */ 196214501Srpaulo key->key_index |= BIT(7); 197214501Srpaulo } 198214501Srpaulo 199214501Srpaulo /* Key is encrypted using "Key-IV + MSK[0..31]" as the RC4-key and 200214501Srpaulo * MSK[32..63] is used to sign the message. */ 201214501Srpaulo if (sm->eap_if->eapKeyData == NULL || sm->eap_if->eapKeyDataLen < 64) { 202214501Srpaulo wpa_printf(MSG_ERROR, "No eapKeyData available for encrypting " 203214501Srpaulo "and signing EAPOL-Key"); 204214501Srpaulo os_free(buf); 205214501Srpaulo return; 206214501Srpaulo } 207214501Srpaulo os_memcpy((u8 *) (key + 1), key_data, key_len); 208214501Srpaulo ekey_len = sizeof(key->key_iv) + 32; 209214501Srpaulo ekey = os_malloc(ekey_len); 210214501Srpaulo if (ekey == NULL) { 211214501Srpaulo wpa_printf(MSG_ERROR, "Could not encrypt key"); 212214501Srpaulo os_free(buf); 213214501Srpaulo return; 214214501Srpaulo } 215214501Srpaulo os_memcpy(ekey, key->key_iv, sizeof(key->key_iv)); 216214501Srpaulo os_memcpy(ekey + sizeof(key->key_iv), sm->eap_if->eapKeyData, 32); 217214501Srpaulo rc4_skip(ekey, ekey_len, 0, (u8 *) (key + 1), key_len); 218214501Srpaulo os_free(ekey); 219214501Srpaulo 220214501Srpaulo /* This header is needed here for HMAC-MD5, but it will be regenerated 221214501Srpaulo * in ieee802_1x_send() */ 222214501Srpaulo hdr->version = hapd->conf->eapol_version; 223351611Scy#ifdef CONFIG_MACSEC 224351611Scy if (hdr->version > 2) 225351611Scy hdr->version = 2; 226351611Scy#endif /* CONFIG_MACSEC */ 227214501Srpaulo hdr->type = IEEE802_1X_TYPE_EAPOL_KEY; 228214501Srpaulo hdr->length = host_to_be16(len); 229214501Srpaulo hmac_md5(sm->eap_if->eapKeyData + 32, 32, buf, sizeof(*hdr) + len, 230214501Srpaulo key->key_signature); 231214501Srpaulo 232214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key to " MACSTR 233214501Srpaulo " (%s index=%d)", MAC2STR(sm->addr), 234214501Srpaulo broadcast ? "broadcast" : "unicast", idx); 235214501Srpaulo ieee802_1x_send(hapd, sta, IEEE802_1X_TYPE_EAPOL_KEY, (u8 *) key, len); 236214501Srpaulo if (sta->eapol_sm) 237214501Srpaulo sta->eapol_sm->dot1xAuthEapolFramesTx++; 238214501Srpaulo os_free(buf); 239214501Srpaulo} 240214501Srpaulo 241214501Srpaulo 242289549Srpaulostatic void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta) 243214501Srpaulo{ 244214501Srpaulo struct eapol_authenticator *eapol = hapd->eapol_auth; 245214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 246214501Srpaulo 247214501Srpaulo if (sm == NULL || !sm->eap_if->eapKeyData) 248214501Srpaulo return; 249214501Srpaulo 250214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key(s) to " MACSTR, 251214501Srpaulo MAC2STR(sta->addr)); 252214501Srpaulo 253214501Srpaulo#ifndef CONFIG_NO_VLAN 254337817Scy if (sta->vlan_id > 0) { 255281806Srpaulo wpa_printf(MSG_ERROR, "Using WEP with vlans is not supported."); 256281806Srpaulo return; 257281806Srpaulo } 258281806Srpaulo#endif /* CONFIG_NO_VLAN */ 259214501Srpaulo 260214501Srpaulo if (eapol->default_wep_key) { 261214501Srpaulo ieee802_1x_tx_key_one(hapd, sta, eapol->default_wep_key_idx, 1, 262214501Srpaulo eapol->default_wep_key, 263214501Srpaulo hapd->conf->default_wep_key_len); 264214501Srpaulo } 265214501Srpaulo 266214501Srpaulo if (hapd->conf->individual_wep_key_len > 0) { 267214501Srpaulo u8 *ikey; 268214501Srpaulo ikey = os_malloc(hapd->conf->individual_wep_key_len); 269214501Srpaulo if (ikey == NULL || 270252726Srpaulo random_get_bytes(ikey, hapd->conf->individual_wep_key_len)) 271252726Srpaulo { 272214501Srpaulo wpa_printf(MSG_ERROR, "Could not generate random " 273214501Srpaulo "individual WEP key."); 274214501Srpaulo os_free(ikey); 275214501Srpaulo return; 276214501Srpaulo } 277214501Srpaulo 278214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "Individual WEP key", 279214501Srpaulo ikey, hapd->conf->individual_wep_key_len); 280214501Srpaulo 281214501Srpaulo ieee802_1x_tx_key_one(hapd, sta, 0, 0, ikey, 282214501Srpaulo hapd->conf->individual_wep_key_len); 283214501Srpaulo 284214501Srpaulo /* TODO: set encryption in TX callback, i.e., only after STA 285214501Srpaulo * has ACKed EAPOL-Key frame */ 286252726Srpaulo if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, 287252726Srpaulo sta->addr, 0, 1, NULL, 0, ikey, 288252726Srpaulo hapd->conf->individual_wep_key_len)) { 289214501Srpaulo wpa_printf(MSG_ERROR, "Could not set individual WEP " 290214501Srpaulo "encryption."); 291214501Srpaulo } 292214501Srpaulo 293214501Srpaulo os_free(ikey); 294214501Srpaulo } 295214501Srpaulo} 296214501Srpaulo 297289549Srpaulo#endif /* CONFIG_NO_RC4 */ 298289549Srpaulo#endif /* CONFIG_FIPS */ 299214501Srpaulo 300289549Srpaulo 301214501Srpauloconst char *radius_mode_txt(struct hostapd_data *hapd) 302214501Srpaulo{ 303214501Srpaulo switch (hapd->iface->conf->hw_mode) { 304252726Srpaulo case HOSTAPD_MODE_IEEE80211AD: 305252726Srpaulo return "802.11ad"; 306214501Srpaulo case HOSTAPD_MODE_IEEE80211A: 307214501Srpaulo return "802.11a"; 308214501Srpaulo case HOSTAPD_MODE_IEEE80211G: 309214501Srpaulo return "802.11g"; 310214501Srpaulo case HOSTAPD_MODE_IEEE80211B: 311214501Srpaulo default: 312214501Srpaulo return "802.11b"; 313214501Srpaulo } 314214501Srpaulo} 315214501Srpaulo 316214501Srpaulo 317214501Srpauloint radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta) 318214501Srpaulo{ 319214501Srpaulo int i; 320214501Srpaulo u8 rate = 0; 321214501Srpaulo 322214501Srpaulo for (i = 0; i < sta->supported_rates_len; i++) 323214501Srpaulo if ((sta->supported_rates[i] & 0x7f) > rate) 324214501Srpaulo rate = sta->supported_rates[i] & 0x7f; 325214501Srpaulo 326214501Srpaulo return rate; 327214501Srpaulo} 328214501Srpaulo 329214501Srpaulo 330214501Srpaulo#ifndef CONFIG_NO_RADIUS 331214501Srpaulostatic void ieee802_1x_learn_identity(struct hostapd_data *hapd, 332214501Srpaulo struct eapol_state_machine *sm, 333214501Srpaulo const u8 *eap, size_t len) 334214501Srpaulo{ 335214501Srpaulo const u8 *identity; 336214501Srpaulo size_t identity_len; 337281806Srpaulo const struct eap_hdr *hdr = (const struct eap_hdr *) eap; 338214501Srpaulo 339214501Srpaulo if (len <= sizeof(struct eap_hdr) || 340281806Srpaulo (hdr->code == EAP_CODE_RESPONSE && 341281806Srpaulo eap[sizeof(struct eap_hdr)] != EAP_TYPE_IDENTITY) || 342281806Srpaulo (hdr->code == EAP_CODE_INITIATE && 343281806Srpaulo eap[sizeof(struct eap_hdr)] != EAP_ERP_TYPE_REAUTH) || 344281806Srpaulo (hdr->code != EAP_CODE_RESPONSE && 345281806Srpaulo hdr->code != EAP_CODE_INITIATE)) 346214501Srpaulo return; 347214501Srpaulo 348346981Scy eap_erp_update_identity(sm->eap, eap, len); 349214501Srpaulo identity = eap_get_identity(sm->eap, &identity_len); 350214501Srpaulo if (identity == NULL) 351214501Srpaulo return; 352214501Srpaulo 353214501Srpaulo /* Save station identity for future RADIUS packets */ 354214501Srpaulo os_free(sm->identity); 355281806Srpaulo sm->identity = (u8 *) dup_binstr(identity, identity_len); 356214501Srpaulo if (sm->identity == NULL) { 357214501Srpaulo sm->identity_len = 0; 358214501Srpaulo return; 359214501Srpaulo } 360214501Srpaulo 361214501Srpaulo sm->identity_len = identity_len; 362214501Srpaulo hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, 363214501Srpaulo HOSTAPD_LEVEL_DEBUG, "STA identity '%s'", sm->identity); 364214501Srpaulo sm->dot1xAuthEapolRespIdFramesRx++; 365214501Srpaulo} 366214501Srpaulo 367214501Srpaulo 368281806Srpaulostatic int add_common_radius_sta_attr_rsn(struct hostapd_data *hapd, 369281806Srpaulo struct hostapd_radius_attr *req_attr, 370281806Srpaulo struct sta_info *sta, 371281806Srpaulo struct radius_msg *msg) 372281806Srpaulo{ 373281806Srpaulo u32 suite; 374281806Srpaulo int ver, val; 375281806Srpaulo 376281806Srpaulo ver = wpa_auth_sta_wpa_version(sta->wpa_sm); 377281806Srpaulo val = wpa_auth_get_pairwise(sta->wpa_sm); 378281806Srpaulo suite = wpa_cipher_to_suite(ver, val); 379281806Srpaulo if (val != -1 && 380281806Srpaulo !hostapd_config_get_radius_attr(req_attr, 381281806Srpaulo RADIUS_ATTR_WLAN_PAIRWISE_CIPHER) && 382281806Srpaulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_PAIRWISE_CIPHER, 383281806Srpaulo suite)) { 384281806Srpaulo wpa_printf(MSG_ERROR, "Could not add WLAN-Pairwise-Cipher"); 385281806Srpaulo return -1; 386281806Srpaulo } 387281806Srpaulo 388289549Srpaulo suite = wpa_cipher_to_suite(((hapd->conf->wpa & 0x2) || 389289549Srpaulo hapd->conf->osen) ? 390281806Srpaulo WPA_PROTO_RSN : WPA_PROTO_WPA, 391281806Srpaulo hapd->conf->wpa_group); 392281806Srpaulo if (!hostapd_config_get_radius_attr(req_attr, 393281806Srpaulo RADIUS_ATTR_WLAN_GROUP_CIPHER) && 394281806Srpaulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_GROUP_CIPHER, 395281806Srpaulo suite)) { 396281806Srpaulo wpa_printf(MSG_ERROR, "Could not add WLAN-Group-Cipher"); 397281806Srpaulo return -1; 398281806Srpaulo } 399281806Srpaulo 400281806Srpaulo val = wpa_auth_sta_key_mgmt(sta->wpa_sm); 401281806Srpaulo suite = wpa_akm_to_suite(val); 402281806Srpaulo if (val != -1 && 403281806Srpaulo !hostapd_config_get_radius_attr(req_attr, 404281806Srpaulo RADIUS_ATTR_WLAN_AKM_SUITE) && 405281806Srpaulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_AKM_SUITE, 406281806Srpaulo suite)) { 407281806Srpaulo wpa_printf(MSG_ERROR, "Could not add WLAN-AKM-Suite"); 408281806Srpaulo return -1; 409281806Srpaulo } 410281806Srpaulo 411281806Srpaulo#ifdef CONFIG_IEEE80211W 412281806Srpaulo if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { 413281806Srpaulo suite = wpa_cipher_to_suite(WPA_PROTO_RSN, 414281806Srpaulo hapd->conf->group_mgmt_cipher); 415281806Srpaulo if (!hostapd_config_get_radius_attr( 416281806Srpaulo req_attr, RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER) && 417281806Srpaulo !radius_msg_add_attr_int32( 418281806Srpaulo msg, RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER, suite)) { 419281806Srpaulo wpa_printf(MSG_ERROR, 420281806Srpaulo "Could not add WLAN-Group-Mgmt-Cipher"); 421281806Srpaulo return -1; 422281806Srpaulo } 423281806Srpaulo } 424281806Srpaulo#endif /* CONFIG_IEEE80211W */ 425281806Srpaulo 426281806Srpaulo return 0; 427281806Srpaulo} 428281806Srpaulo 429281806Srpaulo 430252726Srpaulostatic int add_common_radius_sta_attr(struct hostapd_data *hapd, 431252726Srpaulo struct hostapd_radius_attr *req_attr, 432252726Srpaulo struct sta_info *sta, 433252726Srpaulo struct radius_msg *msg) 434252726Srpaulo{ 435252726Srpaulo char buf[128]; 436252726Srpaulo 437252726Srpaulo if (!hostapd_config_get_radius_attr(req_attr, 438337817Scy RADIUS_ATTR_SERVICE_TYPE) && 439337817Scy !radius_msg_add_attr_int32(msg, RADIUS_ATTR_SERVICE_TYPE, 440337817Scy RADIUS_SERVICE_TYPE_FRAMED)) { 441337817Scy wpa_printf(MSG_ERROR, "Could not add Service-Type"); 442337817Scy return -1; 443337817Scy } 444337817Scy 445337817Scy if (!hostapd_config_get_radius_attr(req_attr, 446252726Srpaulo RADIUS_ATTR_NAS_PORT) && 447337817Scy sta->aid > 0 && 448252726Srpaulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) { 449252726Srpaulo wpa_printf(MSG_ERROR, "Could not add NAS-Port"); 450252726Srpaulo return -1; 451252726Srpaulo } 452252726Srpaulo 453252726Srpaulo os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, 454252726Srpaulo MAC2STR(sta->addr)); 455252726Srpaulo buf[sizeof(buf) - 1] = '\0'; 456252726Srpaulo if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, 457252726Srpaulo (u8 *) buf, os_strlen(buf))) { 458252726Srpaulo wpa_printf(MSG_ERROR, "Could not add Calling-Station-Id"); 459252726Srpaulo return -1; 460252726Srpaulo } 461252726Srpaulo 462252726Srpaulo if (sta->flags & WLAN_STA_PREAUTH) { 463252726Srpaulo os_strlcpy(buf, "IEEE 802.11i Pre-Authentication", 464252726Srpaulo sizeof(buf)); 465252726Srpaulo } else { 466252726Srpaulo os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s", 467252726Srpaulo radius_sta_rate(hapd, sta) / 2, 468252726Srpaulo (radius_sta_rate(hapd, sta) & 1) ? ".5" : "", 469252726Srpaulo radius_mode_txt(hapd)); 470252726Srpaulo buf[sizeof(buf) - 1] = '\0'; 471252726Srpaulo } 472252726Srpaulo if (!hostapd_config_get_radius_attr(req_attr, 473252726Srpaulo RADIUS_ATTR_CONNECT_INFO) && 474252726Srpaulo !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, 475252726Srpaulo (u8 *) buf, os_strlen(buf))) { 476252726Srpaulo wpa_printf(MSG_ERROR, "Could not add Connect-Info"); 477252726Srpaulo return -1; 478252726Srpaulo } 479252726Srpaulo 480337817Scy if (sta->acct_session_id) { 481337817Scy os_snprintf(buf, sizeof(buf), "%016llX", 482337817Scy (unsigned long long) sta->acct_session_id); 483252726Srpaulo if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID, 484252726Srpaulo (u8 *) buf, os_strlen(buf))) { 485252726Srpaulo wpa_printf(MSG_ERROR, "Could not add Acct-Session-Id"); 486252726Srpaulo return -1; 487252726Srpaulo } 488252726Srpaulo } 489252726Srpaulo 490337817Scy if ((hapd->conf->wpa & 2) && 491337817Scy !hapd->conf->disable_pmksa_caching && 492337817Scy sta->eapol_sm && sta->eapol_sm->acct_multi_session_id) { 493337817Scy os_snprintf(buf, sizeof(buf), "%016llX", 494337817Scy (unsigned long long) 495337817Scy sta->eapol_sm->acct_multi_session_id); 496337817Scy if (!radius_msg_add_attr( 497337817Scy msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID, 498337817Scy (u8 *) buf, os_strlen(buf))) { 499337817Scy wpa_printf(MSG_INFO, 500337817Scy "Could not add Acct-Multi-Session-Id"); 501337817Scy return -1; 502337817Scy } 503337817Scy } 504337817Scy 505346981Scy#ifdef CONFIG_IEEE80211R_AP 506281806Srpaulo if (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) && 507281806Srpaulo sta->wpa_sm && 508281806Srpaulo (wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm)) || 509281806Srpaulo sta->auth_alg == WLAN_AUTH_FT) && 510281806Srpaulo !hostapd_config_get_radius_attr(req_attr, 511281806Srpaulo RADIUS_ATTR_MOBILITY_DOMAIN_ID) && 512281806Srpaulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_MOBILITY_DOMAIN_ID, 513281806Srpaulo WPA_GET_BE16( 514281806Srpaulo hapd->conf->mobility_domain))) { 515281806Srpaulo wpa_printf(MSG_ERROR, "Could not add Mobility-Domain-Id"); 516281806Srpaulo return -1; 517281806Srpaulo } 518346981Scy#endif /* CONFIG_IEEE80211R_AP */ 519281806Srpaulo 520289549Srpaulo if ((hapd->conf->wpa || hapd->conf->osen) && sta->wpa_sm && 521281806Srpaulo add_common_radius_sta_attr_rsn(hapd, req_attr, sta, msg) < 0) 522281806Srpaulo return -1; 523281806Srpaulo 524252726Srpaulo return 0; 525252726Srpaulo} 526252726Srpaulo 527252726Srpaulo 528252726Srpauloint add_common_radius_attr(struct hostapd_data *hapd, 529252726Srpaulo struct hostapd_radius_attr *req_attr, 530252726Srpaulo struct sta_info *sta, 531252726Srpaulo struct radius_msg *msg) 532252726Srpaulo{ 533252726Srpaulo char buf[128]; 534252726Srpaulo struct hostapd_radius_attr *attr; 535337817Scy int len; 536252726Srpaulo 537252726Srpaulo if (!hostapd_config_get_radius_attr(req_attr, 538252726Srpaulo RADIUS_ATTR_NAS_IP_ADDRESS) && 539252726Srpaulo hapd->conf->own_ip_addr.af == AF_INET && 540252726Srpaulo !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, 541252726Srpaulo (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) { 542252726Srpaulo wpa_printf(MSG_ERROR, "Could not add NAS-IP-Address"); 543252726Srpaulo return -1; 544252726Srpaulo } 545252726Srpaulo 546252726Srpaulo#ifdef CONFIG_IPV6 547252726Srpaulo if (!hostapd_config_get_radius_attr(req_attr, 548252726Srpaulo RADIUS_ATTR_NAS_IPV6_ADDRESS) && 549252726Srpaulo hapd->conf->own_ip_addr.af == AF_INET6 && 550252726Srpaulo !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS, 551252726Srpaulo (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) { 552252726Srpaulo wpa_printf(MSG_ERROR, "Could not add NAS-IPv6-Address"); 553252726Srpaulo return -1; 554252726Srpaulo } 555252726Srpaulo#endif /* CONFIG_IPV6 */ 556252726Srpaulo 557252726Srpaulo if (!hostapd_config_get_radius_attr(req_attr, 558252726Srpaulo RADIUS_ATTR_NAS_IDENTIFIER) && 559252726Srpaulo hapd->conf->nas_identifier && 560252726Srpaulo !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER, 561252726Srpaulo (u8 *) hapd->conf->nas_identifier, 562252726Srpaulo os_strlen(hapd->conf->nas_identifier))) { 563252726Srpaulo wpa_printf(MSG_ERROR, "Could not add NAS-Identifier"); 564252726Srpaulo return -1; 565252726Srpaulo } 566252726Srpaulo 567337817Scy len = os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":", 568337817Scy MAC2STR(hapd->own_addr)); 569337817Scy os_memcpy(&buf[len], hapd->conf->ssid.ssid, 570337817Scy hapd->conf->ssid.ssid_len); 571337817Scy len += hapd->conf->ssid.ssid_len; 572252726Srpaulo if (!hostapd_config_get_radius_attr(req_attr, 573252726Srpaulo RADIUS_ATTR_CALLED_STATION_ID) && 574252726Srpaulo !radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID, 575337817Scy (u8 *) buf, len)) { 576252726Srpaulo wpa_printf(MSG_ERROR, "Could not add Called-Station-Id"); 577252726Srpaulo return -1; 578252726Srpaulo } 579252726Srpaulo 580252726Srpaulo if (!hostapd_config_get_radius_attr(req_attr, 581252726Srpaulo RADIUS_ATTR_NAS_PORT_TYPE) && 582252726Srpaulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE, 583252726Srpaulo RADIUS_NAS_PORT_TYPE_IEEE_802_11)) { 584252726Srpaulo wpa_printf(MSG_ERROR, "Could not add NAS-Port-Type"); 585252726Srpaulo return -1; 586252726Srpaulo } 587252726Srpaulo 588281806Srpaulo#ifdef CONFIG_INTERWORKING 589281806Srpaulo if (hapd->conf->interworking && 590281806Srpaulo !is_zero_ether_addr(hapd->conf->hessid)) { 591281806Srpaulo os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, 592281806Srpaulo MAC2STR(hapd->conf->hessid)); 593281806Srpaulo buf[sizeof(buf) - 1] = '\0'; 594281806Srpaulo if (!hostapd_config_get_radius_attr(req_attr, 595281806Srpaulo RADIUS_ATTR_WLAN_HESSID) && 596281806Srpaulo !radius_msg_add_attr(msg, RADIUS_ATTR_WLAN_HESSID, 597281806Srpaulo (u8 *) buf, os_strlen(buf))) { 598281806Srpaulo wpa_printf(MSG_ERROR, "Could not add WLAN-HESSID"); 599281806Srpaulo return -1; 600281806Srpaulo } 601281806Srpaulo } 602281806Srpaulo#endif /* CONFIG_INTERWORKING */ 603281806Srpaulo 604252726Srpaulo if (sta && add_common_radius_sta_attr(hapd, req_attr, sta, msg) < 0) 605252726Srpaulo return -1; 606252726Srpaulo 607252726Srpaulo for (attr = req_attr; attr; attr = attr->next) { 608252726Srpaulo if (!radius_msg_add_attr(msg, attr->type, 609252726Srpaulo wpabuf_head(attr->val), 610252726Srpaulo wpabuf_len(attr->val))) { 611252726Srpaulo wpa_printf(MSG_ERROR, "Could not add RADIUS " 612252726Srpaulo "attribute"); 613252726Srpaulo return -1; 614252726Srpaulo } 615252726Srpaulo } 616252726Srpaulo 617252726Srpaulo return 0; 618252726Srpaulo} 619252726Srpaulo 620252726Srpaulo 621351611Scyint add_sqlite_radius_attr(struct hostapd_data *hapd, struct sta_info *sta, 622351611Scy struct radius_msg *msg, int acct) 623351611Scy{ 624351611Scy#ifdef CONFIG_SQLITE 625351611Scy const char *attrtxt; 626351611Scy char addrtxt[3 * ETH_ALEN]; 627351611Scy char *sql; 628351611Scy sqlite3_stmt *stmt = NULL; 629351611Scy 630351611Scy if (!hapd->rad_attr_db) 631351611Scy return 0; 632351611Scy 633351611Scy os_snprintf(addrtxt, sizeof(addrtxt), MACSTR, MAC2STR(sta->addr)); 634351611Scy 635351611Scy sql = "SELECT attr FROM radius_attributes WHERE sta=? AND (reqtype=? OR reqtype IS NULL);"; 636351611Scy if (sqlite3_prepare_v2(hapd->rad_attr_db, sql, os_strlen(sql), &stmt, 637351611Scy NULL) != SQLITE_OK) { 638351611Scy wpa_printf(MSG_ERROR, "DB: Failed to prepare SQL statement: %s", 639351611Scy sqlite3_errmsg(hapd->rad_attr_db)); 640351611Scy return -1; 641351611Scy } 642351611Scy sqlite3_bind_text(stmt, 1, addrtxt, os_strlen(addrtxt), SQLITE_STATIC); 643351611Scy sqlite3_bind_text(stmt, 2, acct ? "acct" : "auth", 4, SQLITE_STATIC); 644351611Scy while (sqlite3_step(stmt) == SQLITE_ROW) { 645351611Scy struct hostapd_radius_attr *attr; 646351611Scy struct radius_attr_hdr *hdr; 647351611Scy 648351611Scy attrtxt = (const char *) sqlite3_column_text(stmt, 0); 649351611Scy attr = hostapd_parse_radius_attr(attrtxt); 650351611Scy if (!attr) { 651351611Scy wpa_printf(MSG_ERROR, 652351611Scy "Skipping invalid attribute from SQL: %s", 653351611Scy attrtxt); 654351611Scy continue; 655351611Scy } 656351611Scy wpa_printf(MSG_DEBUG, "Adding RADIUS attribute from SQL: %s", 657351611Scy attrtxt); 658351611Scy hdr = radius_msg_add_attr(msg, attr->type, 659351611Scy wpabuf_head(attr->val), 660351611Scy wpabuf_len(attr->val)); 661351611Scy hostapd_config_free_radius_attr(attr); 662351611Scy if (!hdr) { 663351611Scy wpa_printf(MSG_ERROR, 664351611Scy "Could not add RADIUS attribute from SQL"); 665351611Scy continue; 666351611Scy } 667351611Scy } 668351611Scy 669351611Scy sqlite3_reset(stmt); 670351611Scy sqlite3_clear_bindings(stmt); 671351611Scy sqlite3_finalize(stmt); 672351611Scy#endif /* CONFIG_SQLITE */ 673351611Scy 674351611Scy return 0; 675351611Scy} 676351611Scy 677351611Scy 678346981Scyvoid ieee802_1x_encapsulate_radius(struct hostapd_data *hapd, 679346981Scy struct sta_info *sta, 680346981Scy const u8 *eap, size_t len) 681214501Srpaulo{ 682214501Srpaulo struct radius_msg *msg; 683214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 684214501Srpaulo 685214501Srpaulo if (sm == NULL) 686214501Srpaulo return; 687214501Srpaulo 688214501Srpaulo ieee802_1x_learn_identity(hapd, sm, eap, len); 689214501Srpaulo 690214501Srpaulo wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS " 691214501Srpaulo "packet"); 692214501Srpaulo 693214501Srpaulo sm->radius_identifier = radius_client_get_id(hapd->radius); 694214501Srpaulo msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, 695214501Srpaulo sm->radius_identifier); 696214501Srpaulo if (msg == NULL) { 697281806Srpaulo wpa_printf(MSG_INFO, "Could not create new RADIUS packet"); 698214501Srpaulo return; 699214501Srpaulo } 700214501Srpaulo 701337817Scy if (radius_msg_make_authenticator(msg) < 0) { 702337817Scy wpa_printf(MSG_INFO, "Could not make Request Authenticator"); 703337817Scy goto fail; 704337817Scy } 705214501Srpaulo 706214501Srpaulo if (sm->identity && 707214501Srpaulo !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, 708214501Srpaulo sm->identity, sm->identity_len)) { 709281806Srpaulo wpa_printf(MSG_INFO, "Could not add User-Name"); 710214501Srpaulo goto fail; 711214501Srpaulo } 712214501Srpaulo 713252726Srpaulo if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr, sta, 714252726Srpaulo msg) < 0) 715214501Srpaulo goto fail; 716214501Srpaulo 717351611Scy if (sta && add_sqlite_radius_attr(hapd, sta, msg, 0) < 0) 718351611Scy goto fail; 719351611Scy 720214501Srpaulo /* TODO: should probably check MTU from driver config; 2304 is max for 721214501Srpaulo * IEEE 802.11, but use 1400 to avoid problems with too large packets 722214501Srpaulo */ 723252726Srpaulo if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr, 724252726Srpaulo RADIUS_ATTR_FRAMED_MTU) && 725252726Srpaulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) { 726281806Srpaulo wpa_printf(MSG_INFO, "Could not add Framed-MTU"); 727214501Srpaulo goto fail; 728214501Srpaulo } 729214501Srpaulo 730289549Srpaulo if (!radius_msg_add_eap(msg, eap, len)) { 731281806Srpaulo wpa_printf(MSG_INFO, "Could not add EAP-Message"); 732214501Srpaulo goto fail; 733214501Srpaulo } 734214501Srpaulo 735214501Srpaulo /* State attribute must be copied if and only if this packet is 736214501Srpaulo * Access-Request reply to the previous Access-Challenge */ 737214501Srpaulo if (sm->last_recv_radius && 738214501Srpaulo radius_msg_get_hdr(sm->last_recv_radius)->code == 739214501Srpaulo RADIUS_CODE_ACCESS_CHALLENGE) { 740214501Srpaulo int res = radius_msg_copy_attr(msg, sm->last_recv_radius, 741214501Srpaulo RADIUS_ATTR_STATE); 742214501Srpaulo if (res < 0) { 743281806Srpaulo wpa_printf(MSG_INFO, "Could not copy State attribute from previous Access-Challenge"); 744214501Srpaulo goto fail; 745214501Srpaulo } 746214501Srpaulo if (res > 0) { 747214501Srpaulo wpa_printf(MSG_DEBUG, "Copied RADIUS State Attribute"); 748214501Srpaulo } 749214501Srpaulo } 750214501Srpaulo 751252726Srpaulo if (hapd->conf->radius_request_cui) { 752252726Srpaulo const u8 *cui; 753252726Srpaulo size_t cui_len; 754252726Srpaulo /* Add previously learned CUI or nul CUI to request CUI */ 755252726Srpaulo if (sm->radius_cui) { 756252726Srpaulo cui = wpabuf_head(sm->radius_cui); 757252726Srpaulo cui_len = wpabuf_len(sm->radius_cui); 758252726Srpaulo } else { 759252726Srpaulo cui = (const u8 *) "\0"; 760252726Srpaulo cui_len = 1; 761252726Srpaulo } 762252726Srpaulo if (!radius_msg_add_attr(msg, 763252726Srpaulo RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, 764252726Srpaulo cui, cui_len)) { 765252726Srpaulo wpa_printf(MSG_ERROR, "Could not add CUI"); 766252726Srpaulo goto fail; 767252726Srpaulo } 768252726Srpaulo } 769252726Srpaulo 770281806Srpaulo#ifdef CONFIG_HS20 771281806Srpaulo if (hapd->conf->hs20) { 772346981Scy u8 ver = hapd->conf->hs20_release - 1; 773346981Scy 774281806Srpaulo if (!radius_msg_add_wfa( 775281806Srpaulo msg, RADIUS_VENDOR_ATTR_WFA_HS20_AP_VERSION, 776281806Srpaulo &ver, 1)) { 777281806Srpaulo wpa_printf(MSG_ERROR, "Could not add HS 2.0 AP " 778281806Srpaulo "version"); 779281806Srpaulo goto fail; 780281806Srpaulo } 781281806Srpaulo 782281806Srpaulo if (sta->hs20_ie && wpabuf_len(sta->hs20_ie) > 0) { 783281806Srpaulo const u8 *pos; 784281806Srpaulo u8 buf[3]; 785281806Srpaulo u16 id; 786281806Srpaulo pos = wpabuf_head_u8(sta->hs20_ie); 787281806Srpaulo buf[0] = (*pos) >> 4; 788281806Srpaulo if (((*pos) & HS20_PPS_MO_ID_PRESENT) && 789281806Srpaulo wpabuf_len(sta->hs20_ie) >= 3) 790281806Srpaulo id = WPA_GET_LE16(pos + 1); 791281806Srpaulo else 792281806Srpaulo id = 0; 793281806Srpaulo WPA_PUT_BE16(buf + 1, id); 794281806Srpaulo if (!radius_msg_add_wfa( 795281806Srpaulo msg, 796281806Srpaulo RADIUS_VENDOR_ATTR_WFA_HS20_STA_VERSION, 797281806Srpaulo buf, sizeof(buf))) { 798281806Srpaulo wpa_printf(MSG_ERROR, "Could not add HS 2.0 " 799281806Srpaulo "STA version"); 800281806Srpaulo goto fail; 801281806Srpaulo } 802281806Srpaulo } 803346981Scy 804346981Scy if (sta->roaming_consortium && 805346981Scy !radius_msg_add_wfa( 806346981Scy msg, RADIUS_VENDOR_ATTR_WFA_HS20_ROAMING_CONSORTIUM, 807346981Scy wpabuf_head(sta->roaming_consortium), 808346981Scy wpabuf_len(sta->roaming_consortium))) { 809346981Scy wpa_printf(MSG_ERROR, 810346981Scy "Could not add HS 2.0 Roaming Consortium"); 811346981Scy goto fail; 812346981Scy } 813346981Scy 814346981Scy if (hapd->conf->t_c_filename) { 815346981Scy be32 timestamp; 816346981Scy 817346981Scy if (!radius_msg_add_wfa( 818346981Scy msg, 819346981Scy RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILENAME, 820346981Scy (const u8 *) hapd->conf->t_c_filename, 821346981Scy os_strlen(hapd->conf->t_c_filename))) { 822346981Scy wpa_printf(MSG_ERROR, 823346981Scy "Could not add HS 2.0 T&C Filename"); 824346981Scy goto fail; 825346981Scy } 826346981Scy 827346981Scy timestamp = host_to_be32(hapd->conf->t_c_timestamp); 828346981Scy if (!radius_msg_add_wfa( 829346981Scy msg, 830346981Scy RADIUS_VENDOR_ATTR_WFA_HS20_TIMESTAMP, 831346981Scy (const u8 *) ×tamp, 832346981Scy sizeof(timestamp))) { 833346981Scy wpa_printf(MSG_ERROR, 834346981Scy "Could not add HS 2.0 Timestamp"); 835346981Scy goto fail; 836346981Scy } 837346981Scy } 838281806Srpaulo } 839281806Srpaulo#endif /* CONFIG_HS20 */ 840281806Srpaulo 841252726Srpaulo if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr) < 0) 842252726Srpaulo goto fail; 843252726Srpaulo 844214501Srpaulo return; 845214501Srpaulo 846214501Srpaulo fail: 847214501Srpaulo radius_msg_free(msg); 848214501Srpaulo} 849214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 850214501Srpaulo 851214501Srpaulo 852214501Srpaulostatic void handle_eap_response(struct hostapd_data *hapd, 853214501Srpaulo struct sta_info *sta, struct eap_hdr *eap, 854214501Srpaulo size_t len) 855214501Srpaulo{ 856214501Srpaulo u8 type, *data; 857214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 858214501Srpaulo if (sm == NULL) 859214501Srpaulo return; 860214501Srpaulo 861214501Srpaulo data = (u8 *) (eap + 1); 862214501Srpaulo 863214501Srpaulo if (len < sizeof(*eap) + 1) { 864281806Srpaulo wpa_printf(MSG_INFO, "handle_eap_response: too short response data"); 865214501Srpaulo return; 866214501Srpaulo } 867214501Srpaulo 868214501Srpaulo sm->eap_type_supp = type = data[0]; 869214501Srpaulo 870214501Srpaulo hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, 871214501Srpaulo HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d " 872214501Srpaulo "id=%d len=%d) from STA: EAP Response-%s (%d)", 873214501Srpaulo eap->code, eap->identifier, be_to_host16(eap->length), 874214501Srpaulo eap_server_get_name(0, type), type); 875214501Srpaulo 876214501Srpaulo sm->dot1xAuthEapolRespFramesRx++; 877214501Srpaulo 878214501Srpaulo wpabuf_free(sm->eap_if->eapRespData); 879214501Srpaulo sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len); 880214501Srpaulo sm->eapolEap = TRUE; 881214501Srpaulo} 882214501Srpaulo 883214501Srpaulo 884281806Srpaulostatic void handle_eap_initiate(struct hostapd_data *hapd, 885281806Srpaulo struct sta_info *sta, struct eap_hdr *eap, 886281806Srpaulo size_t len) 887281806Srpaulo{ 888281806Srpaulo#ifdef CONFIG_ERP 889281806Srpaulo u8 type, *data; 890281806Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 891281806Srpaulo 892281806Srpaulo if (sm == NULL) 893281806Srpaulo return; 894281806Srpaulo 895281806Srpaulo if (len < sizeof(*eap) + 1) { 896281806Srpaulo wpa_printf(MSG_INFO, 897281806Srpaulo "handle_eap_initiate: too short response data"); 898281806Srpaulo return; 899281806Srpaulo } 900281806Srpaulo 901281806Srpaulo data = (u8 *) (eap + 1); 902281806Srpaulo type = data[0]; 903281806Srpaulo 904281806Srpaulo hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, 905281806Srpaulo HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d " 906281806Srpaulo "id=%d len=%d) from STA: EAP Initiate type %u", 907281806Srpaulo eap->code, eap->identifier, be_to_host16(eap->length), 908281806Srpaulo type); 909281806Srpaulo 910281806Srpaulo wpabuf_free(sm->eap_if->eapRespData); 911281806Srpaulo sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len); 912281806Srpaulo sm->eapolEap = TRUE; 913281806Srpaulo#endif /* CONFIG_ERP */ 914281806Srpaulo} 915281806Srpaulo 916281806Srpaulo 917214501Srpaulo/* Process incoming EAP packet from Supplicant */ 918214501Srpaulostatic void handle_eap(struct hostapd_data *hapd, struct sta_info *sta, 919214501Srpaulo u8 *buf, size_t len) 920214501Srpaulo{ 921214501Srpaulo struct eap_hdr *eap; 922214501Srpaulo u16 eap_len; 923214501Srpaulo 924214501Srpaulo if (len < sizeof(*eap)) { 925281806Srpaulo wpa_printf(MSG_INFO, " too short EAP packet"); 926214501Srpaulo return; 927214501Srpaulo } 928214501Srpaulo 929214501Srpaulo eap = (struct eap_hdr *) buf; 930214501Srpaulo 931214501Srpaulo eap_len = be_to_host16(eap->length); 932214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: code=%d identifier=%d length=%d", 933214501Srpaulo eap->code, eap->identifier, eap_len); 934214501Srpaulo if (eap_len < sizeof(*eap)) { 935214501Srpaulo wpa_printf(MSG_DEBUG, " Invalid EAP length"); 936214501Srpaulo return; 937214501Srpaulo } else if (eap_len > len) { 938214501Srpaulo wpa_printf(MSG_DEBUG, " Too short frame to contain this EAP " 939214501Srpaulo "packet"); 940214501Srpaulo return; 941214501Srpaulo } else if (eap_len < len) { 942214501Srpaulo wpa_printf(MSG_DEBUG, " Ignoring %lu extra bytes after EAP " 943214501Srpaulo "packet", (unsigned long) len - eap_len); 944214501Srpaulo } 945214501Srpaulo 946214501Srpaulo switch (eap->code) { 947214501Srpaulo case EAP_CODE_REQUEST: 948214501Srpaulo wpa_printf(MSG_DEBUG, " (request)"); 949214501Srpaulo return; 950214501Srpaulo case EAP_CODE_RESPONSE: 951214501Srpaulo wpa_printf(MSG_DEBUG, " (response)"); 952214501Srpaulo handle_eap_response(hapd, sta, eap, eap_len); 953214501Srpaulo break; 954214501Srpaulo case EAP_CODE_SUCCESS: 955214501Srpaulo wpa_printf(MSG_DEBUG, " (success)"); 956214501Srpaulo return; 957214501Srpaulo case EAP_CODE_FAILURE: 958214501Srpaulo wpa_printf(MSG_DEBUG, " (failure)"); 959214501Srpaulo return; 960281806Srpaulo case EAP_CODE_INITIATE: 961281806Srpaulo wpa_printf(MSG_DEBUG, " (initiate)"); 962281806Srpaulo handle_eap_initiate(hapd, sta, eap, eap_len); 963281806Srpaulo break; 964281806Srpaulo case EAP_CODE_FINISH: 965281806Srpaulo wpa_printf(MSG_DEBUG, " (finish)"); 966281806Srpaulo break; 967214501Srpaulo default: 968214501Srpaulo wpa_printf(MSG_DEBUG, " (unknown code)"); 969214501Srpaulo return; 970214501Srpaulo } 971214501Srpaulo} 972214501Srpaulo 973214501Srpaulo 974346981Scystruct eapol_state_machine * 975214501Srpauloieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta) 976214501Srpaulo{ 977214501Srpaulo int flags = 0; 978214501Srpaulo if (sta->flags & WLAN_STA_PREAUTH) 979214501Srpaulo flags |= EAPOL_SM_PREAUTH; 980214501Srpaulo if (sta->wpa_sm) { 981214501Srpaulo flags |= EAPOL_SM_USES_WPA; 982214501Srpaulo if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) 983214501Srpaulo flags |= EAPOL_SM_FROM_PMKSA_CACHE; 984214501Srpaulo } 985214501Srpaulo return eapol_auth_alloc(hapd->eapol_auth, sta->addr, flags, 986252726Srpaulo sta->wps_ie, sta->p2p_ie, sta, 987252726Srpaulo sta->identity, sta->radius_cui); 988214501Srpaulo} 989214501Srpaulo 990214501Srpaulo 991337817Scystatic void ieee802_1x_save_eapol(struct sta_info *sta, const u8 *buf, 992337817Scy size_t len) 993337817Scy{ 994337817Scy if (sta->pending_eapol_rx) { 995337817Scy wpabuf_free(sta->pending_eapol_rx->buf); 996337817Scy } else { 997337817Scy sta->pending_eapol_rx = 998337817Scy os_malloc(sizeof(*sta->pending_eapol_rx)); 999337817Scy if (!sta->pending_eapol_rx) 1000337817Scy return; 1001337817Scy } 1002337817Scy 1003337817Scy sta->pending_eapol_rx->buf = wpabuf_alloc_copy(buf, len); 1004337817Scy if (!sta->pending_eapol_rx->buf) { 1005337817Scy os_free(sta->pending_eapol_rx); 1006337817Scy sta->pending_eapol_rx = NULL; 1007337817Scy return; 1008337817Scy } 1009337817Scy 1010337817Scy os_get_reltime(&sta->pending_eapol_rx->rx_time); 1011337817Scy} 1012337817Scy 1013337817Scy 1014214501Srpaulo/** 1015214501Srpaulo * ieee802_1x_receive - Process the EAPOL frames from the Supplicant 1016214501Srpaulo * @hapd: hostapd BSS data 1017214501Srpaulo * @sa: Source address (sender of the EAPOL frame) 1018214501Srpaulo * @buf: EAPOL frame 1019214501Srpaulo * @len: Length of buf in octets 1020214501Srpaulo * 1021214501Srpaulo * This function is called for each incoming EAPOL frame from the interface 1022214501Srpaulo */ 1023214501Srpaulovoid ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, 1024214501Srpaulo size_t len) 1025214501Srpaulo{ 1026214501Srpaulo struct sta_info *sta; 1027214501Srpaulo struct ieee802_1x_hdr *hdr; 1028214501Srpaulo struct ieee802_1x_eapol_key *key; 1029214501Srpaulo u16 datalen; 1030214501Srpaulo struct rsn_pmksa_cache_entry *pmksa; 1031252726Srpaulo int key_mgmt; 1032214501Srpaulo 1033281806Srpaulo if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->osen && 1034214501Srpaulo !hapd->conf->wps_state) 1035214501Srpaulo return; 1036214501Srpaulo 1037214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR, 1038214501Srpaulo (unsigned long) len, MAC2STR(sa)); 1039214501Srpaulo sta = ap_get_sta(hapd, sa); 1040252726Srpaulo if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) && 1041252726Srpaulo !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) { 1042214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not " 1043252726Srpaulo "associated/Pre-authenticating STA"); 1044337817Scy 1045337817Scy if (sta && (sta->flags & WLAN_STA_AUTH)) { 1046337817Scy wpa_printf(MSG_DEBUG, "Saving EAPOL frame from " MACSTR 1047337817Scy " for later use", MAC2STR(sta->addr)); 1048337817Scy ieee802_1x_save_eapol(sta, buf, len); 1049337817Scy } 1050337817Scy 1051214501Srpaulo return; 1052214501Srpaulo } 1053214501Srpaulo 1054214501Srpaulo if (len < sizeof(*hdr)) { 1055281806Srpaulo wpa_printf(MSG_INFO, " too short IEEE 802.1X packet"); 1056214501Srpaulo return; 1057214501Srpaulo } 1058214501Srpaulo 1059214501Srpaulo hdr = (struct ieee802_1x_hdr *) buf; 1060214501Srpaulo datalen = be_to_host16(hdr->length); 1061214501Srpaulo wpa_printf(MSG_DEBUG, " IEEE 802.1X: version=%d type=%d length=%d", 1062214501Srpaulo hdr->version, hdr->type, datalen); 1063214501Srpaulo 1064214501Srpaulo if (len - sizeof(*hdr) < datalen) { 1065281806Srpaulo wpa_printf(MSG_INFO, " frame too short for this IEEE 802.1X packet"); 1066214501Srpaulo if (sta->eapol_sm) 1067214501Srpaulo sta->eapol_sm->dot1xAuthEapLengthErrorFramesRx++; 1068214501Srpaulo return; 1069214501Srpaulo } 1070214501Srpaulo if (len - sizeof(*hdr) > datalen) { 1071214501Srpaulo wpa_printf(MSG_DEBUG, " ignoring %lu extra octets after " 1072214501Srpaulo "IEEE 802.1X packet", 1073214501Srpaulo (unsigned long) len - sizeof(*hdr) - datalen); 1074214501Srpaulo } 1075214501Srpaulo 1076214501Srpaulo if (sta->eapol_sm) { 1077214501Srpaulo sta->eapol_sm->dot1xAuthLastEapolFrameVersion = hdr->version; 1078214501Srpaulo sta->eapol_sm->dot1xAuthEapolFramesRx++; 1079214501Srpaulo } 1080214501Srpaulo 1081214501Srpaulo key = (struct ieee802_1x_eapol_key *) (hdr + 1); 1082214501Srpaulo if (datalen >= sizeof(struct ieee802_1x_eapol_key) && 1083214501Srpaulo hdr->type == IEEE802_1X_TYPE_EAPOL_KEY && 1084214501Srpaulo (key->type == EAPOL_KEY_TYPE_WPA || 1085214501Srpaulo key->type == EAPOL_KEY_TYPE_RSN)) { 1086214501Srpaulo wpa_receive(hapd->wpa_auth, sta->wpa_sm, (u8 *) hdr, 1087214501Srpaulo sizeof(*hdr) + datalen); 1088214501Srpaulo return; 1089214501Srpaulo } 1090214501Srpaulo 1091281806Srpaulo if (!hapd->conf->ieee802_1x && !hapd->conf->osen && 1092252726Srpaulo !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) { 1093252726Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - " 1094252726Srpaulo "802.1X not enabled and WPS not used"); 1095214501Srpaulo return; 1096252726Srpaulo } 1097214501Srpaulo 1098252726Srpaulo key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm); 1099346981Scy if (key_mgmt != -1 && 1100346981Scy (wpa_key_mgmt_wpa_psk(key_mgmt) || key_mgmt == WPA_KEY_MGMT_OWE || 1101346981Scy key_mgmt == WPA_KEY_MGMT_DPP)) { 1102252726Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - " 1103252726Srpaulo "STA is using PSK"); 1104252726Srpaulo return; 1105252726Srpaulo } 1106252726Srpaulo 1107214501Srpaulo if (!sta->eapol_sm) { 1108214501Srpaulo sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta); 1109214501Srpaulo if (!sta->eapol_sm) 1110214501Srpaulo return; 1111214501Srpaulo 1112214501Srpaulo#ifdef CONFIG_WPS 1113281806Srpaulo if (!hapd->conf->ieee802_1x && hapd->conf->wps_state) { 1114252726Srpaulo u32 wflags = sta->flags & (WLAN_STA_WPS | 1115252726Srpaulo WLAN_STA_WPS2 | 1116252726Srpaulo WLAN_STA_MAYBE_WPS); 1117252726Srpaulo if (wflags == WLAN_STA_MAYBE_WPS || 1118252726Srpaulo wflags == (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) { 1119252726Srpaulo /* 1120252726Srpaulo * Delay EAPOL frame transmission until a 1121252726Srpaulo * possible WPS STA initiates the handshake 1122252726Srpaulo * with EAPOL-Start. Only allow the wait to be 1123252726Srpaulo * skipped if the STA is known to support WPS 1124252726Srpaulo * 2.0. 1125252726Srpaulo */ 1126252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Do not start " 1127252726Srpaulo "EAPOL until EAPOL-Start is " 1128252726Srpaulo "received"); 1129252726Srpaulo sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; 1130252726Srpaulo } 1131214501Srpaulo } 1132214501Srpaulo#endif /* CONFIG_WPS */ 1133214501Srpaulo 1134214501Srpaulo sta->eapol_sm->eap_if->portEnabled = TRUE; 1135214501Srpaulo } 1136214501Srpaulo 1137214501Srpaulo /* since we support version 1, we can ignore version field and proceed 1138214501Srpaulo * as specified in version 1 standard [IEEE Std 802.1X-2001, 7.5.5] */ 1139214501Srpaulo /* TODO: actually, we are not version 1 anymore.. However, Version 2 1140214501Srpaulo * does not change frame contents, so should be ok to process frames 1141214501Srpaulo * more or less identically. Some changes might be needed for 1142214501Srpaulo * verification of fields. */ 1143214501Srpaulo 1144214501Srpaulo switch (hdr->type) { 1145214501Srpaulo case IEEE802_1X_TYPE_EAP_PACKET: 1146214501Srpaulo handle_eap(hapd, sta, (u8 *) (hdr + 1), datalen); 1147214501Srpaulo break; 1148214501Srpaulo 1149214501Srpaulo case IEEE802_1X_TYPE_EAPOL_START: 1150214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1151214501Srpaulo HOSTAPD_LEVEL_DEBUG, "received EAPOL-Start " 1152214501Srpaulo "from STA"); 1153214501Srpaulo sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START; 1154214501Srpaulo pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm); 1155214501Srpaulo if (pmksa) { 1156214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, 1157214501Srpaulo HOSTAPD_LEVEL_DEBUG, "cached PMKSA " 1158214501Srpaulo "available - ignore it since " 1159214501Srpaulo "STA sent EAPOL-Start"); 1160214501Srpaulo wpa_auth_sta_clear_pmksa(sta->wpa_sm, pmksa); 1161214501Srpaulo } 1162214501Srpaulo sta->eapol_sm->eapolStart = TRUE; 1163214501Srpaulo sta->eapol_sm->dot1xAuthEapolStartFramesRx++; 1164252726Srpaulo eap_server_clear_identity(sta->eapol_sm->eap); 1165214501Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL); 1166214501Srpaulo break; 1167214501Srpaulo 1168214501Srpaulo case IEEE802_1X_TYPE_EAPOL_LOGOFF: 1169214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1170214501Srpaulo HOSTAPD_LEVEL_DEBUG, "received EAPOL-Logoff " 1171214501Srpaulo "from STA"); 1172214501Srpaulo sta->acct_terminate_cause = 1173214501Srpaulo RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; 1174214501Srpaulo accounting_sta_stop(hapd, sta); 1175214501Srpaulo sta->eapol_sm->eapolLogoff = TRUE; 1176214501Srpaulo sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++; 1177252726Srpaulo eap_server_clear_identity(sta->eapol_sm->eap); 1178214501Srpaulo break; 1179214501Srpaulo 1180214501Srpaulo case IEEE802_1X_TYPE_EAPOL_KEY: 1181214501Srpaulo wpa_printf(MSG_DEBUG, " EAPOL-Key"); 1182252726Srpaulo if (!ap_sta_is_authorized(sta)) { 1183214501Srpaulo wpa_printf(MSG_DEBUG, " Dropped key data from " 1184214501Srpaulo "unauthorized Supplicant"); 1185214501Srpaulo break; 1186214501Srpaulo } 1187214501Srpaulo break; 1188214501Srpaulo 1189214501Srpaulo case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT: 1190214501Srpaulo wpa_printf(MSG_DEBUG, " EAPOL-Encapsulated-ASF-Alert"); 1191214501Srpaulo /* TODO: implement support for this; show data */ 1192214501Srpaulo break; 1193214501Srpaulo 1194351611Scy#ifdef CONFIG_MACSEC 1195351611Scy case IEEE802_1X_TYPE_EAPOL_MKA: 1196351611Scy wpa_printf(MSG_EXCESSIVE, 1197351611Scy "EAPOL type %d will be handled by MKA", hdr->type); 1198351611Scy break; 1199351611Scy#endif /* CONFIG_MACSEC */ 1200351611Scy 1201214501Srpaulo default: 1202214501Srpaulo wpa_printf(MSG_DEBUG, " unknown IEEE 802.1X packet type"); 1203214501Srpaulo sta->eapol_sm->dot1xAuthInvalidEapolFramesRx++; 1204214501Srpaulo break; 1205214501Srpaulo } 1206214501Srpaulo 1207214501Srpaulo eapol_auth_step(sta->eapol_sm); 1208214501Srpaulo} 1209214501Srpaulo 1210214501Srpaulo 1211214501Srpaulo/** 1212214501Srpaulo * ieee802_1x_new_station - Start IEEE 802.1X authentication 1213214501Srpaulo * @hapd: hostapd BSS data 1214214501Srpaulo * @sta: The station 1215214501Srpaulo * 1216214501Srpaulo * This function is called to start IEEE 802.1X authentication when a new 1217214501Srpaulo * station completes IEEE 802.11 association. 1218214501Srpaulo */ 1219214501Srpaulovoid ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta) 1220214501Srpaulo{ 1221214501Srpaulo struct rsn_pmksa_cache_entry *pmksa; 1222214501Srpaulo int reassoc = 1; 1223214501Srpaulo int force_1x = 0; 1224252726Srpaulo int key_mgmt; 1225214501Srpaulo 1226214501Srpaulo#ifdef CONFIG_WPS 1227281806Srpaulo if (hapd->conf->wps_state && 1228281806Srpaulo ((hapd->conf->wpa && (sta->flags & WLAN_STA_MAYBE_WPS)) || 1229281806Srpaulo (sta->flags & WLAN_STA_WPS))) { 1230214501Srpaulo /* 1231214501Srpaulo * Need to enable IEEE 802.1X/EAPOL state machines for possible 1232214501Srpaulo * WPS handshake even if IEEE 802.1X/EAPOL is not used for 1233214501Srpaulo * authentication in this BSS. 1234214501Srpaulo */ 1235214501Srpaulo force_1x = 1; 1236214501Srpaulo } 1237214501Srpaulo#endif /* CONFIG_WPS */ 1238214501Srpaulo 1239281806Srpaulo if (!force_1x && !hapd->conf->ieee802_1x && !hapd->conf->osen) { 1240252726Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - " 1241252726Srpaulo "802.1X not enabled or forced for WPS"); 1242252726Srpaulo /* 1243252726Srpaulo * Clear any possible EAPOL authenticator state to support 1244252726Srpaulo * reassociation change from WPS to PSK. 1245252726Srpaulo */ 1246337817Scy ieee802_1x_free_station(hapd, sta); 1247214501Srpaulo return; 1248252726Srpaulo } 1249214501Srpaulo 1250252726Srpaulo key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm); 1251346981Scy if (key_mgmt != -1 && 1252346981Scy (wpa_key_mgmt_wpa_psk(key_mgmt) || key_mgmt == WPA_KEY_MGMT_OWE || 1253346981Scy key_mgmt == WPA_KEY_MGMT_DPP)) { 1254252726Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - using PSK"); 1255252726Srpaulo /* 1256252726Srpaulo * Clear any possible EAPOL authenticator state to support 1257252726Srpaulo * reassociation change from WPA-EAP to PSK. 1258252726Srpaulo */ 1259337817Scy ieee802_1x_free_station(hapd, sta); 1260252726Srpaulo return; 1261252726Srpaulo } 1262252726Srpaulo 1263214501Srpaulo if (sta->eapol_sm == NULL) { 1264214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1265214501Srpaulo HOSTAPD_LEVEL_DEBUG, "start authentication"); 1266214501Srpaulo sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta); 1267214501Srpaulo if (sta->eapol_sm == NULL) { 1268214501Srpaulo hostapd_logger(hapd, sta->addr, 1269214501Srpaulo HOSTAPD_MODULE_IEEE8021X, 1270214501Srpaulo HOSTAPD_LEVEL_INFO, 1271214501Srpaulo "failed to allocate state machine"); 1272214501Srpaulo return; 1273214501Srpaulo } 1274214501Srpaulo reassoc = 0; 1275214501Srpaulo } 1276214501Srpaulo 1277214501Srpaulo#ifdef CONFIG_WPS 1278214501Srpaulo sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START; 1279281806Srpaulo if (!hapd->conf->ieee802_1x && hapd->conf->wps_state && 1280281806Srpaulo !(sta->flags & WLAN_STA_WPS2)) { 1281214501Srpaulo /* 1282252726Srpaulo * Delay EAPOL frame transmission until a possible WPS STA 1283252726Srpaulo * initiates the handshake with EAPOL-Start. Only allow the 1284252726Srpaulo * wait to be skipped if the STA is known to support WPS 2.0. 1285214501Srpaulo */ 1286252726Srpaulo wpa_printf(MSG_DEBUG, "WPS: Do not start EAPOL until " 1287252726Srpaulo "EAPOL-Start is received"); 1288214501Srpaulo sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; 1289214501Srpaulo } 1290214501Srpaulo#endif /* CONFIG_WPS */ 1291214501Srpaulo 1292214501Srpaulo sta->eapol_sm->eap_if->portEnabled = TRUE; 1293214501Srpaulo 1294346981Scy#ifdef CONFIG_IEEE80211R_AP 1295252726Srpaulo if (sta->auth_alg == WLAN_AUTH_FT) { 1296252726Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1297252726Srpaulo HOSTAPD_LEVEL_DEBUG, 1298252726Srpaulo "PMK from FT - skip IEEE 802.1X/EAP"); 1299252726Srpaulo /* Setup EAPOL state machines to already authenticated state 1300252726Srpaulo * because of existing FT information from R0KH. */ 1301252726Srpaulo sta->eapol_sm->keyRun = TRUE; 1302252726Srpaulo sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; 1303252726Srpaulo sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; 1304252726Srpaulo sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; 1305252726Srpaulo sta->eapol_sm->authSuccess = TRUE; 1306252726Srpaulo sta->eapol_sm->authFail = FALSE; 1307337817Scy sta->eapol_sm->portValid = TRUE; 1308252726Srpaulo if (sta->eapol_sm->eap) 1309252726Srpaulo eap_sm_notify_cached(sta->eapol_sm->eap); 1310346981Scy ap_sta_bind_vlan(hapd, sta); 1311252726Srpaulo return; 1312252726Srpaulo } 1313346981Scy#endif /* CONFIG_IEEE80211R_AP */ 1314252726Srpaulo 1315346981Scy#ifdef CONFIG_FILS 1316346981Scy if (sta->auth_alg == WLAN_AUTH_FILS_SK || 1317346981Scy sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || 1318346981Scy sta->auth_alg == WLAN_AUTH_FILS_PK) { 1319346981Scy hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1320346981Scy HOSTAPD_LEVEL_DEBUG, 1321346981Scy "PMK from FILS - skip IEEE 802.1X/EAP"); 1322346981Scy /* Setup EAPOL state machines to already authenticated state 1323346981Scy * because of existing FILS information. */ 1324346981Scy sta->eapol_sm->keyRun = TRUE; 1325346981Scy sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; 1326346981Scy sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; 1327346981Scy sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; 1328346981Scy sta->eapol_sm->authSuccess = TRUE; 1329346981Scy sta->eapol_sm->authFail = FALSE; 1330346981Scy sta->eapol_sm->portValid = TRUE; 1331346981Scy if (sta->eapol_sm->eap) 1332346981Scy eap_sm_notify_cached(sta->eapol_sm->eap); 1333346981Scy wpa_auth_set_ptk_rekey_timer(sta->wpa_sm); 1334346981Scy return; 1335346981Scy } 1336346981Scy#endif /* CONFIG_FILS */ 1337346981Scy 1338214501Srpaulo pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm); 1339214501Srpaulo if (pmksa) { 1340214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1341214501Srpaulo HOSTAPD_LEVEL_DEBUG, 1342214501Srpaulo "PMK from PMKSA cache - skip IEEE 802.1X/EAP"); 1343214501Srpaulo /* Setup EAPOL state machines to already authenticated state 1344214501Srpaulo * because of existing PMKSA information in the cache. */ 1345214501Srpaulo sta->eapol_sm->keyRun = TRUE; 1346214501Srpaulo sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; 1347214501Srpaulo sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; 1348214501Srpaulo sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; 1349214501Srpaulo sta->eapol_sm->authSuccess = TRUE; 1350252726Srpaulo sta->eapol_sm->authFail = FALSE; 1351214501Srpaulo if (sta->eapol_sm->eap) 1352214501Srpaulo eap_sm_notify_cached(sta->eapol_sm->eap); 1353337817Scy pmksa_cache_to_eapol_data(hapd, pmksa, sta->eapol_sm); 1354289549Srpaulo ap_sta_bind_vlan(hapd, sta); 1355214501Srpaulo } else { 1356214501Srpaulo if (reassoc) { 1357214501Srpaulo /* 1358214501Srpaulo * Force EAPOL state machines to start 1359214501Srpaulo * re-authentication without having to wait for the 1360214501Srpaulo * Supplicant to send EAPOL-Start. 1361214501Srpaulo */ 1362214501Srpaulo sta->eapol_sm->reAuthenticate = TRUE; 1363214501Srpaulo } 1364214501Srpaulo eapol_auth_step(sta->eapol_sm); 1365214501Srpaulo } 1366214501Srpaulo} 1367214501Srpaulo 1368214501Srpaulo 1369337817Scyvoid ieee802_1x_free_station(struct hostapd_data *hapd, struct sta_info *sta) 1370214501Srpaulo{ 1371214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 1372214501Srpaulo 1373337817Scy#ifdef CONFIG_HS20 1374337817Scy eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta); 1375337817Scy#endif /* CONFIG_HS20 */ 1376337817Scy 1377337817Scy if (sta->pending_eapol_rx) { 1378337817Scy wpabuf_free(sta->pending_eapol_rx->buf); 1379337817Scy os_free(sta->pending_eapol_rx); 1380337817Scy sta->pending_eapol_rx = NULL; 1381337817Scy } 1382337817Scy 1383214501Srpaulo if (sm == NULL) 1384214501Srpaulo return; 1385214501Srpaulo 1386214501Srpaulo sta->eapol_sm = NULL; 1387214501Srpaulo 1388214501Srpaulo#ifndef CONFIG_NO_RADIUS 1389214501Srpaulo radius_msg_free(sm->last_recv_radius); 1390214501Srpaulo radius_free_class(&sm->radius_class); 1391214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 1392214501Srpaulo 1393214501Srpaulo eapol_auth_free(sm); 1394214501Srpaulo} 1395214501Srpaulo 1396214501Srpaulo 1397214501Srpaulo#ifndef CONFIG_NO_RADIUS 1398214501Srpaulostatic void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd, 1399214501Srpaulo struct sta_info *sta) 1400214501Srpaulo{ 1401252726Srpaulo struct wpabuf *eap; 1402252726Srpaulo const struct eap_hdr *hdr; 1403214501Srpaulo int eap_type = -1; 1404214501Srpaulo char buf[64]; 1405214501Srpaulo struct radius_msg *msg; 1406214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 1407214501Srpaulo 1408214501Srpaulo if (sm == NULL || sm->last_recv_radius == NULL) { 1409214501Srpaulo if (sm) 1410214501Srpaulo sm->eap_if->aaaEapNoReq = TRUE; 1411214501Srpaulo return; 1412214501Srpaulo } 1413214501Srpaulo 1414214501Srpaulo msg = sm->last_recv_radius; 1415214501Srpaulo 1416252726Srpaulo eap = radius_msg_get_eap(msg); 1417214501Srpaulo if (eap == NULL) { 1418214501Srpaulo /* RFC 3579, Chap. 2.6.3: 1419214501Srpaulo * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message 1420214501Srpaulo * attribute */ 1421214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1422214501Srpaulo HOSTAPD_LEVEL_WARNING, "could not extract " 1423214501Srpaulo "EAP-Message from RADIUS message"); 1424214501Srpaulo sm->eap_if->aaaEapNoReq = TRUE; 1425214501Srpaulo return; 1426214501Srpaulo } 1427214501Srpaulo 1428252726Srpaulo if (wpabuf_len(eap) < sizeof(*hdr)) { 1429214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1430214501Srpaulo HOSTAPD_LEVEL_WARNING, "too short EAP packet " 1431214501Srpaulo "received from authentication server"); 1432252726Srpaulo wpabuf_free(eap); 1433214501Srpaulo sm->eap_if->aaaEapNoReq = TRUE; 1434214501Srpaulo return; 1435214501Srpaulo } 1436214501Srpaulo 1437252726Srpaulo if (wpabuf_len(eap) > sizeof(*hdr)) 1438252726Srpaulo eap_type = (wpabuf_head_u8(eap))[sizeof(*hdr)]; 1439214501Srpaulo 1440252726Srpaulo hdr = wpabuf_head(eap); 1441214501Srpaulo switch (hdr->code) { 1442214501Srpaulo case EAP_CODE_REQUEST: 1443214501Srpaulo if (eap_type >= 0) 1444214501Srpaulo sm->eap_type_authsrv = eap_type; 1445214501Srpaulo os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)", 1446281806Srpaulo eap_server_get_name(0, eap_type), eap_type); 1447214501Srpaulo break; 1448214501Srpaulo case EAP_CODE_RESPONSE: 1449214501Srpaulo os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)", 1450281806Srpaulo eap_server_get_name(0, eap_type), eap_type); 1451214501Srpaulo break; 1452214501Srpaulo case EAP_CODE_SUCCESS: 1453214501Srpaulo os_strlcpy(buf, "EAP Success", sizeof(buf)); 1454214501Srpaulo break; 1455214501Srpaulo case EAP_CODE_FAILURE: 1456214501Srpaulo os_strlcpy(buf, "EAP Failure", sizeof(buf)); 1457214501Srpaulo break; 1458214501Srpaulo default: 1459214501Srpaulo os_strlcpy(buf, "unknown EAP code", sizeof(buf)); 1460214501Srpaulo break; 1461214501Srpaulo } 1462214501Srpaulo buf[sizeof(buf) - 1] = '\0'; 1463214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1464214501Srpaulo HOSTAPD_LEVEL_DEBUG, "decapsulated EAP packet (code=%d " 1465214501Srpaulo "id=%d len=%d) from RADIUS server: %s", 1466214501Srpaulo hdr->code, hdr->identifier, be_to_host16(hdr->length), 1467214501Srpaulo buf); 1468214501Srpaulo sm->eap_if->aaaEapReq = TRUE; 1469214501Srpaulo 1470214501Srpaulo wpabuf_free(sm->eap_if->aaaEapReqData); 1471252726Srpaulo sm->eap_if->aaaEapReqData = eap; 1472214501Srpaulo} 1473214501Srpaulo 1474214501Srpaulo 1475214501Srpaulostatic void ieee802_1x_get_keys(struct hostapd_data *hapd, 1476214501Srpaulo struct sta_info *sta, struct radius_msg *msg, 1477214501Srpaulo struct radius_msg *req, 1478214501Srpaulo const u8 *shared_secret, 1479214501Srpaulo size_t shared_secret_len) 1480214501Srpaulo{ 1481214501Srpaulo struct radius_ms_mppe_keys *keys; 1482351611Scy u8 *buf; 1483351611Scy size_t len; 1484214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 1485214501Srpaulo if (sm == NULL) 1486214501Srpaulo return; 1487214501Srpaulo 1488214501Srpaulo keys = radius_msg_get_ms_keys(msg, req, shared_secret, 1489214501Srpaulo shared_secret_len); 1490214501Srpaulo 1491214501Srpaulo if (keys && keys->send && keys->recv) { 1492351611Scy len = keys->send_len + keys->recv_len; 1493214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Send-Key", 1494214501Srpaulo keys->send, keys->send_len); 1495214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Recv-Key", 1496214501Srpaulo keys->recv, keys->recv_len); 1497214501Srpaulo 1498214501Srpaulo os_free(sm->eap_if->aaaEapKeyData); 1499214501Srpaulo sm->eap_if->aaaEapKeyData = os_malloc(len); 1500214501Srpaulo if (sm->eap_if->aaaEapKeyData) { 1501214501Srpaulo os_memcpy(sm->eap_if->aaaEapKeyData, keys->recv, 1502214501Srpaulo keys->recv_len); 1503214501Srpaulo os_memcpy(sm->eap_if->aaaEapKeyData + keys->recv_len, 1504214501Srpaulo keys->send, keys->send_len); 1505214501Srpaulo sm->eap_if->aaaEapKeyDataLen = len; 1506214501Srpaulo sm->eap_if->aaaEapKeyAvailable = TRUE; 1507214501Srpaulo } 1508281806Srpaulo } else { 1509281806Srpaulo wpa_printf(MSG_DEBUG, 1510281806Srpaulo "MS-MPPE: 1x_get_keys, could not get keys: %p send: %p recv: %p", 1511281806Srpaulo keys, keys ? keys->send : NULL, 1512281806Srpaulo keys ? keys->recv : NULL); 1513214501Srpaulo } 1514214501Srpaulo 1515214501Srpaulo if (keys) { 1516214501Srpaulo os_free(keys->send); 1517214501Srpaulo os_free(keys->recv); 1518214501Srpaulo os_free(keys); 1519214501Srpaulo } 1520351611Scy 1521351611Scy if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_EAP_KEY_NAME, &buf, &len, 1522351611Scy NULL) == 0) { 1523351611Scy os_free(sm->eap_if->eapSessionId); 1524351611Scy sm->eap_if->eapSessionId = os_memdup(buf, len); 1525351611Scy if (sm->eap_if->eapSessionId) { 1526351611Scy sm->eap_if->eapSessionIdLen = len; 1527351611Scy wpa_hexdump(MSG_DEBUG, "EAP-Key Name", 1528351611Scy sm->eap_if->eapSessionId, 1529351611Scy sm->eap_if->eapSessionIdLen); 1530351611Scy } 1531351611Scy } else { 1532351611Scy sm->eap_if->eapSessionIdLen = 0; 1533351611Scy } 1534214501Srpaulo} 1535214501Srpaulo 1536214501Srpaulo 1537214501Srpaulostatic void ieee802_1x_store_radius_class(struct hostapd_data *hapd, 1538214501Srpaulo struct sta_info *sta, 1539214501Srpaulo struct radius_msg *msg) 1540214501Srpaulo{ 1541289549Srpaulo u8 *attr_class; 1542214501Srpaulo size_t class_len; 1543214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 1544214501Srpaulo int count, i; 1545214501Srpaulo struct radius_attr_data *nclass; 1546214501Srpaulo size_t nclass_count; 1547214501Srpaulo 1548214501Srpaulo if (!hapd->conf->radius->acct_server || hapd->radius == NULL || 1549214501Srpaulo sm == NULL) 1550214501Srpaulo return; 1551214501Srpaulo 1552214501Srpaulo radius_free_class(&sm->radius_class); 1553214501Srpaulo count = radius_msg_count_attr(msg, RADIUS_ATTR_CLASS, 1); 1554214501Srpaulo if (count <= 0) 1555214501Srpaulo return; 1556214501Srpaulo 1557252726Srpaulo nclass = os_calloc(count, sizeof(struct radius_attr_data)); 1558214501Srpaulo if (nclass == NULL) 1559214501Srpaulo return; 1560214501Srpaulo 1561214501Srpaulo nclass_count = 0; 1562214501Srpaulo 1563289549Srpaulo attr_class = NULL; 1564214501Srpaulo for (i = 0; i < count; i++) { 1565214501Srpaulo do { 1566214501Srpaulo if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS, 1567289549Srpaulo &attr_class, &class_len, 1568289549Srpaulo attr_class) < 0) { 1569214501Srpaulo i = count; 1570214501Srpaulo break; 1571214501Srpaulo } 1572214501Srpaulo } while (class_len < 1); 1573214501Srpaulo 1574346981Scy nclass[nclass_count].data = os_memdup(attr_class, class_len); 1575214501Srpaulo if (nclass[nclass_count].data == NULL) 1576214501Srpaulo break; 1577214501Srpaulo 1578214501Srpaulo nclass[nclass_count].len = class_len; 1579214501Srpaulo nclass_count++; 1580214501Srpaulo } 1581214501Srpaulo 1582214501Srpaulo sm->radius_class.attr = nclass; 1583214501Srpaulo sm->radius_class.count = nclass_count; 1584214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Stored %lu RADIUS Class " 1585214501Srpaulo "attributes for " MACSTR, 1586214501Srpaulo (unsigned long) sm->radius_class.count, 1587214501Srpaulo MAC2STR(sta->addr)); 1588214501Srpaulo} 1589214501Srpaulo 1590214501Srpaulo 1591214501Srpaulo/* Update sta->identity based on User-Name attribute in Access-Accept */ 1592214501Srpaulostatic void ieee802_1x_update_sta_identity(struct hostapd_data *hapd, 1593214501Srpaulo struct sta_info *sta, 1594214501Srpaulo struct radius_msg *msg) 1595214501Srpaulo{ 1596214501Srpaulo u8 *buf, *identity; 1597214501Srpaulo size_t len; 1598214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 1599214501Srpaulo 1600214501Srpaulo if (sm == NULL) 1601214501Srpaulo return; 1602214501Srpaulo 1603214501Srpaulo if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &buf, &len, 1604214501Srpaulo NULL) < 0) 1605214501Srpaulo return; 1606214501Srpaulo 1607281806Srpaulo identity = (u8 *) dup_binstr(buf, len); 1608214501Srpaulo if (identity == NULL) 1609214501Srpaulo return; 1610214501Srpaulo 1611214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1612214501Srpaulo HOSTAPD_LEVEL_DEBUG, "old identity '%s' updated with " 1613214501Srpaulo "User-Name from Access-Accept '%s'", 1614214501Srpaulo sm->identity ? (char *) sm->identity : "N/A", 1615214501Srpaulo (char *) identity); 1616214501Srpaulo 1617214501Srpaulo os_free(sm->identity); 1618214501Srpaulo sm->identity = identity; 1619214501Srpaulo sm->identity_len = len; 1620214501Srpaulo} 1621214501Srpaulo 1622214501Srpaulo 1623252726Srpaulo/* Update CUI based on Chargeable-User-Identity attribute in Access-Accept */ 1624252726Srpaulostatic void ieee802_1x_update_sta_cui(struct hostapd_data *hapd, 1625252726Srpaulo struct sta_info *sta, 1626252726Srpaulo struct radius_msg *msg) 1627252726Srpaulo{ 1628252726Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 1629252726Srpaulo struct wpabuf *cui; 1630252726Srpaulo u8 *buf; 1631252726Srpaulo size_t len; 1632252726Srpaulo 1633252726Srpaulo if (sm == NULL) 1634252726Srpaulo return; 1635252726Srpaulo 1636252726Srpaulo if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, 1637252726Srpaulo &buf, &len, NULL) < 0) 1638252726Srpaulo return; 1639252726Srpaulo 1640252726Srpaulo cui = wpabuf_alloc_copy(buf, len); 1641252726Srpaulo if (cui == NULL) 1642252726Srpaulo return; 1643252726Srpaulo 1644252726Srpaulo wpabuf_free(sm->radius_cui); 1645252726Srpaulo sm->radius_cui = cui; 1646252726Srpaulo} 1647252726Srpaulo 1648252726Srpaulo 1649281806Srpaulo#ifdef CONFIG_HS20 1650281806Srpaulo 1651281806Srpaulostatic void ieee802_1x_hs20_sub_rem(struct sta_info *sta, u8 *pos, size_t len) 1652281806Srpaulo{ 1653281806Srpaulo sta->remediation = 1; 1654281806Srpaulo os_free(sta->remediation_url); 1655281806Srpaulo if (len > 2) { 1656281806Srpaulo sta->remediation_url = os_malloc(len); 1657281806Srpaulo if (!sta->remediation_url) 1658281806Srpaulo return; 1659281806Srpaulo sta->remediation_method = pos[0]; 1660281806Srpaulo os_memcpy(sta->remediation_url, pos + 1, len - 1); 1661281806Srpaulo sta->remediation_url[len - 1] = '\0'; 1662281806Srpaulo wpa_printf(MSG_DEBUG, "HS 2.0: Subscription remediation needed " 1663281806Srpaulo "for " MACSTR " - server method %u URL %s", 1664281806Srpaulo MAC2STR(sta->addr), sta->remediation_method, 1665281806Srpaulo sta->remediation_url); 1666281806Srpaulo } else { 1667281806Srpaulo sta->remediation_url = NULL; 1668281806Srpaulo wpa_printf(MSG_DEBUG, "HS 2.0: Subscription remediation needed " 1669281806Srpaulo "for " MACSTR, MAC2STR(sta->addr)); 1670281806Srpaulo } 1671281806Srpaulo /* TODO: assign the STA into remediation VLAN or add filtering */ 1672281806Srpaulo} 1673281806Srpaulo 1674281806Srpaulo 1675281806Srpaulostatic void ieee802_1x_hs20_deauth_req(struct hostapd_data *hapd, 1676281806Srpaulo struct sta_info *sta, u8 *pos, 1677281806Srpaulo size_t len) 1678281806Srpaulo{ 1679281806Srpaulo if (len < 3) 1680281806Srpaulo return; /* Malformed information */ 1681281806Srpaulo sta->hs20_deauth_requested = 1; 1682281806Srpaulo wpa_printf(MSG_DEBUG, "HS 2.0: Deauthentication request - Code %u " 1683281806Srpaulo "Re-auth Delay %u", 1684281806Srpaulo *pos, WPA_GET_LE16(pos + 1)); 1685281806Srpaulo wpabuf_free(sta->hs20_deauth_req); 1686281806Srpaulo sta->hs20_deauth_req = wpabuf_alloc(len + 1); 1687281806Srpaulo if (sta->hs20_deauth_req) { 1688281806Srpaulo wpabuf_put_data(sta->hs20_deauth_req, pos, 3); 1689281806Srpaulo wpabuf_put_u8(sta->hs20_deauth_req, len - 3); 1690281806Srpaulo wpabuf_put_data(sta->hs20_deauth_req, pos + 3, len - 3); 1691281806Srpaulo } 1692281806Srpaulo ap_sta_session_timeout(hapd, sta, hapd->conf->hs20_deauth_req_timeout); 1693281806Srpaulo} 1694281806Srpaulo 1695281806Srpaulo 1696281806Srpaulostatic void ieee802_1x_hs20_session_info(struct hostapd_data *hapd, 1697281806Srpaulo struct sta_info *sta, u8 *pos, 1698281806Srpaulo size_t len, int session_timeout) 1699281806Srpaulo{ 1700281806Srpaulo unsigned int swt; 1701281806Srpaulo int warning_time, beacon_int; 1702281806Srpaulo 1703281806Srpaulo if (len < 1) 1704281806Srpaulo return; /* Malformed information */ 1705281806Srpaulo os_free(sta->hs20_session_info_url); 1706281806Srpaulo sta->hs20_session_info_url = os_malloc(len); 1707281806Srpaulo if (sta->hs20_session_info_url == NULL) 1708281806Srpaulo return; 1709281806Srpaulo swt = pos[0]; 1710281806Srpaulo os_memcpy(sta->hs20_session_info_url, pos + 1, len - 1); 1711281806Srpaulo sta->hs20_session_info_url[len - 1] = '\0'; 1712281806Srpaulo wpa_printf(MSG_DEBUG, "HS 2.0: Session Information URL='%s' SWT=%u " 1713281806Srpaulo "(session_timeout=%d)", 1714281806Srpaulo sta->hs20_session_info_url, swt, session_timeout); 1715281806Srpaulo if (session_timeout < 0) { 1716281806Srpaulo wpa_printf(MSG_DEBUG, "HS 2.0: No Session-Timeout set - ignore session info URL"); 1717281806Srpaulo return; 1718281806Srpaulo } 1719281806Srpaulo if (swt == 255) 1720281806Srpaulo swt = 1; /* Use one minute as the AP selected value */ 1721281806Srpaulo 1722281806Srpaulo if ((unsigned int) session_timeout < swt * 60) 1723281806Srpaulo warning_time = 0; 1724281806Srpaulo else 1725281806Srpaulo warning_time = session_timeout - swt * 60; 1726281806Srpaulo 1727281806Srpaulo beacon_int = hapd->iconf->beacon_int; 1728281806Srpaulo if (beacon_int < 1) 1729281806Srpaulo beacon_int = 100; /* best guess */ 1730281806Srpaulo sta->hs20_disassoc_timer = swt * 60 * 1000 / beacon_int * 125 / 128; 1731281806Srpaulo if (sta->hs20_disassoc_timer > 65535) 1732281806Srpaulo sta->hs20_disassoc_timer = 65535; 1733281806Srpaulo 1734281806Srpaulo ap_sta_session_warning_timeout(hapd, sta, warning_time); 1735281806Srpaulo} 1736281806Srpaulo 1737346981Scy 1738346981Scystatic void ieee802_1x_hs20_t_c_filtering(struct hostapd_data *hapd, 1739346981Scy struct sta_info *sta, u8 *pos, 1740346981Scy size_t len) 1741346981Scy{ 1742346981Scy if (len < 4) 1743346981Scy return; /* Malformed information */ 1744346981Scy wpa_printf(MSG_DEBUG, 1745346981Scy "HS 2.0: Terms and Conditions filtering %02x %02x %02x %02x", 1746346981Scy pos[0], pos[1], pos[2], pos[3]); 1747346981Scy hs20_t_c_filtering(hapd, sta, pos[0] & BIT(0)); 1748346981Scy} 1749346981Scy 1750346981Scy 1751346981Scystatic void ieee802_1x_hs20_t_c_url(struct hostapd_data *hapd, 1752346981Scy struct sta_info *sta, u8 *pos, size_t len) 1753346981Scy{ 1754346981Scy os_free(sta->t_c_url); 1755346981Scy sta->t_c_url = os_malloc(len + 1); 1756346981Scy if (!sta->t_c_url) 1757346981Scy return; 1758346981Scy os_memcpy(sta->t_c_url, pos, len); 1759346981Scy sta->t_c_url[len] = '\0'; 1760346981Scy wpa_printf(MSG_DEBUG, 1761346981Scy "HS 2.0: Terms and Conditions URL %s", sta->t_c_url); 1762346981Scy} 1763346981Scy 1764281806Srpaulo#endif /* CONFIG_HS20 */ 1765281806Srpaulo 1766281806Srpaulo 1767281806Srpaulostatic void ieee802_1x_check_hs20(struct hostapd_data *hapd, 1768281806Srpaulo struct sta_info *sta, 1769281806Srpaulo struct radius_msg *msg, 1770281806Srpaulo int session_timeout) 1771281806Srpaulo{ 1772281806Srpaulo#ifdef CONFIG_HS20 1773281806Srpaulo u8 *buf, *pos, *end, type, sublen; 1774281806Srpaulo size_t len; 1775281806Srpaulo 1776281806Srpaulo buf = NULL; 1777281806Srpaulo sta->remediation = 0; 1778281806Srpaulo sta->hs20_deauth_requested = 0; 1779281806Srpaulo 1780281806Srpaulo for (;;) { 1781281806Srpaulo if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, 1782281806Srpaulo &buf, &len, buf) < 0) 1783281806Srpaulo break; 1784281806Srpaulo if (len < 6) 1785281806Srpaulo continue; 1786281806Srpaulo pos = buf; 1787281806Srpaulo end = buf + len; 1788281806Srpaulo if (WPA_GET_BE32(pos) != RADIUS_VENDOR_ID_WFA) 1789281806Srpaulo continue; 1790281806Srpaulo pos += 4; 1791281806Srpaulo 1792281806Srpaulo type = *pos++; 1793281806Srpaulo sublen = *pos++; 1794281806Srpaulo if (sublen < 2) 1795281806Srpaulo continue; /* invalid length */ 1796281806Srpaulo sublen -= 2; /* skip header */ 1797281806Srpaulo if (pos + sublen > end) 1798281806Srpaulo continue; /* invalid WFA VSA */ 1799281806Srpaulo 1800281806Srpaulo switch (type) { 1801281806Srpaulo case RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION: 1802281806Srpaulo ieee802_1x_hs20_sub_rem(sta, pos, sublen); 1803281806Srpaulo break; 1804281806Srpaulo case RADIUS_VENDOR_ATTR_WFA_HS20_DEAUTH_REQ: 1805281806Srpaulo ieee802_1x_hs20_deauth_req(hapd, sta, pos, sublen); 1806281806Srpaulo break; 1807281806Srpaulo case RADIUS_VENDOR_ATTR_WFA_HS20_SESSION_INFO_URL: 1808281806Srpaulo ieee802_1x_hs20_session_info(hapd, sta, pos, sublen, 1809281806Srpaulo session_timeout); 1810281806Srpaulo break; 1811346981Scy case RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING: 1812346981Scy ieee802_1x_hs20_t_c_filtering(hapd, sta, pos, sublen); 1813346981Scy break; 1814346981Scy case RADIUS_VENDOR_ATTR_WFA_HS20_T_C_URL: 1815346981Scy ieee802_1x_hs20_t_c_url(hapd, sta, pos, sublen); 1816346981Scy break; 1817281806Srpaulo } 1818281806Srpaulo } 1819281806Srpaulo#endif /* CONFIG_HS20 */ 1820281806Srpaulo} 1821281806Srpaulo 1822281806Srpaulo 1823214501Srpaulostruct sta_id_search { 1824214501Srpaulo u8 identifier; 1825214501Srpaulo struct eapol_state_machine *sm; 1826214501Srpaulo}; 1827214501Srpaulo 1828214501Srpaulo 1829214501Srpaulostatic int ieee802_1x_select_radius_identifier(struct hostapd_data *hapd, 1830214501Srpaulo struct sta_info *sta, 1831214501Srpaulo void *ctx) 1832214501Srpaulo{ 1833214501Srpaulo struct sta_id_search *id_search = ctx; 1834214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 1835214501Srpaulo 1836214501Srpaulo if (sm && sm->radius_identifier >= 0 && 1837214501Srpaulo sm->radius_identifier == id_search->identifier) { 1838214501Srpaulo id_search->sm = sm; 1839214501Srpaulo return 1; 1840214501Srpaulo } 1841214501Srpaulo return 0; 1842214501Srpaulo} 1843214501Srpaulo 1844214501Srpaulo 1845214501Srpaulostatic struct eapol_state_machine * 1846214501Srpauloieee802_1x_search_radius_identifier(struct hostapd_data *hapd, u8 identifier) 1847214501Srpaulo{ 1848214501Srpaulo struct sta_id_search id_search; 1849214501Srpaulo id_search.identifier = identifier; 1850214501Srpaulo id_search.sm = NULL; 1851214501Srpaulo ap_for_each_sta(hapd, ieee802_1x_select_radius_identifier, &id_search); 1852214501Srpaulo return id_search.sm; 1853214501Srpaulo} 1854214501Srpaulo 1855214501Srpaulo 1856346981Scy#ifndef CONFIG_NO_VLAN 1857346981Scystatic int ieee802_1x_update_vlan(struct radius_msg *msg, 1858346981Scy struct hostapd_data *hapd, 1859346981Scy struct sta_info *sta) 1860346981Scy{ 1861346981Scy struct vlan_description vlan_desc; 1862346981Scy 1863346981Scy os_memset(&vlan_desc, 0, sizeof(vlan_desc)); 1864346981Scy vlan_desc.notempty = !!radius_msg_get_vlanid(msg, &vlan_desc.untagged, 1865346981Scy MAX_NUM_TAGGED_VLAN, 1866346981Scy vlan_desc.tagged); 1867346981Scy 1868346981Scy if (vlan_desc.notempty && 1869346981Scy !hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) { 1870346981Scy sta->eapol_sm->authFail = TRUE; 1871346981Scy hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, 1872346981Scy HOSTAPD_LEVEL_INFO, 1873346981Scy "Invalid VLAN %d%s received from RADIUS server", 1874346981Scy vlan_desc.untagged, 1875346981Scy vlan_desc.tagged[0] ? "+" : ""); 1876346981Scy os_memset(&vlan_desc, 0, sizeof(vlan_desc)); 1877346981Scy ap_sta_set_vlan(hapd, sta, &vlan_desc); 1878346981Scy return -1; 1879346981Scy } 1880346981Scy 1881346981Scy if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED && 1882346981Scy !vlan_desc.notempty) { 1883346981Scy sta->eapol_sm->authFail = TRUE; 1884346981Scy hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1885346981Scy HOSTAPD_LEVEL_INFO, 1886346981Scy "authentication server did not include required VLAN ID in Access-Accept"); 1887346981Scy return -1; 1888346981Scy } 1889346981Scy 1890346981Scy return ap_sta_set_vlan(hapd, sta, &vlan_desc); 1891346981Scy} 1892346981Scy#endif /* CONFIG_NO_VLAN */ 1893346981Scy 1894346981Scy 1895214501Srpaulo/** 1896214501Srpaulo * ieee802_1x_receive_auth - Process RADIUS frames from Authentication Server 1897214501Srpaulo * @msg: RADIUS response message 1898214501Srpaulo * @req: RADIUS request message 1899214501Srpaulo * @shared_secret: RADIUS shared secret 1900214501Srpaulo * @shared_secret_len: Length of shared_secret in octets 1901214501Srpaulo * @data: Context data (struct hostapd_data *) 1902214501Srpaulo * Returns: Processing status 1903214501Srpaulo */ 1904214501Srpaulostatic RadiusRxResult 1905214501Srpauloieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, 1906214501Srpaulo const u8 *shared_secret, size_t shared_secret_len, 1907214501Srpaulo void *data) 1908214501Srpaulo{ 1909214501Srpaulo struct hostapd_data *hapd = data; 1910214501Srpaulo struct sta_info *sta; 1911214501Srpaulo u32 session_timeout = 0, termination_action, acct_interim_interval; 1912337817Scy int session_timeout_set; 1913346981Scy u32 reason_code; 1914214501Srpaulo struct eapol_state_machine *sm; 1915214501Srpaulo int override_eapReq = 0; 1916214501Srpaulo struct radius_hdr *hdr = radius_msg_get_hdr(msg); 1917214501Srpaulo 1918214501Srpaulo sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier); 1919214501Srpaulo if (sm == NULL) { 1920214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Could not find matching " 1921214501Srpaulo "station for this RADIUS message"); 1922214501Srpaulo return RADIUS_RX_UNKNOWN; 1923214501Srpaulo } 1924214501Srpaulo sta = sm->sta; 1925214501Srpaulo 1926214501Srpaulo /* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be 1927214501Srpaulo * present when packet contains an EAP-Message attribute */ 1928214501Srpaulo if (hdr->code == RADIUS_CODE_ACCESS_REJECT && 1929214501Srpaulo radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL, 1930214501Srpaulo 0) < 0 && 1931214501Srpaulo radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) { 1932214501Srpaulo wpa_printf(MSG_DEBUG, "Allowing RADIUS Access-Reject without " 1933214501Srpaulo "Message-Authenticator since it does not include " 1934214501Srpaulo "EAP-Message"); 1935214501Srpaulo } else if (radius_msg_verify(msg, shared_secret, shared_secret_len, 1936214501Srpaulo req, 1)) { 1937281806Srpaulo wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Message-Authenticator - dropped"); 1938214501Srpaulo return RADIUS_RX_INVALID_AUTHENTICATOR; 1939214501Srpaulo } 1940214501Srpaulo 1941214501Srpaulo if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT && 1942214501Srpaulo hdr->code != RADIUS_CODE_ACCESS_REJECT && 1943214501Srpaulo hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) { 1944281806Srpaulo wpa_printf(MSG_INFO, "Unknown RADIUS message code"); 1945214501Srpaulo return RADIUS_RX_UNKNOWN; 1946214501Srpaulo } 1947214501Srpaulo 1948214501Srpaulo sm->radius_identifier = -1; 1949214501Srpaulo wpa_printf(MSG_DEBUG, "RADIUS packet matching with station " MACSTR, 1950214501Srpaulo MAC2STR(sta->addr)); 1951214501Srpaulo 1952214501Srpaulo radius_msg_free(sm->last_recv_radius); 1953214501Srpaulo sm->last_recv_radius = msg; 1954214501Srpaulo 1955214501Srpaulo session_timeout_set = 1956214501Srpaulo !radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT, 1957214501Srpaulo &session_timeout); 1958214501Srpaulo if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_TERMINATION_ACTION, 1959214501Srpaulo &termination_action)) 1960214501Srpaulo termination_action = RADIUS_TERMINATION_ACTION_DEFAULT; 1961214501Srpaulo 1962214501Srpaulo if (hapd->conf->acct_interim_interval == 0 && 1963214501Srpaulo hdr->code == RADIUS_CODE_ACCESS_ACCEPT && 1964214501Srpaulo radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL, 1965214501Srpaulo &acct_interim_interval) == 0) { 1966214501Srpaulo if (acct_interim_interval < 60) { 1967214501Srpaulo hostapd_logger(hapd, sta->addr, 1968214501Srpaulo HOSTAPD_MODULE_IEEE8021X, 1969214501Srpaulo HOSTAPD_LEVEL_INFO, 1970214501Srpaulo "ignored too small " 1971214501Srpaulo "Acct-Interim-Interval %d", 1972214501Srpaulo acct_interim_interval); 1973214501Srpaulo } else 1974214501Srpaulo sta->acct_interim_interval = acct_interim_interval; 1975214501Srpaulo } 1976214501Srpaulo 1977214501Srpaulo 1978214501Srpaulo switch (hdr->code) { 1979214501Srpaulo case RADIUS_CODE_ACCESS_ACCEPT: 1980214501Srpaulo#ifndef CONFIG_NO_VLAN 1981346981Scy if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED && 1982346981Scy ieee802_1x_update_vlan(msg, hapd, sta) < 0) 1983289549Srpaulo break; 1984337817Scy 1985337817Scy if (sta->vlan_id > 0) { 1986337817Scy hostapd_logger(hapd, sta->addr, 1987337817Scy HOSTAPD_MODULE_RADIUS, 1988337817Scy HOSTAPD_LEVEL_INFO, 1989337817Scy "VLAN ID %d", sta->vlan_id); 1990337817Scy } 1991337817Scy 1992289549Srpaulo if ((sta->flags & WLAN_STA_ASSOC) && 1993289549Srpaulo ap_sta_bind_vlan(hapd, sta) < 0) 1994214501Srpaulo break; 1995346981Scy#endif /* CONFIG_NO_VLAN */ 1996214501Srpaulo 1997281806Srpaulo sta->session_timeout_set = !!session_timeout_set; 1998346981Scy os_get_reltime(&sta->session_timeout); 1999346981Scy sta->session_timeout.sec += session_timeout; 2000281806Srpaulo 2001214501Srpaulo /* RFC 3580, Ch. 3.17 */ 2002214501Srpaulo if (session_timeout_set && termination_action == 2003346981Scy RADIUS_TERMINATION_ACTION_RADIUS_REQUEST) 2004214501Srpaulo sm->reAuthPeriod = session_timeout; 2005346981Scy else if (session_timeout_set) 2006214501Srpaulo ap_sta_session_timeout(hapd, sta, session_timeout); 2007346981Scy else 2008346981Scy ap_sta_no_session_timeout(hapd, sta); 2009214501Srpaulo 2010214501Srpaulo sm->eap_if->aaaSuccess = TRUE; 2011214501Srpaulo override_eapReq = 1; 2012214501Srpaulo ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret, 2013214501Srpaulo shared_secret_len); 2014214501Srpaulo ieee802_1x_store_radius_class(hapd, sta, msg); 2015214501Srpaulo ieee802_1x_update_sta_identity(hapd, sta, msg); 2016252726Srpaulo ieee802_1x_update_sta_cui(hapd, sta, msg); 2017281806Srpaulo ieee802_1x_check_hs20(hapd, sta, msg, 2018281806Srpaulo session_timeout_set ? 2019281806Srpaulo (int) session_timeout : -1); 2020214501Srpaulo break; 2021214501Srpaulo case RADIUS_CODE_ACCESS_REJECT: 2022214501Srpaulo sm->eap_if->aaaFail = TRUE; 2023214501Srpaulo override_eapReq = 1; 2024346981Scy if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_WLAN_REASON_CODE, 2025346981Scy &reason_code) == 0) { 2026346981Scy wpa_printf(MSG_DEBUG, 2027346981Scy "RADIUS server indicated WLAN-Reason-Code %u in Access-Reject for " 2028346981Scy MACSTR, reason_code, MAC2STR(sta->addr)); 2029346981Scy sta->disconnect_reason_code = reason_code; 2030346981Scy } 2031214501Srpaulo break; 2032214501Srpaulo case RADIUS_CODE_ACCESS_CHALLENGE: 2033214501Srpaulo sm->eap_if->aaaEapReq = TRUE; 2034214501Srpaulo if (session_timeout_set) { 2035214501Srpaulo /* RFC 2869, Ch. 2.3.2; RFC 3580, Ch. 3.17 */ 2036214501Srpaulo sm->eap_if->aaaMethodTimeout = session_timeout; 2037214501Srpaulo hostapd_logger(hapd, sm->addr, 2038214501Srpaulo HOSTAPD_MODULE_IEEE8021X, 2039214501Srpaulo HOSTAPD_LEVEL_DEBUG, 2040214501Srpaulo "using EAP timeout of %d seconds (from " 2041214501Srpaulo "RADIUS)", 2042214501Srpaulo sm->eap_if->aaaMethodTimeout); 2043214501Srpaulo } else { 2044214501Srpaulo /* 2045214501Srpaulo * Use dynamic retransmission behavior per EAP 2046214501Srpaulo * specification. 2047214501Srpaulo */ 2048214501Srpaulo sm->eap_if->aaaMethodTimeout = 0; 2049214501Srpaulo } 2050214501Srpaulo break; 2051214501Srpaulo } 2052214501Srpaulo 2053214501Srpaulo ieee802_1x_decapsulate_radius(hapd, sta); 2054214501Srpaulo if (override_eapReq) 2055214501Srpaulo sm->eap_if->aaaEapReq = FALSE; 2056214501Srpaulo 2057346981Scy#ifdef CONFIG_FILS 2058346981Scy#ifdef NEED_AP_MLME 2059346981Scy if (sta->flags & WLAN_STA_PENDING_FILS_ERP) { 2060346981Scy /* TODO: Add a PMKSA entry on success? */ 2061346981Scy ieee802_11_finish_fils_auth( 2062346981Scy hapd, sta, hdr->code == RADIUS_CODE_ACCESS_ACCEPT, 2063346981Scy sm->eap_if->aaaEapReqData, 2064346981Scy sm->eap_if->aaaEapKeyData, 2065346981Scy sm->eap_if->aaaEapKeyDataLen); 2066346981Scy } 2067346981Scy#endif /* NEED_AP_MLME */ 2068346981Scy#endif /* CONFIG_FILS */ 2069346981Scy 2070214501Srpaulo eapol_auth_step(sm); 2071214501Srpaulo 2072214501Srpaulo return RADIUS_RX_QUEUED; 2073214501Srpaulo} 2074214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 2075214501Srpaulo 2076214501Srpaulo 2077214501Srpaulovoid ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta) 2078214501Srpaulo{ 2079214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 2080214501Srpaulo if (sm == NULL) 2081214501Srpaulo return; 2082214501Srpaulo 2083214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 2084214501Srpaulo HOSTAPD_LEVEL_DEBUG, "aborting authentication"); 2085214501Srpaulo 2086214501Srpaulo#ifndef CONFIG_NO_RADIUS 2087214501Srpaulo radius_msg_free(sm->last_recv_radius); 2088214501Srpaulo sm->last_recv_radius = NULL; 2089214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 2090214501Srpaulo 2091214501Srpaulo if (sm->eap_if->eapTimeout) { 2092214501Srpaulo /* 2093214501Srpaulo * Disconnect the STA since it did not reply to the last EAP 2094214501Srpaulo * request and we cannot continue EAP processing (EAP-Failure 2095214501Srpaulo * could only be sent if the EAP peer actually replied). 2096214501Srpaulo */ 2097252726Srpaulo wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "EAP Timeout, STA " MACSTR, 2098252726Srpaulo MAC2STR(sta->addr)); 2099252726Srpaulo 2100214501Srpaulo sm->eap_if->portEnabled = FALSE; 2101214501Srpaulo ap_sta_disconnect(hapd, sta, sta->addr, 2102214501Srpaulo WLAN_REASON_PREV_AUTH_NOT_VALID); 2103214501Srpaulo } 2104214501Srpaulo} 2105214501Srpaulo 2106214501Srpaulo 2107214501Srpaulostatic int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd) 2108214501Srpaulo{ 2109214501Srpaulo struct eapol_authenticator *eapol = hapd->eapol_auth; 2110214501Srpaulo 2111214501Srpaulo if (hapd->conf->default_wep_key_len < 1) 2112214501Srpaulo return 0; 2113214501Srpaulo 2114214501Srpaulo os_free(eapol->default_wep_key); 2115214501Srpaulo eapol->default_wep_key = os_malloc(hapd->conf->default_wep_key_len); 2116214501Srpaulo if (eapol->default_wep_key == NULL || 2117252726Srpaulo random_get_bytes(eapol->default_wep_key, 2118252726Srpaulo hapd->conf->default_wep_key_len)) { 2119281806Srpaulo wpa_printf(MSG_INFO, "Could not generate random WEP key"); 2120214501Srpaulo os_free(eapol->default_wep_key); 2121214501Srpaulo eapol->default_wep_key = NULL; 2122214501Srpaulo return -1; 2123214501Srpaulo } 2124214501Srpaulo 2125214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "IEEE 802.1X: New default WEP key", 2126214501Srpaulo eapol->default_wep_key, 2127214501Srpaulo hapd->conf->default_wep_key_len); 2128214501Srpaulo 2129214501Srpaulo return 0; 2130214501Srpaulo} 2131214501Srpaulo 2132214501Srpaulo 2133214501Srpaulostatic int ieee802_1x_sta_key_available(struct hostapd_data *hapd, 2134214501Srpaulo struct sta_info *sta, void *ctx) 2135214501Srpaulo{ 2136214501Srpaulo if (sta->eapol_sm) { 2137214501Srpaulo sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; 2138214501Srpaulo eapol_auth_step(sta->eapol_sm); 2139214501Srpaulo } 2140214501Srpaulo return 0; 2141214501Srpaulo} 2142214501Srpaulo 2143214501Srpaulo 2144214501Srpaulostatic void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx) 2145214501Srpaulo{ 2146214501Srpaulo struct hostapd_data *hapd = eloop_ctx; 2147214501Srpaulo struct eapol_authenticator *eapol = hapd->eapol_auth; 2148214501Srpaulo 2149214501Srpaulo if (eapol->default_wep_key_idx >= 3) 2150214501Srpaulo eapol->default_wep_key_idx = 2151214501Srpaulo hapd->conf->individual_wep_key_len > 0 ? 1 : 0; 2152214501Srpaulo else 2153214501Srpaulo eapol->default_wep_key_idx++; 2154214501Srpaulo 2155214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: New default WEP key index %d", 2156214501Srpaulo eapol->default_wep_key_idx); 2157346981Scy 2158214501Srpaulo if (ieee802_1x_rekey_broadcast(hapd)) { 2159214501Srpaulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X, 2160214501Srpaulo HOSTAPD_LEVEL_WARNING, "failed to generate a " 2161214501Srpaulo "new broadcast key"); 2162214501Srpaulo os_free(eapol->default_wep_key); 2163214501Srpaulo eapol->default_wep_key = NULL; 2164214501Srpaulo return; 2165214501Srpaulo } 2166214501Srpaulo 2167214501Srpaulo /* TODO: Could setup key for RX here, but change default TX keyid only 2168214501Srpaulo * after new broadcast key has been sent to all stations. */ 2169252726Srpaulo if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, 2170252726Srpaulo broadcast_ether_addr, 2171252726Srpaulo eapol->default_wep_key_idx, 1, NULL, 0, 2172252726Srpaulo eapol->default_wep_key, 2173252726Srpaulo hapd->conf->default_wep_key_len)) { 2174214501Srpaulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X, 2175214501Srpaulo HOSTAPD_LEVEL_WARNING, "failed to configure a " 2176214501Srpaulo "new broadcast key"); 2177214501Srpaulo os_free(eapol->default_wep_key); 2178214501Srpaulo eapol->default_wep_key = NULL; 2179214501Srpaulo return; 2180214501Srpaulo } 2181214501Srpaulo 2182214501Srpaulo ap_for_each_sta(hapd, ieee802_1x_sta_key_available, NULL); 2183214501Srpaulo 2184214501Srpaulo if (hapd->conf->wep_rekeying_period > 0) { 2185214501Srpaulo eloop_register_timeout(hapd->conf->wep_rekeying_period, 0, 2186214501Srpaulo ieee802_1x_rekey, hapd, NULL); 2187214501Srpaulo } 2188214501Srpaulo} 2189214501Srpaulo 2190214501Srpaulo 2191214501Srpaulostatic void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type, 2192214501Srpaulo const u8 *data, size_t datalen) 2193214501Srpaulo{ 2194214501Srpaulo#ifdef CONFIG_WPS 2195214501Srpaulo struct sta_info *sta = sta_ctx; 2196214501Srpaulo 2197214501Srpaulo if ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) == 2198214501Srpaulo WLAN_STA_MAYBE_WPS) { 2199214501Srpaulo const u8 *identity; 2200214501Srpaulo size_t identity_len; 2201214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 2202214501Srpaulo 2203214501Srpaulo identity = eap_get_identity(sm->eap, &identity_len); 2204214501Srpaulo if (identity && 2205214501Srpaulo ((identity_len == WSC_ID_ENROLLEE_LEN && 2206214501Srpaulo os_memcmp(identity, WSC_ID_ENROLLEE, 2207214501Srpaulo WSC_ID_ENROLLEE_LEN) == 0) || 2208214501Srpaulo (identity_len == WSC_ID_REGISTRAR_LEN && 2209214501Srpaulo os_memcmp(identity, WSC_ID_REGISTRAR, 2210214501Srpaulo WSC_ID_REGISTRAR_LEN) == 0))) { 2211214501Srpaulo wpa_printf(MSG_DEBUG, "WPS: WLAN_STA_MAYBE_WPS -> " 2212214501Srpaulo "WLAN_STA_WPS"); 2213214501Srpaulo sta->flags |= WLAN_STA_WPS; 2214214501Srpaulo } 2215214501Srpaulo } 2216214501Srpaulo#endif /* CONFIG_WPS */ 2217214501Srpaulo 2218214501Srpaulo ieee802_1x_send(ctx, sta_ctx, type, data, datalen); 2219214501Srpaulo} 2220214501Srpaulo 2221214501Srpaulo 2222214501Srpaulostatic void ieee802_1x_aaa_send(void *ctx, void *sta_ctx, 2223214501Srpaulo const u8 *data, size_t datalen) 2224214501Srpaulo{ 2225214501Srpaulo#ifndef CONFIG_NO_RADIUS 2226214501Srpaulo struct hostapd_data *hapd = ctx; 2227214501Srpaulo struct sta_info *sta = sta_ctx; 2228214501Srpaulo 2229214501Srpaulo ieee802_1x_encapsulate_radius(hapd, sta, data, datalen); 2230214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 2231214501Srpaulo} 2232214501Srpaulo 2233214501Srpaulo 2234214501Srpaulostatic void _ieee802_1x_finished(void *ctx, void *sta_ctx, int success, 2235281806Srpaulo int preauth, int remediation) 2236214501Srpaulo{ 2237214501Srpaulo struct hostapd_data *hapd = ctx; 2238214501Srpaulo struct sta_info *sta = sta_ctx; 2239214501Srpaulo if (preauth) 2240214501Srpaulo rsn_preauth_finished(hapd, sta, success); 2241214501Srpaulo else 2242281806Srpaulo ieee802_1x_finished(hapd, sta, success, remediation); 2243214501Srpaulo} 2244214501Srpaulo 2245214501Srpaulo 2246214501Srpaulostatic int ieee802_1x_get_eap_user(void *ctx, const u8 *identity, 2247214501Srpaulo size_t identity_len, int phase2, 2248214501Srpaulo struct eap_user *user) 2249214501Srpaulo{ 2250214501Srpaulo struct hostapd_data *hapd = ctx; 2251214501Srpaulo const struct hostapd_eap_user *eap_user; 2252252726Srpaulo int i; 2253289549Srpaulo int rv = -1; 2254214501Srpaulo 2255252726Srpaulo eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2); 2256214501Srpaulo if (eap_user == NULL) 2257289549Srpaulo goto out; 2258214501Srpaulo 2259214501Srpaulo os_memset(user, 0, sizeof(*user)); 2260214501Srpaulo user->phase2 = phase2; 2261252726Srpaulo for (i = 0; i < EAP_MAX_METHODS; i++) { 2262214501Srpaulo user->methods[i].vendor = eap_user->methods[i].vendor; 2263214501Srpaulo user->methods[i].method = eap_user->methods[i].method; 2264214501Srpaulo } 2265214501Srpaulo 2266214501Srpaulo if (eap_user->password) { 2267346981Scy user->password = os_memdup(eap_user->password, 2268346981Scy eap_user->password_len); 2269214501Srpaulo if (user->password == NULL) 2270289549Srpaulo goto out; 2271214501Srpaulo user->password_len = eap_user->password_len; 2272252726Srpaulo user->password_hash = eap_user->password_hash; 2273346981Scy if (eap_user->salt && eap_user->salt_len) { 2274346981Scy user->salt = os_memdup(eap_user->salt, 2275346981Scy eap_user->salt_len); 2276346981Scy if (!user->salt) 2277346981Scy goto out; 2278346981Scy user->salt_len = eap_user->salt_len; 2279346981Scy } 2280214501Srpaulo } 2281214501Srpaulo user->force_version = eap_user->force_version; 2282281806Srpaulo user->macacl = eap_user->macacl; 2283214501Srpaulo user->ttls_auth = eap_user->ttls_auth; 2284281806Srpaulo user->remediation = eap_user->remediation; 2285289549Srpaulo rv = 0; 2286214501Srpaulo 2287289549Srpauloout: 2288289549Srpaulo if (rv) 2289289549Srpaulo wpa_printf(MSG_DEBUG, "%s: Failed to find user", __func__); 2290289549Srpaulo 2291289549Srpaulo return rv; 2292214501Srpaulo} 2293214501Srpaulo 2294214501Srpaulo 2295214501Srpaulostatic int ieee802_1x_sta_entry_alive(void *ctx, const u8 *addr) 2296214501Srpaulo{ 2297214501Srpaulo struct hostapd_data *hapd = ctx; 2298214501Srpaulo struct sta_info *sta; 2299214501Srpaulo sta = ap_get_sta(hapd, addr); 2300214501Srpaulo if (sta == NULL || sta->eapol_sm == NULL) 2301214501Srpaulo return 0; 2302214501Srpaulo return 1; 2303214501Srpaulo} 2304214501Srpaulo 2305214501Srpaulo 2306214501Srpaulostatic void ieee802_1x_logger(void *ctx, const u8 *addr, 2307214501Srpaulo eapol_logger_level level, const char *txt) 2308214501Srpaulo{ 2309214501Srpaulo#ifndef CONFIG_NO_HOSTAPD_LOGGER 2310214501Srpaulo struct hostapd_data *hapd = ctx; 2311214501Srpaulo int hlevel; 2312214501Srpaulo 2313214501Srpaulo switch (level) { 2314214501Srpaulo case EAPOL_LOGGER_WARNING: 2315214501Srpaulo hlevel = HOSTAPD_LEVEL_WARNING; 2316214501Srpaulo break; 2317214501Srpaulo case EAPOL_LOGGER_INFO: 2318214501Srpaulo hlevel = HOSTAPD_LEVEL_INFO; 2319214501Srpaulo break; 2320214501Srpaulo case EAPOL_LOGGER_DEBUG: 2321214501Srpaulo default: 2322214501Srpaulo hlevel = HOSTAPD_LEVEL_DEBUG; 2323214501Srpaulo break; 2324214501Srpaulo } 2325214501Srpaulo 2326214501Srpaulo hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE8021X, hlevel, "%s", 2327214501Srpaulo txt); 2328214501Srpaulo#endif /* CONFIG_NO_HOSTAPD_LOGGER */ 2329214501Srpaulo} 2330214501Srpaulo 2331214501Srpaulo 2332214501Srpaulostatic void ieee802_1x_set_port_authorized(void *ctx, void *sta_ctx, 2333214501Srpaulo int authorized) 2334214501Srpaulo{ 2335214501Srpaulo struct hostapd_data *hapd = ctx; 2336214501Srpaulo struct sta_info *sta = sta_ctx; 2337214501Srpaulo ieee802_1x_set_sta_authorized(hapd, sta, authorized); 2338214501Srpaulo} 2339214501Srpaulo 2340214501Srpaulo 2341214501Srpaulostatic void _ieee802_1x_abort_auth(void *ctx, void *sta_ctx) 2342214501Srpaulo{ 2343214501Srpaulo struct hostapd_data *hapd = ctx; 2344214501Srpaulo struct sta_info *sta = sta_ctx; 2345214501Srpaulo ieee802_1x_abort_auth(hapd, sta); 2346214501Srpaulo} 2347214501Srpaulo 2348214501Srpaulo 2349214501Srpaulostatic void _ieee802_1x_tx_key(void *ctx, void *sta_ctx) 2350214501Srpaulo{ 2351289549Srpaulo#ifndef CONFIG_FIPS 2352289549Srpaulo#ifndef CONFIG_NO_RC4 2353214501Srpaulo struct hostapd_data *hapd = ctx; 2354214501Srpaulo struct sta_info *sta = sta_ctx; 2355214501Srpaulo ieee802_1x_tx_key(hapd, sta); 2356289549Srpaulo#endif /* CONFIG_NO_RC4 */ 2357289549Srpaulo#endif /* CONFIG_FIPS */ 2358214501Srpaulo} 2359214501Srpaulo 2360214501Srpaulo 2361214501Srpaulostatic void ieee802_1x_eapol_event(void *ctx, void *sta_ctx, 2362214501Srpaulo enum eapol_event type) 2363214501Srpaulo{ 2364214501Srpaulo /* struct hostapd_data *hapd = ctx; */ 2365214501Srpaulo struct sta_info *sta = sta_ctx; 2366214501Srpaulo switch (type) { 2367214501Srpaulo case EAPOL_AUTH_SM_CHANGE: 2368214501Srpaulo wpa_auth_sm_notify(sta->wpa_sm); 2369214501Srpaulo break; 2370214501Srpaulo case EAPOL_AUTH_REAUTHENTICATE: 2371214501Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL); 2372214501Srpaulo break; 2373214501Srpaulo } 2374214501Srpaulo} 2375214501Srpaulo 2376214501Srpaulo 2377281806Srpaulo#ifdef CONFIG_ERP 2378281806Srpaulo 2379281806Srpaulostatic struct eap_server_erp_key * 2380281806Srpauloieee802_1x_erp_get_key(void *ctx, const char *keyname) 2381281806Srpaulo{ 2382281806Srpaulo struct hostapd_data *hapd = ctx; 2383281806Srpaulo struct eap_server_erp_key *erp; 2384281806Srpaulo 2385281806Srpaulo dl_list_for_each(erp, &hapd->erp_keys, struct eap_server_erp_key, 2386281806Srpaulo list) { 2387281806Srpaulo if (os_strcmp(erp->keyname_nai, keyname) == 0) 2388281806Srpaulo return erp; 2389281806Srpaulo } 2390281806Srpaulo 2391281806Srpaulo return NULL; 2392281806Srpaulo} 2393281806Srpaulo 2394281806Srpaulo 2395281806Srpaulostatic int ieee802_1x_erp_add_key(void *ctx, struct eap_server_erp_key *erp) 2396281806Srpaulo{ 2397281806Srpaulo struct hostapd_data *hapd = ctx; 2398281806Srpaulo 2399281806Srpaulo dl_list_add(&hapd->erp_keys, &erp->list); 2400281806Srpaulo return 0; 2401281806Srpaulo} 2402281806Srpaulo 2403281806Srpaulo#endif /* CONFIG_ERP */ 2404281806Srpaulo 2405281806Srpaulo 2406214501Srpauloint ieee802_1x_init(struct hostapd_data *hapd) 2407214501Srpaulo{ 2408214501Srpaulo int i; 2409214501Srpaulo struct eapol_auth_config conf; 2410214501Srpaulo struct eapol_auth_cb cb; 2411214501Srpaulo 2412281806Srpaulo dl_list_init(&hapd->erp_keys); 2413281806Srpaulo 2414214501Srpaulo os_memset(&conf, 0, sizeof(conf)); 2415214501Srpaulo conf.ctx = hapd; 2416214501Srpaulo conf.eap_reauth_period = hapd->conf->eap_reauth_period; 2417214501Srpaulo conf.wpa = hapd->conf->wpa; 2418214501Srpaulo conf.individual_wep_key_len = hapd->conf->individual_wep_key_len; 2419214501Srpaulo conf.eap_server = hapd->conf->eap_server; 2420214501Srpaulo conf.ssl_ctx = hapd->ssl_ctx; 2421214501Srpaulo conf.msg_ctx = hapd->msg_ctx; 2422214501Srpaulo conf.eap_sim_db_priv = hapd->eap_sim_db_priv; 2423214501Srpaulo conf.eap_req_id_text = hapd->conf->eap_req_id_text; 2424214501Srpaulo conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len; 2425281806Srpaulo conf.erp_send_reauth_start = hapd->conf->erp_send_reauth_start; 2426281806Srpaulo conf.erp_domain = hapd->conf->erp_domain; 2427281806Srpaulo conf.erp = hapd->conf->eap_server_erp; 2428289549Srpaulo conf.tls_session_lifetime = hapd->conf->tls_session_lifetime; 2429346981Scy conf.tls_flags = hapd->conf->tls_flags; 2430214501Srpaulo conf.pac_opaque_encr_key = hapd->conf->pac_opaque_encr_key; 2431214501Srpaulo conf.eap_fast_a_id = hapd->conf->eap_fast_a_id; 2432214501Srpaulo conf.eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len; 2433214501Srpaulo conf.eap_fast_a_id_info = hapd->conf->eap_fast_a_id_info; 2434214501Srpaulo conf.eap_fast_prov = hapd->conf->eap_fast_prov; 2435214501Srpaulo conf.pac_key_lifetime = hapd->conf->pac_key_lifetime; 2436214501Srpaulo conf.pac_key_refresh_time = hapd->conf->pac_key_refresh_time; 2437351611Scy conf.eap_teap_auth = hapd->conf->eap_teap_auth; 2438351611Scy conf.eap_teap_pac_no_inner = hapd->conf->eap_teap_pac_no_inner; 2439214501Srpaulo conf.eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind; 2440351611Scy conf.eap_sim_id = hapd->conf->eap_sim_id; 2441214501Srpaulo conf.tnc = hapd->conf->tnc; 2442214501Srpaulo conf.wps = hapd->wps; 2443252726Srpaulo conf.fragment_size = hapd->conf->fragment_size; 2444252726Srpaulo conf.pwd_group = hapd->conf->pwd_group; 2445252726Srpaulo conf.pbc_in_m1 = hapd->conf->pbc_in_m1; 2446281806Srpaulo if (hapd->conf->server_id) { 2447281806Srpaulo conf.server_id = (const u8 *) hapd->conf->server_id; 2448281806Srpaulo conf.server_id_len = os_strlen(hapd->conf->server_id); 2449281806Srpaulo } else { 2450281806Srpaulo conf.server_id = (const u8 *) "hostapd"; 2451281806Srpaulo conf.server_id_len = 7; 2452281806Srpaulo } 2453214501Srpaulo 2454214501Srpaulo os_memset(&cb, 0, sizeof(cb)); 2455214501Srpaulo cb.eapol_send = ieee802_1x_eapol_send; 2456214501Srpaulo cb.aaa_send = ieee802_1x_aaa_send; 2457214501Srpaulo cb.finished = _ieee802_1x_finished; 2458214501Srpaulo cb.get_eap_user = ieee802_1x_get_eap_user; 2459214501Srpaulo cb.sta_entry_alive = ieee802_1x_sta_entry_alive; 2460214501Srpaulo cb.logger = ieee802_1x_logger; 2461214501Srpaulo cb.set_port_authorized = ieee802_1x_set_port_authorized; 2462214501Srpaulo cb.abort_auth = _ieee802_1x_abort_auth; 2463214501Srpaulo cb.tx_key = _ieee802_1x_tx_key; 2464214501Srpaulo cb.eapol_event = ieee802_1x_eapol_event; 2465281806Srpaulo#ifdef CONFIG_ERP 2466281806Srpaulo cb.erp_get_key = ieee802_1x_erp_get_key; 2467281806Srpaulo cb.erp_add_key = ieee802_1x_erp_add_key; 2468281806Srpaulo#endif /* CONFIG_ERP */ 2469214501Srpaulo 2470214501Srpaulo hapd->eapol_auth = eapol_auth_init(&conf, &cb); 2471214501Srpaulo if (hapd->eapol_auth == NULL) 2472214501Srpaulo return -1; 2473214501Srpaulo 2474214501Srpaulo if ((hapd->conf->ieee802_1x || hapd->conf->wpa) && 2475252726Srpaulo hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1)) 2476214501Srpaulo return -1; 2477214501Srpaulo 2478214501Srpaulo#ifndef CONFIG_NO_RADIUS 2479214501Srpaulo if (radius_client_register(hapd->radius, RADIUS_AUTH, 2480214501Srpaulo ieee802_1x_receive_auth, hapd)) 2481214501Srpaulo return -1; 2482214501Srpaulo#endif /* CONFIG_NO_RADIUS */ 2483214501Srpaulo 2484214501Srpaulo if (hapd->conf->default_wep_key_len) { 2485214501Srpaulo for (i = 0; i < 4; i++) 2486252726Srpaulo hostapd_drv_set_key(hapd->conf->iface, hapd, 2487252726Srpaulo WPA_ALG_NONE, NULL, i, 0, NULL, 0, 2488252726Srpaulo NULL, 0); 2489214501Srpaulo 2490214501Srpaulo ieee802_1x_rekey(hapd, NULL); 2491214501Srpaulo 2492214501Srpaulo if (hapd->eapol_auth->default_wep_key == NULL) 2493214501Srpaulo return -1; 2494214501Srpaulo } 2495214501Srpaulo 2496214501Srpaulo return 0; 2497214501Srpaulo} 2498214501Srpaulo 2499214501Srpaulo 2500281806Srpaulovoid ieee802_1x_erp_flush(struct hostapd_data *hapd) 2501281806Srpaulo{ 2502281806Srpaulo struct eap_server_erp_key *erp; 2503281806Srpaulo 2504281806Srpaulo while ((erp = dl_list_first(&hapd->erp_keys, struct eap_server_erp_key, 2505281806Srpaulo list)) != NULL) { 2506281806Srpaulo dl_list_del(&erp->list); 2507281806Srpaulo bin_clear_free(erp, sizeof(*erp)); 2508281806Srpaulo } 2509281806Srpaulo} 2510281806Srpaulo 2511281806Srpaulo 2512214501Srpaulovoid ieee802_1x_deinit(struct hostapd_data *hapd) 2513214501Srpaulo{ 2514214501Srpaulo eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL); 2515214501Srpaulo 2516337817Scy if (hapd->driver && hapd->drv_priv && 2517214501Srpaulo (hapd->conf->ieee802_1x || hapd->conf->wpa)) 2518252726Srpaulo hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0); 2519214501Srpaulo 2520214501Srpaulo eapol_auth_deinit(hapd->eapol_auth); 2521214501Srpaulo hapd->eapol_auth = NULL; 2522281806Srpaulo 2523281806Srpaulo ieee802_1x_erp_flush(hapd); 2524214501Srpaulo} 2525214501Srpaulo 2526214501Srpaulo 2527214501Srpauloint ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta, 2528214501Srpaulo const u8 *buf, size_t len, int ack) 2529214501Srpaulo{ 2530214501Srpaulo struct ieee80211_hdr *hdr; 2531214501Srpaulo u8 *pos; 2532214501Srpaulo const unsigned char rfc1042_hdr[ETH_ALEN] = 2533214501Srpaulo { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; 2534214501Srpaulo 2535214501Srpaulo if (sta == NULL) 2536214501Srpaulo return -1; 2537252726Srpaulo if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2) 2538214501Srpaulo return 0; 2539214501Srpaulo 2540214501Srpaulo hdr = (struct ieee80211_hdr *) buf; 2541214501Srpaulo pos = (u8 *) (hdr + 1); 2542214501Srpaulo if (os_memcmp(pos, rfc1042_hdr, sizeof(rfc1042_hdr)) != 0) 2543214501Srpaulo return 0; 2544214501Srpaulo pos += sizeof(rfc1042_hdr); 2545214501Srpaulo if (WPA_GET_BE16(pos) != ETH_P_PAE) 2546214501Srpaulo return 0; 2547214501Srpaulo pos += 2; 2548214501Srpaulo 2549252726Srpaulo return ieee802_1x_eapol_tx_status(hapd, sta, pos, buf + len - pos, 2550252726Srpaulo ack); 2551252726Srpaulo} 2552214501Srpaulo 2553252726Srpaulo 2554252726Srpauloint ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta, 2555252726Srpaulo const u8 *buf, int len, int ack) 2556252726Srpaulo{ 2557252726Srpaulo const struct ieee802_1x_hdr *xhdr = 2558252726Srpaulo (const struct ieee802_1x_hdr *) buf; 2559252726Srpaulo const u8 *pos = buf + sizeof(*xhdr); 2560252726Srpaulo struct ieee802_1x_eapol_key *key; 2561252726Srpaulo 2562252726Srpaulo if (len < (int) sizeof(*xhdr)) 2563252726Srpaulo return 0; 2564214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " TX status - version=%d " 2565214501Srpaulo "type=%d length=%d - ack=%d", 2566214501Srpaulo MAC2STR(sta->addr), xhdr->version, xhdr->type, 2567214501Srpaulo be_to_host16(xhdr->length), ack); 2568214501Srpaulo 2569346981Scy#ifdef CONFIG_WPS 2570346981Scy if (xhdr->type == IEEE802_1X_TYPE_EAP_PACKET && ack && 2571346981Scy (sta->flags & WLAN_STA_WPS) && 2572346981Scy ap_sta_pending_delayed_1x_auth_fail_disconnect(hapd, sta)) { 2573346981Scy wpa_printf(MSG_DEBUG, 2574346981Scy "WPS: Indicate EAP completion on ACK for EAP-Failure"); 2575346981Scy hostapd_wps_eap_completed(hapd); 2576346981Scy } 2577346981Scy#endif /* CONFIG_WPS */ 2578346981Scy 2579252726Srpaulo if (xhdr->type != IEEE802_1X_TYPE_EAPOL_KEY) 2580252726Srpaulo return 0; 2581252726Srpaulo 2582252726Srpaulo if (pos + sizeof(struct wpa_eapol_key) <= buf + len) { 2583252726Srpaulo const struct wpa_eapol_key *wpa; 2584252726Srpaulo wpa = (const struct wpa_eapol_key *) pos; 2585252726Srpaulo if (wpa->type == EAPOL_KEY_TYPE_RSN || 2586252726Srpaulo wpa->type == EAPOL_KEY_TYPE_WPA) 2587252726Srpaulo wpa_auth_eapol_key_tx_status(hapd->wpa_auth, 2588252726Srpaulo sta->wpa_sm, ack); 2589252726Srpaulo } 2590252726Srpaulo 2591214501Srpaulo /* EAPOL EAP-Packet packets are eventually re-sent by either Supplicant 2592214501Srpaulo * or Authenticator state machines, but EAPOL-Key packets are not 2593252726Srpaulo * retransmitted in case of failure. Try to re-send failed EAPOL-Key 2594214501Srpaulo * packets couple of times because otherwise STA keys become 2595214501Srpaulo * unsynchronized with AP. */ 2596252726Srpaulo if (!ack && pos + sizeof(*key) <= buf + len) { 2597214501Srpaulo key = (struct ieee802_1x_eapol_key *) pos; 2598214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 2599214501Srpaulo HOSTAPD_LEVEL_DEBUG, "did not Ack EAPOL-Key " 2600214501Srpaulo "frame (%scast index=%d)", 2601214501Srpaulo key->key_index & BIT(7) ? "uni" : "broad", 2602214501Srpaulo key->key_index & ~BIT(7)); 2603214501Srpaulo /* TODO: re-send EAPOL-Key couple of times (with short delay 2604214501Srpaulo * between them?). If all attempt fail, report error and 2605214501Srpaulo * deauthenticate STA so that it will get new keys when 2606214501Srpaulo * authenticating again (e.g., after returning in range). 2607214501Srpaulo * Separate limit/transmit state needed both for unicast and 2608214501Srpaulo * broadcast keys(?) */ 2609214501Srpaulo } 2610214501Srpaulo /* TODO: could move unicast key configuration from ieee802_1x_tx_key() 2611214501Srpaulo * to here and change the key only if the EAPOL-Key packet was Acked. 2612214501Srpaulo */ 2613214501Srpaulo 2614214501Srpaulo return 1; 2615214501Srpaulo} 2616214501Srpaulo 2617214501Srpaulo 2618214501Srpaulou8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len) 2619214501Srpaulo{ 2620214501Srpaulo if (sm == NULL || sm->identity == NULL) 2621214501Srpaulo return NULL; 2622214501Srpaulo 2623214501Srpaulo *len = sm->identity_len; 2624214501Srpaulo return sm->identity; 2625214501Srpaulo} 2626214501Srpaulo 2627214501Srpaulo 2628214501Srpaulou8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len, 2629214501Srpaulo int idx) 2630214501Srpaulo{ 2631214501Srpaulo if (sm == NULL || sm->radius_class.attr == NULL || 2632214501Srpaulo idx >= (int) sm->radius_class.count) 2633214501Srpaulo return NULL; 2634214501Srpaulo 2635214501Srpaulo *len = sm->radius_class.attr[idx].len; 2636214501Srpaulo return sm->radius_class.attr[idx].data; 2637214501Srpaulo} 2638214501Srpaulo 2639214501Srpaulo 2640252726Srpaulostruct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm) 2641252726Srpaulo{ 2642252726Srpaulo if (sm == NULL) 2643252726Srpaulo return NULL; 2644252726Srpaulo return sm->radius_cui; 2645252726Srpaulo} 2646252726Srpaulo 2647252726Srpaulo 2648214501Srpauloconst u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len) 2649214501Srpaulo{ 2650252726Srpaulo *len = 0; 2651214501Srpaulo if (sm == NULL) 2652214501Srpaulo return NULL; 2653214501Srpaulo 2654214501Srpaulo *len = sm->eap_if->eapKeyDataLen; 2655214501Srpaulo return sm->eap_if->eapKeyData; 2656214501Srpaulo} 2657214501Srpaulo 2658214501Srpaulo 2659351611Scy#ifdef CONFIG_MACSEC 2660351611Scyconst u8 * ieee802_1x_get_session_id(struct eapol_state_machine *sm, 2661351611Scy size_t *len) 2662351611Scy{ 2663351611Scy *len = 0; 2664351611Scy if (!sm || !sm->eap_if) 2665351611Scy return NULL; 2666351611Scy 2667351611Scy *len = sm->eap_if->eapSessionIdLen; 2668351611Scy return sm->eap_if->eapSessionId; 2669351611Scy} 2670351611Scy#endif /* CONFIG_MACSEC */ 2671351611Scy 2672351611Scy 2673214501Srpaulovoid ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm, 2674214501Srpaulo int enabled) 2675214501Srpaulo{ 2676214501Srpaulo if (sm == NULL) 2677214501Srpaulo return; 2678214501Srpaulo sm->eap_if->portEnabled = enabled ? TRUE : FALSE; 2679214501Srpaulo eapol_auth_step(sm); 2680214501Srpaulo} 2681214501Srpaulo 2682214501Srpaulo 2683214501Srpaulovoid ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, 2684214501Srpaulo int valid) 2685214501Srpaulo{ 2686214501Srpaulo if (sm == NULL) 2687214501Srpaulo return; 2688214501Srpaulo sm->portValid = valid ? TRUE : FALSE; 2689214501Srpaulo eapol_auth_step(sm); 2690214501Srpaulo} 2691214501Srpaulo 2692214501Srpaulo 2693214501Srpaulovoid ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth) 2694214501Srpaulo{ 2695214501Srpaulo if (sm == NULL) 2696214501Srpaulo return; 2697214501Srpaulo if (pre_auth) 2698214501Srpaulo sm->flags |= EAPOL_SM_PREAUTH; 2699214501Srpaulo else 2700214501Srpaulo sm->flags &= ~EAPOL_SM_PREAUTH; 2701214501Srpaulo} 2702214501Srpaulo 2703214501Srpaulo 2704289549Srpaulostatic const char * bool_txt(Boolean val) 2705214501Srpaulo{ 2706289549Srpaulo return val ? "TRUE" : "FALSE"; 2707214501Srpaulo} 2708214501Srpaulo 2709214501Srpaulo 2710214501Srpauloint ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen) 2711214501Srpaulo{ 2712214501Srpaulo /* TODO */ 2713214501Srpaulo return 0; 2714214501Srpaulo} 2715214501Srpaulo 2716214501Srpaulo 2717214501Srpauloint ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, 2718214501Srpaulo char *buf, size_t buflen) 2719214501Srpaulo{ 2720214501Srpaulo int len = 0, ret; 2721214501Srpaulo struct eapol_state_machine *sm = sta->eapol_sm; 2722281806Srpaulo struct os_reltime diff; 2723281806Srpaulo const char *name1; 2724281806Srpaulo const char *name2; 2725346981Scy char *identity_buf = NULL; 2726214501Srpaulo 2727214501Srpaulo if (sm == NULL) 2728214501Srpaulo return 0; 2729214501Srpaulo 2730214501Srpaulo ret = os_snprintf(buf + len, buflen - len, 2731214501Srpaulo "dot1xPaePortNumber=%d\n" 2732214501Srpaulo "dot1xPaePortProtocolVersion=%d\n" 2733214501Srpaulo "dot1xPaePortCapabilities=1\n" 2734214501Srpaulo "dot1xPaePortInitialize=%d\n" 2735214501Srpaulo "dot1xPaePortReauthenticate=FALSE\n", 2736214501Srpaulo sta->aid, 2737214501Srpaulo EAPOL_VERSION, 2738214501Srpaulo sm->initialize); 2739281806Srpaulo if (os_snprintf_error(buflen - len, ret)) 2740214501Srpaulo return len; 2741214501Srpaulo len += ret; 2742214501Srpaulo 2743214501Srpaulo /* dot1xAuthConfigTable */ 2744214501Srpaulo ret = os_snprintf(buf + len, buflen - len, 2745214501Srpaulo "dot1xAuthPaeState=%d\n" 2746214501Srpaulo "dot1xAuthBackendAuthState=%d\n" 2747214501Srpaulo "dot1xAuthAdminControlledDirections=%d\n" 2748214501Srpaulo "dot1xAuthOperControlledDirections=%d\n" 2749214501Srpaulo "dot1xAuthAuthControlledPortStatus=%d\n" 2750214501Srpaulo "dot1xAuthAuthControlledPortControl=%d\n" 2751214501Srpaulo "dot1xAuthQuietPeriod=%u\n" 2752214501Srpaulo "dot1xAuthServerTimeout=%u\n" 2753214501Srpaulo "dot1xAuthReAuthPeriod=%u\n" 2754214501Srpaulo "dot1xAuthReAuthEnabled=%s\n" 2755214501Srpaulo "dot1xAuthKeyTxEnabled=%s\n", 2756214501Srpaulo sm->auth_pae_state + 1, 2757214501Srpaulo sm->be_auth_state + 1, 2758214501Srpaulo sm->adminControlledDirections, 2759214501Srpaulo sm->operControlledDirections, 2760214501Srpaulo sm->authPortStatus, 2761214501Srpaulo sm->portControl, 2762214501Srpaulo sm->quietPeriod, 2763214501Srpaulo sm->serverTimeout, 2764214501Srpaulo sm->reAuthPeriod, 2765214501Srpaulo bool_txt(sm->reAuthEnabled), 2766214501Srpaulo bool_txt(sm->keyTxEnabled)); 2767281806Srpaulo if (os_snprintf_error(buflen - len, ret)) 2768214501Srpaulo return len; 2769214501Srpaulo len += ret; 2770214501Srpaulo 2771214501Srpaulo /* dot1xAuthStatsTable */ 2772214501Srpaulo ret = os_snprintf(buf + len, buflen - len, 2773214501Srpaulo "dot1xAuthEapolFramesRx=%u\n" 2774214501Srpaulo "dot1xAuthEapolFramesTx=%u\n" 2775214501Srpaulo "dot1xAuthEapolStartFramesRx=%u\n" 2776214501Srpaulo "dot1xAuthEapolLogoffFramesRx=%u\n" 2777214501Srpaulo "dot1xAuthEapolRespIdFramesRx=%u\n" 2778214501Srpaulo "dot1xAuthEapolRespFramesRx=%u\n" 2779214501Srpaulo "dot1xAuthEapolReqIdFramesTx=%u\n" 2780214501Srpaulo "dot1xAuthEapolReqFramesTx=%u\n" 2781214501Srpaulo "dot1xAuthInvalidEapolFramesRx=%u\n" 2782214501Srpaulo "dot1xAuthEapLengthErrorFramesRx=%u\n" 2783214501Srpaulo "dot1xAuthLastEapolFrameVersion=%u\n" 2784214501Srpaulo "dot1xAuthLastEapolFrameSource=" MACSTR "\n", 2785214501Srpaulo sm->dot1xAuthEapolFramesRx, 2786214501Srpaulo sm->dot1xAuthEapolFramesTx, 2787214501Srpaulo sm->dot1xAuthEapolStartFramesRx, 2788214501Srpaulo sm->dot1xAuthEapolLogoffFramesRx, 2789214501Srpaulo sm->dot1xAuthEapolRespIdFramesRx, 2790214501Srpaulo sm->dot1xAuthEapolRespFramesRx, 2791214501Srpaulo sm->dot1xAuthEapolReqIdFramesTx, 2792214501Srpaulo sm->dot1xAuthEapolReqFramesTx, 2793214501Srpaulo sm->dot1xAuthInvalidEapolFramesRx, 2794214501Srpaulo sm->dot1xAuthEapLengthErrorFramesRx, 2795214501Srpaulo sm->dot1xAuthLastEapolFrameVersion, 2796214501Srpaulo MAC2STR(sm->addr)); 2797281806Srpaulo if (os_snprintf_error(buflen - len, ret)) 2798214501Srpaulo return len; 2799214501Srpaulo len += ret; 2800214501Srpaulo 2801214501Srpaulo /* dot1xAuthDiagTable */ 2802214501Srpaulo ret = os_snprintf(buf + len, buflen - len, 2803214501Srpaulo "dot1xAuthEntersConnecting=%u\n" 2804214501Srpaulo "dot1xAuthEapLogoffsWhileConnecting=%u\n" 2805214501Srpaulo "dot1xAuthEntersAuthenticating=%u\n" 2806214501Srpaulo "dot1xAuthAuthSuccessesWhileAuthenticating=%u\n" 2807214501Srpaulo "dot1xAuthAuthTimeoutsWhileAuthenticating=%u\n" 2808214501Srpaulo "dot1xAuthAuthFailWhileAuthenticating=%u\n" 2809214501Srpaulo "dot1xAuthAuthEapStartsWhileAuthenticating=%u\n" 2810214501Srpaulo "dot1xAuthAuthEapLogoffWhileAuthenticating=%u\n" 2811214501Srpaulo "dot1xAuthAuthReauthsWhileAuthenticated=%u\n" 2812214501Srpaulo "dot1xAuthAuthEapStartsWhileAuthenticated=%u\n" 2813214501Srpaulo "dot1xAuthAuthEapLogoffWhileAuthenticated=%u\n" 2814214501Srpaulo "dot1xAuthBackendResponses=%u\n" 2815214501Srpaulo "dot1xAuthBackendAccessChallenges=%u\n" 2816214501Srpaulo "dot1xAuthBackendOtherRequestsToSupplicant=%u\n" 2817214501Srpaulo "dot1xAuthBackendAuthSuccesses=%u\n" 2818214501Srpaulo "dot1xAuthBackendAuthFails=%u\n", 2819214501Srpaulo sm->authEntersConnecting, 2820214501Srpaulo sm->authEapLogoffsWhileConnecting, 2821214501Srpaulo sm->authEntersAuthenticating, 2822214501Srpaulo sm->authAuthSuccessesWhileAuthenticating, 2823214501Srpaulo sm->authAuthTimeoutsWhileAuthenticating, 2824214501Srpaulo sm->authAuthFailWhileAuthenticating, 2825214501Srpaulo sm->authAuthEapStartsWhileAuthenticating, 2826214501Srpaulo sm->authAuthEapLogoffWhileAuthenticating, 2827214501Srpaulo sm->authAuthReauthsWhileAuthenticated, 2828214501Srpaulo sm->authAuthEapStartsWhileAuthenticated, 2829214501Srpaulo sm->authAuthEapLogoffWhileAuthenticated, 2830214501Srpaulo sm->backendResponses, 2831214501Srpaulo sm->backendAccessChallenges, 2832214501Srpaulo sm->backendOtherRequestsToSupplicant, 2833214501Srpaulo sm->backendAuthSuccesses, 2834214501Srpaulo sm->backendAuthFails); 2835281806Srpaulo if (os_snprintf_error(buflen - len, ret)) 2836214501Srpaulo return len; 2837214501Srpaulo len += ret; 2838214501Srpaulo 2839214501Srpaulo /* dot1xAuthSessionStatsTable */ 2840281806Srpaulo os_reltime_age(&sta->acct_session_start, &diff); 2841346981Scy if (sm->eap && !sm->identity) { 2842346981Scy const u8 *id; 2843346981Scy size_t id_len; 2844346981Scy 2845346981Scy id = eap_get_identity(sm->eap, &id_len); 2846346981Scy if (id) 2847346981Scy identity_buf = dup_binstr(id, id_len); 2848346981Scy } 2849214501Srpaulo ret = os_snprintf(buf + len, buflen - len, 2850214501Srpaulo /* TODO: dot1xAuthSessionOctetsRx */ 2851214501Srpaulo /* TODO: dot1xAuthSessionOctetsTx */ 2852214501Srpaulo /* TODO: dot1xAuthSessionFramesRx */ 2853214501Srpaulo /* TODO: dot1xAuthSessionFramesTx */ 2854337817Scy "dot1xAuthSessionId=%016llX\n" 2855214501Srpaulo "dot1xAuthSessionAuthenticMethod=%d\n" 2856214501Srpaulo "dot1xAuthSessionTime=%u\n" 2857214501Srpaulo "dot1xAuthSessionTerminateCause=999\n" 2858214501Srpaulo "dot1xAuthSessionUserName=%s\n", 2859337817Scy (unsigned long long) sta->acct_session_id, 2860214501Srpaulo (wpa_key_mgmt_wpa_ieee8021x( 2861214501Srpaulo wpa_auth_sta_key_mgmt(sta->wpa_sm))) ? 2862214501Srpaulo 1 : 2, 2863281806Srpaulo (unsigned int) diff.sec, 2864346981Scy sm->identity ? (char *) sm->identity : 2865346981Scy (identity_buf ? identity_buf : "N/A")); 2866346981Scy os_free(identity_buf); 2867281806Srpaulo if (os_snprintf_error(buflen - len, ret)) 2868214501Srpaulo return len; 2869214501Srpaulo len += ret; 2870214501Srpaulo 2871337817Scy if (sm->acct_multi_session_id) { 2872281806Srpaulo ret = os_snprintf(buf + len, buflen - len, 2873337817Scy "authMultiSessionId=%016llX\n", 2874337817Scy (unsigned long long) 2875337817Scy sm->acct_multi_session_id); 2876281806Srpaulo if (os_snprintf_error(buflen - len, ret)) 2877281806Srpaulo return len; 2878281806Srpaulo len += ret; 2879281806Srpaulo } 2880281806Srpaulo 2881281806Srpaulo name1 = eap_server_get_name(0, sm->eap_type_authsrv); 2882281806Srpaulo name2 = eap_server_get_name(0, sm->eap_type_supp); 2883281806Srpaulo ret = os_snprintf(buf + len, buflen - len, 2884281806Srpaulo "last_eap_type_as=%d (%s)\n" 2885281806Srpaulo "last_eap_type_sta=%d (%s)\n", 2886281806Srpaulo sm->eap_type_authsrv, name1, 2887281806Srpaulo sm->eap_type_supp, name2); 2888281806Srpaulo if (os_snprintf_error(buflen - len, ret)) 2889281806Srpaulo return len; 2890281806Srpaulo len += ret; 2891281806Srpaulo 2892214501Srpaulo return len; 2893214501Srpaulo} 2894214501Srpaulo 2895214501Srpaulo 2896337817Scy#ifdef CONFIG_HS20 2897337817Scystatic void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx) 2898337817Scy{ 2899337817Scy struct hostapd_data *hapd = eloop_ctx; 2900337817Scy struct sta_info *sta = timeout_ctx; 2901337817Scy 2902337817Scy if (sta->remediation) { 2903337817Scy wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to " 2904337817Scy MACSTR " to indicate Subscription Remediation", 2905337817Scy MAC2STR(sta->addr)); 2906337817Scy hs20_send_wnm_notification(hapd, sta->addr, 2907337817Scy sta->remediation_method, 2908337817Scy sta->remediation_url); 2909337817Scy os_free(sta->remediation_url); 2910337817Scy sta->remediation_url = NULL; 2911337817Scy } 2912337817Scy 2913337817Scy if (sta->hs20_deauth_req) { 2914337817Scy wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to " 2915337817Scy MACSTR " to indicate imminent deauthentication", 2916337817Scy MAC2STR(sta->addr)); 2917337817Scy hs20_send_wnm_notification_deauth_req(hapd, sta->addr, 2918337817Scy sta->hs20_deauth_req); 2919337817Scy } 2920346981Scy 2921346981Scy if (sta->hs20_t_c_filtering) { 2922346981Scy wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to " 2923346981Scy MACSTR " to indicate Terms and Conditions filtering", 2924346981Scy MAC2STR(sta->addr)); 2925346981Scy hs20_send_wnm_notification_t_c(hapd, sta->addr, sta->t_c_url); 2926346981Scy os_free(sta->t_c_url); 2927346981Scy sta->t_c_url = NULL; 2928346981Scy } 2929337817Scy} 2930337817Scy#endif /* CONFIG_HS20 */ 2931337817Scy 2932337817Scy 2933214501Srpaulostatic void ieee802_1x_finished(struct hostapd_data *hapd, 2934281806Srpaulo struct sta_info *sta, int success, 2935281806Srpaulo int remediation) 2936214501Srpaulo{ 2937214501Srpaulo const u8 *key; 2938214501Srpaulo size_t len; 2939214501Srpaulo /* TODO: get PMKLifetime from WPA parameters */ 2940214501Srpaulo static const int dot11RSNAConfigPMKLifetime = 43200; 2941281806Srpaulo unsigned int session_timeout; 2942346981Scy struct os_reltime now, remaining; 2943214501Srpaulo 2944281806Srpaulo#ifdef CONFIG_HS20 2945281806Srpaulo if (remediation && !sta->remediation) { 2946281806Srpaulo sta->remediation = 1; 2947281806Srpaulo os_free(sta->remediation_url); 2948281806Srpaulo sta->remediation_url = 2949281806Srpaulo os_strdup(hapd->conf->subscr_remediation_url); 2950281806Srpaulo sta->remediation_method = 1; /* SOAP-XML SPP */ 2951281806Srpaulo } 2952281806Srpaulo 2953346981Scy if (success && (sta->remediation || sta->hs20_deauth_req || 2954346981Scy sta->hs20_t_c_filtering)) { 2955337817Scy wpa_printf(MSG_DEBUG, "HS 2.0: Schedule WNM-Notification to " 2956337817Scy MACSTR " in 100 ms", MAC2STR(sta->addr)); 2957337817Scy eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta); 2958337817Scy eloop_register_timeout(0, 100000, ieee802_1x_wnm_notif_send, 2959337817Scy hapd, sta); 2960281806Srpaulo } 2961281806Srpaulo#endif /* CONFIG_HS20 */ 2962281806Srpaulo 2963351611Scy#ifdef CONFIG_MACSEC 2964351611Scy ieee802_1x_notify_create_actor_hapd(hapd, sta); 2965351611Scy#endif /* CONFIG_MACSEC */ 2966351611Scy 2967214501Srpaulo key = ieee802_1x_get_key(sta->eapol_sm, &len); 2968346981Scy if (sta->session_timeout_set) { 2969346981Scy os_get_reltime(&now); 2970346981Scy os_reltime_sub(&sta->session_timeout, &now, &remaining); 2971346981Scy session_timeout = (remaining.sec > 0) ? remaining.sec : 1; 2972346981Scy } else { 2973281806Srpaulo session_timeout = dot11RSNAConfigPMKLifetime; 2974346981Scy } 2975281806Srpaulo if (success && key && len >= PMK_LEN && !sta->remediation && 2976281806Srpaulo !sta->hs20_deauth_requested && 2977337817Scy wpa_auth_pmksa_add(sta->wpa_sm, key, len, session_timeout, 2978214501Srpaulo sta->eapol_sm) == 0) { 2979214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, 2980214501Srpaulo HOSTAPD_LEVEL_DEBUG, 2981214501Srpaulo "Added PMKSA cache entry (IEEE 802.1X)"); 2982214501Srpaulo } 2983214501Srpaulo 2984252726Srpaulo if (!success) { 2985214501Srpaulo /* 2986214501Srpaulo * Many devices require deauthentication after WPS provisioning 2987214501Srpaulo * and some may not be be able to do that themselves, so 2988252726Srpaulo * disconnect the client here. In addition, this may also 2989252726Srpaulo * benefit IEEE 802.1X/EAPOL authentication cases, too since 2990252726Srpaulo * the EAPOL PAE state machine would remain in HELD state for 2991252726Srpaulo * considerable amount of time and some EAP methods, like 2992252726Srpaulo * EAP-FAST with anonymous provisioning, may require another 2993252726Srpaulo * EAPOL authentication to be started to complete connection. 2994214501Srpaulo */ 2995346981Scy ap_sta_delayed_1x_auth_fail_disconnect(hapd, sta); 2996214501Srpaulo } 2997214501Srpaulo} 2998