1e28a4053SRui Paulo /* 2e28a4053SRui Paulo * hostapd / IEEE 802.1X-2004 Authenticator 34bc52338SCy Schubert * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> 4e28a4053SRui Paulo * 5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6f05cddf9SRui Paulo * See README for more details. 7e28a4053SRui Paulo */ 8e28a4053SRui Paulo 9e28a4053SRui Paulo #include "utils/includes.h" 10206b73d0SCy Schubert #ifdef CONFIG_SQLITE 11206b73d0SCy Schubert #include <sqlite3.h> 12206b73d0SCy Schubert #endif /* CONFIG_SQLITE */ 13e28a4053SRui Paulo 14e28a4053SRui Paulo #include "utils/common.h" 15e28a4053SRui Paulo #include "utils/eloop.h" 16e28a4053SRui Paulo #include "crypto/md5.h" 17e28a4053SRui Paulo #include "crypto/crypto.h" 18f05cddf9SRui Paulo #include "crypto/random.h" 19e28a4053SRui Paulo #include "common/ieee802_11_defs.h" 20e28a4053SRui Paulo #include "radius/radius.h" 21e28a4053SRui Paulo #include "radius/radius_client.h" 22e28a4053SRui Paulo #include "eap_server/eap.h" 23e28a4053SRui Paulo #include "eap_common/eap_wsc_common.h" 24e28a4053SRui Paulo #include "eapol_auth/eapol_auth_sm.h" 25e28a4053SRui Paulo #include "eapol_auth/eapol_auth_sm_i.h" 26f05cddf9SRui Paulo #include "p2p/p2p.h" 27e28a4053SRui Paulo #include "hostapd.h" 28e28a4053SRui Paulo #include "accounting.h" 29e28a4053SRui Paulo #include "sta_info.h" 30e28a4053SRui Paulo #include "wpa_auth.h" 31e28a4053SRui Paulo #include "preauth_auth.h" 32e28a4053SRui Paulo #include "pmksa_cache_auth.h" 33e28a4053SRui Paulo #include "ap_config.h" 34f05cddf9SRui Paulo #include "ap_drv_ops.h" 355b9c547cSRui Paulo #include "wps_hostapd.h" 365b9c547cSRui Paulo #include "hs20.h" 3785732ac8SCy Schubert /* FIX: Not really a good thing to require ieee802_11.h here.. (FILS) */ 3885732ac8SCy Schubert #include "ieee802_11.h" 39e28a4053SRui Paulo #include "ieee802_1x.h" 40206b73d0SCy Schubert #include "wpa_auth_kay.h" 41e28a4053SRui Paulo 42e28a4053SRui Paulo 43780fb4a2SCy Schubert #ifdef CONFIG_HS20 44780fb4a2SCy Schubert static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx); 45780fb4a2SCy Schubert #endif /* CONFIG_HS20 */ 46e28a4053SRui Paulo static void ieee802_1x_finished(struct hostapd_data *hapd, 475b9c547cSRui Paulo struct sta_info *sta, int success, 485b9c547cSRui Paulo int remediation); 49e28a4053SRui Paulo 50e28a4053SRui Paulo 51e28a4053SRui Paulo static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta, 52e28a4053SRui Paulo u8 type, const u8 *data, size_t datalen) 53e28a4053SRui Paulo { 54e28a4053SRui Paulo u8 *buf; 55e28a4053SRui Paulo struct ieee802_1x_hdr *xhdr; 56e28a4053SRui Paulo size_t len; 57e28a4053SRui Paulo int encrypt = 0; 58e28a4053SRui Paulo 59e28a4053SRui Paulo len = sizeof(*xhdr) + datalen; 60e28a4053SRui Paulo buf = os_zalloc(len); 61*c1d255d3SCy Schubert if (!buf) { 62*c1d255d3SCy Schubert wpa_printf(MSG_ERROR, "malloc() failed for %s(len=%lu)", 63*c1d255d3SCy Schubert __func__, (unsigned long) len); 64e28a4053SRui Paulo return; 65e28a4053SRui Paulo } 66e28a4053SRui Paulo 67e28a4053SRui Paulo xhdr = (struct ieee802_1x_hdr *) buf; 68e28a4053SRui Paulo xhdr->version = hapd->conf->eapol_version; 69206b73d0SCy Schubert #ifdef CONFIG_MACSEC 70206b73d0SCy Schubert if (xhdr->version > 2 && hapd->conf->macsec_policy == 0) 71206b73d0SCy Schubert xhdr->version = 2; 72206b73d0SCy Schubert #endif /* CONFIG_MACSEC */ 73e28a4053SRui Paulo xhdr->type = type; 74e28a4053SRui Paulo xhdr->length = host_to_be16(datalen); 75e28a4053SRui Paulo 76e28a4053SRui Paulo if (datalen > 0 && data != NULL) 77e28a4053SRui Paulo os_memcpy(xhdr + 1, data, datalen); 78e28a4053SRui Paulo 79e28a4053SRui Paulo if (wpa_auth_pairwise_set(sta->wpa_sm)) 80e28a4053SRui Paulo encrypt = 1; 815b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS 825b9c547cSRui Paulo if (hapd->ext_eapol_frame_io) { 835b9c547cSRui Paulo size_t hex_len = 2 * len + 1; 845b9c547cSRui Paulo char *hex = os_malloc(hex_len); 855b9c547cSRui Paulo 865b9c547cSRui Paulo if (hex) { 875b9c547cSRui Paulo wpa_snprintf_hex(hex, hex_len, buf, len); 885b9c547cSRui Paulo wpa_msg(hapd->msg_ctx, MSG_INFO, 895b9c547cSRui Paulo "EAPOL-TX " MACSTR " %s", 905b9c547cSRui Paulo MAC2STR(sta->addr), hex); 915b9c547cSRui Paulo os_free(hex); 925b9c547cSRui Paulo } 935b9c547cSRui Paulo } else 945b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */ 95e28a4053SRui Paulo if (sta->flags & WLAN_STA_PREAUTH) { 96e28a4053SRui Paulo rsn_preauth_send(hapd, sta, buf, len); 97e28a4053SRui Paulo } else { 98f05cddf9SRui Paulo hostapd_drv_hapd_send_eapol( 99f05cddf9SRui Paulo hapd, sta->addr, buf, len, 100f05cddf9SRui Paulo encrypt, hostapd_sta_flags_to_drv(sta->flags)); 101e28a4053SRui Paulo } 102e28a4053SRui Paulo 103e28a4053SRui Paulo os_free(buf); 104e28a4053SRui Paulo } 105e28a4053SRui Paulo 106e28a4053SRui Paulo 107e28a4053SRui Paulo void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd, 108e28a4053SRui Paulo struct sta_info *sta, int authorized) 109e28a4053SRui Paulo { 110e28a4053SRui Paulo int res; 111e28a4053SRui Paulo 112e28a4053SRui Paulo if (sta->flags & WLAN_STA_PREAUTH) 113e28a4053SRui Paulo return; 114e28a4053SRui Paulo 115e28a4053SRui Paulo if (authorized) { 116f05cddf9SRui Paulo ap_sta_set_authorized(hapd, sta, 1); 117f05cddf9SRui Paulo res = hostapd_set_authorized(hapd, sta, 1); 118e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 119e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "authorizing port"); 120e28a4053SRui Paulo } else { 121f05cddf9SRui Paulo ap_sta_set_authorized(hapd, sta, 0); 122f05cddf9SRui Paulo res = hostapd_set_authorized(hapd, sta, 0); 123e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 124e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "unauthorizing port"); 125e28a4053SRui Paulo } 126e28a4053SRui Paulo 127e28a4053SRui Paulo if (res && errno != ENOENT) { 1285b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "Could not set station " MACSTR 1295b9c547cSRui Paulo " flags for kernel driver (errno=%d).", 1305b9c547cSRui Paulo MAC2STR(sta->addr), errno); 131e28a4053SRui Paulo } 132e28a4053SRui Paulo 133f05cddf9SRui Paulo if (authorized) { 1345b9c547cSRui Paulo os_get_reltime(&sta->connected_time); 135e28a4053SRui Paulo accounting_sta_start(hapd, sta); 136e28a4053SRui Paulo } 137f05cddf9SRui Paulo } 138e28a4053SRui Paulo 139e28a4053SRui Paulo 140*c1d255d3SCy Schubert #ifdef CONFIG_WEP 141325151a3SRui Paulo #ifndef CONFIG_FIPS 142325151a3SRui Paulo #ifndef CONFIG_NO_RC4 143325151a3SRui Paulo 144e28a4053SRui Paulo static void ieee802_1x_tx_key_one(struct hostapd_data *hapd, 145e28a4053SRui Paulo struct sta_info *sta, 146e28a4053SRui Paulo int idx, int broadcast, 147e28a4053SRui Paulo u8 *key_data, size_t key_len) 148e28a4053SRui Paulo { 149e28a4053SRui Paulo u8 *buf, *ekey; 150e28a4053SRui Paulo struct ieee802_1x_hdr *hdr; 151e28a4053SRui Paulo struct ieee802_1x_eapol_key *key; 152e28a4053SRui Paulo size_t len, ekey_len; 153e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 154e28a4053SRui Paulo 155*c1d255d3SCy Schubert if (!sm) 156e28a4053SRui Paulo return; 157e28a4053SRui Paulo 158e28a4053SRui Paulo len = sizeof(*key) + key_len; 159e28a4053SRui Paulo buf = os_zalloc(sizeof(*hdr) + len); 160*c1d255d3SCy Schubert if (!buf) 161e28a4053SRui Paulo return; 162e28a4053SRui Paulo 163e28a4053SRui Paulo hdr = (struct ieee802_1x_hdr *) buf; 164e28a4053SRui Paulo key = (struct ieee802_1x_eapol_key *) (hdr + 1); 165e28a4053SRui Paulo key->type = EAPOL_KEY_TYPE_RC4; 166f05cddf9SRui Paulo WPA_PUT_BE16(key->key_length, key_len); 167e28a4053SRui Paulo wpa_get_ntp_timestamp(key->replay_counter); 168206b73d0SCy Schubert if (os_memcmp(key->replay_counter, 169206b73d0SCy Schubert hapd->last_1x_eapol_key_replay_counter, 170206b73d0SCy Schubert IEEE8021X_REPLAY_COUNTER_LEN) <= 0) { 171206b73d0SCy Schubert /* NTP timestamp did not increment from last EAPOL-Key frame; 172206b73d0SCy Schubert * use previously used value + 1 instead. */ 173206b73d0SCy Schubert inc_byte_array(hapd->last_1x_eapol_key_replay_counter, 174206b73d0SCy Schubert IEEE8021X_REPLAY_COUNTER_LEN); 175206b73d0SCy Schubert os_memcpy(key->replay_counter, 176206b73d0SCy Schubert hapd->last_1x_eapol_key_replay_counter, 177206b73d0SCy Schubert IEEE8021X_REPLAY_COUNTER_LEN); 178206b73d0SCy Schubert } else { 179206b73d0SCy Schubert os_memcpy(hapd->last_1x_eapol_key_replay_counter, 180206b73d0SCy Schubert key->replay_counter, 181206b73d0SCy Schubert IEEE8021X_REPLAY_COUNTER_LEN); 182206b73d0SCy Schubert } 183e28a4053SRui Paulo 184f05cddf9SRui Paulo if (random_get_bytes(key->key_iv, sizeof(key->key_iv))) { 185e28a4053SRui Paulo wpa_printf(MSG_ERROR, "Could not get random numbers"); 186e28a4053SRui Paulo os_free(buf); 187e28a4053SRui Paulo return; 188e28a4053SRui Paulo } 189e28a4053SRui Paulo 190e28a4053SRui Paulo key->key_index = idx | (broadcast ? 0 : BIT(7)); 191e28a4053SRui Paulo if (hapd->conf->eapol_key_index_workaround) { 192e28a4053SRui Paulo /* According to some information, WinXP Supplicant seems to 193e28a4053SRui Paulo * interpret bit7 as an indication whether the key is to be 194e28a4053SRui Paulo * activated, so make it possible to enable workaround that 195e28a4053SRui Paulo * sets this bit for all keys. */ 196e28a4053SRui Paulo key->key_index |= BIT(7); 197e28a4053SRui Paulo } 198e28a4053SRui Paulo 199e28a4053SRui Paulo /* Key is encrypted using "Key-IV + MSK[0..31]" as the RC4-key and 200e28a4053SRui Paulo * MSK[32..63] is used to sign the message. */ 201*c1d255d3SCy Schubert if (!sm->eap_if->eapKeyData || sm->eap_if->eapKeyDataLen < 64) { 202*c1d255d3SCy Schubert wpa_printf(MSG_ERROR, 203*c1d255d3SCy Schubert "No eapKeyData available for encrypting and signing EAPOL-Key"); 204e28a4053SRui Paulo os_free(buf); 205e28a4053SRui Paulo return; 206e28a4053SRui Paulo } 207e28a4053SRui Paulo os_memcpy((u8 *) (key + 1), key_data, key_len); 208e28a4053SRui Paulo ekey_len = sizeof(key->key_iv) + 32; 209e28a4053SRui Paulo ekey = os_malloc(ekey_len); 210*c1d255d3SCy Schubert if (!ekey) { 211e28a4053SRui Paulo wpa_printf(MSG_ERROR, "Could not encrypt key"); 212e28a4053SRui Paulo os_free(buf); 213e28a4053SRui Paulo return; 214e28a4053SRui Paulo } 215e28a4053SRui Paulo os_memcpy(ekey, key->key_iv, sizeof(key->key_iv)); 216e28a4053SRui Paulo os_memcpy(ekey + sizeof(key->key_iv), sm->eap_if->eapKeyData, 32); 217e28a4053SRui Paulo rc4_skip(ekey, ekey_len, 0, (u8 *) (key + 1), key_len); 218e28a4053SRui Paulo os_free(ekey); 219e28a4053SRui Paulo 220e28a4053SRui Paulo /* This header is needed here for HMAC-MD5, but it will be regenerated 221e28a4053SRui Paulo * in ieee802_1x_send() */ 222e28a4053SRui Paulo hdr->version = hapd->conf->eapol_version; 223206b73d0SCy Schubert #ifdef CONFIG_MACSEC 224206b73d0SCy Schubert if (hdr->version > 2) 225206b73d0SCy Schubert hdr->version = 2; 226206b73d0SCy Schubert #endif /* CONFIG_MACSEC */ 227e28a4053SRui Paulo hdr->type = IEEE802_1X_TYPE_EAPOL_KEY; 228e28a4053SRui Paulo hdr->length = host_to_be16(len); 229e28a4053SRui Paulo hmac_md5(sm->eap_if->eapKeyData + 32, 32, buf, sizeof(*hdr) + len, 230e28a4053SRui Paulo key->key_signature); 231e28a4053SRui Paulo 232e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key to " MACSTR 233e28a4053SRui Paulo " (%s index=%d)", MAC2STR(sm->addr), 234e28a4053SRui Paulo broadcast ? "broadcast" : "unicast", idx); 235e28a4053SRui Paulo ieee802_1x_send(hapd, sta, IEEE802_1X_TYPE_EAPOL_KEY, (u8 *) key, len); 236e28a4053SRui Paulo if (sta->eapol_sm) 237e28a4053SRui Paulo sta->eapol_sm->dot1xAuthEapolFramesTx++; 238e28a4053SRui Paulo os_free(buf); 239e28a4053SRui Paulo } 240e28a4053SRui Paulo 241e28a4053SRui Paulo 242325151a3SRui Paulo static void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta) 243e28a4053SRui Paulo { 244e28a4053SRui Paulo struct eapol_authenticator *eapol = hapd->eapol_auth; 245e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 246e28a4053SRui Paulo 247*c1d255d3SCy Schubert if (!sm || !sm->eap_if->eapKeyData) 248e28a4053SRui Paulo return; 249e28a4053SRui Paulo 250e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key(s) to " MACSTR, 251e28a4053SRui Paulo MAC2STR(sta->addr)); 252e28a4053SRui Paulo 253e28a4053SRui Paulo #ifndef CONFIG_NO_VLAN 254780fb4a2SCy Schubert if (sta->vlan_id > 0) { 2555b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Using WEP with vlans is not supported."); 2565b9c547cSRui Paulo return; 2575b9c547cSRui Paulo } 258e28a4053SRui Paulo #endif /* CONFIG_NO_VLAN */ 2595b9c547cSRui Paulo 260e28a4053SRui Paulo if (eapol->default_wep_key) { 261e28a4053SRui Paulo ieee802_1x_tx_key_one(hapd, sta, eapol->default_wep_key_idx, 1, 262e28a4053SRui Paulo eapol->default_wep_key, 263e28a4053SRui Paulo hapd->conf->default_wep_key_len); 264e28a4053SRui Paulo } 265e28a4053SRui Paulo 266e28a4053SRui Paulo if (hapd->conf->individual_wep_key_len > 0) { 267e28a4053SRui Paulo u8 *ikey; 268*c1d255d3SCy Schubert 269e28a4053SRui Paulo ikey = os_malloc(hapd->conf->individual_wep_key_len); 270*c1d255d3SCy Schubert if (!ikey || 271f05cddf9SRui Paulo random_get_bytes(ikey, hapd->conf->individual_wep_key_len)) 272f05cddf9SRui Paulo { 273*c1d255d3SCy Schubert wpa_printf(MSG_ERROR, 274*c1d255d3SCy Schubert "Could not generate random individual WEP key"); 275e28a4053SRui Paulo os_free(ikey); 276e28a4053SRui Paulo return; 277e28a4053SRui Paulo } 278e28a4053SRui Paulo 279e28a4053SRui Paulo wpa_hexdump_key(MSG_DEBUG, "Individual WEP key", 280e28a4053SRui Paulo ikey, hapd->conf->individual_wep_key_len); 281e28a4053SRui Paulo 282e28a4053SRui Paulo ieee802_1x_tx_key_one(hapd, sta, 0, 0, ikey, 283e28a4053SRui Paulo hapd->conf->individual_wep_key_len); 284e28a4053SRui Paulo 285e28a4053SRui Paulo /* TODO: set encryption in TX callback, i.e., only after STA 286e28a4053SRui Paulo * has ACKed EAPOL-Key frame */ 287f05cddf9SRui Paulo if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, 288*c1d255d3SCy Schubert sta->addr, 0, 0, 1, NULL, 0, ikey, 289*c1d255d3SCy Schubert hapd->conf->individual_wep_key_len, 290*c1d255d3SCy Schubert KEY_FLAG_PAIRWISE_RX_TX)) { 291*c1d255d3SCy Schubert wpa_printf(MSG_ERROR, 292*c1d255d3SCy Schubert "Could not set individual WEP encryption"); 293e28a4053SRui Paulo } 294e28a4053SRui Paulo 295e28a4053SRui Paulo os_free(ikey); 296e28a4053SRui Paulo } 297e28a4053SRui Paulo } 298e28a4053SRui Paulo 299325151a3SRui Paulo #endif /* CONFIG_NO_RC4 */ 300325151a3SRui Paulo #endif /* CONFIG_FIPS */ 301*c1d255d3SCy Schubert #endif /* CONFIG_WEP */ 302325151a3SRui Paulo 303e28a4053SRui Paulo 304e28a4053SRui Paulo const char *radius_mode_txt(struct hostapd_data *hapd) 305e28a4053SRui Paulo { 306e28a4053SRui Paulo switch (hapd->iface->conf->hw_mode) { 307f05cddf9SRui Paulo case HOSTAPD_MODE_IEEE80211AD: 308f05cddf9SRui Paulo return "802.11ad"; 309e28a4053SRui Paulo case HOSTAPD_MODE_IEEE80211A: 310e28a4053SRui Paulo return "802.11a"; 311e28a4053SRui Paulo case HOSTAPD_MODE_IEEE80211G: 312e28a4053SRui Paulo return "802.11g"; 313e28a4053SRui Paulo case HOSTAPD_MODE_IEEE80211B: 314e28a4053SRui Paulo default: 315e28a4053SRui Paulo return "802.11b"; 316e28a4053SRui Paulo } 317e28a4053SRui Paulo } 318e28a4053SRui Paulo 319e28a4053SRui Paulo 320e28a4053SRui Paulo int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta) 321e28a4053SRui Paulo { 322e28a4053SRui Paulo int i; 323e28a4053SRui Paulo u8 rate = 0; 324e28a4053SRui Paulo 325e28a4053SRui Paulo for (i = 0; i < sta->supported_rates_len; i++) 326e28a4053SRui Paulo if ((sta->supported_rates[i] & 0x7f) > rate) 327e28a4053SRui Paulo rate = sta->supported_rates[i] & 0x7f; 328e28a4053SRui Paulo 329e28a4053SRui Paulo return rate; 330e28a4053SRui Paulo } 331e28a4053SRui Paulo 332e28a4053SRui Paulo 333e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS 334e28a4053SRui Paulo static void ieee802_1x_learn_identity(struct hostapd_data *hapd, 335e28a4053SRui Paulo struct eapol_state_machine *sm, 336e28a4053SRui Paulo const u8 *eap, size_t len) 337e28a4053SRui Paulo { 338e28a4053SRui Paulo const u8 *identity; 339e28a4053SRui Paulo size_t identity_len; 3405b9c547cSRui Paulo const struct eap_hdr *hdr = (const struct eap_hdr *) eap; 341e28a4053SRui Paulo 342e28a4053SRui Paulo if (len <= sizeof(struct eap_hdr) || 3435b9c547cSRui Paulo (hdr->code == EAP_CODE_RESPONSE && 3445b9c547cSRui Paulo eap[sizeof(struct eap_hdr)] != EAP_TYPE_IDENTITY) || 3455b9c547cSRui Paulo (hdr->code == EAP_CODE_INITIATE && 3465b9c547cSRui Paulo eap[sizeof(struct eap_hdr)] != EAP_ERP_TYPE_REAUTH) || 3475b9c547cSRui Paulo (hdr->code != EAP_CODE_RESPONSE && 3485b9c547cSRui Paulo hdr->code != EAP_CODE_INITIATE)) 349e28a4053SRui Paulo return; 350e28a4053SRui Paulo 35185732ac8SCy Schubert eap_erp_update_identity(sm->eap, eap, len); 352e28a4053SRui Paulo identity = eap_get_identity(sm->eap, &identity_len); 353*c1d255d3SCy Schubert if (!identity) 354e28a4053SRui Paulo return; 355e28a4053SRui Paulo 356e28a4053SRui Paulo /* Save station identity for future RADIUS packets */ 357e28a4053SRui Paulo os_free(sm->identity); 3585b9c547cSRui Paulo sm->identity = (u8 *) dup_binstr(identity, identity_len); 359*c1d255d3SCy Schubert if (!sm->identity) { 360e28a4053SRui Paulo sm->identity_len = 0; 361e28a4053SRui Paulo return; 362e28a4053SRui Paulo } 363e28a4053SRui Paulo 364e28a4053SRui Paulo sm->identity_len = identity_len; 365e28a4053SRui Paulo hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, 366e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "STA identity '%s'", sm->identity); 367e28a4053SRui Paulo sm->dot1xAuthEapolRespIdFramesRx++; 368e28a4053SRui Paulo } 369e28a4053SRui Paulo 370e28a4053SRui Paulo 3715b9c547cSRui Paulo static int add_common_radius_sta_attr_rsn(struct hostapd_data *hapd, 3725b9c547cSRui Paulo struct hostapd_radius_attr *req_attr, 3735b9c547cSRui Paulo struct sta_info *sta, 3745b9c547cSRui Paulo struct radius_msg *msg) 3755b9c547cSRui Paulo { 3765b9c547cSRui Paulo u32 suite; 3775b9c547cSRui Paulo int ver, val; 3785b9c547cSRui Paulo 3795b9c547cSRui Paulo ver = wpa_auth_sta_wpa_version(sta->wpa_sm); 3805b9c547cSRui Paulo val = wpa_auth_get_pairwise(sta->wpa_sm); 3815b9c547cSRui Paulo suite = wpa_cipher_to_suite(ver, val); 3825b9c547cSRui Paulo if (val != -1 && 3835b9c547cSRui Paulo !hostapd_config_get_radius_attr(req_attr, 3845b9c547cSRui Paulo RADIUS_ATTR_WLAN_PAIRWISE_CIPHER) && 3855b9c547cSRui Paulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_PAIRWISE_CIPHER, 3865b9c547cSRui Paulo suite)) { 3875b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not add WLAN-Pairwise-Cipher"); 3885b9c547cSRui Paulo return -1; 3895b9c547cSRui Paulo } 3905b9c547cSRui Paulo 391325151a3SRui Paulo suite = wpa_cipher_to_suite(((hapd->conf->wpa & 0x2) || 392325151a3SRui Paulo hapd->conf->osen) ? 3935b9c547cSRui Paulo WPA_PROTO_RSN : WPA_PROTO_WPA, 3945b9c547cSRui Paulo hapd->conf->wpa_group); 3955b9c547cSRui Paulo if (!hostapd_config_get_radius_attr(req_attr, 3965b9c547cSRui Paulo RADIUS_ATTR_WLAN_GROUP_CIPHER) && 3975b9c547cSRui Paulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_GROUP_CIPHER, 3985b9c547cSRui Paulo suite)) { 3995b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not add WLAN-Group-Cipher"); 4005b9c547cSRui Paulo return -1; 4015b9c547cSRui Paulo } 4025b9c547cSRui Paulo 4035b9c547cSRui Paulo val = wpa_auth_sta_key_mgmt(sta->wpa_sm); 4045b9c547cSRui Paulo suite = wpa_akm_to_suite(val); 4055b9c547cSRui Paulo if (val != -1 && 4065b9c547cSRui Paulo !hostapd_config_get_radius_attr(req_attr, 4075b9c547cSRui Paulo RADIUS_ATTR_WLAN_AKM_SUITE) && 4085b9c547cSRui Paulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_AKM_SUITE, 4095b9c547cSRui Paulo suite)) { 4105b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not add WLAN-AKM-Suite"); 4115b9c547cSRui Paulo return -1; 4125b9c547cSRui Paulo } 4135b9c547cSRui Paulo 4145b9c547cSRui Paulo if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { 4155b9c547cSRui Paulo suite = wpa_cipher_to_suite(WPA_PROTO_RSN, 4165b9c547cSRui Paulo hapd->conf->group_mgmt_cipher); 4175b9c547cSRui Paulo if (!hostapd_config_get_radius_attr( 4185b9c547cSRui Paulo req_attr, RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER) && 4195b9c547cSRui Paulo !radius_msg_add_attr_int32( 4205b9c547cSRui Paulo msg, RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER, suite)) { 4215b9c547cSRui Paulo wpa_printf(MSG_ERROR, 4225b9c547cSRui Paulo "Could not add WLAN-Group-Mgmt-Cipher"); 4235b9c547cSRui Paulo return -1; 4245b9c547cSRui Paulo } 4255b9c547cSRui Paulo } 4265b9c547cSRui Paulo 4275b9c547cSRui Paulo return 0; 4285b9c547cSRui Paulo } 4295b9c547cSRui Paulo 4305b9c547cSRui Paulo 431f05cddf9SRui Paulo static int add_common_radius_sta_attr(struct hostapd_data *hapd, 432f05cddf9SRui Paulo struct hostapd_radius_attr *req_attr, 433f05cddf9SRui Paulo struct sta_info *sta, 434f05cddf9SRui Paulo struct radius_msg *msg) 435f05cddf9SRui Paulo { 436f05cddf9SRui Paulo char buf[128]; 437f05cddf9SRui Paulo 438f05cddf9SRui Paulo if (!hostapd_config_get_radius_attr(req_attr, 439780fb4a2SCy Schubert RADIUS_ATTR_SERVICE_TYPE) && 440780fb4a2SCy Schubert !radius_msg_add_attr_int32(msg, RADIUS_ATTR_SERVICE_TYPE, 441780fb4a2SCy Schubert RADIUS_SERVICE_TYPE_FRAMED)) { 442780fb4a2SCy Schubert wpa_printf(MSG_ERROR, "Could not add Service-Type"); 443780fb4a2SCy Schubert return -1; 444780fb4a2SCy Schubert } 445780fb4a2SCy Schubert 446780fb4a2SCy Schubert if (!hostapd_config_get_radius_attr(req_attr, 447f05cddf9SRui Paulo RADIUS_ATTR_NAS_PORT) && 448780fb4a2SCy Schubert sta->aid > 0 && 449f05cddf9SRui Paulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) { 450f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add NAS-Port"); 451f05cddf9SRui Paulo return -1; 452f05cddf9SRui Paulo } 453f05cddf9SRui Paulo 454f05cddf9SRui Paulo os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, 455f05cddf9SRui Paulo MAC2STR(sta->addr)); 456f05cddf9SRui Paulo buf[sizeof(buf) - 1] = '\0'; 457f05cddf9SRui Paulo if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, 458f05cddf9SRui Paulo (u8 *) buf, os_strlen(buf))) { 459f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add Calling-Station-Id"); 460f05cddf9SRui Paulo return -1; 461f05cddf9SRui Paulo } 462f05cddf9SRui Paulo 463f05cddf9SRui Paulo if (sta->flags & WLAN_STA_PREAUTH) { 464f05cddf9SRui Paulo os_strlcpy(buf, "IEEE 802.11i Pre-Authentication", 465f05cddf9SRui Paulo sizeof(buf)); 466f05cddf9SRui Paulo } else { 467f05cddf9SRui Paulo os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s", 468f05cddf9SRui Paulo radius_sta_rate(hapd, sta) / 2, 469f05cddf9SRui Paulo (radius_sta_rate(hapd, sta) & 1) ? ".5" : "", 470f05cddf9SRui Paulo radius_mode_txt(hapd)); 471f05cddf9SRui Paulo buf[sizeof(buf) - 1] = '\0'; 472f05cddf9SRui Paulo } 473f05cddf9SRui Paulo if (!hostapd_config_get_radius_attr(req_attr, 474f05cddf9SRui Paulo RADIUS_ATTR_CONNECT_INFO) && 475f05cddf9SRui Paulo !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, 476f05cddf9SRui Paulo (u8 *) buf, os_strlen(buf))) { 477f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add Connect-Info"); 478f05cddf9SRui Paulo return -1; 479f05cddf9SRui Paulo } 480f05cddf9SRui Paulo 481780fb4a2SCy Schubert if (sta->acct_session_id) { 482780fb4a2SCy Schubert os_snprintf(buf, sizeof(buf), "%016llX", 483780fb4a2SCy Schubert (unsigned long long) sta->acct_session_id); 484f05cddf9SRui Paulo if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID, 485f05cddf9SRui Paulo (u8 *) buf, os_strlen(buf))) { 486f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add Acct-Session-Id"); 487f05cddf9SRui Paulo return -1; 488f05cddf9SRui Paulo } 489f05cddf9SRui Paulo } 490f05cddf9SRui Paulo 491780fb4a2SCy Schubert if ((hapd->conf->wpa & 2) && 492780fb4a2SCy Schubert !hapd->conf->disable_pmksa_caching && 493780fb4a2SCy Schubert sta->eapol_sm && sta->eapol_sm->acct_multi_session_id) { 494780fb4a2SCy Schubert os_snprintf(buf, sizeof(buf), "%016llX", 495780fb4a2SCy Schubert (unsigned long long) 496780fb4a2SCy Schubert sta->eapol_sm->acct_multi_session_id); 497780fb4a2SCy Schubert if (!radius_msg_add_attr( 498780fb4a2SCy Schubert msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID, 499780fb4a2SCy Schubert (u8 *) buf, os_strlen(buf))) { 500780fb4a2SCy Schubert wpa_printf(MSG_INFO, 501780fb4a2SCy Schubert "Could not add Acct-Multi-Session-Id"); 502780fb4a2SCy Schubert return -1; 503780fb4a2SCy Schubert } 504780fb4a2SCy Schubert } 505780fb4a2SCy Schubert 50685732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP 5075b9c547cSRui Paulo if (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) && 5085b9c547cSRui Paulo sta->wpa_sm && 5095b9c547cSRui Paulo (wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm)) || 5105b9c547cSRui Paulo sta->auth_alg == WLAN_AUTH_FT) && 5115b9c547cSRui Paulo !hostapd_config_get_radius_attr(req_attr, 5125b9c547cSRui Paulo RADIUS_ATTR_MOBILITY_DOMAIN_ID) && 5135b9c547cSRui Paulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_MOBILITY_DOMAIN_ID, 5145b9c547cSRui Paulo WPA_GET_BE16( 5155b9c547cSRui Paulo hapd->conf->mobility_domain))) { 5165b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not add Mobility-Domain-Id"); 5175b9c547cSRui Paulo return -1; 5185b9c547cSRui Paulo } 51985732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */ 5205b9c547cSRui Paulo 521325151a3SRui Paulo if ((hapd->conf->wpa || hapd->conf->osen) && sta->wpa_sm && 5225b9c547cSRui Paulo add_common_radius_sta_attr_rsn(hapd, req_attr, sta, msg) < 0) 5235b9c547cSRui Paulo return -1; 5245b9c547cSRui Paulo 525f05cddf9SRui Paulo return 0; 526f05cddf9SRui Paulo } 527f05cddf9SRui Paulo 528f05cddf9SRui Paulo 529f05cddf9SRui Paulo int add_common_radius_attr(struct hostapd_data *hapd, 530f05cddf9SRui Paulo struct hostapd_radius_attr *req_attr, 531f05cddf9SRui Paulo struct sta_info *sta, 532f05cddf9SRui Paulo struct radius_msg *msg) 533f05cddf9SRui Paulo { 534f05cddf9SRui Paulo char buf[128]; 535f05cddf9SRui Paulo struct hostapd_radius_attr *attr; 536780fb4a2SCy Schubert int len; 537f05cddf9SRui Paulo 538f05cddf9SRui Paulo if (!hostapd_config_get_radius_attr(req_attr, 539f05cddf9SRui Paulo RADIUS_ATTR_NAS_IP_ADDRESS) && 540f05cddf9SRui Paulo hapd->conf->own_ip_addr.af == AF_INET && 541f05cddf9SRui Paulo !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, 542f05cddf9SRui Paulo (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) { 543f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add NAS-IP-Address"); 544f05cddf9SRui Paulo return -1; 545f05cddf9SRui Paulo } 546f05cddf9SRui Paulo 547f05cddf9SRui Paulo #ifdef CONFIG_IPV6 548f05cddf9SRui Paulo if (!hostapd_config_get_radius_attr(req_attr, 549f05cddf9SRui Paulo RADIUS_ATTR_NAS_IPV6_ADDRESS) && 550f05cddf9SRui Paulo hapd->conf->own_ip_addr.af == AF_INET6 && 551f05cddf9SRui Paulo !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS, 552f05cddf9SRui Paulo (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) { 553f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add NAS-IPv6-Address"); 554f05cddf9SRui Paulo return -1; 555f05cddf9SRui Paulo } 556f05cddf9SRui Paulo #endif /* CONFIG_IPV6 */ 557f05cddf9SRui Paulo 558f05cddf9SRui Paulo if (!hostapd_config_get_radius_attr(req_attr, 559f05cddf9SRui Paulo RADIUS_ATTR_NAS_IDENTIFIER) && 560f05cddf9SRui Paulo hapd->conf->nas_identifier && 561f05cddf9SRui Paulo !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER, 562f05cddf9SRui Paulo (u8 *) hapd->conf->nas_identifier, 563f05cddf9SRui Paulo os_strlen(hapd->conf->nas_identifier))) { 564f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add NAS-Identifier"); 565f05cddf9SRui Paulo return -1; 566f05cddf9SRui Paulo } 567f05cddf9SRui Paulo 568780fb4a2SCy Schubert len = os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":", 569780fb4a2SCy Schubert MAC2STR(hapd->own_addr)); 570780fb4a2SCy Schubert os_memcpy(&buf[len], hapd->conf->ssid.ssid, 571780fb4a2SCy Schubert hapd->conf->ssid.ssid_len); 572780fb4a2SCy Schubert len += hapd->conf->ssid.ssid_len; 573f05cddf9SRui Paulo if (!hostapd_config_get_radius_attr(req_attr, 574f05cddf9SRui Paulo RADIUS_ATTR_CALLED_STATION_ID) && 575f05cddf9SRui Paulo !radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID, 576780fb4a2SCy Schubert (u8 *) buf, len)) { 577f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add Called-Station-Id"); 578f05cddf9SRui Paulo return -1; 579f05cddf9SRui Paulo } 580f05cddf9SRui Paulo 581f05cddf9SRui Paulo if (!hostapd_config_get_radius_attr(req_attr, 582f05cddf9SRui Paulo RADIUS_ATTR_NAS_PORT_TYPE) && 583f05cddf9SRui Paulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE, 584f05cddf9SRui Paulo RADIUS_NAS_PORT_TYPE_IEEE_802_11)) { 585f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add NAS-Port-Type"); 586f05cddf9SRui Paulo return -1; 587f05cddf9SRui Paulo } 588f05cddf9SRui Paulo 5895b9c547cSRui Paulo #ifdef CONFIG_INTERWORKING 5905b9c547cSRui Paulo if (hapd->conf->interworking && 5915b9c547cSRui Paulo !is_zero_ether_addr(hapd->conf->hessid)) { 5925b9c547cSRui Paulo os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, 5935b9c547cSRui Paulo MAC2STR(hapd->conf->hessid)); 5945b9c547cSRui Paulo buf[sizeof(buf) - 1] = '\0'; 5955b9c547cSRui Paulo if (!hostapd_config_get_radius_attr(req_attr, 5965b9c547cSRui Paulo RADIUS_ATTR_WLAN_HESSID) && 5975b9c547cSRui Paulo !radius_msg_add_attr(msg, RADIUS_ATTR_WLAN_HESSID, 5985b9c547cSRui Paulo (u8 *) buf, os_strlen(buf))) { 5995b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Could not add WLAN-HESSID"); 6005b9c547cSRui Paulo return -1; 6015b9c547cSRui Paulo } 6025b9c547cSRui Paulo } 6035b9c547cSRui Paulo #endif /* CONFIG_INTERWORKING */ 6045b9c547cSRui Paulo 605f05cddf9SRui Paulo if (sta && add_common_radius_sta_attr(hapd, req_attr, sta, msg) < 0) 606f05cddf9SRui Paulo return -1; 607f05cddf9SRui Paulo 608f05cddf9SRui Paulo for (attr = req_attr; attr; attr = attr->next) { 609f05cddf9SRui Paulo if (!radius_msg_add_attr(msg, attr->type, 610f05cddf9SRui Paulo wpabuf_head(attr->val), 611f05cddf9SRui Paulo wpabuf_len(attr->val))) { 612*c1d255d3SCy Schubert wpa_printf(MSG_ERROR, "Could not add RADIUS attribute"); 613f05cddf9SRui Paulo return -1; 614f05cddf9SRui Paulo } 615f05cddf9SRui Paulo } 616f05cddf9SRui Paulo 617f05cddf9SRui Paulo return 0; 618f05cddf9SRui Paulo } 619f05cddf9SRui Paulo 620f05cddf9SRui Paulo 621206b73d0SCy Schubert int add_sqlite_radius_attr(struct hostapd_data *hapd, struct sta_info *sta, 622206b73d0SCy Schubert struct radius_msg *msg, int acct) 623206b73d0SCy Schubert { 624206b73d0SCy Schubert #ifdef CONFIG_SQLITE 625206b73d0SCy Schubert const char *attrtxt; 626206b73d0SCy Schubert char addrtxt[3 * ETH_ALEN]; 627206b73d0SCy Schubert char *sql; 628206b73d0SCy Schubert sqlite3_stmt *stmt = NULL; 629206b73d0SCy Schubert 630206b73d0SCy Schubert if (!hapd->rad_attr_db) 631206b73d0SCy Schubert return 0; 632206b73d0SCy Schubert 633206b73d0SCy Schubert os_snprintf(addrtxt, sizeof(addrtxt), MACSTR, MAC2STR(sta->addr)); 634206b73d0SCy Schubert 635206b73d0SCy Schubert sql = "SELECT attr FROM radius_attributes WHERE sta=? AND (reqtype=? OR reqtype IS NULL);"; 636206b73d0SCy Schubert if (sqlite3_prepare_v2(hapd->rad_attr_db, sql, os_strlen(sql), &stmt, 637206b73d0SCy Schubert NULL) != SQLITE_OK) { 638206b73d0SCy Schubert wpa_printf(MSG_ERROR, "DB: Failed to prepare SQL statement: %s", 639206b73d0SCy Schubert sqlite3_errmsg(hapd->rad_attr_db)); 640206b73d0SCy Schubert return -1; 641206b73d0SCy Schubert } 642206b73d0SCy Schubert sqlite3_bind_text(stmt, 1, addrtxt, os_strlen(addrtxt), SQLITE_STATIC); 643206b73d0SCy Schubert sqlite3_bind_text(stmt, 2, acct ? "acct" : "auth", 4, SQLITE_STATIC); 644206b73d0SCy Schubert while (sqlite3_step(stmt) == SQLITE_ROW) { 645206b73d0SCy Schubert struct hostapd_radius_attr *attr; 646206b73d0SCy Schubert struct radius_attr_hdr *hdr; 647206b73d0SCy Schubert 648206b73d0SCy Schubert attrtxt = (const char *) sqlite3_column_text(stmt, 0); 649206b73d0SCy Schubert attr = hostapd_parse_radius_attr(attrtxt); 650206b73d0SCy Schubert if (!attr) { 651206b73d0SCy Schubert wpa_printf(MSG_ERROR, 652206b73d0SCy Schubert "Skipping invalid attribute from SQL: %s", 653206b73d0SCy Schubert attrtxt); 654206b73d0SCy Schubert continue; 655206b73d0SCy Schubert } 656206b73d0SCy Schubert wpa_printf(MSG_DEBUG, "Adding RADIUS attribute from SQL: %s", 657206b73d0SCy Schubert attrtxt); 658206b73d0SCy Schubert hdr = radius_msg_add_attr(msg, attr->type, 659206b73d0SCy Schubert wpabuf_head(attr->val), 660206b73d0SCy Schubert wpabuf_len(attr->val)); 661206b73d0SCy Schubert hostapd_config_free_radius_attr(attr); 662206b73d0SCy Schubert if (!hdr) { 663206b73d0SCy Schubert wpa_printf(MSG_ERROR, 664206b73d0SCy Schubert "Could not add RADIUS attribute from SQL"); 665206b73d0SCy Schubert continue; 666206b73d0SCy Schubert } 667206b73d0SCy Schubert } 668206b73d0SCy Schubert 669206b73d0SCy Schubert sqlite3_reset(stmt); 670206b73d0SCy Schubert sqlite3_clear_bindings(stmt); 671206b73d0SCy Schubert sqlite3_finalize(stmt); 672206b73d0SCy Schubert #endif /* CONFIG_SQLITE */ 673206b73d0SCy Schubert 674206b73d0SCy Schubert return 0; 675206b73d0SCy Schubert } 676206b73d0SCy Schubert 677206b73d0SCy Schubert 67885732ac8SCy Schubert void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd, 679e28a4053SRui Paulo struct sta_info *sta, 680e28a4053SRui Paulo const u8 *eap, size_t len) 681e28a4053SRui Paulo { 682e28a4053SRui Paulo struct radius_msg *msg; 683e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 684e28a4053SRui Paulo 685*c1d255d3SCy Schubert if (!sm) 686e28a4053SRui Paulo return; 687e28a4053SRui Paulo 688e28a4053SRui Paulo ieee802_1x_learn_identity(hapd, sm, eap, len); 689e28a4053SRui Paulo 690*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS packet"); 691e28a4053SRui Paulo 692e28a4053SRui Paulo sm->radius_identifier = radius_client_get_id(hapd->radius); 693e28a4053SRui Paulo msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, 694e28a4053SRui Paulo sm->radius_identifier); 695*c1d255d3SCy Schubert if (!msg) { 6965b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not create new RADIUS packet"); 697e28a4053SRui Paulo return; 698e28a4053SRui Paulo } 699e28a4053SRui Paulo 700780fb4a2SCy Schubert if (radius_msg_make_authenticator(msg) < 0) { 701780fb4a2SCy Schubert wpa_printf(MSG_INFO, "Could not make Request Authenticator"); 702780fb4a2SCy Schubert goto fail; 703780fb4a2SCy Schubert } 704e28a4053SRui Paulo 705e28a4053SRui Paulo if (sm->identity && 706e28a4053SRui Paulo !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, 707e28a4053SRui Paulo sm->identity, sm->identity_len)) { 7085b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not add User-Name"); 709e28a4053SRui Paulo goto fail; 710e28a4053SRui Paulo } 711e28a4053SRui Paulo 712f05cddf9SRui Paulo if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr, sta, 713f05cddf9SRui Paulo msg) < 0) 714e28a4053SRui Paulo goto fail; 715e28a4053SRui Paulo 716206b73d0SCy Schubert if (sta && add_sqlite_radius_attr(hapd, sta, msg, 0) < 0) 717206b73d0SCy Schubert goto fail; 718206b73d0SCy Schubert 719e28a4053SRui Paulo /* TODO: should probably check MTU from driver config; 2304 is max for 720e28a4053SRui Paulo * IEEE 802.11, but use 1400 to avoid problems with too large packets 721e28a4053SRui Paulo */ 722f05cddf9SRui Paulo if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr, 723f05cddf9SRui Paulo RADIUS_ATTR_FRAMED_MTU) && 724f05cddf9SRui Paulo !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) { 7255b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not add Framed-MTU"); 726e28a4053SRui Paulo goto fail; 727e28a4053SRui Paulo } 728e28a4053SRui Paulo 729325151a3SRui Paulo if (!radius_msg_add_eap(msg, eap, len)) { 7305b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not add EAP-Message"); 731e28a4053SRui Paulo goto fail; 732e28a4053SRui Paulo } 733e28a4053SRui Paulo 734e28a4053SRui Paulo /* State attribute must be copied if and only if this packet is 735e28a4053SRui Paulo * Access-Request reply to the previous Access-Challenge */ 736e28a4053SRui Paulo if (sm->last_recv_radius && 737e28a4053SRui Paulo radius_msg_get_hdr(sm->last_recv_radius)->code == 738e28a4053SRui Paulo RADIUS_CODE_ACCESS_CHALLENGE) { 739e28a4053SRui Paulo int res = radius_msg_copy_attr(msg, sm->last_recv_radius, 740e28a4053SRui Paulo RADIUS_ATTR_STATE); 741e28a4053SRui Paulo if (res < 0) { 742*c1d255d3SCy Schubert wpa_printf(MSG_INFO, 743*c1d255d3SCy Schubert "Could not copy State attribute from previous Access-Challenge"); 744e28a4053SRui Paulo goto fail; 745e28a4053SRui Paulo } 746*c1d255d3SCy Schubert if (res > 0) 747e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "Copied RADIUS State Attribute"); 748e28a4053SRui Paulo } 749e28a4053SRui Paulo 750f05cddf9SRui Paulo if (hapd->conf->radius_request_cui) { 751f05cddf9SRui Paulo const u8 *cui; 752f05cddf9SRui Paulo size_t cui_len; 753f05cddf9SRui Paulo /* Add previously learned CUI or nul CUI to request CUI */ 754f05cddf9SRui Paulo if (sm->radius_cui) { 755f05cddf9SRui Paulo cui = wpabuf_head(sm->radius_cui); 756f05cddf9SRui Paulo cui_len = wpabuf_len(sm->radius_cui); 757f05cddf9SRui Paulo } else { 758f05cddf9SRui Paulo cui = (const u8 *) "\0"; 759f05cddf9SRui Paulo cui_len = 1; 760f05cddf9SRui Paulo } 761f05cddf9SRui Paulo if (!radius_msg_add_attr(msg, 762f05cddf9SRui Paulo RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, 763f05cddf9SRui Paulo cui, cui_len)) { 764f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "Could not add CUI"); 765f05cddf9SRui Paulo goto fail; 766f05cddf9SRui Paulo } 767f05cddf9SRui Paulo } 768f05cddf9SRui Paulo 7695b9c547cSRui Paulo #ifdef CONFIG_HS20 7705b9c547cSRui Paulo if (hapd->conf->hs20) { 7714bc52338SCy Schubert u8 ver = hapd->conf->hs20_release - 1; 7724bc52338SCy Schubert 7735b9c547cSRui Paulo if (!radius_msg_add_wfa( 7745b9c547cSRui Paulo msg, RADIUS_VENDOR_ATTR_WFA_HS20_AP_VERSION, 7755b9c547cSRui Paulo &ver, 1)) { 776*c1d255d3SCy Schubert wpa_printf(MSG_ERROR, 777*c1d255d3SCy Schubert "Could not add HS 2.0 AP version"); 7785b9c547cSRui Paulo goto fail; 7795b9c547cSRui Paulo } 7805b9c547cSRui Paulo 7815b9c547cSRui Paulo if (sta->hs20_ie && wpabuf_len(sta->hs20_ie) > 0) { 7825b9c547cSRui Paulo const u8 *pos; 7835b9c547cSRui Paulo u8 buf[3]; 7845b9c547cSRui Paulo u16 id; 785*c1d255d3SCy Schubert 7865b9c547cSRui Paulo pos = wpabuf_head_u8(sta->hs20_ie); 7875b9c547cSRui Paulo buf[0] = (*pos) >> 4; 7885b9c547cSRui Paulo if (((*pos) & HS20_PPS_MO_ID_PRESENT) && 7895b9c547cSRui Paulo wpabuf_len(sta->hs20_ie) >= 3) 7905b9c547cSRui Paulo id = WPA_GET_LE16(pos + 1); 7915b9c547cSRui Paulo else 7925b9c547cSRui Paulo id = 0; 7935b9c547cSRui Paulo WPA_PUT_BE16(buf + 1, id); 7945b9c547cSRui Paulo if (!radius_msg_add_wfa( 7955b9c547cSRui Paulo msg, 7965b9c547cSRui Paulo RADIUS_VENDOR_ATTR_WFA_HS20_STA_VERSION, 7975b9c547cSRui Paulo buf, sizeof(buf))) { 798*c1d255d3SCy Schubert wpa_printf(MSG_ERROR, 799*c1d255d3SCy Schubert "Could not add HS 2.0 STA version"); 8005b9c547cSRui Paulo goto fail; 8015b9c547cSRui Paulo } 8025b9c547cSRui Paulo } 80385732ac8SCy Schubert 80485732ac8SCy Schubert if (sta->roaming_consortium && 80585732ac8SCy Schubert !radius_msg_add_wfa( 80685732ac8SCy Schubert msg, RADIUS_VENDOR_ATTR_WFA_HS20_ROAMING_CONSORTIUM, 80785732ac8SCy Schubert wpabuf_head(sta->roaming_consortium), 80885732ac8SCy Schubert wpabuf_len(sta->roaming_consortium))) { 80985732ac8SCy Schubert wpa_printf(MSG_ERROR, 81085732ac8SCy Schubert "Could not add HS 2.0 Roaming Consortium"); 81185732ac8SCy Schubert goto fail; 81285732ac8SCy Schubert } 81385732ac8SCy Schubert 81485732ac8SCy Schubert if (hapd->conf->t_c_filename) { 81585732ac8SCy Schubert be32 timestamp; 81685732ac8SCy Schubert 81785732ac8SCy Schubert if (!radius_msg_add_wfa( 81885732ac8SCy Schubert msg, 81985732ac8SCy Schubert RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILENAME, 82085732ac8SCy Schubert (const u8 *) hapd->conf->t_c_filename, 82185732ac8SCy Schubert os_strlen(hapd->conf->t_c_filename))) { 82285732ac8SCy Schubert wpa_printf(MSG_ERROR, 82385732ac8SCy Schubert "Could not add HS 2.0 T&C Filename"); 82485732ac8SCy Schubert goto fail; 82585732ac8SCy Schubert } 82685732ac8SCy Schubert 82785732ac8SCy Schubert timestamp = host_to_be32(hapd->conf->t_c_timestamp); 82885732ac8SCy Schubert if (!radius_msg_add_wfa( 82985732ac8SCy Schubert msg, 83085732ac8SCy Schubert RADIUS_VENDOR_ATTR_WFA_HS20_TIMESTAMP, 83185732ac8SCy Schubert (const u8 *) ×tamp, 83285732ac8SCy Schubert sizeof(timestamp))) { 83385732ac8SCy Schubert wpa_printf(MSG_ERROR, 83485732ac8SCy Schubert "Could not add HS 2.0 Timestamp"); 83585732ac8SCy Schubert goto fail; 83685732ac8SCy Schubert } 83785732ac8SCy Schubert } 8385b9c547cSRui Paulo } 8395b9c547cSRui Paulo #endif /* CONFIG_HS20 */ 8405b9c547cSRui Paulo 841f05cddf9SRui Paulo if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr) < 0) 842f05cddf9SRui Paulo goto fail; 843f05cddf9SRui Paulo 844e28a4053SRui Paulo return; 845e28a4053SRui Paulo 846e28a4053SRui Paulo fail: 847e28a4053SRui Paulo radius_msg_free(msg); 848e28a4053SRui Paulo } 849e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */ 850e28a4053SRui Paulo 851e28a4053SRui Paulo 852e28a4053SRui Paulo static void handle_eap_response(struct hostapd_data *hapd, 853e28a4053SRui Paulo struct sta_info *sta, struct eap_hdr *eap, 854e28a4053SRui Paulo size_t len) 855e28a4053SRui Paulo { 856e28a4053SRui Paulo u8 type, *data; 857e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 858*c1d255d3SCy Schubert 859*c1d255d3SCy Schubert if (!sm) 860e28a4053SRui Paulo return; 861e28a4053SRui Paulo 862e28a4053SRui Paulo data = (u8 *) (eap + 1); 863e28a4053SRui Paulo 864e28a4053SRui Paulo if (len < sizeof(*eap) + 1) { 865*c1d255d3SCy Schubert wpa_printf(MSG_INFO, "%s: too short response data", __func__); 866e28a4053SRui Paulo return; 867e28a4053SRui Paulo } 868e28a4053SRui Paulo 869e28a4053SRui Paulo sm->eap_type_supp = type = data[0]; 870e28a4053SRui Paulo 871e28a4053SRui Paulo hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, 872e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d " 873e28a4053SRui Paulo "id=%d len=%d) from STA: EAP Response-%s (%d)", 874e28a4053SRui Paulo eap->code, eap->identifier, be_to_host16(eap->length), 875e28a4053SRui Paulo eap_server_get_name(0, type), type); 876e28a4053SRui Paulo 877e28a4053SRui Paulo sm->dot1xAuthEapolRespFramesRx++; 878e28a4053SRui Paulo 879e28a4053SRui Paulo wpabuf_free(sm->eap_if->eapRespData); 880e28a4053SRui Paulo sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len); 881*c1d255d3SCy Schubert sm->eapolEap = true; 882e28a4053SRui Paulo } 883e28a4053SRui Paulo 884e28a4053SRui Paulo 8855b9c547cSRui Paulo static void handle_eap_initiate(struct hostapd_data *hapd, 8865b9c547cSRui Paulo struct sta_info *sta, struct eap_hdr *eap, 8875b9c547cSRui Paulo size_t len) 8885b9c547cSRui Paulo { 8895b9c547cSRui Paulo #ifdef CONFIG_ERP 8905b9c547cSRui Paulo u8 type, *data; 8915b9c547cSRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 8925b9c547cSRui Paulo 893*c1d255d3SCy Schubert if (!sm) 8945b9c547cSRui Paulo return; 8955b9c547cSRui Paulo 8965b9c547cSRui Paulo if (len < sizeof(*eap) + 1) { 897*c1d255d3SCy Schubert wpa_printf(MSG_INFO, "%s: too short response data", __func__); 8985b9c547cSRui Paulo return; 8995b9c547cSRui Paulo } 9005b9c547cSRui Paulo 9015b9c547cSRui Paulo data = (u8 *) (eap + 1); 9025b9c547cSRui Paulo type = data[0]; 9035b9c547cSRui Paulo 9045b9c547cSRui Paulo hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, 905*c1d255d3SCy Schubert HOSTAPD_LEVEL_DEBUG, 906*c1d255d3SCy Schubert "received EAP packet (code=%d id=%d len=%d) from STA: EAP Initiate type %u", 9075b9c547cSRui Paulo eap->code, eap->identifier, be_to_host16(eap->length), 9085b9c547cSRui Paulo type); 9095b9c547cSRui Paulo 9105b9c547cSRui Paulo wpabuf_free(sm->eap_if->eapRespData); 9115b9c547cSRui Paulo sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len); 912*c1d255d3SCy Schubert sm->eapolEap = true; 9135b9c547cSRui Paulo #endif /* CONFIG_ERP */ 9145b9c547cSRui Paulo } 9155b9c547cSRui Paulo 9165b9c547cSRui Paulo 917*c1d255d3SCy Schubert #ifndef CONFIG_NO_STDOUT_DEBUG 918*c1d255d3SCy Schubert static const char * eap_code_str(u8 code) 919*c1d255d3SCy Schubert { 920*c1d255d3SCy Schubert switch (code) { 921*c1d255d3SCy Schubert case EAP_CODE_REQUEST: 922*c1d255d3SCy Schubert return "request"; 923*c1d255d3SCy Schubert case EAP_CODE_RESPONSE: 924*c1d255d3SCy Schubert return "response"; 925*c1d255d3SCy Schubert case EAP_CODE_SUCCESS: 926*c1d255d3SCy Schubert return "success"; 927*c1d255d3SCy Schubert case EAP_CODE_FAILURE: 928*c1d255d3SCy Schubert return "failure"; 929*c1d255d3SCy Schubert case EAP_CODE_INITIATE: 930*c1d255d3SCy Schubert return "initiate"; 931*c1d255d3SCy Schubert case EAP_CODE_FINISH: 932*c1d255d3SCy Schubert return "finish"; 933*c1d255d3SCy Schubert default: 934*c1d255d3SCy Schubert return "unknown"; 935*c1d255d3SCy Schubert } 936*c1d255d3SCy Schubert } 937*c1d255d3SCy Schubert #endif /* CONFIG_NO_STDOUT_DEBUG */ 938*c1d255d3SCy Schubert 939*c1d255d3SCy Schubert 940e28a4053SRui Paulo /* Process incoming EAP packet from Supplicant */ 941e28a4053SRui Paulo static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta, 942e28a4053SRui Paulo u8 *buf, size_t len) 943e28a4053SRui Paulo { 944e28a4053SRui Paulo struct eap_hdr *eap; 945e28a4053SRui Paulo u16 eap_len; 946e28a4053SRui Paulo 947e28a4053SRui Paulo if (len < sizeof(*eap)) { 9485b9c547cSRui Paulo wpa_printf(MSG_INFO, " too short EAP packet"); 949e28a4053SRui Paulo return; 950e28a4053SRui Paulo } 951e28a4053SRui Paulo 952e28a4053SRui Paulo eap = (struct eap_hdr *) buf; 953e28a4053SRui Paulo 954e28a4053SRui Paulo eap_len = be_to_host16(eap->length); 955*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "EAP: code=%d (%s) identifier=%d length=%d", 956*c1d255d3SCy Schubert eap->code, eap_code_str(eap->code), eap->identifier, 957*c1d255d3SCy Schubert eap_len); 958e28a4053SRui Paulo if (eap_len < sizeof(*eap)) { 959e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " Invalid EAP length"); 960e28a4053SRui Paulo return; 961e28a4053SRui Paulo } else if (eap_len > len) { 962*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 963*c1d255d3SCy Schubert " Too short frame to contain this EAP packet"); 964e28a4053SRui Paulo return; 965e28a4053SRui Paulo } else if (eap_len < len) { 966*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 967*c1d255d3SCy Schubert " Ignoring %lu extra bytes after EAP packet", 968*c1d255d3SCy Schubert (unsigned long) len - eap_len); 969e28a4053SRui Paulo } 970e28a4053SRui Paulo 971e28a4053SRui Paulo switch (eap->code) { 972e28a4053SRui Paulo case EAP_CODE_RESPONSE: 973e28a4053SRui Paulo handle_eap_response(hapd, sta, eap, eap_len); 974e28a4053SRui Paulo break; 9755b9c547cSRui Paulo case EAP_CODE_INITIATE: 9765b9c547cSRui Paulo handle_eap_initiate(hapd, sta, eap, eap_len); 9775b9c547cSRui Paulo break; 978e28a4053SRui Paulo } 979e28a4053SRui Paulo } 980e28a4053SRui Paulo 981e28a4053SRui Paulo 98285732ac8SCy Schubert struct eapol_state_machine * 983e28a4053SRui Paulo ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta) 984e28a4053SRui Paulo { 985e28a4053SRui Paulo int flags = 0; 986*c1d255d3SCy Schubert 987e28a4053SRui Paulo if (sta->flags & WLAN_STA_PREAUTH) 988e28a4053SRui Paulo flags |= EAPOL_SM_PREAUTH; 989e28a4053SRui Paulo if (sta->wpa_sm) { 990e28a4053SRui Paulo flags |= EAPOL_SM_USES_WPA; 991e28a4053SRui Paulo if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) 992e28a4053SRui Paulo flags |= EAPOL_SM_FROM_PMKSA_CACHE; 993e28a4053SRui Paulo } 994e28a4053SRui Paulo return eapol_auth_alloc(hapd->eapol_auth, sta->addr, flags, 995f05cddf9SRui Paulo sta->wps_ie, sta->p2p_ie, sta, 996f05cddf9SRui Paulo sta->identity, sta->radius_cui); 997e28a4053SRui Paulo } 998e28a4053SRui Paulo 999e28a4053SRui Paulo 1000780fb4a2SCy Schubert static void ieee802_1x_save_eapol(struct sta_info *sta, const u8 *buf, 1001780fb4a2SCy Schubert size_t len) 1002780fb4a2SCy Schubert { 1003780fb4a2SCy Schubert if (sta->pending_eapol_rx) { 1004780fb4a2SCy Schubert wpabuf_free(sta->pending_eapol_rx->buf); 1005780fb4a2SCy Schubert } else { 1006780fb4a2SCy Schubert sta->pending_eapol_rx = 1007780fb4a2SCy Schubert os_malloc(sizeof(*sta->pending_eapol_rx)); 1008780fb4a2SCy Schubert if (!sta->pending_eapol_rx) 1009780fb4a2SCy Schubert return; 1010780fb4a2SCy Schubert } 1011780fb4a2SCy Schubert 1012780fb4a2SCy Schubert sta->pending_eapol_rx->buf = wpabuf_alloc_copy(buf, len); 1013780fb4a2SCy Schubert if (!sta->pending_eapol_rx->buf) { 1014780fb4a2SCy Schubert os_free(sta->pending_eapol_rx); 1015780fb4a2SCy Schubert sta->pending_eapol_rx = NULL; 1016780fb4a2SCy Schubert return; 1017780fb4a2SCy Schubert } 1018780fb4a2SCy Schubert 1019780fb4a2SCy Schubert os_get_reltime(&sta->pending_eapol_rx->rx_time); 1020780fb4a2SCy Schubert } 1021780fb4a2SCy Schubert 1022780fb4a2SCy Schubert 1023e28a4053SRui Paulo /** 1024e28a4053SRui Paulo * ieee802_1x_receive - Process the EAPOL frames from the Supplicant 1025e28a4053SRui Paulo * @hapd: hostapd BSS data 1026e28a4053SRui Paulo * @sa: Source address (sender of the EAPOL frame) 1027e28a4053SRui Paulo * @buf: EAPOL frame 1028e28a4053SRui Paulo * @len: Length of buf in octets 1029e28a4053SRui Paulo * 1030e28a4053SRui Paulo * This function is called for each incoming EAPOL frame from the interface 1031e28a4053SRui Paulo */ 1032e28a4053SRui Paulo void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, 1033e28a4053SRui Paulo size_t len) 1034e28a4053SRui Paulo { 1035e28a4053SRui Paulo struct sta_info *sta; 1036e28a4053SRui Paulo struct ieee802_1x_hdr *hdr; 1037e28a4053SRui Paulo struct ieee802_1x_eapol_key *key; 1038e28a4053SRui Paulo u16 datalen; 1039e28a4053SRui Paulo struct rsn_pmksa_cache_entry *pmksa; 1040f05cddf9SRui Paulo int key_mgmt; 1041e28a4053SRui Paulo 10425b9c547cSRui Paulo if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->osen && 1043e28a4053SRui Paulo !hapd->conf->wps_state) 1044e28a4053SRui Paulo return; 1045e28a4053SRui Paulo 1046e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR, 1047e28a4053SRui Paulo (unsigned long) len, MAC2STR(sa)); 1048e28a4053SRui Paulo sta = ap_get_sta(hapd, sa); 1049f05cddf9SRui Paulo if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) && 1050f05cddf9SRui Paulo !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) { 1051*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1052*c1d255d3SCy Schubert "IEEE 802.1X data frame from not associated/Pre-authenticating STA"); 1053780fb4a2SCy Schubert 1054780fb4a2SCy Schubert if (sta && (sta->flags & WLAN_STA_AUTH)) { 1055780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "Saving EAPOL frame from " MACSTR 1056780fb4a2SCy Schubert " for later use", MAC2STR(sta->addr)); 1057780fb4a2SCy Schubert ieee802_1x_save_eapol(sta, buf, len); 1058780fb4a2SCy Schubert } 1059780fb4a2SCy Schubert 1060e28a4053SRui Paulo return; 1061e28a4053SRui Paulo } 1062e28a4053SRui Paulo 1063e28a4053SRui Paulo if (len < sizeof(*hdr)) { 10645b9c547cSRui Paulo wpa_printf(MSG_INFO, " too short IEEE 802.1X packet"); 1065e28a4053SRui Paulo return; 1066e28a4053SRui Paulo } 1067e28a4053SRui Paulo 1068e28a4053SRui Paulo hdr = (struct ieee802_1x_hdr *) buf; 1069e28a4053SRui Paulo datalen = be_to_host16(hdr->length); 1070e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " IEEE 802.1X: version=%d type=%d length=%d", 1071e28a4053SRui Paulo hdr->version, hdr->type, datalen); 1072e28a4053SRui Paulo 1073e28a4053SRui Paulo if (len - sizeof(*hdr) < datalen) { 1074*c1d255d3SCy Schubert wpa_printf(MSG_INFO, 1075*c1d255d3SCy Schubert " frame too short for this IEEE 802.1X packet"); 1076e28a4053SRui Paulo if (sta->eapol_sm) 1077e28a4053SRui Paulo sta->eapol_sm->dot1xAuthEapLengthErrorFramesRx++; 1078e28a4053SRui Paulo return; 1079e28a4053SRui Paulo } 1080e28a4053SRui Paulo if (len - sizeof(*hdr) > datalen) { 1081*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1082*c1d255d3SCy Schubert " ignoring %lu extra octets after IEEE 802.1X packet", 1083e28a4053SRui Paulo (unsigned long) len - sizeof(*hdr) - datalen); 1084e28a4053SRui Paulo } 1085e28a4053SRui Paulo 1086e28a4053SRui Paulo if (sta->eapol_sm) { 1087e28a4053SRui Paulo sta->eapol_sm->dot1xAuthLastEapolFrameVersion = hdr->version; 1088e28a4053SRui Paulo sta->eapol_sm->dot1xAuthEapolFramesRx++; 1089e28a4053SRui Paulo } 1090e28a4053SRui Paulo 1091e28a4053SRui Paulo key = (struct ieee802_1x_eapol_key *) (hdr + 1); 1092e28a4053SRui Paulo if (datalen >= sizeof(struct ieee802_1x_eapol_key) && 1093e28a4053SRui Paulo hdr->type == IEEE802_1X_TYPE_EAPOL_KEY && 1094e28a4053SRui Paulo (key->type == EAPOL_KEY_TYPE_WPA || 1095e28a4053SRui Paulo key->type == EAPOL_KEY_TYPE_RSN)) { 1096e28a4053SRui Paulo wpa_receive(hapd->wpa_auth, sta->wpa_sm, (u8 *) hdr, 1097e28a4053SRui Paulo sizeof(*hdr) + datalen); 1098e28a4053SRui Paulo return; 1099e28a4053SRui Paulo } 1100e28a4053SRui Paulo 11015b9c547cSRui Paulo if (!hapd->conf->ieee802_1x && !hapd->conf->osen && 1102f05cddf9SRui Paulo !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) { 1103*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1104*c1d255d3SCy Schubert "IEEE 802.1X: Ignore EAPOL message - 802.1X not enabled and WPS not used"); 1105e28a4053SRui Paulo return; 1106f05cddf9SRui Paulo } 1107f05cddf9SRui Paulo 1108f05cddf9SRui Paulo key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm); 110985732ac8SCy Schubert if (key_mgmt != -1 && 111085732ac8SCy Schubert (wpa_key_mgmt_wpa_psk(key_mgmt) || key_mgmt == WPA_KEY_MGMT_OWE || 111185732ac8SCy Schubert key_mgmt == WPA_KEY_MGMT_DPP)) { 1112*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1113*c1d255d3SCy Schubert "IEEE 802.1X: Ignore EAPOL message - STA is using PSK"); 1114f05cddf9SRui Paulo return; 1115f05cddf9SRui Paulo } 1116e28a4053SRui Paulo 1117e28a4053SRui Paulo if (!sta->eapol_sm) { 1118e28a4053SRui Paulo sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta); 1119e28a4053SRui Paulo if (!sta->eapol_sm) 1120e28a4053SRui Paulo return; 1121e28a4053SRui Paulo 1122e28a4053SRui Paulo #ifdef CONFIG_WPS 11235b9c547cSRui Paulo if (!hapd->conf->ieee802_1x && hapd->conf->wps_state) { 1124f05cddf9SRui Paulo u32 wflags = sta->flags & (WLAN_STA_WPS | 1125f05cddf9SRui Paulo WLAN_STA_WPS2 | 1126f05cddf9SRui Paulo WLAN_STA_MAYBE_WPS); 1127f05cddf9SRui Paulo if (wflags == WLAN_STA_MAYBE_WPS || 1128f05cddf9SRui Paulo wflags == (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) { 1129e28a4053SRui Paulo /* 1130f05cddf9SRui Paulo * Delay EAPOL frame transmission until a 1131f05cddf9SRui Paulo * possible WPS STA initiates the handshake 1132f05cddf9SRui Paulo * with EAPOL-Start. Only allow the wait to be 1133f05cddf9SRui Paulo * skipped if the STA is known to support WPS 1134f05cddf9SRui Paulo * 2.0. 1135e28a4053SRui Paulo */ 1136*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1137*c1d255d3SCy Schubert "WPS: Do not start EAPOL until EAPOL-Start is received"); 1138e28a4053SRui Paulo sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; 1139e28a4053SRui Paulo } 1140f05cddf9SRui Paulo } 1141e28a4053SRui Paulo #endif /* CONFIG_WPS */ 1142e28a4053SRui Paulo 1143*c1d255d3SCy Schubert sta->eapol_sm->eap_if->portEnabled = true; 1144e28a4053SRui Paulo } 1145e28a4053SRui Paulo 1146e28a4053SRui Paulo /* since we support version 1, we can ignore version field and proceed 1147e28a4053SRui Paulo * as specified in version 1 standard [IEEE Std 802.1X-2001, 7.5.5] */ 1148e28a4053SRui Paulo /* TODO: actually, we are not version 1 anymore.. However, Version 2 1149e28a4053SRui Paulo * does not change frame contents, so should be ok to process frames 1150e28a4053SRui Paulo * more or less identically. Some changes might be needed for 1151e28a4053SRui Paulo * verification of fields. */ 1152e28a4053SRui Paulo 1153e28a4053SRui Paulo switch (hdr->type) { 1154e28a4053SRui Paulo case IEEE802_1X_TYPE_EAP_PACKET: 1155e28a4053SRui Paulo handle_eap(hapd, sta, (u8 *) (hdr + 1), datalen); 1156e28a4053SRui Paulo break; 1157e28a4053SRui Paulo 1158e28a4053SRui Paulo case IEEE802_1X_TYPE_EAPOL_START: 1159e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1160*c1d255d3SCy Schubert HOSTAPD_LEVEL_DEBUG, 1161*c1d255d3SCy Schubert "received EAPOL-Start from STA"); 1162e28a4053SRui Paulo sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START; 1163e28a4053SRui Paulo pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm); 1164e28a4053SRui Paulo if (pmksa) { 1165e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, 1166*c1d255d3SCy Schubert HOSTAPD_LEVEL_DEBUG, 1167*c1d255d3SCy Schubert "cached PMKSA available - ignore it since STA sent EAPOL-Start"); 1168e28a4053SRui Paulo wpa_auth_sta_clear_pmksa(sta->wpa_sm, pmksa); 1169e28a4053SRui Paulo } 1170*c1d255d3SCy Schubert sta->eapol_sm->eapolStart = true; 1171e28a4053SRui Paulo sta->eapol_sm->dot1xAuthEapolStartFramesRx++; 1172f05cddf9SRui Paulo eap_server_clear_identity(sta->eapol_sm->eap); 1173e28a4053SRui Paulo wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL); 1174e28a4053SRui Paulo break; 1175e28a4053SRui Paulo 1176e28a4053SRui Paulo case IEEE802_1X_TYPE_EAPOL_LOGOFF: 1177e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1178*c1d255d3SCy Schubert HOSTAPD_LEVEL_DEBUG, 1179*c1d255d3SCy Schubert "received EAPOL-Logoff from STA"); 1180e28a4053SRui Paulo sta->acct_terminate_cause = 1181e28a4053SRui Paulo RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; 1182e28a4053SRui Paulo accounting_sta_stop(hapd, sta); 1183*c1d255d3SCy Schubert sta->eapol_sm->eapolLogoff = true; 1184e28a4053SRui Paulo sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++; 1185f05cddf9SRui Paulo eap_server_clear_identity(sta->eapol_sm->eap); 1186e28a4053SRui Paulo break; 1187e28a4053SRui Paulo 1188e28a4053SRui Paulo case IEEE802_1X_TYPE_EAPOL_KEY: 1189e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " EAPOL-Key"); 1190f05cddf9SRui Paulo if (!ap_sta_is_authorized(sta)) { 1191*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1192*c1d255d3SCy Schubert " Dropped key data from unauthorized Supplicant"); 1193e28a4053SRui Paulo break; 1194e28a4053SRui Paulo } 1195e28a4053SRui Paulo break; 1196e28a4053SRui Paulo 1197e28a4053SRui Paulo case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT: 1198e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " EAPOL-Encapsulated-ASF-Alert"); 1199e28a4053SRui Paulo /* TODO: implement support for this; show data */ 1200e28a4053SRui Paulo break; 1201e28a4053SRui Paulo 1202206b73d0SCy Schubert #ifdef CONFIG_MACSEC 1203206b73d0SCy Schubert case IEEE802_1X_TYPE_EAPOL_MKA: 1204206b73d0SCy Schubert wpa_printf(MSG_EXCESSIVE, 1205206b73d0SCy Schubert "EAPOL type %d will be handled by MKA", hdr->type); 1206206b73d0SCy Schubert break; 1207206b73d0SCy Schubert #endif /* CONFIG_MACSEC */ 1208206b73d0SCy Schubert 1209e28a4053SRui Paulo default: 1210e28a4053SRui Paulo wpa_printf(MSG_DEBUG, " unknown IEEE 802.1X packet type"); 1211e28a4053SRui Paulo sta->eapol_sm->dot1xAuthInvalidEapolFramesRx++; 1212e28a4053SRui Paulo break; 1213e28a4053SRui Paulo } 1214e28a4053SRui Paulo 1215e28a4053SRui Paulo eapol_auth_step(sta->eapol_sm); 1216e28a4053SRui Paulo } 1217e28a4053SRui Paulo 1218e28a4053SRui Paulo 1219e28a4053SRui Paulo /** 1220e28a4053SRui Paulo * ieee802_1x_new_station - Start IEEE 802.1X authentication 1221e28a4053SRui Paulo * @hapd: hostapd BSS data 1222e28a4053SRui Paulo * @sta: The station 1223e28a4053SRui Paulo * 1224e28a4053SRui Paulo * This function is called to start IEEE 802.1X authentication when a new 1225e28a4053SRui Paulo * station completes IEEE 802.11 association. 1226e28a4053SRui Paulo */ 1227e28a4053SRui Paulo void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta) 1228e28a4053SRui Paulo { 1229e28a4053SRui Paulo struct rsn_pmksa_cache_entry *pmksa; 1230e28a4053SRui Paulo int reassoc = 1; 1231e28a4053SRui Paulo int force_1x = 0; 1232f05cddf9SRui Paulo int key_mgmt; 1233e28a4053SRui Paulo 1234e28a4053SRui Paulo #ifdef CONFIG_WPS 12355b9c547cSRui Paulo if (hapd->conf->wps_state && 12365b9c547cSRui Paulo ((hapd->conf->wpa && (sta->flags & WLAN_STA_MAYBE_WPS)) || 12375b9c547cSRui Paulo (sta->flags & WLAN_STA_WPS))) { 1238e28a4053SRui Paulo /* 1239e28a4053SRui Paulo * Need to enable IEEE 802.1X/EAPOL state machines for possible 1240e28a4053SRui Paulo * WPS handshake even if IEEE 802.1X/EAPOL is not used for 1241e28a4053SRui Paulo * authentication in this BSS. 1242e28a4053SRui Paulo */ 1243e28a4053SRui Paulo force_1x = 1; 1244e28a4053SRui Paulo } 1245e28a4053SRui Paulo #endif /* CONFIG_WPS */ 1246e28a4053SRui Paulo 12475b9c547cSRui Paulo if (!force_1x && !hapd->conf->ieee802_1x && !hapd->conf->osen) { 1248*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1249*c1d255d3SCy Schubert "IEEE 802.1X: Ignore STA - 802.1X not enabled or forced for WPS"); 1250f05cddf9SRui Paulo /* 1251f05cddf9SRui Paulo * Clear any possible EAPOL authenticator state to support 1252f05cddf9SRui Paulo * reassociation change from WPS to PSK. 1253f05cddf9SRui Paulo */ 1254780fb4a2SCy Schubert ieee802_1x_free_station(hapd, sta); 1255e28a4053SRui Paulo return; 1256f05cddf9SRui Paulo } 1257f05cddf9SRui Paulo 1258f05cddf9SRui Paulo key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm); 125985732ac8SCy Schubert if (key_mgmt != -1 && 126085732ac8SCy Schubert (wpa_key_mgmt_wpa_psk(key_mgmt) || key_mgmt == WPA_KEY_MGMT_OWE || 126185732ac8SCy Schubert key_mgmt == WPA_KEY_MGMT_DPP)) { 1262f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - using PSK"); 1263f05cddf9SRui Paulo /* 1264f05cddf9SRui Paulo * Clear any possible EAPOL authenticator state to support 1265f05cddf9SRui Paulo * reassociation change from WPA-EAP to PSK. 1266f05cddf9SRui Paulo */ 1267780fb4a2SCy Schubert ieee802_1x_free_station(hapd, sta); 1268f05cddf9SRui Paulo return; 1269f05cddf9SRui Paulo } 1270e28a4053SRui Paulo 1271*c1d255d3SCy Schubert if (!sta->eapol_sm) { 1272e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1273e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "start authentication"); 1274e28a4053SRui Paulo sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta); 1275*c1d255d3SCy Schubert if (!sta->eapol_sm) { 1276e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, 1277e28a4053SRui Paulo HOSTAPD_MODULE_IEEE8021X, 1278e28a4053SRui Paulo HOSTAPD_LEVEL_INFO, 1279e28a4053SRui Paulo "failed to allocate state machine"); 1280e28a4053SRui Paulo return; 1281e28a4053SRui Paulo } 1282e28a4053SRui Paulo reassoc = 0; 1283e28a4053SRui Paulo } 1284e28a4053SRui Paulo 1285e28a4053SRui Paulo #ifdef CONFIG_WPS 1286e28a4053SRui Paulo sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START; 12875b9c547cSRui Paulo if (!hapd->conf->ieee802_1x && hapd->conf->wps_state && 12885b9c547cSRui Paulo !(sta->flags & WLAN_STA_WPS2)) { 1289e28a4053SRui Paulo /* 1290f05cddf9SRui Paulo * Delay EAPOL frame transmission until a possible WPS STA 1291f05cddf9SRui Paulo * initiates the handshake with EAPOL-Start. Only allow the 1292f05cddf9SRui Paulo * wait to be skipped if the STA is known to support WPS 2.0. 1293e28a4053SRui Paulo */ 1294*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1295*c1d255d3SCy Schubert "WPS: Do not start EAPOL until EAPOL-Start is received"); 1296e28a4053SRui Paulo sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; 1297e28a4053SRui Paulo } 1298e28a4053SRui Paulo #endif /* CONFIG_WPS */ 1299e28a4053SRui Paulo 1300*c1d255d3SCy Schubert sta->eapol_sm->eap_if->portEnabled = true; 1301e28a4053SRui Paulo 130285732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP 1303f05cddf9SRui Paulo if (sta->auth_alg == WLAN_AUTH_FT) { 1304f05cddf9SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1305f05cddf9SRui Paulo HOSTAPD_LEVEL_DEBUG, 1306f05cddf9SRui Paulo "PMK from FT - skip IEEE 802.1X/EAP"); 1307f05cddf9SRui Paulo /* Setup EAPOL state machines to already authenticated state 1308f05cddf9SRui Paulo * because of existing FT information from R0KH. */ 1309*c1d255d3SCy Schubert sta->eapol_sm->keyRun = true; 1310*c1d255d3SCy Schubert sta->eapol_sm->eap_if->eapKeyAvailable = true; 1311f05cddf9SRui Paulo sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; 1312f05cddf9SRui Paulo sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; 1313*c1d255d3SCy Schubert sta->eapol_sm->authSuccess = true; 1314*c1d255d3SCy Schubert sta->eapol_sm->authFail = false; 1315*c1d255d3SCy Schubert sta->eapol_sm->portValid = true; 1316f05cddf9SRui Paulo if (sta->eapol_sm->eap) 1317f05cddf9SRui Paulo eap_sm_notify_cached(sta->eapol_sm->eap); 131885732ac8SCy Schubert ap_sta_bind_vlan(hapd, sta); 1319f05cddf9SRui Paulo return; 1320f05cddf9SRui Paulo } 132185732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */ 132285732ac8SCy Schubert 132385732ac8SCy Schubert #ifdef CONFIG_FILS 132485732ac8SCy Schubert if (sta->auth_alg == WLAN_AUTH_FILS_SK || 132585732ac8SCy Schubert sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || 132685732ac8SCy Schubert sta->auth_alg == WLAN_AUTH_FILS_PK) { 132785732ac8SCy Schubert hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 132885732ac8SCy Schubert HOSTAPD_LEVEL_DEBUG, 132985732ac8SCy Schubert "PMK from FILS - skip IEEE 802.1X/EAP"); 133085732ac8SCy Schubert /* Setup EAPOL state machines to already authenticated state 133185732ac8SCy Schubert * because of existing FILS information. */ 1332*c1d255d3SCy Schubert sta->eapol_sm->keyRun = true; 1333*c1d255d3SCy Schubert sta->eapol_sm->eap_if->eapKeyAvailable = true; 133485732ac8SCy Schubert sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; 133585732ac8SCy Schubert sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; 1336*c1d255d3SCy Schubert sta->eapol_sm->authSuccess = true; 1337*c1d255d3SCy Schubert sta->eapol_sm->authFail = false; 1338*c1d255d3SCy Schubert sta->eapol_sm->portValid = true; 133985732ac8SCy Schubert if (sta->eapol_sm->eap) 134085732ac8SCy Schubert eap_sm_notify_cached(sta->eapol_sm->eap); 13414bc52338SCy Schubert wpa_auth_set_ptk_rekey_timer(sta->wpa_sm); 134285732ac8SCy Schubert return; 134385732ac8SCy Schubert } 134485732ac8SCy Schubert #endif /* CONFIG_FILS */ 1345f05cddf9SRui Paulo 1346e28a4053SRui Paulo pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm); 1347e28a4053SRui Paulo if (pmksa) { 1348e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1349e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, 1350e28a4053SRui Paulo "PMK from PMKSA cache - skip IEEE 802.1X/EAP"); 1351e28a4053SRui Paulo /* Setup EAPOL state machines to already authenticated state 1352e28a4053SRui Paulo * because of existing PMKSA information in the cache. */ 1353*c1d255d3SCy Schubert sta->eapol_sm->keyRun = true; 1354*c1d255d3SCy Schubert sta->eapol_sm->eap_if->eapKeyAvailable = true; 1355e28a4053SRui Paulo sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; 1356e28a4053SRui Paulo sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; 1357*c1d255d3SCy Schubert sta->eapol_sm->authSuccess = true; 1358*c1d255d3SCy Schubert sta->eapol_sm->authFail = false; 1359e28a4053SRui Paulo if (sta->eapol_sm->eap) 1360e28a4053SRui Paulo eap_sm_notify_cached(sta->eapol_sm->eap); 1361780fb4a2SCy Schubert pmksa_cache_to_eapol_data(hapd, pmksa, sta->eapol_sm); 1362325151a3SRui Paulo ap_sta_bind_vlan(hapd, sta); 1363e28a4053SRui Paulo } else { 1364e28a4053SRui Paulo if (reassoc) { 1365e28a4053SRui Paulo /* 1366e28a4053SRui Paulo * Force EAPOL state machines to start 1367e28a4053SRui Paulo * re-authentication without having to wait for the 1368e28a4053SRui Paulo * Supplicant to send EAPOL-Start. 1369e28a4053SRui Paulo */ 1370*c1d255d3SCy Schubert sta->eapol_sm->reAuthenticate = true; 1371e28a4053SRui Paulo } 1372e28a4053SRui Paulo eapol_auth_step(sta->eapol_sm); 1373e28a4053SRui Paulo } 1374e28a4053SRui Paulo } 1375e28a4053SRui Paulo 1376e28a4053SRui Paulo 1377780fb4a2SCy Schubert void ieee802_1x_free_station(struct hostapd_data *hapd, struct sta_info *sta) 1378e28a4053SRui Paulo { 1379e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 1380e28a4053SRui Paulo 1381780fb4a2SCy Schubert #ifdef CONFIG_HS20 1382780fb4a2SCy Schubert eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta); 1383780fb4a2SCy Schubert #endif /* CONFIG_HS20 */ 1384780fb4a2SCy Schubert 1385780fb4a2SCy Schubert if (sta->pending_eapol_rx) { 1386780fb4a2SCy Schubert wpabuf_free(sta->pending_eapol_rx->buf); 1387780fb4a2SCy Schubert os_free(sta->pending_eapol_rx); 1388780fb4a2SCy Schubert sta->pending_eapol_rx = NULL; 1389780fb4a2SCy Schubert } 1390780fb4a2SCy Schubert 1391*c1d255d3SCy Schubert if (!sm) 1392e28a4053SRui Paulo return; 1393e28a4053SRui Paulo 1394e28a4053SRui Paulo sta->eapol_sm = NULL; 1395e28a4053SRui Paulo 1396e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS 1397e28a4053SRui Paulo radius_msg_free(sm->last_recv_radius); 1398e28a4053SRui Paulo radius_free_class(&sm->radius_class); 1399e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */ 1400e28a4053SRui Paulo 1401e28a4053SRui Paulo eapol_auth_free(sm); 1402e28a4053SRui Paulo } 1403e28a4053SRui Paulo 1404e28a4053SRui Paulo 1405e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS 1406e28a4053SRui Paulo static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd, 1407e28a4053SRui Paulo struct sta_info *sta) 1408e28a4053SRui Paulo { 1409f05cddf9SRui Paulo struct wpabuf *eap; 1410f05cddf9SRui Paulo const struct eap_hdr *hdr; 1411e28a4053SRui Paulo int eap_type = -1; 1412e28a4053SRui Paulo char buf[64]; 1413e28a4053SRui Paulo struct radius_msg *msg; 1414e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 1415e28a4053SRui Paulo 1416*c1d255d3SCy Schubert if (!sm || !sm->last_recv_radius) { 1417e28a4053SRui Paulo if (sm) 1418*c1d255d3SCy Schubert sm->eap_if->aaaEapNoReq = true; 1419e28a4053SRui Paulo return; 1420e28a4053SRui Paulo } 1421e28a4053SRui Paulo 1422e28a4053SRui Paulo msg = sm->last_recv_radius; 1423e28a4053SRui Paulo 1424f05cddf9SRui Paulo eap = radius_msg_get_eap(msg); 1425*c1d255d3SCy Schubert if (!eap) { 1426e28a4053SRui Paulo /* RFC 3579, Chap. 2.6.3: 1427e28a4053SRui Paulo * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message 1428e28a4053SRui Paulo * attribute */ 1429e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1430*c1d255d3SCy Schubert HOSTAPD_LEVEL_WARNING, 1431*c1d255d3SCy Schubert "could not extract EAP-Message from RADIUS message"); 1432*c1d255d3SCy Schubert sm->eap_if->aaaEapNoReq = true; 1433e28a4053SRui Paulo return; 1434e28a4053SRui Paulo } 1435e28a4053SRui Paulo 1436f05cddf9SRui Paulo if (wpabuf_len(eap) < sizeof(*hdr)) { 1437e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1438*c1d255d3SCy Schubert HOSTAPD_LEVEL_WARNING, 1439*c1d255d3SCy Schubert "too short EAP packet received from authentication server"); 1440f05cddf9SRui Paulo wpabuf_free(eap); 1441*c1d255d3SCy Schubert sm->eap_if->aaaEapNoReq = true; 1442e28a4053SRui Paulo return; 1443e28a4053SRui Paulo } 1444e28a4053SRui Paulo 1445f05cddf9SRui Paulo if (wpabuf_len(eap) > sizeof(*hdr)) 1446f05cddf9SRui Paulo eap_type = (wpabuf_head_u8(eap))[sizeof(*hdr)]; 1447e28a4053SRui Paulo 1448f05cddf9SRui Paulo hdr = wpabuf_head(eap); 1449e28a4053SRui Paulo switch (hdr->code) { 1450e28a4053SRui Paulo case EAP_CODE_REQUEST: 1451e28a4053SRui Paulo if (eap_type >= 0) 1452e28a4053SRui Paulo sm->eap_type_authsrv = eap_type; 1453e28a4053SRui Paulo os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)", 14545b9c547cSRui Paulo eap_server_get_name(0, eap_type), eap_type); 1455e28a4053SRui Paulo break; 1456e28a4053SRui Paulo case EAP_CODE_RESPONSE: 1457e28a4053SRui Paulo os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)", 14585b9c547cSRui Paulo eap_server_get_name(0, eap_type), eap_type); 1459e28a4053SRui Paulo break; 1460e28a4053SRui Paulo case EAP_CODE_SUCCESS: 1461e28a4053SRui Paulo os_strlcpy(buf, "EAP Success", sizeof(buf)); 1462e28a4053SRui Paulo break; 1463e28a4053SRui Paulo case EAP_CODE_FAILURE: 1464e28a4053SRui Paulo os_strlcpy(buf, "EAP Failure", sizeof(buf)); 1465e28a4053SRui Paulo break; 1466e28a4053SRui Paulo default: 1467e28a4053SRui Paulo os_strlcpy(buf, "unknown EAP code", sizeof(buf)); 1468e28a4053SRui Paulo break; 1469e28a4053SRui Paulo } 1470e28a4053SRui Paulo buf[sizeof(buf) - 1] = '\0'; 1471e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1472*c1d255d3SCy Schubert HOSTAPD_LEVEL_DEBUG, 1473*c1d255d3SCy Schubert "decapsulated EAP packet (code=%d id=%d len=%d) from RADIUS server: %s", 1474e28a4053SRui Paulo hdr->code, hdr->identifier, be_to_host16(hdr->length), 1475e28a4053SRui Paulo buf); 1476*c1d255d3SCy Schubert sm->eap_if->aaaEapReq = true; 1477e28a4053SRui Paulo 1478e28a4053SRui Paulo wpabuf_free(sm->eap_if->aaaEapReqData); 1479f05cddf9SRui Paulo sm->eap_if->aaaEapReqData = eap; 1480e28a4053SRui Paulo } 1481e28a4053SRui Paulo 1482e28a4053SRui Paulo 1483e28a4053SRui Paulo static void ieee802_1x_get_keys(struct hostapd_data *hapd, 1484e28a4053SRui Paulo struct sta_info *sta, struct radius_msg *msg, 1485e28a4053SRui Paulo struct radius_msg *req, 1486e28a4053SRui Paulo const u8 *shared_secret, 1487e28a4053SRui Paulo size_t shared_secret_len) 1488e28a4053SRui Paulo { 1489e28a4053SRui Paulo struct radius_ms_mppe_keys *keys; 1490206b73d0SCy Schubert u8 *buf; 1491206b73d0SCy Schubert size_t len; 1492e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 1493*c1d255d3SCy Schubert 1494*c1d255d3SCy Schubert if (!sm) 1495e28a4053SRui Paulo return; 1496e28a4053SRui Paulo 1497e28a4053SRui Paulo keys = radius_msg_get_ms_keys(msg, req, shared_secret, 1498e28a4053SRui Paulo shared_secret_len); 1499e28a4053SRui Paulo 1500e28a4053SRui Paulo if (keys && keys->send && keys->recv) { 1501206b73d0SCy Schubert len = keys->send_len + keys->recv_len; 1502e28a4053SRui Paulo wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Send-Key", 1503e28a4053SRui Paulo keys->send, keys->send_len); 1504e28a4053SRui Paulo wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Recv-Key", 1505e28a4053SRui Paulo keys->recv, keys->recv_len); 1506e28a4053SRui Paulo 1507e28a4053SRui Paulo os_free(sm->eap_if->aaaEapKeyData); 1508e28a4053SRui Paulo sm->eap_if->aaaEapKeyData = os_malloc(len); 1509e28a4053SRui Paulo if (sm->eap_if->aaaEapKeyData) { 1510e28a4053SRui Paulo os_memcpy(sm->eap_if->aaaEapKeyData, keys->recv, 1511e28a4053SRui Paulo keys->recv_len); 1512e28a4053SRui Paulo os_memcpy(sm->eap_if->aaaEapKeyData + keys->recv_len, 1513e28a4053SRui Paulo keys->send, keys->send_len); 1514e28a4053SRui Paulo sm->eap_if->aaaEapKeyDataLen = len; 1515*c1d255d3SCy Schubert sm->eap_if->aaaEapKeyAvailable = true; 1516e28a4053SRui Paulo } 15175b9c547cSRui Paulo } else { 15185b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 15195b9c547cSRui Paulo "MS-MPPE: 1x_get_keys, could not get keys: %p send: %p recv: %p", 15205b9c547cSRui Paulo keys, keys ? keys->send : NULL, 15215b9c547cSRui Paulo keys ? keys->recv : NULL); 1522e28a4053SRui Paulo } 1523e28a4053SRui Paulo 1524e28a4053SRui Paulo if (keys) { 1525e28a4053SRui Paulo os_free(keys->send); 1526e28a4053SRui Paulo os_free(keys->recv); 1527e28a4053SRui Paulo os_free(keys); 1528e28a4053SRui Paulo } 1529206b73d0SCy Schubert 1530206b73d0SCy Schubert if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_EAP_KEY_NAME, &buf, &len, 1531206b73d0SCy Schubert NULL) == 0) { 1532206b73d0SCy Schubert os_free(sm->eap_if->eapSessionId); 1533206b73d0SCy Schubert sm->eap_if->eapSessionId = os_memdup(buf, len); 1534206b73d0SCy Schubert if (sm->eap_if->eapSessionId) { 1535206b73d0SCy Schubert sm->eap_if->eapSessionIdLen = len; 1536206b73d0SCy Schubert wpa_hexdump(MSG_DEBUG, "EAP-Key Name", 1537206b73d0SCy Schubert sm->eap_if->eapSessionId, 1538206b73d0SCy Schubert sm->eap_if->eapSessionIdLen); 1539206b73d0SCy Schubert } 1540206b73d0SCy Schubert } else { 1541206b73d0SCy Schubert sm->eap_if->eapSessionIdLen = 0; 1542206b73d0SCy Schubert } 1543e28a4053SRui Paulo } 1544e28a4053SRui Paulo 1545e28a4053SRui Paulo 1546e28a4053SRui Paulo static void ieee802_1x_store_radius_class(struct hostapd_data *hapd, 1547e28a4053SRui Paulo struct sta_info *sta, 1548e28a4053SRui Paulo struct radius_msg *msg) 1549e28a4053SRui Paulo { 1550325151a3SRui Paulo u8 *attr_class; 1551e28a4053SRui Paulo size_t class_len; 1552e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 1553e28a4053SRui Paulo int count, i; 1554e28a4053SRui Paulo struct radius_attr_data *nclass; 1555e28a4053SRui Paulo size_t nclass_count; 1556e28a4053SRui Paulo 1557*c1d255d3SCy Schubert if (!hapd->conf->radius->acct_server || !hapd->radius || !sm) 1558e28a4053SRui Paulo return; 1559e28a4053SRui Paulo 1560e28a4053SRui Paulo radius_free_class(&sm->radius_class); 1561e28a4053SRui Paulo count = radius_msg_count_attr(msg, RADIUS_ATTR_CLASS, 1); 1562e28a4053SRui Paulo if (count <= 0) 1563e28a4053SRui Paulo return; 1564e28a4053SRui Paulo 1565f05cddf9SRui Paulo nclass = os_calloc(count, sizeof(struct radius_attr_data)); 1566*c1d255d3SCy Schubert if (!nclass) 1567e28a4053SRui Paulo return; 1568e28a4053SRui Paulo 1569e28a4053SRui Paulo nclass_count = 0; 1570e28a4053SRui Paulo 1571325151a3SRui Paulo attr_class = NULL; 1572e28a4053SRui Paulo for (i = 0; i < count; i++) { 1573e28a4053SRui Paulo do { 1574e28a4053SRui Paulo if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS, 1575325151a3SRui Paulo &attr_class, &class_len, 1576325151a3SRui Paulo attr_class) < 0) { 1577e28a4053SRui Paulo i = count; 1578e28a4053SRui Paulo break; 1579e28a4053SRui Paulo } 1580e28a4053SRui Paulo } while (class_len < 1); 1581e28a4053SRui Paulo 158285732ac8SCy Schubert nclass[nclass_count].data = os_memdup(attr_class, class_len); 1583*c1d255d3SCy Schubert if (!nclass[nclass_count].data) 1584e28a4053SRui Paulo break; 1585e28a4053SRui Paulo 1586e28a4053SRui Paulo nclass[nclass_count].len = class_len; 1587e28a4053SRui Paulo nclass_count++; 1588e28a4053SRui Paulo } 1589e28a4053SRui Paulo 1590e28a4053SRui Paulo sm->radius_class.attr = nclass; 1591e28a4053SRui Paulo sm->radius_class.count = nclass_count; 1592*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1593*c1d255d3SCy Schubert "IEEE 802.1X: Stored %lu RADIUS Class attributes for " 1594*c1d255d3SCy Schubert MACSTR, 1595e28a4053SRui Paulo (unsigned long) sm->radius_class.count, 1596e28a4053SRui Paulo MAC2STR(sta->addr)); 1597e28a4053SRui Paulo } 1598e28a4053SRui Paulo 1599e28a4053SRui Paulo 1600e28a4053SRui Paulo /* Update sta->identity based on User-Name attribute in Access-Accept */ 1601e28a4053SRui Paulo static void ieee802_1x_update_sta_identity(struct hostapd_data *hapd, 1602e28a4053SRui Paulo struct sta_info *sta, 1603e28a4053SRui Paulo struct radius_msg *msg) 1604e28a4053SRui Paulo { 1605e28a4053SRui Paulo u8 *buf, *identity; 1606e28a4053SRui Paulo size_t len; 1607e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 1608e28a4053SRui Paulo 1609*c1d255d3SCy Schubert if (!sm) 1610e28a4053SRui Paulo return; 1611e28a4053SRui Paulo 1612e28a4053SRui Paulo if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &buf, &len, 1613e28a4053SRui Paulo NULL) < 0) 1614e28a4053SRui Paulo return; 1615e28a4053SRui Paulo 16165b9c547cSRui Paulo identity = (u8 *) dup_binstr(buf, len); 1617*c1d255d3SCy Schubert if (!identity) 1618e28a4053SRui Paulo return; 1619e28a4053SRui Paulo 1620e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1621*c1d255d3SCy Schubert HOSTAPD_LEVEL_DEBUG, 1622*c1d255d3SCy Schubert "old identity '%s' updated with User-Name from Access-Accept '%s'", 1623e28a4053SRui Paulo sm->identity ? (char *) sm->identity : "N/A", 1624e28a4053SRui Paulo (char *) identity); 1625e28a4053SRui Paulo 1626e28a4053SRui Paulo os_free(sm->identity); 1627e28a4053SRui Paulo sm->identity = identity; 1628e28a4053SRui Paulo sm->identity_len = len; 1629e28a4053SRui Paulo } 1630e28a4053SRui Paulo 1631e28a4053SRui Paulo 1632f05cddf9SRui Paulo /* Update CUI based on Chargeable-User-Identity attribute in Access-Accept */ 1633f05cddf9SRui Paulo static void ieee802_1x_update_sta_cui(struct hostapd_data *hapd, 1634f05cddf9SRui Paulo struct sta_info *sta, 1635f05cddf9SRui Paulo struct radius_msg *msg) 1636f05cddf9SRui Paulo { 1637f05cddf9SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 1638f05cddf9SRui Paulo struct wpabuf *cui; 1639f05cddf9SRui Paulo u8 *buf; 1640f05cddf9SRui Paulo size_t len; 1641f05cddf9SRui Paulo 1642*c1d255d3SCy Schubert if (!sm) 1643f05cddf9SRui Paulo return; 1644f05cddf9SRui Paulo 1645f05cddf9SRui Paulo if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, 1646f05cddf9SRui Paulo &buf, &len, NULL) < 0) 1647f05cddf9SRui Paulo return; 1648f05cddf9SRui Paulo 1649f05cddf9SRui Paulo cui = wpabuf_alloc_copy(buf, len); 1650*c1d255d3SCy Schubert if (!cui) 1651f05cddf9SRui Paulo return; 1652f05cddf9SRui Paulo 1653f05cddf9SRui Paulo wpabuf_free(sm->radius_cui); 1654f05cddf9SRui Paulo sm->radius_cui = cui; 1655f05cddf9SRui Paulo } 1656f05cddf9SRui Paulo 1657f05cddf9SRui Paulo 16585b9c547cSRui Paulo #ifdef CONFIG_HS20 16595b9c547cSRui Paulo 16605b9c547cSRui Paulo static void ieee802_1x_hs20_sub_rem(struct sta_info *sta, u8 *pos, size_t len) 16615b9c547cSRui Paulo { 16625b9c547cSRui Paulo sta->remediation = 1; 16635b9c547cSRui Paulo os_free(sta->remediation_url); 16645b9c547cSRui Paulo if (len > 2) { 16655b9c547cSRui Paulo sta->remediation_url = os_malloc(len); 16665b9c547cSRui Paulo if (!sta->remediation_url) 16675b9c547cSRui Paulo return; 16685b9c547cSRui Paulo sta->remediation_method = pos[0]; 16695b9c547cSRui Paulo os_memcpy(sta->remediation_url, pos + 1, len - 1); 16705b9c547cSRui Paulo sta->remediation_url[len - 1] = '\0'; 1671*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1672*c1d255d3SCy Schubert "HS 2.0: Subscription remediation needed for " 1673*c1d255d3SCy Schubert MACSTR " - server method %u URL %s", 16745b9c547cSRui Paulo MAC2STR(sta->addr), sta->remediation_method, 16755b9c547cSRui Paulo sta->remediation_url); 16765b9c547cSRui Paulo } else { 16775b9c547cSRui Paulo sta->remediation_url = NULL; 1678*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1679*c1d255d3SCy Schubert "HS 2.0: Subscription remediation needed for " 1680*c1d255d3SCy Schubert MACSTR, MAC2STR(sta->addr)); 16815b9c547cSRui Paulo } 16825b9c547cSRui Paulo /* TODO: assign the STA into remediation VLAN or add filtering */ 16835b9c547cSRui Paulo } 16845b9c547cSRui Paulo 16855b9c547cSRui Paulo 16865b9c547cSRui Paulo static void ieee802_1x_hs20_deauth_req(struct hostapd_data *hapd, 16875b9c547cSRui Paulo struct sta_info *sta, u8 *pos, 16885b9c547cSRui Paulo size_t len) 16895b9c547cSRui Paulo { 16905b9c547cSRui Paulo if (len < 3) 16915b9c547cSRui Paulo return; /* Malformed information */ 16925b9c547cSRui Paulo sta->hs20_deauth_requested = 1; 1693*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1694*c1d255d3SCy Schubert "HS 2.0: Deauthentication request - Code %u Re-auth Delay %u", 16955b9c547cSRui Paulo *pos, WPA_GET_LE16(pos + 1)); 16965b9c547cSRui Paulo wpabuf_free(sta->hs20_deauth_req); 16975b9c547cSRui Paulo sta->hs20_deauth_req = wpabuf_alloc(len + 1); 16985b9c547cSRui Paulo if (sta->hs20_deauth_req) { 16995b9c547cSRui Paulo wpabuf_put_data(sta->hs20_deauth_req, pos, 3); 17005b9c547cSRui Paulo wpabuf_put_u8(sta->hs20_deauth_req, len - 3); 17015b9c547cSRui Paulo wpabuf_put_data(sta->hs20_deauth_req, pos + 3, len - 3); 17025b9c547cSRui Paulo } 17035b9c547cSRui Paulo ap_sta_session_timeout(hapd, sta, hapd->conf->hs20_deauth_req_timeout); 17045b9c547cSRui Paulo } 17055b9c547cSRui Paulo 17065b9c547cSRui Paulo 17075b9c547cSRui Paulo static void ieee802_1x_hs20_session_info(struct hostapd_data *hapd, 17085b9c547cSRui Paulo struct sta_info *sta, u8 *pos, 17095b9c547cSRui Paulo size_t len, int session_timeout) 17105b9c547cSRui Paulo { 17115b9c547cSRui Paulo unsigned int swt; 17125b9c547cSRui Paulo int warning_time, beacon_int; 17135b9c547cSRui Paulo 17145b9c547cSRui Paulo if (len < 1) 17155b9c547cSRui Paulo return; /* Malformed information */ 17165b9c547cSRui Paulo os_free(sta->hs20_session_info_url); 17175b9c547cSRui Paulo sta->hs20_session_info_url = os_malloc(len); 1718*c1d255d3SCy Schubert if (!sta->hs20_session_info_url) 17195b9c547cSRui Paulo return; 17205b9c547cSRui Paulo swt = pos[0]; 17215b9c547cSRui Paulo os_memcpy(sta->hs20_session_info_url, pos + 1, len - 1); 17225b9c547cSRui Paulo sta->hs20_session_info_url[len - 1] = '\0'; 1723*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1724*c1d255d3SCy Schubert "HS 2.0: Session Information URL='%s' SWT=%u (session_timeout=%d)", 17255b9c547cSRui Paulo sta->hs20_session_info_url, swt, session_timeout); 17265b9c547cSRui Paulo if (session_timeout < 0) { 1727*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1728*c1d255d3SCy Schubert "HS 2.0: No Session-Timeout set - ignore session info URL"); 17295b9c547cSRui Paulo return; 17305b9c547cSRui Paulo } 17315b9c547cSRui Paulo if (swt == 255) 17325b9c547cSRui Paulo swt = 1; /* Use one minute as the AP selected value */ 17335b9c547cSRui Paulo 17345b9c547cSRui Paulo if ((unsigned int) session_timeout < swt * 60) 17355b9c547cSRui Paulo warning_time = 0; 17365b9c547cSRui Paulo else 17375b9c547cSRui Paulo warning_time = session_timeout - swt * 60; 17385b9c547cSRui Paulo 17395b9c547cSRui Paulo beacon_int = hapd->iconf->beacon_int; 17405b9c547cSRui Paulo if (beacon_int < 1) 17415b9c547cSRui Paulo beacon_int = 100; /* best guess */ 17425b9c547cSRui Paulo sta->hs20_disassoc_timer = swt * 60 * 1000 / beacon_int * 125 / 128; 17435b9c547cSRui Paulo if (sta->hs20_disassoc_timer > 65535) 17445b9c547cSRui Paulo sta->hs20_disassoc_timer = 65535; 17455b9c547cSRui Paulo 17465b9c547cSRui Paulo ap_sta_session_warning_timeout(hapd, sta, warning_time); 17475b9c547cSRui Paulo } 17485b9c547cSRui Paulo 174985732ac8SCy Schubert 175085732ac8SCy Schubert static void ieee802_1x_hs20_t_c_filtering(struct hostapd_data *hapd, 175185732ac8SCy Schubert struct sta_info *sta, u8 *pos, 175285732ac8SCy Schubert size_t len) 175385732ac8SCy Schubert { 175485732ac8SCy Schubert if (len < 4) 175585732ac8SCy Schubert return; /* Malformed information */ 175685732ac8SCy Schubert wpa_printf(MSG_DEBUG, 175785732ac8SCy Schubert "HS 2.0: Terms and Conditions filtering %02x %02x %02x %02x", 175885732ac8SCy Schubert pos[0], pos[1], pos[2], pos[3]); 175985732ac8SCy Schubert hs20_t_c_filtering(hapd, sta, pos[0] & BIT(0)); 176085732ac8SCy Schubert } 176185732ac8SCy Schubert 176285732ac8SCy Schubert 176385732ac8SCy Schubert static void ieee802_1x_hs20_t_c_url(struct hostapd_data *hapd, 176485732ac8SCy Schubert struct sta_info *sta, u8 *pos, size_t len) 176585732ac8SCy Schubert { 176685732ac8SCy Schubert os_free(sta->t_c_url); 176785732ac8SCy Schubert sta->t_c_url = os_malloc(len + 1); 176885732ac8SCy Schubert if (!sta->t_c_url) 176985732ac8SCy Schubert return; 177085732ac8SCy Schubert os_memcpy(sta->t_c_url, pos, len); 177185732ac8SCy Schubert sta->t_c_url[len] = '\0'; 177285732ac8SCy Schubert wpa_printf(MSG_DEBUG, 177385732ac8SCy Schubert "HS 2.0: Terms and Conditions URL %s", sta->t_c_url); 177485732ac8SCy Schubert } 177585732ac8SCy Schubert 17765b9c547cSRui Paulo #endif /* CONFIG_HS20 */ 17775b9c547cSRui Paulo 17785b9c547cSRui Paulo 17795b9c547cSRui Paulo static void ieee802_1x_check_hs20(struct hostapd_data *hapd, 17805b9c547cSRui Paulo struct sta_info *sta, 17815b9c547cSRui Paulo struct radius_msg *msg, 17825b9c547cSRui Paulo int session_timeout) 17835b9c547cSRui Paulo { 17845b9c547cSRui Paulo #ifdef CONFIG_HS20 17855b9c547cSRui Paulo u8 *buf, *pos, *end, type, sublen; 17865b9c547cSRui Paulo size_t len; 17875b9c547cSRui Paulo 17885b9c547cSRui Paulo buf = NULL; 17895b9c547cSRui Paulo sta->remediation = 0; 17905b9c547cSRui Paulo sta->hs20_deauth_requested = 0; 17915b9c547cSRui Paulo 17925b9c547cSRui Paulo for (;;) { 17935b9c547cSRui Paulo if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, 17945b9c547cSRui Paulo &buf, &len, buf) < 0) 17955b9c547cSRui Paulo break; 17965b9c547cSRui Paulo if (len < 6) 17975b9c547cSRui Paulo continue; 17985b9c547cSRui Paulo pos = buf; 17995b9c547cSRui Paulo end = buf + len; 18005b9c547cSRui Paulo if (WPA_GET_BE32(pos) != RADIUS_VENDOR_ID_WFA) 18015b9c547cSRui Paulo continue; 18025b9c547cSRui Paulo pos += 4; 18035b9c547cSRui Paulo 18045b9c547cSRui Paulo type = *pos++; 18055b9c547cSRui Paulo sublen = *pos++; 18065b9c547cSRui Paulo if (sublen < 2) 18075b9c547cSRui Paulo continue; /* invalid length */ 18085b9c547cSRui Paulo sublen -= 2; /* skip header */ 18095b9c547cSRui Paulo if (pos + sublen > end) 18105b9c547cSRui Paulo continue; /* invalid WFA VSA */ 18115b9c547cSRui Paulo 18125b9c547cSRui Paulo switch (type) { 18135b9c547cSRui Paulo case RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION: 18145b9c547cSRui Paulo ieee802_1x_hs20_sub_rem(sta, pos, sublen); 18155b9c547cSRui Paulo break; 18165b9c547cSRui Paulo case RADIUS_VENDOR_ATTR_WFA_HS20_DEAUTH_REQ: 18175b9c547cSRui Paulo ieee802_1x_hs20_deauth_req(hapd, sta, pos, sublen); 18185b9c547cSRui Paulo break; 18195b9c547cSRui Paulo case RADIUS_VENDOR_ATTR_WFA_HS20_SESSION_INFO_URL: 18205b9c547cSRui Paulo ieee802_1x_hs20_session_info(hapd, sta, pos, sublen, 18215b9c547cSRui Paulo session_timeout); 18225b9c547cSRui Paulo break; 182385732ac8SCy Schubert case RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING: 182485732ac8SCy Schubert ieee802_1x_hs20_t_c_filtering(hapd, sta, pos, sublen); 182585732ac8SCy Schubert break; 182685732ac8SCy Schubert case RADIUS_VENDOR_ATTR_WFA_HS20_T_C_URL: 182785732ac8SCy Schubert ieee802_1x_hs20_t_c_url(hapd, sta, pos, sublen); 182885732ac8SCy Schubert break; 18295b9c547cSRui Paulo } 18305b9c547cSRui Paulo } 18315b9c547cSRui Paulo #endif /* CONFIG_HS20 */ 18325b9c547cSRui Paulo } 18335b9c547cSRui Paulo 18345b9c547cSRui Paulo 1835e28a4053SRui Paulo struct sta_id_search { 1836e28a4053SRui Paulo u8 identifier; 1837e28a4053SRui Paulo struct eapol_state_machine *sm; 1838e28a4053SRui Paulo }; 1839e28a4053SRui Paulo 1840e28a4053SRui Paulo 1841e28a4053SRui Paulo static int ieee802_1x_select_radius_identifier(struct hostapd_data *hapd, 1842e28a4053SRui Paulo struct sta_info *sta, 1843e28a4053SRui Paulo void *ctx) 1844e28a4053SRui Paulo { 1845e28a4053SRui Paulo struct sta_id_search *id_search = ctx; 1846e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 1847e28a4053SRui Paulo 1848e28a4053SRui Paulo if (sm && sm->radius_identifier >= 0 && 1849e28a4053SRui Paulo sm->radius_identifier == id_search->identifier) { 1850e28a4053SRui Paulo id_search->sm = sm; 1851e28a4053SRui Paulo return 1; 1852e28a4053SRui Paulo } 1853e28a4053SRui Paulo return 0; 1854e28a4053SRui Paulo } 1855e28a4053SRui Paulo 1856e28a4053SRui Paulo 1857e28a4053SRui Paulo static struct eapol_state_machine * 1858e28a4053SRui Paulo ieee802_1x_search_radius_identifier(struct hostapd_data *hapd, u8 identifier) 1859e28a4053SRui Paulo { 1860e28a4053SRui Paulo struct sta_id_search id_search; 1861*c1d255d3SCy Schubert 1862e28a4053SRui Paulo id_search.identifier = identifier; 1863e28a4053SRui Paulo id_search.sm = NULL; 1864e28a4053SRui Paulo ap_for_each_sta(hapd, ieee802_1x_select_radius_identifier, &id_search); 1865e28a4053SRui Paulo return id_search.sm; 1866e28a4053SRui Paulo } 1867e28a4053SRui Paulo 1868e28a4053SRui Paulo 18694bc52338SCy Schubert #ifndef CONFIG_NO_VLAN 18704bc52338SCy Schubert static int ieee802_1x_update_vlan(struct radius_msg *msg, 18714bc52338SCy Schubert struct hostapd_data *hapd, 18724bc52338SCy Schubert struct sta_info *sta) 18734bc52338SCy Schubert { 18744bc52338SCy Schubert struct vlan_description vlan_desc; 18754bc52338SCy Schubert 18764bc52338SCy Schubert os_memset(&vlan_desc, 0, sizeof(vlan_desc)); 18774bc52338SCy Schubert vlan_desc.notempty = !!radius_msg_get_vlanid(msg, &vlan_desc.untagged, 18784bc52338SCy Schubert MAX_NUM_TAGGED_VLAN, 18794bc52338SCy Schubert vlan_desc.tagged); 18804bc52338SCy Schubert 18814bc52338SCy Schubert if (vlan_desc.notempty && 18824bc52338SCy Schubert !hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) { 1883*c1d255d3SCy Schubert sta->eapol_sm->authFail = true; 18844bc52338SCy Schubert hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, 18854bc52338SCy Schubert HOSTAPD_LEVEL_INFO, 18864bc52338SCy Schubert "Invalid VLAN %d%s received from RADIUS server", 18874bc52338SCy Schubert vlan_desc.untagged, 18884bc52338SCy Schubert vlan_desc.tagged[0] ? "+" : ""); 18894bc52338SCy Schubert os_memset(&vlan_desc, 0, sizeof(vlan_desc)); 18904bc52338SCy Schubert ap_sta_set_vlan(hapd, sta, &vlan_desc); 18914bc52338SCy Schubert return -1; 18924bc52338SCy Schubert } 18934bc52338SCy Schubert 18944bc52338SCy Schubert if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED && 18954bc52338SCy Schubert !vlan_desc.notempty) { 1896*c1d255d3SCy Schubert sta->eapol_sm->authFail = true; 18974bc52338SCy Schubert hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 18984bc52338SCy Schubert HOSTAPD_LEVEL_INFO, 18994bc52338SCy Schubert "authentication server did not include required VLAN ID in Access-Accept"); 19004bc52338SCy Schubert return -1; 19014bc52338SCy Schubert } 19024bc52338SCy Schubert 19034bc52338SCy Schubert return ap_sta_set_vlan(hapd, sta, &vlan_desc); 19044bc52338SCy Schubert } 19054bc52338SCy Schubert #endif /* CONFIG_NO_VLAN */ 19064bc52338SCy Schubert 19074bc52338SCy Schubert 1908e28a4053SRui Paulo /** 1909e28a4053SRui Paulo * ieee802_1x_receive_auth - Process RADIUS frames from Authentication Server 1910e28a4053SRui Paulo * @msg: RADIUS response message 1911e28a4053SRui Paulo * @req: RADIUS request message 1912e28a4053SRui Paulo * @shared_secret: RADIUS shared secret 1913e28a4053SRui Paulo * @shared_secret_len: Length of shared_secret in octets 1914e28a4053SRui Paulo * @data: Context data (struct hostapd_data *) 1915e28a4053SRui Paulo * Returns: Processing status 1916e28a4053SRui Paulo */ 1917e28a4053SRui Paulo static RadiusRxResult 1918e28a4053SRui Paulo ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, 1919e28a4053SRui Paulo const u8 *shared_secret, size_t shared_secret_len, 1920e28a4053SRui Paulo void *data) 1921e28a4053SRui Paulo { 1922e28a4053SRui Paulo struct hostapd_data *hapd = data; 1923e28a4053SRui Paulo struct sta_info *sta; 1924e28a4053SRui Paulo u32 session_timeout = 0, termination_action, acct_interim_interval; 1925780fb4a2SCy Schubert int session_timeout_set; 192685732ac8SCy Schubert u32 reason_code; 1927e28a4053SRui Paulo struct eapol_state_machine *sm; 1928e28a4053SRui Paulo int override_eapReq = 0; 1929e28a4053SRui Paulo struct radius_hdr *hdr = radius_msg_get_hdr(msg); 1930e28a4053SRui Paulo 1931e28a4053SRui Paulo sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier); 1932*c1d255d3SCy Schubert if (!sm) { 1933*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1934*c1d255d3SCy Schubert "IEEE 802.1X: Could not find matching station for this RADIUS message"); 1935e28a4053SRui Paulo return RADIUS_RX_UNKNOWN; 1936e28a4053SRui Paulo } 1937e28a4053SRui Paulo sta = sm->sta; 1938e28a4053SRui Paulo 1939e28a4053SRui Paulo /* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be 1940e28a4053SRui Paulo * present when packet contains an EAP-Message attribute */ 1941e28a4053SRui Paulo if (hdr->code == RADIUS_CODE_ACCESS_REJECT && 1942e28a4053SRui Paulo radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL, 1943e28a4053SRui Paulo 0) < 0 && 1944e28a4053SRui Paulo radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) { 1945*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 1946*c1d255d3SCy Schubert "Allowing RADIUS Access-Reject without Message-Authenticator since it does not include EAP-Message"); 1947e28a4053SRui Paulo } else if (radius_msg_verify(msg, shared_secret, shared_secret_len, 1948e28a4053SRui Paulo req, 1)) { 1949*c1d255d3SCy Schubert wpa_printf(MSG_INFO, 1950*c1d255d3SCy Schubert "Incoming RADIUS packet did not have correct Message-Authenticator - dropped"); 1951e28a4053SRui Paulo return RADIUS_RX_INVALID_AUTHENTICATOR; 1952e28a4053SRui Paulo } 1953e28a4053SRui Paulo 1954e28a4053SRui Paulo if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT && 1955e28a4053SRui Paulo hdr->code != RADIUS_CODE_ACCESS_REJECT && 1956e28a4053SRui Paulo hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) { 19575b9c547cSRui Paulo wpa_printf(MSG_INFO, "Unknown RADIUS message code"); 1958e28a4053SRui Paulo return RADIUS_RX_UNKNOWN; 1959e28a4053SRui Paulo } 1960e28a4053SRui Paulo 1961e28a4053SRui Paulo sm->radius_identifier = -1; 1962e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "RADIUS packet matching with station " MACSTR, 1963e28a4053SRui Paulo MAC2STR(sta->addr)); 1964e28a4053SRui Paulo 1965e28a4053SRui Paulo radius_msg_free(sm->last_recv_radius); 1966e28a4053SRui Paulo sm->last_recv_radius = msg; 1967e28a4053SRui Paulo 1968e28a4053SRui Paulo session_timeout_set = 1969e28a4053SRui Paulo !radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT, 1970e28a4053SRui Paulo &session_timeout); 1971e28a4053SRui Paulo if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_TERMINATION_ACTION, 1972e28a4053SRui Paulo &termination_action)) 1973e28a4053SRui Paulo termination_action = RADIUS_TERMINATION_ACTION_DEFAULT; 1974e28a4053SRui Paulo 1975e28a4053SRui Paulo if (hapd->conf->acct_interim_interval == 0 && 1976e28a4053SRui Paulo hdr->code == RADIUS_CODE_ACCESS_ACCEPT && 1977e28a4053SRui Paulo radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL, 1978e28a4053SRui Paulo &acct_interim_interval) == 0) { 1979e28a4053SRui Paulo if (acct_interim_interval < 60) { 1980e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, 1981e28a4053SRui Paulo HOSTAPD_MODULE_IEEE8021X, 1982e28a4053SRui Paulo HOSTAPD_LEVEL_INFO, 1983*c1d255d3SCy Schubert "ignored too small Acct-Interim-Interval %d", 1984e28a4053SRui Paulo acct_interim_interval); 1985e28a4053SRui Paulo } else 1986e28a4053SRui Paulo sta->acct_interim_interval = acct_interim_interval; 1987e28a4053SRui Paulo } 1988e28a4053SRui Paulo 1989e28a4053SRui Paulo 1990e28a4053SRui Paulo switch (hdr->code) { 1991e28a4053SRui Paulo case RADIUS_CODE_ACCESS_ACCEPT: 1992e28a4053SRui Paulo #ifndef CONFIG_NO_VLAN 19934bc52338SCy Schubert if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED && 19944bc52338SCy Schubert ieee802_1x_update_vlan(msg, hapd, sta) < 0) 1995780fb4a2SCy Schubert break; 1996780fb4a2SCy Schubert 1997780fb4a2SCy Schubert if (sta->vlan_id > 0) { 1998780fb4a2SCy Schubert hostapd_logger(hapd, sta->addr, 1999780fb4a2SCy Schubert HOSTAPD_MODULE_RADIUS, 2000780fb4a2SCy Schubert HOSTAPD_LEVEL_INFO, 2001780fb4a2SCy Schubert "VLAN ID %d", sta->vlan_id); 2002780fb4a2SCy Schubert } 2003780fb4a2SCy Schubert 2004325151a3SRui Paulo if ((sta->flags & WLAN_STA_ASSOC) && 2005325151a3SRui Paulo ap_sta_bind_vlan(hapd, sta) < 0) 2006e28a4053SRui Paulo break; 20074bc52338SCy Schubert #endif /* CONFIG_NO_VLAN */ 2008e28a4053SRui Paulo 20095b9c547cSRui Paulo sta->session_timeout_set = !!session_timeout_set; 201085732ac8SCy Schubert os_get_reltime(&sta->session_timeout); 201185732ac8SCy Schubert sta->session_timeout.sec += session_timeout; 20125b9c547cSRui Paulo 2013e28a4053SRui Paulo /* RFC 3580, Ch. 3.17 */ 2014e28a4053SRui Paulo if (session_timeout_set && termination_action == 201585732ac8SCy Schubert RADIUS_TERMINATION_ACTION_RADIUS_REQUEST) 2016e28a4053SRui Paulo sm->reAuthPeriod = session_timeout; 201785732ac8SCy Schubert else if (session_timeout_set) 2018e28a4053SRui Paulo ap_sta_session_timeout(hapd, sta, session_timeout); 201985732ac8SCy Schubert else 202085732ac8SCy Schubert ap_sta_no_session_timeout(hapd, sta); 2021e28a4053SRui Paulo 2022*c1d255d3SCy Schubert sm->eap_if->aaaSuccess = true; 2023e28a4053SRui Paulo override_eapReq = 1; 2024e28a4053SRui Paulo ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret, 2025e28a4053SRui Paulo shared_secret_len); 2026e28a4053SRui Paulo ieee802_1x_store_radius_class(hapd, sta, msg); 2027e28a4053SRui Paulo ieee802_1x_update_sta_identity(hapd, sta, msg); 2028f05cddf9SRui Paulo ieee802_1x_update_sta_cui(hapd, sta, msg); 20295b9c547cSRui Paulo ieee802_1x_check_hs20(hapd, sta, msg, 20305b9c547cSRui Paulo session_timeout_set ? 20315b9c547cSRui Paulo (int) session_timeout : -1); 2032e28a4053SRui Paulo break; 2033e28a4053SRui Paulo case RADIUS_CODE_ACCESS_REJECT: 2034*c1d255d3SCy Schubert sm->eap_if->aaaFail = true; 2035e28a4053SRui Paulo override_eapReq = 1; 203685732ac8SCy Schubert if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_WLAN_REASON_CODE, 203785732ac8SCy Schubert &reason_code) == 0) { 203885732ac8SCy Schubert wpa_printf(MSG_DEBUG, 203985732ac8SCy Schubert "RADIUS server indicated WLAN-Reason-Code %u in Access-Reject for " 204085732ac8SCy Schubert MACSTR, reason_code, MAC2STR(sta->addr)); 204185732ac8SCy Schubert sta->disconnect_reason_code = reason_code; 204285732ac8SCy Schubert } 2043e28a4053SRui Paulo break; 2044e28a4053SRui Paulo case RADIUS_CODE_ACCESS_CHALLENGE: 2045*c1d255d3SCy Schubert sm->eap_if->aaaEapReq = true; 2046e28a4053SRui Paulo if (session_timeout_set) { 2047e28a4053SRui Paulo /* RFC 2869, Ch. 2.3.2; RFC 3580, Ch. 3.17 */ 2048e28a4053SRui Paulo sm->eap_if->aaaMethodTimeout = session_timeout; 2049e28a4053SRui Paulo hostapd_logger(hapd, sm->addr, 2050e28a4053SRui Paulo HOSTAPD_MODULE_IEEE8021X, 2051e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, 2052*c1d255d3SCy Schubert "using EAP timeout of %d seconds (from RADIUS)", 2053e28a4053SRui Paulo sm->eap_if->aaaMethodTimeout); 2054e28a4053SRui Paulo } else { 2055e28a4053SRui Paulo /* 2056e28a4053SRui Paulo * Use dynamic retransmission behavior per EAP 2057e28a4053SRui Paulo * specification. 2058e28a4053SRui Paulo */ 2059e28a4053SRui Paulo sm->eap_if->aaaMethodTimeout = 0; 2060e28a4053SRui Paulo } 2061e28a4053SRui Paulo break; 2062e28a4053SRui Paulo } 2063e28a4053SRui Paulo 2064e28a4053SRui Paulo ieee802_1x_decapsulate_radius(hapd, sta); 2065e28a4053SRui Paulo if (override_eapReq) 2066*c1d255d3SCy Schubert sm->eap_if->aaaEapReq = false; 2067e28a4053SRui Paulo 206885732ac8SCy Schubert #ifdef CONFIG_FILS 206985732ac8SCy Schubert #ifdef NEED_AP_MLME 2070*c1d255d3SCy Schubert if (sta->flags & 2071*c1d255d3SCy Schubert (WLAN_STA_PENDING_FILS_ERP | WLAN_STA_PENDING_PASN_FILS_ERP)) { 207285732ac8SCy Schubert /* TODO: Add a PMKSA entry on success? */ 207385732ac8SCy Schubert ieee802_11_finish_fils_auth( 207485732ac8SCy Schubert hapd, sta, hdr->code == RADIUS_CODE_ACCESS_ACCEPT, 207585732ac8SCy Schubert sm->eap_if->aaaEapReqData, 207685732ac8SCy Schubert sm->eap_if->aaaEapKeyData, 207785732ac8SCy Schubert sm->eap_if->aaaEapKeyDataLen); 207885732ac8SCy Schubert } 207985732ac8SCy Schubert #endif /* NEED_AP_MLME */ 208085732ac8SCy Schubert #endif /* CONFIG_FILS */ 208185732ac8SCy Schubert 2082e28a4053SRui Paulo eapol_auth_step(sm); 2083e28a4053SRui Paulo 2084e28a4053SRui Paulo return RADIUS_RX_QUEUED; 2085e28a4053SRui Paulo } 2086e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */ 2087e28a4053SRui Paulo 2088e28a4053SRui Paulo 2089e28a4053SRui Paulo void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta) 2090e28a4053SRui Paulo { 2091e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 2092*c1d255d3SCy Schubert 2093*c1d255d3SCy Schubert if (!sm) 2094e28a4053SRui Paulo return; 2095e28a4053SRui Paulo 2096e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 2097e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, "aborting authentication"); 2098e28a4053SRui Paulo 2099e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS 2100e28a4053SRui Paulo radius_msg_free(sm->last_recv_radius); 2101e28a4053SRui Paulo sm->last_recv_radius = NULL; 2102e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */ 2103e28a4053SRui Paulo 2104e28a4053SRui Paulo if (sm->eap_if->eapTimeout) { 2105e28a4053SRui Paulo /* 2106e28a4053SRui Paulo * Disconnect the STA since it did not reply to the last EAP 2107e28a4053SRui Paulo * request and we cannot continue EAP processing (EAP-Failure 2108e28a4053SRui Paulo * could only be sent if the EAP peer actually replied). 2109e28a4053SRui Paulo */ 2110f05cddf9SRui Paulo wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "EAP Timeout, STA " MACSTR, 2111f05cddf9SRui Paulo MAC2STR(sta->addr)); 2112f05cddf9SRui Paulo 2113*c1d255d3SCy Schubert sm->eap_if->portEnabled = false; 2114e28a4053SRui Paulo ap_sta_disconnect(hapd, sta, sta->addr, 2115e28a4053SRui Paulo WLAN_REASON_PREV_AUTH_NOT_VALID); 2116e28a4053SRui Paulo } 2117e28a4053SRui Paulo } 2118e28a4053SRui Paulo 2119e28a4053SRui Paulo 2120*c1d255d3SCy Schubert #ifdef CONFIG_WEP 2121*c1d255d3SCy Schubert 2122e28a4053SRui Paulo static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd) 2123e28a4053SRui Paulo { 2124e28a4053SRui Paulo struct eapol_authenticator *eapol = hapd->eapol_auth; 2125e28a4053SRui Paulo 2126e28a4053SRui Paulo if (hapd->conf->default_wep_key_len < 1) 2127e28a4053SRui Paulo return 0; 2128e28a4053SRui Paulo 2129e28a4053SRui Paulo os_free(eapol->default_wep_key); 2130e28a4053SRui Paulo eapol->default_wep_key = os_malloc(hapd->conf->default_wep_key_len); 2131*c1d255d3SCy Schubert if (!eapol->default_wep_key || 2132f05cddf9SRui Paulo random_get_bytes(eapol->default_wep_key, 2133e28a4053SRui Paulo hapd->conf->default_wep_key_len)) { 21345b9c547cSRui Paulo wpa_printf(MSG_INFO, "Could not generate random WEP key"); 2135e28a4053SRui Paulo os_free(eapol->default_wep_key); 2136e28a4053SRui Paulo eapol->default_wep_key = NULL; 2137e28a4053SRui Paulo return -1; 2138e28a4053SRui Paulo } 2139e28a4053SRui Paulo 2140e28a4053SRui Paulo wpa_hexdump_key(MSG_DEBUG, "IEEE 802.1X: New default WEP key", 2141e28a4053SRui Paulo eapol->default_wep_key, 2142e28a4053SRui Paulo hapd->conf->default_wep_key_len); 2143e28a4053SRui Paulo 2144e28a4053SRui Paulo return 0; 2145e28a4053SRui Paulo } 2146e28a4053SRui Paulo 2147e28a4053SRui Paulo 2148e28a4053SRui Paulo static int ieee802_1x_sta_key_available(struct hostapd_data *hapd, 2149e28a4053SRui Paulo struct sta_info *sta, void *ctx) 2150e28a4053SRui Paulo { 2151e28a4053SRui Paulo if (sta->eapol_sm) { 2152*c1d255d3SCy Schubert sta->eapol_sm->eap_if->eapKeyAvailable = true; 2153e28a4053SRui Paulo eapol_auth_step(sta->eapol_sm); 2154e28a4053SRui Paulo } 2155e28a4053SRui Paulo return 0; 2156e28a4053SRui Paulo } 2157e28a4053SRui Paulo 2158e28a4053SRui Paulo 2159e28a4053SRui Paulo static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx) 2160e28a4053SRui Paulo { 2161e28a4053SRui Paulo struct hostapd_data *hapd = eloop_ctx; 2162e28a4053SRui Paulo struct eapol_authenticator *eapol = hapd->eapol_auth; 2163e28a4053SRui Paulo 2164e28a4053SRui Paulo if (eapol->default_wep_key_idx >= 3) 2165e28a4053SRui Paulo eapol->default_wep_key_idx = 2166e28a4053SRui Paulo hapd->conf->individual_wep_key_len > 0 ? 1 : 0; 2167e28a4053SRui Paulo else 2168e28a4053SRui Paulo eapol->default_wep_key_idx++; 2169e28a4053SRui Paulo 2170e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "IEEE 802.1X: New default WEP key index %d", 2171e28a4053SRui Paulo eapol->default_wep_key_idx); 2172e28a4053SRui Paulo 2173e28a4053SRui Paulo if (ieee802_1x_rekey_broadcast(hapd)) { 2174e28a4053SRui Paulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X, 2175*c1d255d3SCy Schubert HOSTAPD_LEVEL_WARNING, 2176*c1d255d3SCy Schubert "failed to generate a new broadcast key"); 2177e28a4053SRui Paulo os_free(eapol->default_wep_key); 2178e28a4053SRui Paulo eapol->default_wep_key = NULL; 2179e28a4053SRui Paulo return; 2180e28a4053SRui Paulo } 2181e28a4053SRui Paulo 2182e28a4053SRui Paulo /* TODO: Could setup key for RX here, but change default TX keyid only 2183e28a4053SRui Paulo * after new broadcast key has been sent to all stations. */ 2184f05cddf9SRui Paulo if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, 2185f05cddf9SRui Paulo broadcast_ether_addr, 2186*c1d255d3SCy Schubert eapol->default_wep_key_idx, 0, 1, NULL, 0, 2187e28a4053SRui Paulo eapol->default_wep_key, 2188*c1d255d3SCy Schubert hapd->conf->default_wep_key_len, 2189*c1d255d3SCy Schubert KEY_FLAG_GROUP_RX_TX_DEFAULT)) { 2190e28a4053SRui Paulo hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X, 2191*c1d255d3SCy Schubert HOSTAPD_LEVEL_WARNING, 2192*c1d255d3SCy Schubert "failed to configure a new broadcast key"); 2193e28a4053SRui Paulo os_free(eapol->default_wep_key); 2194e28a4053SRui Paulo eapol->default_wep_key = NULL; 2195e28a4053SRui Paulo return; 2196e28a4053SRui Paulo } 2197e28a4053SRui Paulo 2198e28a4053SRui Paulo ap_for_each_sta(hapd, ieee802_1x_sta_key_available, NULL); 2199e28a4053SRui Paulo 2200e28a4053SRui Paulo if (hapd->conf->wep_rekeying_period > 0) { 2201e28a4053SRui Paulo eloop_register_timeout(hapd->conf->wep_rekeying_period, 0, 2202e28a4053SRui Paulo ieee802_1x_rekey, hapd, NULL); 2203e28a4053SRui Paulo } 2204e28a4053SRui Paulo } 2205e28a4053SRui Paulo 2206*c1d255d3SCy Schubert #endif /* CONFIG_WEP */ 2207*c1d255d3SCy Schubert 2208e28a4053SRui Paulo 2209e28a4053SRui Paulo static void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type, 2210e28a4053SRui Paulo const u8 *data, size_t datalen) 2211e28a4053SRui Paulo { 2212e28a4053SRui Paulo #ifdef CONFIG_WPS 2213e28a4053SRui Paulo struct sta_info *sta = sta_ctx; 2214e28a4053SRui Paulo 2215e28a4053SRui Paulo if ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) == 2216e28a4053SRui Paulo WLAN_STA_MAYBE_WPS) { 2217e28a4053SRui Paulo const u8 *identity; 2218e28a4053SRui Paulo size_t identity_len; 2219e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 2220e28a4053SRui Paulo 2221e28a4053SRui Paulo identity = eap_get_identity(sm->eap, &identity_len); 2222e28a4053SRui Paulo if (identity && 2223e28a4053SRui Paulo ((identity_len == WSC_ID_ENROLLEE_LEN && 2224e28a4053SRui Paulo os_memcmp(identity, WSC_ID_ENROLLEE, 2225e28a4053SRui Paulo WSC_ID_ENROLLEE_LEN) == 0) || 2226e28a4053SRui Paulo (identity_len == WSC_ID_REGISTRAR_LEN && 2227e28a4053SRui Paulo os_memcmp(identity, WSC_ID_REGISTRAR, 2228e28a4053SRui Paulo WSC_ID_REGISTRAR_LEN) == 0))) { 2229*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, 2230*c1d255d3SCy Schubert "WPS: WLAN_STA_MAYBE_WPS -> WLAN_STA_WPS"); 2231e28a4053SRui Paulo sta->flags |= WLAN_STA_WPS; 2232e28a4053SRui Paulo } 2233e28a4053SRui Paulo } 2234e28a4053SRui Paulo #endif /* CONFIG_WPS */ 2235e28a4053SRui Paulo 2236e28a4053SRui Paulo ieee802_1x_send(ctx, sta_ctx, type, data, datalen); 2237e28a4053SRui Paulo } 2238e28a4053SRui Paulo 2239e28a4053SRui Paulo 2240e28a4053SRui Paulo static void ieee802_1x_aaa_send(void *ctx, void *sta_ctx, 2241e28a4053SRui Paulo const u8 *data, size_t datalen) 2242e28a4053SRui Paulo { 2243e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS 2244e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 2245e28a4053SRui Paulo struct sta_info *sta = sta_ctx; 2246e28a4053SRui Paulo 2247e28a4053SRui Paulo ieee802_1x_encapsulate_radius(hapd, sta, data, datalen); 2248e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */ 2249e28a4053SRui Paulo } 2250e28a4053SRui Paulo 2251e28a4053SRui Paulo 2252e28a4053SRui Paulo static void _ieee802_1x_finished(void *ctx, void *sta_ctx, int success, 22535b9c547cSRui Paulo int preauth, int remediation) 2254e28a4053SRui Paulo { 2255e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 2256e28a4053SRui Paulo struct sta_info *sta = sta_ctx; 2257*c1d255d3SCy Schubert 2258e28a4053SRui Paulo if (preauth) 2259e28a4053SRui Paulo rsn_preauth_finished(hapd, sta, success); 2260e28a4053SRui Paulo else 22615b9c547cSRui Paulo ieee802_1x_finished(hapd, sta, success, remediation); 2262e28a4053SRui Paulo } 2263e28a4053SRui Paulo 2264e28a4053SRui Paulo 2265e28a4053SRui Paulo static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity, 2266e28a4053SRui Paulo size_t identity_len, int phase2, 2267e28a4053SRui Paulo struct eap_user *user) 2268e28a4053SRui Paulo { 2269e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 2270e28a4053SRui Paulo const struct hostapd_eap_user *eap_user; 2271f05cddf9SRui Paulo int i; 2272325151a3SRui Paulo int rv = -1; 2273e28a4053SRui Paulo 2274f05cddf9SRui Paulo eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2); 2275*c1d255d3SCy Schubert if (!eap_user) 2276325151a3SRui Paulo goto out; 2277e28a4053SRui Paulo 2278e28a4053SRui Paulo os_memset(user, 0, sizeof(*user)); 2279e28a4053SRui Paulo user->phase2 = phase2; 2280f05cddf9SRui Paulo for (i = 0; i < EAP_MAX_METHODS; i++) { 2281e28a4053SRui Paulo user->methods[i].vendor = eap_user->methods[i].vendor; 2282e28a4053SRui Paulo user->methods[i].method = eap_user->methods[i].method; 2283e28a4053SRui Paulo } 2284e28a4053SRui Paulo 2285e28a4053SRui Paulo if (eap_user->password) { 228685732ac8SCy Schubert user->password = os_memdup(eap_user->password, 228785732ac8SCy Schubert eap_user->password_len); 2288*c1d255d3SCy Schubert if (!user->password) 2289325151a3SRui Paulo goto out; 2290e28a4053SRui Paulo user->password_len = eap_user->password_len; 2291f05cddf9SRui Paulo user->password_hash = eap_user->password_hash; 229285732ac8SCy Schubert if (eap_user->salt && eap_user->salt_len) { 229385732ac8SCy Schubert user->salt = os_memdup(eap_user->salt, 229485732ac8SCy Schubert eap_user->salt_len); 229585732ac8SCy Schubert if (!user->salt) 229685732ac8SCy Schubert goto out; 229785732ac8SCy Schubert user->salt_len = eap_user->salt_len; 229885732ac8SCy Schubert } 2299e28a4053SRui Paulo } 2300e28a4053SRui Paulo user->force_version = eap_user->force_version; 23015b9c547cSRui Paulo user->macacl = eap_user->macacl; 2302e28a4053SRui Paulo user->ttls_auth = eap_user->ttls_auth; 23035b9c547cSRui Paulo user->remediation = eap_user->remediation; 2304325151a3SRui Paulo rv = 0; 2305e28a4053SRui Paulo 2306325151a3SRui Paulo out: 2307325151a3SRui Paulo if (rv) 2308325151a3SRui Paulo wpa_printf(MSG_DEBUG, "%s: Failed to find user", __func__); 2309325151a3SRui Paulo 2310325151a3SRui Paulo return rv; 2311e28a4053SRui Paulo } 2312e28a4053SRui Paulo 2313e28a4053SRui Paulo 2314e28a4053SRui Paulo static int ieee802_1x_sta_entry_alive(void *ctx, const u8 *addr) 2315e28a4053SRui Paulo { 2316e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 2317e28a4053SRui Paulo struct sta_info *sta; 2318*c1d255d3SCy Schubert 2319e28a4053SRui Paulo sta = ap_get_sta(hapd, addr); 2320*c1d255d3SCy Schubert if (!sta || !sta->eapol_sm) 2321e28a4053SRui Paulo return 0; 2322e28a4053SRui Paulo return 1; 2323e28a4053SRui Paulo } 2324e28a4053SRui Paulo 2325e28a4053SRui Paulo 2326e28a4053SRui Paulo static void ieee802_1x_logger(void *ctx, const u8 *addr, 2327e28a4053SRui Paulo eapol_logger_level level, const char *txt) 2328e28a4053SRui Paulo { 2329e28a4053SRui Paulo #ifndef CONFIG_NO_HOSTAPD_LOGGER 2330e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 2331e28a4053SRui Paulo int hlevel; 2332e28a4053SRui Paulo 2333e28a4053SRui Paulo switch (level) { 2334e28a4053SRui Paulo case EAPOL_LOGGER_WARNING: 2335e28a4053SRui Paulo hlevel = HOSTAPD_LEVEL_WARNING; 2336e28a4053SRui Paulo break; 2337e28a4053SRui Paulo case EAPOL_LOGGER_INFO: 2338e28a4053SRui Paulo hlevel = HOSTAPD_LEVEL_INFO; 2339e28a4053SRui Paulo break; 2340e28a4053SRui Paulo case EAPOL_LOGGER_DEBUG: 2341e28a4053SRui Paulo default: 2342e28a4053SRui Paulo hlevel = HOSTAPD_LEVEL_DEBUG; 2343e28a4053SRui Paulo break; 2344e28a4053SRui Paulo } 2345e28a4053SRui Paulo 2346e28a4053SRui Paulo hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE8021X, hlevel, "%s", 2347e28a4053SRui Paulo txt); 2348e28a4053SRui Paulo #endif /* CONFIG_NO_HOSTAPD_LOGGER */ 2349e28a4053SRui Paulo } 2350e28a4053SRui Paulo 2351e28a4053SRui Paulo 2352e28a4053SRui Paulo static void ieee802_1x_set_port_authorized(void *ctx, void *sta_ctx, 2353e28a4053SRui Paulo int authorized) 2354e28a4053SRui Paulo { 2355e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 2356e28a4053SRui Paulo struct sta_info *sta = sta_ctx; 2357*c1d255d3SCy Schubert 2358e28a4053SRui Paulo ieee802_1x_set_sta_authorized(hapd, sta, authorized); 2359e28a4053SRui Paulo } 2360e28a4053SRui Paulo 2361e28a4053SRui Paulo 2362e28a4053SRui Paulo static void _ieee802_1x_abort_auth(void *ctx, void *sta_ctx) 2363e28a4053SRui Paulo { 2364e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 2365e28a4053SRui Paulo struct sta_info *sta = sta_ctx; 2366*c1d255d3SCy Schubert 2367e28a4053SRui Paulo ieee802_1x_abort_auth(hapd, sta); 2368e28a4053SRui Paulo } 2369e28a4053SRui Paulo 2370e28a4053SRui Paulo 2371*c1d255d3SCy Schubert #ifdef CONFIG_WEP 2372e28a4053SRui Paulo static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx) 2373e28a4053SRui Paulo { 2374325151a3SRui Paulo #ifndef CONFIG_FIPS 2375325151a3SRui Paulo #ifndef CONFIG_NO_RC4 2376e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 2377e28a4053SRui Paulo struct sta_info *sta = sta_ctx; 2378*c1d255d3SCy Schubert 2379e28a4053SRui Paulo ieee802_1x_tx_key(hapd, sta); 2380325151a3SRui Paulo #endif /* CONFIG_NO_RC4 */ 2381325151a3SRui Paulo #endif /* CONFIG_FIPS */ 2382e28a4053SRui Paulo } 2383*c1d255d3SCy Schubert #endif /* CONFIG_WEP */ 2384e28a4053SRui Paulo 2385e28a4053SRui Paulo 2386e28a4053SRui Paulo static void ieee802_1x_eapol_event(void *ctx, void *sta_ctx, 2387e28a4053SRui Paulo enum eapol_event type) 2388e28a4053SRui Paulo { 2389e28a4053SRui Paulo /* struct hostapd_data *hapd = ctx; */ 2390e28a4053SRui Paulo struct sta_info *sta = sta_ctx; 2391*c1d255d3SCy Schubert 2392e28a4053SRui Paulo switch (type) { 2393e28a4053SRui Paulo case EAPOL_AUTH_SM_CHANGE: 2394e28a4053SRui Paulo wpa_auth_sm_notify(sta->wpa_sm); 2395e28a4053SRui Paulo break; 2396e28a4053SRui Paulo case EAPOL_AUTH_REAUTHENTICATE: 2397e28a4053SRui Paulo wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL); 2398e28a4053SRui Paulo break; 2399e28a4053SRui Paulo } 2400e28a4053SRui Paulo } 2401e28a4053SRui Paulo 2402e28a4053SRui Paulo 24035b9c547cSRui Paulo #ifdef CONFIG_ERP 24045b9c547cSRui Paulo 24055b9c547cSRui Paulo static struct eap_server_erp_key * 24065b9c547cSRui Paulo ieee802_1x_erp_get_key(void *ctx, const char *keyname) 24075b9c547cSRui Paulo { 24085b9c547cSRui Paulo struct hostapd_data *hapd = ctx; 24095b9c547cSRui Paulo struct eap_server_erp_key *erp; 24105b9c547cSRui Paulo 24115b9c547cSRui Paulo dl_list_for_each(erp, &hapd->erp_keys, struct eap_server_erp_key, 24125b9c547cSRui Paulo list) { 24135b9c547cSRui Paulo if (os_strcmp(erp->keyname_nai, keyname) == 0) 24145b9c547cSRui Paulo return erp; 24155b9c547cSRui Paulo } 24165b9c547cSRui Paulo 24175b9c547cSRui Paulo return NULL; 24185b9c547cSRui Paulo } 24195b9c547cSRui Paulo 24205b9c547cSRui Paulo 24215b9c547cSRui Paulo static int ieee802_1x_erp_add_key(void *ctx, struct eap_server_erp_key *erp) 24225b9c547cSRui Paulo { 24235b9c547cSRui Paulo struct hostapd_data *hapd = ctx; 24245b9c547cSRui Paulo 24255b9c547cSRui Paulo dl_list_add(&hapd->erp_keys, &erp->list); 24265b9c547cSRui Paulo return 0; 24275b9c547cSRui Paulo } 24285b9c547cSRui Paulo 24295b9c547cSRui Paulo #endif /* CONFIG_ERP */ 24305b9c547cSRui Paulo 24315b9c547cSRui Paulo 2432e28a4053SRui Paulo int ieee802_1x_init(struct hostapd_data *hapd) 2433e28a4053SRui Paulo { 2434e28a4053SRui Paulo struct eapol_auth_config conf; 2435e28a4053SRui Paulo struct eapol_auth_cb cb; 2436e28a4053SRui Paulo 24375b9c547cSRui Paulo dl_list_init(&hapd->erp_keys); 24385b9c547cSRui Paulo 2439e28a4053SRui Paulo os_memset(&conf, 0, sizeof(conf)); 2440*c1d255d3SCy Schubert conf.eap_cfg = hapd->eap_cfg; 2441e28a4053SRui Paulo conf.ctx = hapd; 2442e28a4053SRui Paulo conf.eap_reauth_period = hapd->conf->eap_reauth_period; 2443e28a4053SRui Paulo conf.wpa = hapd->conf->wpa; 2444*c1d255d3SCy Schubert #ifdef CONFIG_WEP 2445e28a4053SRui Paulo conf.individual_wep_key_len = hapd->conf->individual_wep_key_len; 2446*c1d255d3SCy Schubert #endif /* CONFIG_WEP */ 2447e28a4053SRui Paulo conf.eap_req_id_text = hapd->conf->eap_req_id_text; 2448e28a4053SRui Paulo conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len; 24495b9c547cSRui Paulo conf.erp_send_reauth_start = hapd->conf->erp_send_reauth_start; 24505b9c547cSRui Paulo conf.erp_domain = hapd->conf->erp_domain; 2451e28a4053SRui Paulo 2452e28a4053SRui Paulo os_memset(&cb, 0, sizeof(cb)); 2453e28a4053SRui Paulo cb.eapol_send = ieee802_1x_eapol_send; 2454e28a4053SRui Paulo cb.aaa_send = ieee802_1x_aaa_send; 2455e28a4053SRui Paulo cb.finished = _ieee802_1x_finished; 2456e28a4053SRui Paulo cb.get_eap_user = ieee802_1x_get_eap_user; 2457e28a4053SRui Paulo cb.sta_entry_alive = ieee802_1x_sta_entry_alive; 2458e28a4053SRui Paulo cb.logger = ieee802_1x_logger; 2459e28a4053SRui Paulo cb.set_port_authorized = ieee802_1x_set_port_authorized; 2460e28a4053SRui Paulo cb.abort_auth = _ieee802_1x_abort_auth; 2461*c1d255d3SCy Schubert #ifdef CONFIG_WEP 2462e28a4053SRui Paulo cb.tx_key = _ieee802_1x_tx_key; 2463*c1d255d3SCy Schubert #endif /* CONFIG_WEP */ 2464e28a4053SRui Paulo cb.eapol_event = ieee802_1x_eapol_event; 24655b9c547cSRui Paulo #ifdef CONFIG_ERP 24665b9c547cSRui Paulo cb.erp_get_key = ieee802_1x_erp_get_key; 24675b9c547cSRui Paulo cb.erp_add_key = ieee802_1x_erp_add_key; 24685b9c547cSRui Paulo #endif /* CONFIG_ERP */ 2469e28a4053SRui Paulo 2470e28a4053SRui Paulo hapd->eapol_auth = eapol_auth_init(&conf, &cb); 2471*c1d255d3SCy Schubert if (!hapd->eapol_auth) 2472e28a4053SRui Paulo return -1; 2473e28a4053SRui Paulo 2474e28a4053SRui Paulo if ((hapd->conf->ieee802_1x || hapd->conf->wpa) && 2475f05cddf9SRui Paulo hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1)) 2476e28a4053SRui Paulo return -1; 2477e28a4053SRui Paulo 2478e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS 2479e28a4053SRui Paulo if (radius_client_register(hapd->radius, RADIUS_AUTH, 2480e28a4053SRui Paulo ieee802_1x_receive_auth, hapd)) 2481e28a4053SRui Paulo return -1; 2482e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */ 2483e28a4053SRui Paulo 2484*c1d255d3SCy Schubert #ifdef CONFIG_WEP 2485e28a4053SRui Paulo if (hapd->conf->default_wep_key_len) { 2486*c1d255d3SCy Schubert int i; 2487*c1d255d3SCy Schubert 2488e28a4053SRui Paulo for (i = 0; i < 4; i++) 2489f05cddf9SRui Paulo hostapd_drv_set_key(hapd->conf->iface, hapd, 2490*c1d255d3SCy Schubert WPA_ALG_NONE, NULL, i, 0, 0, NULL, 2491*c1d255d3SCy Schubert 0, NULL, 0, KEY_FLAG_GROUP); 2492e28a4053SRui Paulo 2493e28a4053SRui Paulo ieee802_1x_rekey(hapd, NULL); 2494e28a4053SRui Paulo 2495*c1d255d3SCy Schubert if (!hapd->eapol_auth->default_wep_key) 2496e28a4053SRui Paulo return -1; 2497e28a4053SRui Paulo } 2498*c1d255d3SCy Schubert #endif /* CONFIG_WEP */ 2499e28a4053SRui Paulo 2500e28a4053SRui Paulo return 0; 2501e28a4053SRui Paulo } 2502e28a4053SRui Paulo 2503e28a4053SRui Paulo 25045b9c547cSRui Paulo void ieee802_1x_erp_flush(struct hostapd_data *hapd) 25055b9c547cSRui Paulo { 25065b9c547cSRui Paulo struct eap_server_erp_key *erp; 25075b9c547cSRui Paulo 25085b9c547cSRui Paulo while ((erp = dl_list_first(&hapd->erp_keys, struct eap_server_erp_key, 25095b9c547cSRui Paulo list)) != NULL) { 25105b9c547cSRui Paulo dl_list_del(&erp->list); 25115b9c547cSRui Paulo bin_clear_free(erp, sizeof(*erp)); 25125b9c547cSRui Paulo } 25135b9c547cSRui Paulo } 25145b9c547cSRui Paulo 25155b9c547cSRui Paulo 2516e28a4053SRui Paulo void ieee802_1x_deinit(struct hostapd_data *hapd) 2517e28a4053SRui Paulo { 2518*c1d255d3SCy Schubert #ifdef CONFIG_WEP 2519e28a4053SRui Paulo eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL); 2520*c1d255d3SCy Schubert #endif /* CONFIG_WEP */ 2521e28a4053SRui Paulo 2522780fb4a2SCy Schubert if (hapd->driver && hapd->drv_priv && 2523e28a4053SRui Paulo (hapd->conf->ieee802_1x || hapd->conf->wpa)) 2524f05cddf9SRui Paulo hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0); 2525e28a4053SRui Paulo 2526e28a4053SRui Paulo eapol_auth_deinit(hapd->eapol_auth); 2527e28a4053SRui Paulo hapd->eapol_auth = NULL; 25285b9c547cSRui Paulo 25295b9c547cSRui Paulo ieee802_1x_erp_flush(hapd); 2530e28a4053SRui Paulo } 2531e28a4053SRui Paulo 2532e28a4053SRui Paulo 2533e28a4053SRui Paulo int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta, 2534e28a4053SRui Paulo const u8 *buf, size_t len, int ack) 2535e28a4053SRui Paulo { 2536e28a4053SRui Paulo struct ieee80211_hdr *hdr; 2537e28a4053SRui Paulo u8 *pos; 2538e28a4053SRui Paulo const unsigned char rfc1042_hdr[ETH_ALEN] = 2539e28a4053SRui Paulo { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; 2540e28a4053SRui Paulo 2541*c1d255d3SCy Schubert if (!sta) 2542e28a4053SRui Paulo return -1; 2543f05cddf9SRui Paulo if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2) 2544e28a4053SRui Paulo return 0; 2545e28a4053SRui Paulo 2546e28a4053SRui Paulo hdr = (struct ieee80211_hdr *) buf; 2547e28a4053SRui Paulo pos = (u8 *) (hdr + 1); 2548e28a4053SRui Paulo if (os_memcmp(pos, rfc1042_hdr, sizeof(rfc1042_hdr)) != 0) 2549e28a4053SRui Paulo return 0; 2550e28a4053SRui Paulo pos += sizeof(rfc1042_hdr); 2551e28a4053SRui Paulo if (WPA_GET_BE16(pos) != ETH_P_PAE) 2552e28a4053SRui Paulo return 0; 2553e28a4053SRui Paulo pos += 2; 2554e28a4053SRui Paulo 2555f05cddf9SRui Paulo return ieee802_1x_eapol_tx_status(hapd, sta, pos, buf + len - pos, 2556f05cddf9SRui Paulo ack); 2557f05cddf9SRui Paulo } 2558e28a4053SRui Paulo 2559f05cddf9SRui Paulo 2560f05cddf9SRui Paulo int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta, 2561f05cddf9SRui Paulo const u8 *buf, int len, int ack) 2562f05cddf9SRui Paulo { 2563f05cddf9SRui Paulo const struct ieee802_1x_hdr *xhdr = 2564f05cddf9SRui Paulo (const struct ieee802_1x_hdr *) buf; 2565f05cddf9SRui Paulo const u8 *pos = buf + sizeof(*xhdr); 2566f05cddf9SRui Paulo struct ieee802_1x_eapol_key *key; 2567f05cddf9SRui Paulo 2568f05cddf9SRui Paulo if (len < (int) sizeof(*xhdr)) 2569f05cddf9SRui Paulo return 0; 2570*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR 2571*c1d255d3SCy Schubert " TX status - version=%d type=%d length=%d - ack=%d", 2572e28a4053SRui Paulo MAC2STR(sta->addr), xhdr->version, xhdr->type, 2573e28a4053SRui Paulo be_to_host16(xhdr->length), ack); 2574e28a4053SRui Paulo 257585732ac8SCy Schubert #ifdef CONFIG_WPS 257685732ac8SCy Schubert if (xhdr->type == IEEE802_1X_TYPE_EAP_PACKET && ack && 257785732ac8SCy Schubert (sta->flags & WLAN_STA_WPS) && 257885732ac8SCy Schubert ap_sta_pending_delayed_1x_auth_fail_disconnect(hapd, sta)) { 257985732ac8SCy Schubert wpa_printf(MSG_DEBUG, 258085732ac8SCy Schubert "WPS: Indicate EAP completion on ACK for EAP-Failure"); 258185732ac8SCy Schubert hostapd_wps_eap_completed(hapd); 258285732ac8SCy Schubert } 258385732ac8SCy Schubert #endif /* CONFIG_WPS */ 258485732ac8SCy Schubert 2585f05cddf9SRui Paulo if (xhdr->type != IEEE802_1X_TYPE_EAPOL_KEY) 2586f05cddf9SRui Paulo return 0; 2587f05cddf9SRui Paulo 2588f05cddf9SRui Paulo if (pos + sizeof(struct wpa_eapol_key) <= buf + len) { 2589f05cddf9SRui Paulo const struct wpa_eapol_key *wpa; 2590*c1d255d3SCy Schubert 2591f05cddf9SRui Paulo wpa = (const struct wpa_eapol_key *) pos; 2592f05cddf9SRui Paulo if (wpa->type == EAPOL_KEY_TYPE_RSN || 2593f05cddf9SRui Paulo wpa->type == EAPOL_KEY_TYPE_WPA) 2594f05cddf9SRui Paulo wpa_auth_eapol_key_tx_status(hapd->wpa_auth, 2595f05cddf9SRui Paulo sta->wpa_sm, ack); 2596f05cddf9SRui Paulo } 2597f05cddf9SRui Paulo 2598e28a4053SRui Paulo /* EAPOL EAP-Packet packets are eventually re-sent by either Supplicant 2599e28a4053SRui Paulo * or Authenticator state machines, but EAPOL-Key packets are not 2600f05cddf9SRui Paulo * retransmitted in case of failure. Try to re-send failed EAPOL-Key 2601e28a4053SRui Paulo * packets couple of times because otherwise STA keys become 2602e28a4053SRui Paulo * unsynchronized with AP. */ 2603f05cddf9SRui Paulo if (!ack && pos + sizeof(*key) <= buf + len) { 2604e28a4053SRui Paulo key = (struct ieee802_1x_eapol_key *) pos; 2605e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 2606*c1d255d3SCy Schubert HOSTAPD_LEVEL_DEBUG, 2607*c1d255d3SCy Schubert "did not Ack EAPOL-Key frame (%scast index=%d)", 2608e28a4053SRui Paulo key->key_index & BIT(7) ? "uni" : "broad", 2609e28a4053SRui Paulo key->key_index & ~BIT(7)); 2610e28a4053SRui Paulo /* TODO: re-send EAPOL-Key couple of times (with short delay 2611e28a4053SRui Paulo * between them?). If all attempt fail, report error and 2612e28a4053SRui Paulo * deauthenticate STA so that it will get new keys when 2613e28a4053SRui Paulo * authenticating again (e.g., after returning in range). 2614e28a4053SRui Paulo * Separate limit/transmit state needed both for unicast and 2615e28a4053SRui Paulo * broadcast keys(?) */ 2616e28a4053SRui Paulo } 2617e28a4053SRui Paulo /* TODO: could move unicast key configuration from ieee802_1x_tx_key() 2618e28a4053SRui Paulo * to here and change the key only if the EAPOL-Key packet was Acked. 2619e28a4053SRui Paulo */ 2620e28a4053SRui Paulo 2621e28a4053SRui Paulo return 1; 2622e28a4053SRui Paulo } 2623e28a4053SRui Paulo 2624e28a4053SRui Paulo 2625e28a4053SRui Paulo u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len) 2626e28a4053SRui Paulo { 2627*c1d255d3SCy Schubert if (!sm || !sm->identity) 2628e28a4053SRui Paulo return NULL; 2629e28a4053SRui Paulo 2630e28a4053SRui Paulo *len = sm->identity_len; 2631e28a4053SRui Paulo return sm->identity; 2632e28a4053SRui Paulo } 2633e28a4053SRui Paulo 2634e28a4053SRui Paulo 2635e28a4053SRui Paulo u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len, 2636e28a4053SRui Paulo int idx) 2637e28a4053SRui Paulo { 2638*c1d255d3SCy Schubert if (!sm || !sm->radius_class.attr || 2639e28a4053SRui Paulo idx >= (int) sm->radius_class.count) 2640e28a4053SRui Paulo return NULL; 2641e28a4053SRui Paulo 2642e28a4053SRui Paulo *len = sm->radius_class.attr[idx].len; 2643e28a4053SRui Paulo return sm->radius_class.attr[idx].data; 2644e28a4053SRui Paulo } 2645e28a4053SRui Paulo 2646e28a4053SRui Paulo 2647f05cddf9SRui Paulo struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm) 2648f05cddf9SRui Paulo { 2649*c1d255d3SCy Schubert if (!sm) 2650f05cddf9SRui Paulo return NULL; 2651f05cddf9SRui Paulo return sm->radius_cui; 2652f05cddf9SRui Paulo } 2653f05cddf9SRui Paulo 2654f05cddf9SRui Paulo 2655e28a4053SRui Paulo const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len) 2656e28a4053SRui Paulo { 2657f05cddf9SRui Paulo *len = 0; 2658*c1d255d3SCy Schubert if (!sm) 2659e28a4053SRui Paulo return NULL; 2660e28a4053SRui Paulo 2661e28a4053SRui Paulo *len = sm->eap_if->eapKeyDataLen; 2662e28a4053SRui Paulo return sm->eap_if->eapKeyData; 2663e28a4053SRui Paulo } 2664e28a4053SRui Paulo 2665e28a4053SRui Paulo 2666206b73d0SCy Schubert #ifdef CONFIG_MACSEC 2667206b73d0SCy Schubert const u8 * ieee802_1x_get_session_id(struct eapol_state_machine *sm, 2668206b73d0SCy Schubert size_t *len) 2669206b73d0SCy Schubert { 2670206b73d0SCy Schubert *len = 0; 2671206b73d0SCy Schubert if (!sm || !sm->eap_if) 2672206b73d0SCy Schubert return NULL; 2673206b73d0SCy Schubert 2674206b73d0SCy Schubert *len = sm->eap_if->eapSessionIdLen; 2675206b73d0SCy Schubert return sm->eap_if->eapSessionId; 2676206b73d0SCy Schubert } 2677206b73d0SCy Schubert #endif /* CONFIG_MACSEC */ 2678206b73d0SCy Schubert 2679206b73d0SCy Schubert 2680e28a4053SRui Paulo void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm, 2681*c1d255d3SCy Schubert bool enabled) 2682e28a4053SRui Paulo { 2683*c1d255d3SCy Schubert if (!sm) 2684e28a4053SRui Paulo return; 2685*c1d255d3SCy Schubert sm->eap_if->portEnabled = enabled; 2686e28a4053SRui Paulo eapol_auth_step(sm); 2687e28a4053SRui Paulo } 2688e28a4053SRui Paulo 2689e28a4053SRui Paulo 2690*c1d255d3SCy Schubert void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, bool valid) 2691e28a4053SRui Paulo { 2692*c1d255d3SCy Schubert if (!sm) 2693e28a4053SRui Paulo return; 2694*c1d255d3SCy Schubert sm->portValid = valid; 2695e28a4053SRui Paulo eapol_auth_step(sm); 2696e28a4053SRui Paulo } 2697e28a4053SRui Paulo 2698e28a4053SRui Paulo 2699*c1d255d3SCy Schubert void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, bool pre_auth) 2700e28a4053SRui Paulo { 2701*c1d255d3SCy Schubert if (!sm) 2702e28a4053SRui Paulo return; 2703e28a4053SRui Paulo if (pre_auth) 2704e28a4053SRui Paulo sm->flags |= EAPOL_SM_PREAUTH; 2705e28a4053SRui Paulo else 2706e28a4053SRui Paulo sm->flags &= ~EAPOL_SM_PREAUTH; 2707e28a4053SRui Paulo } 2708e28a4053SRui Paulo 2709e28a4053SRui Paulo 2710*c1d255d3SCy Schubert static const char * bool_txt(bool val) 2711e28a4053SRui Paulo { 2712325151a3SRui Paulo return val ? "TRUE" : "FALSE"; 2713e28a4053SRui Paulo } 2714e28a4053SRui Paulo 2715e28a4053SRui Paulo 2716e28a4053SRui Paulo int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen) 2717e28a4053SRui Paulo { 2718e28a4053SRui Paulo /* TODO */ 2719e28a4053SRui Paulo return 0; 2720e28a4053SRui Paulo } 2721e28a4053SRui Paulo 2722e28a4053SRui Paulo 2723e28a4053SRui Paulo int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, 2724e28a4053SRui Paulo char *buf, size_t buflen) 2725e28a4053SRui Paulo { 2726e28a4053SRui Paulo int len = 0, ret; 2727e28a4053SRui Paulo struct eapol_state_machine *sm = sta->eapol_sm; 27285b9c547cSRui Paulo struct os_reltime diff; 27295b9c547cSRui Paulo const char *name1; 27305b9c547cSRui Paulo const char *name2; 27314bc52338SCy Schubert char *identity_buf = NULL; 2732e28a4053SRui Paulo 2733*c1d255d3SCy Schubert if (!sm) 2734e28a4053SRui Paulo return 0; 2735e28a4053SRui Paulo 2736e28a4053SRui Paulo ret = os_snprintf(buf + len, buflen - len, 2737e28a4053SRui Paulo "dot1xPaePortNumber=%d\n" 2738e28a4053SRui Paulo "dot1xPaePortProtocolVersion=%d\n" 2739e28a4053SRui Paulo "dot1xPaePortCapabilities=1\n" 2740e28a4053SRui Paulo "dot1xPaePortInitialize=%d\n" 2741e28a4053SRui Paulo "dot1xPaePortReauthenticate=FALSE\n", 2742e28a4053SRui Paulo sta->aid, 2743e28a4053SRui Paulo EAPOL_VERSION, 2744e28a4053SRui Paulo sm->initialize); 27455b9c547cSRui Paulo if (os_snprintf_error(buflen - len, ret)) 2746e28a4053SRui Paulo return len; 2747e28a4053SRui Paulo len += ret; 2748e28a4053SRui Paulo 2749e28a4053SRui Paulo /* dot1xAuthConfigTable */ 2750e28a4053SRui Paulo ret = os_snprintf(buf + len, buflen - len, 2751e28a4053SRui Paulo "dot1xAuthPaeState=%d\n" 2752e28a4053SRui Paulo "dot1xAuthBackendAuthState=%d\n" 2753e28a4053SRui Paulo "dot1xAuthAdminControlledDirections=%d\n" 2754e28a4053SRui Paulo "dot1xAuthOperControlledDirections=%d\n" 2755e28a4053SRui Paulo "dot1xAuthAuthControlledPortStatus=%d\n" 2756e28a4053SRui Paulo "dot1xAuthAuthControlledPortControl=%d\n" 2757e28a4053SRui Paulo "dot1xAuthQuietPeriod=%u\n" 2758e28a4053SRui Paulo "dot1xAuthServerTimeout=%u\n" 2759e28a4053SRui Paulo "dot1xAuthReAuthPeriod=%u\n" 2760e28a4053SRui Paulo "dot1xAuthReAuthEnabled=%s\n" 2761e28a4053SRui Paulo "dot1xAuthKeyTxEnabled=%s\n", 2762e28a4053SRui Paulo sm->auth_pae_state + 1, 2763e28a4053SRui Paulo sm->be_auth_state + 1, 2764e28a4053SRui Paulo sm->adminControlledDirections, 2765e28a4053SRui Paulo sm->operControlledDirections, 2766e28a4053SRui Paulo sm->authPortStatus, 2767e28a4053SRui Paulo sm->portControl, 2768e28a4053SRui Paulo sm->quietPeriod, 2769e28a4053SRui Paulo sm->serverTimeout, 2770e28a4053SRui Paulo sm->reAuthPeriod, 2771e28a4053SRui Paulo bool_txt(sm->reAuthEnabled), 2772e28a4053SRui Paulo bool_txt(sm->keyTxEnabled)); 27735b9c547cSRui Paulo if (os_snprintf_error(buflen - len, ret)) 2774e28a4053SRui Paulo return len; 2775e28a4053SRui Paulo len += ret; 2776e28a4053SRui Paulo 2777e28a4053SRui Paulo /* dot1xAuthStatsTable */ 2778e28a4053SRui Paulo ret = os_snprintf(buf + len, buflen - len, 2779e28a4053SRui Paulo "dot1xAuthEapolFramesRx=%u\n" 2780e28a4053SRui Paulo "dot1xAuthEapolFramesTx=%u\n" 2781e28a4053SRui Paulo "dot1xAuthEapolStartFramesRx=%u\n" 2782e28a4053SRui Paulo "dot1xAuthEapolLogoffFramesRx=%u\n" 2783e28a4053SRui Paulo "dot1xAuthEapolRespIdFramesRx=%u\n" 2784e28a4053SRui Paulo "dot1xAuthEapolRespFramesRx=%u\n" 2785e28a4053SRui Paulo "dot1xAuthEapolReqIdFramesTx=%u\n" 2786e28a4053SRui Paulo "dot1xAuthEapolReqFramesTx=%u\n" 2787e28a4053SRui Paulo "dot1xAuthInvalidEapolFramesRx=%u\n" 2788e28a4053SRui Paulo "dot1xAuthEapLengthErrorFramesRx=%u\n" 2789e28a4053SRui Paulo "dot1xAuthLastEapolFrameVersion=%u\n" 2790e28a4053SRui Paulo "dot1xAuthLastEapolFrameSource=" MACSTR "\n", 2791e28a4053SRui Paulo sm->dot1xAuthEapolFramesRx, 2792e28a4053SRui Paulo sm->dot1xAuthEapolFramesTx, 2793e28a4053SRui Paulo sm->dot1xAuthEapolStartFramesRx, 2794e28a4053SRui Paulo sm->dot1xAuthEapolLogoffFramesRx, 2795e28a4053SRui Paulo sm->dot1xAuthEapolRespIdFramesRx, 2796e28a4053SRui Paulo sm->dot1xAuthEapolRespFramesRx, 2797e28a4053SRui Paulo sm->dot1xAuthEapolReqIdFramesTx, 2798e28a4053SRui Paulo sm->dot1xAuthEapolReqFramesTx, 2799e28a4053SRui Paulo sm->dot1xAuthInvalidEapolFramesRx, 2800e28a4053SRui Paulo sm->dot1xAuthEapLengthErrorFramesRx, 2801e28a4053SRui Paulo sm->dot1xAuthLastEapolFrameVersion, 2802e28a4053SRui Paulo MAC2STR(sm->addr)); 28035b9c547cSRui Paulo if (os_snprintf_error(buflen - len, ret)) 2804e28a4053SRui Paulo return len; 2805e28a4053SRui Paulo len += ret; 2806e28a4053SRui Paulo 2807e28a4053SRui Paulo /* dot1xAuthDiagTable */ 2808e28a4053SRui Paulo ret = os_snprintf(buf + len, buflen - len, 2809e28a4053SRui Paulo "dot1xAuthEntersConnecting=%u\n" 2810e28a4053SRui Paulo "dot1xAuthEapLogoffsWhileConnecting=%u\n" 2811e28a4053SRui Paulo "dot1xAuthEntersAuthenticating=%u\n" 2812e28a4053SRui Paulo "dot1xAuthAuthSuccessesWhileAuthenticating=%u\n" 2813e28a4053SRui Paulo "dot1xAuthAuthTimeoutsWhileAuthenticating=%u\n" 2814e28a4053SRui Paulo "dot1xAuthAuthFailWhileAuthenticating=%u\n" 2815e28a4053SRui Paulo "dot1xAuthAuthEapStartsWhileAuthenticating=%u\n" 2816e28a4053SRui Paulo "dot1xAuthAuthEapLogoffWhileAuthenticating=%u\n" 2817e28a4053SRui Paulo "dot1xAuthAuthReauthsWhileAuthenticated=%u\n" 2818e28a4053SRui Paulo "dot1xAuthAuthEapStartsWhileAuthenticated=%u\n" 2819e28a4053SRui Paulo "dot1xAuthAuthEapLogoffWhileAuthenticated=%u\n" 2820e28a4053SRui Paulo "dot1xAuthBackendResponses=%u\n" 2821e28a4053SRui Paulo "dot1xAuthBackendAccessChallenges=%u\n" 2822e28a4053SRui Paulo "dot1xAuthBackendOtherRequestsToSupplicant=%u\n" 2823e28a4053SRui Paulo "dot1xAuthBackendAuthSuccesses=%u\n" 2824e28a4053SRui Paulo "dot1xAuthBackendAuthFails=%u\n", 2825e28a4053SRui Paulo sm->authEntersConnecting, 2826e28a4053SRui Paulo sm->authEapLogoffsWhileConnecting, 2827e28a4053SRui Paulo sm->authEntersAuthenticating, 2828e28a4053SRui Paulo sm->authAuthSuccessesWhileAuthenticating, 2829e28a4053SRui Paulo sm->authAuthTimeoutsWhileAuthenticating, 2830e28a4053SRui Paulo sm->authAuthFailWhileAuthenticating, 2831e28a4053SRui Paulo sm->authAuthEapStartsWhileAuthenticating, 2832e28a4053SRui Paulo sm->authAuthEapLogoffWhileAuthenticating, 2833e28a4053SRui Paulo sm->authAuthReauthsWhileAuthenticated, 2834e28a4053SRui Paulo sm->authAuthEapStartsWhileAuthenticated, 2835e28a4053SRui Paulo sm->authAuthEapLogoffWhileAuthenticated, 2836e28a4053SRui Paulo sm->backendResponses, 2837e28a4053SRui Paulo sm->backendAccessChallenges, 2838e28a4053SRui Paulo sm->backendOtherRequestsToSupplicant, 2839e28a4053SRui Paulo sm->backendAuthSuccesses, 2840e28a4053SRui Paulo sm->backendAuthFails); 28415b9c547cSRui Paulo if (os_snprintf_error(buflen - len, ret)) 2842e28a4053SRui Paulo return len; 2843e28a4053SRui Paulo len += ret; 2844e28a4053SRui Paulo 2845e28a4053SRui Paulo /* dot1xAuthSessionStatsTable */ 28465b9c547cSRui Paulo os_reltime_age(&sta->acct_session_start, &diff); 28474bc52338SCy Schubert if (sm->eap && !sm->identity) { 28484bc52338SCy Schubert const u8 *id; 28494bc52338SCy Schubert size_t id_len; 28504bc52338SCy Schubert 28514bc52338SCy Schubert id = eap_get_identity(sm->eap, &id_len); 28524bc52338SCy Schubert if (id) 28534bc52338SCy Schubert identity_buf = dup_binstr(id, id_len); 28544bc52338SCy Schubert } 2855e28a4053SRui Paulo ret = os_snprintf(buf + len, buflen - len, 2856e28a4053SRui Paulo /* TODO: dot1xAuthSessionOctetsRx */ 2857e28a4053SRui Paulo /* TODO: dot1xAuthSessionOctetsTx */ 2858e28a4053SRui Paulo /* TODO: dot1xAuthSessionFramesRx */ 2859e28a4053SRui Paulo /* TODO: dot1xAuthSessionFramesTx */ 2860780fb4a2SCy Schubert "dot1xAuthSessionId=%016llX\n" 2861e28a4053SRui Paulo "dot1xAuthSessionAuthenticMethod=%d\n" 2862e28a4053SRui Paulo "dot1xAuthSessionTime=%u\n" 2863e28a4053SRui Paulo "dot1xAuthSessionTerminateCause=999\n" 2864e28a4053SRui Paulo "dot1xAuthSessionUserName=%s\n", 2865780fb4a2SCy Schubert (unsigned long long) sta->acct_session_id, 2866e28a4053SRui Paulo (wpa_key_mgmt_wpa_ieee8021x( 2867e28a4053SRui Paulo wpa_auth_sta_key_mgmt(sta->wpa_sm))) ? 2868e28a4053SRui Paulo 1 : 2, 28695b9c547cSRui Paulo (unsigned int) diff.sec, 28704bc52338SCy Schubert sm->identity ? (char *) sm->identity : 28714bc52338SCy Schubert (identity_buf ? identity_buf : "N/A")); 28724bc52338SCy Schubert os_free(identity_buf); 28735b9c547cSRui Paulo if (os_snprintf_error(buflen - len, ret)) 28745b9c547cSRui Paulo return len; 28755b9c547cSRui Paulo len += ret; 28765b9c547cSRui Paulo 2877780fb4a2SCy Schubert if (sm->acct_multi_session_id) { 28785b9c547cSRui Paulo ret = os_snprintf(buf + len, buflen - len, 2879780fb4a2SCy Schubert "authMultiSessionId=%016llX\n", 2880780fb4a2SCy Schubert (unsigned long long) 2881780fb4a2SCy Schubert sm->acct_multi_session_id); 28825b9c547cSRui Paulo if (os_snprintf_error(buflen - len, ret)) 28835b9c547cSRui Paulo return len; 28845b9c547cSRui Paulo len += ret; 28855b9c547cSRui Paulo } 28865b9c547cSRui Paulo 28875b9c547cSRui Paulo name1 = eap_server_get_name(0, sm->eap_type_authsrv); 28885b9c547cSRui Paulo name2 = eap_server_get_name(0, sm->eap_type_supp); 28895b9c547cSRui Paulo ret = os_snprintf(buf + len, buflen - len, 28905b9c547cSRui Paulo "last_eap_type_as=%d (%s)\n" 28915b9c547cSRui Paulo "last_eap_type_sta=%d (%s)\n", 28925b9c547cSRui Paulo sm->eap_type_authsrv, name1, 28935b9c547cSRui Paulo sm->eap_type_supp, name2); 28945b9c547cSRui Paulo if (os_snprintf_error(buflen - len, ret)) 2895e28a4053SRui Paulo return len; 2896e28a4053SRui Paulo len += ret; 2897e28a4053SRui Paulo 2898e28a4053SRui Paulo return len; 2899e28a4053SRui Paulo } 2900e28a4053SRui Paulo 2901e28a4053SRui Paulo 2902780fb4a2SCy Schubert #ifdef CONFIG_HS20 2903780fb4a2SCy Schubert static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx) 2904780fb4a2SCy Schubert { 2905780fb4a2SCy Schubert struct hostapd_data *hapd = eloop_ctx; 2906780fb4a2SCy Schubert struct sta_info *sta = timeout_ctx; 2907780fb4a2SCy Schubert 2908780fb4a2SCy Schubert if (sta->remediation) { 2909780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to " 2910780fb4a2SCy Schubert MACSTR " to indicate Subscription Remediation", 2911780fb4a2SCy Schubert MAC2STR(sta->addr)); 2912780fb4a2SCy Schubert hs20_send_wnm_notification(hapd, sta->addr, 2913780fb4a2SCy Schubert sta->remediation_method, 2914780fb4a2SCy Schubert sta->remediation_url); 2915780fb4a2SCy Schubert os_free(sta->remediation_url); 2916780fb4a2SCy Schubert sta->remediation_url = NULL; 2917780fb4a2SCy Schubert } 2918780fb4a2SCy Schubert 2919780fb4a2SCy Schubert if (sta->hs20_deauth_req) { 2920780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to " 2921780fb4a2SCy Schubert MACSTR " to indicate imminent deauthentication", 2922780fb4a2SCy Schubert MAC2STR(sta->addr)); 2923780fb4a2SCy Schubert hs20_send_wnm_notification_deauth_req(hapd, sta->addr, 2924780fb4a2SCy Schubert sta->hs20_deauth_req); 2925780fb4a2SCy Schubert } 292685732ac8SCy Schubert 292785732ac8SCy Schubert if (sta->hs20_t_c_filtering) { 292885732ac8SCy Schubert wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to " 292985732ac8SCy Schubert MACSTR " to indicate Terms and Conditions filtering", 293085732ac8SCy Schubert MAC2STR(sta->addr)); 293185732ac8SCy Schubert hs20_send_wnm_notification_t_c(hapd, sta->addr, sta->t_c_url); 293285732ac8SCy Schubert os_free(sta->t_c_url); 293385732ac8SCy Schubert sta->t_c_url = NULL; 293485732ac8SCy Schubert } 2935780fb4a2SCy Schubert } 2936780fb4a2SCy Schubert #endif /* CONFIG_HS20 */ 2937780fb4a2SCy Schubert 2938780fb4a2SCy Schubert 2939e28a4053SRui Paulo static void ieee802_1x_finished(struct hostapd_data *hapd, 29405b9c547cSRui Paulo struct sta_info *sta, int success, 29415b9c547cSRui Paulo int remediation) 2942e28a4053SRui Paulo { 2943e28a4053SRui Paulo const u8 *key; 2944e28a4053SRui Paulo size_t len; 2945e28a4053SRui Paulo /* TODO: get PMKLifetime from WPA parameters */ 2946e28a4053SRui Paulo static const int dot11RSNAConfigPMKLifetime = 43200; 29475b9c547cSRui Paulo unsigned int session_timeout; 294885732ac8SCy Schubert struct os_reltime now, remaining; 29495b9c547cSRui Paulo 29505b9c547cSRui Paulo #ifdef CONFIG_HS20 29515b9c547cSRui Paulo if (remediation && !sta->remediation) { 29525b9c547cSRui Paulo sta->remediation = 1; 29535b9c547cSRui Paulo os_free(sta->remediation_url); 29545b9c547cSRui Paulo sta->remediation_url = 29555b9c547cSRui Paulo os_strdup(hapd->conf->subscr_remediation_url); 29565b9c547cSRui Paulo sta->remediation_method = 1; /* SOAP-XML SPP */ 29575b9c547cSRui Paulo } 29585b9c547cSRui Paulo 295985732ac8SCy Schubert if (success && (sta->remediation || sta->hs20_deauth_req || 296085732ac8SCy Schubert sta->hs20_t_c_filtering)) { 2961780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "HS 2.0: Schedule WNM-Notification to " 2962780fb4a2SCy Schubert MACSTR " in 100 ms", MAC2STR(sta->addr)); 2963780fb4a2SCy Schubert eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta); 2964780fb4a2SCy Schubert eloop_register_timeout(0, 100000, ieee802_1x_wnm_notif_send, 2965780fb4a2SCy Schubert hapd, sta); 29665b9c547cSRui Paulo } 29675b9c547cSRui Paulo #endif /* CONFIG_HS20 */ 2968e28a4053SRui Paulo 2969206b73d0SCy Schubert #ifdef CONFIG_MACSEC 2970206b73d0SCy Schubert ieee802_1x_notify_create_actor_hapd(hapd, sta); 2971206b73d0SCy Schubert #endif /* CONFIG_MACSEC */ 2972206b73d0SCy Schubert 2973e28a4053SRui Paulo key = ieee802_1x_get_key(sta->eapol_sm, &len); 297485732ac8SCy Schubert if (sta->session_timeout_set) { 297585732ac8SCy Schubert os_get_reltime(&now); 297685732ac8SCy Schubert os_reltime_sub(&sta->session_timeout, &now, &remaining); 297785732ac8SCy Schubert session_timeout = (remaining.sec > 0) ? remaining.sec : 1; 297885732ac8SCy Schubert } else { 29795b9c547cSRui Paulo session_timeout = dot11RSNAConfigPMKLifetime; 298085732ac8SCy Schubert } 29815b9c547cSRui Paulo if (success && key && len >= PMK_LEN && !sta->remediation && 29825b9c547cSRui Paulo !sta->hs20_deauth_requested && 2983780fb4a2SCy Schubert wpa_auth_pmksa_add(sta->wpa_sm, key, len, session_timeout, 2984e28a4053SRui Paulo sta->eapol_sm) == 0) { 2985e28a4053SRui Paulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, 2986e28a4053SRui Paulo HOSTAPD_LEVEL_DEBUG, 2987e28a4053SRui Paulo "Added PMKSA cache entry (IEEE 802.1X)"); 2988e28a4053SRui Paulo } 2989e28a4053SRui Paulo 2990f05cddf9SRui Paulo if (!success) { 2991e28a4053SRui Paulo /* 2992e28a4053SRui Paulo * Many devices require deauthentication after WPS provisioning 2993e28a4053SRui Paulo * and some may not be be able to do that themselves, so 2994f05cddf9SRui Paulo * disconnect the client here. In addition, this may also 2995f05cddf9SRui Paulo * benefit IEEE 802.1X/EAPOL authentication cases, too since 2996f05cddf9SRui Paulo * the EAPOL PAE state machine would remain in HELD state for 2997f05cddf9SRui Paulo * considerable amount of time and some EAP methods, like 2998f05cddf9SRui Paulo * EAP-FAST with anonymous provisioning, may require another 2999f05cddf9SRui Paulo * EAPOL authentication to be started to complete connection. 3000e28a4053SRui Paulo */ 300185732ac8SCy Schubert ap_sta_delayed_1x_auth_fail_disconnect(hapd, sta); 3002e28a4053SRui Paulo } 3003e28a4053SRui Paulo } 3004