1e5b75505Sopenharmony_ci/* 2e5b75505Sopenharmony_ci * hostapd / IEEE 802.1X-2004 Authenticator 3e5b75505Sopenharmony_ci * Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> 4e5b75505Sopenharmony_ci * 5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license. 6e5b75505Sopenharmony_ci * See README for more details. 7e5b75505Sopenharmony_ci */ 8e5b75505Sopenharmony_ci 9e5b75505Sopenharmony_ci#include "utils/includes.h" 10e5b75505Sopenharmony_ci#ifdef CONFIG_SQLITE 11e5b75505Sopenharmony_ci#include <sqlite3.h> 12e5b75505Sopenharmony_ci#endif /* CONFIG_SQLITE */ 13e5b75505Sopenharmony_ci 14e5b75505Sopenharmony_ci#include "utils/common.h" 15e5b75505Sopenharmony_ci#include "utils/eloop.h" 16e5b75505Sopenharmony_ci#include "crypto/md5.h" 17e5b75505Sopenharmony_ci#include "crypto/crypto.h" 18e5b75505Sopenharmony_ci#include "crypto/random.h" 19e5b75505Sopenharmony_ci#include "common/ieee802_11_defs.h" 20e5b75505Sopenharmony_ci#include "radius/radius.h" 21e5b75505Sopenharmony_ci#include "radius/radius_client.h" 22e5b75505Sopenharmony_ci#include "eap_server/eap.h" 23e5b75505Sopenharmony_ci#include "eap_common/eap_wsc_common.h" 24e5b75505Sopenharmony_ci#include "eapol_auth/eapol_auth_sm.h" 25e5b75505Sopenharmony_ci#include "eapol_auth/eapol_auth_sm_i.h" 26e5b75505Sopenharmony_ci#include "p2p/p2p.h" 27e5b75505Sopenharmony_ci#include "hostapd.h" 28e5b75505Sopenharmony_ci#include "accounting.h" 29e5b75505Sopenharmony_ci#include "sta_info.h" 30e5b75505Sopenharmony_ci#include "wpa_auth.h" 31e5b75505Sopenharmony_ci#include "preauth_auth.h" 32e5b75505Sopenharmony_ci#include "pmksa_cache_auth.h" 33e5b75505Sopenharmony_ci#include "ap_config.h" 34e5b75505Sopenharmony_ci#include "ap_drv_ops.h" 35e5b75505Sopenharmony_ci#include "wps_hostapd.h" 36e5b75505Sopenharmony_ci#include "hs20.h" 37e5b75505Sopenharmony_ci/* FIX: Not really a good thing to require ieee802_11.h here.. (FILS) */ 38e5b75505Sopenharmony_ci#include "ieee802_11.h" 39e5b75505Sopenharmony_ci#include "ieee802_1x.h" 40e5b75505Sopenharmony_ci#include "wpa_auth_kay.h" 41e5b75505Sopenharmony_ci 42e5b75505Sopenharmony_ci 43e5b75505Sopenharmony_ci#ifdef CONFIG_HS20 44e5b75505Sopenharmony_cistatic void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx); 45e5b75505Sopenharmony_ci#endif /* CONFIG_HS20 */ 46e5b75505Sopenharmony_cistatic void ieee802_1x_finished(struct hostapd_data *hapd, 47e5b75505Sopenharmony_ci struct sta_info *sta, int success, 48e5b75505Sopenharmony_ci int remediation); 49e5b75505Sopenharmony_ci 50e5b75505Sopenharmony_ci 51e5b75505Sopenharmony_cistatic void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta, 52e5b75505Sopenharmony_ci u8 type, const u8 *data, size_t datalen) 53e5b75505Sopenharmony_ci{ 54e5b75505Sopenharmony_ci u8 *buf; 55e5b75505Sopenharmony_ci struct ieee802_1x_hdr *xhdr; 56e5b75505Sopenharmony_ci size_t len; 57e5b75505Sopenharmony_ci int encrypt = 0; 58e5b75505Sopenharmony_ci 59e5b75505Sopenharmony_ci len = sizeof(*xhdr) + datalen; 60e5b75505Sopenharmony_ci buf = os_zalloc(len); 61e5b75505Sopenharmony_ci if (buf == NULL) { 62e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "malloc() failed for " 63e5b75505Sopenharmony_ci "ieee802_1x_send(len=%lu)", 64e5b75505Sopenharmony_ci (unsigned long) len); 65e5b75505Sopenharmony_ci return; 66e5b75505Sopenharmony_ci } 67e5b75505Sopenharmony_ci 68e5b75505Sopenharmony_ci xhdr = (struct ieee802_1x_hdr *) buf; 69e5b75505Sopenharmony_ci xhdr->version = hapd->conf->eapol_version; 70e5b75505Sopenharmony_ci#ifdef CONFIG_MACSEC 71e5b75505Sopenharmony_ci if (xhdr->version > 2 && hapd->conf->macsec_policy == 0) 72e5b75505Sopenharmony_ci xhdr->version = 2; 73e5b75505Sopenharmony_ci#endif /* CONFIG_MACSEC */ 74e5b75505Sopenharmony_ci xhdr->type = type; 75e5b75505Sopenharmony_ci xhdr->length = host_to_be16(datalen); 76e5b75505Sopenharmony_ci 77e5b75505Sopenharmony_ci if (datalen > 0 && data != NULL) 78e5b75505Sopenharmony_ci os_memcpy(xhdr + 1, data, datalen); 79e5b75505Sopenharmony_ci 80e5b75505Sopenharmony_ci if (wpa_auth_pairwise_set(sta->wpa_sm)) 81e5b75505Sopenharmony_ci encrypt = 1; 82e5b75505Sopenharmony_ci#ifdef CONFIG_TESTING_OPTIONS 83e5b75505Sopenharmony_ci if (hapd->ext_eapol_frame_io) { 84e5b75505Sopenharmony_ci size_t hex_len = 2 * len + 1; 85e5b75505Sopenharmony_ci char *hex = os_malloc(hex_len); 86e5b75505Sopenharmony_ci 87e5b75505Sopenharmony_ci if (hex) { 88e5b75505Sopenharmony_ci wpa_snprintf_hex(hex, hex_len, buf, len); 89e5b75505Sopenharmony_ci wpa_msg(hapd->msg_ctx, MSG_INFO, 90e5b75505Sopenharmony_ci "EAPOL-TX " MACSTR " %s", 91e5b75505Sopenharmony_ci MAC2STR(sta->addr), hex); 92e5b75505Sopenharmony_ci os_free(hex); 93e5b75505Sopenharmony_ci } 94e5b75505Sopenharmony_ci } else 95e5b75505Sopenharmony_ci#endif /* CONFIG_TESTING_OPTIONS */ 96e5b75505Sopenharmony_ci if (sta->flags & WLAN_STA_PREAUTH) { 97e5b75505Sopenharmony_ci rsn_preauth_send(hapd, sta, buf, len); 98e5b75505Sopenharmony_ci } else { 99e5b75505Sopenharmony_ci hostapd_drv_hapd_send_eapol( 100e5b75505Sopenharmony_ci hapd, sta->addr, buf, len, 101e5b75505Sopenharmony_ci encrypt, hostapd_sta_flags_to_drv(sta->flags)); 102e5b75505Sopenharmony_ci } 103e5b75505Sopenharmony_ci 104e5b75505Sopenharmony_ci os_free(buf); 105e5b75505Sopenharmony_ci} 106e5b75505Sopenharmony_ci 107e5b75505Sopenharmony_ci 108e5b75505Sopenharmony_civoid ieee802_1x_set_sta_authorized(struct hostapd_data *hapd, 109e5b75505Sopenharmony_ci struct sta_info *sta, int authorized) 110e5b75505Sopenharmony_ci{ 111e5b75505Sopenharmony_ci int res; 112e5b75505Sopenharmony_ci 113e5b75505Sopenharmony_ci if (sta->flags & WLAN_STA_PREAUTH) 114e5b75505Sopenharmony_ci return; 115e5b75505Sopenharmony_ci 116e5b75505Sopenharmony_ci if (authorized) { 117e5b75505Sopenharmony_ci ap_sta_set_authorized(hapd, sta, 1); 118e5b75505Sopenharmony_ci res = hostapd_set_authorized(hapd, sta, 1); 119e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 120e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, "authorizing port"); 121e5b75505Sopenharmony_ci } else { 122e5b75505Sopenharmony_ci ap_sta_set_authorized(hapd, sta, 0); 123e5b75505Sopenharmony_ci res = hostapd_set_authorized(hapd, sta, 0); 124e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 125e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, "unauthorizing port"); 126e5b75505Sopenharmony_ci } 127e5b75505Sopenharmony_ci 128e5b75505Sopenharmony_ci if (res && errno != ENOENT) { 129e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Could not set station " MACSTR 130e5b75505Sopenharmony_ci " flags for kernel driver (errno=%d).", 131e5b75505Sopenharmony_ci MAC2STR(sta->addr), errno); 132e5b75505Sopenharmony_ci } 133e5b75505Sopenharmony_ci 134e5b75505Sopenharmony_ci if (authorized) { 135e5b75505Sopenharmony_ci os_get_reltime(&sta->connected_time); 136e5b75505Sopenharmony_ci accounting_sta_start(hapd, sta); 137e5b75505Sopenharmony_ci } 138e5b75505Sopenharmony_ci} 139e5b75505Sopenharmony_ci 140e5b75505Sopenharmony_ci 141e5b75505Sopenharmony_ci#ifndef CONFIG_FIPS 142e5b75505Sopenharmony_ci#ifndef CONFIG_NO_RC4 143e5b75505Sopenharmony_ci 144e5b75505Sopenharmony_cistatic void ieee802_1x_tx_key_one(struct hostapd_data *hapd, 145e5b75505Sopenharmony_ci struct sta_info *sta, 146e5b75505Sopenharmony_ci int idx, int broadcast, 147e5b75505Sopenharmony_ci u8 *key_data, size_t key_len) 148e5b75505Sopenharmony_ci{ 149e5b75505Sopenharmony_ci u8 *buf, *ekey; 150e5b75505Sopenharmony_ci struct ieee802_1x_hdr *hdr; 151e5b75505Sopenharmony_ci struct ieee802_1x_eapol_key *key; 152e5b75505Sopenharmony_ci size_t len, ekey_len; 153e5b75505Sopenharmony_ci struct eapol_state_machine *sm = sta->eapol_sm; 154e5b75505Sopenharmony_ci 155e5b75505Sopenharmony_ci if (sm == NULL) 156e5b75505Sopenharmony_ci return; 157e5b75505Sopenharmony_ci 158e5b75505Sopenharmony_ci len = sizeof(*key) + key_len; 159e5b75505Sopenharmony_ci buf = os_zalloc(sizeof(*hdr) + len); 160e5b75505Sopenharmony_ci if (buf == NULL) 161e5b75505Sopenharmony_ci return; 162e5b75505Sopenharmony_ci 163e5b75505Sopenharmony_ci hdr = (struct ieee802_1x_hdr *) buf; 164e5b75505Sopenharmony_ci key = (struct ieee802_1x_eapol_key *) (hdr + 1); 165e5b75505Sopenharmony_ci key->type = EAPOL_KEY_TYPE_RC4; 166e5b75505Sopenharmony_ci WPA_PUT_BE16(key->key_length, key_len); 167e5b75505Sopenharmony_ci wpa_get_ntp_timestamp(key->replay_counter); 168e5b75505Sopenharmony_ci if (os_memcmp(key->replay_counter, 169e5b75505Sopenharmony_ci hapd->last_1x_eapol_key_replay_counter, 170e5b75505Sopenharmony_ci IEEE8021X_REPLAY_COUNTER_LEN) <= 0) { 171e5b75505Sopenharmony_ci /* NTP timestamp did not increment from last EAPOL-Key frame; 172e5b75505Sopenharmony_ci * use previously used value + 1 instead. */ 173e5b75505Sopenharmony_ci inc_byte_array(hapd->last_1x_eapol_key_replay_counter, 174e5b75505Sopenharmony_ci IEEE8021X_REPLAY_COUNTER_LEN); 175e5b75505Sopenharmony_ci os_memcpy(key->replay_counter, 176e5b75505Sopenharmony_ci hapd->last_1x_eapol_key_replay_counter, 177e5b75505Sopenharmony_ci IEEE8021X_REPLAY_COUNTER_LEN); 178e5b75505Sopenharmony_ci } else { 179e5b75505Sopenharmony_ci os_memcpy(hapd->last_1x_eapol_key_replay_counter, 180e5b75505Sopenharmony_ci key->replay_counter, 181e5b75505Sopenharmony_ci IEEE8021X_REPLAY_COUNTER_LEN); 182e5b75505Sopenharmony_ci } 183e5b75505Sopenharmony_ci 184e5b75505Sopenharmony_ci if (random_get_bytes(key->key_iv, sizeof(key->key_iv))) { 185e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Could not get random numbers"); 186e5b75505Sopenharmony_ci os_free(buf); 187e5b75505Sopenharmony_ci return; 188e5b75505Sopenharmony_ci } 189e5b75505Sopenharmony_ci 190e5b75505Sopenharmony_ci key->key_index = idx | (broadcast ? 0 : BIT(7)); 191e5b75505Sopenharmony_ci if (hapd->conf->eapol_key_index_workaround) { 192e5b75505Sopenharmony_ci /* According to some information, WinXP Supplicant seems to 193e5b75505Sopenharmony_ci * interpret bit7 as an indication whether the key is to be 194e5b75505Sopenharmony_ci * activated, so make it possible to enable workaround that 195e5b75505Sopenharmony_ci * sets this bit for all keys. */ 196e5b75505Sopenharmony_ci key->key_index |= BIT(7); 197e5b75505Sopenharmony_ci } 198e5b75505Sopenharmony_ci 199e5b75505Sopenharmony_ci /* Key is encrypted using "Key-IV + MSK[0..31]" as the RC4-key and 200e5b75505Sopenharmony_ci * MSK[32..63] is used to sign the message. */ 201e5b75505Sopenharmony_ci if (sm->eap_if->eapKeyData == NULL || sm->eap_if->eapKeyDataLen < 64) { 202e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "No eapKeyData available for encrypting " 203e5b75505Sopenharmony_ci "and signing EAPOL-Key"); 204e5b75505Sopenharmony_ci os_free(buf); 205e5b75505Sopenharmony_ci return; 206e5b75505Sopenharmony_ci } 207e5b75505Sopenharmony_ci os_memcpy((u8 *) (key + 1), key_data, key_len); 208e5b75505Sopenharmony_ci ekey_len = sizeof(key->key_iv) + 32; 209e5b75505Sopenharmony_ci ekey = os_malloc(ekey_len); 210e5b75505Sopenharmony_ci if (ekey == NULL) { 211e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Could not encrypt key"); 212e5b75505Sopenharmony_ci os_free(buf); 213e5b75505Sopenharmony_ci return; 214e5b75505Sopenharmony_ci } 215e5b75505Sopenharmony_ci os_memcpy(ekey, key->key_iv, sizeof(key->key_iv)); 216e5b75505Sopenharmony_ci os_memcpy(ekey + sizeof(key->key_iv), sm->eap_if->eapKeyData, 32); 217e5b75505Sopenharmony_ci rc4_skip(ekey, ekey_len, 0, (u8 *) (key + 1), key_len); 218e5b75505Sopenharmony_ci os_free(ekey); 219e5b75505Sopenharmony_ci 220e5b75505Sopenharmony_ci /* This header is needed here for HMAC-MD5, but it will be regenerated 221e5b75505Sopenharmony_ci * in ieee802_1x_send() */ 222e5b75505Sopenharmony_ci hdr->version = hapd->conf->eapol_version; 223e5b75505Sopenharmony_ci#ifdef CONFIG_MACSEC 224e5b75505Sopenharmony_ci if (hdr->version > 2) 225e5b75505Sopenharmony_ci hdr->version = 2; 226e5b75505Sopenharmony_ci#endif /* CONFIG_MACSEC */ 227e5b75505Sopenharmony_ci hdr->type = IEEE802_1X_TYPE_EAPOL_KEY; 228e5b75505Sopenharmony_ci hdr->length = host_to_be16(len); 229e5b75505Sopenharmony_ci hmac_md5(sm->eap_if->eapKeyData + 32, 32, buf, sizeof(*hdr) + len, 230e5b75505Sopenharmony_ci key->key_signature); 231e5b75505Sopenharmony_ci 232e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key to " MACSTR 233e5b75505Sopenharmony_ci " (%s index=%d)", MAC2STR(sm->addr), 234e5b75505Sopenharmony_ci broadcast ? "broadcast" : "unicast", idx); 235e5b75505Sopenharmony_ci ieee802_1x_send(hapd, sta, IEEE802_1X_TYPE_EAPOL_KEY, (u8 *) key, len); 236e5b75505Sopenharmony_ci if (sta->eapol_sm) 237e5b75505Sopenharmony_ci sta->eapol_sm->dot1xAuthEapolFramesTx++; 238e5b75505Sopenharmony_ci os_free(buf); 239e5b75505Sopenharmony_ci} 240e5b75505Sopenharmony_ci 241e5b75505Sopenharmony_ci 242e5b75505Sopenharmony_cistatic void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta) 243e5b75505Sopenharmony_ci{ 244e5b75505Sopenharmony_ci struct eapol_authenticator *eapol = hapd->eapol_auth; 245e5b75505Sopenharmony_ci struct eapol_state_machine *sm = sta->eapol_sm; 246e5b75505Sopenharmony_ci 247e5b75505Sopenharmony_ci if (sm == NULL || !sm->eap_if->eapKeyData) 248e5b75505Sopenharmony_ci return; 249e5b75505Sopenharmony_ci 250e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key(s) to " MACSTR, 251e5b75505Sopenharmony_ci MAC2STR(sta->addr)); 252e5b75505Sopenharmony_ci 253e5b75505Sopenharmony_ci#ifndef CONFIG_NO_VLAN 254e5b75505Sopenharmony_ci if (sta->vlan_id > 0) { 255e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Using WEP with vlans is not supported."); 256e5b75505Sopenharmony_ci return; 257e5b75505Sopenharmony_ci } 258e5b75505Sopenharmony_ci#endif /* CONFIG_NO_VLAN */ 259e5b75505Sopenharmony_ci 260e5b75505Sopenharmony_ci if (eapol->default_wep_key) { 261e5b75505Sopenharmony_ci ieee802_1x_tx_key_one(hapd, sta, eapol->default_wep_key_idx, 1, 262e5b75505Sopenharmony_ci eapol->default_wep_key, 263e5b75505Sopenharmony_ci hapd->conf->default_wep_key_len); 264e5b75505Sopenharmony_ci } 265e5b75505Sopenharmony_ci 266e5b75505Sopenharmony_ci if (hapd->conf->individual_wep_key_len > 0) { 267e5b75505Sopenharmony_ci u8 *ikey; 268e5b75505Sopenharmony_ci ikey = os_malloc(hapd->conf->individual_wep_key_len); 269e5b75505Sopenharmony_ci if (ikey == NULL || 270e5b75505Sopenharmony_ci random_get_bytes(ikey, hapd->conf->individual_wep_key_len)) 271e5b75505Sopenharmony_ci { 272e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Could not generate random " 273e5b75505Sopenharmony_ci "individual WEP key."); 274e5b75505Sopenharmony_ci os_free(ikey); 275e5b75505Sopenharmony_ci return; 276e5b75505Sopenharmony_ci } 277e5b75505Sopenharmony_ci 278e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "Individual WEP key", 279e5b75505Sopenharmony_ci ikey, hapd->conf->individual_wep_key_len); 280e5b75505Sopenharmony_ci 281e5b75505Sopenharmony_ci ieee802_1x_tx_key_one(hapd, sta, 0, 0, ikey, 282e5b75505Sopenharmony_ci hapd->conf->individual_wep_key_len); 283e5b75505Sopenharmony_ci 284e5b75505Sopenharmony_ci /* TODO: set encryption in TX callback, i.e., only after STA 285e5b75505Sopenharmony_ci * has ACKed EAPOL-Key frame */ 286e5b75505Sopenharmony_ci if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, 287e5b75505Sopenharmony_ci sta->addr, 0, 1, NULL, 0, ikey, 288e5b75505Sopenharmony_ci hapd->conf->individual_wep_key_len)) { 289e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Could not set individual WEP " 290e5b75505Sopenharmony_ci "encryption."); 291e5b75505Sopenharmony_ci } 292e5b75505Sopenharmony_ci 293e5b75505Sopenharmony_ci os_free(ikey); 294e5b75505Sopenharmony_ci } 295e5b75505Sopenharmony_ci} 296e5b75505Sopenharmony_ci 297e5b75505Sopenharmony_ci#endif /* CONFIG_NO_RC4 */ 298e5b75505Sopenharmony_ci#endif /* CONFIG_FIPS */ 299e5b75505Sopenharmony_ci 300e5b75505Sopenharmony_ci 301e5b75505Sopenharmony_ciconst char *radius_mode_txt(struct hostapd_data *hapd) 302e5b75505Sopenharmony_ci{ 303e5b75505Sopenharmony_ci switch (hapd->iface->conf->hw_mode) { 304e5b75505Sopenharmony_ci case HOSTAPD_MODE_IEEE80211AD: 305e5b75505Sopenharmony_ci return "802.11ad"; 306e5b75505Sopenharmony_ci case HOSTAPD_MODE_IEEE80211A: 307e5b75505Sopenharmony_ci return "802.11a"; 308e5b75505Sopenharmony_ci case HOSTAPD_MODE_IEEE80211G: 309e5b75505Sopenharmony_ci return "802.11g"; 310e5b75505Sopenharmony_ci case HOSTAPD_MODE_IEEE80211B: 311e5b75505Sopenharmony_ci default: 312e5b75505Sopenharmony_ci return "802.11b"; 313e5b75505Sopenharmony_ci } 314e5b75505Sopenharmony_ci} 315e5b75505Sopenharmony_ci 316e5b75505Sopenharmony_ci 317e5b75505Sopenharmony_ciint radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta) 318e5b75505Sopenharmony_ci{ 319e5b75505Sopenharmony_ci int i; 320e5b75505Sopenharmony_ci u8 rate = 0; 321e5b75505Sopenharmony_ci 322e5b75505Sopenharmony_ci for (i = 0; i < sta->supported_rates_len; i++) 323e5b75505Sopenharmony_ci if ((sta->supported_rates[i] & 0x7f) > rate) 324e5b75505Sopenharmony_ci rate = sta->supported_rates[i] & 0x7f; 325e5b75505Sopenharmony_ci 326e5b75505Sopenharmony_ci return rate; 327e5b75505Sopenharmony_ci} 328e5b75505Sopenharmony_ci 329e5b75505Sopenharmony_ci 330e5b75505Sopenharmony_ci#ifndef CONFIG_NO_RADIUS 331e5b75505Sopenharmony_cistatic void ieee802_1x_learn_identity(struct hostapd_data *hapd, 332e5b75505Sopenharmony_ci struct eapol_state_machine *sm, 333e5b75505Sopenharmony_ci const u8 *eap, size_t len) 334e5b75505Sopenharmony_ci{ 335e5b75505Sopenharmony_ci const u8 *identity; 336e5b75505Sopenharmony_ci size_t identity_len; 337e5b75505Sopenharmony_ci const struct eap_hdr *hdr = (const struct eap_hdr *) eap; 338e5b75505Sopenharmony_ci 339e5b75505Sopenharmony_ci if (len <= sizeof(struct eap_hdr) || 340e5b75505Sopenharmony_ci (hdr->code == EAP_CODE_RESPONSE && 341e5b75505Sopenharmony_ci eap[sizeof(struct eap_hdr)] != EAP_TYPE_IDENTITY) || 342e5b75505Sopenharmony_ci (hdr->code == EAP_CODE_INITIATE && 343e5b75505Sopenharmony_ci eap[sizeof(struct eap_hdr)] != EAP_ERP_TYPE_REAUTH) || 344e5b75505Sopenharmony_ci (hdr->code != EAP_CODE_RESPONSE && 345e5b75505Sopenharmony_ci hdr->code != EAP_CODE_INITIATE)) 346e5b75505Sopenharmony_ci return; 347e5b75505Sopenharmony_ci 348e5b75505Sopenharmony_ci eap_erp_update_identity(sm->eap, eap, len); 349e5b75505Sopenharmony_ci identity = eap_get_identity(sm->eap, &identity_len); 350e5b75505Sopenharmony_ci if (identity == NULL) 351e5b75505Sopenharmony_ci return; 352e5b75505Sopenharmony_ci 353e5b75505Sopenharmony_ci /* Save station identity for future RADIUS packets */ 354e5b75505Sopenharmony_ci os_free(sm->identity); 355e5b75505Sopenharmony_ci sm->identity = (u8 *) dup_binstr(identity, identity_len); 356e5b75505Sopenharmony_ci if (sm->identity == NULL) { 357e5b75505Sopenharmony_ci sm->identity_len = 0; 358e5b75505Sopenharmony_ci return; 359e5b75505Sopenharmony_ci } 360e5b75505Sopenharmony_ci 361e5b75505Sopenharmony_ci sm->identity_len = identity_len; 362e5b75505Sopenharmony_ci hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, 363e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, "STA identity '%s'", sm->identity); 364e5b75505Sopenharmony_ci sm->dot1xAuthEapolRespIdFramesRx++; 365e5b75505Sopenharmony_ci} 366e5b75505Sopenharmony_ci 367e5b75505Sopenharmony_ci 368e5b75505Sopenharmony_cistatic int add_common_radius_sta_attr_rsn(struct hostapd_data *hapd, 369e5b75505Sopenharmony_ci struct hostapd_radius_attr *req_attr, 370e5b75505Sopenharmony_ci struct sta_info *sta, 371e5b75505Sopenharmony_ci struct radius_msg *msg) 372e5b75505Sopenharmony_ci{ 373e5b75505Sopenharmony_ci u32 suite; 374e5b75505Sopenharmony_ci int ver, val; 375e5b75505Sopenharmony_ci 376e5b75505Sopenharmony_ci ver = wpa_auth_sta_wpa_version(sta->wpa_sm); 377e5b75505Sopenharmony_ci val = wpa_auth_get_pairwise(sta->wpa_sm); 378e5b75505Sopenharmony_ci suite = wpa_cipher_to_suite(ver, val); 379e5b75505Sopenharmony_ci if (val != -1 && 380e5b75505Sopenharmony_ci !hostapd_config_get_radius_attr(req_attr, 381e5b75505Sopenharmony_ci RADIUS_ATTR_WLAN_PAIRWISE_CIPHER) && 382e5b75505Sopenharmony_ci !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_PAIRWISE_CIPHER, 383e5b75505Sopenharmony_ci suite)) { 384e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Could not add WLAN-Pairwise-Cipher"); 385e5b75505Sopenharmony_ci return -1; 386e5b75505Sopenharmony_ci } 387e5b75505Sopenharmony_ci 388e5b75505Sopenharmony_ci suite = wpa_cipher_to_suite(((hapd->conf->wpa & 0x2) || 389e5b75505Sopenharmony_ci hapd->conf->osen) ? 390e5b75505Sopenharmony_ci WPA_PROTO_RSN : WPA_PROTO_WPA, 391e5b75505Sopenharmony_ci hapd->conf->wpa_group); 392e5b75505Sopenharmony_ci if (!hostapd_config_get_radius_attr(req_attr, 393e5b75505Sopenharmony_ci RADIUS_ATTR_WLAN_GROUP_CIPHER) && 394e5b75505Sopenharmony_ci !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_GROUP_CIPHER, 395e5b75505Sopenharmony_ci suite)) { 396e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Could not add WLAN-Group-Cipher"); 397e5b75505Sopenharmony_ci return -1; 398e5b75505Sopenharmony_ci } 399e5b75505Sopenharmony_ci 400e5b75505Sopenharmony_ci val = wpa_auth_sta_key_mgmt(sta->wpa_sm); 401e5b75505Sopenharmony_ci suite = wpa_akm_to_suite(val); 402e5b75505Sopenharmony_ci if (val != -1 && 403e5b75505Sopenharmony_ci !hostapd_config_get_radius_attr(req_attr, 404e5b75505Sopenharmony_ci RADIUS_ATTR_WLAN_AKM_SUITE) && 405e5b75505Sopenharmony_ci !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_AKM_SUITE, 406e5b75505Sopenharmony_ci suite)) { 407e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Could not add WLAN-AKM-Suite"); 408e5b75505Sopenharmony_ci return -1; 409e5b75505Sopenharmony_ci } 410e5b75505Sopenharmony_ci 411e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211W 412e5b75505Sopenharmony_ci if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { 413e5b75505Sopenharmony_ci suite = wpa_cipher_to_suite(WPA_PROTO_RSN, 414e5b75505Sopenharmony_ci hapd->conf->group_mgmt_cipher); 415e5b75505Sopenharmony_ci if (!hostapd_config_get_radius_attr( 416e5b75505Sopenharmony_ci req_attr, RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER) && 417e5b75505Sopenharmony_ci !radius_msg_add_attr_int32( 418e5b75505Sopenharmony_ci msg, RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER, suite)) { 419e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 420e5b75505Sopenharmony_ci "Could not add WLAN-Group-Mgmt-Cipher"); 421e5b75505Sopenharmony_ci return -1; 422e5b75505Sopenharmony_ci } 423e5b75505Sopenharmony_ci } 424e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211W */ 425e5b75505Sopenharmony_ci 426e5b75505Sopenharmony_ci return 0; 427e5b75505Sopenharmony_ci} 428e5b75505Sopenharmony_ci 429e5b75505Sopenharmony_ci 430e5b75505Sopenharmony_cistatic int add_common_radius_sta_attr(struct hostapd_data *hapd, 431e5b75505Sopenharmony_ci struct hostapd_radius_attr *req_attr, 432e5b75505Sopenharmony_ci struct sta_info *sta, 433e5b75505Sopenharmony_ci struct radius_msg *msg) 434e5b75505Sopenharmony_ci{ 435e5b75505Sopenharmony_ci char buf[128]; 436e5b75505Sopenharmony_ci 437e5b75505Sopenharmony_ci if (!hostapd_config_get_radius_attr(req_attr, 438e5b75505Sopenharmony_ci RADIUS_ATTR_SERVICE_TYPE) && 439e5b75505Sopenharmony_ci !radius_msg_add_attr_int32(msg, RADIUS_ATTR_SERVICE_TYPE, 440e5b75505Sopenharmony_ci RADIUS_SERVICE_TYPE_FRAMED)) { 441e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Could not add Service-Type"); 442e5b75505Sopenharmony_ci return -1; 443e5b75505Sopenharmony_ci } 444e5b75505Sopenharmony_ci 445e5b75505Sopenharmony_ci if (!hostapd_config_get_radius_attr(req_attr, 446e5b75505Sopenharmony_ci RADIUS_ATTR_NAS_PORT) && 447e5b75505Sopenharmony_ci sta->aid > 0 && 448e5b75505Sopenharmony_ci !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) { 449e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Could not add NAS-Port"); 450e5b75505Sopenharmony_ci return -1; 451e5b75505Sopenharmony_ci } 452e5b75505Sopenharmony_ci 453e5b75505Sopenharmony_ci os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, 454e5b75505Sopenharmony_ci MAC2STR(sta->addr)); 455e5b75505Sopenharmony_ci buf[sizeof(buf) - 1] = '\0'; 456e5b75505Sopenharmony_ci if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, 457e5b75505Sopenharmony_ci (u8 *) buf, os_strlen(buf))) { 458e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Could not add Calling-Station-Id"); 459e5b75505Sopenharmony_ci return -1; 460e5b75505Sopenharmony_ci } 461e5b75505Sopenharmony_ci 462e5b75505Sopenharmony_ci if (sta->flags & WLAN_STA_PREAUTH) { 463e5b75505Sopenharmony_ci os_strlcpy(buf, "IEEE 802.11i Pre-Authentication", 464e5b75505Sopenharmony_ci sizeof(buf)); 465e5b75505Sopenharmony_ci } else { 466e5b75505Sopenharmony_ci os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s", 467e5b75505Sopenharmony_ci radius_sta_rate(hapd, sta) / 2, 468e5b75505Sopenharmony_ci (radius_sta_rate(hapd, sta) & 1) ? ".5" : "", 469e5b75505Sopenharmony_ci radius_mode_txt(hapd)); 470e5b75505Sopenharmony_ci buf[sizeof(buf) - 1] = '\0'; 471e5b75505Sopenharmony_ci } 472e5b75505Sopenharmony_ci if (!hostapd_config_get_radius_attr(req_attr, 473e5b75505Sopenharmony_ci RADIUS_ATTR_CONNECT_INFO) && 474e5b75505Sopenharmony_ci !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, 475e5b75505Sopenharmony_ci (u8 *) buf, os_strlen(buf))) { 476e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Could not add Connect-Info"); 477e5b75505Sopenharmony_ci return -1; 478e5b75505Sopenharmony_ci } 479e5b75505Sopenharmony_ci 480e5b75505Sopenharmony_ci if (sta->acct_session_id) { 481e5b75505Sopenharmony_ci os_snprintf(buf, sizeof(buf), "%016llX", 482e5b75505Sopenharmony_ci (unsigned long long) sta->acct_session_id); 483e5b75505Sopenharmony_ci if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID, 484e5b75505Sopenharmony_ci (u8 *) buf, os_strlen(buf))) { 485e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Could not add Acct-Session-Id"); 486e5b75505Sopenharmony_ci return -1; 487e5b75505Sopenharmony_ci } 488e5b75505Sopenharmony_ci } 489e5b75505Sopenharmony_ci 490e5b75505Sopenharmony_ci if ((hapd->conf->wpa & 2) && 491e5b75505Sopenharmony_ci !hapd->conf->disable_pmksa_caching && 492e5b75505Sopenharmony_ci sta->eapol_sm && sta->eapol_sm->acct_multi_session_id) { 493e5b75505Sopenharmony_ci os_snprintf(buf, sizeof(buf), "%016llX", 494e5b75505Sopenharmony_ci (unsigned long long) 495e5b75505Sopenharmony_ci sta->eapol_sm->acct_multi_session_id); 496e5b75505Sopenharmony_ci if (!radius_msg_add_attr( 497e5b75505Sopenharmony_ci msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID, 498e5b75505Sopenharmony_ci (u8 *) buf, os_strlen(buf))) { 499e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 500e5b75505Sopenharmony_ci "Could not add Acct-Multi-Session-Id"); 501e5b75505Sopenharmony_ci return -1; 502e5b75505Sopenharmony_ci } 503e5b75505Sopenharmony_ci } 504e5b75505Sopenharmony_ci 505e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211R_AP 506e5b75505Sopenharmony_ci if (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) && 507e5b75505Sopenharmony_ci sta->wpa_sm && 508e5b75505Sopenharmony_ci (wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm)) || 509e5b75505Sopenharmony_ci sta->auth_alg == WLAN_AUTH_FT) && 510e5b75505Sopenharmony_ci !hostapd_config_get_radius_attr(req_attr, 511e5b75505Sopenharmony_ci RADIUS_ATTR_MOBILITY_DOMAIN_ID) && 512e5b75505Sopenharmony_ci !radius_msg_add_attr_int32(msg, RADIUS_ATTR_MOBILITY_DOMAIN_ID, 513e5b75505Sopenharmony_ci WPA_GET_BE16( 514e5b75505Sopenharmony_ci hapd->conf->mobility_domain))) { 515e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Could not add Mobility-Domain-Id"); 516e5b75505Sopenharmony_ci return -1; 517e5b75505Sopenharmony_ci } 518e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211R_AP */ 519e5b75505Sopenharmony_ci 520e5b75505Sopenharmony_ci if ((hapd->conf->wpa || hapd->conf->osen) && sta->wpa_sm && 521e5b75505Sopenharmony_ci add_common_radius_sta_attr_rsn(hapd, req_attr, sta, msg) < 0) 522e5b75505Sopenharmony_ci return -1; 523e5b75505Sopenharmony_ci 524e5b75505Sopenharmony_ci return 0; 525e5b75505Sopenharmony_ci} 526e5b75505Sopenharmony_ci 527e5b75505Sopenharmony_ci 528e5b75505Sopenharmony_ciint add_common_radius_attr(struct hostapd_data *hapd, 529e5b75505Sopenharmony_ci struct hostapd_radius_attr *req_attr, 530e5b75505Sopenharmony_ci struct sta_info *sta, 531e5b75505Sopenharmony_ci struct radius_msg *msg) 532e5b75505Sopenharmony_ci{ 533e5b75505Sopenharmony_ci char buf[128]; 534e5b75505Sopenharmony_ci struct hostapd_radius_attr *attr; 535e5b75505Sopenharmony_ci int len; 536e5b75505Sopenharmony_ci 537e5b75505Sopenharmony_ci if (!hostapd_config_get_radius_attr(req_attr, 538e5b75505Sopenharmony_ci RADIUS_ATTR_NAS_IP_ADDRESS) && 539e5b75505Sopenharmony_ci hapd->conf->own_ip_addr.af == AF_INET && 540e5b75505Sopenharmony_ci !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, 541e5b75505Sopenharmony_ci (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) { 542e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Could not add NAS-IP-Address"); 543e5b75505Sopenharmony_ci return -1; 544e5b75505Sopenharmony_ci } 545e5b75505Sopenharmony_ci 546e5b75505Sopenharmony_ci#ifdef CONFIG_IPV6 547e5b75505Sopenharmony_ci if (!hostapd_config_get_radius_attr(req_attr, 548e5b75505Sopenharmony_ci RADIUS_ATTR_NAS_IPV6_ADDRESS) && 549e5b75505Sopenharmony_ci hapd->conf->own_ip_addr.af == AF_INET6 && 550e5b75505Sopenharmony_ci !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS, 551e5b75505Sopenharmony_ci (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) { 552e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Could not add NAS-IPv6-Address"); 553e5b75505Sopenharmony_ci return -1; 554e5b75505Sopenharmony_ci } 555e5b75505Sopenharmony_ci#endif /* CONFIG_IPV6 */ 556e5b75505Sopenharmony_ci 557e5b75505Sopenharmony_ci if (!hostapd_config_get_radius_attr(req_attr, 558e5b75505Sopenharmony_ci RADIUS_ATTR_NAS_IDENTIFIER) && 559e5b75505Sopenharmony_ci hapd->conf->nas_identifier && 560e5b75505Sopenharmony_ci !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER, 561e5b75505Sopenharmony_ci (u8 *) hapd->conf->nas_identifier, 562e5b75505Sopenharmony_ci os_strlen(hapd->conf->nas_identifier))) { 563e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Could not add NAS-Identifier"); 564e5b75505Sopenharmony_ci return -1; 565e5b75505Sopenharmony_ci } 566e5b75505Sopenharmony_ci 567e5b75505Sopenharmony_ci len = os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":", 568e5b75505Sopenharmony_ci MAC2STR(hapd->own_addr)); 569e5b75505Sopenharmony_ci os_memcpy(&buf[len], hapd->conf->ssid.ssid, 570e5b75505Sopenharmony_ci hapd->conf->ssid.ssid_len); 571e5b75505Sopenharmony_ci len += hapd->conf->ssid.ssid_len; 572e5b75505Sopenharmony_ci if (!hostapd_config_get_radius_attr(req_attr, 573e5b75505Sopenharmony_ci RADIUS_ATTR_CALLED_STATION_ID) && 574e5b75505Sopenharmony_ci !radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID, 575e5b75505Sopenharmony_ci (u8 *) buf, len)) { 576e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Could not add Called-Station-Id"); 577e5b75505Sopenharmony_ci return -1; 578e5b75505Sopenharmony_ci } 579e5b75505Sopenharmony_ci 580e5b75505Sopenharmony_ci if (!hostapd_config_get_radius_attr(req_attr, 581e5b75505Sopenharmony_ci RADIUS_ATTR_NAS_PORT_TYPE) && 582e5b75505Sopenharmony_ci !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE, 583e5b75505Sopenharmony_ci RADIUS_NAS_PORT_TYPE_IEEE_802_11)) { 584e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Could not add NAS-Port-Type"); 585e5b75505Sopenharmony_ci return -1; 586e5b75505Sopenharmony_ci } 587e5b75505Sopenharmony_ci 588e5b75505Sopenharmony_ci#ifdef CONFIG_INTERWORKING 589e5b75505Sopenharmony_ci if (hapd->conf->interworking && 590e5b75505Sopenharmony_ci !is_zero_ether_addr(hapd->conf->hessid)) { 591e5b75505Sopenharmony_ci os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, 592e5b75505Sopenharmony_ci MAC2STR(hapd->conf->hessid)); 593e5b75505Sopenharmony_ci buf[sizeof(buf) - 1] = '\0'; 594e5b75505Sopenharmony_ci if (!hostapd_config_get_radius_attr(req_attr, 595e5b75505Sopenharmony_ci RADIUS_ATTR_WLAN_HESSID) && 596e5b75505Sopenharmony_ci !radius_msg_add_attr(msg, RADIUS_ATTR_WLAN_HESSID, 597e5b75505Sopenharmony_ci (u8 *) buf, os_strlen(buf))) { 598e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Could not add WLAN-HESSID"); 599e5b75505Sopenharmony_ci return -1; 600e5b75505Sopenharmony_ci } 601e5b75505Sopenharmony_ci } 602e5b75505Sopenharmony_ci#endif /* CONFIG_INTERWORKING */ 603e5b75505Sopenharmony_ci 604e5b75505Sopenharmony_ci if (sta && add_common_radius_sta_attr(hapd, req_attr, sta, msg) < 0) 605e5b75505Sopenharmony_ci return -1; 606e5b75505Sopenharmony_ci 607e5b75505Sopenharmony_ci for (attr = req_attr; attr; attr = attr->next) { 608e5b75505Sopenharmony_ci if (!radius_msg_add_attr(msg, attr->type, 609e5b75505Sopenharmony_ci wpabuf_head(attr->val), 610e5b75505Sopenharmony_ci wpabuf_len(attr->val))) { 611e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Could not add RADIUS " 612e5b75505Sopenharmony_ci "attribute"); 613e5b75505Sopenharmony_ci return -1; 614e5b75505Sopenharmony_ci } 615e5b75505Sopenharmony_ci } 616e5b75505Sopenharmony_ci 617e5b75505Sopenharmony_ci return 0; 618e5b75505Sopenharmony_ci} 619e5b75505Sopenharmony_ci 620e5b75505Sopenharmony_ci 621e5b75505Sopenharmony_ciint add_sqlite_radius_attr(struct hostapd_data *hapd, struct sta_info *sta, 622e5b75505Sopenharmony_ci struct radius_msg *msg, int acct) 623e5b75505Sopenharmony_ci{ 624e5b75505Sopenharmony_ci#ifdef CONFIG_SQLITE 625e5b75505Sopenharmony_ci const char *attrtxt; 626e5b75505Sopenharmony_ci char addrtxt[3 * ETH_ALEN]; 627e5b75505Sopenharmony_ci char *sql; 628e5b75505Sopenharmony_ci sqlite3_stmt *stmt = NULL; 629e5b75505Sopenharmony_ci 630e5b75505Sopenharmony_ci if (!hapd->rad_attr_db) 631e5b75505Sopenharmony_ci return 0; 632e5b75505Sopenharmony_ci 633e5b75505Sopenharmony_ci os_snprintf(addrtxt, sizeof(addrtxt), MACSTR, MAC2STR(sta->addr)); 634e5b75505Sopenharmony_ci 635e5b75505Sopenharmony_ci sql = "SELECT attr FROM radius_attributes WHERE sta=? AND (reqtype=? OR reqtype IS NULL);"; 636e5b75505Sopenharmony_ci if (sqlite3_prepare_v2(hapd->rad_attr_db, sql, os_strlen(sql), &stmt, 637e5b75505Sopenharmony_ci NULL) != SQLITE_OK) { 638e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "DB: Failed to prepare SQL statement: %s", 639e5b75505Sopenharmony_ci sqlite3_errmsg(hapd->rad_attr_db)); 640e5b75505Sopenharmony_ci return -1; 641e5b75505Sopenharmony_ci } 642e5b75505Sopenharmony_ci sqlite3_bind_text(stmt, 1, addrtxt, os_strlen(addrtxt), SQLITE_STATIC); 643e5b75505Sopenharmony_ci sqlite3_bind_text(stmt, 2, acct ? "acct" : "auth", 4, SQLITE_STATIC); 644e5b75505Sopenharmony_ci while (sqlite3_step(stmt) == SQLITE_ROW) { 645e5b75505Sopenharmony_ci struct hostapd_radius_attr *attr; 646e5b75505Sopenharmony_ci struct radius_attr_hdr *hdr; 647e5b75505Sopenharmony_ci 648e5b75505Sopenharmony_ci attrtxt = (const char *) sqlite3_column_text(stmt, 0); 649e5b75505Sopenharmony_ci attr = hostapd_parse_radius_attr(attrtxt); 650e5b75505Sopenharmony_ci if (!attr) { 651e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 652e5b75505Sopenharmony_ci "Skipping invalid attribute from SQL: %s", 653e5b75505Sopenharmony_ci attrtxt); 654e5b75505Sopenharmony_ci continue; 655e5b75505Sopenharmony_ci } 656e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Adding RADIUS attribute from SQL: %s", 657e5b75505Sopenharmony_ci attrtxt); 658e5b75505Sopenharmony_ci hdr = radius_msg_add_attr(msg, attr->type, 659e5b75505Sopenharmony_ci wpabuf_head(attr->val), 660e5b75505Sopenharmony_ci wpabuf_len(attr->val)); 661e5b75505Sopenharmony_ci hostapd_config_free_radius_attr(attr); 662e5b75505Sopenharmony_ci if (!hdr) { 663e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 664e5b75505Sopenharmony_ci "Could not add RADIUS attribute from SQL"); 665e5b75505Sopenharmony_ci continue; 666e5b75505Sopenharmony_ci } 667e5b75505Sopenharmony_ci } 668e5b75505Sopenharmony_ci 669e5b75505Sopenharmony_ci sqlite3_reset(stmt); 670e5b75505Sopenharmony_ci sqlite3_clear_bindings(stmt); 671e5b75505Sopenharmony_ci sqlite3_finalize(stmt); 672e5b75505Sopenharmony_ci#endif /* CONFIG_SQLITE */ 673e5b75505Sopenharmony_ci 674e5b75505Sopenharmony_ci return 0; 675e5b75505Sopenharmony_ci} 676e5b75505Sopenharmony_ci 677e5b75505Sopenharmony_ci 678e5b75505Sopenharmony_civoid ieee802_1x_encapsulate_radius(struct hostapd_data *hapd, 679e5b75505Sopenharmony_ci struct sta_info *sta, 680e5b75505Sopenharmony_ci const u8 *eap, size_t len) 681e5b75505Sopenharmony_ci{ 682e5b75505Sopenharmony_ci struct radius_msg *msg; 683e5b75505Sopenharmony_ci struct eapol_state_machine *sm = sta->eapol_sm; 684e5b75505Sopenharmony_ci 685e5b75505Sopenharmony_ci if (sm == NULL) 686e5b75505Sopenharmony_ci return; 687e5b75505Sopenharmony_ci 688e5b75505Sopenharmony_ci ieee802_1x_learn_identity(hapd, sm, eap, len); 689e5b75505Sopenharmony_ci 690e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS " 691e5b75505Sopenharmony_ci "packet"); 692e5b75505Sopenharmony_ci 693e5b75505Sopenharmony_ci sm->radius_identifier = radius_client_get_id(hapd->radius); 694e5b75505Sopenharmony_ci msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, 695e5b75505Sopenharmony_ci sm->radius_identifier); 696e5b75505Sopenharmony_ci if (msg == NULL) { 697e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "Could not create new RADIUS packet"); 698e5b75505Sopenharmony_ci return; 699e5b75505Sopenharmony_ci } 700e5b75505Sopenharmony_ci 701e5b75505Sopenharmony_ci if (radius_msg_make_authenticator(msg) < 0) { 702e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "Could not make Request Authenticator"); 703e5b75505Sopenharmony_ci goto fail; 704e5b75505Sopenharmony_ci } 705e5b75505Sopenharmony_ci 706e5b75505Sopenharmony_ci if (sm->identity && 707e5b75505Sopenharmony_ci !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, 708e5b75505Sopenharmony_ci sm->identity, sm->identity_len)) { 709e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "Could not add User-Name"); 710e5b75505Sopenharmony_ci goto fail; 711e5b75505Sopenharmony_ci } 712e5b75505Sopenharmony_ci 713e5b75505Sopenharmony_ci if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr, sta, 714e5b75505Sopenharmony_ci msg) < 0) 715e5b75505Sopenharmony_ci goto fail; 716e5b75505Sopenharmony_ci 717e5b75505Sopenharmony_ci if (sta && add_sqlite_radius_attr(hapd, sta, msg, 0) < 0) 718e5b75505Sopenharmony_ci goto fail; 719e5b75505Sopenharmony_ci 720e5b75505Sopenharmony_ci /* TODO: should probably check MTU from driver config; 2304 is max for 721e5b75505Sopenharmony_ci * IEEE 802.11, but use 1400 to avoid problems with too large packets 722e5b75505Sopenharmony_ci */ 723e5b75505Sopenharmony_ci if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr, 724e5b75505Sopenharmony_ci RADIUS_ATTR_FRAMED_MTU) && 725e5b75505Sopenharmony_ci !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) { 726e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "Could not add Framed-MTU"); 727e5b75505Sopenharmony_ci goto fail; 728e5b75505Sopenharmony_ci } 729e5b75505Sopenharmony_ci 730e5b75505Sopenharmony_ci if (!radius_msg_add_eap(msg, eap, len)) { 731e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "Could not add EAP-Message"); 732e5b75505Sopenharmony_ci goto fail; 733e5b75505Sopenharmony_ci } 734e5b75505Sopenharmony_ci 735e5b75505Sopenharmony_ci /* State attribute must be copied if and only if this packet is 736e5b75505Sopenharmony_ci * Access-Request reply to the previous Access-Challenge */ 737e5b75505Sopenharmony_ci if (sm->last_recv_radius && 738e5b75505Sopenharmony_ci radius_msg_get_hdr(sm->last_recv_radius)->code == 739e5b75505Sopenharmony_ci RADIUS_CODE_ACCESS_CHALLENGE) { 740e5b75505Sopenharmony_ci int res = radius_msg_copy_attr(msg, sm->last_recv_radius, 741e5b75505Sopenharmony_ci RADIUS_ATTR_STATE); 742e5b75505Sopenharmony_ci if (res < 0) { 743e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "Could not copy State attribute from previous Access-Challenge"); 744e5b75505Sopenharmony_ci goto fail; 745e5b75505Sopenharmony_ci } 746e5b75505Sopenharmony_ci if (res > 0) { 747e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Copied RADIUS State Attribute"); 748e5b75505Sopenharmony_ci } 749e5b75505Sopenharmony_ci } 750e5b75505Sopenharmony_ci 751e5b75505Sopenharmony_ci if (hapd->conf->radius_request_cui) { 752e5b75505Sopenharmony_ci const u8 *cui; 753e5b75505Sopenharmony_ci size_t cui_len; 754e5b75505Sopenharmony_ci /* Add previously learned CUI or nul CUI to request CUI */ 755e5b75505Sopenharmony_ci if (sm->radius_cui) { 756e5b75505Sopenharmony_ci cui = wpabuf_head(sm->radius_cui); 757e5b75505Sopenharmony_ci cui_len = wpabuf_len(sm->radius_cui); 758e5b75505Sopenharmony_ci } else { 759e5b75505Sopenharmony_ci cui = (const u8 *) "\0"; 760e5b75505Sopenharmony_ci cui_len = 1; 761e5b75505Sopenharmony_ci } 762e5b75505Sopenharmony_ci if (!radius_msg_add_attr(msg, 763e5b75505Sopenharmony_ci RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, 764e5b75505Sopenharmony_ci cui, cui_len)) { 765e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Could not add CUI"); 766e5b75505Sopenharmony_ci goto fail; 767e5b75505Sopenharmony_ci } 768e5b75505Sopenharmony_ci } 769e5b75505Sopenharmony_ci 770e5b75505Sopenharmony_ci#ifdef CONFIG_HS20 771e5b75505Sopenharmony_ci if (hapd->conf->hs20) { 772e5b75505Sopenharmony_ci u8 ver = hapd->conf->hs20_release - 1; 773e5b75505Sopenharmony_ci 774e5b75505Sopenharmony_ci if (!radius_msg_add_wfa( 775e5b75505Sopenharmony_ci msg, RADIUS_VENDOR_ATTR_WFA_HS20_AP_VERSION, 776e5b75505Sopenharmony_ci &ver, 1)) { 777e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Could not add HS 2.0 AP " 778e5b75505Sopenharmony_ci "version"); 779e5b75505Sopenharmony_ci goto fail; 780e5b75505Sopenharmony_ci } 781e5b75505Sopenharmony_ci 782e5b75505Sopenharmony_ci if (sta->hs20_ie && wpabuf_len(sta->hs20_ie) > 0) { 783e5b75505Sopenharmony_ci const u8 *pos; 784e5b75505Sopenharmony_ci u8 buf[3]; 785e5b75505Sopenharmony_ci u16 id; 786e5b75505Sopenharmony_ci pos = wpabuf_head_u8(sta->hs20_ie); 787e5b75505Sopenharmony_ci buf[0] = (*pos) >> 4; 788e5b75505Sopenharmony_ci if (((*pos) & HS20_PPS_MO_ID_PRESENT) && 789e5b75505Sopenharmony_ci wpabuf_len(sta->hs20_ie) >= 3) 790e5b75505Sopenharmony_ci id = WPA_GET_LE16(pos + 1); 791e5b75505Sopenharmony_ci else 792e5b75505Sopenharmony_ci id = 0; 793e5b75505Sopenharmony_ci WPA_PUT_BE16(buf + 1, id); 794e5b75505Sopenharmony_ci if (!radius_msg_add_wfa( 795e5b75505Sopenharmony_ci msg, 796e5b75505Sopenharmony_ci RADIUS_VENDOR_ATTR_WFA_HS20_STA_VERSION, 797e5b75505Sopenharmony_ci buf, sizeof(buf))) { 798e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, "Could not add HS 2.0 " 799e5b75505Sopenharmony_ci "STA version"); 800e5b75505Sopenharmony_ci goto fail; 801e5b75505Sopenharmony_ci } 802e5b75505Sopenharmony_ci } 803e5b75505Sopenharmony_ci 804e5b75505Sopenharmony_ci if (sta->roaming_consortium && 805e5b75505Sopenharmony_ci !radius_msg_add_wfa( 806e5b75505Sopenharmony_ci msg, RADIUS_VENDOR_ATTR_WFA_HS20_ROAMING_CONSORTIUM, 807e5b75505Sopenharmony_ci wpabuf_head(sta->roaming_consortium), 808e5b75505Sopenharmony_ci wpabuf_len(sta->roaming_consortium))) { 809e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 810e5b75505Sopenharmony_ci "Could not add HS 2.0 Roaming Consortium"); 811e5b75505Sopenharmony_ci goto fail; 812e5b75505Sopenharmony_ci } 813e5b75505Sopenharmony_ci 814e5b75505Sopenharmony_ci if (hapd->conf->t_c_filename) { 815e5b75505Sopenharmony_ci be32 timestamp; 816e5b75505Sopenharmony_ci 817e5b75505Sopenharmony_ci if (!radius_msg_add_wfa( 818e5b75505Sopenharmony_ci msg, 819e5b75505Sopenharmony_ci RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILENAME, 820e5b75505Sopenharmony_ci (const u8 *) hapd->conf->t_c_filename, 821e5b75505Sopenharmony_ci os_strlen(hapd->conf->t_c_filename))) { 822e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 823e5b75505Sopenharmony_ci "Could not add HS 2.0 T&C Filename"); 824e5b75505Sopenharmony_ci goto fail; 825e5b75505Sopenharmony_ci } 826e5b75505Sopenharmony_ci 827e5b75505Sopenharmony_ci timestamp = host_to_be32(hapd->conf->t_c_timestamp); 828e5b75505Sopenharmony_ci if (!radius_msg_add_wfa( 829e5b75505Sopenharmony_ci msg, 830e5b75505Sopenharmony_ci RADIUS_VENDOR_ATTR_WFA_HS20_TIMESTAMP, 831e5b75505Sopenharmony_ci (const u8 *) ×tamp, 832e5b75505Sopenharmony_ci sizeof(timestamp))) { 833e5b75505Sopenharmony_ci wpa_printf(MSG_ERROR, 834e5b75505Sopenharmony_ci "Could not add HS 2.0 Timestamp"); 835e5b75505Sopenharmony_ci goto fail; 836e5b75505Sopenharmony_ci } 837e5b75505Sopenharmony_ci } 838e5b75505Sopenharmony_ci } 839e5b75505Sopenharmony_ci#endif /* CONFIG_HS20 */ 840e5b75505Sopenharmony_ci 841e5b75505Sopenharmony_ci if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr) < 0) 842e5b75505Sopenharmony_ci goto fail; 843e5b75505Sopenharmony_ci 844e5b75505Sopenharmony_ci return; 845e5b75505Sopenharmony_ci 846e5b75505Sopenharmony_ci fail: 847e5b75505Sopenharmony_ci radius_msg_free(msg); 848e5b75505Sopenharmony_ci} 849e5b75505Sopenharmony_ci#endif /* CONFIG_NO_RADIUS */ 850e5b75505Sopenharmony_ci 851e5b75505Sopenharmony_ci 852e5b75505Sopenharmony_cistatic void handle_eap_response(struct hostapd_data *hapd, 853e5b75505Sopenharmony_ci struct sta_info *sta, struct eap_hdr *eap, 854e5b75505Sopenharmony_ci size_t len) 855e5b75505Sopenharmony_ci{ 856e5b75505Sopenharmony_ci u8 type, *data; 857e5b75505Sopenharmony_ci struct eapol_state_machine *sm = sta->eapol_sm; 858e5b75505Sopenharmony_ci if (sm == NULL) 859e5b75505Sopenharmony_ci return; 860e5b75505Sopenharmony_ci 861e5b75505Sopenharmony_ci data = (u8 *) (eap + 1); 862e5b75505Sopenharmony_ci 863e5b75505Sopenharmony_ci if (len < sizeof(*eap) + 1) { 864e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "handle_eap_response: too short response data"); 865e5b75505Sopenharmony_ci return; 866e5b75505Sopenharmony_ci } 867e5b75505Sopenharmony_ci 868e5b75505Sopenharmony_ci sm->eap_type_supp = type = data[0]; 869e5b75505Sopenharmony_ci 870e5b75505Sopenharmony_ci hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, 871e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d " 872e5b75505Sopenharmony_ci "id=%d len=%d) from STA: EAP Response-%s (%d)", 873e5b75505Sopenharmony_ci eap->code, eap->identifier, be_to_host16(eap->length), 874e5b75505Sopenharmony_ci eap_server_get_name(0, type), type); 875e5b75505Sopenharmony_ci 876e5b75505Sopenharmony_ci sm->dot1xAuthEapolRespFramesRx++; 877e5b75505Sopenharmony_ci 878e5b75505Sopenharmony_ci wpabuf_free(sm->eap_if->eapRespData); 879e5b75505Sopenharmony_ci sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len); 880e5b75505Sopenharmony_ci sm->eapolEap = TRUE; 881e5b75505Sopenharmony_ci} 882e5b75505Sopenharmony_ci 883e5b75505Sopenharmony_ci 884e5b75505Sopenharmony_cistatic void handle_eap_initiate(struct hostapd_data *hapd, 885e5b75505Sopenharmony_ci struct sta_info *sta, struct eap_hdr *eap, 886e5b75505Sopenharmony_ci size_t len) 887e5b75505Sopenharmony_ci{ 888e5b75505Sopenharmony_ci#ifdef CONFIG_ERP 889e5b75505Sopenharmony_ci u8 type, *data; 890e5b75505Sopenharmony_ci struct eapol_state_machine *sm = sta->eapol_sm; 891e5b75505Sopenharmony_ci 892e5b75505Sopenharmony_ci if (sm == NULL) 893e5b75505Sopenharmony_ci return; 894e5b75505Sopenharmony_ci 895e5b75505Sopenharmony_ci if (len < sizeof(*eap) + 1) { 896e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, 897e5b75505Sopenharmony_ci "handle_eap_initiate: too short response data"); 898e5b75505Sopenharmony_ci return; 899e5b75505Sopenharmony_ci } 900e5b75505Sopenharmony_ci 901e5b75505Sopenharmony_ci data = (u8 *) (eap + 1); 902e5b75505Sopenharmony_ci type = data[0]; 903e5b75505Sopenharmony_ci 904e5b75505Sopenharmony_ci hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X, 905e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d " 906e5b75505Sopenharmony_ci "id=%d len=%d) from STA: EAP Initiate type %u", 907e5b75505Sopenharmony_ci eap->code, eap->identifier, be_to_host16(eap->length), 908e5b75505Sopenharmony_ci type); 909e5b75505Sopenharmony_ci 910e5b75505Sopenharmony_ci wpabuf_free(sm->eap_if->eapRespData); 911e5b75505Sopenharmony_ci sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len); 912e5b75505Sopenharmony_ci sm->eapolEap = TRUE; 913e5b75505Sopenharmony_ci#endif /* CONFIG_ERP */ 914e5b75505Sopenharmony_ci} 915e5b75505Sopenharmony_ci 916e5b75505Sopenharmony_ci 917e5b75505Sopenharmony_ci/* Process incoming EAP packet from Supplicant */ 918e5b75505Sopenharmony_cistatic void handle_eap(struct hostapd_data *hapd, struct sta_info *sta, 919e5b75505Sopenharmony_ci u8 *buf, size_t len) 920e5b75505Sopenharmony_ci{ 921e5b75505Sopenharmony_ci struct eap_hdr *eap; 922e5b75505Sopenharmony_ci u16 eap_len; 923e5b75505Sopenharmony_ci 924e5b75505Sopenharmony_ci if (len < sizeof(*eap)) { 925e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, " too short EAP packet"); 926e5b75505Sopenharmony_ci return; 927e5b75505Sopenharmony_ci } 928e5b75505Sopenharmony_ci 929e5b75505Sopenharmony_ci eap = (struct eap_hdr *) buf; 930e5b75505Sopenharmony_ci 931e5b75505Sopenharmony_ci eap_len = be_to_host16(eap->length); 932e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "EAP: code=%d identifier=%d length=%d", 933e5b75505Sopenharmony_ci eap->code, eap->identifier, eap_len); 934e5b75505Sopenharmony_ci if (eap_len < sizeof(*eap)) { 935e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, " Invalid EAP length"); 936e5b75505Sopenharmony_ci return; 937e5b75505Sopenharmony_ci } else if (eap_len > len) { 938e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, " Too short frame to contain this EAP " 939e5b75505Sopenharmony_ci "packet"); 940e5b75505Sopenharmony_ci return; 941e5b75505Sopenharmony_ci } else if (eap_len < len) { 942e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, " Ignoring %lu extra bytes after EAP " 943e5b75505Sopenharmony_ci "packet", (unsigned long) len - eap_len); 944e5b75505Sopenharmony_ci } 945e5b75505Sopenharmony_ci 946e5b75505Sopenharmony_ci switch (eap->code) { 947e5b75505Sopenharmony_ci case EAP_CODE_REQUEST: 948e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, " (request)"); 949e5b75505Sopenharmony_ci return; 950e5b75505Sopenharmony_ci case EAP_CODE_RESPONSE: 951e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, " (response)"); 952e5b75505Sopenharmony_ci handle_eap_response(hapd, sta, eap, eap_len); 953e5b75505Sopenharmony_ci break; 954e5b75505Sopenharmony_ci case EAP_CODE_SUCCESS: 955e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, " (success)"); 956e5b75505Sopenharmony_ci return; 957e5b75505Sopenharmony_ci case EAP_CODE_FAILURE: 958e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, " (failure)"); 959e5b75505Sopenharmony_ci return; 960e5b75505Sopenharmony_ci case EAP_CODE_INITIATE: 961e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, " (initiate)"); 962e5b75505Sopenharmony_ci handle_eap_initiate(hapd, sta, eap, eap_len); 963e5b75505Sopenharmony_ci break; 964e5b75505Sopenharmony_ci case EAP_CODE_FINISH: 965e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, " (finish)"); 966e5b75505Sopenharmony_ci break; 967e5b75505Sopenharmony_ci default: 968e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, " (unknown code)"); 969e5b75505Sopenharmony_ci return; 970e5b75505Sopenharmony_ci } 971e5b75505Sopenharmony_ci} 972e5b75505Sopenharmony_ci 973e5b75505Sopenharmony_ci 974e5b75505Sopenharmony_cistruct eapol_state_machine * 975e5b75505Sopenharmony_ciieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta) 976e5b75505Sopenharmony_ci{ 977e5b75505Sopenharmony_ci int flags = 0; 978e5b75505Sopenharmony_ci if (sta->flags & WLAN_STA_PREAUTH) 979e5b75505Sopenharmony_ci flags |= EAPOL_SM_PREAUTH; 980e5b75505Sopenharmony_ci if (sta->wpa_sm) { 981e5b75505Sopenharmony_ci flags |= EAPOL_SM_USES_WPA; 982e5b75505Sopenharmony_ci if (wpa_auth_sta_get_pmksa(sta->wpa_sm)) 983e5b75505Sopenharmony_ci flags |= EAPOL_SM_FROM_PMKSA_CACHE; 984e5b75505Sopenharmony_ci } 985e5b75505Sopenharmony_ci return eapol_auth_alloc(hapd->eapol_auth, sta->addr, flags, 986e5b75505Sopenharmony_ci sta->wps_ie, sta->p2p_ie, sta, 987e5b75505Sopenharmony_ci sta->identity, sta->radius_cui); 988e5b75505Sopenharmony_ci} 989e5b75505Sopenharmony_ci 990e5b75505Sopenharmony_ci 991e5b75505Sopenharmony_cistatic void ieee802_1x_save_eapol(struct sta_info *sta, const u8 *buf, 992e5b75505Sopenharmony_ci size_t len) 993e5b75505Sopenharmony_ci{ 994e5b75505Sopenharmony_ci if (sta->pending_eapol_rx) { 995e5b75505Sopenharmony_ci wpabuf_free(sta->pending_eapol_rx->buf); 996e5b75505Sopenharmony_ci } else { 997e5b75505Sopenharmony_ci sta->pending_eapol_rx = 998e5b75505Sopenharmony_ci os_malloc(sizeof(*sta->pending_eapol_rx)); 999e5b75505Sopenharmony_ci if (!sta->pending_eapol_rx) 1000e5b75505Sopenharmony_ci return; 1001e5b75505Sopenharmony_ci } 1002e5b75505Sopenharmony_ci 1003e5b75505Sopenharmony_ci sta->pending_eapol_rx->buf = wpabuf_alloc_copy(buf, len); 1004e5b75505Sopenharmony_ci if (!sta->pending_eapol_rx->buf) { 1005e5b75505Sopenharmony_ci os_free(sta->pending_eapol_rx); 1006e5b75505Sopenharmony_ci sta->pending_eapol_rx = NULL; 1007e5b75505Sopenharmony_ci return; 1008e5b75505Sopenharmony_ci } 1009e5b75505Sopenharmony_ci 1010e5b75505Sopenharmony_ci os_get_reltime(&sta->pending_eapol_rx->rx_time); 1011e5b75505Sopenharmony_ci} 1012e5b75505Sopenharmony_ci 1013e5b75505Sopenharmony_ci 1014e5b75505Sopenharmony_ci/** 1015e5b75505Sopenharmony_ci * ieee802_1x_receive - Process the EAPOL frames from the Supplicant 1016e5b75505Sopenharmony_ci * @hapd: hostapd BSS data 1017e5b75505Sopenharmony_ci * @sa: Source address (sender of the EAPOL frame) 1018e5b75505Sopenharmony_ci * @buf: EAPOL frame 1019e5b75505Sopenharmony_ci * @len: Length of buf in octets 1020e5b75505Sopenharmony_ci * 1021e5b75505Sopenharmony_ci * This function is called for each incoming EAPOL frame from the interface 1022e5b75505Sopenharmony_ci */ 1023e5b75505Sopenharmony_civoid ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf, 1024e5b75505Sopenharmony_ci size_t len) 1025e5b75505Sopenharmony_ci{ 1026e5b75505Sopenharmony_ci struct sta_info *sta; 1027e5b75505Sopenharmony_ci struct ieee802_1x_hdr *hdr; 1028e5b75505Sopenharmony_ci struct ieee802_1x_eapol_key *key; 1029e5b75505Sopenharmony_ci u16 datalen; 1030e5b75505Sopenharmony_ci struct rsn_pmksa_cache_entry *pmksa; 1031e5b75505Sopenharmony_ci int key_mgmt; 1032e5b75505Sopenharmony_ci 1033e5b75505Sopenharmony_ci if (!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->osen && 1034e5b75505Sopenharmony_ci !hapd->conf->wps_state) 1035e5b75505Sopenharmony_ci return; 1036e5b75505Sopenharmony_ci 1037e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR, 1038e5b75505Sopenharmony_ci (unsigned long) len, MAC2STR(sa)); 1039e5b75505Sopenharmony_ci sta = ap_get_sta(hapd, sa); 1040e5b75505Sopenharmony_ci if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) && 1041e5b75505Sopenharmony_ci !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) { 1042e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not " 1043e5b75505Sopenharmony_ci "associated/Pre-authenticating STA"); 1044e5b75505Sopenharmony_ci 1045e5b75505Sopenharmony_ci if (sta && (sta->flags & WLAN_STA_AUTH)) { 1046e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Saving EAPOL frame from " MACSTR 1047e5b75505Sopenharmony_ci " for later use", MAC2STR(sta->addr)); 1048e5b75505Sopenharmony_ci ieee802_1x_save_eapol(sta, buf, len); 1049e5b75505Sopenharmony_ci } 1050e5b75505Sopenharmony_ci 1051e5b75505Sopenharmony_ci return; 1052e5b75505Sopenharmony_ci } 1053e5b75505Sopenharmony_ci 1054e5b75505Sopenharmony_ci if (len < sizeof(*hdr)) { 1055e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, " too short IEEE 802.1X packet"); 1056e5b75505Sopenharmony_ci return; 1057e5b75505Sopenharmony_ci } 1058e5b75505Sopenharmony_ci 1059e5b75505Sopenharmony_ci hdr = (struct ieee802_1x_hdr *) buf; 1060e5b75505Sopenharmony_ci datalen = be_to_host16(hdr->length); 1061e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, " IEEE 802.1X: version=%d type=%d length=%d", 1062e5b75505Sopenharmony_ci hdr->version, hdr->type, datalen); 1063e5b75505Sopenharmony_ci 1064e5b75505Sopenharmony_ci if (len - sizeof(*hdr) < datalen) { 1065e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, " frame too short for this IEEE 802.1X packet"); 1066e5b75505Sopenharmony_ci if (sta->eapol_sm) 1067e5b75505Sopenharmony_ci sta->eapol_sm->dot1xAuthEapLengthErrorFramesRx++; 1068e5b75505Sopenharmony_ci return; 1069e5b75505Sopenharmony_ci } 1070e5b75505Sopenharmony_ci if (len - sizeof(*hdr) > datalen) { 1071e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, " ignoring %lu extra octets after " 1072e5b75505Sopenharmony_ci "IEEE 802.1X packet", 1073e5b75505Sopenharmony_ci (unsigned long) len - sizeof(*hdr) - datalen); 1074e5b75505Sopenharmony_ci } 1075e5b75505Sopenharmony_ci 1076e5b75505Sopenharmony_ci if (sta->eapol_sm) { 1077e5b75505Sopenharmony_ci sta->eapol_sm->dot1xAuthLastEapolFrameVersion = hdr->version; 1078e5b75505Sopenharmony_ci sta->eapol_sm->dot1xAuthEapolFramesRx++; 1079e5b75505Sopenharmony_ci } 1080e5b75505Sopenharmony_ci 1081e5b75505Sopenharmony_ci key = (struct ieee802_1x_eapol_key *) (hdr + 1); 1082e5b75505Sopenharmony_ci if (datalen >= sizeof(struct ieee802_1x_eapol_key) && 1083e5b75505Sopenharmony_ci hdr->type == IEEE802_1X_TYPE_EAPOL_KEY && 1084e5b75505Sopenharmony_ci (key->type == EAPOL_KEY_TYPE_WPA || 1085e5b75505Sopenharmony_ci key->type == EAPOL_KEY_TYPE_RSN)) { 1086e5b75505Sopenharmony_ci wpa_receive(hapd->wpa_auth, sta->wpa_sm, (u8 *) hdr, 1087e5b75505Sopenharmony_ci sizeof(*hdr) + datalen); 1088e5b75505Sopenharmony_ci return; 1089e5b75505Sopenharmony_ci } 1090e5b75505Sopenharmony_ci 1091e5b75505Sopenharmony_ci if (!hapd->conf->ieee802_1x && !hapd->conf->osen && 1092e5b75505Sopenharmony_ci !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) { 1093e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - " 1094e5b75505Sopenharmony_ci "802.1X not enabled and WPS not used"); 1095e5b75505Sopenharmony_ci return; 1096e5b75505Sopenharmony_ci } 1097e5b75505Sopenharmony_ci 1098e5b75505Sopenharmony_ci key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm); 1099e5b75505Sopenharmony_ci if (key_mgmt != -1 && 1100e5b75505Sopenharmony_ci (wpa_key_mgmt_wpa_psk(key_mgmt) || key_mgmt == WPA_KEY_MGMT_OWE || 1101e5b75505Sopenharmony_ci key_mgmt == WPA_KEY_MGMT_DPP)) { 1102e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - " 1103e5b75505Sopenharmony_ci "STA is using PSK"); 1104e5b75505Sopenharmony_ci return; 1105e5b75505Sopenharmony_ci } 1106e5b75505Sopenharmony_ci 1107e5b75505Sopenharmony_ci if (!sta->eapol_sm) { 1108e5b75505Sopenharmony_ci sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta); 1109e5b75505Sopenharmony_ci if (!sta->eapol_sm) 1110e5b75505Sopenharmony_ci return; 1111e5b75505Sopenharmony_ci 1112e5b75505Sopenharmony_ci#ifdef CONFIG_WPS 1113e5b75505Sopenharmony_ci if (!hapd->conf->ieee802_1x && hapd->conf->wps_state) { 1114e5b75505Sopenharmony_ci u32 wflags = sta->flags & (WLAN_STA_WPS | 1115e5b75505Sopenharmony_ci WLAN_STA_WPS2 | 1116e5b75505Sopenharmony_ci WLAN_STA_MAYBE_WPS); 1117e5b75505Sopenharmony_ci if (wflags == WLAN_STA_MAYBE_WPS || 1118e5b75505Sopenharmony_ci wflags == (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) { 1119e5b75505Sopenharmony_ci /* 1120e5b75505Sopenharmony_ci * Delay EAPOL frame transmission until a 1121e5b75505Sopenharmony_ci * possible WPS STA initiates the handshake 1122e5b75505Sopenharmony_ci * with EAPOL-Start. Only allow the wait to be 1123e5b75505Sopenharmony_ci * skipped if the STA is known to support WPS 1124e5b75505Sopenharmony_ci * 2.0. 1125e5b75505Sopenharmony_ci */ 1126e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Do not start " 1127e5b75505Sopenharmony_ci "EAPOL until EAPOL-Start is " 1128e5b75505Sopenharmony_ci "received"); 1129e5b75505Sopenharmony_ci sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; 1130e5b75505Sopenharmony_ci } 1131e5b75505Sopenharmony_ci } 1132e5b75505Sopenharmony_ci#endif /* CONFIG_WPS */ 1133e5b75505Sopenharmony_ci 1134e5b75505Sopenharmony_ci sta->eapol_sm->eap_if->portEnabled = TRUE; 1135e5b75505Sopenharmony_ci } 1136e5b75505Sopenharmony_ci 1137e5b75505Sopenharmony_ci /* since we support version 1, we can ignore version field and proceed 1138e5b75505Sopenharmony_ci * as specified in version 1 standard [IEEE Std 802.1X-2001, 7.5.5] */ 1139e5b75505Sopenharmony_ci /* TODO: actually, we are not version 1 anymore.. However, Version 2 1140e5b75505Sopenharmony_ci * does not change frame contents, so should be ok to process frames 1141e5b75505Sopenharmony_ci * more or less identically. Some changes might be needed for 1142e5b75505Sopenharmony_ci * verification of fields. */ 1143e5b75505Sopenharmony_ci 1144e5b75505Sopenharmony_ci switch (hdr->type) { 1145e5b75505Sopenharmony_ci case IEEE802_1X_TYPE_EAP_PACKET: 1146e5b75505Sopenharmony_ci handle_eap(hapd, sta, (u8 *) (hdr + 1), datalen); 1147e5b75505Sopenharmony_ci break; 1148e5b75505Sopenharmony_ci 1149e5b75505Sopenharmony_ci case IEEE802_1X_TYPE_EAPOL_START: 1150e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1151e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, "received EAPOL-Start " 1152e5b75505Sopenharmony_ci "from STA"); 1153e5b75505Sopenharmony_ci sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START; 1154e5b75505Sopenharmony_ci pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm); 1155e5b75505Sopenharmony_ci if (pmksa) { 1156e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, 1157e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, "cached PMKSA " 1158e5b75505Sopenharmony_ci "available - ignore it since " 1159e5b75505Sopenharmony_ci "STA sent EAPOL-Start"); 1160e5b75505Sopenharmony_ci wpa_auth_sta_clear_pmksa(sta->wpa_sm, pmksa); 1161e5b75505Sopenharmony_ci } 1162e5b75505Sopenharmony_ci sta->eapol_sm->eapolStart = TRUE; 1163e5b75505Sopenharmony_ci sta->eapol_sm->dot1xAuthEapolStartFramesRx++; 1164e5b75505Sopenharmony_ci eap_server_clear_identity(sta->eapol_sm->eap); 1165e5b75505Sopenharmony_ci wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL); 1166e5b75505Sopenharmony_ci break; 1167e5b75505Sopenharmony_ci 1168e5b75505Sopenharmony_ci case IEEE802_1X_TYPE_EAPOL_LOGOFF: 1169e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1170e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, "received EAPOL-Logoff " 1171e5b75505Sopenharmony_ci "from STA"); 1172e5b75505Sopenharmony_ci sta->acct_terminate_cause = 1173e5b75505Sopenharmony_ci RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; 1174e5b75505Sopenharmony_ci accounting_sta_stop(hapd, sta); 1175e5b75505Sopenharmony_ci sta->eapol_sm->eapolLogoff = TRUE; 1176e5b75505Sopenharmony_ci sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++; 1177e5b75505Sopenharmony_ci eap_server_clear_identity(sta->eapol_sm->eap); 1178e5b75505Sopenharmony_ci break; 1179e5b75505Sopenharmony_ci 1180e5b75505Sopenharmony_ci case IEEE802_1X_TYPE_EAPOL_KEY: 1181e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, " EAPOL-Key"); 1182e5b75505Sopenharmony_ci if (!ap_sta_is_authorized(sta)) { 1183e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, " Dropped key data from " 1184e5b75505Sopenharmony_ci "unauthorized Supplicant"); 1185e5b75505Sopenharmony_ci break; 1186e5b75505Sopenharmony_ci } 1187e5b75505Sopenharmony_ci break; 1188e5b75505Sopenharmony_ci 1189e5b75505Sopenharmony_ci case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT: 1190e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, " EAPOL-Encapsulated-ASF-Alert"); 1191e5b75505Sopenharmony_ci /* TODO: implement support for this; show data */ 1192e5b75505Sopenharmony_ci break; 1193e5b75505Sopenharmony_ci 1194e5b75505Sopenharmony_ci#ifdef CONFIG_MACSEC 1195e5b75505Sopenharmony_ci case IEEE802_1X_TYPE_EAPOL_MKA: 1196e5b75505Sopenharmony_ci wpa_printf(MSG_EXCESSIVE, 1197e5b75505Sopenharmony_ci "EAPOL type %d will be handled by MKA", hdr->type); 1198e5b75505Sopenharmony_ci break; 1199e5b75505Sopenharmony_ci#endif /* CONFIG_MACSEC */ 1200e5b75505Sopenharmony_ci 1201e5b75505Sopenharmony_ci default: 1202e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, " unknown IEEE 802.1X packet type"); 1203e5b75505Sopenharmony_ci sta->eapol_sm->dot1xAuthInvalidEapolFramesRx++; 1204e5b75505Sopenharmony_ci break; 1205e5b75505Sopenharmony_ci } 1206e5b75505Sopenharmony_ci 1207e5b75505Sopenharmony_ci eapol_auth_step(sta->eapol_sm); 1208e5b75505Sopenharmony_ci} 1209e5b75505Sopenharmony_ci 1210e5b75505Sopenharmony_ci 1211e5b75505Sopenharmony_ci/** 1212e5b75505Sopenharmony_ci * ieee802_1x_new_station - Start IEEE 802.1X authentication 1213e5b75505Sopenharmony_ci * @hapd: hostapd BSS data 1214e5b75505Sopenharmony_ci * @sta: The station 1215e5b75505Sopenharmony_ci * 1216e5b75505Sopenharmony_ci * This function is called to start IEEE 802.1X authentication when a new 1217e5b75505Sopenharmony_ci * station completes IEEE 802.11 association. 1218e5b75505Sopenharmony_ci */ 1219e5b75505Sopenharmony_civoid ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta) 1220e5b75505Sopenharmony_ci{ 1221e5b75505Sopenharmony_ci struct rsn_pmksa_cache_entry *pmksa; 1222e5b75505Sopenharmony_ci int reassoc = 1; 1223e5b75505Sopenharmony_ci int force_1x = 0; 1224e5b75505Sopenharmony_ci int key_mgmt; 1225e5b75505Sopenharmony_ci 1226e5b75505Sopenharmony_ci#ifdef CONFIG_WPS 1227e5b75505Sopenharmony_ci if (hapd->conf->wps_state && 1228e5b75505Sopenharmony_ci ((hapd->conf->wpa && (sta->flags & WLAN_STA_MAYBE_WPS)) || 1229e5b75505Sopenharmony_ci (sta->flags & WLAN_STA_WPS))) { 1230e5b75505Sopenharmony_ci /* 1231e5b75505Sopenharmony_ci * Need to enable IEEE 802.1X/EAPOL state machines for possible 1232e5b75505Sopenharmony_ci * WPS handshake even if IEEE 802.1X/EAPOL is not used for 1233e5b75505Sopenharmony_ci * authentication in this BSS. 1234e5b75505Sopenharmony_ci */ 1235e5b75505Sopenharmony_ci force_1x = 1; 1236e5b75505Sopenharmony_ci } 1237e5b75505Sopenharmony_ci#endif /* CONFIG_WPS */ 1238e5b75505Sopenharmony_ci 1239e5b75505Sopenharmony_ci if (!force_1x && !hapd->conf->ieee802_1x && !hapd->conf->osen) { 1240e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - " 1241e5b75505Sopenharmony_ci "802.1X not enabled or forced for WPS"); 1242e5b75505Sopenharmony_ci /* 1243e5b75505Sopenharmony_ci * Clear any possible EAPOL authenticator state to support 1244e5b75505Sopenharmony_ci * reassociation change from WPS to PSK. 1245e5b75505Sopenharmony_ci */ 1246e5b75505Sopenharmony_ci ieee802_1x_free_station(hapd, sta); 1247e5b75505Sopenharmony_ci return; 1248e5b75505Sopenharmony_ci } 1249e5b75505Sopenharmony_ci 1250e5b75505Sopenharmony_ci key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm); 1251e5b75505Sopenharmony_ci if (key_mgmt != -1 && 1252e5b75505Sopenharmony_ci (wpa_key_mgmt_wpa_psk(key_mgmt) || key_mgmt == WPA_KEY_MGMT_OWE || 1253e5b75505Sopenharmony_ci key_mgmt == WPA_KEY_MGMT_DPP)) { 1254e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - using PSK"); 1255e5b75505Sopenharmony_ci /* 1256e5b75505Sopenharmony_ci * Clear any possible EAPOL authenticator state to support 1257e5b75505Sopenharmony_ci * reassociation change from WPA-EAP to PSK. 1258e5b75505Sopenharmony_ci */ 1259e5b75505Sopenharmony_ci ieee802_1x_free_station(hapd, sta); 1260e5b75505Sopenharmony_ci return; 1261e5b75505Sopenharmony_ci } 1262e5b75505Sopenharmony_ci 1263e5b75505Sopenharmony_ci if (sta->eapol_sm == NULL) { 1264e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1265e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, "start authentication"); 1266e5b75505Sopenharmony_ci sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta); 1267e5b75505Sopenharmony_ci if (sta->eapol_sm == NULL) { 1268e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, 1269e5b75505Sopenharmony_ci HOSTAPD_MODULE_IEEE8021X, 1270e5b75505Sopenharmony_ci HOSTAPD_LEVEL_INFO, 1271e5b75505Sopenharmony_ci "failed to allocate state machine"); 1272e5b75505Sopenharmony_ci return; 1273e5b75505Sopenharmony_ci } 1274e5b75505Sopenharmony_ci reassoc = 0; 1275e5b75505Sopenharmony_ci } 1276e5b75505Sopenharmony_ci 1277e5b75505Sopenharmony_ci#ifdef CONFIG_WPS 1278e5b75505Sopenharmony_ci sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START; 1279e5b75505Sopenharmony_ci if (!hapd->conf->ieee802_1x && hapd->conf->wps_state && 1280e5b75505Sopenharmony_ci !(sta->flags & WLAN_STA_WPS2)) { 1281e5b75505Sopenharmony_ci /* 1282e5b75505Sopenharmony_ci * Delay EAPOL frame transmission until a possible WPS STA 1283e5b75505Sopenharmony_ci * initiates the handshake with EAPOL-Start. Only allow the 1284e5b75505Sopenharmony_ci * wait to be skipped if the STA is known to support WPS 2.0. 1285e5b75505Sopenharmony_ci */ 1286e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: Do not start EAPOL until " 1287e5b75505Sopenharmony_ci "EAPOL-Start is received"); 1288e5b75505Sopenharmony_ci sta->eapol_sm->flags |= EAPOL_SM_WAIT_START; 1289e5b75505Sopenharmony_ci } 1290e5b75505Sopenharmony_ci#endif /* CONFIG_WPS */ 1291e5b75505Sopenharmony_ci 1292e5b75505Sopenharmony_ci sta->eapol_sm->eap_if->portEnabled = TRUE; 1293e5b75505Sopenharmony_ci 1294e5b75505Sopenharmony_ci#ifdef CONFIG_IEEE80211R_AP 1295e5b75505Sopenharmony_ci if (sta->auth_alg == WLAN_AUTH_FT) { 1296e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1297e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 1298e5b75505Sopenharmony_ci "PMK from FT - skip IEEE 802.1X/EAP"); 1299e5b75505Sopenharmony_ci /* Setup EAPOL state machines to already authenticated state 1300e5b75505Sopenharmony_ci * because of existing FT information from R0KH. */ 1301e5b75505Sopenharmony_ci sta->eapol_sm->keyRun = TRUE; 1302e5b75505Sopenharmony_ci sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; 1303e5b75505Sopenharmony_ci sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; 1304e5b75505Sopenharmony_ci sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; 1305e5b75505Sopenharmony_ci sta->eapol_sm->authSuccess = TRUE; 1306e5b75505Sopenharmony_ci sta->eapol_sm->authFail = FALSE; 1307e5b75505Sopenharmony_ci sta->eapol_sm->portValid = TRUE; 1308e5b75505Sopenharmony_ci if (sta->eapol_sm->eap) 1309e5b75505Sopenharmony_ci eap_sm_notify_cached(sta->eapol_sm->eap); 1310e5b75505Sopenharmony_ci ap_sta_bind_vlan(hapd, sta); 1311e5b75505Sopenharmony_ci return; 1312e5b75505Sopenharmony_ci } 1313e5b75505Sopenharmony_ci#endif /* CONFIG_IEEE80211R_AP */ 1314e5b75505Sopenharmony_ci 1315e5b75505Sopenharmony_ci#ifdef CONFIG_FILS 1316e5b75505Sopenharmony_ci if (sta->auth_alg == WLAN_AUTH_FILS_SK || 1317e5b75505Sopenharmony_ci sta->auth_alg == WLAN_AUTH_FILS_SK_PFS || 1318e5b75505Sopenharmony_ci sta->auth_alg == WLAN_AUTH_FILS_PK) { 1319e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1320e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 1321e5b75505Sopenharmony_ci "PMK from FILS - skip IEEE 802.1X/EAP"); 1322e5b75505Sopenharmony_ci /* Setup EAPOL state machines to already authenticated state 1323e5b75505Sopenharmony_ci * because of existing FILS information. */ 1324e5b75505Sopenharmony_ci sta->eapol_sm->keyRun = TRUE; 1325e5b75505Sopenharmony_ci sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; 1326e5b75505Sopenharmony_ci sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; 1327e5b75505Sopenharmony_ci sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; 1328e5b75505Sopenharmony_ci sta->eapol_sm->authSuccess = TRUE; 1329e5b75505Sopenharmony_ci sta->eapol_sm->authFail = FALSE; 1330e5b75505Sopenharmony_ci sta->eapol_sm->portValid = TRUE; 1331e5b75505Sopenharmony_ci if (sta->eapol_sm->eap) 1332e5b75505Sopenharmony_ci eap_sm_notify_cached(sta->eapol_sm->eap); 1333e5b75505Sopenharmony_ci wpa_auth_set_ptk_rekey_timer(sta->wpa_sm); 1334e5b75505Sopenharmony_ci return; 1335e5b75505Sopenharmony_ci } 1336e5b75505Sopenharmony_ci#endif /* CONFIG_FILS */ 1337e5b75505Sopenharmony_ci 1338e5b75505Sopenharmony_ci pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm); 1339e5b75505Sopenharmony_ci if (pmksa) { 1340e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1341e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 1342e5b75505Sopenharmony_ci "PMK from PMKSA cache - skip IEEE 802.1X/EAP"); 1343e5b75505Sopenharmony_ci /* Setup EAPOL state machines to already authenticated state 1344e5b75505Sopenharmony_ci * because of existing PMKSA information in the cache. */ 1345e5b75505Sopenharmony_ci sta->eapol_sm->keyRun = TRUE; 1346e5b75505Sopenharmony_ci sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; 1347e5b75505Sopenharmony_ci sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING; 1348e5b75505Sopenharmony_ci sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS; 1349e5b75505Sopenharmony_ci sta->eapol_sm->authSuccess = TRUE; 1350e5b75505Sopenharmony_ci sta->eapol_sm->authFail = FALSE; 1351e5b75505Sopenharmony_ci if (sta->eapol_sm->eap) 1352e5b75505Sopenharmony_ci eap_sm_notify_cached(sta->eapol_sm->eap); 1353e5b75505Sopenharmony_ci pmksa_cache_to_eapol_data(hapd, pmksa, sta->eapol_sm); 1354e5b75505Sopenharmony_ci ap_sta_bind_vlan(hapd, sta); 1355e5b75505Sopenharmony_ci } else { 1356e5b75505Sopenharmony_ci if (reassoc) { 1357e5b75505Sopenharmony_ci /* 1358e5b75505Sopenharmony_ci * Force EAPOL state machines to start 1359e5b75505Sopenharmony_ci * re-authentication without having to wait for the 1360e5b75505Sopenharmony_ci * Supplicant to send EAPOL-Start. 1361e5b75505Sopenharmony_ci */ 1362e5b75505Sopenharmony_ci sta->eapol_sm->reAuthenticate = TRUE; 1363e5b75505Sopenharmony_ci } 1364e5b75505Sopenharmony_ci eapol_auth_step(sta->eapol_sm); 1365e5b75505Sopenharmony_ci } 1366e5b75505Sopenharmony_ci} 1367e5b75505Sopenharmony_ci 1368e5b75505Sopenharmony_ci 1369e5b75505Sopenharmony_civoid ieee802_1x_free_station(struct hostapd_data *hapd, struct sta_info *sta) 1370e5b75505Sopenharmony_ci{ 1371e5b75505Sopenharmony_ci struct eapol_state_machine *sm = sta->eapol_sm; 1372e5b75505Sopenharmony_ci 1373e5b75505Sopenharmony_ci#ifdef CONFIG_HS20 1374e5b75505Sopenharmony_ci eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta); 1375e5b75505Sopenharmony_ci#endif /* CONFIG_HS20 */ 1376e5b75505Sopenharmony_ci 1377e5b75505Sopenharmony_ci if (sta->pending_eapol_rx) { 1378e5b75505Sopenharmony_ci wpabuf_free(sta->pending_eapol_rx->buf); 1379e5b75505Sopenharmony_ci os_free(sta->pending_eapol_rx); 1380e5b75505Sopenharmony_ci sta->pending_eapol_rx = NULL; 1381e5b75505Sopenharmony_ci } 1382e5b75505Sopenharmony_ci 1383e5b75505Sopenharmony_ci if (sm == NULL) 1384e5b75505Sopenharmony_ci return; 1385e5b75505Sopenharmony_ci 1386e5b75505Sopenharmony_ci sta->eapol_sm = NULL; 1387e5b75505Sopenharmony_ci 1388e5b75505Sopenharmony_ci#ifndef CONFIG_NO_RADIUS 1389e5b75505Sopenharmony_ci radius_msg_free(sm->last_recv_radius); 1390e5b75505Sopenharmony_ci radius_free_class(&sm->radius_class); 1391e5b75505Sopenharmony_ci#endif /* CONFIG_NO_RADIUS */ 1392e5b75505Sopenharmony_ci 1393e5b75505Sopenharmony_ci eapol_auth_free(sm); 1394e5b75505Sopenharmony_ci} 1395e5b75505Sopenharmony_ci 1396e5b75505Sopenharmony_ci 1397e5b75505Sopenharmony_ci#ifndef CONFIG_NO_RADIUS 1398e5b75505Sopenharmony_cistatic void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd, 1399e5b75505Sopenharmony_ci struct sta_info *sta) 1400e5b75505Sopenharmony_ci{ 1401e5b75505Sopenharmony_ci struct wpabuf *eap; 1402e5b75505Sopenharmony_ci const struct eap_hdr *hdr; 1403e5b75505Sopenharmony_ci int eap_type = -1; 1404e5b75505Sopenharmony_ci char buf[64]; 1405e5b75505Sopenharmony_ci struct radius_msg *msg; 1406e5b75505Sopenharmony_ci struct eapol_state_machine *sm = sta->eapol_sm; 1407e5b75505Sopenharmony_ci 1408e5b75505Sopenharmony_ci if (sm == NULL || sm->last_recv_radius == NULL) { 1409e5b75505Sopenharmony_ci if (sm) 1410e5b75505Sopenharmony_ci sm->eap_if->aaaEapNoReq = TRUE; 1411e5b75505Sopenharmony_ci return; 1412e5b75505Sopenharmony_ci } 1413e5b75505Sopenharmony_ci 1414e5b75505Sopenharmony_ci msg = sm->last_recv_radius; 1415e5b75505Sopenharmony_ci 1416e5b75505Sopenharmony_ci eap = radius_msg_get_eap(msg); 1417e5b75505Sopenharmony_ci if (eap == NULL) { 1418e5b75505Sopenharmony_ci /* RFC 3579, Chap. 2.6.3: 1419e5b75505Sopenharmony_ci * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message 1420e5b75505Sopenharmony_ci * attribute */ 1421e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1422e5b75505Sopenharmony_ci HOSTAPD_LEVEL_WARNING, "could not extract " 1423e5b75505Sopenharmony_ci "EAP-Message from RADIUS message"); 1424e5b75505Sopenharmony_ci sm->eap_if->aaaEapNoReq = TRUE; 1425e5b75505Sopenharmony_ci return; 1426e5b75505Sopenharmony_ci } 1427e5b75505Sopenharmony_ci 1428e5b75505Sopenharmony_ci if (wpabuf_len(eap) < sizeof(*hdr)) { 1429e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1430e5b75505Sopenharmony_ci HOSTAPD_LEVEL_WARNING, "too short EAP packet " 1431e5b75505Sopenharmony_ci "received from authentication server"); 1432e5b75505Sopenharmony_ci wpabuf_free(eap); 1433e5b75505Sopenharmony_ci sm->eap_if->aaaEapNoReq = TRUE; 1434e5b75505Sopenharmony_ci return; 1435e5b75505Sopenharmony_ci } 1436e5b75505Sopenharmony_ci 1437e5b75505Sopenharmony_ci if (wpabuf_len(eap) > sizeof(*hdr)) 1438e5b75505Sopenharmony_ci eap_type = (wpabuf_head_u8(eap))[sizeof(*hdr)]; 1439e5b75505Sopenharmony_ci 1440e5b75505Sopenharmony_ci hdr = wpabuf_head(eap); 1441e5b75505Sopenharmony_ci switch (hdr->code) { 1442e5b75505Sopenharmony_ci case EAP_CODE_REQUEST: 1443e5b75505Sopenharmony_ci if (eap_type >= 0) 1444e5b75505Sopenharmony_ci sm->eap_type_authsrv = eap_type; 1445e5b75505Sopenharmony_ci os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)", 1446e5b75505Sopenharmony_ci eap_server_get_name(0, eap_type), eap_type); 1447e5b75505Sopenharmony_ci break; 1448e5b75505Sopenharmony_ci case EAP_CODE_RESPONSE: 1449e5b75505Sopenharmony_ci os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)", 1450e5b75505Sopenharmony_ci eap_server_get_name(0, eap_type), eap_type); 1451e5b75505Sopenharmony_ci break; 1452e5b75505Sopenharmony_ci case EAP_CODE_SUCCESS: 1453e5b75505Sopenharmony_ci os_strlcpy(buf, "EAP Success", sizeof(buf)); 1454e5b75505Sopenharmony_ci break; 1455e5b75505Sopenharmony_ci case EAP_CODE_FAILURE: 1456e5b75505Sopenharmony_ci os_strlcpy(buf, "EAP Failure", sizeof(buf)); 1457e5b75505Sopenharmony_ci break; 1458e5b75505Sopenharmony_ci default: 1459e5b75505Sopenharmony_ci os_strlcpy(buf, "unknown EAP code", sizeof(buf)); 1460e5b75505Sopenharmony_ci break; 1461e5b75505Sopenharmony_ci } 1462e5b75505Sopenharmony_ci buf[sizeof(buf) - 1] = '\0'; 1463e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1464e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, "decapsulated EAP packet (code=%d " 1465e5b75505Sopenharmony_ci "id=%d len=%d) from RADIUS server: %s", 1466e5b75505Sopenharmony_ci hdr->code, hdr->identifier, be_to_host16(hdr->length), 1467e5b75505Sopenharmony_ci buf); 1468e5b75505Sopenharmony_ci sm->eap_if->aaaEapReq = TRUE; 1469e5b75505Sopenharmony_ci 1470e5b75505Sopenharmony_ci wpabuf_free(sm->eap_if->aaaEapReqData); 1471e5b75505Sopenharmony_ci sm->eap_if->aaaEapReqData = eap; 1472e5b75505Sopenharmony_ci} 1473e5b75505Sopenharmony_ci 1474e5b75505Sopenharmony_ci 1475e5b75505Sopenharmony_cistatic void ieee802_1x_get_keys(struct hostapd_data *hapd, 1476e5b75505Sopenharmony_ci struct sta_info *sta, struct radius_msg *msg, 1477e5b75505Sopenharmony_ci struct radius_msg *req, 1478e5b75505Sopenharmony_ci const u8 *shared_secret, 1479e5b75505Sopenharmony_ci size_t shared_secret_len) 1480e5b75505Sopenharmony_ci{ 1481e5b75505Sopenharmony_ci struct radius_ms_mppe_keys *keys; 1482e5b75505Sopenharmony_ci u8 *buf; 1483e5b75505Sopenharmony_ci size_t len; 1484e5b75505Sopenharmony_ci struct eapol_state_machine *sm = sta->eapol_sm; 1485e5b75505Sopenharmony_ci if (sm == NULL) 1486e5b75505Sopenharmony_ci return; 1487e5b75505Sopenharmony_ci 1488e5b75505Sopenharmony_ci keys = radius_msg_get_ms_keys(msg, req, shared_secret, 1489e5b75505Sopenharmony_ci shared_secret_len); 1490e5b75505Sopenharmony_ci 1491e5b75505Sopenharmony_ci if (keys && keys->send && keys->recv) { 1492e5b75505Sopenharmony_ci len = keys->send_len + keys->recv_len; 1493e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Send-Key", 1494e5b75505Sopenharmony_ci keys->send, keys->send_len); 1495e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Recv-Key", 1496e5b75505Sopenharmony_ci keys->recv, keys->recv_len); 1497e5b75505Sopenharmony_ci 1498e5b75505Sopenharmony_ci os_free(sm->eap_if->aaaEapKeyData); 1499e5b75505Sopenharmony_ci sm->eap_if->aaaEapKeyData = os_malloc(len); 1500e5b75505Sopenharmony_ci if (sm->eap_if->aaaEapKeyData) { 1501e5b75505Sopenharmony_ci os_memcpy(sm->eap_if->aaaEapKeyData, keys->recv, 1502e5b75505Sopenharmony_ci keys->recv_len); 1503e5b75505Sopenharmony_ci os_memcpy(sm->eap_if->aaaEapKeyData + keys->recv_len, 1504e5b75505Sopenharmony_ci keys->send, keys->send_len); 1505e5b75505Sopenharmony_ci sm->eap_if->aaaEapKeyDataLen = len; 1506e5b75505Sopenharmony_ci sm->eap_if->aaaEapKeyAvailable = TRUE; 1507e5b75505Sopenharmony_ci } 1508e5b75505Sopenharmony_ci } else { 1509e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1510e5b75505Sopenharmony_ci "MS-MPPE: 1x_get_keys, could not get keys: %p send: %p recv: %p", 1511e5b75505Sopenharmony_ci keys, keys ? keys->send : NULL, 1512e5b75505Sopenharmony_ci keys ? keys->recv : NULL); 1513e5b75505Sopenharmony_ci } 1514e5b75505Sopenharmony_ci 1515e5b75505Sopenharmony_ci if (keys) { 1516e5b75505Sopenharmony_ci os_free(keys->send); 1517e5b75505Sopenharmony_ci os_free(keys->recv); 1518e5b75505Sopenharmony_ci os_free(keys); 1519e5b75505Sopenharmony_ci } 1520e5b75505Sopenharmony_ci 1521e5b75505Sopenharmony_ci if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_EAP_KEY_NAME, &buf, &len, 1522e5b75505Sopenharmony_ci NULL) == 0) { 1523e5b75505Sopenharmony_ci os_free(sm->eap_if->eapSessionId); 1524e5b75505Sopenharmony_ci sm->eap_if->eapSessionId = os_memdup(buf, len); 1525e5b75505Sopenharmony_ci if (sm->eap_if->eapSessionId) { 1526e5b75505Sopenharmony_ci sm->eap_if->eapSessionIdLen = len; 1527e5b75505Sopenharmony_ci wpa_hexdump(MSG_DEBUG, "EAP-Key Name", 1528e5b75505Sopenharmony_ci sm->eap_if->eapSessionId, 1529e5b75505Sopenharmony_ci sm->eap_if->eapSessionIdLen); 1530e5b75505Sopenharmony_ci } 1531e5b75505Sopenharmony_ci } else { 1532e5b75505Sopenharmony_ci sm->eap_if->eapSessionIdLen = 0; 1533e5b75505Sopenharmony_ci } 1534e5b75505Sopenharmony_ci} 1535e5b75505Sopenharmony_ci 1536e5b75505Sopenharmony_ci 1537e5b75505Sopenharmony_cistatic void ieee802_1x_store_radius_class(struct hostapd_data *hapd, 1538e5b75505Sopenharmony_ci struct sta_info *sta, 1539e5b75505Sopenharmony_ci struct radius_msg *msg) 1540e5b75505Sopenharmony_ci{ 1541e5b75505Sopenharmony_ci u8 *attr_class; 1542e5b75505Sopenharmony_ci size_t class_len; 1543e5b75505Sopenharmony_ci struct eapol_state_machine *sm = sta->eapol_sm; 1544e5b75505Sopenharmony_ci int count, i; 1545e5b75505Sopenharmony_ci struct radius_attr_data *nclass; 1546e5b75505Sopenharmony_ci size_t nclass_count; 1547e5b75505Sopenharmony_ci 1548e5b75505Sopenharmony_ci if (!hapd->conf->radius->acct_server || hapd->radius == NULL || 1549e5b75505Sopenharmony_ci sm == NULL) 1550e5b75505Sopenharmony_ci return; 1551e5b75505Sopenharmony_ci 1552e5b75505Sopenharmony_ci radius_free_class(&sm->radius_class); 1553e5b75505Sopenharmony_ci count = radius_msg_count_attr(msg, RADIUS_ATTR_CLASS, 1); 1554e5b75505Sopenharmony_ci if (count <= 0) 1555e5b75505Sopenharmony_ci return; 1556e5b75505Sopenharmony_ci 1557e5b75505Sopenharmony_ci nclass = os_calloc(count, sizeof(struct radius_attr_data)); 1558e5b75505Sopenharmony_ci if (nclass == NULL) 1559e5b75505Sopenharmony_ci return; 1560e5b75505Sopenharmony_ci 1561e5b75505Sopenharmony_ci nclass_count = 0; 1562e5b75505Sopenharmony_ci 1563e5b75505Sopenharmony_ci attr_class = NULL; 1564e5b75505Sopenharmony_ci for (i = 0; i < count; i++) { 1565e5b75505Sopenharmony_ci do { 1566e5b75505Sopenharmony_ci if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS, 1567e5b75505Sopenharmony_ci &attr_class, &class_len, 1568e5b75505Sopenharmony_ci attr_class) < 0) { 1569e5b75505Sopenharmony_ci i = count; 1570e5b75505Sopenharmony_ci break; 1571e5b75505Sopenharmony_ci } 1572e5b75505Sopenharmony_ci } while (class_len < 1); 1573e5b75505Sopenharmony_ci 1574e5b75505Sopenharmony_ci nclass[nclass_count].data = os_memdup(attr_class, class_len); 1575e5b75505Sopenharmony_ci if (nclass[nclass_count].data == NULL) 1576e5b75505Sopenharmony_ci break; 1577e5b75505Sopenharmony_ci 1578e5b75505Sopenharmony_ci nclass[nclass_count].len = class_len; 1579e5b75505Sopenharmony_ci nclass_count++; 1580e5b75505Sopenharmony_ci } 1581e5b75505Sopenharmony_ci 1582e5b75505Sopenharmony_ci sm->radius_class.attr = nclass; 1583e5b75505Sopenharmony_ci sm->radius_class.count = nclass_count; 1584e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IEEE 802.1X: Stored %lu RADIUS Class " 1585e5b75505Sopenharmony_ci "attributes for " MACSTR, 1586e5b75505Sopenharmony_ci (unsigned long) sm->radius_class.count, 1587e5b75505Sopenharmony_ci MAC2STR(sta->addr)); 1588e5b75505Sopenharmony_ci} 1589e5b75505Sopenharmony_ci 1590e5b75505Sopenharmony_ci 1591e5b75505Sopenharmony_ci/* Update sta->identity based on User-Name attribute in Access-Accept */ 1592e5b75505Sopenharmony_cistatic void ieee802_1x_update_sta_identity(struct hostapd_data *hapd, 1593e5b75505Sopenharmony_ci struct sta_info *sta, 1594e5b75505Sopenharmony_ci struct radius_msg *msg) 1595e5b75505Sopenharmony_ci{ 1596e5b75505Sopenharmony_ci u8 *buf, *identity; 1597e5b75505Sopenharmony_ci size_t len; 1598e5b75505Sopenharmony_ci struct eapol_state_machine *sm = sta->eapol_sm; 1599e5b75505Sopenharmony_ci 1600e5b75505Sopenharmony_ci if (sm == NULL) 1601e5b75505Sopenharmony_ci return; 1602e5b75505Sopenharmony_ci 1603e5b75505Sopenharmony_ci if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &buf, &len, 1604e5b75505Sopenharmony_ci NULL) < 0) 1605e5b75505Sopenharmony_ci return; 1606e5b75505Sopenharmony_ci 1607e5b75505Sopenharmony_ci identity = (u8 *) dup_binstr(buf, len); 1608e5b75505Sopenharmony_ci if (identity == NULL) 1609e5b75505Sopenharmony_ci return; 1610e5b75505Sopenharmony_ci 1611e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1612e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, "old identity '%s' updated with " 1613e5b75505Sopenharmony_ci "User-Name from Access-Accept '%s'", 1614e5b75505Sopenharmony_ci sm->identity ? (char *) sm->identity : "N/A", 1615e5b75505Sopenharmony_ci (char *) identity); 1616e5b75505Sopenharmony_ci 1617e5b75505Sopenharmony_ci os_free(sm->identity); 1618e5b75505Sopenharmony_ci sm->identity = identity; 1619e5b75505Sopenharmony_ci sm->identity_len = len; 1620e5b75505Sopenharmony_ci} 1621e5b75505Sopenharmony_ci 1622e5b75505Sopenharmony_ci 1623e5b75505Sopenharmony_ci/* Update CUI based on Chargeable-User-Identity attribute in Access-Accept */ 1624e5b75505Sopenharmony_cistatic void ieee802_1x_update_sta_cui(struct hostapd_data *hapd, 1625e5b75505Sopenharmony_ci struct sta_info *sta, 1626e5b75505Sopenharmony_ci struct radius_msg *msg) 1627e5b75505Sopenharmony_ci{ 1628e5b75505Sopenharmony_ci struct eapol_state_machine *sm = sta->eapol_sm; 1629e5b75505Sopenharmony_ci struct wpabuf *cui; 1630e5b75505Sopenharmony_ci u8 *buf; 1631e5b75505Sopenharmony_ci size_t len; 1632e5b75505Sopenharmony_ci 1633e5b75505Sopenharmony_ci if (sm == NULL) 1634e5b75505Sopenharmony_ci return; 1635e5b75505Sopenharmony_ci 1636e5b75505Sopenharmony_ci if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, 1637e5b75505Sopenharmony_ci &buf, &len, NULL) < 0) 1638e5b75505Sopenharmony_ci return; 1639e5b75505Sopenharmony_ci 1640e5b75505Sopenharmony_ci cui = wpabuf_alloc_copy(buf, len); 1641e5b75505Sopenharmony_ci if (cui == NULL) 1642e5b75505Sopenharmony_ci return; 1643e5b75505Sopenharmony_ci 1644e5b75505Sopenharmony_ci wpabuf_free(sm->radius_cui); 1645e5b75505Sopenharmony_ci sm->radius_cui = cui; 1646e5b75505Sopenharmony_ci} 1647e5b75505Sopenharmony_ci 1648e5b75505Sopenharmony_ci 1649e5b75505Sopenharmony_ci#ifdef CONFIG_HS20 1650e5b75505Sopenharmony_ci 1651e5b75505Sopenharmony_cistatic void ieee802_1x_hs20_sub_rem(struct sta_info *sta, u8 *pos, size_t len) 1652e5b75505Sopenharmony_ci{ 1653e5b75505Sopenharmony_ci sta->remediation = 1; 1654e5b75505Sopenharmony_ci os_free(sta->remediation_url); 1655e5b75505Sopenharmony_ci if (len > 2) { 1656e5b75505Sopenharmony_ci sta->remediation_url = os_malloc(len); 1657e5b75505Sopenharmony_ci if (!sta->remediation_url) 1658e5b75505Sopenharmony_ci return; 1659e5b75505Sopenharmony_ci sta->remediation_method = pos[0]; 1660e5b75505Sopenharmony_ci os_memcpy(sta->remediation_url, pos + 1, len - 1); 1661e5b75505Sopenharmony_ci sta->remediation_url[len - 1] = '\0'; 1662e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "HS 2.0: Subscription remediation needed " 1663e5b75505Sopenharmony_ci "for " MACSTR " - server method %u URL %s", 1664e5b75505Sopenharmony_ci MAC2STR(sta->addr), sta->remediation_method, 1665e5b75505Sopenharmony_ci sta->remediation_url); 1666e5b75505Sopenharmony_ci } else { 1667e5b75505Sopenharmony_ci sta->remediation_url = NULL; 1668e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "HS 2.0: Subscription remediation needed " 1669e5b75505Sopenharmony_ci "for " MACSTR, MAC2STR(sta->addr)); 1670e5b75505Sopenharmony_ci } 1671e5b75505Sopenharmony_ci /* TODO: assign the STA into remediation VLAN or add filtering */ 1672e5b75505Sopenharmony_ci} 1673e5b75505Sopenharmony_ci 1674e5b75505Sopenharmony_ci 1675e5b75505Sopenharmony_cistatic void ieee802_1x_hs20_deauth_req(struct hostapd_data *hapd, 1676e5b75505Sopenharmony_ci struct sta_info *sta, u8 *pos, 1677e5b75505Sopenharmony_ci size_t len) 1678e5b75505Sopenharmony_ci{ 1679e5b75505Sopenharmony_ci if (len < 3) 1680e5b75505Sopenharmony_ci return; /* Malformed information */ 1681e5b75505Sopenharmony_ci sta->hs20_deauth_requested = 1; 1682e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "HS 2.0: Deauthentication request - Code %u " 1683e5b75505Sopenharmony_ci "Re-auth Delay %u", 1684e5b75505Sopenharmony_ci *pos, WPA_GET_LE16(pos + 1)); 1685e5b75505Sopenharmony_ci wpabuf_free(sta->hs20_deauth_req); 1686e5b75505Sopenharmony_ci sta->hs20_deauth_req = wpabuf_alloc(len + 1); 1687e5b75505Sopenharmony_ci if (sta->hs20_deauth_req) { 1688e5b75505Sopenharmony_ci wpabuf_put_data(sta->hs20_deauth_req, pos, 3); 1689e5b75505Sopenharmony_ci wpabuf_put_u8(sta->hs20_deauth_req, len - 3); 1690e5b75505Sopenharmony_ci wpabuf_put_data(sta->hs20_deauth_req, pos + 3, len - 3); 1691e5b75505Sopenharmony_ci } 1692e5b75505Sopenharmony_ci ap_sta_session_timeout(hapd, sta, hapd->conf->hs20_deauth_req_timeout); 1693e5b75505Sopenharmony_ci} 1694e5b75505Sopenharmony_ci 1695e5b75505Sopenharmony_ci 1696e5b75505Sopenharmony_cistatic void ieee802_1x_hs20_session_info(struct hostapd_data *hapd, 1697e5b75505Sopenharmony_ci struct sta_info *sta, u8 *pos, 1698e5b75505Sopenharmony_ci size_t len, int session_timeout) 1699e5b75505Sopenharmony_ci{ 1700e5b75505Sopenharmony_ci unsigned int swt; 1701e5b75505Sopenharmony_ci int warning_time, beacon_int; 1702e5b75505Sopenharmony_ci 1703e5b75505Sopenharmony_ci if (len < 1) 1704e5b75505Sopenharmony_ci return; /* Malformed information */ 1705e5b75505Sopenharmony_ci os_free(sta->hs20_session_info_url); 1706e5b75505Sopenharmony_ci sta->hs20_session_info_url = os_malloc(len); 1707e5b75505Sopenharmony_ci if (sta->hs20_session_info_url == NULL) 1708e5b75505Sopenharmony_ci return; 1709e5b75505Sopenharmony_ci swt = pos[0]; 1710e5b75505Sopenharmony_ci os_memcpy(sta->hs20_session_info_url, pos + 1, len - 1); 1711e5b75505Sopenharmony_ci sta->hs20_session_info_url[len - 1] = '\0'; 1712e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "HS 2.0: Session Information URL='%s' SWT=%u " 1713e5b75505Sopenharmony_ci "(session_timeout=%d)", 1714e5b75505Sopenharmony_ci sta->hs20_session_info_url, swt, session_timeout); 1715e5b75505Sopenharmony_ci if (session_timeout < 0) { 1716e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "HS 2.0: No Session-Timeout set - ignore session info URL"); 1717e5b75505Sopenharmony_ci return; 1718e5b75505Sopenharmony_ci } 1719e5b75505Sopenharmony_ci if (swt == 255) 1720e5b75505Sopenharmony_ci swt = 1; /* Use one minute as the AP selected value */ 1721e5b75505Sopenharmony_ci 1722e5b75505Sopenharmony_ci if ((unsigned int) session_timeout < swt * 60) 1723e5b75505Sopenharmony_ci warning_time = 0; 1724e5b75505Sopenharmony_ci else 1725e5b75505Sopenharmony_ci warning_time = session_timeout - swt * 60; 1726e5b75505Sopenharmony_ci 1727e5b75505Sopenharmony_ci beacon_int = hapd->iconf->beacon_int; 1728e5b75505Sopenharmony_ci if (beacon_int < 1) 1729e5b75505Sopenharmony_ci beacon_int = 100; /* best guess */ 1730e5b75505Sopenharmony_ci sta->hs20_disassoc_timer = swt * 60 * 1000 / beacon_int * 125 / 128; 1731e5b75505Sopenharmony_ci if (sta->hs20_disassoc_timer > 65535) 1732e5b75505Sopenharmony_ci sta->hs20_disassoc_timer = 65535; 1733e5b75505Sopenharmony_ci 1734e5b75505Sopenharmony_ci ap_sta_session_warning_timeout(hapd, sta, warning_time); 1735e5b75505Sopenharmony_ci} 1736e5b75505Sopenharmony_ci 1737e5b75505Sopenharmony_ci 1738e5b75505Sopenharmony_cistatic void ieee802_1x_hs20_t_c_filtering(struct hostapd_data *hapd, 1739e5b75505Sopenharmony_ci struct sta_info *sta, u8 *pos, 1740e5b75505Sopenharmony_ci size_t len) 1741e5b75505Sopenharmony_ci{ 1742e5b75505Sopenharmony_ci if (len < 4) 1743e5b75505Sopenharmony_ci return; /* Malformed information */ 1744e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1745e5b75505Sopenharmony_ci "HS 2.0: Terms and Conditions filtering %02x %02x %02x %02x", 1746e5b75505Sopenharmony_ci pos[0], pos[1], pos[2], pos[3]); 1747e5b75505Sopenharmony_ci hs20_t_c_filtering(hapd, sta, pos[0] & BIT(0)); 1748e5b75505Sopenharmony_ci} 1749e5b75505Sopenharmony_ci 1750e5b75505Sopenharmony_ci 1751e5b75505Sopenharmony_cistatic void ieee802_1x_hs20_t_c_url(struct hostapd_data *hapd, 1752e5b75505Sopenharmony_ci struct sta_info *sta, u8 *pos, size_t len) 1753e5b75505Sopenharmony_ci{ 1754e5b75505Sopenharmony_ci os_free(sta->t_c_url); 1755e5b75505Sopenharmony_ci sta->t_c_url = os_malloc(len + 1); 1756e5b75505Sopenharmony_ci if (!sta->t_c_url) 1757e5b75505Sopenharmony_ci return; 1758e5b75505Sopenharmony_ci os_memcpy(sta->t_c_url, pos, len); 1759e5b75505Sopenharmony_ci sta->t_c_url[len] = '\0'; 1760e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 1761e5b75505Sopenharmony_ci "HS 2.0: Terms and Conditions URL %s", sta->t_c_url); 1762e5b75505Sopenharmony_ci} 1763e5b75505Sopenharmony_ci 1764e5b75505Sopenharmony_ci#endif /* CONFIG_HS20 */ 1765e5b75505Sopenharmony_ci 1766e5b75505Sopenharmony_ci 1767e5b75505Sopenharmony_cistatic void ieee802_1x_check_hs20(struct hostapd_data *hapd, 1768e5b75505Sopenharmony_ci struct sta_info *sta, 1769e5b75505Sopenharmony_ci struct radius_msg *msg, 1770e5b75505Sopenharmony_ci int session_timeout) 1771e5b75505Sopenharmony_ci{ 1772e5b75505Sopenharmony_ci#ifdef CONFIG_HS20 1773e5b75505Sopenharmony_ci u8 *buf, *pos, *end, type, sublen; 1774e5b75505Sopenharmony_ci size_t len; 1775e5b75505Sopenharmony_ci 1776e5b75505Sopenharmony_ci buf = NULL; 1777e5b75505Sopenharmony_ci sta->remediation = 0; 1778e5b75505Sopenharmony_ci sta->hs20_deauth_requested = 0; 1779e5b75505Sopenharmony_ci 1780e5b75505Sopenharmony_ci for (;;) { 1781e5b75505Sopenharmony_ci if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, 1782e5b75505Sopenharmony_ci &buf, &len, buf) < 0) 1783e5b75505Sopenharmony_ci break; 1784e5b75505Sopenharmony_ci if (len < 6) 1785e5b75505Sopenharmony_ci continue; 1786e5b75505Sopenharmony_ci pos = buf; 1787e5b75505Sopenharmony_ci end = buf + len; 1788e5b75505Sopenharmony_ci if (WPA_GET_BE32(pos) != RADIUS_VENDOR_ID_WFA) 1789e5b75505Sopenharmony_ci continue; 1790e5b75505Sopenharmony_ci pos += 4; 1791e5b75505Sopenharmony_ci 1792e5b75505Sopenharmony_ci type = *pos++; 1793e5b75505Sopenharmony_ci sublen = *pos++; 1794e5b75505Sopenharmony_ci if (sublen < 2) 1795e5b75505Sopenharmony_ci continue; /* invalid length */ 1796e5b75505Sopenharmony_ci sublen -= 2; /* skip header */ 1797e5b75505Sopenharmony_ci if (pos + sublen > end) 1798e5b75505Sopenharmony_ci continue; /* invalid WFA VSA */ 1799e5b75505Sopenharmony_ci 1800e5b75505Sopenharmony_ci switch (type) { 1801e5b75505Sopenharmony_ci case RADIUS_VENDOR_ATTR_WFA_HS20_SUBSCR_REMEDIATION: 1802e5b75505Sopenharmony_ci ieee802_1x_hs20_sub_rem(sta, pos, sublen); 1803e5b75505Sopenharmony_ci break; 1804e5b75505Sopenharmony_ci case RADIUS_VENDOR_ATTR_WFA_HS20_DEAUTH_REQ: 1805e5b75505Sopenharmony_ci ieee802_1x_hs20_deauth_req(hapd, sta, pos, sublen); 1806e5b75505Sopenharmony_ci break; 1807e5b75505Sopenharmony_ci case RADIUS_VENDOR_ATTR_WFA_HS20_SESSION_INFO_URL: 1808e5b75505Sopenharmony_ci ieee802_1x_hs20_session_info(hapd, sta, pos, sublen, 1809e5b75505Sopenharmony_ci session_timeout); 1810e5b75505Sopenharmony_ci break; 1811e5b75505Sopenharmony_ci case RADIUS_VENDOR_ATTR_WFA_HS20_T_C_FILTERING: 1812e5b75505Sopenharmony_ci ieee802_1x_hs20_t_c_filtering(hapd, sta, pos, sublen); 1813e5b75505Sopenharmony_ci break; 1814e5b75505Sopenharmony_ci case RADIUS_VENDOR_ATTR_WFA_HS20_T_C_URL: 1815e5b75505Sopenharmony_ci ieee802_1x_hs20_t_c_url(hapd, sta, pos, sublen); 1816e5b75505Sopenharmony_ci break; 1817e5b75505Sopenharmony_ci } 1818e5b75505Sopenharmony_ci } 1819e5b75505Sopenharmony_ci#endif /* CONFIG_HS20 */ 1820e5b75505Sopenharmony_ci} 1821e5b75505Sopenharmony_ci 1822e5b75505Sopenharmony_ci 1823e5b75505Sopenharmony_cistruct sta_id_search { 1824e5b75505Sopenharmony_ci u8 identifier; 1825e5b75505Sopenharmony_ci struct eapol_state_machine *sm; 1826e5b75505Sopenharmony_ci}; 1827e5b75505Sopenharmony_ci 1828e5b75505Sopenharmony_ci 1829e5b75505Sopenharmony_cistatic int ieee802_1x_select_radius_identifier(struct hostapd_data *hapd, 1830e5b75505Sopenharmony_ci struct sta_info *sta, 1831e5b75505Sopenharmony_ci void *ctx) 1832e5b75505Sopenharmony_ci{ 1833e5b75505Sopenharmony_ci struct sta_id_search *id_search = ctx; 1834e5b75505Sopenharmony_ci struct eapol_state_machine *sm = sta->eapol_sm; 1835e5b75505Sopenharmony_ci 1836e5b75505Sopenharmony_ci if (sm && sm->radius_identifier >= 0 && 1837e5b75505Sopenharmony_ci sm->radius_identifier == id_search->identifier) { 1838e5b75505Sopenharmony_ci id_search->sm = sm; 1839e5b75505Sopenharmony_ci return 1; 1840e5b75505Sopenharmony_ci } 1841e5b75505Sopenharmony_ci return 0; 1842e5b75505Sopenharmony_ci} 1843e5b75505Sopenharmony_ci 1844e5b75505Sopenharmony_ci 1845e5b75505Sopenharmony_cistatic struct eapol_state_machine * 1846e5b75505Sopenharmony_ciieee802_1x_search_radius_identifier(struct hostapd_data *hapd, u8 identifier) 1847e5b75505Sopenharmony_ci{ 1848e5b75505Sopenharmony_ci struct sta_id_search id_search; 1849e5b75505Sopenharmony_ci id_search.identifier = identifier; 1850e5b75505Sopenharmony_ci id_search.sm = NULL; 1851e5b75505Sopenharmony_ci ap_for_each_sta(hapd, ieee802_1x_select_radius_identifier, &id_search); 1852e5b75505Sopenharmony_ci return id_search.sm; 1853e5b75505Sopenharmony_ci} 1854e5b75505Sopenharmony_ci 1855e5b75505Sopenharmony_ci 1856e5b75505Sopenharmony_ci#ifndef CONFIG_NO_VLAN 1857e5b75505Sopenharmony_cistatic int ieee802_1x_update_vlan(struct radius_msg *msg, 1858e5b75505Sopenharmony_ci struct hostapd_data *hapd, 1859e5b75505Sopenharmony_ci struct sta_info *sta) 1860e5b75505Sopenharmony_ci{ 1861e5b75505Sopenharmony_ci struct vlan_description vlan_desc; 1862e5b75505Sopenharmony_ci 1863e5b75505Sopenharmony_ci os_memset(&vlan_desc, 0, sizeof(vlan_desc)); 1864e5b75505Sopenharmony_ci vlan_desc.notempty = !!radius_msg_get_vlanid(msg, &vlan_desc.untagged, 1865e5b75505Sopenharmony_ci MAX_NUM_TAGGED_VLAN, 1866e5b75505Sopenharmony_ci vlan_desc.tagged); 1867e5b75505Sopenharmony_ci 1868e5b75505Sopenharmony_ci if (vlan_desc.notempty && 1869e5b75505Sopenharmony_ci !hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) { 1870e5b75505Sopenharmony_ci sta->eapol_sm->authFail = TRUE; 1871e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, 1872e5b75505Sopenharmony_ci HOSTAPD_LEVEL_INFO, 1873e5b75505Sopenharmony_ci "Invalid VLAN %d%s received from RADIUS server", 1874e5b75505Sopenharmony_ci vlan_desc.untagged, 1875e5b75505Sopenharmony_ci vlan_desc.tagged[0] ? "+" : ""); 1876e5b75505Sopenharmony_ci os_memset(&vlan_desc, 0, sizeof(vlan_desc)); 1877e5b75505Sopenharmony_ci ap_sta_set_vlan(hapd, sta, &vlan_desc); 1878e5b75505Sopenharmony_ci return -1; 1879e5b75505Sopenharmony_ci } 1880e5b75505Sopenharmony_ci 1881e5b75505Sopenharmony_ci if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED && 1882e5b75505Sopenharmony_ci !vlan_desc.notempty) { 1883e5b75505Sopenharmony_ci sta->eapol_sm->authFail = TRUE; 1884e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 1885e5b75505Sopenharmony_ci HOSTAPD_LEVEL_INFO, 1886e5b75505Sopenharmony_ci "authentication server did not include required VLAN ID in Access-Accept"); 1887e5b75505Sopenharmony_ci return -1; 1888e5b75505Sopenharmony_ci } 1889e5b75505Sopenharmony_ci 1890e5b75505Sopenharmony_ci return ap_sta_set_vlan(hapd, sta, &vlan_desc); 1891e5b75505Sopenharmony_ci} 1892e5b75505Sopenharmony_ci#endif /* CONFIG_NO_VLAN */ 1893e5b75505Sopenharmony_ci 1894e5b75505Sopenharmony_ci 1895e5b75505Sopenharmony_ci/** 1896e5b75505Sopenharmony_ci * ieee802_1x_receive_auth - Process RADIUS frames from Authentication Server 1897e5b75505Sopenharmony_ci * @msg: RADIUS response message 1898e5b75505Sopenharmony_ci * @req: RADIUS request message 1899e5b75505Sopenharmony_ci * @shared_secret: RADIUS shared secret 1900e5b75505Sopenharmony_ci * @shared_secret_len: Length of shared_secret in octets 1901e5b75505Sopenharmony_ci * @data: Context data (struct hostapd_data *) 1902e5b75505Sopenharmony_ci * Returns: Processing status 1903e5b75505Sopenharmony_ci */ 1904e5b75505Sopenharmony_cistatic RadiusRxResult 1905e5b75505Sopenharmony_ciieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, 1906e5b75505Sopenharmony_ci const u8 *shared_secret, size_t shared_secret_len, 1907e5b75505Sopenharmony_ci void *data) 1908e5b75505Sopenharmony_ci{ 1909e5b75505Sopenharmony_ci struct hostapd_data *hapd = data; 1910e5b75505Sopenharmony_ci struct sta_info *sta; 1911e5b75505Sopenharmony_ci u32 session_timeout = 0, termination_action, acct_interim_interval; 1912e5b75505Sopenharmony_ci int session_timeout_set; 1913e5b75505Sopenharmony_ci u32 reason_code; 1914e5b75505Sopenharmony_ci struct eapol_state_machine *sm; 1915e5b75505Sopenharmony_ci int override_eapReq = 0; 1916e5b75505Sopenharmony_ci struct radius_hdr *hdr = radius_msg_get_hdr(msg); 1917e5b75505Sopenharmony_ci 1918e5b75505Sopenharmony_ci sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier); 1919e5b75505Sopenharmony_ci if (sm == NULL) { 1920e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IEEE 802.1X: Could not find matching " 1921e5b75505Sopenharmony_ci "station for this RADIUS message"); 1922e5b75505Sopenharmony_ci return RADIUS_RX_UNKNOWN; 1923e5b75505Sopenharmony_ci } 1924e5b75505Sopenharmony_ci sta = sm->sta; 1925e5b75505Sopenharmony_ci 1926e5b75505Sopenharmony_ci /* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be 1927e5b75505Sopenharmony_ci * present when packet contains an EAP-Message attribute */ 1928e5b75505Sopenharmony_ci if (hdr->code == RADIUS_CODE_ACCESS_REJECT && 1929e5b75505Sopenharmony_ci radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL, 1930e5b75505Sopenharmony_ci 0) < 0 && 1931e5b75505Sopenharmony_ci radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) { 1932e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "Allowing RADIUS Access-Reject without " 1933e5b75505Sopenharmony_ci "Message-Authenticator since it does not include " 1934e5b75505Sopenharmony_ci "EAP-Message"); 1935e5b75505Sopenharmony_ci } else if (radius_msg_verify(msg, shared_secret, shared_secret_len, 1936e5b75505Sopenharmony_ci req, 1)) { 1937e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have correct Message-Authenticator - dropped"); 1938e5b75505Sopenharmony_ci return RADIUS_RX_INVALID_AUTHENTICATOR; 1939e5b75505Sopenharmony_ci } 1940e5b75505Sopenharmony_ci 1941e5b75505Sopenharmony_ci if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT && 1942e5b75505Sopenharmony_ci hdr->code != RADIUS_CODE_ACCESS_REJECT && 1943e5b75505Sopenharmony_ci hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) { 1944e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "Unknown RADIUS message code"); 1945e5b75505Sopenharmony_ci return RADIUS_RX_UNKNOWN; 1946e5b75505Sopenharmony_ci } 1947e5b75505Sopenharmony_ci 1948e5b75505Sopenharmony_ci sm->radius_identifier = -1; 1949e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "RADIUS packet matching with station " MACSTR, 1950e5b75505Sopenharmony_ci MAC2STR(sta->addr)); 1951e5b75505Sopenharmony_ci 1952e5b75505Sopenharmony_ci radius_msg_free(sm->last_recv_radius); 1953e5b75505Sopenharmony_ci sm->last_recv_radius = msg; 1954e5b75505Sopenharmony_ci 1955e5b75505Sopenharmony_ci session_timeout_set = 1956e5b75505Sopenharmony_ci !radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT, 1957e5b75505Sopenharmony_ci &session_timeout); 1958e5b75505Sopenharmony_ci if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_TERMINATION_ACTION, 1959e5b75505Sopenharmony_ci &termination_action)) 1960e5b75505Sopenharmony_ci termination_action = RADIUS_TERMINATION_ACTION_DEFAULT; 1961e5b75505Sopenharmony_ci 1962e5b75505Sopenharmony_ci if (hapd->conf->acct_interim_interval == 0 && 1963e5b75505Sopenharmony_ci hdr->code == RADIUS_CODE_ACCESS_ACCEPT && 1964e5b75505Sopenharmony_ci radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL, 1965e5b75505Sopenharmony_ci &acct_interim_interval) == 0) { 1966e5b75505Sopenharmony_ci if (acct_interim_interval < 60) { 1967e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, 1968e5b75505Sopenharmony_ci HOSTAPD_MODULE_IEEE8021X, 1969e5b75505Sopenharmony_ci HOSTAPD_LEVEL_INFO, 1970e5b75505Sopenharmony_ci "ignored too small " 1971e5b75505Sopenharmony_ci "Acct-Interim-Interval %d", 1972e5b75505Sopenharmony_ci acct_interim_interval); 1973e5b75505Sopenharmony_ci } else 1974e5b75505Sopenharmony_ci sta->acct_interim_interval = acct_interim_interval; 1975e5b75505Sopenharmony_ci } 1976e5b75505Sopenharmony_ci 1977e5b75505Sopenharmony_ci 1978e5b75505Sopenharmony_ci switch (hdr->code) { 1979e5b75505Sopenharmony_ci case RADIUS_CODE_ACCESS_ACCEPT: 1980e5b75505Sopenharmony_ci#ifndef CONFIG_NO_VLAN 1981e5b75505Sopenharmony_ci if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED && 1982e5b75505Sopenharmony_ci ieee802_1x_update_vlan(msg, hapd, sta) < 0) 1983e5b75505Sopenharmony_ci break; 1984e5b75505Sopenharmony_ci 1985e5b75505Sopenharmony_ci if (sta->vlan_id > 0) { 1986e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, 1987e5b75505Sopenharmony_ci HOSTAPD_MODULE_RADIUS, 1988e5b75505Sopenharmony_ci HOSTAPD_LEVEL_INFO, 1989e5b75505Sopenharmony_ci "VLAN ID %d", sta->vlan_id); 1990e5b75505Sopenharmony_ci } 1991e5b75505Sopenharmony_ci 1992e5b75505Sopenharmony_ci if ((sta->flags & WLAN_STA_ASSOC) && 1993e5b75505Sopenharmony_ci ap_sta_bind_vlan(hapd, sta) < 0) 1994e5b75505Sopenharmony_ci break; 1995e5b75505Sopenharmony_ci#endif /* CONFIG_NO_VLAN */ 1996e5b75505Sopenharmony_ci 1997e5b75505Sopenharmony_ci sta->session_timeout_set = !!session_timeout_set; 1998e5b75505Sopenharmony_ci os_get_reltime(&sta->session_timeout); 1999e5b75505Sopenharmony_ci sta->session_timeout.sec += session_timeout; 2000e5b75505Sopenharmony_ci 2001e5b75505Sopenharmony_ci /* RFC 3580, Ch. 3.17 */ 2002e5b75505Sopenharmony_ci if (session_timeout_set && termination_action == 2003e5b75505Sopenharmony_ci RADIUS_TERMINATION_ACTION_RADIUS_REQUEST) 2004e5b75505Sopenharmony_ci sm->reAuthPeriod = session_timeout; 2005e5b75505Sopenharmony_ci else if (session_timeout_set) 2006e5b75505Sopenharmony_ci ap_sta_session_timeout(hapd, sta, session_timeout); 2007e5b75505Sopenharmony_ci else 2008e5b75505Sopenharmony_ci ap_sta_no_session_timeout(hapd, sta); 2009e5b75505Sopenharmony_ci 2010e5b75505Sopenharmony_ci sm->eap_if->aaaSuccess = TRUE; 2011e5b75505Sopenharmony_ci override_eapReq = 1; 2012e5b75505Sopenharmony_ci ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret, 2013e5b75505Sopenharmony_ci shared_secret_len); 2014e5b75505Sopenharmony_ci ieee802_1x_store_radius_class(hapd, sta, msg); 2015e5b75505Sopenharmony_ci ieee802_1x_update_sta_identity(hapd, sta, msg); 2016e5b75505Sopenharmony_ci ieee802_1x_update_sta_cui(hapd, sta, msg); 2017e5b75505Sopenharmony_ci ieee802_1x_check_hs20(hapd, sta, msg, 2018e5b75505Sopenharmony_ci session_timeout_set ? 2019e5b75505Sopenharmony_ci (int) session_timeout : -1); 2020e5b75505Sopenharmony_ci break; 2021e5b75505Sopenharmony_ci case RADIUS_CODE_ACCESS_REJECT: 2022e5b75505Sopenharmony_ci sm->eap_if->aaaFail = TRUE; 2023e5b75505Sopenharmony_ci override_eapReq = 1; 2024e5b75505Sopenharmony_ci if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_WLAN_REASON_CODE, 2025e5b75505Sopenharmony_ci &reason_code) == 0) { 2026e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 2027e5b75505Sopenharmony_ci "RADIUS server indicated WLAN-Reason-Code %u in Access-Reject for " 2028e5b75505Sopenharmony_ci MACSTR, reason_code, MAC2STR(sta->addr)); 2029e5b75505Sopenharmony_ci sta->disconnect_reason_code = reason_code; 2030e5b75505Sopenharmony_ci } 2031e5b75505Sopenharmony_ci break; 2032e5b75505Sopenharmony_ci case RADIUS_CODE_ACCESS_CHALLENGE: 2033e5b75505Sopenharmony_ci sm->eap_if->aaaEapReq = TRUE; 2034e5b75505Sopenharmony_ci if (session_timeout_set) { 2035e5b75505Sopenharmony_ci /* RFC 2869, Ch. 2.3.2; RFC 3580, Ch. 3.17 */ 2036e5b75505Sopenharmony_ci sm->eap_if->aaaMethodTimeout = session_timeout; 2037e5b75505Sopenharmony_ci hostapd_logger(hapd, sm->addr, 2038e5b75505Sopenharmony_ci HOSTAPD_MODULE_IEEE8021X, 2039e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 2040e5b75505Sopenharmony_ci "using EAP timeout of %d seconds (from " 2041e5b75505Sopenharmony_ci "RADIUS)", 2042e5b75505Sopenharmony_ci sm->eap_if->aaaMethodTimeout); 2043e5b75505Sopenharmony_ci } else { 2044e5b75505Sopenharmony_ci /* 2045e5b75505Sopenharmony_ci * Use dynamic retransmission behavior per EAP 2046e5b75505Sopenharmony_ci * specification. 2047e5b75505Sopenharmony_ci */ 2048e5b75505Sopenharmony_ci sm->eap_if->aaaMethodTimeout = 0; 2049e5b75505Sopenharmony_ci } 2050e5b75505Sopenharmony_ci break; 2051e5b75505Sopenharmony_ci } 2052e5b75505Sopenharmony_ci 2053e5b75505Sopenharmony_ci ieee802_1x_decapsulate_radius(hapd, sta); 2054e5b75505Sopenharmony_ci if (override_eapReq) 2055e5b75505Sopenharmony_ci sm->eap_if->aaaEapReq = FALSE; 2056e5b75505Sopenharmony_ci 2057e5b75505Sopenharmony_ci#ifdef CONFIG_FILS 2058e5b75505Sopenharmony_ci#ifdef NEED_AP_MLME 2059e5b75505Sopenharmony_ci if (sta->flags & WLAN_STA_PENDING_FILS_ERP) { 2060e5b75505Sopenharmony_ci /* TODO: Add a PMKSA entry on success? */ 2061e5b75505Sopenharmony_ci ieee802_11_finish_fils_auth( 2062e5b75505Sopenharmony_ci hapd, sta, hdr->code == RADIUS_CODE_ACCESS_ACCEPT, 2063e5b75505Sopenharmony_ci sm->eap_if->aaaEapReqData, 2064e5b75505Sopenharmony_ci sm->eap_if->aaaEapKeyData, 2065e5b75505Sopenharmony_ci sm->eap_if->aaaEapKeyDataLen); 2066e5b75505Sopenharmony_ci } 2067e5b75505Sopenharmony_ci#endif /* NEED_AP_MLME */ 2068e5b75505Sopenharmony_ci#endif /* CONFIG_FILS */ 2069e5b75505Sopenharmony_ci 2070e5b75505Sopenharmony_ci eapol_auth_step(sm); 2071e5b75505Sopenharmony_ci 2072e5b75505Sopenharmony_ci return RADIUS_RX_QUEUED; 2073e5b75505Sopenharmony_ci} 2074e5b75505Sopenharmony_ci#endif /* CONFIG_NO_RADIUS */ 2075e5b75505Sopenharmony_ci 2076e5b75505Sopenharmony_ci 2077e5b75505Sopenharmony_civoid ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta) 2078e5b75505Sopenharmony_ci{ 2079e5b75505Sopenharmony_ci struct eapol_state_machine *sm = sta->eapol_sm; 2080e5b75505Sopenharmony_ci if (sm == NULL) 2081e5b75505Sopenharmony_ci return; 2082e5b75505Sopenharmony_ci 2083e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 2084e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, "aborting authentication"); 2085e5b75505Sopenharmony_ci 2086e5b75505Sopenharmony_ci#ifndef CONFIG_NO_RADIUS 2087e5b75505Sopenharmony_ci radius_msg_free(sm->last_recv_radius); 2088e5b75505Sopenharmony_ci sm->last_recv_radius = NULL; 2089e5b75505Sopenharmony_ci#endif /* CONFIG_NO_RADIUS */ 2090e5b75505Sopenharmony_ci 2091e5b75505Sopenharmony_ci if (sm->eap_if->eapTimeout) { 2092e5b75505Sopenharmony_ci /* 2093e5b75505Sopenharmony_ci * Disconnect the STA since it did not reply to the last EAP 2094e5b75505Sopenharmony_ci * request and we cannot continue EAP processing (EAP-Failure 2095e5b75505Sopenharmony_ci * could only be sent if the EAP peer actually replied). 2096e5b75505Sopenharmony_ci */ 2097e5b75505Sopenharmony_ci wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "EAP Timeout, STA " MACSTR, 2098e5b75505Sopenharmony_ci MAC2STR(sta->addr)); 2099e5b75505Sopenharmony_ci 2100e5b75505Sopenharmony_ci sm->eap_if->portEnabled = FALSE; 2101e5b75505Sopenharmony_ci ap_sta_disconnect(hapd, sta, sta->addr, 2102e5b75505Sopenharmony_ci WLAN_REASON_PREV_AUTH_NOT_VALID); 2103e5b75505Sopenharmony_ci } 2104e5b75505Sopenharmony_ci} 2105e5b75505Sopenharmony_ci 2106e5b75505Sopenharmony_ci 2107e5b75505Sopenharmony_cistatic int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd) 2108e5b75505Sopenharmony_ci{ 2109e5b75505Sopenharmony_ci struct eapol_authenticator *eapol = hapd->eapol_auth; 2110e5b75505Sopenharmony_ci 2111e5b75505Sopenharmony_ci if (hapd->conf->default_wep_key_len < 1) 2112e5b75505Sopenharmony_ci return 0; 2113e5b75505Sopenharmony_ci 2114e5b75505Sopenharmony_ci os_free(eapol->default_wep_key); 2115e5b75505Sopenharmony_ci eapol->default_wep_key = os_malloc(hapd->conf->default_wep_key_len); 2116e5b75505Sopenharmony_ci if (eapol->default_wep_key == NULL || 2117e5b75505Sopenharmony_ci random_get_bytes(eapol->default_wep_key, 2118e5b75505Sopenharmony_ci hapd->conf->default_wep_key_len)) { 2119e5b75505Sopenharmony_ci wpa_printf(MSG_INFO, "Could not generate random WEP key"); 2120e5b75505Sopenharmony_ci os_free(eapol->default_wep_key); 2121e5b75505Sopenharmony_ci eapol->default_wep_key = NULL; 2122e5b75505Sopenharmony_ci return -1; 2123e5b75505Sopenharmony_ci } 2124e5b75505Sopenharmony_ci 2125e5b75505Sopenharmony_ci wpa_hexdump_key(MSG_DEBUG, "IEEE 802.1X: New default WEP key", 2126e5b75505Sopenharmony_ci eapol->default_wep_key, 2127e5b75505Sopenharmony_ci hapd->conf->default_wep_key_len); 2128e5b75505Sopenharmony_ci 2129e5b75505Sopenharmony_ci return 0; 2130e5b75505Sopenharmony_ci} 2131e5b75505Sopenharmony_ci 2132e5b75505Sopenharmony_ci 2133e5b75505Sopenharmony_cistatic int ieee802_1x_sta_key_available(struct hostapd_data *hapd, 2134e5b75505Sopenharmony_ci struct sta_info *sta, void *ctx) 2135e5b75505Sopenharmony_ci{ 2136e5b75505Sopenharmony_ci if (sta->eapol_sm) { 2137e5b75505Sopenharmony_ci sta->eapol_sm->eap_if->eapKeyAvailable = TRUE; 2138e5b75505Sopenharmony_ci eapol_auth_step(sta->eapol_sm); 2139e5b75505Sopenharmony_ci } 2140e5b75505Sopenharmony_ci return 0; 2141e5b75505Sopenharmony_ci} 2142e5b75505Sopenharmony_ci 2143e5b75505Sopenharmony_ci 2144e5b75505Sopenharmony_cistatic void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx) 2145e5b75505Sopenharmony_ci{ 2146e5b75505Sopenharmony_ci struct hostapd_data *hapd = eloop_ctx; 2147e5b75505Sopenharmony_ci struct eapol_authenticator *eapol = hapd->eapol_auth; 2148e5b75505Sopenharmony_ci 2149e5b75505Sopenharmony_ci if (eapol->default_wep_key_idx >= 3) 2150e5b75505Sopenharmony_ci eapol->default_wep_key_idx = 2151e5b75505Sopenharmony_ci hapd->conf->individual_wep_key_len > 0 ? 1 : 0; 2152e5b75505Sopenharmony_ci else 2153e5b75505Sopenharmony_ci eapol->default_wep_key_idx++; 2154e5b75505Sopenharmony_ci 2155e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IEEE 802.1X: New default WEP key index %d", 2156e5b75505Sopenharmony_ci eapol->default_wep_key_idx); 2157e5b75505Sopenharmony_ci 2158e5b75505Sopenharmony_ci if (ieee802_1x_rekey_broadcast(hapd)) { 2159e5b75505Sopenharmony_ci hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X, 2160e5b75505Sopenharmony_ci HOSTAPD_LEVEL_WARNING, "failed to generate a " 2161e5b75505Sopenharmony_ci "new broadcast key"); 2162e5b75505Sopenharmony_ci os_free(eapol->default_wep_key); 2163e5b75505Sopenharmony_ci eapol->default_wep_key = NULL; 2164e5b75505Sopenharmony_ci return; 2165e5b75505Sopenharmony_ci } 2166e5b75505Sopenharmony_ci 2167e5b75505Sopenharmony_ci /* TODO: Could setup key for RX here, but change default TX keyid only 2168e5b75505Sopenharmony_ci * after new broadcast key has been sent to all stations. */ 2169e5b75505Sopenharmony_ci if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, 2170e5b75505Sopenharmony_ci broadcast_ether_addr, 2171e5b75505Sopenharmony_ci eapol->default_wep_key_idx, 1, NULL, 0, 2172e5b75505Sopenharmony_ci eapol->default_wep_key, 2173e5b75505Sopenharmony_ci hapd->conf->default_wep_key_len)) { 2174e5b75505Sopenharmony_ci hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X, 2175e5b75505Sopenharmony_ci HOSTAPD_LEVEL_WARNING, "failed to configure a " 2176e5b75505Sopenharmony_ci "new broadcast key"); 2177e5b75505Sopenharmony_ci os_free(eapol->default_wep_key); 2178e5b75505Sopenharmony_ci eapol->default_wep_key = NULL; 2179e5b75505Sopenharmony_ci return; 2180e5b75505Sopenharmony_ci } 2181e5b75505Sopenharmony_ci 2182e5b75505Sopenharmony_ci ap_for_each_sta(hapd, ieee802_1x_sta_key_available, NULL); 2183e5b75505Sopenharmony_ci 2184e5b75505Sopenharmony_ci if (hapd->conf->wep_rekeying_period > 0) { 2185e5b75505Sopenharmony_ci eloop_register_timeout(hapd->conf->wep_rekeying_period, 0, 2186e5b75505Sopenharmony_ci ieee802_1x_rekey, hapd, NULL); 2187e5b75505Sopenharmony_ci } 2188e5b75505Sopenharmony_ci} 2189e5b75505Sopenharmony_ci 2190e5b75505Sopenharmony_ci 2191e5b75505Sopenharmony_cistatic void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type, 2192e5b75505Sopenharmony_ci const u8 *data, size_t datalen) 2193e5b75505Sopenharmony_ci{ 2194e5b75505Sopenharmony_ci#ifdef CONFIG_WPS 2195e5b75505Sopenharmony_ci struct sta_info *sta = sta_ctx; 2196e5b75505Sopenharmony_ci 2197e5b75505Sopenharmony_ci if ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) == 2198e5b75505Sopenharmony_ci WLAN_STA_MAYBE_WPS) { 2199e5b75505Sopenharmony_ci const u8 *identity; 2200e5b75505Sopenharmony_ci size_t identity_len; 2201e5b75505Sopenharmony_ci struct eapol_state_machine *sm = sta->eapol_sm; 2202e5b75505Sopenharmony_ci 2203e5b75505Sopenharmony_ci identity = eap_get_identity(sm->eap, &identity_len); 2204e5b75505Sopenharmony_ci if (identity && 2205e5b75505Sopenharmony_ci ((identity_len == WSC_ID_ENROLLEE_LEN && 2206e5b75505Sopenharmony_ci os_memcmp(identity, WSC_ID_ENROLLEE, 2207e5b75505Sopenharmony_ci WSC_ID_ENROLLEE_LEN) == 0) || 2208e5b75505Sopenharmony_ci (identity_len == WSC_ID_REGISTRAR_LEN && 2209e5b75505Sopenharmony_ci os_memcmp(identity, WSC_ID_REGISTRAR, 2210e5b75505Sopenharmony_ci WSC_ID_REGISTRAR_LEN) == 0))) { 2211e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "WPS: WLAN_STA_MAYBE_WPS -> " 2212e5b75505Sopenharmony_ci "WLAN_STA_WPS"); 2213e5b75505Sopenharmony_ci sta->flags |= WLAN_STA_WPS; 2214e5b75505Sopenharmony_ci } 2215e5b75505Sopenharmony_ci } 2216e5b75505Sopenharmony_ci#endif /* CONFIG_WPS */ 2217e5b75505Sopenharmony_ci 2218e5b75505Sopenharmony_ci ieee802_1x_send(ctx, sta_ctx, type, data, datalen); 2219e5b75505Sopenharmony_ci} 2220e5b75505Sopenharmony_ci 2221e5b75505Sopenharmony_ci 2222e5b75505Sopenharmony_cistatic void ieee802_1x_aaa_send(void *ctx, void *sta_ctx, 2223e5b75505Sopenharmony_ci const u8 *data, size_t datalen) 2224e5b75505Sopenharmony_ci{ 2225e5b75505Sopenharmony_ci#ifndef CONFIG_NO_RADIUS 2226e5b75505Sopenharmony_ci struct hostapd_data *hapd = ctx; 2227e5b75505Sopenharmony_ci struct sta_info *sta = sta_ctx; 2228e5b75505Sopenharmony_ci 2229e5b75505Sopenharmony_ci ieee802_1x_encapsulate_radius(hapd, sta, data, datalen); 2230e5b75505Sopenharmony_ci#endif /* CONFIG_NO_RADIUS */ 2231e5b75505Sopenharmony_ci} 2232e5b75505Sopenharmony_ci 2233e5b75505Sopenharmony_ci 2234e5b75505Sopenharmony_cistatic void _ieee802_1x_finished(void *ctx, void *sta_ctx, int success, 2235e5b75505Sopenharmony_ci int preauth, int remediation) 2236e5b75505Sopenharmony_ci{ 2237e5b75505Sopenharmony_ci struct hostapd_data *hapd = ctx; 2238e5b75505Sopenharmony_ci struct sta_info *sta = sta_ctx; 2239e5b75505Sopenharmony_ci if (preauth) 2240e5b75505Sopenharmony_ci rsn_preauth_finished(hapd, sta, success); 2241e5b75505Sopenharmony_ci else 2242e5b75505Sopenharmony_ci ieee802_1x_finished(hapd, sta, success, remediation); 2243e5b75505Sopenharmony_ci} 2244e5b75505Sopenharmony_ci 2245e5b75505Sopenharmony_ci 2246e5b75505Sopenharmony_cistatic int ieee802_1x_get_eap_user(void *ctx, const u8 *identity, 2247e5b75505Sopenharmony_ci size_t identity_len, int phase2, 2248e5b75505Sopenharmony_ci struct eap_user *user) 2249e5b75505Sopenharmony_ci{ 2250e5b75505Sopenharmony_ci struct hostapd_data *hapd = ctx; 2251e5b75505Sopenharmony_ci const struct hostapd_eap_user *eap_user; 2252e5b75505Sopenharmony_ci int i; 2253e5b75505Sopenharmony_ci int rv = -1; 2254e5b75505Sopenharmony_ci 2255e5b75505Sopenharmony_ci eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2); 2256e5b75505Sopenharmony_ci if (eap_user == NULL) 2257e5b75505Sopenharmony_ci goto out; 2258e5b75505Sopenharmony_ci 2259e5b75505Sopenharmony_ci os_memset(user, 0, sizeof(*user)); 2260e5b75505Sopenharmony_ci user->phase2 = phase2; 2261e5b75505Sopenharmony_ci for (i = 0; i < EAP_MAX_METHODS; i++) { 2262e5b75505Sopenharmony_ci user->methods[i].vendor = eap_user->methods[i].vendor; 2263e5b75505Sopenharmony_ci user->methods[i].method = eap_user->methods[i].method; 2264e5b75505Sopenharmony_ci } 2265e5b75505Sopenharmony_ci 2266e5b75505Sopenharmony_ci if (eap_user->password) { 2267e5b75505Sopenharmony_ci user->password = os_memdup(eap_user->password, 2268e5b75505Sopenharmony_ci eap_user->password_len); 2269e5b75505Sopenharmony_ci if (user->password == NULL) 2270e5b75505Sopenharmony_ci goto out; 2271e5b75505Sopenharmony_ci user->password_len = eap_user->password_len; 2272e5b75505Sopenharmony_ci user->password_hash = eap_user->password_hash; 2273e5b75505Sopenharmony_ci if (eap_user->salt && eap_user->salt_len) { 2274e5b75505Sopenharmony_ci user->salt = os_memdup(eap_user->salt, 2275e5b75505Sopenharmony_ci eap_user->salt_len); 2276e5b75505Sopenharmony_ci if (!user->salt) 2277e5b75505Sopenharmony_ci goto out; 2278e5b75505Sopenharmony_ci user->salt_len = eap_user->salt_len; 2279e5b75505Sopenharmony_ci } 2280e5b75505Sopenharmony_ci } 2281e5b75505Sopenharmony_ci user->force_version = eap_user->force_version; 2282e5b75505Sopenharmony_ci user->macacl = eap_user->macacl; 2283e5b75505Sopenharmony_ci user->ttls_auth = eap_user->ttls_auth; 2284e5b75505Sopenharmony_ci user->remediation = eap_user->remediation; 2285e5b75505Sopenharmony_ci rv = 0; 2286e5b75505Sopenharmony_ci 2287e5b75505Sopenharmony_ciout: 2288e5b75505Sopenharmony_ci if (rv) 2289e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "%s: Failed to find user", __func__); 2290e5b75505Sopenharmony_ci 2291e5b75505Sopenharmony_ci return rv; 2292e5b75505Sopenharmony_ci} 2293e5b75505Sopenharmony_ci 2294e5b75505Sopenharmony_ci 2295e5b75505Sopenharmony_cistatic int ieee802_1x_sta_entry_alive(void *ctx, const u8 *addr) 2296e5b75505Sopenharmony_ci{ 2297e5b75505Sopenharmony_ci struct hostapd_data *hapd = ctx; 2298e5b75505Sopenharmony_ci struct sta_info *sta; 2299e5b75505Sopenharmony_ci sta = ap_get_sta(hapd, addr); 2300e5b75505Sopenharmony_ci if (sta == NULL || sta->eapol_sm == NULL) 2301e5b75505Sopenharmony_ci return 0; 2302e5b75505Sopenharmony_ci return 1; 2303e5b75505Sopenharmony_ci} 2304e5b75505Sopenharmony_ci 2305e5b75505Sopenharmony_ci 2306e5b75505Sopenharmony_cistatic void ieee802_1x_logger(void *ctx, const u8 *addr, 2307e5b75505Sopenharmony_ci eapol_logger_level level, const char *txt) 2308e5b75505Sopenharmony_ci{ 2309e5b75505Sopenharmony_ci#ifndef CONFIG_NO_HOSTAPD_LOGGER 2310e5b75505Sopenharmony_ci struct hostapd_data *hapd = ctx; 2311e5b75505Sopenharmony_ci int hlevel; 2312e5b75505Sopenharmony_ci 2313e5b75505Sopenharmony_ci switch (level) { 2314e5b75505Sopenharmony_ci case EAPOL_LOGGER_WARNING: 2315e5b75505Sopenharmony_ci hlevel = HOSTAPD_LEVEL_WARNING; 2316e5b75505Sopenharmony_ci break; 2317e5b75505Sopenharmony_ci case EAPOL_LOGGER_INFO: 2318e5b75505Sopenharmony_ci hlevel = HOSTAPD_LEVEL_INFO; 2319e5b75505Sopenharmony_ci break; 2320e5b75505Sopenharmony_ci case EAPOL_LOGGER_DEBUG: 2321e5b75505Sopenharmony_ci default: 2322e5b75505Sopenharmony_ci hlevel = HOSTAPD_LEVEL_DEBUG; 2323e5b75505Sopenharmony_ci break; 2324e5b75505Sopenharmony_ci } 2325e5b75505Sopenharmony_ci 2326e5b75505Sopenharmony_ci hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE8021X, hlevel, "%s", 2327e5b75505Sopenharmony_ci txt); 2328e5b75505Sopenharmony_ci#endif /* CONFIG_NO_HOSTAPD_LOGGER */ 2329e5b75505Sopenharmony_ci} 2330e5b75505Sopenharmony_ci 2331e5b75505Sopenharmony_ci 2332e5b75505Sopenharmony_cistatic void ieee802_1x_set_port_authorized(void *ctx, void *sta_ctx, 2333e5b75505Sopenharmony_ci int authorized) 2334e5b75505Sopenharmony_ci{ 2335e5b75505Sopenharmony_ci struct hostapd_data *hapd = ctx; 2336e5b75505Sopenharmony_ci struct sta_info *sta = sta_ctx; 2337e5b75505Sopenharmony_ci ieee802_1x_set_sta_authorized(hapd, sta, authorized); 2338e5b75505Sopenharmony_ci} 2339e5b75505Sopenharmony_ci 2340e5b75505Sopenharmony_ci 2341e5b75505Sopenharmony_cistatic void _ieee802_1x_abort_auth(void *ctx, void *sta_ctx) 2342e5b75505Sopenharmony_ci{ 2343e5b75505Sopenharmony_ci struct hostapd_data *hapd = ctx; 2344e5b75505Sopenharmony_ci struct sta_info *sta = sta_ctx; 2345e5b75505Sopenharmony_ci ieee802_1x_abort_auth(hapd, sta); 2346e5b75505Sopenharmony_ci} 2347e5b75505Sopenharmony_ci 2348e5b75505Sopenharmony_ci 2349e5b75505Sopenharmony_cistatic void _ieee802_1x_tx_key(void *ctx, void *sta_ctx) 2350e5b75505Sopenharmony_ci{ 2351e5b75505Sopenharmony_ci#ifndef CONFIG_FIPS 2352e5b75505Sopenharmony_ci#ifndef CONFIG_NO_RC4 2353e5b75505Sopenharmony_ci struct hostapd_data *hapd = ctx; 2354e5b75505Sopenharmony_ci struct sta_info *sta = sta_ctx; 2355e5b75505Sopenharmony_ci ieee802_1x_tx_key(hapd, sta); 2356e5b75505Sopenharmony_ci#endif /* CONFIG_NO_RC4 */ 2357e5b75505Sopenharmony_ci#endif /* CONFIG_FIPS */ 2358e5b75505Sopenharmony_ci} 2359e5b75505Sopenharmony_ci 2360e5b75505Sopenharmony_ci 2361e5b75505Sopenharmony_cistatic void ieee802_1x_eapol_event(void *ctx, void *sta_ctx, 2362e5b75505Sopenharmony_ci enum eapol_event type) 2363e5b75505Sopenharmony_ci{ 2364e5b75505Sopenharmony_ci /* struct hostapd_data *hapd = ctx; */ 2365e5b75505Sopenharmony_ci struct sta_info *sta = sta_ctx; 2366e5b75505Sopenharmony_ci switch (type) { 2367e5b75505Sopenharmony_ci case EAPOL_AUTH_SM_CHANGE: 2368e5b75505Sopenharmony_ci wpa_auth_sm_notify(sta->wpa_sm); 2369e5b75505Sopenharmony_ci break; 2370e5b75505Sopenharmony_ci case EAPOL_AUTH_REAUTHENTICATE: 2371e5b75505Sopenharmony_ci wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL); 2372e5b75505Sopenharmony_ci break; 2373e5b75505Sopenharmony_ci } 2374e5b75505Sopenharmony_ci} 2375e5b75505Sopenharmony_ci 2376e5b75505Sopenharmony_ci 2377e5b75505Sopenharmony_ci#ifdef CONFIG_ERP 2378e5b75505Sopenharmony_ci 2379e5b75505Sopenharmony_cistatic struct eap_server_erp_key * 2380e5b75505Sopenharmony_ciieee802_1x_erp_get_key(void *ctx, const char *keyname) 2381e5b75505Sopenharmony_ci{ 2382e5b75505Sopenharmony_ci struct hostapd_data *hapd = ctx; 2383e5b75505Sopenharmony_ci struct eap_server_erp_key *erp; 2384e5b75505Sopenharmony_ci 2385e5b75505Sopenharmony_ci dl_list_for_each(erp, &hapd->erp_keys, struct eap_server_erp_key, 2386e5b75505Sopenharmony_ci list) { 2387e5b75505Sopenharmony_ci if (os_strcmp(erp->keyname_nai, keyname) == 0) 2388e5b75505Sopenharmony_ci return erp; 2389e5b75505Sopenharmony_ci } 2390e5b75505Sopenharmony_ci 2391e5b75505Sopenharmony_ci return NULL; 2392e5b75505Sopenharmony_ci} 2393e5b75505Sopenharmony_ci 2394e5b75505Sopenharmony_ci 2395e5b75505Sopenharmony_cistatic int ieee802_1x_erp_add_key(void *ctx, struct eap_server_erp_key *erp) 2396e5b75505Sopenharmony_ci{ 2397e5b75505Sopenharmony_ci struct hostapd_data *hapd = ctx; 2398e5b75505Sopenharmony_ci 2399e5b75505Sopenharmony_ci dl_list_add(&hapd->erp_keys, &erp->list); 2400e5b75505Sopenharmony_ci return 0; 2401e5b75505Sopenharmony_ci} 2402e5b75505Sopenharmony_ci 2403e5b75505Sopenharmony_ci#endif /* CONFIG_ERP */ 2404e5b75505Sopenharmony_ci 2405e5b75505Sopenharmony_ci 2406e5b75505Sopenharmony_ciint ieee802_1x_init(struct hostapd_data *hapd) 2407e5b75505Sopenharmony_ci{ 2408e5b75505Sopenharmony_ci int i; 2409e5b75505Sopenharmony_ci struct eapol_auth_config conf; 2410e5b75505Sopenharmony_ci struct eapol_auth_cb cb; 2411e5b75505Sopenharmony_ci 2412e5b75505Sopenharmony_ci dl_list_init(&hapd->erp_keys); 2413e5b75505Sopenharmony_ci 2414e5b75505Sopenharmony_ci os_memset(&conf, 0, sizeof(conf)); 2415e5b75505Sopenharmony_ci conf.ctx = hapd; 2416e5b75505Sopenharmony_ci conf.eap_reauth_period = hapd->conf->eap_reauth_period; 2417e5b75505Sopenharmony_ci conf.wpa = hapd->conf->wpa; 2418e5b75505Sopenharmony_ci conf.individual_wep_key_len = hapd->conf->individual_wep_key_len; 2419e5b75505Sopenharmony_ci conf.eap_server = hapd->conf->eap_server; 2420e5b75505Sopenharmony_ci conf.ssl_ctx = hapd->ssl_ctx; 2421e5b75505Sopenharmony_ci conf.msg_ctx = hapd->msg_ctx; 2422e5b75505Sopenharmony_ci conf.eap_sim_db_priv = hapd->eap_sim_db_priv; 2423e5b75505Sopenharmony_ci conf.eap_req_id_text = hapd->conf->eap_req_id_text; 2424e5b75505Sopenharmony_ci conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len; 2425e5b75505Sopenharmony_ci conf.erp_send_reauth_start = hapd->conf->erp_send_reauth_start; 2426e5b75505Sopenharmony_ci conf.erp_domain = hapd->conf->erp_domain; 2427e5b75505Sopenharmony_ci conf.erp = hapd->conf->eap_server_erp; 2428e5b75505Sopenharmony_ci conf.tls_session_lifetime = hapd->conf->tls_session_lifetime; 2429e5b75505Sopenharmony_ci conf.tls_flags = hapd->conf->tls_flags; 2430e5b75505Sopenharmony_ci conf.pac_opaque_encr_key = hapd->conf->pac_opaque_encr_key; 2431e5b75505Sopenharmony_ci conf.eap_fast_a_id = hapd->conf->eap_fast_a_id; 2432e5b75505Sopenharmony_ci conf.eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len; 2433e5b75505Sopenharmony_ci conf.eap_fast_a_id_info = hapd->conf->eap_fast_a_id_info; 2434e5b75505Sopenharmony_ci conf.eap_fast_prov = hapd->conf->eap_fast_prov; 2435e5b75505Sopenharmony_ci conf.pac_key_lifetime = hapd->conf->pac_key_lifetime; 2436e5b75505Sopenharmony_ci conf.pac_key_refresh_time = hapd->conf->pac_key_refresh_time; 2437e5b75505Sopenharmony_ci conf.eap_teap_auth = hapd->conf->eap_teap_auth; 2438e5b75505Sopenharmony_ci conf.eap_teap_pac_no_inner = hapd->conf->eap_teap_pac_no_inner; 2439e5b75505Sopenharmony_ci conf.eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind; 2440e5b75505Sopenharmony_ci conf.eap_sim_id = hapd->conf->eap_sim_id; 2441e5b75505Sopenharmony_ci conf.tnc = hapd->conf->tnc; 2442e5b75505Sopenharmony_ci conf.wps = hapd->wps; 2443e5b75505Sopenharmony_ci conf.fragment_size = hapd->conf->fragment_size; 2444e5b75505Sopenharmony_ci conf.pwd_group = hapd->conf->pwd_group; 2445e5b75505Sopenharmony_ci conf.pbc_in_m1 = hapd->conf->pbc_in_m1; 2446e5b75505Sopenharmony_ci if (hapd->conf->server_id) { 2447e5b75505Sopenharmony_ci conf.server_id = (const u8 *) hapd->conf->server_id; 2448e5b75505Sopenharmony_ci conf.server_id_len = os_strlen(hapd->conf->server_id); 2449e5b75505Sopenharmony_ci } else { 2450e5b75505Sopenharmony_ci conf.server_id = (const u8 *) "hostapd"; 2451e5b75505Sopenharmony_ci conf.server_id_len = 7; 2452e5b75505Sopenharmony_ci } 2453e5b75505Sopenharmony_ci 2454e5b75505Sopenharmony_ci os_memset(&cb, 0, sizeof(cb)); 2455e5b75505Sopenharmony_ci cb.eapol_send = ieee802_1x_eapol_send; 2456e5b75505Sopenharmony_ci cb.aaa_send = ieee802_1x_aaa_send; 2457e5b75505Sopenharmony_ci cb.finished = _ieee802_1x_finished; 2458e5b75505Sopenharmony_ci cb.get_eap_user = ieee802_1x_get_eap_user; 2459e5b75505Sopenharmony_ci cb.sta_entry_alive = ieee802_1x_sta_entry_alive; 2460e5b75505Sopenharmony_ci cb.logger = ieee802_1x_logger; 2461e5b75505Sopenharmony_ci cb.set_port_authorized = ieee802_1x_set_port_authorized; 2462e5b75505Sopenharmony_ci cb.abort_auth = _ieee802_1x_abort_auth; 2463e5b75505Sopenharmony_ci cb.tx_key = _ieee802_1x_tx_key; 2464e5b75505Sopenharmony_ci cb.eapol_event = ieee802_1x_eapol_event; 2465e5b75505Sopenharmony_ci#ifdef CONFIG_ERP 2466e5b75505Sopenharmony_ci cb.erp_get_key = ieee802_1x_erp_get_key; 2467e5b75505Sopenharmony_ci cb.erp_add_key = ieee802_1x_erp_add_key; 2468e5b75505Sopenharmony_ci#endif /* CONFIG_ERP */ 2469e5b75505Sopenharmony_ci 2470e5b75505Sopenharmony_ci hapd->eapol_auth = eapol_auth_init(&conf, &cb); 2471e5b75505Sopenharmony_ci if (hapd->eapol_auth == NULL) 2472e5b75505Sopenharmony_ci return -1; 2473e5b75505Sopenharmony_ci 2474e5b75505Sopenharmony_ci if ((hapd->conf->ieee802_1x || hapd->conf->wpa) && 2475e5b75505Sopenharmony_ci hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1)) 2476e5b75505Sopenharmony_ci return -1; 2477e5b75505Sopenharmony_ci 2478e5b75505Sopenharmony_ci#ifndef CONFIG_NO_RADIUS 2479e5b75505Sopenharmony_ci if (radius_client_register(hapd->radius, RADIUS_AUTH, 2480e5b75505Sopenharmony_ci ieee802_1x_receive_auth, hapd)) 2481e5b75505Sopenharmony_ci return -1; 2482e5b75505Sopenharmony_ci#endif /* CONFIG_NO_RADIUS */ 2483e5b75505Sopenharmony_ci 2484e5b75505Sopenharmony_ci if (hapd->conf->default_wep_key_len) { 2485e5b75505Sopenharmony_ci for (i = 0; i < 4; i++) 2486e5b75505Sopenharmony_ci hostapd_drv_set_key(hapd->conf->iface, hapd, 2487e5b75505Sopenharmony_ci WPA_ALG_NONE, NULL, i, 0, NULL, 0, 2488e5b75505Sopenharmony_ci NULL, 0); 2489e5b75505Sopenharmony_ci 2490e5b75505Sopenharmony_ci ieee802_1x_rekey(hapd, NULL); 2491e5b75505Sopenharmony_ci 2492e5b75505Sopenharmony_ci if (hapd->eapol_auth->default_wep_key == NULL) 2493e5b75505Sopenharmony_ci return -1; 2494e5b75505Sopenharmony_ci } 2495e5b75505Sopenharmony_ci 2496e5b75505Sopenharmony_ci return 0; 2497e5b75505Sopenharmony_ci} 2498e5b75505Sopenharmony_ci 2499e5b75505Sopenharmony_ci 2500e5b75505Sopenharmony_civoid ieee802_1x_erp_flush(struct hostapd_data *hapd) 2501e5b75505Sopenharmony_ci{ 2502e5b75505Sopenharmony_ci struct eap_server_erp_key *erp; 2503e5b75505Sopenharmony_ci 2504e5b75505Sopenharmony_ci while ((erp = dl_list_first(&hapd->erp_keys, struct eap_server_erp_key, 2505e5b75505Sopenharmony_ci list)) != NULL) { 2506e5b75505Sopenharmony_ci dl_list_del(&erp->list); 2507e5b75505Sopenharmony_ci bin_clear_free(erp, sizeof(*erp)); 2508e5b75505Sopenharmony_ci } 2509e5b75505Sopenharmony_ci} 2510e5b75505Sopenharmony_ci 2511e5b75505Sopenharmony_ci 2512e5b75505Sopenharmony_civoid ieee802_1x_deinit(struct hostapd_data *hapd) 2513e5b75505Sopenharmony_ci{ 2514e5b75505Sopenharmony_ci eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL); 2515e5b75505Sopenharmony_ci 2516e5b75505Sopenharmony_ci if (hapd->driver && hapd->drv_priv && 2517e5b75505Sopenharmony_ci (hapd->conf->ieee802_1x || hapd->conf->wpa)) 2518e5b75505Sopenharmony_ci hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0); 2519e5b75505Sopenharmony_ci 2520e5b75505Sopenharmony_ci eapol_auth_deinit(hapd->eapol_auth); 2521e5b75505Sopenharmony_ci hapd->eapol_auth = NULL; 2522e5b75505Sopenharmony_ci 2523e5b75505Sopenharmony_ci ieee802_1x_erp_flush(hapd); 2524e5b75505Sopenharmony_ci} 2525e5b75505Sopenharmony_ci 2526e5b75505Sopenharmony_ci 2527e5b75505Sopenharmony_ciint ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta, 2528e5b75505Sopenharmony_ci const u8 *buf, size_t len, int ack) 2529e5b75505Sopenharmony_ci{ 2530e5b75505Sopenharmony_ci struct ieee80211_hdr *hdr; 2531e5b75505Sopenharmony_ci u8 *pos; 2532e5b75505Sopenharmony_ci const unsigned char rfc1042_hdr[ETH_ALEN] = 2533e5b75505Sopenharmony_ci { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; 2534e5b75505Sopenharmony_ci 2535e5b75505Sopenharmony_ci if (sta == NULL) 2536e5b75505Sopenharmony_ci return -1; 2537e5b75505Sopenharmony_ci if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2) 2538e5b75505Sopenharmony_ci return 0; 2539e5b75505Sopenharmony_ci 2540e5b75505Sopenharmony_ci hdr = (struct ieee80211_hdr *) buf; 2541e5b75505Sopenharmony_ci pos = (u8 *) (hdr + 1); 2542e5b75505Sopenharmony_ci if (os_memcmp(pos, rfc1042_hdr, sizeof(rfc1042_hdr)) != 0) 2543e5b75505Sopenharmony_ci return 0; 2544e5b75505Sopenharmony_ci pos += sizeof(rfc1042_hdr); 2545e5b75505Sopenharmony_ci if (WPA_GET_BE16(pos) != ETH_P_PAE) 2546e5b75505Sopenharmony_ci return 0; 2547e5b75505Sopenharmony_ci pos += 2; 2548e5b75505Sopenharmony_ci 2549e5b75505Sopenharmony_ci return ieee802_1x_eapol_tx_status(hapd, sta, pos, buf + len - pos, 2550e5b75505Sopenharmony_ci ack); 2551e5b75505Sopenharmony_ci} 2552e5b75505Sopenharmony_ci 2553e5b75505Sopenharmony_ci 2554e5b75505Sopenharmony_ciint ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta, 2555e5b75505Sopenharmony_ci const u8 *buf, int len, int ack) 2556e5b75505Sopenharmony_ci{ 2557e5b75505Sopenharmony_ci const struct ieee802_1x_hdr *xhdr = 2558e5b75505Sopenharmony_ci (const struct ieee802_1x_hdr *) buf; 2559e5b75505Sopenharmony_ci const u8 *pos = buf + sizeof(*xhdr); 2560e5b75505Sopenharmony_ci struct ieee802_1x_eapol_key *key; 2561e5b75505Sopenharmony_ci 2562e5b75505Sopenharmony_ci if (len < (int) sizeof(*xhdr)) 2563e5b75505Sopenharmony_ci return 0; 2564e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " TX status - version=%d " 2565e5b75505Sopenharmony_ci "type=%d length=%d - ack=%d", 2566e5b75505Sopenharmony_ci MAC2STR(sta->addr), xhdr->version, xhdr->type, 2567e5b75505Sopenharmony_ci be_to_host16(xhdr->length), ack); 2568e5b75505Sopenharmony_ci 2569e5b75505Sopenharmony_ci#ifdef CONFIG_WPS 2570e5b75505Sopenharmony_ci if (xhdr->type == IEEE802_1X_TYPE_EAP_PACKET && ack && 2571e5b75505Sopenharmony_ci (sta->flags & WLAN_STA_WPS) && 2572e5b75505Sopenharmony_ci ap_sta_pending_delayed_1x_auth_fail_disconnect(hapd, sta)) { 2573e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, 2574e5b75505Sopenharmony_ci "WPS: Indicate EAP completion on ACK for EAP-Failure"); 2575e5b75505Sopenharmony_ci hostapd_wps_eap_completed(hapd); 2576e5b75505Sopenharmony_ci } 2577e5b75505Sopenharmony_ci#endif /* CONFIG_WPS */ 2578e5b75505Sopenharmony_ci 2579e5b75505Sopenharmony_ci if (xhdr->type != IEEE802_1X_TYPE_EAPOL_KEY) 2580e5b75505Sopenharmony_ci return 0; 2581e5b75505Sopenharmony_ci 2582e5b75505Sopenharmony_ci if (pos + sizeof(struct wpa_eapol_key) <= buf + len) { 2583e5b75505Sopenharmony_ci const struct wpa_eapol_key *wpa; 2584e5b75505Sopenharmony_ci wpa = (const struct wpa_eapol_key *) pos; 2585e5b75505Sopenharmony_ci if (wpa->type == EAPOL_KEY_TYPE_RSN || 2586e5b75505Sopenharmony_ci wpa->type == EAPOL_KEY_TYPE_WPA) 2587e5b75505Sopenharmony_ci wpa_auth_eapol_key_tx_status(hapd->wpa_auth, 2588e5b75505Sopenharmony_ci sta->wpa_sm, ack); 2589e5b75505Sopenharmony_ci } 2590e5b75505Sopenharmony_ci 2591e5b75505Sopenharmony_ci /* EAPOL EAP-Packet packets are eventually re-sent by either Supplicant 2592e5b75505Sopenharmony_ci * or Authenticator state machines, but EAPOL-Key packets are not 2593e5b75505Sopenharmony_ci * retransmitted in case of failure. Try to re-send failed EAPOL-Key 2594e5b75505Sopenharmony_ci * packets couple of times because otherwise STA keys become 2595e5b75505Sopenharmony_ci * unsynchronized with AP. */ 2596e5b75505Sopenharmony_ci if (!ack && pos + sizeof(*key) <= buf + len) { 2597e5b75505Sopenharmony_ci key = (struct ieee802_1x_eapol_key *) pos; 2598e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X, 2599e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, "did not Ack EAPOL-Key " 2600e5b75505Sopenharmony_ci "frame (%scast index=%d)", 2601e5b75505Sopenharmony_ci key->key_index & BIT(7) ? "uni" : "broad", 2602e5b75505Sopenharmony_ci key->key_index & ~BIT(7)); 2603e5b75505Sopenharmony_ci /* TODO: re-send EAPOL-Key couple of times (with short delay 2604e5b75505Sopenharmony_ci * between them?). If all attempt fail, report error and 2605e5b75505Sopenharmony_ci * deauthenticate STA so that it will get new keys when 2606e5b75505Sopenharmony_ci * authenticating again (e.g., after returning in range). 2607e5b75505Sopenharmony_ci * Separate limit/transmit state needed both for unicast and 2608e5b75505Sopenharmony_ci * broadcast keys(?) */ 2609e5b75505Sopenharmony_ci } 2610e5b75505Sopenharmony_ci /* TODO: could move unicast key configuration from ieee802_1x_tx_key() 2611e5b75505Sopenharmony_ci * to here and change the key only if the EAPOL-Key packet was Acked. 2612e5b75505Sopenharmony_ci */ 2613e5b75505Sopenharmony_ci 2614e5b75505Sopenharmony_ci return 1; 2615e5b75505Sopenharmony_ci} 2616e5b75505Sopenharmony_ci 2617e5b75505Sopenharmony_ci 2618e5b75505Sopenharmony_ciu8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len) 2619e5b75505Sopenharmony_ci{ 2620e5b75505Sopenharmony_ci if (sm == NULL || sm->identity == NULL) 2621e5b75505Sopenharmony_ci return NULL; 2622e5b75505Sopenharmony_ci 2623e5b75505Sopenharmony_ci *len = sm->identity_len; 2624e5b75505Sopenharmony_ci return sm->identity; 2625e5b75505Sopenharmony_ci} 2626e5b75505Sopenharmony_ci 2627e5b75505Sopenharmony_ci 2628e5b75505Sopenharmony_ciu8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len, 2629e5b75505Sopenharmony_ci int idx) 2630e5b75505Sopenharmony_ci{ 2631e5b75505Sopenharmony_ci if (sm == NULL || sm->radius_class.attr == NULL || 2632e5b75505Sopenharmony_ci idx >= (int) sm->radius_class.count) 2633e5b75505Sopenharmony_ci return NULL; 2634e5b75505Sopenharmony_ci 2635e5b75505Sopenharmony_ci *len = sm->radius_class.attr[idx].len; 2636e5b75505Sopenharmony_ci return sm->radius_class.attr[idx].data; 2637e5b75505Sopenharmony_ci} 2638e5b75505Sopenharmony_ci 2639e5b75505Sopenharmony_ci 2640e5b75505Sopenharmony_cistruct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm) 2641e5b75505Sopenharmony_ci{ 2642e5b75505Sopenharmony_ci if (sm == NULL) 2643e5b75505Sopenharmony_ci return NULL; 2644e5b75505Sopenharmony_ci return sm->radius_cui; 2645e5b75505Sopenharmony_ci} 2646e5b75505Sopenharmony_ci 2647e5b75505Sopenharmony_ci 2648e5b75505Sopenharmony_ciconst u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len) 2649e5b75505Sopenharmony_ci{ 2650e5b75505Sopenharmony_ci *len = 0; 2651e5b75505Sopenharmony_ci if (sm == NULL) 2652e5b75505Sopenharmony_ci return NULL; 2653e5b75505Sopenharmony_ci 2654e5b75505Sopenharmony_ci *len = sm->eap_if->eapKeyDataLen; 2655e5b75505Sopenharmony_ci return sm->eap_if->eapKeyData; 2656e5b75505Sopenharmony_ci} 2657e5b75505Sopenharmony_ci 2658e5b75505Sopenharmony_ci 2659e5b75505Sopenharmony_ci#ifdef CONFIG_MACSEC 2660e5b75505Sopenharmony_ciconst u8 * ieee802_1x_get_session_id(struct eapol_state_machine *sm, 2661e5b75505Sopenharmony_ci size_t *len) 2662e5b75505Sopenharmony_ci{ 2663e5b75505Sopenharmony_ci *len = 0; 2664e5b75505Sopenharmony_ci if (!sm || !sm->eap_if) 2665e5b75505Sopenharmony_ci return NULL; 2666e5b75505Sopenharmony_ci 2667e5b75505Sopenharmony_ci *len = sm->eap_if->eapSessionIdLen; 2668e5b75505Sopenharmony_ci return sm->eap_if->eapSessionId; 2669e5b75505Sopenharmony_ci} 2670e5b75505Sopenharmony_ci#endif /* CONFIG_MACSEC */ 2671e5b75505Sopenharmony_ci 2672e5b75505Sopenharmony_ci 2673e5b75505Sopenharmony_civoid ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm, 2674e5b75505Sopenharmony_ci int enabled) 2675e5b75505Sopenharmony_ci{ 2676e5b75505Sopenharmony_ci if (sm == NULL) 2677e5b75505Sopenharmony_ci return; 2678e5b75505Sopenharmony_ci sm->eap_if->portEnabled = enabled ? TRUE : FALSE; 2679e5b75505Sopenharmony_ci eapol_auth_step(sm); 2680e5b75505Sopenharmony_ci} 2681e5b75505Sopenharmony_ci 2682e5b75505Sopenharmony_ci 2683e5b75505Sopenharmony_civoid ieee802_1x_notify_port_valid(struct eapol_state_machine *sm, 2684e5b75505Sopenharmony_ci int valid) 2685e5b75505Sopenharmony_ci{ 2686e5b75505Sopenharmony_ci if (sm == NULL) 2687e5b75505Sopenharmony_ci return; 2688e5b75505Sopenharmony_ci sm->portValid = valid ? TRUE : FALSE; 2689e5b75505Sopenharmony_ci eapol_auth_step(sm); 2690e5b75505Sopenharmony_ci} 2691e5b75505Sopenharmony_ci 2692e5b75505Sopenharmony_ci 2693e5b75505Sopenharmony_civoid ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth) 2694e5b75505Sopenharmony_ci{ 2695e5b75505Sopenharmony_ci if (sm == NULL) 2696e5b75505Sopenharmony_ci return; 2697e5b75505Sopenharmony_ci if (pre_auth) 2698e5b75505Sopenharmony_ci sm->flags |= EAPOL_SM_PREAUTH; 2699e5b75505Sopenharmony_ci else 2700e5b75505Sopenharmony_ci sm->flags &= ~EAPOL_SM_PREAUTH; 2701e5b75505Sopenharmony_ci} 2702e5b75505Sopenharmony_ci 2703e5b75505Sopenharmony_ci 2704e5b75505Sopenharmony_cistatic const char * bool_txt(Boolean val) 2705e5b75505Sopenharmony_ci{ 2706e5b75505Sopenharmony_ci return val ? "TRUE" : "FALSE"; 2707e5b75505Sopenharmony_ci} 2708e5b75505Sopenharmony_ci 2709e5b75505Sopenharmony_ci 2710e5b75505Sopenharmony_ciint ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen) 2711e5b75505Sopenharmony_ci{ 2712e5b75505Sopenharmony_ci /* TODO */ 2713e5b75505Sopenharmony_ci return 0; 2714e5b75505Sopenharmony_ci} 2715e5b75505Sopenharmony_ci 2716e5b75505Sopenharmony_ci 2717e5b75505Sopenharmony_ciint ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, 2718e5b75505Sopenharmony_ci char *buf, size_t buflen) 2719e5b75505Sopenharmony_ci{ 2720e5b75505Sopenharmony_ci int len = 0, ret; 2721e5b75505Sopenharmony_ci struct eapol_state_machine *sm = sta->eapol_sm; 2722e5b75505Sopenharmony_ci struct os_reltime diff; 2723e5b75505Sopenharmony_ci const char *name1; 2724e5b75505Sopenharmony_ci const char *name2; 2725e5b75505Sopenharmony_ci char *identity_buf = NULL; 2726e5b75505Sopenharmony_ci 2727e5b75505Sopenharmony_ci if (sm == NULL) 2728e5b75505Sopenharmony_ci return 0; 2729e5b75505Sopenharmony_ci 2730e5b75505Sopenharmony_ci ret = os_snprintf(buf + len, buflen - len, 2731e5b75505Sopenharmony_ci "dot1xPaePortNumber=%d\n" 2732e5b75505Sopenharmony_ci "dot1xPaePortProtocolVersion=%d\n" 2733e5b75505Sopenharmony_ci "dot1xPaePortCapabilities=1\n" 2734e5b75505Sopenharmony_ci "dot1xPaePortInitialize=%d\n" 2735e5b75505Sopenharmony_ci "dot1xPaePortReauthenticate=FALSE\n", 2736e5b75505Sopenharmony_ci sta->aid, 2737e5b75505Sopenharmony_ci EAPOL_VERSION, 2738e5b75505Sopenharmony_ci sm->initialize); 2739e5b75505Sopenharmony_ci if (os_snprintf_error(buflen - len, ret)) 2740e5b75505Sopenharmony_ci return len; 2741e5b75505Sopenharmony_ci len += ret; 2742e5b75505Sopenharmony_ci 2743e5b75505Sopenharmony_ci /* dot1xAuthConfigTable */ 2744e5b75505Sopenharmony_ci ret = os_snprintf(buf + len, buflen - len, 2745e5b75505Sopenharmony_ci "dot1xAuthPaeState=%d\n" 2746e5b75505Sopenharmony_ci "dot1xAuthBackendAuthState=%d\n" 2747e5b75505Sopenharmony_ci "dot1xAuthAdminControlledDirections=%d\n" 2748e5b75505Sopenharmony_ci "dot1xAuthOperControlledDirections=%d\n" 2749e5b75505Sopenharmony_ci "dot1xAuthAuthControlledPortStatus=%d\n" 2750e5b75505Sopenharmony_ci "dot1xAuthAuthControlledPortControl=%d\n" 2751e5b75505Sopenharmony_ci "dot1xAuthQuietPeriod=%u\n" 2752e5b75505Sopenharmony_ci "dot1xAuthServerTimeout=%u\n" 2753e5b75505Sopenharmony_ci "dot1xAuthReAuthPeriod=%u\n" 2754e5b75505Sopenharmony_ci "dot1xAuthReAuthEnabled=%s\n" 2755e5b75505Sopenharmony_ci "dot1xAuthKeyTxEnabled=%s\n", 2756e5b75505Sopenharmony_ci sm->auth_pae_state + 1, 2757e5b75505Sopenharmony_ci sm->be_auth_state + 1, 2758e5b75505Sopenharmony_ci sm->adminControlledDirections, 2759e5b75505Sopenharmony_ci sm->operControlledDirections, 2760e5b75505Sopenharmony_ci sm->authPortStatus, 2761e5b75505Sopenharmony_ci sm->portControl, 2762e5b75505Sopenharmony_ci sm->quietPeriod, 2763e5b75505Sopenharmony_ci sm->serverTimeout, 2764e5b75505Sopenharmony_ci sm->reAuthPeriod, 2765e5b75505Sopenharmony_ci bool_txt(sm->reAuthEnabled), 2766e5b75505Sopenharmony_ci bool_txt(sm->keyTxEnabled)); 2767e5b75505Sopenharmony_ci if (os_snprintf_error(buflen - len, ret)) 2768e5b75505Sopenharmony_ci return len; 2769e5b75505Sopenharmony_ci len += ret; 2770e5b75505Sopenharmony_ci 2771e5b75505Sopenharmony_ci /* dot1xAuthStatsTable */ 2772e5b75505Sopenharmony_ci ret = os_snprintf(buf + len, buflen - len, 2773e5b75505Sopenharmony_ci "dot1xAuthEapolFramesRx=%u\n" 2774e5b75505Sopenharmony_ci "dot1xAuthEapolFramesTx=%u\n" 2775e5b75505Sopenharmony_ci "dot1xAuthEapolStartFramesRx=%u\n" 2776e5b75505Sopenharmony_ci "dot1xAuthEapolLogoffFramesRx=%u\n" 2777e5b75505Sopenharmony_ci "dot1xAuthEapolRespIdFramesRx=%u\n" 2778e5b75505Sopenharmony_ci "dot1xAuthEapolRespFramesRx=%u\n" 2779e5b75505Sopenharmony_ci "dot1xAuthEapolReqIdFramesTx=%u\n" 2780e5b75505Sopenharmony_ci "dot1xAuthEapolReqFramesTx=%u\n" 2781e5b75505Sopenharmony_ci "dot1xAuthInvalidEapolFramesRx=%u\n" 2782e5b75505Sopenharmony_ci "dot1xAuthEapLengthErrorFramesRx=%u\n" 2783e5b75505Sopenharmony_ci "dot1xAuthLastEapolFrameVersion=%u\n" 2784e5b75505Sopenharmony_ci "dot1xAuthLastEapolFrameSource=" MACSTR "\n", 2785e5b75505Sopenharmony_ci sm->dot1xAuthEapolFramesRx, 2786e5b75505Sopenharmony_ci sm->dot1xAuthEapolFramesTx, 2787e5b75505Sopenharmony_ci sm->dot1xAuthEapolStartFramesRx, 2788e5b75505Sopenharmony_ci sm->dot1xAuthEapolLogoffFramesRx, 2789e5b75505Sopenharmony_ci sm->dot1xAuthEapolRespIdFramesRx, 2790e5b75505Sopenharmony_ci sm->dot1xAuthEapolRespFramesRx, 2791e5b75505Sopenharmony_ci sm->dot1xAuthEapolReqIdFramesTx, 2792e5b75505Sopenharmony_ci sm->dot1xAuthEapolReqFramesTx, 2793e5b75505Sopenharmony_ci sm->dot1xAuthInvalidEapolFramesRx, 2794e5b75505Sopenharmony_ci sm->dot1xAuthEapLengthErrorFramesRx, 2795e5b75505Sopenharmony_ci sm->dot1xAuthLastEapolFrameVersion, 2796e5b75505Sopenharmony_ci MAC2STR(sm->addr)); 2797e5b75505Sopenharmony_ci if (os_snprintf_error(buflen - len, ret)) 2798e5b75505Sopenharmony_ci return len; 2799e5b75505Sopenharmony_ci len += ret; 2800e5b75505Sopenharmony_ci 2801e5b75505Sopenharmony_ci /* dot1xAuthDiagTable */ 2802e5b75505Sopenharmony_ci ret = os_snprintf(buf + len, buflen - len, 2803e5b75505Sopenharmony_ci "dot1xAuthEntersConnecting=%u\n" 2804e5b75505Sopenharmony_ci "dot1xAuthEapLogoffsWhileConnecting=%u\n" 2805e5b75505Sopenharmony_ci "dot1xAuthEntersAuthenticating=%u\n" 2806e5b75505Sopenharmony_ci "dot1xAuthAuthSuccessesWhileAuthenticating=%u\n" 2807e5b75505Sopenharmony_ci "dot1xAuthAuthTimeoutsWhileAuthenticating=%u\n" 2808e5b75505Sopenharmony_ci "dot1xAuthAuthFailWhileAuthenticating=%u\n" 2809e5b75505Sopenharmony_ci "dot1xAuthAuthEapStartsWhileAuthenticating=%u\n" 2810e5b75505Sopenharmony_ci "dot1xAuthAuthEapLogoffWhileAuthenticating=%u\n" 2811e5b75505Sopenharmony_ci "dot1xAuthAuthReauthsWhileAuthenticated=%u\n" 2812e5b75505Sopenharmony_ci "dot1xAuthAuthEapStartsWhileAuthenticated=%u\n" 2813e5b75505Sopenharmony_ci "dot1xAuthAuthEapLogoffWhileAuthenticated=%u\n" 2814e5b75505Sopenharmony_ci "dot1xAuthBackendResponses=%u\n" 2815e5b75505Sopenharmony_ci "dot1xAuthBackendAccessChallenges=%u\n" 2816e5b75505Sopenharmony_ci "dot1xAuthBackendOtherRequestsToSupplicant=%u\n" 2817e5b75505Sopenharmony_ci "dot1xAuthBackendAuthSuccesses=%u\n" 2818e5b75505Sopenharmony_ci "dot1xAuthBackendAuthFails=%u\n", 2819e5b75505Sopenharmony_ci sm->authEntersConnecting, 2820e5b75505Sopenharmony_ci sm->authEapLogoffsWhileConnecting, 2821e5b75505Sopenharmony_ci sm->authEntersAuthenticating, 2822e5b75505Sopenharmony_ci sm->authAuthSuccessesWhileAuthenticating, 2823e5b75505Sopenharmony_ci sm->authAuthTimeoutsWhileAuthenticating, 2824e5b75505Sopenharmony_ci sm->authAuthFailWhileAuthenticating, 2825e5b75505Sopenharmony_ci sm->authAuthEapStartsWhileAuthenticating, 2826e5b75505Sopenharmony_ci sm->authAuthEapLogoffWhileAuthenticating, 2827e5b75505Sopenharmony_ci sm->authAuthReauthsWhileAuthenticated, 2828e5b75505Sopenharmony_ci sm->authAuthEapStartsWhileAuthenticated, 2829e5b75505Sopenharmony_ci sm->authAuthEapLogoffWhileAuthenticated, 2830e5b75505Sopenharmony_ci sm->backendResponses, 2831e5b75505Sopenharmony_ci sm->backendAccessChallenges, 2832e5b75505Sopenharmony_ci sm->backendOtherRequestsToSupplicant, 2833e5b75505Sopenharmony_ci sm->backendAuthSuccesses, 2834e5b75505Sopenharmony_ci sm->backendAuthFails); 2835e5b75505Sopenharmony_ci if (os_snprintf_error(buflen - len, ret)) 2836e5b75505Sopenharmony_ci return len; 2837e5b75505Sopenharmony_ci len += ret; 2838e5b75505Sopenharmony_ci 2839e5b75505Sopenharmony_ci /* dot1xAuthSessionStatsTable */ 2840e5b75505Sopenharmony_ci os_reltime_age(&sta->acct_session_start, &diff); 2841e5b75505Sopenharmony_ci if (sm->eap && !sm->identity) { 2842e5b75505Sopenharmony_ci const u8 *id; 2843e5b75505Sopenharmony_ci size_t id_len; 2844e5b75505Sopenharmony_ci 2845e5b75505Sopenharmony_ci id = eap_get_identity(sm->eap, &id_len); 2846e5b75505Sopenharmony_ci if (id) 2847e5b75505Sopenharmony_ci identity_buf = dup_binstr(id, id_len); 2848e5b75505Sopenharmony_ci } 2849e5b75505Sopenharmony_ci ret = os_snprintf(buf + len, buflen - len, 2850e5b75505Sopenharmony_ci /* TODO: dot1xAuthSessionOctetsRx */ 2851e5b75505Sopenharmony_ci /* TODO: dot1xAuthSessionOctetsTx */ 2852e5b75505Sopenharmony_ci /* TODO: dot1xAuthSessionFramesRx */ 2853e5b75505Sopenharmony_ci /* TODO: dot1xAuthSessionFramesTx */ 2854e5b75505Sopenharmony_ci "dot1xAuthSessionId=%016llX\n" 2855e5b75505Sopenharmony_ci "dot1xAuthSessionAuthenticMethod=%d\n" 2856e5b75505Sopenharmony_ci "dot1xAuthSessionTime=%u\n" 2857e5b75505Sopenharmony_ci "dot1xAuthSessionTerminateCause=999\n" 2858e5b75505Sopenharmony_ci "dot1xAuthSessionUserName=%s\n", 2859e5b75505Sopenharmony_ci (unsigned long long) sta->acct_session_id, 2860e5b75505Sopenharmony_ci (wpa_key_mgmt_wpa_ieee8021x( 2861e5b75505Sopenharmony_ci wpa_auth_sta_key_mgmt(sta->wpa_sm))) ? 2862e5b75505Sopenharmony_ci 1 : 2, 2863e5b75505Sopenharmony_ci (unsigned int) diff.sec, 2864e5b75505Sopenharmony_ci sm->identity ? (char *) sm->identity : 2865e5b75505Sopenharmony_ci (identity_buf ? identity_buf : "N/A")); 2866e5b75505Sopenharmony_ci os_free(identity_buf); 2867e5b75505Sopenharmony_ci if (os_snprintf_error(buflen - len, ret)) 2868e5b75505Sopenharmony_ci return len; 2869e5b75505Sopenharmony_ci len += ret; 2870e5b75505Sopenharmony_ci 2871e5b75505Sopenharmony_ci if (sm->acct_multi_session_id) { 2872e5b75505Sopenharmony_ci ret = os_snprintf(buf + len, buflen - len, 2873e5b75505Sopenharmony_ci "authMultiSessionId=%016llX\n", 2874e5b75505Sopenharmony_ci (unsigned long long) 2875e5b75505Sopenharmony_ci sm->acct_multi_session_id); 2876e5b75505Sopenharmony_ci if (os_snprintf_error(buflen - len, ret)) 2877e5b75505Sopenharmony_ci return len; 2878e5b75505Sopenharmony_ci len += ret; 2879e5b75505Sopenharmony_ci } 2880e5b75505Sopenharmony_ci 2881e5b75505Sopenharmony_ci name1 = eap_server_get_name(0, sm->eap_type_authsrv); 2882e5b75505Sopenharmony_ci name2 = eap_server_get_name(0, sm->eap_type_supp); 2883e5b75505Sopenharmony_ci ret = os_snprintf(buf + len, buflen - len, 2884e5b75505Sopenharmony_ci "last_eap_type_as=%d (%s)\n" 2885e5b75505Sopenharmony_ci "last_eap_type_sta=%d (%s)\n", 2886e5b75505Sopenharmony_ci sm->eap_type_authsrv, name1, 2887e5b75505Sopenharmony_ci sm->eap_type_supp, name2); 2888e5b75505Sopenharmony_ci if (os_snprintf_error(buflen - len, ret)) 2889e5b75505Sopenharmony_ci return len; 2890e5b75505Sopenharmony_ci len += ret; 2891e5b75505Sopenharmony_ci 2892e5b75505Sopenharmony_ci return len; 2893e5b75505Sopenharmony_ci} 2894e5b75505Sopenharmony_ci 2895e5b75505Sopenharmony_ci 2896e5b75505Sopenharmony_ci#ifdef CONFIG_HS20 2897e5b75505Sopenharmony_cistatic void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx) 2898e5b75505Sopenharmony_ci{ 2899e5b75505Sopenharmony_ci struct hostapd_data *hapd = eloop_ctx; 2900e5b75505Sopenharmony_ci struct sta_info *sta = timeout_ctx; 2901e5b75505Sopenharmony_ci 2902e5b75505Sopenharmony_ci if (sta->remediation) { 2903e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to " 2904e5b75505Sopenharmony_ci MACSTR " to indicate Subscription Remediation", 2905e5b75505Sopenharmony_ci MAC2STR(sta->addr)); 2906e5b75505Sopenharmony_ci hs20_send_wnm_notification(hapd, sta->addr, 2907e5b75505Sopenharmony_ci sta->remediation_method, 2908e5b75505Sopenharmony_ci sta->remediation_url); 2909e5b75505Sopenharmony_ci os_free(sta->remediation_url); 2910e5b75505Sopenharmony_ci sta->remediation_url = NULL; 2911e5b75505Sopenharmony_ci } 2912e5b75505Sopenharmony_ci 2913e5b75505Sopenharmony_ci if (sta->hs20_deauth_req) { 2914e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to " 2915e5b75505Sopenharmony_ci MACSTR " to indicate imminent deauthentication", 2916e5b75505Sopenharmony_ci MAC2STR(sta->addr)); 2917e5b75505Sopenharmony_ci hs20_send_wnm_notification_deauth_req(hapd, sta->addr, 2918e5b75505Sopenharmony_ci sta->hs20_deauth_req); 2919e5b75505Sopenharmony_ci } 2920e5b75505Sopenharmony_ci 2921e5b75505Sopenharmony_ci if (sta->hs20_t_c_filtering) { 2922e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "HS 2.0: Send WNM-Notification to " 2923e5b75505Sopenharmony_ci MACSTR " to indicate Terms and Conditions filtering", 2924e5b75505Sopenharmony_ci MAC2STR(sta->addr)); 2925e5b75505Sopenharmony_ci hs20_send_wnm_notification_t_c(hapd, sta->addr, sta->t_c_url); 2926e5b75505Sopenharmony_ci os_free(sta->t_c_url); 2927e5b75505Sopenharmony_ci sta->t_c_url = NULL; 2928e5b75505Sopenharmony_ci } 2929e5b75505Sopenharmony_ci} 2930e5b75505Sopenharmony_ci#endif /* CONFIG_HS20 */ 2931e5b75505Sopenharmony_ci 2932e5b75505Sopenharmony_ci 2933e5b75505Sopenharmony_cistatic void ieee802_1x_finished(struct hostapd_data *hapd, 2934e5b75505Sopenharmony_ci struct sta_info *sta, int success, 2935e5b75505Sopenharmony_ci int remediation) 2936e5b75505Sopenharmony_ci{ 2937e5b75505Sopenharmony_ci const u8 *key; 2938e5b75505Sopenharmony_ci size_t len; 2939e5b75505Sopenharmony_ci /* TODO: get PMKLifetime from WPA parameters */ 2940e5b75505Sopenharmony_ci static const int dot11RSNAConfigPMKLifetime = 43200; 2941e5b75505Sopenharmony_ci unsigned int session_timeout; 2942e5b75505Sopenharmony_ci struct os_reltime now, remaining; 2943e5b75505Sopenharmony_ci 2944e5b75505Sopenharmony_ci#ifdef CONFIG_HS20 2945e5b75505Sopenharmony_ci if (remediation && !sta->remediation) { 2946e5b75505Sopenharmony_ci sta->remediation = 1; 2947e5b75505Sopenharmony_ci os_free(sta->remediation_url); 2948e5b75505Sopenharmony_ci sta->remediation_url = 2949e5b75505Sopenharmony_ci os_strdup(hapd->conf->subscr_remediation_url); 2950e5b75505Sopenharmony_ci sta->remediation_method = 1; /* SOAP-XML SPP */ 2951e5b75505Sopenharmony_ci } 2952e5b75505Sopenharmony_ci 2953e5b75505Sopenharmony_ci if (success && (sta->remediation || sta->hs20_deauth_req || 2954e5b75505Sopenharmony_ci sta->hs20_t_c_filtering)) { 2955e5b75505Sopenharmony_ci wpa_printf(MSG_DEBUG, "HS 2.0: Schedule WNM-Notification to " 2956e5b75505Sopenharmony_ci MACSTR " in 100 ms", MAC2STR(sta->addr)); 2957e5b75505Sopenharmony_ci eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta); 2958e5b75505Sopenharmony_ci eloop_register_timeout(0, 100000, ieee802_1x_wnm_notif_send, 2959e5b75505Sopenharmony_ci hapd, sta); 2960e5b75505Sopenharmony_ci } 2961e5b75505Sopenharmony_ci#endif /* CONFIG_HS20 */ 2962e5b75505Sopenharmony_ci 2963e5b75505Sopenharmony_ci#ifdef CONFIG_MACSEC 2964e5b75505Sopenharmony_ci ieee802_1x_notify_create_actor_hapd(hapd, sta); 2965e5b75505Sopenharmony_ci#endif /* CONFIG_MACSEC */ 2966e5b75505Sopenharmony_ci 2967e5b75505Sopenharmony_ci key = ieee802_1x_get_key(sta->eapol_sm, &len); 2968e5b75505Sopenharmony_ci if (sta->session_timeout_set) { 2969e5b75505Sopenharmony_ci os_get_reltime(&now); 2970e5b75505Sopenharmony_ci os_reltime_sub(&sta->session_timeout, &now, &remaining); 2971e5b75505Sopenharmony_ci session_timeout = (remaining.sec > 0) ? remaining.sec : 1; 2972e5b75505Sopenharmony_ci } else { 2973e5b75505Sopenharmony_ci session_timeout = dot11RSNAConfigPMKLifetime; 2974e5b75505Sopenharmony_ci } 2975e5b75505Sopenharmony_ci if (success && key && len >= PMK_LEN && !sta->remediation && 2976e5b75505Sopenharmony_ci !sta->hs20_deauth_requested && 2977e5b75505Sopenharmony_ci wpa_auth_pmksa_add(sta->wpa_sm, key, len, session_timeout, 2978e5b75505Sopenharmony_ci sta->eapol_sm) == 0) { 2979e5b75505Sopenharmony_ci hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, 2980e5b75505Sopenharmony_ci HOSTAPD_LEVEL_DEBUG, 2981e5b75505Sopenharmony_ci "Added PMKSA cache entry (IEEE 802.1X)"); 2982e5b75505Sopenharmony_ci } 2983e5b75505Sopenharmony_ci 2984e5b75505Sopenharmony_ci if (!success) { 2985e5b75505Sopenharmony_ci /* 2986e5b75505Sopenharmony_ci * Many devices require deauthentication after WPS provisioning 2987e5b75505Sopenharmony_ci * and some may not be be able to do that themselves, so 2988e5b75505Sopenharmony_ci * disconnect the client here. In addition, this may also 2989e5b75505Sopenharmony_ci * benefit IEEE 802.1X/EAPOL authentication cases, too since 2990e5b75505Sopenharmony_ci * the EAPOL PAE state machine would remain in HELD state for 2991e5b75505Sopenharmony_ci * considerable amount of time and some EAP methods, like 2992e5b75505Sopenharmony_ci * EAP-FAST with anonymous provisioning, may require another 2993e5b75505Sopenharmony_ci * EAPOL authentication to be started to complete connection. 2994e5b75505Sopenharmony_ci */ 2995e5b75505Sopenharmony_ci ap_sta_delayed_1x_auth_fail_disconnect(hapd, sta); 2996e5b75505Sopenharmony_ci } 2997e5b75505Sopenharmony_ci} 2998